之前折腾过的游戏方案都需要路由器支持,但普通路由器跑个 KCP 都能炸。即便是 AC68U也不令人满意:科学上网插件中的访问控制虽然能让单独的游戏设备使用游戏模式达到 FullCone 的效果,但 Nat Type 时不时会掉到 F,十分影响游戏体验。

于是乎又折腾起了树莓派,发现做成一个透明代理网关完全符合需求。

此方案同样适用于 PS4 等游戏主机,只需要连上 树莓派的 WIFI 或单独设置网关地址为树莓派 IP 就能达到无污染上网、流畅玩游戏的效果。

环境

服务器:阿里云深圳小鸡,像怪物猎人这种 P2P 的联机游戏,选国内的服务器相当合适。

树莓派系统:2016-03-18-raspbian-jessie
http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian/images/

替换USTC源前请备份:

1
2
3
4
5
sudo nano /etc/apt/sources.lis
#修改源
deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi
# 更新
sudo apt-get update -y

烧录工具:
https://www.alexpage.de/usb-image-tool/download/

拓容: sudo rpi-config --> Expand FileSystem

BBR

没错,树莓派也能用 BBR 了 hhh。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sudo rpi-update
sudo reboot
# 内核版本大于 4.9 即可
uname -r
输出:4.19.46-v7+
sudo bash -c 'echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf'
sudo bash -c 'echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf'
sudo sysctl -p
sudo reboot
# 重启后检查一下有没有 bbr 模块即可
sysctl net.ipv4.tcp_available_congestion_control
输出:net.ipv4.tcp_available_congestion_control = bbr cubic reno
lsmod | grep bbr
输出:tcp_bbr 20480 1

热点

带 rtl871xdrv 补丁的 hostapd

3B+内置的网卡信号太感人,外接个 USB 带天线的网卡会好很多,8192CUS 驱动请参考最后的链接来配置。

1
2
3
4
5
6
7
8
9
10
11
12
sudo apt install -y libnl-3-dev libnl-genl-3-dev libssl-dev
wget https://w1.fi/releases/hostapd-2.6.tar.gz
wget https://raw.githubusercontent.com/pritambaral/hostapd-rtl871xdrv/hostapd_2_6/rtlxdrv.patch
tar zxf hostapd-2.6.tar.gz
cd hostapd-2.6
patch -p1 < ../rtlxdrv.patch
cd hostapd
cp defconfig .config
echo CONFIG_LIBNL32=y >> .config
echo CONFIG_DRIVER_RTW=y >> .config
make -j
sudo make install

create_ap

想自行设置热点请参考官方文档:https://www.raspberrypi.org/documentation/configuration/wireless/access-point.md

这里一步到位用了 create_ap,热点不设置密码也是可以的。
eth0、wlan0 为树莓派默认网卡名,不同的话请自行修改。

1
2
3
4
5
6
sudo apt-get install -y haveged dnsmasq iproute2 iptables
git clone https://github.com/oblique/create_ap
cd create_ap
sudo make install
# 启动热点
sudo create_ap wlan0 eth0 $ap_name $ap_password --no-virt

打开路由转发

1
2
3
4
5
6
7
sudo vim /etc/sysctl.conf
//取消net.ipv4.ip_forward=1的注释
sudo sysctl -p
输出:
net.ipv4.ip_forward = 1
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

此时客户端连接上 WIFI 可以上网就可以进行下一步了

SS

  • no-install-recommends参数来避免安装非必须的文件,从而减小镜像的体积。

  • 只有 C 语言版的 Shadowsocks-libev才支持 UDP 转发,且更新频率最高、CPU内存占用率最小,所以推荐使用。

各种有的没的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
sudo apt-get install -y --no-install-recommends vim git gettext libssl-dev build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libcurl4-openssl-dev ipset rng-tools screen
 
# Libsodium
export LIBSODIUM_VER=1.0.16
wget https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VER.tar.gz
tar xvf libsodium-$LIBSODIUM_VER.tar.gz
pushd libsodium-$LIBSODIUM_VER
./configure --prefix=/usr && make -j
sudo make install
popd
sudo ldconfig
 
# Mbedtls
export MBEDTLS_VER=2.6.0
wget https://tls.mbed.org/download/mbedtls-$MBEDTLS_VER-gpl.tgz
tar xvf mbedtls-$MBEDTLS_VER-gpl.tgz
pushd mbedtls-$MBEDTLS_VER
make SHARED=1 CFLAGS=-fPIC
sudo make DESTDIR=/usr install
popd
sudo ldconfig
 
# Obfs
git clone https://github.com/shadowsocks/simple-obfs.git
cd simple-obfs
git submodule update --init --recursive
./autogen.sh && ./configure && make -j
sudo make install
cd ~
 
# Shadowsocks-libev
git clone https://github.com/shadowsocks/shadowsocks-libev.git
cd shadowsocks-libev
git submodule update --init --recursive
./autogen.sh && ./configure --prefix=/usr && make -j
sudo make install
cd ~

服务器端配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"server": ["0.0.0.0"],
"server_port": 8388,
"password": "test",
"timeout": 300,
"user": "nobody",
"fast_open": true,
"method": "aes-256-gcm",
"plugin": "obfs-server",
"plugin_opts": "obfs=http",
"nameserver": "8.8.8.8",
"mode": "tcp_and_udp",
"mtu": 1300,
"workers": 2
}

mtu参数这里要手动设置成1300,后面再讲为什么。

dnsmasq

1
2
3
4
5
6
sudo vim /etc/dnsmasq.conf
 
no-resolv # 不让 dnsmasq 以 /etc/resolve.conf 中的服务器为上游服务器
no-poll # 不让 dnsmasq 向 /etc/resolve.conf 中的服务器发起查询请求
server=127.0.0.1#15353 # ip 是 cloudflared 监听的 IP,一般是本地 IP;port 是 cloudflared 监听的端口
conf-dir=/etc/dnsmasq.d/,*.conf # dnsmasq-china-list 的配置文件将要存放在 dnsmasq.d 中,引入配置文件

dnsmasq-china-list

之前用 chinadns 不稳定,还要配合 dnsforwarder 使用。
dnsmasq-china-list项目维护了一张国内常用但是通过国外DNS会解析错误的网站域名的列表,保证List中的国内域名全部走国内DNS服务器解析。

1
2
3
4
5
6
wget https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/install.sh
chmod +x install.sh
sudo ./install.sh
 
# 启动
sudo systemctl restart dnsmasq

iptables

UDP 转发不能像转发 TCP 一样,需要借助TPROXY模块。
关于 NAT 这一块,感兴趣的可以看这篇:https://vvl.me/2018/06/09/from-ss-redir-to-linux-nat/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 清空iptables
sudo su
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
 
# SS-REDIR TCP
iptables -t nat -N SSREDIR_TCP
 
# Bypass ssserver and LAN
iptables -t nat -A SSREDIR_TCP -d $Server_IP -j RETURN
iptables -t nat -A SSREDIR_TCP -d 0.0.0.0/8 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 10.0.0.0/8 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 127.0.0.0/8 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 169.254.0.0/16 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 172.16.0.0/12 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 192.168.0.0/16 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 224.0.0.0/4 -j RETURN
iptables -t nat -A SSREDIR_TCP -d 240.0.0.0/4 -j RETURN
# Redirect TCP
iptables -t nat -A SSREDIR_TCP -p tcp -j REDIRECT --to-ports 60080
 
# SS_REDIR UDP
ip rule add fwmark 0x02/0x02 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N SSREDIR_UDP
iptables -t mangle -A SSREDIR_UDP -d $Server_IP -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A SSREDIR_UDP -d 240.0.0.0/4 -j RETURN
# Redirect UDP
iptables -t mangle -A SSREDIR_UDP -p udp -j TPROXY --on-port 60080 --tproxy-mark 0x02/0x02
 
# Enable
iptables -t nat -A PREROUTING -p tcp -j SSREDIR_TCP
iptables -t mangle -A PREROUTING -j SSREDIR_UDP

写进开机启动自动恢复已保存的路由

保存

1
sudo sh -c "iptables-save > /etc/iptables/rules.v4"

开机恢复

1
sudo sh -c "iptables-restore < /etc/iptables/rules.v4"

ss-redir

1
nohup sudo ss-redir -s $Your_Server_IP -p 8388 -m aes-256-gcm -k test -b 0.0.0.0 -l 60080 -u --no-delay --fast-open --reuse-port --plugin obfs-local --plugin-opts "obfs=http;obfs-host=www.cloudflare.com" --mtu 1300 -v 2>&1 > /dev/null &

Dns Over Https

UPDATE
cloudflared 的解析延迟还是不太能接受,这里推荐红鱼 DNS OVER HTTPS。
配置参考:https://www.rubyfish.cn/config-dnscrypt-proxy

cloudflared 监听 0.0.0.0,端口设置为 15353,防止占用系统 53 端口。

1
2
3
4
wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-arm.tgz
tar -xvf cloudflared-stable-linux-arm.tgz
chmod +x cloudflared
nohup /home/pi/ss/cloudflared proxy-dns --address 0.0.0.0 --port 15353 2>&1 > /dev/null &

定时启动

ss-redir 和 create_ap 都需要 root 权限

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
 
systemctl restart dnsmasq
killall create_ap
killall ss-redir
killall cloudflared
 
nohup sudo /usr/bin/ss-redir -s $Server_IP -p 8388 -m aes-256-gcm -k $Password -b 0.0.0.0 -l 60080 -u --no-delay --fast-open --plugin obfs-local --plugin-opts "obfs
=http;obfs-host=www.cloudflare.com" --mtu 1400 -v 2>&1 > /dev/null &
 
nohup ./cloudflared proxy-dns --address 0.0.0.0 --port 15353 2>&1 > /dev/null &
 
nohup /usr/bin/create_ap wlan0 eth0 $AP_Name $AP_Password --no-virt 2>&1 > /dev/null &

优化

我们都知道Bind不配合数据库的情况下,经常需要重新载入并读取配置文件,这是造成性能低下的原因。根据这点教训,我们可以考虑不读取/etc/hosts文件。而是另外指定一个在共享内存里的文件,比如/dev/shm/dnsrecord.txt ,这样就不费劲了,又由于内存的非持久性,重启就消失,可以定期同步硬盘上的某个内容到内存文件中。

1
2
3
4
5
6
7
no-hosts 
addn-hosts=/dev/shm/dnsrecord.txt
# 开机启动
echo "cat /etc/hosts > /dev/shm/dnsrecord.txt" >> /etc/rc.local
# 定时同步内容
crontab -e
*/10 * * * * cat /etc/hosts > /dev/shm/dnsrecord.txt

如果上述配置已经能让你流畅联机的话,那么以下内容请无视。
如果上述配置已经能让你流畅联机的话,那么以下内容请无视。
如果上述配置已经能让你流畅联机的话,那么以下内容请无视。

Kcptun

服务器端配置参考:https://github.com/xtaci/kcptun/issues/427

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"listen": ":28900",
"target": "127.0.0.1:1080",
"key": "test",
"crypt": "salsa20",
"mode": "fast2",
"mtu": 512,
"sndwnd": 1024,
"rcvwnd": 1024,
"datashard": 5,
"parityshard": 5,
"dscp": 46,
"nocomp": true,
"nodelay": 0,
"interval": 10,
"resend": 0,
"nc": 1,
"conn": 1
}

客户端配置参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"localaddr": ":1080",
"remoteaddr":"127.0.0.1:2000",
"key": "test",
"crypt": "salsa20",
"mode": "fast2",
"mtu": 512,
"sndwnd": 1024,
"rcvwnd": 1024,
"datashard": 5,
"parityshard": 5,
"dscp": 46,
"nocomp": true,
"nodelay": 0,
"interval": 10,
"resend": 0,
"nc": 1,
"conn": 1
}

UDPSpeeder

1
2
3
4
5
# 服务器
./speederv2_amd64 -s -l0.0.0.0:2001 -r127.0.0.1:1080 -f2:4 -k "test" --mode 0 -q 1
 
# 客户端
./speederv2_arm -c -l127.0.0.1:1080 -r0.0.0.0:2001 -f2:4 -k "test" --mode 0 -q 1

Udp2raw

贵校 Qos 水平远超我想象,UDP 包稍稍发送频繁一些都会做丢包处理,所以服务器端开两个 udp2raw tunnel 来伪装流量。

1
2
3
4
5
# TCP
./udp2raw_arm -c -l127.0.0.1:2000 -r$Server_IP:28900 -k "test" --raw-mode faketcp --sock-buf 4096 --force-sock-buf
 
# UDP
./udp2raw_arm -c -l127.0.0.1:2001 -r$Server_IP:28901 -k "test" --raw-mode faketcp --sock-buf 4096 --force-sock-buf

串联

效果

连上树莓派的 WIFI 或者将 Switch 的网关和 DNS 设置成树莓派 IP 就能将 Nat Type 升到 A,其他游戏设备同理。
Switch网关设置

Switch连接树莓派WIFI
最后,有采集卡的朋友建议弄个有线网卡和小型的散热底座,一来是联机稳定,二是 Switch 原生底座散热太感人,一旦发热起来录制就掉帧,担心屏幕会变形。。。

Have Fun~
代理游戏效果