[NAS 系列第三弹]为局域网设备配置无感知的透明代理

记得我上篇文章中有提到：

本篇不解决网络问题，默认 docker 镜像等均可连接外网，如果不行请手动为镜像配置 HTTP_PROXY、HTTPS_PROXY。

今天这篇文章就来分享一下我的网络配置。经过配置后，可以让任何一台通过有线或无线方式连接到局域网中的设备，无需任何配置就可连接外网，并可以使用非常简单的语法做到 DNS 和流量分流。

整体思路是将 NAS 作为旁路网关，让 dhcp 返回的默认网关指向 NAS，在 NAS 侧配置代理工具。老样子，在开始之前写几条声明：

本文中提到的代理工具 dae 需要内核版本 >= 5.8，如不符合需要换用其它代理工具；

本人 NAS 网络使用 Network Manager 配置，其它工具请自行查找替代写法；

不同家庭的网络配置和结构不同，或许不能原样照搬，但基本原理相同；

ALL IN ONE, ALL IN BOOM !

网络结构

家里的网络结构如下图所示（原谅我拙劣的作图手法）：

可以看到我并没有单独的路由器，拨号、NAT、无线 AP 都由内置路由的光猫代劳，只需要把所有设备连接到光猫即可上网。

因为所有设备都在同个网段，实现代理非常简单，整体来说分为三个步骤：

把 NAS 的所有网口桥接（可跳过，主要是拓展有线接口）

固定光猫和 NAS 的 IP 地址

在 NAS 上配置代理和 IP 转发

修改 DHCP 服务器，将默认网关指向 NAS

下面展开说明。

桥接 NAS 的所有网口（可跳过）

我 NAS 的主板上自带一个网口，因为担心光猫网口不够用，所以单独购入了一块四口 pcie 网卡做桥接：

插上之后执行 ifconfig，发现我的五个网口编号依次是 enp3s0、enp4s0、enp5s0、enp6s0、enp7s0。使用 Network Manager 可以很方便地桥接网口：

Copy
# 新建一个网桥
sudo nmcli connection add type bridge ifname br0 stp no
# 把物理网口全加到网桥里
sudo nmcli connection add type bridge-slave ifname enp3s0 master br0
sudo nmcli connection add type bridge-slave ifname enp4s0 master br0
sudo nmcli connection add type bridge-slave ifname enp5s0 master br0
sudo nmcli connection add type bridge-slave ifname enp6s0 master br0
sudo nmcli connection add type bridge-slave ifname enp7s0 master br0

固定光猫和 NAS 的 IP 地址

光猫略过不表，因为其在一般情况下 IP 都是固定的（如 192.168.0.1、192.168.1.1），此处需要固定 NAS 的 IP 地址。

使用 sudo nmcli connection show 可以看到所有的连接，位于前面并且高亮的是活跃的连接：

如上图所示，一般使用最前面的连接就可以。

注：如果刚刚桥接了网口，那么桥接的 bridge-xx 默认不会启用，这种情况下应该使用 bridge-xx 而非最前面的连接。

以 bridge-br0 为例，固定 IP 地址的命令如下：

Copy
# 固定你的 ip 和网关（需要和光猫在同个网段）
sudo nmcli connection modify bridge-br0 ipv4.addresses 192.168.1.250/24 ipv4.gateway 192.168.1.1
# 使用你想要的 dns
sudo nmcli connection modify bridge-br0 ipv4.dns 119.29.29.29
# 调整 ipv4 地址分配方式为手动
sudo nmcli connection modify bridge-br0 ipv4.method manual
# reload 一下
sudo nmcli connection reload

注：同样对于刚刚桥接过的情况，这里还需要启用桥接的所有网口，停用现有 connection 并启用 bridge：

Copy
# 启用桥接的所有网口
sudo nmcli connection up bridge-slave-enp3s0
sudo nmcli connection up bridge-slave-enp4s0
sudo nmcli connection up bridge-slave-enp5s0
sudo nmcli connection up bridge-slave-enp6s0
sudo nmcli connection up bridge-slave-enp7s0
# 停用正在使用的 connection
sudo nmcli connection down Wired\ connection\ 6
# 启用刚刚配置好的 bridge
sudo nmcli connection up bridge-br0

在 NAS 上配置代理和 IP 转发

来到了最关键的一步，配置代理和 IP 转发。

IP 转发

首先启用 IP 转发，这将允许这台设备作为网关转发其它设备的流量：

Copy
sudo vim /etc/sysctl.d/30-ipforward.conf

# 写入如下内容并保存
net.ipv4.ip_forward=1
net.ipv6.conf.default.forwarding=1
net.ipv6.conf.all.forwarding=1

# 重载
sudo sysctl --system

代理

本篇使用的代理工具是 dae，实践中为了操作方便，往往使用带有 webui 的 daed：

在 Arch Linux 上安装非常简单，使用如下命令安装并自启动：

Copy
sudo pacman -S daed
sudo systemctl enable --now daed.service

打开 NAS 的 2023 端口，输入初始化的账号密码，就能看到主页面了：

整体的操作逻辑非常简单，在右下方添加订阅，并把订阅或节点拖动到左下方的群组中即可。在 DNS 和路由模块中点击编辑按钮即可展开配置，编写分流规则。

dae 的分流规则继承了 v2raya，语法简单明了，下面是我的 DNS 和路由规则样例：

Copy
# dns 规则

upstream {
googledns: 'tcp+udp://dns.google.com:53'
alidns: 'udp://dns.alidns.com:53'
}
routing {
request {
# 阻断广告的 dns 解析
qname(geosite:category-ads) -> reject
qname(geosite:category-ads-all) -> reject
# 默认使用 alidns 查询
fallback: alidns
}
response {
# 上游是 googledns 直接通过，避免回环
upstream(googledns) -> accept
# 非国内网站解析到了局域网 ip，认为是遇到 dns 污染，重新在 googledns 查一次
!qname(geosite:cn) && ip(geoip:private) -> googledns
# 其它情况直接 accept
fallback: accept
}
}

Copy
# 路由规则

# 在默认规则的基础上添加了 qbittorrent 的直连
pname(NetworkManager, systemd-resolved, qbittorrent-nox) -> direct
# 阻断广告连接
domain(geosite:category-ads, geosite:category-ads-all) -> block
# 一般梯子都不支持 ipv6，走直连
ipversion(6) -> direct
# 对于 chatgpt，走固定的节点组
domain(geosite:openai, regex: ".+\.openai$") -> chatgpt
# 广播地址、局域网地址和国内 ip，走直连
dip(224.0.0.0/3, 'ff00::/8', geoip:private, geoip:cn) -> direct
# steam、国内域名走直连
domain(geosite:steam@cn, geosite:cn, geosite:geolocation-cn) -> direct
# 未匹配，走代理
fallback: proxy

分流规则设置完毕后，需要在配置中设置需要绑定的接口。在旁路网关的使用场景中，LAN 和 WAN 中都应该添加当前活跃的接口（对于我来说是 br0），此外 LAN 口还可以添加一些其它需要代理的接口（如 docker0）：

其它选项一般不需要修改，点击最下面的提交，接着在主页右上角点击启动即可。

此时 NAS 和所有网关指向 NAS 的设备产生的流量均会被 dae 接管分流，实现了透明代理。

修改 DHCP 服务器，将默认网关指向 NAS

虽然现在网关指向 NAS 即可透明代理，但 DHCP 返回的网关仍然是 192.168.1.1（即光猫路由器的地址），接入到网络的设备需要手动修改网关才能成功代理。为了改变这种情况，需要调整 DHCP 服务器。

光猫路由器内提供的 DHCP 服务器没办法修改返回的网关地址，因此需要在 NAS 上启动一个 DHCP 服务器，并用其替代光猫路由器上的 DHCP 服务器。

在 NAS 上部署 DHCP 服务器

Linux 上可用的 DHCP 服务器有很多，个人选用的是 dhcpd 的继任者 kea，dnsmasq 也能实现同样的目的：

在 Arch Linux 中安装：

Copy
sudo pacman -S kea

在这里我们只需要替换掉 dhcp4 即可满足需求。参考官方文档编写 dhcp 配置如下：

Copy
{ "Dhcp4":

{
"interfaces-config": {
"interfaces": [ "br0" ]
},

"lease-database": {
"type": "memfile",
"lfc-interval": 3600
},

"valid-lifetime": 4000,

"subnet4": [
{
"pools": [ { "pool": "192.168.1.2 - 192.168.1.254" } ],
"subnet": "192.168.1.0/24",
"interface": "br0",
"option-data": [
{
"name": "domain-name-servers",
"data": "119.29.29.29"
},
{
"name": "routers",
"data": "192.168.1.250"
},
]
}
],
"loggers": [
{
"name": "kea-dhcp4",
"output_options": [
{
"output": "stdout"
}
],
"severity": "INFO"
}
]
}

}

将上述配置写入 /etc/kea/kea-dhcp4.conf，并启动 kea-dhcp4 服务：

Copy
sudo systemctl enable --now kea-dhcp4.service

接着登录光猫路由器的后台，关闭自带的 dhcp4 服务器：

现在随便使用某台有线或无线设备连接到网络中，查看 dhcp 是否正常工作：

看到路由器位置显示的地址是我们设置的 192.168.1.250，说明 NAS 上部署的 dhcp 工作正常。

至此配置完毕，大功告成。

参考资料

dae dns 文档

dae routing 文档

dae 配置示例

Arch Wiki - Network Bridge

Arch Wiki - Internet Sharing

Kea examples