歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux實現基於Loopback的NVI(NAT Virtual Interface)

Linux實現基於Loopback的NVI(NAT Virtual Interface)

日期:2017/2/28 14:43:13   编辑:Linux教程

Loopback實際上是個hole

但是如果它不是一個hole,它確實可以做一些事,類似Cisco的NVI那樣。既然前期是“如果它不是一個hole”,那就需要對代碼進行一些修改。在修改之前,你必須明白的是,Linux的loopback接口為什麼是一個hole。

標准規定,所有試圖經過loopback接口去往其它地方(非本機)的數據包要全部丟棄。Linux使用loop hole做到了這一點。Linux的限制loopback流量在本機范圍的方式是,所有的loopback流量肯定經由本機發送,那麼在ip_output的時候就會將其設置為loopback_dst,然後進行入IP接收例程的時候,它已經有關聯的路由項了,進而就不會再去查詢路由表,因此凡是進入ip_input邏輯的數據包都不是本機發出的,於是在其內部就可以做比較狠的判斷的,凡是源地址是本機地址的,一律丟棄!這樣本機發出的包就不會先經由loopback口然後去往外部,下面我們看一下外部進入的包是否能經由loopback口去往外部。答案無疑是否定的,看下面的流程:數據包從物理網卡進入->被路由到lo口->將loopback_dst這個路由項關聯給數據包->loopback接口xmit數據包->模擬loopback接口接收數據包->進入ip_input路由判斷->由於已經有了路由項故按照路由項轉發。路由項的轉發方式有兩種,對於外部進入的數據包,將不斷調用ip_forward,直到TTL變為0。因此只要進入了loopback,要麼直接丟棄,要麼瘋狂loop,是絕對出不去的。

下面我就來說一下如何來破除這些約束。首先說一下本機發出的數據包如何先經由loopback再出去,然後說明外部進入的數據包如何先經由loopback再出去,最後說明,當做NAT的時候會碰到什麼問題以及如何結合上述針對本機發包以及外部發包兩種場景的措施來解決NAT問題。

1.本機發包經由loopback發出

修改代碼是不必可少的了,因為我這是在破壞原則。幸運的是,代碼只是修改一點點而已。修改的部分就是將這種“經由loopback發往別處”的包識別出來,然後刪除其關聯的路由項。這個用Netfilter在PREROUTING上做比較簡單。另外就是將表示該本機地址的Local路由從Local表刪除,然後作為unicast路由加入main表中,這樣在做反向路由查詢的時候,就不會匹配到Local表的路由了(Linux要求反向路由的類型必須是unicast的),到此即OK!

2.外部發包經由loopback轉發

對於這種情況,只要是刪除了數據包的loopback路由項關聯,即可被順利轉發。因為數據包的源IP地址不可能是本機的IP,因此也就不可能是Local,如果數據流想原路返回的話,它就一定有反向的unicast路由。

3.NAT的問題

在配置了SNAT的情況下,要看SNAT成了什麼地址,如果是SANT成了本機地址,那就面臨上述第1節的問題,解決方法就是將該地址從Local表中刪除,但是刪除了之後會導致其它機器arp該地址的時候,本機不再回復,因此刪除了之後還要顯式arping一下該地址的arp更新;如果SNAT成了別的地址,就涉及到了反向可達性的問題,因為下一跳不一定知道該地址的可達性。

4.NAT問題的解決

NAT的問題僅僅是在SNAT成了別的地址時才會存在。這裡又分為兩種情況,第一種情況就是SNAT成了一個不相關的其它網段的地址,這樣僅僅要求下一跳配置到該地址的路由就可以保證數據流的反向包能返回到此BOX,這個路由配置在簡單環境下可以手工配置,復雜環境下可以用動態路由的方式進行SNAT地址的宣告;第二種情況就是SNAT的地址是和下一跳同一網段的情況,這會導致數據流反向包返回到下一跳的的時候,該SNAT的地址此時成了目標地址,由於處於同一網段,所以會被直接ARP,因此需要添加一條ARP轉換規則:

arptables -t mangle -A OUTPUT -d 下一跳網關地址 -j mangle --mangle-ip-s SNAT成的地址

知道了問題所在以及解決方案,現在就可以動手了。本文的目標是實現一個類似Cisco NVI的東西,也就是一個虛擬網卡,在虛擬網卡的發送流程中實現NAT。鑒於有loopback這麼好的現成的東西,我也就不再寫虛擬網卡了,直接用loopback模擬一個也好。大體流程如下:

數據包從物理網卡進入->執行DNAT->路由到loopback->執行SNAT->loopback口發出->策略路由->物理網卡發出

可以看到,路由執行了兩次,第一次是為了NAT,第二次是真正的路由。

除了使用loopback,編寫一個類似veth的虛擬網卡是一個更不錯的選擇:

Veth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected

with each other.

比loopback好的是,這基本可以不修改代碼實現NVI,並且可以很容易取到數據包原始的進入接口。該驅動的邏輯非常簡單,即一個pair中包含一個主接口和一個輔助接口,數據包從主接口進入被路由到該主接口的輔助接口,注意,不改變skb的接收接口,這個所謂的路由只是為了搞一次“從物理網卡接收到發送到某另一個網卡的動作”,此時PREROUTING/POSTROUTING都已經完成了,真正的路由之後就可以從另一個主接口發出了。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-10/90951p2.htm

Copyright © Linux教程網 All Rights Reserved