1. 程式人生 > >IPv6來啦 (by quqi99)

IPv6來啦 (by quqi99)

版權宣告:可以任意轉載,轉載時請務必以超連結形式標明文章原始出處和作者資訊及本版權宣告 (作者:張華 發表於:2018-08-03)

問題

家裡用的是中國移動的寬頻, 一直挺穩定的, 而且昨天發現ISP下發了IPv6地址(不是子網, 形如: 2409:8a00:7805:xxxx:xxxx:xxxx:xxxx:xxxx/64, 打xxxx的部分是動態變化的). 好吧, 咱就用用.

路由器配置

  • 配置/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模式來實現外網訪問內網的目的.
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'

[email protected]:~# 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=`route -A inet6 |grep lo |grep 2409:8a00:7805 |grep ::/128 |awk -F '::/' '{print $1"::/64"}' |uniq`
ip -6 route del $PREFIX dev br-lan > /dev/null 2>&1
route -A inet6 add $PREFIX dev br-lan > /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 <VPS-IP> -j DNAT --to-destination <tunnelbroker-ip>
#sudo iptables -t nat -A POSTROUTING -p 41 -d <tunnelbroker-ip> -j SNAT --to-source <VPS-IP>
#sudo iptables -A INPUT -p 41 -j ACCEPT

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