版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 (作者:张华 发表于: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的原因吧,待确定.
config interface 'lan'
...
option ip6assign '64'
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
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地址.
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的默认路由会造成很多问题.
#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
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服务器通信。
今天通过这个帖子(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模式吧.
上述静态路由过期的问题原因找到, 原因是需要添加metric
上面使用replay时的bug解不了, 无奈之下, 只好使用NAT6, 外面访问不了内网就访问不了吧, 起码可以内网访问外网啊.
config globals 'globals'
option ula_prefix '2001:192:168:99::/64'
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'
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, 可以通过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的流量
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
使用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地址吧.