美文网首页路由联盟It
4-Openwrt ipv6之NAT6

4-Openwrt ipv6之NAT6

作者: Creator_Ly | 来源:发表于2020-09-24 18:27 被阅读0次

    在实际使用过程有时候电信宽带可以下发给Wan口使用的ipv6地址,但是不下发给lan口使用的ipv6地址前缀。

    这时候可以使用NAT6的方式,跟ipv4的NAT一样,有自己的内网地址,访问外部的时候经过NAT转化。ipv6也使用内网地址,根据ipv6的规则FD::/8开始的地址为内网地址。

    IPv6的NAT关键在于

    • 设置br-lan端口的ipv6的网段/前缀
    • 设置ip6tables规则,将br-lan网段的数据包通过snat地址转换后发出

    1. nat6配置


    1. 开启config配置
    CONFIG_PACKAGE_ip6tables=y
    CONFIG_PACKAGE_kmod-ipt-nat6=y
    
    1. 配置给br-lan端口的ipv6地址前缀,在netifd里面已经实现了一个uci配置值ula_prefix,将/etc/config/network里面的ula_prefix设置成fd开头的内网地址
    config globals 'globals'
        option ula_prefix 'fd00:eeee:eeee::/48' 
    
    1. 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
    
    1. 根据对应的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 "$@"
    
    1. 为了方便启动和停止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/

    相关文章

      网友评论

        本文标题:4-Openwrt ipv6之NAT6

        本文链接:https://www.haomeiwen.com/subject/lkdtuktx.html