Linux 向局域网内设备分享网络

UPDATE 2022-09-03:

添加了在装有 ufw 时的配置。

======

UPDATE 2022-07-24:

将使用 firewalld 的方法添加到了 Arch Wiki - Internet sharing 上。

======

现某台 Linux 服务器 a 能访问网络 A 、 B 与 C ,希望能通过 a 使 C 下的其他设备访问网络 A 、 B 。具体配置如下:

服务器 a 上的设置

使用 nftables

首先允许网络转发:

# sysctl net.ipv4.ip_forward=1

再使用 nftables 建立一个新表,设置转发规则:

# nft add table inet nat
# nft 'add chain inet nat postrouting { type nat hook postrouting priority 100 ; }'
# nft add rule inet nat postrouting ip saddr 192.168.44.0/24 masquerade

值得一提的是, Arch Wiki 上的操作是指定 oifname ,但没有指定 ip saddr 。我的理解是:

  1. 不指定 source address 留下了安全风险
  2. 使用 oifname 假定了只有一个需要做 NAT 的网络区域。即使是只有一个区域,一般情况下机器在这个网络区域里也只有一个 IP 地址,这种情况下应该去设置 snat 而不是 masquerade 以获得更好的性能。

如果服务器上还装了 ufw

ufw 默认把所有 IP Forward 都 block 掉。网络上的大部分方法都是把默认策略改成 ACCEPT 。。我们装防火墙是为了防止攻击的,这种引入其他风险的策略听上去就有很大问题。 ufw 的用户界面应该是没有提供相关选项,我们需要手工写 iptables 策略(是的, ufw 用 iptables ,导致我们同时写了 nftables 规则和 iptables 规则)

编辑 /etc/ufw/before.rules ,添加以下内容:

-A ufw-before-forward -s 192.168.44.0/24 -j ACCEPT

使用 firewalld

firewalld 的 external 区域应该是默认开启 masquerade ,意味着 firewalld 也会为我们开启网络转发,所以聚焦于 firewalld 的设置就好。

设置网口区域并检查设置:

# firewall-cmd --zone=external --change-interface=eno1 --permanent
# firewall-cmd --zone=external --change-interface=eno2 --permanent
# firewall-cmd --zone=internal --change-interface=eno3 --permanent
# firewall-cmd --zone=internal --set-target=ACCEPT --permanent
# firewall-cmd --reload
# firewall-cmd --get-active-zones

添加配置规则:

# firewall-cmd --zone=internal --permanent --add-rich-rule='rule family="ipv4" source address="192.168.44.0/24" masquerade'
# firewall-cmd --reload

网络 C 路由器上的配置

路由网关指向该服务器即可。

Router OS Route Config

后记

因为最开始忘记了网络出口的问题,导致折腾了很长时间也没明白出了什么问题。

firewalld 生成 nftables 表时,内容非常冗杂,但都有规则可循。但是前一段时间折腾 docker (仍然使用 iptables 后端配置网络,对 ipv6 支持还是很差)与 firewalld 的共存时留下了心理阴影,遂开始手工编写 nftables chain ,并在规则中加入 log 来排查问题,具体步骤可以参考 nftables wiki - Loggin traffic