记录一下如何把电子垃圾变成家庭网关。
其实并没有什么技术含量,但是互联网上几乎没有相关的内容(基本都是基于 OpenWrt 或者 VyOS 之类的比较专用的方案)。
希望本文可以给同样想折腾的后来者提供一些帮助,如果有幸能给你带来一些启发那就再好不过了。
前置条件
- 闲置的 x86 / ARM 盒子 (¥100~200) , 单网口也可以
- 一点好奇心和耐心
拓扑
┌──────────────────────┐
│ │
│ │
│ 光猫或主路由 │
│ 192.168.1.1 │
│ │
└──────────┬───────────┘
│
│
│
│
│
┌──────────┴────────┐
│ │
│ │
┌─────────────┼ 一般睿智的交换机 ┼───────────────────┐
│ │ │ │
│ └───────────────┬───┘ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
┌──────────┴───────┐ ┌──────┴─────┐ ┌─────┴──────┐
│ │ │ │ │ │
│ 旁路网关 │ │ │ │ │
│ │ │ 192.168.1.x│ │192.168.1.y │
│ │ │ │ │ │
│ 192.168.1.254 │ │ │ │ │
└──────────────────┘ └────────────┘ └────────────┘
灵魂绘图 (x
总之是不能再简单的最常见的家庭网络拓扑了...
DHCP 服务器可以用光猫/主路由的, 你也可以关掉光猫/主路由自带的 DHCP 服务器在自己的旁路网关上面跑一个
总之请确保设备通过 DHCP 获取到的地址信息里网关是指向旁路网关的(192.168.1.254), 当然你也可以手动指定
旁路网关设置
思路上和 tproxy + 4层 socket 实现的透明代理方案有一些不同,我这里是 wireguard*一把梭
这样的话旁路网关的配置基本上和路由是一样的,配置路由表特殊流量走 wireguard 的 TUN 接口就可以了。
wg0: flags=80c3<UP,BROADCAST,RUNNING,NOARP,MULTICAST> mtu 1420
index 4 priority 0 llprio 3
wgport 1111
wgpubkey whatever
groups: wg egress
inet 10.114.5.14 netmask 0xffffffff
*:wireguard 的协议特征的确很明显,并不适合用来对抗审查。但是目前 ipv6 环境下似乎没有做针对性的检测,所以暂时可以用。相同的方案并不限于 wireguard,您也可以考虑使用其他协议。
# 启动时自动配置 wireguard 接口和路由
# crontab -e 添加在 crontab 里
@reboot /usr/local/bin/wg setconf wg0 /path/to/wg.conf
@reboot /sbin/route add default 10.114.5.14
# 启用 ip forwarding
wyse# cat /etc/sysctl.conf
net.inet.ip.forwarding=1
# /etc/pf.conf
# 等价于 iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
pass out on wg0 inet to any nat-to (wg0)
TCP MSS Clamping
当你完成了以上步骤后会发现网络已经可以使用了,但是速度非常慢。
原因在于客户端并不知道网络环境里存在一个旁路网关,所以 MTU 还是 1500,而旁路网关对收到的数据包做封装是有开销的(大约 40-80 bytes),于是旁路网关封装好的包可能会超过链路的 MTU 造成丢包或分片,或者需要网关的 CPU 来拆包重新封装。
为了避免这个问题,这里可以用 pf 来修改 TCP 握手时的 MSS 值
# /etc/pf.conf
# 您可以根据自己的环境调整 MSS 值,如果不确定的话可以使用 1220 (for ipv6 uplinks)
match out on wg0 inet to any scrub (max-mss 1352)
或者,如果你的 DHCP 服务器和客户端均支持 Option 26 的话,也可以在分配地址时为接口的 MTU 设置一个合适的值,MSS 会根据 MTU 自动计算,无需通过 pf 修改。
中国路由直连 (可选)
经典的 chnroute
我用的是 https://github.com/misakaio/chnroutes2
简单的修改路由的脚本,如果你对上述项目不放心的话可以加一个判断 $line 是否为合法的 ip CIDR
DNS 分流 (可选)
https://github.com/felixonmars/dnsmasq-china-list
这里用 OpenBSD 自带的 unbound 做一下中国域名的分流
# /var/unbound/etc/unbound.conf
# $OpenBSD: unbound.conf,v 1.21 2020/10/28 11:35:58 sthen Exp $
server:
interface: <your interface>
access-control: 0.0.0.0/0 allow
hide-identity: yes
hide-version: yes
private-address: ::/0 # filter AAAA
remote-control:
control-enable: yes
control-interface: /var/run/unbound.sock
include: /var/unbound/etc/*.unbound.conf # chroot jail
# Use an upstream forwarder (recursive resolver) for some or all zones.
#
forward-zone:
name: "." # use for ALL queries
forward-addr: 8.8.8.8
这里有一点需要注意一下,BSD 的 make 还有 sed 和 GNU 的不太一样,请不要用项目自带的 Makefile 来生成 unbound 配置文件,因为 BSD 的 sed 不认识 \n...需要写成 \[换行]
自动更新 (可选)
# /etc/daily.local
cd /path/to/dnsmasq-china-list && git pull && sh /path/to/unbound.sh && cp /path/to/dnsmasq-china-list/*.unbound.conf /var/unbound/etc && unbound-control reload
cd /path/to/chnroutes2 && git pull && sh /path/to/chnroute.sh /path/to/chnroutes2/chnroutes.txt