其实过程非常简单。
首先,当然是要有能用的代理,无论是http proxy还是socks proxy,甚至只是一个shadowsocks server也行,现有的工具都能适配使用。
然后,用redsocks或ss-redir在树莓派上开端口,一定要监听在0.0.0.0上,我之前就是开在127.0.0.1上,然后纠结了大半天,一直是树莓派自己能翻过去,其他把它当网关的机器翻不出去。redsocks目前我看到有两个不同版本,一个原版,从2012年以来就很少更新了,可以将本地tcp流量封装到http connect/http relay/socks协议里,配合iptables等机制实现系统全局代理,另一个是国人修改版, 在原版的基础上又增加了一些功能,比如后端协议还支持了shadowsocks(就跟ss-redir一样)和直连,以及auto proxy自动检测是否需要代理,还有自称修正了一些原版中的bug等等。但我昨天试用下来,发现这新增的功能很不稳定,基本经不起日常使用。我最后就直 接用了ss-redir,这是shadowsocks-libev中的一个工具,功能与redsocks类似,但它只提供了shadowsocks的协议作为后端,不过胜在稳定,又不用多走一次socks5代理,所以估计效率也会好一点。
接着,把树莓派设置流量转发。打开/etc/sysctl.conf,设置net.ipv4.ip_forward=1,让更新实时生效: sysctl -p /etc/sysctl.conf。这样树莓派就已经可以做为网关使用了。还要把流量转发到ss-redir开的端口(我用58100)上去,Linux 上用iptables:
iptables -F
iptables -X
iptables -Z
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -A INPUT -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --dport 58100 -m state --state NEW,ESTABLISHED -j ACCEPT
# dnat
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
iptables -t nat -N SS
# 过滤私有地址,vps地址
iptables -t nat -A SS -d 127.0.0.1 -j RETURN
iptables -t nat -A SS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A SS -d 172.16.0.0/21 -j RETURN
iptables -t nat -A SS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A SS -d shadowsocks-server-ip -j RETURN
# 过滤中国ip地址,网上搜一下“中国ip段"
iptables -t nat -A SS -d 58.14.0.0/15 -j RETURN
iptables -t nat -A SS -d 58.16.0.0/13 -j RETURN
iptables -t nat -A SS -d 58.24.0.0/15 -j RETURN
# 所有其他的ip,都提交给shadowsocks
iptables -t nat -A SS -p tcp -j REDIRECT --to-port 58100
# 使用SS链,其他设备走PREROUTING链
iptables -t nat -A PREROUTING -p tcp -j SS
# 使用SS链,树莓派自己走OUTPUT链
iptables -t nat -A OUTPUT -p tcp -j SS
curl http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest | grep 'apnic|CN|ipv4' | awk -F\| '{ printf("iptables -t nat -A SS -d %s/%d -j RETURN\n", $4, 32-log($5)/log(2)) }' > cn_rules.conf
cn_rules.conf
的内容执行一下。最后,把家里所有要翻墙的设备都在网关一项里填成树莓派的IP。比较方便的做法是,在DHCP那里就直接返回树莓派的IP当网关。比较郁闷的是我的 Netgear R6300v2貌似没找到怎么在DHCP里设置自定义的网关地址。当然树莓派一定要用静态设置上级路由器的IP为网关。这样所有连入的设备就自动能翻墙 了。
上面还有一点没提到的是DNS污染的问题,现在也有很多方案了,我的做法是在树莓派上建了个dnsmasq,上游走OpenDNS的5353端口,国内常用域名有个列表,走114DNS.
在树莓派上搭建全局透明代理网关
有的程序本身不支持设置代理,所以需要在网关上动手。正好一直使用树莓派当路由器,所以尝试把树莓派打造成一个带有智能转发功能的透明网关,即国内的 IP 直连,海外的 IP 走代理加速。
配置无线网络
本文关注点不在此,所以一笔带过。
可以通过一键安装脚本 pi-setup-wifi.sh 来安装和配置树莓派的无线。该脚本会创建一个名为SSID
,密码为PASSWORD
的无线网络,使用的网段为 192.168.68/24
。
启动 DoH 服务来避免 DNS 污染
目前 GFW 大概有这么几个级别的干扰:
- 随机丢包、限速
- 域名阻断、IP阻断
- DNS 干扰
一般的网站都基本上处于1或2,一般来说只要 TCP/UDP 流量不直连就行,但是 Google 家的产品比较强,直接上了最高规格的屏蔽,即 DNS 解析污染。
出于性能和速度的考虑, DNS 协议使用了 UDP 这种不可靠的协议,这使得 DNS 解析污染出现,即被中间路由截获并返回了虚假的 IP 地址,因此我们需要建立一个可靠的 DNS 解析服务。
目前已经有很多解决方案,如基于 TCP 的 DNS 解析,但是由于 TCP 流量仍然能够被嗅探,所以出现了 DoH (DNS over Https),这样只要服务器没问题,返回的结果就一定是正确的。
本文权衡各工具,最后选择了 Cloudflare 家的 DoH服务。
首先到 下载页 下载 Binary: ARMv6
这一栏的压缩包,然后解压。
(被屏蔽了,需要用代理下载)
1 | tar -xzvf cloudflared-stable-linux-amd64.tgz |
然后把 cloudflared 移动到 /usr/local 目录下,并启动。
1 | /usr/local/cloudflared proxy-dns --address 0.0.0.0 --port 15353 |
只监听本地的话wifi客户端会有问题
5353 端口被 avahi 占用了,所以使用15353
你可以在 /etc/rc.local 文件中配置开机启动。
1 | nohup /usr/local/cloudflared proxy-dns --port 15353 & |
不同网络层之间协议转换
安装 redsocks
来把无线网卡的流量转发到 socks5 代理,这本质上是转换两个不同网络层的流量。
1 | sudo apt install -y redsocks |
编辑配置文件 /etc/redsocks.conf
1 | redsocks { |
这里的ip必须改成0.0.0.0,实测如果保留127.0.0.1会让wifi客户端无法上网
这里假设已经有一个开放在 1080 端口的 socks5 服务,可以使用 Shadowsocks
来创建一个。
重启 redsocks 以使配置生效
1 | sudo service redsocks restart |
忽略国内地址
安装 ipset
来生成国内地址列表
1 | sudo apt install -y ipset |
在系统重启后,使用如下命令来恢复ipset
1 | sudo ipset restore < /etc/chnroute.ipset |
使用 iptables 来转发流量
1 | sudo iptables -t nat -N SHADOWSOCKS |
覆盖设备自身的 DNS 服务器
因为 Google Home 内置了 DNS 服务器,而不是网关分配的,所以需要把流量截获然后转发到可靠的 DNS 解析。
1 | sudo iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 15353 |
至此,搭建完毕,将 Google Home 连接到 wifi 上,就可以开始欢快的使用各种服务啦^_^。
Hey, Google, nice to meet you ~