[筆記] 利用 iptables 在 Linux 上調整 TCP MSS
前文
當使用 Tunnel 時,例如 WireGuard、GRE、或其他協議,常會遇到 DNS、Git 不通的問題,這種時候,大多是因為 MTU 過大,但實際上沒辦法傳送那麼大的封包。
這篇文章將介紹 MTU 以及 MSS 等相關知識,讓你理解為什麼在使用 tunnel 時,需要修改 MTU 或是 MSS 讓服務可以正常使用,並將提供利用 iptables 在 Linux 上調整 MSS 的範例。
MTU 是甚麼?
最大傳輸單元(英語:Maximum Transmission Unit,縮寫MTU)是指資料鏈路層上面所能通過的最大封包大小(以位元組為單位)。最大傳輸單元這個參數通常與通訊介面有關(網路卡、序列埠等)。
來源:維基百科
這邊我們以包裹舉例,MTU 就像是一個包裹的箱子,這個箱子有固定的大小限制,想像一下,當你在網路上傳送資料的時候,這些資料就像是要寄出去的包裹。
如果你的資料太大,超過了這個箱子的大小(MTU),那這些資料就需要被分成好幾個包裹才能寄出去,除了比較麻煩,還需要花更多時間把大包裹拆開,再把小包裹重新組合起來。
在網路中,MTU 就是指單一封包最大的大小,常見的 MTU 有 1500,如有 PPPOE 則會見到 1508、1492 等。
MSS 是甚麼?
最大分段大小是傳輸控制協定的一個參數,以位元組數定義一個電腦或通信裝置所能接受的分段的最大數據量。
來源:維基百科
也就是說,MSS 就是表示純資料可以多大。
為什麼需要指定 MSS?
在使用 tunnel protocol 時,例如 WireGuard、GRE,都會占用封包的一些欄位,而導致雙邊實際上對於水管可以傳輸的封包大小有誤差,造成其中一邊傳送了水管無法接受的大小,造成異常,於是需要透過指定 MSS,告訴系統,多少資料要切一刀。
現在,我們來看看 IPv4 封包內包含哪些資訊:
來源:維基百科
假設今天,網卡的 MTU 為 1500,不考慮是否使用了 tunnel protocol 或是其他會占用封包長度的東西。
實際上 IPv4 能傳輸的資料只有 1500 - 20(IPv4) = 1480,也就是一個封包最多能包含 1480 Bytes 的資料;而 IPv6 則是 1500 - 40 = 1460。
該如何計算 MSS 要設定多少
這邊推薦大家一個網站,可以便利的計算 MTU / MSS:
https://baturin.org/tools/encapcalc/
他預設是給 MTU 的計算,但也可以用於計算 MSS,如果是要計算 IPv4 的 MSS,則為 MTU - 20,如果是要計算 IPv6 的 MSS,則為 MTU - 40。
這邊以 WireGuard 舉例,如果架構像這樣:
則雙方 MTU 該設定多少呢?
WireGuard 會占用 40 Bytes,故應該設定為 1460。
那如果今天要設定 MSS 呢?
那我們就要考量是 IPv4 還是 IPv6,如果是 IPv4,則需要扣掉 IPv4 header 的 20 Bytes,MSS 設定為 1440。
那如果為 IPv6,則需要扣掉 IPv6 header 的 40 Bytes,MSS 為 1420。
該如何在 Linux 上設定 MSS?(iptables 為例)
這邊直接給指令使用!
只需要將指令中的 1400 改為要使用的 MSS 值即可。
iptables
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
ip6tables
iptables6 -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables6 -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400
iptables6 -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400
iptables6 -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
同場加映,什麼是 PMTU
PMTU 簡單來說就是依據走過的路,自動發現並調整 MTU 值。
在 IPv4 中預設沒有開,需要透過設定 DF flag 來設定,例如上面的 iptables 指令,可以明顯看到我們開了 pmtu 來避免因為經過 MTU 比較小的節點,而造成資料遺失的情況,而在 IPv6 中,是強制使用 pmtu 來避免這些問題。
本文為作者 @Yuan 原創並公開於Yuan's Blog。本文章採用 CC BY-NC-SA 4.0 授權。
留言