使用linux纯手工搭一台五网口软路由
使用linux纯手工搭一台五网口软路由
来源 https://mp.weixin.qq.com/s/60luwRm0s4InJYdcvBDD6g
纯手工搭一台五网口软路由

会用 ip 看网卡、用 systemctl 管服务,就可以跟着这篇文章,把一台五网口小主机配成软路由。我们从装好 Linux 的机器开始,逐项配置,再用命令看看内核实际做了什么。
系统刚装好时,五个网口仍是五个独立接口。我们要让一个口接上游,另四个口组成内网:在内核里建桥,给桥设置网关地址,开启 IP 转发,再配置防火墙和出站地址转换。
下面假设 Linux 能看到五张独立网卡:enp1s0 接 WAN,通过上游 DHCP 取地址;enp2s0 到 enp5s0 是四个 LAN 口,加入 br0;网关地址 192.168.50.1/24 配在 br0 上。客户端通过 dnsmasq 获取地址、默认网关和 DNS。配置以 Debian 系为例,文中的地址和输出是教学示意,没有在某台五口机器上实测吞吐。
五个物理口,内核里是两种角色

机身上并排的五个插孔,配置时要分成两组:WAN 独立接上游,四个 LAN 口加入同一个二层广播域。br0 是内核里的 Linux bridge,负责在四个 LAN 口之间转发以太网帧。WAN 留在桥外;把它也加进去,上游和内网就会直接连成同一张二层网。
网关地址配在桥接口上。 这里的桥叫 br0。客户端从任意 LAN 口接入,都使用 192.168.50.1 作为网关,由同一个 DHCP 服务分配 192.168.50.0/24 网段的地址。接在 LAN4 上的无线 AP 使用桥接/AP 模式,关闭自己的 DHCP 与 NAT;无线设备也会进入这张内网。
前提是 Linux 确实能看到五个独立接口。有些设备用交换芯片管理多个插孔,系统显示的可能是 DSA 端口,也可能少于五个网卡接口。动手前先用 ip -br link 对照插孔和接口名。LAN 间的转发能否交给交换芯片,还取决于硬件与驱动;五个插孔本身不保证硬件线速。
选机器时还要看网卡驱动、散热、电源和系统盘的可靠性。WAN、LAN 的速率由链路双方协商;PPPoE、VPN、流量整形和连接数也会影响 CPU 负担。内存与磁盘要给日志、更新和连接跟踪留余量。
从 LAN1 进来,数据会走哪条路

LAN1 上的电脑访问 LAN2 上的 NAS:电脑地址 192.168.50.23,NAS 地址 192.168.50.50,同属 192.168.50.0/24。电脑通过 ARP 找到 NAS 的 MAC,发出的以太网帧直接以 NAS 的 MAC 为目的。
帧进入 LAN1 网卡后,驱动从接收队列取包。常见网卡由中断触发 NAPI 轮询,内核再用 sk_buff(简称 skb)携带数据和元信息。bridge 记住帧的源 MAC 来自 LAN1,然后用目的 MAC 查 FDB。查到 NAS 位于 LAN2,帧就从 LAN2 发出;还没学到目的 MAC,或者收到广播帧时,bridge 可能向其他 LAN 口泛洪。WAN 不在 br0 内,不会收到这些桥接帧。
LAN 口之间的帧由 bridge 转发,不经过这里配置的 IPv4 路由和 SNAT。 两台设备若接在 LAN1 外面的同一台交换机上,帧甚至不会进入软路由。ip_forward=1 控制三层转发,不影响这段桥接通信。
这里没有配置 nftables 的 bridge family 规则,也没有用 br_netfilter 把桥包送入 IP 过滤钩子。虚拟化平台若启用了这些功能,实际经过的过滤规则会有所不同。要隔离四个 LAN 口,需要另设 VLAN 或桥过滤规则。
电脑访问外网时,目标 IP 不在本地网段。电脑把帧交给默认网关 192.168.50.1;帧的目的 MAC 是 br0 的地址,bridge 便将它交给本机 IPv4 栈。随后内核关联连接跟踪记录、查路由、经过转发防火墙,最后在 WAN 出口做 SNAT。目的 MAC 指向 NAS,走桥转发;指向网关,才进入本机的三层处理。
哪些是软件,哪些在内核里处理包

图的上半部是用户态程序。systemd-networkd 读取 .network 和 .netdev 文件,通过 rtnetlink 告诉内核哪些口加入 br0,网关地址和路由怎样设置。nft 把防火墙规则写进 nf_tables。dnsmasq 处理发往网关的 DHCP、DNS 请求;这类请求进入本机的 input 路径,响应由 output 发出。平时经过网关的转发流量由内核处理,不会逐包交给这三个程序。
图的下半部画了桥内通信、LAN 出站和 WAN 回包。三条路径都从网卡驱动开始,后续处理由帧的去向决定。这里按普通内核路径绘制,没有启用 XDP、flowtable 快路径或交换芯片卸载;启用这些功能后,有些包会绕过图中的部分步骤。
看图时记住三个查找:FDB 按目的 MAC 选桥端口,FIB 按目的 IP 选三层出口,邻居表把下一跳 IP 解析成 MAC。 它们处理不同的地址。比如回包要送给 192.168.50.23,内核先通过邻居表找到客户端 MAC,bridge 再从 FDB 找到 LAN1。
后面配置好网口后,可以用 networkctl、ip -br addr 和 bridge link 查接口归属,用 bridge fdb show br br0 查 MAC 学习结果。sysctl net.ipv4.ip_forward 查看三层转发开关;nft list ruleset 看过滤与 SNAT;conntrack -L 查看内核记录的连接。排查时按数据包经过的顺序查,比盯着某个服务是否“运行中”更有用。
从零配置:先建立桥,再给网关地址
下面示例在 Debian 系最小安装上以 root 执行。先在本机控制台用 ip -br link 和拔插网线核对五个接口名;远程改 WAN 或防火墙很容易切断当前 SSH。安装 nftables、dnsmasq、conntrack 后,再开始改网络:
apt update
apt install nftables dnsmasq conntrack
先确认谁在管理网口
这里用 systemd-networkd 管网口。桥设备、成员口和 WAN 地址都写在 .netdev、.network 文件里,打开文件就能对照配置。NetworkManager 也能完成同样的工作;迁移时要确保每个接口只由一个程序管理。
在改文件前先看当前状态:
systemctl is-active NetworkManager
systemctl is-active systemd-networkd
systemctl is-active networking
nmcli device status
networkctl status enp1s0
没有安装 NetworkManager 时,nmcli 可能不存在;单看某个服务显示 active 也不能证明它接管了这五个口。重点核对 nmcli 中五口是已连接还是 unmanaged、networkctl 是否将接口标为 unmanaged,以及 /etc/network/interfaces 和 /etc/network/interfaces.d/ 是否给这些口写了 auto/iface 配置。
若五个口正由 NetworkManager 管理,先备份其连接配置,并在本机控制台完成移交。可以用独立配置片段让 NetworkManager 持久忽略这些接口及即将创建的桥:
# /etc/NetworkManager/conf.d/90-router-unmanaged.conf
[keyfile]
unmanaged-devices=interface-name:enp1s0;interface-name:enp2s0;interface-name:enp3s0;interface-name:enp4s0;interface-name:enp5s0;interface-name:br0
先写好这个片段,等下文四份 systemd-networkd 文件也备齐,再在本机控制台执行 nmcli general reload conf 使 NetworkManager 放手,紧接着启用 systemd-networkd,然后复查 nmcli device status。若由 ifupdown 管理,则备份并撤下这五个口在 /etc/network/interfaces 或 interfaces.d/ 中的对应段落,保留 lo 等其他既有配置。不通时从本机控制台恢复备份;不要在仍依赖该 WAN 的远程 SSH 会话中做移交。
WAN 保持独立,使用 DHCPv4:
# /etc/systemd/network/10-wan.network
[Match]
Name=enp1s0
[Network]
DHCP=ipv4
IPv6AcceptRA=no
创建内核桥设备 br0,再把四个物理口交给它。Name= 可列出多个接口名;这四个口都不单独配置 IPv4 地址。
# /etc/systemd/network/15-br0.netdev
[NetDev]
Name=br0
Kind=bridge
# /etc/systemd/network/20-lan-ports.network
[Match]
Name=enp2s0 enp3s0 enp4s0 enp5s0
[Network]
Bridge=br0
IPv6AcceptRA=no
网关地址只配在桥接口上,不为 LAN 设置默认路由:
# /etc/systemd/network/21-br0.network
[Match]
Name=br0
[Network]
Address=192.168.50.1/24
IPv6AcceptRA=no
这四个文件配置的是 IPv4 网关。IPv6AcceptRA=no 让接口忽略 IPv6 路由通告;IPv6 协议栈仍在,链路本地地址也可能存在。上游若提供 IPv6,还要配置 WAN 的 RA 或前缀委派、向 LAN 发布前缀、IPv6 转发和防火墙。这里暂不处理 IPv6 上网。
确认原有管理器不再接管这五口后,执行 systemctl enable --now systemd-networkd。若服务原本已运行,改完文件需要 networkctl reload 并重新配置受影响接口,或在本机控制台重启服务。检查 networkctl status br0、bridge link 和 ip -4 route:四个 LAN 应显示桥主设备为 br0,192.168.50.1/24 应在 br0,默认路由应来自 WAN 的 DHCP。若 nmcli 仍显示五口由 NetworkManager 管理,先停下来解决归属冲突。上游若要求 PPPoE、静态 IP 或带标签的 VLAN,先替换 WAN 配置;不能照搬 DHCP 示例。
四个 LAN 口已经能通过桥互通。要让发给网关的 IP 包继续从 WAN 出去,再打开 IPv4 转发:
sysctl -w net.ipv4.ip_forward=1
printf 'net.ipv4.ip_forward=1\n' > /etc/sysctl.d/90-router.conf
sysctl net.ipv4.ip_forward
sysctl -w 立即生效,配置文件供重启时读取。现在先读回一次,重启后再查一次。防火墙和 SNAT 还需按下一节配置。
配置 WAN 出口的过滤和 SNAT

LAN1 收到发往外网的帧后,网卡驱动经常见的 NAPI 接收流程将其交给 bridge。帧的目的 MAC 是网关,br0 因而把它交给本机 IP 栈。Netfilter 在 PREROUTING 阶段关联 conntrack 记录,FIB 随后按目的 IP 查出 WAN 这条路。
包经过 FORWARD 过滤,转发时 TTL 减一。过滤规则放行后,POSTROUTING 的 masquerade 建立 SNAT 映射,把私网源地址换成 WAN 当前地址。WAN 侧邻居表查出上游下一跳的 MAC,网卡驱动据此发出新的以太网帧。FORWARD 没放行,包到不了出口;缺少 SNAT,上游若没有返回内网的路由,回包就找不到客户端。

图里画的是LAN 客户端发起连接后的回包。WAN 网卡驱动收包后,连接跟踪在 PREROUTING 阶段按已有 SNAT 映射,把目的 IP 还原为 192.168.50.23。然后 FIB 查到客户端位于 br0 直连网段,FORWARD 中的 ct state established,related accept 放行回包。这里无需另写 WAN 到 LAN 的 DNAT 规则。
包到达 br0 后,ARP/邻居表根据客户端 IP 找到它的 MAC,bridge 再从 FDB 查到 LAN1 物理口,由 LAN1 驱动发帧。公网主机若主动发起一条新连接,既没有现成 NAT 映射,FORWARD 规则也不会放行它,因此进不了 LAN。
把下面的规则保存为 /etc/nftables.conf。input 处理发给网关的 DHCP、DNS、SSH;forward 控制 LAN 与 WAN 之间的转发;postrouting 在包离开 WAN 前做源 NAT。LAN 口之间的桥接帧不经过这条 inet forward 规则。
flush ruleset
define WAN = "enp1s0"
define LAN_NET = 192.168.50.0/24
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state invalid drop
ct state established,related accept
iifname $WAN udp sport 67 udp dport 68 accept
iifname "br0" udp dport 67 accept
iifname "br0" udp dport 53 accept
iifname "br0" tcp dport 53 accept
iifname "br0" tcp dport 22 accept
iifname "br0" ip protocol icmp accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state invalid drop
ct state established,related accept
iifname "br0" oifname $WAN ip saddr $LAN_NET counter accept
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr $LAN_NET oifname $WAN counter masquerade
}
}
input 链默认拒绝发往网关本机的新流量,规则从上到下读:lo 放行回环通信;invalid 丢弃无法正常归入连接的包;established,related 允许已有连接的回包和关联报文。
$WAN udp sport 67 udp dport 68 对应上游 DHCPv4 服务器发给 WAN DHCP 客户端的应答。部分客户端的实际收包路径可能不依赖这条 input 规则,是否拿到租约应看 networkctl 和 WAN 地址。br0 的 UDP 67 留给本机 DHCP 服务,UDP/TCP 53 留给 DNS。
TCP 22 只允许 LAN 管理 SSH,IPv4 ICMP 方便 LAN 侧诊断网关。规则没有开放 WAN 侧的 SSH 或 DNS,也没有额外设置 output 链来限制网关主动发出的包。
WAN 经 DHCP 获取地址时,masquerade 使用当前出口地址,属于动态 SNAT。假如 WAN 有固定地址,可以把最后一条改为显式 snat to <WAN固定IPv4地址>,但具体地址必须真实存在于出口方案中。SNAT 改写的是源地址,不负责放行;LAN→WAN 的许可来自 forward。上游若给 WAN 的仍是私网地址,这台软路由照样可以 masquerade,但会形成上游再做一次 NAT 的“双重 NAT”,不能据此宣称拿到了公网入站能力。
先用 nft -c -f /etc/nftables.conf 检查语法,再用 nft -f /etc/nftables.conf 加载,并执行 systemctl enable nftables 设置开机加载。文件开头的 flush ruleset 会清除已有 nftables 规则;如果机器同时跑 Docker、虚拟化或别的防火墙管理器,必须先梳理规则所有权,不能直接覆盖。
DHCP 和 DNS 只绑定在 br0
让 dnsmasq 监听 br0。四个 LAN 口处在同一个桥里,客户端从任何一个口接入,都可以向网关请求 192.168.50.0/24 网段的地址。
# /etc/dnsmasq.d/lan.conf
interface=br0
bind-interfaces
dhcp-range=192.168.50.100,192.168.50.199,12h
dhcp-option=option:router,192.168.50.1
dhcp-option=option:dns-server,192.168.50.1
no-resolv
server=1.1.1.1
server=9.9.9.9
上游 DNS 地址只是教学示例,可按实际网络替换。no-resolv 使 dnsmasq 不读本机 resolv.conf,避免意外指回自己。检查 53 端口是否被其他 DNS 服务占用、LAN 是否还有第二个 DHCP 服务器,然后用 dnsmasq --test 检查配置,执行 systemctl enable --now dnsmasq;若服务已经运行,修改后再用 systemctl restart dnsmasq 重新加载。AP 如需接入 LAN4,应关闭 AP 自己的路由、NAT 与 DHCP 功能。
用命令逐层验收:先桥,再路由,最后 DNS
下面只列出预期会看到的关键字段,并非某台机器的实测记录。接口序号、WAN 地址、客户端 MAC、计数值和 DNS 答案都会变化。
先在网关上查 br0 和四个桥成员:
ip -br addr show br0
bridge link show
四个 LAN 口都接着已启动的设备、链路已协商成功时,预期能找到这样的字段:
br0 UP 192.168.50.1/24
enp2s0 ... master br0 ... state forwarding
enp3s0 ... master br0 ... state forwarding
enp4s0 ... master br0 ... state forwarding
enp5s0 ... master br0 ... state forwarding
没有插线的 LAN 口可能显示 state disabled,但仍应有 master br0。br0 没有地址,查 .netdev 是否创建成功以及 21-br0.network 是否匹配;缺少某个 LAN 成员,查接口名和 20-lan-ports.network。电脑与 NAS 分接不同 LAN 口并互相访问后,运行 bridge fdb show br br0,应看到客户端 MAC 学到相应物理口。若两台终端接在外部同一交换机上,它们的通信未必进入本机,不能用缺少 FDB 项直接断定桥坏了。
想核对回包最后的两步,可让 LAN1 客户端访问外网后,在网关上并排看邻居表与 FDB:
ip -4 neigh show dev br0
bridge fdb show br br0
按前面的示例地址,关键字段会接近 192.168.50.23 dev br0 lladdr <客户端MAC>,以及 <客户端MAC> dev enp2s0 master br0。前者记录 IP→MAC,后者记录 MAC→物理口;邻居状态和具体 MAC 会随时间变化。
再核对三层出口与转发开关:
ip -4 route show
sysctl net.ipv4.ip_forward
预期输出的关键部分如下,其中尖括号是说明性占位符,不是命令会原样打印的字:
192.168.50.0/24 dev br0 ... src 192.168.50.1
default via <上游网关> dev enp1s0 ...
net.ipv4.ip_forward = 1
默认路由中的上游网关由 WAN 的 DHCP 决定,不应填写成 192.168.50.1。如果只有直连路由、没有默认路由,先查 WAN 的 DHCP 或上游连接,不要去改 SNAT。
接着核对规则和计数:
nft -c -f /etc/nftables.conf
nft list chain inet filter forward
nft list chain ip nat postrouting
语法检查成功时,第一条命令通常没有输出,退出状态为 0。查看后两条命令的结果时,分别核对:
inet filter forward中有从br0到enp1s0、源网段为192.168.50.0/24的counter accept规则。ip nat postrouting中有同一源网段、从enp1s0出口执行的counter masquerade规则。
客户端新建外网连接后,两处 counter packets 的数字应增加。NAT 链主要在连接建立映射时命中,它的包计数不能当成整条连接的逐包吞吐量。
最后在接入任一 LAN 口的 Linux 客户端上检查:
ip -4 addr
ip -4 route
ping -c 1 192.168.50.1
ping -c 1 1.1.1.1
getent ahostsv4 example.com
预期客户端拿到 192.168.50.100~192.168.50.199 范围内的地址,默认路由指向 192.168.50.1;能到网关、能到外部 IP,最后能返回域名的 IPv4 地址。这里的外部 IP 与域名仅作连通性示例,某些网络会拦 ICMP,单独一次 ping 失败不足以证明路由错误。能到网关却不能出网,查 WAN、转发和防火墙;能到外部 IP 却不能解析域名,再查 dnsmasq、客户端 DNS 设置与上游 DNS。
常见现象,先查这一层
br0没有192.168.50.1/24:查15-br0.netdev是否创建桥、21-br0.network是否匹配,及是否还有别的管理器给桥改地址。- 某个 LAN 口没有
master br0:核对实际接口名、20-lan-ports.network的Name=列表和该口是否被别的管理器接管。无网线时state disabled不等于没入桥。 - 只有
192.168.50.0/24直连路由,没有默认路由:先查 WAN 线缆、上游 DHCP、10-wan.network;此时改 SNAT 不会补出默认路由。 - 客户端外网新连接发起后,
forward规则计数不增:先确认客户端默认网关、ip_forward=1、WAN 路由出口以及规则中的br0、enp1s0和源网段。单纯 LAN 到 LAN 流量本来就不增加这个计数。 forward有命中而masquerade始终不增:用新连接重试,再查postrouting规则的出口接口和源网段;NAT 链计数只反映建立映射时的命中。- 外部 IP 可达但域名不通:先确认客户端 DNS 指向
192.168.50.1,再查dnsmasq监听、53 端口冲突和上游 DNS。
到这里,四个 LAN 口已经组成一张二层网,WAN 提供 IPv4 NAT 出口。IPv6 上网还需配置上游前缀、LAN 路由通告、转发和防火墙;要隔离 LAN 口,则需要 VLAN 或 bridge family 规则。PPPoE、多 WAN、VPN、流量整形和硬件卸载也各有自己的配置,遇到问题就沿着收包、桥接、路由、改写、发包逐段查。
=========== End

浙公网安备 33010602011771号