IPv6来啦 (by quqi99)

版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 (作者:张华 发表于:2018-08-03)

问题

家里用的是中国移动的宽带, 一直挺稳定的, 而且昨天发现ISP下发了IPv6地址(不是子网, 形如: 2409:8a00:7805:xxxx:xxxx:xxxx:xxxx:xxxx/64, 打xxxx的部分是动态变化的). 好吧, 咱就用用.

20200814更新
联通宽带在安装的时候要告诉师傅将光猫改桥接(后台改), 改桥接之后,会有公网IP及IPv6 (TL-WDR7660路由器需要在IPv6也设置为像IPv6一样宽带联网才能使用IPv6的).
即使改桥接后得到的公网IP也是作了限制的,并且所有端口全是封的,给联通打电话时,他们会装作不慬公网,不懂端口,一问三不知.总之,最后他们还是偷偷地给改好了.
但是WDR7660下接的WNDR4300 openwrt路由器却无法获取IPv6地址,估计没有安装odhcp6c的原因吧,待确定.

路由器配置

  • 配置/etc/config/network使用’option ip6assign ‘64’
config interface 'lan'                    
        ...      
        option ip6assign '64'
  • 配置/etc/confignetwork删除config globals 'globals’段中和 IPv6 ULA-Prefix相关的配置 (注: 使用IPv6 ULA-Prefix的话, LAN中机器就会得到一个以它打头的IPv6地址, 但如何从外网访问这个地址呢? 有三种方式: 一是使用我们现在使用的relay方式得到是ISP提供的全球可路由的IPv6地址;二是配置ULA-Prefix=2409:8a00:7805:1::/80之后再使用下列的neigh proxy的方法解决, 但这种一般是子网长度80比64大, 但ISP并没有给我们分配subnet, 只是分配了IPv6地址, 所以无法保证2409:8a00:7805:1::/80这个前缀与ISP分配的2409:8a00:7805:xxxx:xxxx:xxxx:xxxx:xxxx/64一致;三是ULA-Prefix配置一个与ISP分配的不同的路由然后通过配置路由的方式但前提是也得有全球可路由的IPv6 subnet啊. 所以这里我们选择了relay模式来实现外网访问内网的目的.
config globals 'globals'
        option ula_prefix 'fd89:714c:1c30::/48'
sysctl -w net.ipv6.conf.all.proxy_ndp=1
ip -6 neigh add proxy 2409:8a00:7805:1::430 dev pppoe-wan
ip -6 neigh show proxy
  • 配置/etc/config/dhcp使用relay模式, relay模式意味着openwrt通过默认的odhcpd作为中继自动为LAN的其他机器配置ISP的IPv6地址
config dhcp 'wan'                                                                                                                       
        option interface 'wan'                                                                                                          
        option ignore '1'                                                                                                               
        option dhcpv6 'disabled'                                                                                                        
        option ndp 'relay'                                                                                                              
        option ra 'relay'                                                                                                               
        option master '1'                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
config dhcp 'lan'                                                                                                                       
        option interface 'lan'                                                                                                          
        option start '100'                                                                                                              
        option limit '150'                                                                                                              
        option leasetime '12h'                                                                                                          
        list dhcp_option '6,192.168.99.1'                                                                                               
        option ndp 'relay'                                                                                                              
        option ra 'relay'                                                                                                               
        option dhcpv6 'relay'

# actually I use 60, not 64
cat /etc/config/network
config interface 'lan'
	...
	option ip6assign '60'

配置完之后就可以通过下列命令重启路由器服务就可以在br-lan与pppoe-wan上获得ISP分配的IPv6地址了.

/etc/init.d/network restart
/etc/init.d/odhcpd restart

内网机器直接通过’sudo /etc/init.d/network-manager restart’重启网络也会获取ISP分配的IPv6地址.

验证

  • 内网机器访问br-lan内网网关, 能通是因为下列路由的功能:
hua@t440p:~$ ip -6 route list |grep 2409:8a00:7805:b7df::/64
2409:8a00:7805:b7df::/64 dev eth0  proto ra  metric 100  pref medium

root@OpenWrt:~# route -A inet6 |grep ::/0
::/0                                        fe80::200:5eff:fe00:134                 UG    1024   0        0

注: 后面我们会看到::/0的默认路由会造成很多问题.

  • 内网机器访问pppoe-wan外网网关
    对于relay模式由于内网机器拿到的本来就是ISP分配的可路由的IP所以自然能通. 但对于nat模式由于内网机器分配的是和ISP不同网段的IP, 所以需要在路由器上做NAT6, 如:
#ip6tables -t nat -I POSTROUTING -o pppoe-wan -j MASQUERADE
ip6tables -t nat -I POSTROUTING -s `uci get network.globals.ula_prefix` -j MASQUERADE > /dev/null 2>&1
  • 外网访问内网机器
    如果使用relay由于内网机器使用的是全球可路由的IPv6地址, 外网直接就是可以访问内网机器的;但如果是不同子网需要做路由;如果只是前缀相同只是子网长度不同可以做neigh proxy
  • 但是此时我们发现内网机器无法访问外网(如ping6 ipv6.baidu.com), 但此时在路由器上却是可以访问外网的. 原因就在于上面使用::/0的默认路由似乎有问题(报这个错: Destination unreachable: Unknown code 5), 改成了2000::/3就好了:
route -A inet6 add 2000::/3 `route -A inet6 | grep ::/0 | awk 'NR==1{print"gw "$2" dev "$7}'`

或者:

ip -6 route add default from 2409:8a00:7805::48 dev pppoe-wan

但上面两种方法仍然遇到了不稳定的问题, 感觉是openwrt的odhcpd不稳定, 照下列方法更换为6relayd之后仍然不好使.

wget https://www.shintaku.cc/files/6relayd_2013-10-21_ar71xx.ipk
opkg install 6relayd_2013-10-21_ar71xx.ipk
vi /etc/config/6relayd
config relay
        option master 'wan'
        option network 'lan'
        option rd 'relay'
        option dhcpv6 'relay'
        option ndp 'relay'
/etc/init.d/odhcpd disable
/etc/init.d/odhcpd stop
/etc/init.d/6relayd enable
/etc/init.d/6relayd start

接着使用tcpdump查看好像是DHCPv6 reply包从pppoe-wan过不来br-lan口:

08:22:53.810272 IP6 2400:da00:2::29 > 2409:8a00:7805:b7df:8d79:6c9:315a:9ca3: ICMP6, echo reply, seq 7, length 64

所以接着, 在/etc/config/firewall文件的 Allow-ICMPv6-Forward项中添加了下列行后确认已经有了129(129就是reply)相关的iptables rules之后仍然不好使.

        list icmp_type 'router-solicitation'    
        list icmp_type 'neighbour-solicitation' 
        list icmp_type 'router-advertisement'   
        list icmp_type 'neighbour-advertisement'
        
root@OpenWrt:~# ip6tables-save |grep Allow-ICMPv6-Forward |grep 129
-A zone_wan_forward -p ipv6-icmp -m icmp6 --icmpv6-type 129 -m limit --limit 1000/sec -m comment --comment Allow-ICMPv6-Forward -j ACCEPT

google查到的和这个bug相同(https://github.com/openwrt/odhcpd/issues/37), 但里面的所有方法都试过了不成功.
似乎是ISP使用的是Statefull DHCPV6的方式, 6relayd可以把ra信息relay过来,但LAN端机器似乎无法跟DHCPV6服务器通信。

2018-0805更新

今天通过这个帖子(https://bbs.pku.edu.cn/v2/post-read.php?bid=35&threadid=15501646)解决了上面的问题:
OpenWRT默认是在wan口使用DHCPv6 Client, 在LAN口使用odhcpd开启RA和DHCPv6. 这个默认配置适用于国外主流ISP, 因为他们DHCPv6-PD (prefix delegation)把一个至少/64地址段分配给客户使用(还有的使用小于64的地址段给客户分配静态IP).
不过中国移动给客户分配的是SLAAC地址, 没有使用DHCPv6, 也就没使用DHCPv6-PD, 这样拿不到前缀(ISP分配的2409:8a00:7805:xxx::/64地址的第4段总是变化的), 所以odhcpd也就无法根据这个前缀设置路由, 所以我们需要手工设置确保可以在OpenWrt上ping通内网机器, 这样才能保证reply消息到达br-lan之后能到达内网机器, 如:
route -A inet6 add 2409:8a00:7805:d9b1::/64 dev br-lan
所以最终添加在/etc/firewall.user的内容如下:

# make ipv6 relay to work
PREFIX=`ip -6 route list dev br-lan |grep 2409:8a00 |awk -F '::/' '{print $1"::/64"}' |uniq`
ip -6 route del $PREFIX dev br-lan > /dev/null 2>&1
# NOTE: too too important, we must add 'metric' option, or this route will have expire time, or use 'ip' to add route
route -A inet6 add $PREFIX dev br-lan metric 1 > /dev/null 2>&1                                
                                                                                                               
# make ipv6 nat to work                                                                                        
#ip -6 route add default from $PREFIX dev pppoe-wan > /dev/null 2>&1                                           
#route -A inet6 add 2000::/3 `route -A inet6 | grep ::/0 | awk 'NR==1{print"gw "$2" dev "$7}'` > /dev/null 2>&1

再就是得配置replay消息能从pppoe-wan到达br-lan, 所以最终使用下列配置(也记得去掉IPv6 ULA-Prefix):

config dhcp 'wan'                                
        option interface 'wan'                   
        option ignore '1'                        
        option ndp 'relay'                       
        option ra 'relay'                        
        option master '1'                                      
config dhcp 'lan'             
        option interface 'lan'
        option start '100'    
        option limit '150'    
        option leasetime '12h'
        list dhcp_option '6,192.168.99.1'
        option ndp 'relay'               
        option ra 'relay'   

可新问题又来了, 这条路由总是过期, 如下:

2409:8a00:7805:da41::/64 dev br-lan  proto kernel  metric 256  expires 259019sec

重新执行一下上面的命令又能恢复, 太不稳定了, 还是转回ipv6 NAT模式吧.

20180902更新

上述静态路由过期的问题原因找到, 原因是需要添加metric

  • route -A inet6 add 2409:8a00:7805:d9b1::/64 dev br-lan # 会有过期时间
  • route -A inet6 add 2409:8a00:7805:d9b1::/64 dev br-lan metric 1 # 无过期时间
    或者使用ip命令它添加的无过期时间 - ip -6 route del 2409:8a00:7805:d9b1::/64 dev br-lan

转试NAT6

上面使用replay时的bug解不了, 无奈之下, 只好使用NAT6, 外面访问不了内网就访问不了吧, 起码可以内网访问外网啊.

  • 在/etc/config/network中配置了ula_prefix=2001:192:168:99::/64, 这时路由器上的br-lan除了ISP分配的IP之外, 也会多时我们这个自己配置的地址: 2001:192:168:99:0:0:0:1/64
config globals 'globals'
        option ula_prefix '2001:192:168:99::/64'
  • 修改/etc/config/dhcp将relay模式改到server模式即NAT模式
config dhcp 'lan'                                
        option interface 'lan'                   
        option start '100'                       
        option limit '150'                       
        option leasetime '12h'                   
        list dhcp_option '6,192.168.99.1'        
        option dhcpv6 'server'                   
        option ra_management '2'                 
        option ra 'server'                       
        option ra_default '1'
  • 在/etc/firewall.user中添加下列SNAT规则
ip6tables -t nat -I POSTROUTING -s `uci get network.globals.ula_prefix` -j MASQUERADE > /dev/null 2>&1 
route -A inet6 add 2000::/3 `route -A inet6 | grep ::/0 | awk 'NR==1{print"gw "$2" dev "$7}'` > /dev/null 2>&1

之后, 内网机器随便手动配置一个IP如2001:192:168:99:0:0:0:3/64并添加默认路由之后就可以访问外网了.
如果想外网访问2001:192:168:99::3/64, 是不能够使用下面的neigh proxy方式的, 因为网段和ISP分配的可路由网段根据就不一样嘛. 唯一的办法其实就是做DNAT

sysctl -w net.ipv6.conf.all.proxy_ndp=1
ip -6 neigh add proxy 2001:192:168:99:0:0:0:3 dev pppoe-wan
ip -6 neigh show proxy

VPS不支持IPv6时如何使用IPv6

VPS若不支持IPv6, 可以通过tunnelbroker来配置6in4隧道支持IPv6, 但前提是VPS要能支持配置允许proto-41流量通过 (iptables -A INPUT -p 41 -j ACCEPT), 目前google cloud VPS是无法配置这个的.
若您的VPS支持这个, 可以继续. 先在https://www.tunnelbroker.net/ 登录后在’User Functions -> Create Regular Tunnel’菜单创建 Create Regular Tunnel, 然后:

cat << EOF | sudo tee -a /etc/network/interfaces
auto he-ipv6
iface he-ipv6 inet6 v4tunnel
        address 2001:470:a:xx::2
        netmask 64
        endpoint 216.218.226.xx
        local 162.xx.xx.xx
        ttl 255
        gateway 2001:470:a:4c4::1
EOF
cat << EOF | sudo tee -a /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0
EOF
sudo sysctl -p
sudo apt install -y ifupdown
sudo ifup he-ipv6
# can't do tunnelbroker as 6in4 is unsupported (NAT/gateways won't pass proto-41)
#sudo iptables -t nat -A PREROUTING -p 41 -d  -j DNAT --to-destination 
#sudo iptables -t nat -A POSTROUTING -p 41 -d  -j SNAT --to-source 
#sudo iptables -A INPUT -p 41 -j ACCEPT

使用tunnelbroker需要VPS有公网IPv4地址, 若没有, 可以使用miredo(sudo apt-get install miredo), 但前提也是要防火墙允许proto-41的流量

附件 - OpenWRT自动恢复网络脚本

1, /etc/init.d/cron enable
2, crontab -e

*/4 * * * * /root/auto_restart.sh >> /var/log/cron.log 2>&1
0 1 * * * /root/auto_restart_haproxy.sh >> /var/log/cron.log 2>&1

3, auto_restart.sh

root@OpenWrt:~# cat /root/auto_restart.sh 
#! /bin/sh
# /etc/init.d/cron start
# /etc/init.d/cron enable
# crontab -e
# */5 * * * * /root/auto_restart.sh >> /var/log/cron.log 2>&1
EXIST=$(ip route list 0.0.0.0/0)
if test -z "$EXIST"
then
   echo $(date) 'default route disappears, adding it now ...'
   route add default dev pppoe-wan
   sleep 5
   echo $(date) 'check network connection ...'
   #ping -c 1 114.114.114.114 &> /dev/null && echo 'success' || /etc/init.d/network restart;
   if ping -c 1 114.114.114.114 &> /dev/null
   then
      echo 'ping success'
   else
      echo 'ping failed'
      /etc/init.d/network restart
      # for ipv6
      /etc/init.d/odhcpd restart
      sleep 5
      PREFIX=`ip -6 route list dev br-lan |grep 2409:8a00 |awk -F '::/' '{print $1"::/64"}' |uniq`
      ip -6 route del $PREFIX dev br-lan > /dev/null 2>&1
      # NOTE: too too important, we must add 'metric' option, or this route will have expire time, or use 'ip' to add route
      route -A inet6 add $PREFIX dev br-lan metric 1 > /dev/null 2>&1
   fi
fi
root@OpenWrt:~# cat /root/auto_restart_haproxy.sh 
#! /bin/sh
echo $(date) 'restarting haproxy ...'
/etc/init.d/haproxy restart

20190119更新 - 最终的设置

使用relay模式即使按上面说的加metric之后有缓解但还是容易时不是断线, 不清楚什么原因, 这里一个android关于忽略RA的帖子, 估计有关吧. - https://issuetracker.google.com/issues/36949115
换回stateful IPv6还需要继续在openwrt上配置DHCPv6 Server的, 并且android等某些系统并不支持stateful IPv6
换回stateless IPv6也有问题, 在ubuntu系统上可以通过命令"echo ‘precedence ::ffff:0:0/96 100’ >> /etc/gai.conf"配置IPv4优先, 但android系统下对4G网络可以配置是否使用IPv4/IPv6, 但对于wifi则没这个配置项. 而stateless IPv6会给android分配2001:192:168:99::1的DHCPv6, 而在openwrt上要pdnsd支持IPv6的话还得再编译, 也是麻烦.
所以最后退回为单纯的SLAAC配置, 仅是通过openwrt路由器拿RA, 并不配置DHCPv6. 所以最终的配置为:

config dhcp 'lan'                                
        option interface 'lan'                   
        option start '100'                       
        option limit '150'                       
        option leasetime '12h'                   
        list dhcp_option '6,192.168.99.1'        
        option ra 'server'

并且禁用掉用于提供DHCPv6的odhcpd服务.

/etc/init.d/odhcpd disable
/etc/init.d/odhcpd stop

看来要想支持IPv6好, 需要全生态链的所有软件都能支持IPv6好并且方便啊, 目前看到的android, openwrt与pdnsd在这方面都就有所欠缺.
但上面改了之后, 是不再给client发dhcp信息了, 但同样网卡上也没有配置IPv6地址(静态指定的除外), 原因仍然是openwrt上的bug, /etc/init.d/radvd脚本没有根据/etc/config/radvd里的配置生成/var/etc/radvd.conf, 那我们人工生成一个配置文件:

root@OpenWrt:~# cat /var/etc/radvd2.conf 
interface br-lan
{
   AdvSendAdvert on;
   prefix 2001:192:168:99::/64
   {
       AdvOnLink on;
       AdvAutonomous on;
   };
};

然后修改/etc/init.d/radvd中的下列三行即可:

        #[ -z "$RADVD_CONFIG_FILE" ] && return 1
        #service_start /usr/sbin/radvd -C "$RADVD_CONFIG_FILE" -m stderr_syslog -p /var/run/radvd.pid
        service_start /usr/sbin/radvd -C /var/etc/radvd2.conf -m stderr_syslog -p /var/run/radvd.pid

即使如此, 仍然有一些软件如和包之类的无法在IPv6与IPv4之间做fallback.
好吧, 看来IPv6的生态链太有问题了, 还是故意再把radvd恢复成不可用状态吧. 这样android手机就不会配置IPv6地址也不会配置DHCPv6从页可以正常使用和包之类的其他对IPv6支持不大好的软件, 同时ubuntu上想要使用IPv6的话就做静态配置指定IPv6地址吧.

你可能感兴趣的:(networking)