OpenWRT 配置 NAT6

以前一直用的是 Padavan 自带的 NAPT66 实现 IPv6 转发。最近开始用 Lean 的 LEDE,实现 NAT6 的方法有所不同。

方案 A

关闭 Source Filter

SSH 连接后执行:

1
2
3
uci set network.wan6.sourcefilter=0
uci commit network
ifup wan6

设置 IPv6 ULA 前缀

打开「网络」-「接口」-「全局网络选项」-「IPv6 ULA 前缀」,将第一位的「f」改成「d」。

设置 LAN 的 DHCPv6 服务器

打开「网络」-「接口」-「LAN」-「DHCP 服务器」-「IPv6 设置」,勾选「总是通告默认路由」。

加入 NAT6 规则

打开「网络」-「防火墙」-「自定义规则」,末尾加入:

1
ip6tables -t nat -A POSTROUTING -o eth0.2 -j MASQUERADE

这里的 eth0.2 需要替换为 WAN6 接口的名称。

重启

重启测试。

如果遇到启动后不能连接 IPv6 的情况,手动重启防火墙即可。

方案 B

设置 IPv6 ULA 前缀

打开「网络」-「接口」-「全局网络选项」-「IPv6 ULA 前缀」,将第一位的「f」改成「d」。

设置 LAN 的 DHCPv6 服务器

打开「网络」-「接口」-「LAN」-「DHCP 服务器」-「IPv6 设置」,勾选「总是通告默认路由」。

创建 NAT6 服务脚本

编辑「/etc/init.d/nat6」,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/bin/sh /etc/rc.common
# NAT6 init script for OpenWrt // Depends on package: kmod-ipt-nat6

START=55

# Options
# -------

# Use temporary addresses (IPv6 privacy extensions) for outgoing connections? Yes: 1 / No: 0
PRIVACY=1

# Maximum number of attempts before this script will stop in case no IPv6 route is available
# This limits the execution time of the IPv6 route lookup to (MAX_TRIES+1)*(MAX_TRIES/2) seconds. The default (15) equals 120 seconds.
MAX_TRIES=15

# An initial delay (in seconds) helps to avoid looking for the IPv6 network too early. Ideally, the first probe is successful.
# This would be the case if the time passed between the system log messages "Probing IPv6 route" and "Setting up NAT6" is 1 second.
DELAY=5

# Logical interface name of outbound IPv6 connection
# There should be no need to modify this, unless you changed the default network interface names
# Edit by Vincent: I never changed my default network interface names, but still I have to change the WAN6_NAME to "wan" instead of "wan6"
WAN6_NAME="wan6"

# ---------------------------------------------------
# Options end here - no need to change anything below

boot() {
[ $DELAY -gt 0 ] && sleep $DELAY
logger -t NAT6 "Probing IPv6 route"
PROBE=0
COUNT=1
while [ $PROBE -eq 0 ]
do
if [ $COUNT -gt $MAX_TRIES ]
then
logger -t NAT6 "Fatal error: No IPv6 route found (reached retry limit)" && exit 1
fi
sleep $COUNT
COUNT=$((COUNT+1))
PROBE=$(route -A inet6 | grep -c '::/0')
done

logger -t NAT6 "Setting up NAT6"

WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.ifname")
if [ -z "$WAN6_INTERFACE" ] || [ ! -e "/sys/class/net/$WAN6_INTERFACE/" ] ; then
logger -t NAT6 "Fatal error: Lookup of $WAN6_NAME interface failed. Were the default interface names changed?" && exit 1
fi
WAN6_GATEWAY=$(route -A inet6 -e | grep "$WAN6_INTERFACE" | awk '/::\/0/{print $2; exit}')
if [ -z "$WAN6_GATEWAY" ] ; then
logger -t NAT6 "Fatal error: No IPv6 gateway for $WAN6_INTERFACE found" && exit 1
fi
LAN_ULA_PREFIX=$(uci get network.globals.ula_prefix)
if [ $(echo "$LAN_ULA_PREFIX" | grep -c -E "^([0-9a-fA-F]{4}):([0-9a-fA-F]{0,4}):") -ne 1 ] ; then
logger -t NAT6 "Fatal error: IPv6 ULA prefix $LAN_ULA_PREFIX seems invalid. Please verify that a prefix is set and valid." && exit 1
fi

ip6tables -t nat -I POSTROUTING -s "$LAN_ULA_PREFIX" -o "$WAN6_INTERFACE" -j MASQUERADE
if [ $? -eq 0 ] ; then
logger -t NAT6 "Added IPv6 masquerading rule to the firewall (Src: $LAN_ULA_PREFIX - Dst: $WAN6_INTERFACE)"
else
logger -t NAT6 "Fatal error: Failed to add IPv6 masquerading rule to the firewall (Src: $LAN_ULA_PREFIX - Dst: $WAN6_INTERFACE)" && exit 1
fi

route -A inet6 add 2000::/3 gw "$WAN6_GATEWAY" dev "$WAN6_INTERFACE"
if [ $? -eq 0 ] ; then
logger -t NAT6 "Added $WAN6_GATEWAY to routing table as gateway on $WAN6_INTERFACE for outgoing connections"
else
logger -t NAT6 "Error: Failed to add $WAN6_GATEWAY to routing table as gateway on $WAN6_INTERFACE for outgoing connections"
fi

if [ $PRIVACY -eq 1 ] ; then
echo 2 > "/proc/sys/net/ipv6/conf/$WAN6_INTERFACE/accept_ra"
if [ $? -eq 0 ] ; then
logger -t NAT6 "Accepting router advertisements on $WAN6_INTERFACE even if forwarding is enabled (required for temporary addresses)"
else
logger -t NAT6 "Error: Failed to change router advertisements accept policy on $WAN6_INTERFACE (required for temporary addresses)"
fi
echo 2 > "/proc/sys/net/ipv6/conf/$WAN6_INTERFACE/use_tempaddr"
if [ $? -eq 0 ] ; then
logger -t NAT6 "Using temporary addresses for outgoing connections on interface $WAN6_INTERFACE"
else
logger -t NAT6 "Error: Failed to enable temporary addresses for outgoing connections on interface $WAN6_INTERFACE"
fi
fi

exit 0
}

之后使用下面命令添加执行权限并打开开机自启。

1
2
chmod +x /etc/init.d/nat6
/etc/init.d/nat6 enable

开启 IPv6 转发

修改「/etc/sysctl.conf」文件,编辑或加入下面内容:

1
2
3
4
net.ipv6.conf.default.forwarding=2
net.ipv6.conf.all.forwarding=2
net.ipv6.conf.default.accept_ra=2
net.ipv6.conf.all.accept_ra=2

加入转发规则

打开「网络」-「防火墙」-「自定义规则」,末尾加入:

1
ip6tables -t nat -I POSTROUTING -s $(uci get network.globals.ula_prefix) -j MASQUERADE

重启路由器

之后 NAT6 就生效了,NAT6 的服务脚本头部的参数可以根据需要自行定制。