架设OSU私服时的奇怪bug

Peace

Posted by Sakura on September 15, 2021

奇怪的Bug…从来没有见过这么奇怪的Bug…

前言

学习学累了 ,又想着折腾折腾。这次准备折腾个OSU!私服架设,先从Google上搜信息。。又在Git上找到了许多Bancho(OSU!服务端)的实现。还发现了OSU!圈子里国人大神用Rust写的实现。看README说性能优越。就它了。

Peace

PurePeace大佬写的实现

https://github.com/Pure-Peace/Peace

大概描述一下这个项目的结构

配置

本机修改hosts

127.0.0.1 osu.ppy.sh
127.0.0.1 c.ppy.sh
127.0.0.1 c1.ppy.sh
127.0.0.1 c2.ppy.sh
127.0.0.1 c3.ppy.sh
127.0.0.1 c4.ppy.sh
127.0.0.1 c5.ppy.sh
127.0.0.1 c6.ppy.sh
127.0.0.1 ce.ppy.sh
127.0.0.1 a.ppy.sh
127.0.0.1 i.ppy.sh

修改nginx配置(bancho.conf)

# Peace's bancho & avatar server config
#
# Please change: $default_avatar, $avatar_dir and ssl_certificates
#
upstream peace {
	# Tcp (default) peace
	server 127.0.0.1:8080 fail_timeout=0;
	# Unix sock
	# server $unix:/path/to/.sock fail_timeout=0;

	keepalive 600;
	keepalive_timeout 120s;
	keepalive_requests 4000;
}

server {
	# Bancho server
	server_name ~^(?:c[e4-6|osu]?)\.ppy\.sh;
	listen 80;
	listen 443 ssl;

	gzip on;

	proxy_http_version 1.1;
	proxy_redirect off;
	proxy_set_header Connection "";
	proxy_set_header Host $http_host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-IP $remote_addr;

	ssl_certificate /cargo/Peace/nginx/cert/cert.cer;
	ssl_certificate_key /cargo/Peace/nginx/cert/key.pem;

	location / {
		proxy_pass http://127.0.0.1:8080/bancho/;
	}

	location /web/ {
		proxy_pass http://127.0.0.1:8080/web/;
	}
}

server {
	# Avatar static server
	server_name a.ppy.sh;
	listen 80;
	listen 443 ssl;

	# Warn: Please *MAKESURE* that default avatar file is exists
	set $default_avatar default.png;
	# Change the avatar_dir
	# Recommended absolute path
	set $avatar_dir /cargo/avater;

	add_header cache-control "public, max-age=7200";

	index $default_avatar;
	root $avatar_dir;

	ssl_certificate /cargo/Peace/nginx/cert/cert.cer;
	ssl_certificate_key /cargo/Peace/nginx/cert/key.pem;

	proxy_intercept_errors on;
	error_page 497 500 403 404 =200 /$default_avatar;

	# Disable direct access to files:
	# Attempts to access with a file suffix (such as /1.png /1.jpg...)
	# will be redirected to an address with no suffix (/1)
	location ~(.*)\.(.*)$ {
		rewrite ^/(.*)\.(.*)$ $1 permanent;
	}

	# Access with image name (No suffix, player id only)
	location / {
		try_files $uri.png $uri.jpg $uri.jpeg $uri.gif /$default_avatar break;
	}

}

公网环境

本机

内网运行时,一切正常,于是我准备把服务端提到公网环境,按照项目运行架构,Peace可以不对外公开,仅通过Nginx转发请求。于是我将Hosts修改为本机公网IP

image-20210915213016645

再通过osu.ppy.sh测试转发情况 ,成功

image-20210915212949276

经过上面的设置,按理来说应该已经成功了啊?可是此项目是运行在个人电脑。ISP给的公网IP默认封禁了80端口,意思是说,只有我自己能连进来,别人改了hosts是访问不到本机的。

所以为了解决问题,我准备将项目迁移到阿里云服务器上

阿里云

在经过一系列配置后,在阿里云上配置的结构是这样的

image-20210915214529948

Peace换成了8081,因为Tomcat占了8080。Nginx配置也对应更换。Hosts直接将osu.ppy.sh一系列域名转发到阿里云IP。

阿里云运行Peace+Nginx,一切正常(忽略那个数据库版本问题-w-)

image-20210915215013781

本以为大功告成,可是接下来碰见的这个Bug困扰了我整整一天。。。

在浏览器中输入osu.ppy.sh发现无法访问

image-20210915214650733

EDGE直接访问显示出错

image-20210915214710806

火狐出现这个错误

问题是我直接访问IP是可以成功访问的,Https也成功握手。

image-20210915215848243

但如果我从Hosts劫持的域名访问就失败。

查看Nginx日志,压根没有输出错误,也就是说在Nginx之前就出错了。。

看了好久SSL证书+Nginx配置仍然没有解决问题。

无奈的我开始排除法慢慢寻找问题的根源。

BUG

我修改了Hosts的域名,换成百度或者别的发现竟可以成功访问了

image-20210915215824548

直接访问百度

image-20210915215441560

出现这个错误是因为证书不匹配,但是证明已经成功握手。

也就是说其他域名可以转发到我的服务器,但是osu.ppy.sh不行,于是我以为是域名有问题,继续排除

我又修改了hosts里的IP,用osu.ppy.sh转发到其他的IP比如百度,发现也可以访问

image-20210915215932134

image-20210915220055727

也就是说,其他的域名都可以通过hosts访问我的服务器,只有osu.ppy.sh访问不到

并且osu.ppy.sh可以访问到别的IP,就访问不到我的服务器。

简直怪了

通过Wireshark抓包发现发送了Client Hello后服务端莫名其妙直接扔回来一个RST(???)

image-20210915220532868

通过除osu.ppy.sh以外的域名访问服务器

image-20210915220754313

就可以握手成功

Openssl尝试验证出现以下错误

image-20210915221613309

另外我尝试将hosts域名修改为我未备案的域名,发现也不能访问,估计是没有备案的原因80和443无法访问吧。

另辟蹊径

这下坏了,游戏是通过hosts劫持*.ppy.sh一系列域名来切换私服的,可是这些域名却访问不到我的服务器,这可怎么办。

想了想,还有别的方法。

OSU!连接私服的方法除了安装证书劫持域名外还有一个方法

通过给程序增加参数,修改游戏连接的服务器

image-20210915221803622

可是我不太清楚这个参数的具体作用,我在这里修改成我服务器的域名(未备案),发现无法连接到我的bancho,我并不知道这个参数具体改变了什么。

最后我从另一个使用Python写Bancho实现的项目那里,发现了下面的nginx配置

image-20210915222012654

在这个配置的下面,还有一些注释掉的代码

image-20210915222018606

server switcher support,这个server switcher就是私服一键修改hosts并安装证书的小程序,也就是说如果是-devserver方式运行的私服就是通过上面没注释的代码运行的。

看了一下最大的差别就在这一行了image-20210915222200963

通过hosts转发则是image-20210915222301255

发现两者server_name抓取的后半部分域名不同,一个是ppy.sh,另一个是自己的顶级域名。

所以我推断,-devserver参数会将游戏输出的包修改为**.你的参数*

比如-devserver后跟的参数为abc.com

那么游戏会将自己的包修改为osu.abc.com a.abc.com c1.abc.com等等。具体有什么包就可以看上面的hosts来确定。

image-20210915222747541

这下可以通过这个方式来绕过osu.ppy.sh这个域名了,可是我自己的域名还没有备案。没办法,火速备案。但备案之前我就想先试验一下我的想法是否是正确的。

我将-devserver后添加一个虚拟域名 abc.com

image-20210915223045684

然后再将nginx配置修改为匹配abc.com

image-20210915222915349

修改证书生成配置

image-20210915223000964

本机安装证书image-20210915223141829

hosts 增加abc.com的转发

image-20210915223246542

成功访问!

image-20210915223412281

来看一下游戏是否将信息发到了这个域名(想法是否出错)

image-20210915223513601

客户端成功连接到服务端检测到登录行为

image-20210915223624046

抓包显示也握手成功

总结

成功用-devserver参数的方式绕过了osu.ppy.sh这个域名,再使用hosts转发虚拟域名到服务器上来成功访问私服。

虽然解决了bug,但没有完全解决。

等域名备案下来,就可以删掉自签名证书和hosts内容了,只通过-devserver+自己的顶级域名即可访问。

但是我们仍未知道那天的bug是什么原因QAQ,为什么osu.ppy.sh就是转发不到我的服务器,仍然是个谜;w;