校园网环境下的OpenWrt NAT6配置¶
背景与前提¶
同济寝室的IPv6以前可以直接获取/64的前缀,可以支持路由器下所有支持IPv6的设备自动获取IPv6地址,非常方便。但前一阵子突然炸了,仔细检查后发现,现在寝室的IPv6只给/128的地址了,只能重新折腾一下路由器了 (又可以摸了) 。
基本完全参考[2]的方案,此方案是给不支持 DHCPv6-PD且设备需要认证才能联网的环境使用的,不过也没条件尝试其他情况……
假如你获取的IPv6地址不能获取前缀,即地址后有”/128“的后缀,按此文配置NAT6可能可以解决路由器下其他设备的IPv6访问问题。
正常情况家宽支持 IPv6,只要光猫处于桥接模式,直接使用 OpenWRT 默认设置即可完美支持 IPv6。
注意:根据原贴信息,需要确保使用的 OpenWRT 依然是基于 iptables 这一套做的防火墙,如果是基于 nftables 的 OpenWRT 原贴没有研究过 (我也没有) 。(比如官方 OpenWRT 从 22.03 版本开始切换为 nftables,国内修改版一般不会跟进这个修改。)
配置步骤¶
1. 安装必要的软件包¶
提示:某些第三方OpenWRT固件(如X-WRT、Lean固件)可能已预装这些软件包
2. 调整IPv6内网地址前缀¶
uci set network.globals.ula_prefix="$(uci get network.globals.ula_prefix | sed 's/^./d/')"
uci commit network
重要说明:
- 家庭宽带通常使用
2
开头的IPv6前缀- 此步骤仅适用于特殊网络环境,不推荐普通家庭网络使用
3. 配置DHCP服务器通告默认路由¶
4. 创建NAT6启动脚本¶
创建 /etc/init.d/nat6
文件:
(脚本内容请参考附录)
5. 设置脚本开机启动¶
6. 调整防火墙规则(可选)¶
uci set firewall.@rule["$(uci show firewall | grep 'Allow-ICMPv6-Forward' | cut -d'[' -f2 | cut -d']' -f1)"].enabled='0'
uci commit firewall
7. 修改系统内核转发配置¶
在 /etc/sysctl.conf
中添加或修改:
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
强烈建议:直接在
sysctl.conf
中修改,而非依赖其他脚本
8. 重启路由器¶
9. 备用方案:手动添加防火墙规则¶
如果重启后仍无法成功进行NAT6,可在OpenWRT防火墙规则中添加:
参考资料¶
附录¶
file-nat6¶
修改后的 NAT6 文件内容如下,换行符必须是LF
Tip
在更新的OpenWRT里(如OpenWRT 21),有一处地方又发生了变化
文件的 $(uci get "network.$WAN6_NAME.ifname")
可能需要改成 $(uci get "network.$WAN6_NAME.device")
才能生效
因此作者进一步改了脚本 改成了 $(uci get "network.$WAN6_NAME.device" || uci get "network.$WAN6_NAME.ifname")
或者可以直接把 WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.ifname")
替换为 WAN6_INTERFACE=wan
,其中wan为WAN6对应的网络设备名
#!/bin/sh /etc/rc.common
# NAT6 init script for OpenWrt // Depends on package: kmod-ipt-nat6
# edited by Sad Pencil at 2020-02-09
# replace route command with ip command to solve issues on new OpenWRT
# edited by Sad Pencil at 2021-11-29
# update line WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.device" || uci get "network.$WAN6_NAME.ifname")
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
WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.device" || uci get "network.$WAN6_NAME.ifname")
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=$(ip -6 route | grep -i '^default.*via' | grep -i -F "dev $WAN6_INTERFACE" | grep -i -o 'via.*' | wc -l)
done
logger -t NAT6 "Setting up NAT6"
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=$(ip -6 route | grep -i '^default.*via' | grep -i -F "dev $WAN6_INTERFACE" | grep -i -o 'via.*' | cut -d ' ' -f 2 | head -n 1)
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
ip -6 route add 2000::/3 via "$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
}