4-Openwrt ipv6之NAT6
在实际使用过程有时候电信宽带可以下发给Wan口使用的ipv6地址,但是不下发给lan口使用的ipv6地址前缀。
这时候可以使用NAT6的方式,跟ipv4的NAT一样,有自己的内网地址,访问外部的时候经过NAT转化。ipv6也使用内网地址,根据ipv6的规则FD::/8开始的地址为内网地址。
IPv6的NAT关键在于
- 设置br-lan端口的ipv6的网段/前缀
- 设置ip6tables规则,将br-lan网段的数据包通过snat地址转换后发出
1. nat6配置
- 开启config配置
CONFIG_PACKAGE_ip6tables=y
CONFIG_PACKAGE_kmod-ipt-nat6=y
- 配置给br-lan端口的ipv6地址前缀,在netifd里面已经实现了一个uci配置值ula_prefix,将/etc/config/network里面的ula_prefix设置成fd开头的内网地址
config globals 'globals'
option ula_prefix 'fd00:eeee:eeee::/48'
- odhcpd服务器需要添加两个参数配置,ra_management和ra_default
config dhcp 'lan'
option interface 'lan'
option start '100'
option limit '150'
option leasetime '12h'
option dhcpv6 'server'
option ra 'server'
option ra_management '1'
option ra_default '1'
这两个值的含义在官网有给出解释
- ra_default设置成:总是通知默认路由器
- ra_management设置成:“NDP-Proxy” is disabled
ra_default integer 0 Override default route
0: default
1: ignore no public address
2: ignore all
ra_management integer 1 RA management mode
0: no M-Flag but A-Flag
1: both M and A
2: M but not A
- 根据对应的wan口interface添加br-lan网段的ip6tables规则
ip6tables -t nat "POSTROUTING" -s "$ula_prefix" -j MASQUERADE
对于ip6tables规则的设置,需要做一些校验等,这个在openwrt官网里面有给出一个方案就是masq6功能
原理相当于在firewall下面添加masq6开启的配置,然后添加nat6配置条目,当启动防火墙的时候会主动将/etc/firewall.nat6脚本拉起来。
# /etc/config/firewall
config zone
option name 'wan'
...
option masq6 '1' # Enable masquerading NAT6
option masq6_privacy '1' # Optionally enable IPv6 privacy extensions
config include 'nat6'
option path '/etc/firewall.nat6'
option reload '1'
/etc/firewall.nat6脚本里面就是实现ip6tables规则的设置等判断,脚本位于https://github.com/akatrevorjay/openwrt-masq6里面
#!/bin/sh
#
# Masquerading nat6 firewall.d script.
#
# Place as: /etc/firewall.d/with_reload/90-nat6.fw and make it executable.
#
# Then you can configure in /etc/config/firewall per zone, ala where you have:
# option masq 1
# Just drop this in beneath it:
# option masq6 1
# For IPv6 privacy (temporary addresses used for outgoing), also add:
# option masq6_privacy 1
#
# Hope it's useful!
#
# https://github.com/akatrevorjay/openwrt-masq6
# ~ trevorj <github@trevor.joynson.io>
#
set -eo pipefail
. /lib/functions.sh
. /lib/functions/network.sh
. /usr/share/libubox/jshn.sh
log() {
logger -t nat6 -s "$@"
}
get_ula_prefix() {
uci get network.globals.ula_prefix
}
validate_ula_prefix() {
local ula_prefix="$1"
if [ $(echo "$ula_prefix" | grep -c -E "^([0-9a-fA-F]{4}):([0-9a-fA-F]{0,4}):") -ne 1 ] ; then
log "Fatal error: IPv6 ULA ula_prefix=\"$ula_prefix\" seems invalid. Please verify that a ula_prefix is set and valid."
return 1
fi
}
ip6t() {
ip6tables "$@"
}
ip6t_ensure_append() {
if ! ip6t -C "$@" >/dev/null 2>&1; then
ip6t -A "$@"
fi
}
masq6_network() {
# $config contains the ID of the current section
local network_name="$1"
local device
network_get_device device "$network_name" || return 0
local done_net_dev
for done_net_dev in $DONE_NETWORK_DEVICES; do
if [[ "$done_net_dev" == "$device" ]]; then
log "Already configured device=\"$device\", so leaving as is."
return 0
fi
done
log "Found device=\"$device\" for network_name=\"$network_name\"."
if [ $zone_masq6_privacy -eq 1 ]; then
log "Enabling IPv6 temporary addresses for device=\"$device\"."
log "Accepting router advertisements on $device even if forwarding is enabled (required for temporary addresses)"
echo 2 > "/proc/sys/net/ipv6/conf/$device/accept_ra" \
|| log "Error: Failed to change router advertisements accept policy on $device (required for temporary addresses)"
log "Using temporary addresses for outgoing connections on interface $device"
echo 2 > "/proc/sys/net/ipv6/conf/$device/use_tempaddr" \
|| log "Error: Failed to enable temporary addresses for outgoing connections on interface $device"
fi
append DONE_NETWORK_DEVICES "$device"
}
handle_zone() {
# $config contains the ID of the current section
local config="$1"
local zone_name
config_get zone_name "$config" name
# Enable masquerading via NAT6?
local zone_masq6
config_get_bool zone_masq6 "$config" masq6 0
log "Firewall config=\"$config\" zone=\"$zone_name\" zone_masq6=\"$zone_masq6\"."
if [ $zone_masq6 -eq 0 ]; then
return 0
fi
# IPv6 privacy extensions: Use temporary addrs for outgoing connections?
local zone_masq6_privacy
config_get_bool zone_masq6_privacy "$config" masq6_privacy 1
log "Found firewall zone_name=\"$zone_name\" with zone_masq6=\"$zone_masq6\" zone_masq6_privacy=\"$zone_masq6_privacy\"."
log "Setting up masquerading nat6 for zone_name=\"$zone_name\" with zone_masq6_privacy=\"$zone_masq6_privacy\""
local ula_prefix=$(get_ula_prefix)
validate_ula_prefix "$ula_prefix" || return 1
local postrouting_chain="zone_${zone_name}_postrouting"
log "Ensuring ip6tables chain=\"$postrouting_chain\" contains our MASQUERADE."
if ! ip6t_ensure_append "$postrouting_chain" -t nat -s "$ula_prefix" -j MASQUERADE; then
# Some releases of OpenWrt just leave the nat table empty for some reason (version dependent?)
log "Could not find table=\"$postrouting_chain\", but yolo so adding to POSTROUTING directly."
ip6t_ensure_append "POSTROUTING" -t nat -s "$ula_prefix" -j MASQUERADE
fi
local DONE_NETWORK_DEVICES=""
config_list_foreach "$config" network masq6_network
log "Done setting up nat6 for zone=\"$zone_name\" on devices: $DONE_NETWORK_DEVICES"
}
main() {
config_load firewall
config_foreach handle_zone zone
}
main "$@"
- 为了方便启动和停止nat6,添加脚本/etc/init.d/znat6
#!/bin/sh /etc/rc.common
start()
{
local ipv6_enabled=$(uci -q get network.wan6.web_enabled)
if [ $ipv6_enabled == 1 ]; then
# Set the DHCPv6 server to always announce default router.
uci set dhcp.lan.ra_management='1'
uci set dhcp.lan.ra_default="1"
uci commit dhcp
/etc/init.d/odhcpd restart
# Enable the new masq6 option in your firewall on your upstream zone.
uci set firewall.wan.masq6='1'
uci set firewall.wan.masq6_privacy='1'
# Since masquerading is enabled, disable the redundant firewall rule ...Allow-ICMPv6-Forward....
uci set firewall.@rule["$(uci show firewall | grep 'Allow-ICMPv6-Forward' | cut -d'[' -f2 | cut -d']' -f1)"].enabled='0'
# Include the NAT6 firewall script in the configuration.
uci -q delete firewall.nat6
uci set firewall.nat6="include"
uci set firewall.nat6.path="/etc/firewall.nat6"
uci set firewall.nat6.reload="1"
uci commit firewall
/etc/init.d/firewall restart
fi
}
stop()
{
# reset the DHCPv6 server info
uci -q delete dhcp.lan.ra_management
uci -q delete dhcp.lan.ra_default
uci commit dhcp
/etc/init.d/odhcpd restart
# enable Allow-ICMPv6-Forward
uci set firewall.@rule["$(uci show firewall | grep 'Allow-ICMPv6-Forward' | cut -d'[' -f2 | cut -d']' -f1)"].enabled='1'
# disnable the new masq6 option in your firewall on your upstream zone.
uci set firewall.wan.masq6='0'
uci set firewall.wan.masq6_privacy='0'
uci commit firewall
/etc/init.d/firewall restart
}
查看nat6的firewall.nat6脚本可以发现最上面设置了set -eo pipefail
这么一条语句,就是指令执行有出错的时候就直接返回,不支持了。
2. nat6测试
在公司网络测试,公司是pppoe-wan拨号的,所以odhcp6c设置成dhcpv6,ifname为pppoe-wan
config interface 'wan6'
option def_ifname 'eth1'
option dhcpv6_peerdns '1'
option pppoev6_useipv4info '1'
option pppoev6_peerdns '1'
option web_enabled '1'
option web_proto 'nat6'
option proto 'dhcpv6'
option ifname 'pppoe-wan'
nat6也sdtart,所有都配置好后,重启/etc/init.d/network
发现pppoe-wan口可以获取到ipv6地址,br-lan也设置了ipv6地址,但是用www.test-ipv6.com测试发现一只通过不了。
root@zihome:/# ip -6 route
default from :: via fe80::da86:8eff:febd:4 dev pppoe-wan proto static metric 1024
default from 240e:fa:a8:87b5::/64 via fe80::da86:8eff:febd:4 dev pppoe-wan proto static metric 1024
240e:fa:a8:87b5::/64 dev pppoe-wan proto static metric 256
fd00:6885:6885::/64 dev br-lan proto static metric 1024
unreachable fd00:6885:6885::/64 dev lo proto static metric 2147483647 error -128
fe80::/64 dev br-lan proto kernel metric 256
fe80::/64 dev eth1 proto kernel metric 256
fe80::/10 dev pppoe-wan metric 1
fe80::/10 dev pppoe-wan proto kernel metric 256
查看默认入网发现少了pppoe-wan默认网关的路由,这种情况下可以手动添加默认路由
route -A inet6 add default gw fe80::da86:8eff:febd:4 dev pppoe-wan
添加后www.test-ipv6.com就可以测试通过,但是使用这种方法要去维护这个默认路由ifup的时候 添加,ifdown的时候删除,总是会有一些问题。
最后发现一开始没有默认路由,但是等了5分钟后发现又有了,查看syslog发现原本一直没有获取到ipv6的dns,等了几分钟后获取到了dns信息,默认路由就有了。
syslog如下:
Wed Sep 23 18:00:32 2020 daemon.info dnsmasq[13935]: reading /tmp/resolv.conf.auto
Wed Sep 23 18:00:32 2020 daemon.info dnsmasq[13935]: using local addresses only for domain lan
Wed Sep 23 18:00:32 2020 daemon.info dnsmasq[13935]: using nameserver 202.96.134.33#53
Wed Sep 23 18:00:32 2020 daemon.info dnsmasq[13935]: using nameserver 202.96.128.86#53
Wed Sep 23 18:00:32 2020 daemon.info dnsmasq[13935]: using nameserver 240e:1f:1::1#53
Wed Sep 23 18:00:32 2020 user.notice firewall: Reloading firewall due to ifupdate of wan6 (pppoe-wan)
/tmp/resolv.conf.auto多出了ipv6的dns
root@zihome:/# cat /tmp/resolv.conf.auto
# Interface wan
nameserver 202.96.134.33
nameserver 202.96.128.86
# Interface wan6
nameserver 240e:1f:1::1
ip -6 route多出了默认路由
root@zihome:/# ip -6 route
default from :: via fe80::da86:8eff:febd:4 dev pppoe-wan proto static metric 1024
default from 240e:fa:a8:87b5::/64 via fe80::da86:8eff:febd:4 dev pppoe-wan proto static metric 1024
240e:fa:a8:87b5::/64 dev pppoe-wan proto static metric 256
fd00:6885:6885::/64 dev br-lan proto static metric 1024
unreachable fd00:6885:6885::/64 dev lo proto static metric 2147483647 error -128
fe80::/64 dev br-lan proto kernel metric 256
fe80::/64 dev eth1 proto kernel metric 256
fe80::/10 dev pppoe-wan metric 1
fe80::/10 dev pppoe-wan proto kernel metric 256
default via fe80::da86:8eff:febd:4 dev pppoe-wan proto ra metric 1024 expires 1671sec
后面一切就都正常了,可是为什么要等5分钟后才可以获取到dns呢,分配ipv6 dhcp的时候咋没有呢。
测试发现两台自己的路由器相接,可以很快的获取到nds信息,应该是上级光猫没下发,获取到另一个ipv6地址的时候才下发nds成功,一开始只有一个ipv6地址
root@zihome:/# ifconfig pppoe-wan
pppoe-wan Link encap:Point-to-Point Protocol
inet addr:183.49.45.127 P-t-P:183.49.44.1 Mask:255.255.255.255
inet6 addr: 240e:fa:a8:87b5:1111:c06e:8b81:b6ad/64 Scope:Global
inet6 addr: 240e:fa:a8:87b5:1111:6841:4c33:1a88/64 Scope:Global
inet6 addr: fe80::1d6e:c06e:8b81:b6ad/10 Scope:Link
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1480 Metric:1
RX packets:10008038 errors:0 dropped:0 overruns:0 frame:0
TX packets:9073006 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:8745492897 (8.1 GiB) TX bytes:2913346015 (2.7 GiB)
Openwrt配置NAT6:
https://www.cnblogs.com/Arago/p/7765873.html
openwrt的官方手册如下:
https://openwrt.org/docs/guide-user/network/ipv6/ipv6.nat6#ula_prefix
深圳电信开启IPv6支持:
https://blog.yiwei.li/%E6%B7%B1%E5%9C%B3%E7%94%B5%E4%BF%A1%E5%BC%80%E5%90%AFipv6%E6%94%AF%E6%8C%81/