在树莓派上搭建全局透明代理网关

新剁手了一个Google Home mini,需要科学上网才能正常使用,而 home 本身不支持设置代理,所以需要在网关上动手。正好一直使用树莓派当路由器,所以尝试把树莓派打造成一个带有智能转发功能的透明网关,即国内的 IP 直连,海外的 IP 走代理加速。

配置无线网络

本文关注点不在此,所以一笔带过。

可以通过一键安装脚本 pi-setup-wifi.sh 来安装和配置树莓派的无线。该脚本会创建一个名为SSID,密码为PASSWORD的无线网络,使用的网段为 192.168.68/24

启动 DoH 服务来避免 DNS 污染

目前 GFW 大概有这么几个级别的干扰:

  1. 随机丢包、限速
  2. 域名阻断、IP阻断
  3. 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
2
3
4
5
6
redsocks {
local_ip = 0.0.0.0;
local_port = 12345;
ip = 127.0.0.1;
port = 1080;
}

这里的ip必须改成0.0.0.0,实测如果保留127.0.0.1会让wifi客户端无法上网

这里假设已经有一个开放在 1080 端口的 socks5 服务,可以使用 Shadowsocks 来创建一个。

重启 redsocks 以使配置生效

1
sudo service redsocks restart

忽略国内地址

安装 ipset 来生成国内地址列表

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo apt install -y ipset

# 下载分配给国内运营商的 IP 段
curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | \
grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > chnroute.txt

# 创建一个集合并把上述IP段加进去
sudo ipset create chnroute hash:net

cat chnroute.txt | sudo xargs -I ip ipset add chnroute ip

# 上一条命令执行的非常慢,所以把结果保存下来,下次直接从文件恢复
sudo bash -c "ipset save chnroute > /etc/chnroute.ipset"

在系统重启后,使用如下命令来恢复ipset

1
sudo ipset restore < /etc/chnroute.ipset

使用 iptables 来转发流量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sudo iptables -t nat -N SHADOWSOCKS

# 注意这里要把 $server_IP 改成你自己的 socks5 远程IP,即你的VPS IP,不然无法正常工作
sudo iptables -t nat -A SHADOWSOCKS -d $server_IP -j RETURN

# 忽略局域网地址
sudo iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
sudo iptables -t nat -A SHADOWSOCKS -m set --match-set chnroute dst -j RETURN

# 把流量转发到 12345 端口,即redsocks
sudo iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345
sudo iptables -t nat -A OUTPUT -p tcp -j SHADOWSOCKS
sudo iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS

覆盖设备自身的 DNS 服务器

因为 Google Home 内置了 DNS 服务器,而不是网关分配的,所以需要把流量截获然后转发到可靠的 DNS 解析。

1
2
sudo iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 15353
sudo iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 15353

至此,搭建完毕,将 Google Home 连接到 wifi 上,就可以开始欢快的使用各种服务啦^_^。

Hey, Google, nice to meet you ~

参考链接及资源

Running a DNS over HTTPS Client

求推荐靠谱的防 dns 污染方案

请教如何修改让dns强制重定向到路由

利用shadowsocks打造局域网翻墙透明网关

用树莓派打造无线中继科学上网路由器

ss-redir 透明代理

Dnsmasq 介绍与使用

利用Dnsmasq部署DNS服务

DNSmasq 安装&配置详解

dnsforwarder

Tcp-DNS-proxy

dns-over-https

https_dns_proxy

Pcap_DNSProxy