Internet 共享
本文解释了如何将一台机器上的互联网连接共享给其他机器。
需求
充当服务器的机器应具有额外的网络设备,也称为网络接口。该网络设备需要与将要获得互联网访问权的机器建立功能性的数据链路层连接。
- 为了能够将互联网共享给多台机器,交换机可以提供数据链路层连接。
- 无线设备也可以向多台机器共享访问权,在这种情况下,请先参阅软件接入点。
- 如果你只共享给一台机器,交叉网线就足够了。如果两台计算机的以太网卡之一具有自动 MDI-X 功能,则不需要交叉网线,可以使用普通的以太网线。以 root 身份执行
ethtool interface | grep MDI命令有助于确定。即使该命令给出错误或未在任一台机器上找到任何信息,而你又没有交叉网线,你可能仍然可以继续。
配置
net0,连接到互联网的网络设备名为 internet0。所有配置都在服务器计算机上完成,除了最后一步#为客户端 PC 分配 IP 地址。
静态 IP 地址
在服务器计算机上,为连接到其他计算机的接口分配一个静态 IPv4 地址。该地址的前 3 个字节不能与另一个接口的字节完全相同,除非两个接口的网络掩码都严格大于 /24。
# ip link set up dev net0 # ip addr add 192.168.123.100/24 dev net0 # arbitrary address
要在启动时分配静态 IP,你可以使用网络管理器。
启用数据包转发
要检查当前的数据包转发设置,请运行
# sysctl -a | grep forward
你会注意到有关控制默认转发、按接口转发以及按接口区分 IPv4/IPv6 的选项。有关所有可用选项的详细描述,请参阅内核文档。
要启用 IPv4 和 IPv6 数据包转发,请配置 sysctl 来设置这些选项
net.ipv4.ip_forward = 1 net.ipv4.conf.all.forwarding = 1 net.ipv6.conf.all.forwarding = 1
net.ipv[46].conf.interface_name.forwarding=1 而不是。如果系统使用 systemd-networkd 来控制网络接口,则无法进行按接口设置 IPv4,即 systemd 逻辑会将任何配置的转发传播为 IPv4 的全局(所有接口)设置。建议的解决方法是使用防火墙在选择性接口上禁止再次转发。有关更多信息,请参阅 systemd.network(5) 手册页。在系统版本 220/221 中引入以尊重内核设置的 IPForward=kernel 语义已不再适用。[1] [2]
要使更改在重启后持久生效,请参阅 Sysctl#配置。您可以考虑将设置写入一个具有描述性文件名的文件,例如 /etc/sysctl.d/30-ipforward.conf。
之后,建议在重启后仔细检查转发是否按要求启用。
使用 systemd-networkd 进行数据包转发
如果你正在使用 systemd-networkd 来管理你的网络配置,你也可以在重启后持久化这些设置
/etc/systemd/network/20-lan.network
[Network] IPv4Forwarding=yes ...
这实际上设置了与上一节中提到的 net.ipv[46].conf.interface_name.forwarding=1 相同的选项。对于 IPv6,配置是 IPv6Forwarding=yes。
IPv6Forwarding 选项的行为与文档不符,请参阅 [3]。这仅为特定接口设置了数据包转发。为了使互联网共享正常工作,你需要为应该在其中路由流量的所有接口(通常是你的 lan 和 wan 接口)启用数据包转发。
另见 systemd-networkd#[Network][链接已损坏: 无效的节]。
启用 NAT
除了此处列出的方法外,还可以使用 ufw 来设置 NAT。
使用 iptables
安装 iptables 包。使用 iptables 启用 NAT
# iptables -t nat -A POSTROUTING -o internet0 -j MASQUERADE # iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # iptables -A FORWARD -i net0 -o internet0 -j ACCEPT
如果你安装了 docker,请使用 -I DOCKER-USER 而不是 -A FORWARD。[4]
# iptables -t nat -A POSTROUTING -o internet0 -j MASQUERADE # iptables -I DOCKER-USER 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # iptables -I DOCKER-USER 2 -i net0 -o internet0 -j ACCEPT
如果通过 PPPoE 连接,请将 mss 限制为 pmtu 以防止分片
# iptables -t mangle -A FORWARD -o ppp0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
有关更多信息,请阅读 iptables 文章(尤其是保存规则和在启动时自动应用它)。还有一个关于 iptables 的优秀指南 简单的状态防火墙。
使用 nftables
安装 nftables 包。使用 nftables 启用 NAT,你需要在新/现有表中创建 postrouting 链
# nft add table inet nat
# nft add chain inet nat postrouting '{ type nat hook postrouting priority srcnat ; }'
之后,你需要为 internet0 上的 net0 地址进行伪装
# nft add rule inet nat postrouting oifname internet0 masquerade
许多防火墙配置,例如 默认的 /etc/nftables.conf,将 'filter' 表的 'forward' 链的默认策略设置为 'drop'。在这种情况下,你需要规则来允许转发 NAT 流量
# nft add rule inet filter forward ct state related,established accept # nft add rule inet filter forward iifname net0 oifname internet0 accept
你可以在 nftables Wiki 中找到更多关于 nftables 中 NAT 的信息。如果你想使这些更改永久生效,请遵循 nftables 上的说明。
使用 firewalld
安装 firewalld 包。 firewalld 是一个防火墙守护进程,它依赖于 nftables 或 iptables。首先更改网络接口的 firewalld 区域
# firewall-cmd --zone=external --change-interface=internet0 --permanent # firewall-cmd --zone=internal --change-interface=net0 --permanent
然后添加一个新的策略,让流量在内部和外部区域之间流动
# firewall-cmd --permanent --new-policy int2ext # firewall-cmd --permanent --policy int2ext --add-ingress-zone internal # firewall-cmd --permanent --policy int2ext --add-egress-zone external # firewall-cmd --permanent --policy int2ext --set-target ACCEPT # firewall-cmd --reload
ACCEPT 更严格的策略规则,正如 firewalld 概念页面[5] 的 Firewall Rules 部分所示。例如,要只允许 192.168.2.0/24 中的节点访问互联网,请执行
firewall-cmd --permanent --policy int2ext --add-rich-rule='rule family=ipv4 source address=192.168.2.0/24 accept' 之后不要忘记重新加载规则
firewall-cmd --reload为客户端 PC 分配 IP 地址
如果你计划让多台机器定期使用此机器共享的互联网,那么安装一个DHCP服务器是个好主意。有关可用选项,请参阅Router#DNS 和 DHCP。然后在每台客户端 PC 上配置一个 DHCP 客户端,请参阅网络配置#网络管理器。
必须允许 UDP 端口 67 的入站连接以供 DHCP 服务器使用。还需要允许 UDP/TCP 端口 53 的入站连接以供 DNS 请求使用。
# iptables -I INPUT -p udp --dport 67 -i net0 -j ACCEPT # iptables -I INPUT -p udp --dport 53 -s 192.168.123.0/24 -j ACCEPT # iptables -I INPUT -p tcp --dport 53 -s 192.168.123.0/24 -j ACCEPT
或者使用 firewalld
# firewall-cmd --zone=internal --permanent --add-service dns # firewall-cmd --zone=internal --permanent --add-service dhcp # firewall-cmd --zone=internal --permanent --add-service dhcpv6
如果你不打算定期使用此设置,则可以改为手动为每个客户端添加 IP。
手动添加 IP
除了使用 DHCP 之外,还可以手动配置静态 IP 地址和通过 192.168.123.100 的默认路由。有许多工具可用于相应地配置网络。一个突出的例子是 ip(8),请参阅 网络配置#网络管理。或者,可以使用 .network 文件,请参阅 systemd-networkd#使用静态 IP 的有线适配器 来设置静态 IP。
为每个客户端配置 DNS 服务器,有关详细信息,请参阅 域名解析。
就这样。客户端 PC 现在应该可以访问互联网了。
故障排除
如果你能够连接两台 PC 但无法发送数据(例如,如果客户端 PC 向服务器 PC 发出 DHCP 请求,服务器 PC 收到请求并向客户端提供 IP,但客户端不接受,而是超时),请检查你是否没有其他 iptables 规则 干扰。
客户端无法访问互联网或无法连接
症状可能还包括:ping 主机时客户端显示 host is down,ping 外部 LAN 设备(应由 NAT 转发)时显示 no route to host 或 Destination Host Unreachable,DHCP 响应未跨越桥接接口,等等。
已知 docker 可能导致这些问题。只需禁用 docker.service 和 docker.socket 即可解决此问题。
已连接的第二台 PC 无法使用桥接 LAN
第一台 PC 有两个 LAN。第二台 PC 有一个 LAN 并连接到第一台 PC。假设第二台 PC 在桥接接口后将所有访问权限给予 LAN
# sysctl net.bridge.bridge-nf-filter-pppoe-tagged=0 # sysctl net.bridge.bridge-nf-filter-vlan-tagged=0 # sysctl net.bridge.bridge-nf-call-ip6tables=0 # sysctl net.bridge.bridge-nf-call-iptables=0 # sysctl net.bridge.bridge-nf-call-arptables=0
参见
- Xyne 的指南和脚本,用于启动带 DHCP 和 DNS 的子网
- 如果使用 NetworkManager,它也可以配置用于互联网共享。