官术网_书友最值得收藏!

1.4 Netfilter/iptables

Netfilter子系統是由Linux內核提供的一種通用網絡處理框架。內核在整個報文處理流程中預留了5個掛載點,并允許用戶在這些掛載點注冊回調函數,使得用戶有機會參與內核的報文處理流程。用戶可以在這些掛載點上實現對數據報文的操作,如過濾報文、網絡地址轉換、轉發、丟棄等。

Netfilter整體架構參考圖1-12。

圖1-12 Netfilter整體架構

可以看到,整體上Netfilter的功能分為內核態和用戶態兩部分。下面針對該架構,從下到上依次進行說明。

?Netfilter HOOK Entry:內核代碼中提供了5個掛載點(Hook Point),并允許用戶在每個掛載點上掛載自己的處理函數,以達到用戶干預內核處理報文流程的目的,實現用戶對報文的定制化處理需求。

?Netfilter內核模塊:內核模塊提供Netfilter功能,這些模塊提供一系列的規則表,用戶通過向表中插入自定義規則實現報文的定制化處理。

?Netlink套接字:Netlink提供了一種靈活的用戶空間與內核空間通信的方法,用于替代ioctl系統調用接口,用戶態應用直接通過Netlink套接字與內核通信。

?用戶空間命令iptables:用戶調用iptables命令向內核模塊寫入報文處理規則,此命令相當于Netfilter功能的外部呈現。

用戶使用iptables命令執行規則管理,在進入命令之前先了解iptables的三個概念:表(Table)、鏈(Chain)和規則(Rule)。這三者的關系如圖1-13所示。

圖1-13 iptables基本概念:表、鏈和規則

iptables提供了4張表,每張表中包含預定義鏈以及0個或者多個自定義鏈,每個鏈中又可以包含0個或者多個規則

?預定義鏈:預定義鏈是表的入口鏈,此類型的鏈與Netfilter掛載點一一對應,每個表固定包含數個預定義鏈。用戶可以在預定義鏈中增加規則以跳轉到自定義鏈執行操作,這也是執行自定義鏈的唯一方法。預定義鏈設置了默認處理策略,如果該鏈上的所有規則均未匹配成功,則按照預定義鏈的默認策略來執行。

?自定義鏈:當規則比較簡單時,用戶直接在預定義鏈中增加規則即可,如果規則較為復雜或者存在嵌套調用的情況,則建議放到自定義鏈中實現。

如果用程序語言來描述這三個概念,則可以將鏈理解為“函數”,將規則理解為函數中的“語句”,如果某個規則的作用是跳轉到其他自定義鏈執行,則可理解為“函數調用”。規則匹配過程就像函數調用過程,預定義鏈作為入口鏈,相當于main()函數,內核按照“函數調用”的順序執行每一條鏈/規則,直到匹配成功。如果該預定義鏈上所有的規則均匹配失敗,則按照預定義鏈的默認策略來執行。

以Kubernetes使用的filter表規則為例說明調用過程,執行iptables命令,輸出如下:

內核接收報文后進入INPUT鏈進行匹配。首先匹配第一條規則,該規則要求與本機建立TCP連接的首條報文(ctstate NEW)進入KUBE-PROXY-FIREWALL鏈執行規則匹配。假設本次收到的正是TCP SYN報文,此時跳轉到KUBE-PROXY-FIREWALL鏈繼續處理,本次跳轉相當于“函數調用”。繼續看KUBE-PROXY-FIREWALL鏈,此鏈上沒有掛載任何規則,“函數調用”返回。回到INPUT鏈后,由于沒有匹配到任何結果,所以內核繼續匹配下一條規則,轉到KUBE-NODEPORTS鏈繼續處理,以此類推。

1.4.1 iptables掛載點和鏈

Netfilter提供的5個掛載點在內核處理流程中的位置參考圖1-14。

圖1-14 Netfilter提供的5個掛載點及報文處理路徑

內核在轉發過程中是如何知道該調用哪個iptables鏈的呢?參考圖1-14,Netfilter的每個掛載點分別對應了iptables的一個預定義鏈。

?NF_INET_PRE_ROUTING:內核收到報文后、路由查找之前的掛載點,對應PREROUTING鏈。

?NF_INET_LOCAL_IN:路由查找完成,內核將報文送到用戶應用程序之前的掛載點上,對應INPUT鏈。

?NF_INET_FORWARD:內核根據用戶報文內容執行路由查找,當發現收包設備不是當前設備時執行轉發操作,轉發時內核提供了掛載點供用戶使用,此掛載點對應FORWARD鏈。

?NF_INET_LOCAL_OUT:本機的用戶態應用程序外發報文的掛載點,對應OUTPUT鏈。

?NF_INET_POST_ROUTING:從本機發出報文前的掛載點,對應POSTROUTING鏈,與OUTPUT鏈的區別在于POSTROUTING鏈可以同時處理本機轉發的報文。

圖1-14同時展示了報文處理過程,分為接收、轉發、外發三種場景。

1)路徑①:主機應用接收報文。當數據報文進入內核時,首先執行PREROUTING鏈上的規則。

?這里是接收報文的第一個處理點,如果希望內核的conntrack組件不跟蹤此報文,則可以在這里設置禁止跟蹤報文(raw表)。

?此時尚未執行路由查找,可以在這里執行目的地址轉換(nat表)。

接下來內核根據報文頭信息執行路由匹配,內核判斷將此報文轉發給本機應用處理,所以繼續執行INPUT鏈上的規則。此時用戶可以設置規則決定要不要接收此報文(filter表),如果規則操作結果為ACCEPT,則內核將報文送到用戶的應用中繼續處理。

2)路徑②:主機轉發報文。轉發報文的前半程與路徑①相同,路由匹配完成后發現需要將報文轉發到系統外部,接下來執行FORWARD鏈上的規則,用戶可以在此時設置規則決定要不要轉發報文(filter表)。如果正常轉發則繼續執行POSTROUTING鏈上的規則,此時報文即將從本機發出,用戶可以設置規則執行源地址轉換(nat表),執行完成后報文從主機的物理設備發出。

3)路徑③:主機應用外發報文。應用程序外發報文時,內核首先做路由匹配操作,然后執行OUTPUT鏈上的規則。

?這里是外發報文的第一個處理點,如果希望內核的conntrack組件不跟蹤此報文,則在這里設置禁止跟蹤報文(raw表)。

?用戶可以在這里設置規則以決定報文是否執行外發操作(filter表)。

?如果存在目的地址轉換場景,則在這里設置目的地址轉換規則(nat表)。

接下來繼續執行POSTROUTING鏈上的規則,后續處理流程與路徑②相同。

1.4.2 iptables表

為方便管理,Netfilter提供了4張表,分別負責不同的功能,并且約定了優先級:raw>mangle>nat>filter。例如,用戶同時在4張表的OUTPUT鏈上定義了規則,那么內核按照上述優先級順序執行iptables規則。

1.filter表

filter表主要用于對數據報文進行過濾,內核匹配規則成功后按照該規則指定的策略執行,可選的策略有DROP、ACCEPT、REJECT等。filter表對應的內核模塊為iptable_filter,該表包含三條預定義鏈。

?INPUT鏈:過濾本機應用接收的報文。

?FORWARD鏈:過濾通過本機轉發的報文。

?OUTPUT鏈:過濾本機應用外發的報文。

filter表的三條預定義鏈的位置如圖1-15中灰色部分所示。

圖1-15 iptables filter表的掛載點

filter表主要用于實現防火墻功能。接下來進行實例化驗證,實驗環境如圖1-16所示。

圖1-16 iptables filter表實驗組網

exp主機和aux主機二層直連,用戶在aux主機上發起ping請求,exp主機則通過增加filter規則來限制對ping請求的處理。

(1)實驗1:exp主機設置拒絕ping請求

在exp主機上增加拒絕ICMP請求規則,執行完成后查看iptables規則:

在aux主機上發起對exp主機的ping請求:

結果顯示,aux得到的應答錯誤碼的意思為“目的端口不可達”,滿足預期。

實驗完成后執行下面的命令刪除前面創建的規則:

(2)實驗2:exp主機設置丟棄ping請求

在exp主機上增加丟棄ICMP請求規則:

在aux主機上發起對exp主機的ping請求:

結果顯示,aux主機發起了4次ping請求,但沒有收到任何應答,原因是exp主機將ping請求報文丟棄了,滿足預期。

實驗完成后執行下面的命令刪除前面創建的規則:

2.nat表

nat表用于實現網絡地址轉換功能。在這里,用戶可以設置規則來修改報文的IP地址、端口號等信息。nat表對應的內核模塊為iptable_nat,本表包含以下4條預定義鏈。

?PREROUTING鏈:此掛載點位于路由查找之前,用戶可在此設置規則以修改報文的目的地址,所以目的地址轉換功能在這里實現。

?INPUT鏈:主機應用接收到報文之前的掛載點。

?OUTPUT鏈:外發報文時的掛載點。

?POSTROUTING鏈:報文離開本機之前的掛載點,用戶可在此設置規則以執行源地址轉換。

nat表的4條預定義鏈的位置如圖1-17的灰色部分所示。

圖1-17 iptables nat表的掛載點

nat表的規則支持4種處理策略。

?SNAT(源地址轉換):適用于POSTROUTING鏈,對匹配到的報文做源地址轉換,使用本參數時必須指定源地址。

?MASQUERADE(源地址轉換):適用于POSTROUTING鏈,同樣做源地址轉換,與SNAT的差異在于SNAT必須指定源地址,而MASQUERADE不需要指定。使用MASQUERADE時,內核會自行選擇一個合適的地址作為源地址。

?DNAT(目的地址轉換):適用于PREROUTING鏈和OUTPUT鏈,對匹配到的報文做目的地址轉換。凡是修改目的地址的操作,均可在路由查找之前執行。

?REDIRECT(重定向):適用于PREROUTING鏈和OUTPUT鏈,將報文重定向到指定端口。

接下來驗證源地址轉換功能,實驗環境如圖1-18所示。

圖1-18 iptables nat表實驗組網

aux主機相當于exp和aux2主機之間的橋梁,兩個業務網卡分別連接了兩個不同的網段:enp0s8連接172.16.0.0/24網段,enp0s9連接192.168.20.0/24網段。本實驗希望使用iptables的地址轉換功能實現從exp主機訪問aux2主機。

首先在exp主機上增加訪問192.168.20.0/24網段的路由,下一跳地址設置為aux的地址172.16.0.4。增加完路由后,在exp主機上發起“ping 192.168.20.3”,結果顯示ping響應正常:

接下來嘗試在exp上直接發起對aux2主機地址的ping請求,沒有收到ping響應:

在aux2上進行抓包,結果如圖1-19所示,aux2主機上收到了ping請求報文,但是由于aux2上未配置回程路由,所以aux2無法對此ping請求進行應答。

圖1-19 iptables nat表實驗:aux未配置iptables規則,aux2抓包

那么有沒有辦法在aux2主機不配置回程路由的前提下,使exp主機能夠正常對aux2主機進行ping測試呢?當然是有的,只要aux主機在轉發exp主機的請求報文時執行一次源地址轉換,問題就解決了。

按照上述思路,在aux主機上增加如下配置:

根據iptables規則,對接收的源地址為172.16.0.3的ICMP報文進行源地址轉換。接下來,再次嘗試在exp主機上發起對aux2主機的ping請求,結果顯示網絡連通。

查看aux2主機上的抓包結果,如圖1-20所示。

圖1-20 iptables nat表實驗:aux配置iptables規則,aux2抓包

對于aux2主機,它收到的ping請求的源地址是aux主機地址(192.168.20.3),這也就可以肯定aux主機對轉發的ping請求報文做了源地址轉換。

最后檢查aux主機的連接跟蹤信息。Linux內核中所有連接跟蹤均由conntrack組件管理,使用conntrack命令可以查看系統中已經存在的網絡連接信息,此命令能夠顯示通信雙方的IP地址、協議連接狀態等。

aux主機上conntrack命令的執行結果如下:

每條信息都包含兩組數據,分別對應從發送端接收的報文和從響應端接收的報文。下面以第二行的ICMP流信息為例進行說明。

?第一組數據表示本機收到的請求報文,本例中aux主機接收的請求報文的源地址為172.16.0.3、目的地址為192.168.20.1、type值為8(8表示報文為Echo Request類型)。

?第二組數據表示本機收到的響應報文,本例中aux主機接收的應答報文的源地址為192.168.20.1、目的地址為192.168.20.3、type值為0(0表示報文為Echo Reply類型)。

conntrack組件會為NAT的每次轉換都創建一條記錄。內核收到報文時優先在conntrack中查詢當前報文是否存在連接信息,如果存在,則直接根據此連接信息還原報文地址并轉發。

3.mangle表

mangle表用于修改數據報文IP頭中的參數,如TOS、TTL(Time To Live,生存周期)、數據報文的Mark標志等。Mangle表包含5條預定義鏈,覆蓋iptables的所有掛載點,在任意掛載點上均可以設置規則對報文的字段進行修改。

以TOS字段為例,RFC 1349定義了TOS的取值范圍。該字段一共包含8個比特位,每個比特位的含義如表1-5所示。

表1-5 TOS字段中比特位的含義

如果用戶期望將某種類型的報文設置為最低延遲,則可以通過設置iptables規則將此報文的TOS屬性修改為0x10。例如,下面的命令將HTTP(端口號80)、TELNET(端口號23)、SSH(端口號22)類型的報文設置為最低延遲:

其他字段的使用方法與之相似,不再贅述。

4.raw表

默認情況下,conntrack組件跟蹤內核處理的每條報文,如果希望某些報文不受conntrack組件跟蹤,那該如何處理呢?iptables提供的raw表用于處理此場景。用戶在raw表中增加目標為NOTRACK的規則,一旦此規則匹配成功,那么這條報文將不受conntrack組件的跟蹤。

從功能上看,raw表只能在入口處執行處理操作,所以該表僅包含兩條預定義鏈:OUTPUT和PREROUTING。

本書不涉及mangle表和raw表的功能,如需了解更多請參考“iptables Tutorial 1.2.2”[2]

1.4.3 iptables命令

限于篇幅,本節僅講述后續用到的iptables命令及相關參數。

命令格式:

其命令參數包含如下4段。

?[-t table]:選擇本次操作的表。table參數的取值范圍包括raw、mangle、nat、filter。如果不指定,則默認操作filter表。

?<command>:指定本次操作命令,如增加規則、刪除規則等。

?[rule]:匹配規則,即如何篩選報文。

?[-j target]:匹配成功后執行的動作。

1.操作命令(command)

操作命令用于指定本命令執行的動作,常用的操作命令如表1-6所示。

表1-6 iptables常用操作命令列表

iptables常用操作命令示例:

2.規則(rule)

iptables常用的規則如表1-7所示。

表1-7 iptables常用規則列表

iptables常用規則示例:

3.目標(target)

“-j target”表示匹配到規則后執行的動作、策略,表1-8展示了常用的動作。

表1-8 iptables常用動作列表

iptables常用動作示例:

關于MARK、DNAT、SNAT和MASQUERADE的應用請參考1.4.4節。

1.4.4 iptables應用

1.目的地址轉換

DNAT操作只能用在nat表的PREROUTING和OUTPUT鏈上。使用DNAT操作時,iptables提供了額外的擴展選項,參考表1-9。

表1-9 DNAT擴展選項

下面的示例用于將目的地址為10.0.1.10:80、目的端口號為80的TCP報文通過DNAT操作轉換到192.168.1.1:80上:

下面演示地址范圍的應用。設置目的地址范圍為192.168.1.1-192.168.1.10,執行目的地址轉換操作時,內核隨機選擇范圍內地址作為目的地址:

2.源地址轉換

源地址轉換支持兩種動作——MASQUERADE和SNAT,其差異在于SNAT要求指定源地址。所以,如果待替換的源地址是靜態分配的,則可以使用SNAT操作(也可以使用MASQUERADE操作)。例如,一組主機共享一個靜態的外部地址訪問Internet,可以使用SNAT操作指定源地址方案。在其他場景中,建議使用MASQUERADE操作,內核自動選擇一個合適的地址作為源地址。MASQUERADE覆蓋SNAT功能,所以建議盡量使用MASQUERADE操作。

SNAT的擴展選項與DNAT類似,參考表1-10。

表1-10 SNAT擴展選項

使用MASQUERADE時無須指定源地址,其擴展選項較于SNAT簡單一些,參考表1-11。

表1-11 MASQUERADE擴展選項

下面看SNAT的例子,在參數中指定源地址和端口范圍:

MASQUERADE訪問外部網絡時,內核自動選擇源IP地址,用戶指定源端口范圍(也可以不指定,由內核隨機選擇端口):

3.設置報文標志

MARK動作用于給報文打標志,一個報文可能存在兩種標志。

?nfmark(Netfilter mark,Netfilter標志):用于給數據報文打標志,該標志長度為32比特,用戶根據需要對報文打標志。

?ctmark(connection mark,連接標志):用于給連接打標志,僅用在mangle表中。

iptables中的“--set-mark/--set-xmark value[/mask]”參數用于設置指定報文的nfmark值。對此,命令幫助信息如下:[3]

上述幫助信息中已經給出了詳細算法:首先獲得mask參數中取值為1的比特位列表,將nfmark數據中對應的比特位設置為0,然后對mask和value進行“或”操作(--set-mark)、“異或”操作(--set-xmark)。

使用C語言描述上述算法:

如果執行命令時未指定mask值,則認為mask值為0xFFFFFFFF。

為了方便用戶配置,iptables提供了簡化的參數。

?“--and-mark bits”,等價于“--set-xmark 0/invbits”。

?“--or-mark bits”,等價于“--set-xmark bits/bits”。

?“--xor-mark bits”,等價于“--set-xmark bits/0”。

以Kubernetes提供的iptables規則為例進行說明。下面的規則用于給報文打上“需要進行NAT轉換(0x4000)”的標志:

命令參數為“--set-xmark 0x4000/0x4000”,用C語言描述如下:

執行此命令相當于將該數據報文的nfmark的第14個比特位設置為1。

4.比較報文標志

使用mark參數判斷報文的nfmark值是否滿足要求,參數說明如下:

此參數用于比較nfmark值是否滿足指定的條件。其算法步驟為首先對nfmark與mask執行“與”操作,然后與value值進行比較。

用C語言描述上述算法:

如果未指定mask,則認為mask值為0xFFFFFFFF。

以Kubernetes提供的iptables規則為例進行說明。下面的規則用于判斷數據報文是否打上了“需要進行NAT轉換0x4000”的標志:

第一條規則的命令參數為“!--mark 0x4000/0x4000”,即判斷nfmark&0x4000與0x4000是否相等:如果不相等,則匹配成功,直接返回;如果相等,則匹配失敗,繼續執行下一條規則。

第二條規則的命令參數為“--set-xmark 0x4000/0x0”,用于清除nfmark的第14個比特位的值。

主站蜘蛛池模板: 兰坪| 朝阳市| 嘉义县| 高淳县| 聂荣县| 金溪县| 浦城县| 达孜县| 上思县| 隆尧县| 平乡县| 紫金县| 荃湾区| 恭城| 建德市| 葫芦岛市| 夏邑县| 永德县| 大理市| 阜宁县| 固阳县| 富宁县| 吉安县| 吉木乃县| 河西区| 潼南县| 阿勒泰市| 临沭县| 镇宁| 淮北市| 伊宁县| 平阳县| 保德县| 贵阳市| 枣庄市| 姜堰市| 阜新市| 石林| 辉南县| 太仆寺旗| 富锦市|