OpenWRT 上实现 NPTv6 地址转换

比静态 NAT66 更稳定的 IPv6 NAT 解决方案

为什么 IPv6 时代还搞 NAT?

出于隐私考虑,我不希望一些设备直接获得公网 IPv6 前缀。部分 OpenWRT 用户遇到客户端设备的 IPv6 前缀不能及时更新导致的 IPv6 故障,通过 NAT 把前缀固定下来也能解决。有些人可能希望前缀固定下来以方便管理局域网设备。

静态 NAT66 简介

最简单的 IPv6 方案是静态 NAT66,类似于 IPv6 的 NAT,把局域网设备的多个 IPv6 地址,通过防火墙的 masquerade 功能多对一转换成路由器的 IPv6 地址。
在 OpenWRT Luci 网页界面 防火墙 中就可以设置。

但我个人使用经验静态 NAT66 并不是很稳定,时不时会遇到一些问题。

NPTv6 更稳定的选择

于是我改用 NPTv6 进行地址转换。NPTv6 是网段对网段的地址转换,把局域网设备的 IPv6 地址一对一转换成外部网段的地址。由于是一对一转换,没有多对一 NAT 转换的端口映射问题,NPTv6 外部是什么端口就直接发给内部设备的对应端口。我两年多时间使用 NPTv6 也一直很稳定,没有遇到过故障。


OpenWRT 22.03 版本后 fw4 防火墙下 NPTv6 配置方法

1. 安装依赖

提前安装好 jqnftables-json(脚本使用 grep/sed/awk 处理 json 不是不行,但远不如 jq 安全稳定):

1
opkg install jq nftables-json

2. 设置 ULA 前缀

在 Luci 界面 网络 → 接口 中设置好局域网内部使用的 ULA 前缀。 (此处 ULA 前缀仅为示例,实际操作请按自行需要设置)
并且在局域网接口的 高级设置 → IPv6 前缀过滤器 处选择使用这个 ULA 前缀。

3. 新建 NPTv6 脚本

新建一个 /opt/etc/nptv6.sh 文件(路径可自定义),内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/sh

set -x

LAN_PFX="$(uci -q get network.globals.ula_prefix)"

PD_PREFIX=$(ifstatus wan6 | jq -r '.["ipv6-prefix"][] | "\(.address)/\(.mask)"')

nft add rule inet fw4 srcnat oifname "wan" snat ip6 prefix to ip6 saddr map { "${LAN_PFX}" : "${PD_PREFIX}" }
nft add rule inet fw4 dstnat iifname "wan" dnat ip6 prefix to ip6 daddr map { "${PD_PREFIX}" : "${LAN_PFX}" }

一般来说,OpenWRT 的 WAN 接口名称都是 wanwan6,如有不同请自行修改脚本。

4. 配置防火墙

/etc/config/firewall 结尾添加以下内容:

1
2
3
4
5
config include
        option enabled '1'
        option type 'script'
        option path '/opt/etc/nptv6.sh'
        option fw4_compatible '1'

5. 重启防火墙

1
service firewall restart

此时 NPTv6 即可生效。如遇问题,可执行logread命令查看防火墙重启时的错误日志:

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计