为什么要整这么抽象的活
以前用树莓派 4B 做软路由器.有线网口作为 WAN 口,其他设备通过 WiFi 接入.由于树莓派 WiFi 信号比较弱,所以放在了卧室.又由于卧室里没有网线,用了另一个迷你主机的无线接入客厅的无线路由器,然后用迷你主机的有线网口直连树莓派的有线网口.最近给迷你主机换了硬盘以后总是有很大的电流声,考虑到这些设备都用灯光,于是决定把这些设备都放到客厅,并想办法让 WiFi 信号可以覆盖整个房间.
最初的方案是,让树莓派的 Wan 口接光猫,原本接光猫的无线路由器作为中继.这个方案用了几天感觉还算可以,不过入户的千兆网被树莓派无线网卡的限制成了百兆.
再后来打算换成常规的有两个有线网口的软路由方案,已经在看买 R2S 还是买 R6S 了.这个时候突然发现 VisionFive2 刚好是双网口.到目前为止 OpenWRT 社区还没有支持 VisionFive 2, 考虑到以前在树莓派上的软路由就是用的 Arch Linux 系统,并且 VisionFive 2 上原本安装的也是 Arch Linux, 所以就有了标题中的想法.
在 VisionFive 2 上安装 Arch Linux
参考这个帖子完全够用.我在很久以前就安装了系统,并持续滚动更新,可能最新的安装方式已经有差异,相信手上能拿到板子的人都能装好系统.
软路由
网卡
网卡配置部分参考这篇文章.
WAN: /etc/systemd/network/end0.network
[Match]
Name=end0
[Network]
DHCP=yes
DNSSEC=no
DNS=8.8.8.8
LAN: /etc/systemd/network/end1.network
[Match]
Name=end1
[Link]
Multicast=yes
[Network]
Address=10.22.33.1/24
MulticastDNS=yes
IPMasquerade=both
不要忘了配置服务开机启动
systemctl status systemd-networkd
DNS
用 SmartDNS 实现国内外域名分别查询不同的 DNS 服务器.国内域名来源是 dnsmasq-china-list.
git clone https://github.com/felixonmars/dnsmasq-china-list.git
# 让国内的域名都添加到 smartdns 的 china 组
make SERVER=china smartdns
cp *smartdns.conf /etc/smartdns/
最终 SmartDNS 的配置文件效果
/etc/smartdns/smartdns.conf
conf-file accelerated-domains.china.smartdns.conf
bind 10.22.33.1:53
cache-size 4096
cache-persist yes
cache-file /var/cache/smartdns/smartdns.cache
prefetch-domain yes
serve-expired yes
log-level info
log-file /run/log/smartdns.log
log-size 128k
log-num 2
# china 组的域名能且仅能通过阿里云的 DNS 的服务查
server-tls 223.5.5.5 -group china -exclude-default-group
# 其他域名通过另外的 DNS 服务器
server-tls 8.8.8.8
server-https https://query.esni.tech/doh-public
server-https https://cloudflare-dns.com/dns-query
systemctl enable smartdns
PS: 敏感的小伙伴可能已经发现,这里用的其他 DNS 服务器可能不一定能访问,这个问题在后面解决.
DHCP
/etc/dhcpd.conf
option domain-name-servers 10.22.33.1;
option subnet-mask 255.255.255.0;
option routers 10.22.33.1;
subnet 10.22.33.0 netmask 255.255.255.0 {
range 10.22.33.100 10.22.33.250;
}
创建能够给指定网卡开 dhcpd 的 systemd service
cp /usr/lib/systemd/system/dhcpd4.service /etc/systemd/system/dhcpd4@.service
vim /etc/systemd/system/dhcpd4@.service
[Service]
Type=forking
- ExecStart=/usr/bin/dhcpd -4 -q -cf /etc/dhcpd.conf -pf /run/dhcpd4/dhcpd.pid
+ ExecStart=/usr/bin/dhcpd -4 -q -cf /etc/dhcpd.conf -pf /run/dhcpd4/dhcpd.pid %I
给 LAN 口开服务
systemctl enable dhcpd4@end1
内核转发
echo net.ipv4.ip_forward=1 > /etc/sysctl.d/30-ipforward.conf
目前完成了软路由的配置, WAN 口接光猫, LAN 口接 AP 的 WAN 口,应该就能正常访问国内的网站了.
透明代理
为了给游戏加速,需要同时支持 TCP 和 UDP 的透明代理.我选择的方案是 Shadowsocks 的 Redir. 但是由于 Shadowsocks 报文会被屏蔽,所以在此之上使用自己开发的支持 UDP 通信 VPN. 让 UDP 信道传输游戏里的 UDP 报文.避免了其他方案可能带来的时延.并且隐藏 Shadowsocks UDP 报文的特征.
Candy VPN
这篇文章重点不是讲 VPN 的用法,使用方法可以参考文档, 最终的效果是要让代理服务器与软路由在同一个网络下,可以让 VPN 加密 Shadowsocks 的 UDP 流量.
ShadowSocks
Arch Linux 的仓库里有 shadowsocks-rust, 使用方法就不做赘述了. TCP 流量可以使用 shadowsocks-v2ray-plugin 加密.
IPSet
前面的 SmartDNS 已经完成了域名的分流,但是还需要 IP 地址的分流.实现方案是 IPSet + IPTables.
以前写了一个把 apnic 格式转换成 CIDR 格式的工具 iana-tools. 用这个工具可以提取出所有中国大陆的 IP 地址,并写入 IPSet 的配置文件
#!/bin/bash
echo "Downloading apnic..."
wget --quiet -P /tmp/ http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest
echo "Updating ipset..."
iana-tools \
-file="/tmp/delegated-apnic-latest" \
-cc="CN" \
-type="ipv4" \
-headers="create china hash:net family inet hashsize 2048 maxelem 65536" \
-prefix="add china " > /etc/ipset.conf
echo "Cleaning up..."
rm /tmp/delegated-apnic-latest*
启用 IPSet 服务
systemctl enable ipset
IPTables
配置中的 x.x.x.x 替换为 ShadowSocks 服务器的真实地址.以下命令会清空当前的 iptables 配置,并用新的配置更新 iptables 配置文件.
#!/bin/bash
cd "$(dirname "$0")"
echo "Updating ipstables config"
# clean iptables
iptables-save | awk '/^[*]/ { print $1 }
/^:[A-Z]+ [^-]/ { print $1 " ACCEPT" ; }
/COMMIT/ { print $0; }' | iptables-restore
# TCP
iptables -t nat -N SS-TCP
iptables -t nat -A SS-TCP -d x.x.x.x -j RETURN
iptables -t nat -A SS-TCP -d 0.0.0.0/8 -j RETURN
iptables -t nat -A SS-TCP -d 10.0.0.0/8 -j RETURN
iptables -t nat -A SS-TCP -d 127.0.0.0/8 -j RETURN
iptables -t nat -A SS-TCP -d 169.254.0.0/16 -j RETURN
iptables -t nat -A SS-TCP -d 172.16.0.0/12 -j RETURN
iptables -t nat -A SS-TCP -d 192.168.0.0/16 -j RETURN
iptables -t nat -A SS-TCP -d 224.0.0.0/4 -j RETURN
iptables -t nat -A SS-TCP -d 240.0.0.0/4 -j RETURN
iptables -t nat -A SS-TCP -d 8.8.8.8 -j RETURN
iptables -t nat -A SS-TCP -m set --match-set china dst -j RETURN
iptables -t nat -A SS-TCP -p tcp -j REDIRECT --to-ports 1080
iptables -t nat -A PREROUTING -p tcp -j SS-TCP
iptables -t nat -A OUTPUT -p tcp -j SS-TCP
# UDP
iptables -t mangle -N SS-UDP
iptables -t mangle -A SS-UDP -d x.x.x.x -j RETURN
iptables -t mangle -A SS-UDP -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A SS-UDP -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A SS-UDP -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A SS-UDP -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A SS-UDP -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A SS-UDP -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A SS-UDP -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A SS-UDP -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A SS-UDP -m set --match-set china dst -j RETURN
iptables -t mangle -A SS-UDP -p udp -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 127.0.0.1 --on-port 1080
iptables -t mangle -A PREROUTING -p udp -j SS-UDP
# save iptables
iptables-save -f /etc/iptables/iptables.rules
echo "Update Successful"
启用 IPTables 服务
systemctl enable iptables
TPROXY
上面的 UDP 转发使用了 TPROXY, 因此需要添加路由和规则.
#!/bin/bash
/usr/bin/ip route add local 0.0.0.0/0 dev lo table 100
/usr/bin/ip rule add fwmark 0x1/0x1 lookup 100
这样配置的规则在重启后会丢失,因此我用 crontab @reboot 规则,在开启启动时执行,不写 systemd service 是因为我懒.如果你也用了 crontab, 不要忘了开对应的服务.
启用 IPTables 服务
systemctl enable cronie
完结
此时重启软路由,应该一切正常了吧.