Linux NAT優化的校驗和問題
我們知道,Linux的NAT是基於ip_conntrack的有狀態NAT,其配置類似BSD的keep state的效果!如果看一下Netfilter的PREROUTING,就知道ip_conntrack依賴ip_defrag,也就是凡是分片的IP片必須重組後才可以進入ip_conntrack進而進入NAT,如果我們希望能針對每一個IP分片來做NAT的話,那就需要動一番腦筋了。
下圖是一個優化邏輯,在其它的文章中也屢次貼出:
注意此圖中沒有NAT的邏輯,只是conntrack邏輯。我先說一下NAT需要注意什麼,其實沒有什麼要注意的,唯一的就是IP首部和TCP/UDP(如果有的話)首部的校驗和,注意到這些校驗和的計算並不是加解密,並不是摘要是重要的,因為當你知道校驗和是如此的好計算後,你就從內心克服了針對優化IP分片NAT的恐懼心理!
我們只需要揪出來第一個攜帶TCP頭的分片即可。由於校驗和的計算僅僅是一個算術計算的過程,類似小學學的加法,而加法滿足交換律,結合律,因此我們可以假設檢驗和的數據載荷部分以及其它TCP部分是一個常數,需要改變的僅僅是偽頭部分,而這很簡單,公式如下:
新的校驗和=老的檢驗和-老的偽首部校驗和+新的偽首部校驗和
受影響的僅僅是偽首部,而NAT影響也僅僅是偽首部,由於我已經恨透了動態NAT,鑒於XX銀行實施不成功而不得不去排查問題導致回家晚了而餓著肚子和游離於文明邊緣以外的老婆吵架,此處的NAT指的是一一映射的static NAT,哪怕是TMD我自己實現的static NAT!於是分片到循著上面的圖的出口到達NAT模塊,執行下面的邏輯:
1.判斷是不是攜帶完整的TCP頭,如果是,那麼根據NAT的結果按照上述公式修改TCP的校驗和(別提配角UDP了);
2.如果不是攜帶完整的TCP頭,則不可能!因為上面的圖示保證了總是能攜帶傳輸層頭(但不絕對!);
3.由於2的結果是但不絕對,畢竟可能不針對conntrack做優化,而僅優化NAT!如果真的沒有攜帶完整的TCP頭,則按照上圖的邏輯等待。
一個NAT,折騰了我這麼久!唉,為了一個NAT,我期盼IPv6,現在又扯進了一個IP分片,我更期盼IPv6了,那時既沒有NAT,也沒有分片了!如今,我真的high不起來,游離於邊緣之外的人總是嚎叫,Mac OS的network正玩的盡興,蠻族人又在嚎叫,做打油詩一首:
責罵 誤解 嚎叫!在我身邊萦繞!
狂妄 自私 無聊!在我心頭燃燒!
流露出的凶險,你並不比我更明了,
恃才放曠的傲慢,請你昂起頭,我讓你知道!
理解,或多或少。
我更在乎的,其實我比你更狂躁!
只是
有種東西在慢慢發育,
最終它就是他媽的一個勾當!
shit,everything!shit,the life!