1. 程式人生 > 其它 >家用路由器開啟 IPV6, wifi 訪問變慢甚至打不開網頁?

家用路由器開啟 IPV6, wifi 訪問變慢甚至打不開網頁?

發現最近經常有人提到開啟 IPv6 連線速度慢的問題。目前國內確實存在支援 IPv6 的伺服器、CDN 節點不夠多,IPv6 國際頻寬比 IPv4 頻寬小的問題,但也不至於會開啟國內網站都卡。通常情況下遇到這個問題說明你到目標伺服器的鏈路上存在 PMTU 黑洞。

關於 PMTU 黑洞
MTU (Maximum transmission unit) 是一條鏈路上可以通過的三層資料包的最大尺寸(包含 IP 包頭)。乙太網上預設的 MTU 是 1500 位元組,但是你和目標伺服器之間的路徑上可能存在小於 MTU 1500 的鏈路。這條路徑上最小的 MTU 值就是整條路徑的 PMTU 值。路由器在轉發包時,超過 MTU 大小的包會被分片( Fragmentation ),也就是一個大包會被分切為多個不超過 MTU 的小包進行傳輸,傳輸效率會下降。

終端裝置在發包時,也可以設定 DF ( Don't Fragment )標記來告訴路由器不要分片。這時中間路由器會丟掉超過 MTU 的包,回覆一條 ICMP Fragmentation Needed 訊息。傳送者收到這個包後,下次就會發小一點的包,這個過程叫做 PMTU Discovery 。現實中可以看到 HTTPS ( TLS )的流量大都是帶 DF 標記的。

然而,網際網路上有大量的中間裝置為了所謂的“安全”或者沒有正確配置,不迴應 ICMP Fragmentation Needed 包,這使得訪問某些網站時如果某個包的大小超過了 PMTU,會被無聲地丟棄,直到 TCP 協議發現超時丟包進行重傳,這非常緩慢。遇到這種情況,我們可以說你和目標伺服器的路徑上存在 PMTU 黑洞。

此外,IPv6 不支援分片,換句話說可以理解為 IPv6 下所有的包都是帶 DF 標記的。中間路由器在遇到包尺寸大於 MTU 的情況時,應該回應 ICMPv6 Packet Too Big 訊息。同樣的,由於種種原因,某些中間裝置可能會直接丟包而不迴應 ICMPv6 Packet Too Big 訊息,直到 TCP 協議發現超時丟包進行重傳。。。

為什麼 IPv4 沒有這個問題
其實 IPv4 也有這個問題,我不只一次見網友說自己搭的軟路由訪問某些網站非常慢,而換回硬路由就正常。這是因為多數家用路由器預設對 IPv4 下的 TCP 開啟了 MSS (maximum segment size) Clamping (使用 OpenWRT 軟路由的朋友們可以在防火牆設定中找到 MSS Clamping 開關)。MSS Clamping 是針對 PMTU 黑洞的 Workaround,簡單來說就是 TCP 握手時有個 MSS 欄位決定單個 TCP 包的最大尺寸。路由器可以通過嗅探 TCP 握手包,把 MSS 值改小,使最終的三層 IP 包的尺寸( MSS+TCP 頭大小+IP 頭大小)不超過某個特定的值。

總結
現在國內 ISP 一般都是通過 PPPoE 虛擬撥號建立 WAN 口連線的。Ethernet 的預設 MTU 是 1500,但是 PPPoE 隧道有 8 個 bytes 的開銷,所以 PPPoE 虛連線的 MTU 就是 1500-8=1492,減掉 IPv4 包頭( 20 位元組)和 TCP 包頭( 20 位元組),可以得知 IPv4 下需要把 MSS 設為 1452 以下。

IPv6 的包頭是 40 位元組,所以 IPv6 下需要把 MSS 設為 1432 以下。

這時問題來了,目前很多光貓、家用路由器對 IPv6 的優化很差,不支援對 IPv6 下的 TCP 包進行 MSS Clamping,這就導致訪問 IPv6 網站時,若路徑中存在 PMTU 黑洞,則開啟很慢。

我前段時間幫朋友配置 IPv6 時發現了很多光貓、家用路由器的韌體問題,使得國內使用 IPv6 的體驗不太理想。我打算抽空專門開一個帖子去討論這些問題,聲討那些垃圾廠家。目前來看,要想在國內比較理想地體驗 IPv6,你需要把光貓改為橋接模式,並使用 OpenWRT 或者 VyOS 這類對 IPv6 支援較好的軟路由。

附:在基於 Linux 的路由器啟用MSS Clamping的命令:

自動MSS,假設PPPOE虛介面是pppoe0
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --clamp-mss-to-pmtu
ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --clamp-mss-to-pmtu

手動指定MSS,假設PPPOE虛介面是pppoe0
$ iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --set-mss 1452
$ ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --set-mss 1432

RouterOS裡設定MSS的命令。其中pppoe-out1是wan口,1420是要MSS值,請根據需要修改。

/ipv6 firewall mangle add chain=forward out-interface=pppoe-out1 protocol=tcp tcp-flags=syn action=change-mss new-mss=1420

UBNT Edgerouter 系列的MSS設定方法:

set firewall options mss-clamp6 interface-type pppoe
set firewall options mss-clamp6 mss 1420

轉載:https://www.v2ex.com/t/800024