目前,适合个人使用的软路由系统主要包括 iKuai、OpenWRT 和 RouterOS,其中 RouterOS 我没有用过在此不做介绍。 iKuai 性能和稳定性都很不错,但是扩展性比较差,增加功能比较困难,而 OpenWRT 性能和稳定性略逊于 iKuai, 但是扩展性很强,有丰富的插件可以使用,所以许多人都是 iKuai+OpenWRT 双路由方案。 这种方案在初期的时候是可以满足我的需求的,但是目前这种方案对于我来讲已经变得逐渐不好用了, 一方面是各种插件的配置文件散落在系统的各个位置,不利于维护和备份, 另一方面是 OpenWRT 本身阉割了很多 Linux 的功能,比如我一直没有找到方法用 VSCode 连接 OpenWRT 的方法。 综上所述,我决定自建一个 Linux 网关,最开始我其实是想顺便把 iKuai 也给去除掉的, 但是后来发现 iKuai 的许多功能用纯 Linux 实现比较麻烦而且也没什么优势,所以最终方案是 iKuai+ArchLinux 双路由的方案。
目录
搭建思路
iKuai+ArchLinux 双路由的方案,即 iKuai 作为主路由,主要负责拨号和 DHCP, ArchLinux 作为旁路由,负责运行各种服务(目前包括 DNS 和代理)。
ArchLinux 相比 OpenWRT 是更加完整的 Linux 系统,我们只需要像使用普通 Linux 一样使用它即可。 实际上,你用其他任何 Linux 发行版都可以,比如 Debian、Ubuntu 等,但是 ArchLinux 的包管理器对我目前使用需求来讲更加方便。
搭建方案
我使用的是 ArchLinux,可以使用下面命令安装一些必要的包:
echo "Initializing pacman keyring"
pacman-key --init
pacman-key --populate archlinux
pacman-key --refresh-keys
echo "Setting up pacman mirrorlist"
pacman -S --noconfirm --needed reflector
reflector --save /etc/pacman.d/mirrorlist --country China --protocol https --latest 5
echo "Installing basic tools"
pacman -S --noconfirm --needed base-devel vim git wget unzip cronie
pacman -S --noconfirm --needed iproute2 dnsutils lsof dhclient termshark
echo "Installing paru"
git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si
cd ..
rm -rf paru
由于 paru 需要使用非 root 用户,所以需要创建一个非 root 用户,然后使用这个用户安装其他所需要的包:
paru -S --noconfirm --needed go-yq smartdns mosdns-bin metacubexd mihomo
详细的配置文件可以参考我的项目, 你可以通过下面的命令直接使用我的配置文件,也可以根据自己的需求进行修改
cd /root
git clone https://github.com/zrr1999/system-install-scripts
cd system-install-scripts
sudo cp -r root-gateway/* /
sudo bash /usr/share/mosdns/update.sh
sudo bash /usr/share/mihomo/update.sh
ip rule add fwmark 0x161 lookup 100
ip rule add fwmark 0x162 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
最后使用 systemctl 启动这些服务:
systemctl enable mosdns
systemctl start mosdns
systemctl enable smartdns
systemctl start smartdns
systemctl enable mihomo
systemctl start mihomo
systemctl enable nftables
systemctl start nftables
如果不确定这些服务是否启动成功,可以使用以下命令检查:
systemctl status mosdns
systemctl status smartdns
systemctl status mihomo
systemctl status nftables
有些服务可能需要定期更新(例如国内 IP 库),你可以使用以下命令创建定时任务:
(crontab -l 2>/dev/null; echo "0 3 1 * * bash /usr/share/mosdns/update.sh") | crontab
(crontab -l 2>/dev/null; echo "3 3 1 * * systemctl restart mosdns") | crontab
(crontab -l 2>/dev/null; echo "6 3 1 * * bash /usr/share/mihomo/update.sh") | crontab
(crontab -l 2>/dev/null; echo "9 3 1 * * systemctl restart mihomo") | crontab
nftables 配置
nftables 的配置文件位于 /etc/nftables.conf
,
完整的内容如下:
#!/usr/sbin/nft -f
flush ruleset
define proxy-ip = {
# fakeip
198.18.0.0/16,
# telegram
91.108.0.0/16,
109.239.140.0/24,
149.154.160.0/20
}
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy accept;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table inet nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
tcp dport 53 redirect to :5335
udp dport 53 redirect to :5335
}
chain output {
type nat hook output priority 0; policy accept;
ip daddr 127.0.0.0/24 tcp dport 53 redirect to :5335
ip daddr 127.0.0.0/24 udp dport 53 redirect to :5335
}
chain postrouting {
type nat hook postrouting priority 0; policy accept;
}
}
table ip mangle{
chain proxy {
meta mark 0x162 return
ip daddr $proxy-ip ip protocol {udp, tcp} mark set 0x162 tproxy to 127.0.0.1:7894
}
chain proxy_output {
ip daddr $proxy-ip ip protocol {udp, tcp} mark set 0x161
}
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
jump proxy
}
chain output {
type route hook output priority mangle;policy accept;
jump proxy_output
}
}
这里主要做了两件事,转发 DNS 和配置透明代理。
转发 DNS
对于本地流量,我们通过 ip daddr 127.0.0.0/24 tcp dport 53 redirect to :5335
和 ip daddr 127.0.0.0/24 udp dport 53 redirect to :5335
将流量转发到 MosDNS,
对于路由流量,我们通过 tcp dport 53 redirect to :5335
和 udp dport 53 redirect to :5335
将流量转发到 MosDNS。
配置透明代理
对于本地出站流量,我们通过 ip daddr $proxy-ip ip protocol {udp, tcp} mark set 0x161
对流量进行标记,0x161
表示需要代理的本地出站流量,
因为我们添加了 ip rule add fwmark 0x161 lookup 100
,这些流量会被重新路由到环回地址进行后续处理。
对于其他流量,我们通过 ip daddr $proxy-ip ip protocol {udp, tcp} mark set 0x162 tproxy to 127.0.0.1:7894
直接将流量的透明代理设置成 mihomo,
同样因为我们添加了 ip rule add fwmark 0x162 lookup 100
,这些流量会被重新路由到环回地址进行后续处理,这样 mihomo 才可以接收到这些流量并进行代理。