处于某些奇妙的原因,我需要使用一台 Linux 来共享网络给其他设备使用,但 NetworkManager 不会设置 ipv6 的 NAT 功能,这导致我没办法在该网络在使用 IPv6 访问家里的飞牛或者其他设备,于是就自己手搓了一份脚本来实现这个功能。
基础信息如下:
| 网卡 |
ip |
作用 |
| eno1 |
10.20.0.1 |
出口网络 |
| enp2s0 |
192.168.123.1 |
共享网络 |
开启网络共享
NetworkManager 已经支持创建共享网络了,只用创建一个链接,将 IPv4 设置为共享即可。我使用的是 nmtui 命令编辑的链接,如果是使用 GNOME,可以直接在图形界面里将 IPv4 设置为共享,保存即可。
但是需要注意,这个功能依赖 dnsmasq 来提供 DHCP 和 DNS 服务,如果系统没有安装 dnsmasq,需要先安装它。
Radvd
/etc/radvd.conf 配置文件,为 enp2s0 接口广播 ULA 前缀 fd42:1234:5678::/64,并指定 RDNSS 服务器地址为 fd6d:d05e:e029::1。
interface enp2s0 { AdvSendAdvert on; MinRtrAdvInterval 30; MaxRtrAdvInterval 100; AdvDefaultPreference medium; AdvHomeAgentFlag off;
prefix fd42:1234:5678::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr on; };
RDNSS fd6d:d05e:e029::1 { AdvRDNSSLifetime 900; }; };
|
NetworkManager
使用这个脚本可以在 NetworkManager 创建的共享网络接口上实现 IPv4 和 IPv6 的 NAT 功能,同时配合 radvd 广播 IPv6 前缀。
/etc/NetworkManager/dispatcher.d/99-nm-share-firewall.sh 脚本内容如下:
#!/bin/bash
IF="$1" STATUS="$2"
PHYS_IF="eno1"
SHARE_IF="enp2s0"
SHARE_NET="192.168.123.0/24"
SHARE_IPV6="fd42:1234:5678::/64"
SHARE_IPV6_ADDR="fd42:1234:5678::1/64"
LOG_FILE="/var/log/nm-share-firewall.log"
log() { echo "[$(date)] $1" >> "$LOG_FILE" }
add_firewall() { log "Enabling IPv4/IPv6 forwarding and NAT for $SHARE_IF..."
sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv6.conf.all.forwarding=1
if ! ip -6 addr show dev "$SHARE_IF" | grep -q "${SHARE_IPV6_ADDR%/*}"; then ip -6 addr add "$SHARE_IPV6_ADDR" dev "$SHARE_IF" fi
if ! ip addr show dev "$SHARE_IF" | grep -q "inet 192.168.123"; then ip addr add 192.168.123.1/24 dev "$SHARE_IF" fi
iptables -A FORWARD -i "$SHARE_IF" -j ACCEPT iptables -A FORWARD -o "$SHARE_IF" -j ACCEPT
iptables -t nat -A POSTROUTING -o "$PHYS_IF" -s "$SHARE_NET" -j MASQUERADE
ip6tables -A FORWARD -i "$SHARE_IF" -j ACCEPT ip6tables -A FORWARD -o "$SHARE_IF" -j ACCEPT ip6tables -t nat -A POSTROUTING -o "$PHYS_IF" -s "$SHARE_IPV6" -j MASQUERADE
if systemctl is-active --quiet radvd; then systemctl restart radvd else systemctl start radvd fi
log "Firewall rules added (simple NAT-only mode)" }
remove_firewall() { log "Removing IPv4/IPv6 firewall rules for $SHARE_IF..."
iptables -D FORWARD -i "$SHARE_IF" -j ACCEPT 2>/dev/null iptables -D FORWARD -o "$SHARE_IF" -j ACCEPT 2>/dev/null iptables -t nat -D POSTROUTING -o "$PHYS_IF" -s "$SHARE_NET" -j MASQUERADE 2>/dev/null
ip6tables -D FORWARD -i "$SHARE_IF" -j ACCEPT 2>/dev/null ip6tables -D FORWARD -o "$SHARE_IF" -j ACCEPT 2>/dev/null ip6tables -t nat -D POSTROUTING -o "$PHYS_IF" -s "$SHARE_IPV6" -j MASQUERADE 2>/dev/null
systemctl stop radvd
log "Firewall rules removed" }
case "$STATUS" in up) if [ "$IF" == "$SHARE_IF" ]; then add_firewall fi ;; down) if [ "$IF" == "$SHARE_IF" ]; then remove_firewall fi ;; esac
exit 0
|
成果展示