(十)洞悉linux下的Netfilter&iptables:網絡地址轉換原理之SNAT

源地址轉換:SNAT

    SNAT主要應用於下列場景:

    這種情況下,我們只有一個公網地址A,而又有三臺主機需要同時上網,這時就需要SNAT了。它的主要作用是將那些由私網發來的數據包skb的源地址改成防火牆的公網地址A,這是因爲目的主機在響應源地址爲私網地址的數據包時,私網地址不能在網絡上路由的緣故。

    SNAT僅可以在LOCAL_OUT和POSTROUTING點生效,這也說明了爲什麼用戶空間的iptables命令在配置SNAT規則時只能配置到nat表的OUTPUT和POSTROUTING鏈的緣由。

    我們現在假設的情形是:其他四個HOOK點都沒配任何規則,且內置鏈的缺省處理策略爲ACCEPT,然後在防火牆上配置了一條SNAT規則,私網地址B1要訪問公網地址C的情況。

    和前面DNAT類似,當第一個由B1發往C的數據包到達POSTROUTING點時,在連接跟蹤階段就已經爲該連接建立好了ip_conntrack實例並進行過適當的初始化。SNAT主要是在ip_nat_out()函數中完成,而該函數本質上也調用了ip_nat_fn(),所以流程和DNAT一樣,但執行的操作有所差別。

    還是先回顧一下ip_nat_fn()的流程圖:

    注意,當執行ip_nat_out()函數時,該skb已經被正確路由過了。此時,在ip_nat_fn()裏執行的是ip_nat_rule_find()分支,然後進入ip_nat_setup_info()函數中。

    接下來我們簡單說一下get_unique_tuple()函數。

    如果屬於某條連接的數據包之前已經被執行過NAT了,則其連接跟蹤記錄會被添加到bysource鏈表中。對於SNAT操作,如果是第一個數據包,其流程和DNAT非常相似,在函數find_best_ips_proto()中完成對臨時tuple的源地址的修改。然後,以修改後的tuple計算其響應tuple,最終用該響應tuple替換掉連接跟蹤記錄中原來的響應tuple。替換的結果是:

    此時,連接跟蹤記錄中響應tuple的源地址已經被替換成防火牆的公網地址A了。等會兒當服務器C迴應時,它所發出的報文目的地址就是A,這樣防火牆就可以正確接收到服務器C的迴應報文。最後,會根據該連接跟蹤記錄實例的初始tuple來計算一個hash值,然後將其插入到bysource裏,並對ip_conntrack.status狀態進行適當設置。

    和DNAT類似,最後也是在manip_pkt()函數中完成對skb源地址、IP校驗和進行修改。對skb裏端口的修改也是在manip_pkt()裏完成的。

 

    OK,關於SNAT我們第一階段的分析就完成了,接下來我們來看一下當服務器C收到這個請求報文後,在對其響應的後續流程裏防火牆是如何實現所謂的自動De-SNAT功能。

 

    服務器的響應報文其源地址爲自己的公網地址C,目的地址爲防火牆的公網地址A。當該響應報文到達防火牆後,連接跟蹤系統可以準確地識別該數據包所欲的連接跟蹤記錄,因爲存在一個源地址是C,目的地址是A的響應tuple(如上圖所示)與其匹配。該響應數據包還是會先到達PREROUTING點的ip_nat_in()函數,因爲沒有配置任何DNAT規則,同時ct.status字段又設置了IPS_SRC_NATIPS_SRC_NAT_DONE_BIT標誌位,所以在進入到ip_nat_in()函數的ip_nat_fn()裏時就直接調用ip_nat_packet()接口。

    在ip_nat_packet()中以連接跟蹤記錄的初始tuple計算原來舊的響應tuple:源地址是C,目的地址是B1。因爲在PREROUTING點上要做DNAT,所以此時skb中的目的地址A就被改成了原來的響應tuple中的目的地址B1了。後面的流程和DNAT完全一樣。

    當該響應報文來到POSTROUTING點時,又調用ip_nat_out(),和前面分析SNAT一階段時的流程一樣。

 

    現在我們就明白了,De-SNAT功能是基於manip_pkt()函數實現的。在結尾之際,我們來解釋一下上篇博文中關於NAT的一段描述:“只有每條連接的第一個數據包纔會經過nat表,而屬於該連接的後續數據包會按照第一個數據包則會按照第一個報所執行的動作進行處理,不再經過nat表”。

    從用戶空間的iptables規則來看,每條規則都有一個counter計數器,該計數器記錄的是被該規則成功匹配了數據包的數目。而內核中對該計數器的修改是在ipt_do_table()函數。從ip_nat_fn()函數的執行流程可以看出,當連接跟蹤記錄項被設置了IPS_SRC_NAT_DONE_BIT狀態位,或者連接跟蹤的狀態不再是IP_CT_NEW狀態時,ipt_do_table()函數就不再被調用了,反應在用戶空間所看到的直觀現象就是,nat表的規則計數器不再增長了。

    基於連接跟蹤的NAT,其特殊之處就在於初始和響應tuple不再一致了,而這也是NAT得以正確運行的關鍵所在。通過如下這張圖,讓大家再複習一下NAT的初始和響應tuple之間的關係:

    至此,Linux中Netfilter框架下的nat子系統我們就全部學習完了。用了十個章節基本將Netfilter框架的各個功能子模塊、架構、原理、流程等作了初步簡單的分析瞭解。由於知識有限,本人的分析難免存在疏漏,還請各位大俠不吝指正。在接下來後續的文章中,主要探討以下主題:

1、  用戶空間的iptables是怎樣識別傳遞給它的每個參數?

2、  通過iptables配置的每條規則是如何進到內核裏的?它們又有什麼關係?

3、  內核是如何判斷數據包到底匹配還是不匹配某條具體規則?

4、  如何自己動手擴展iptables的功能模塊?

    未完,待續…

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章