在(一)中說到,報文在內核協議棧中會途經5
個HOOK
點,在每個HOOK
點上會依次執行鏈表上的鉤子函數,那麼這些鉤子函數是如何與用戶使用iptables
下發的各個rule
聯繫起來的呢?這些rule
又是如何存儲的呢? 本文詳細描述這個問題。
table
內核使用struct xt_table
這個結構來表示一個表(table
)。結構中記錄了這個表在哪些HOOK
點有效,它的private
指針保存了這個表包含的所有規則。
每個新的net namespace
創建時,Netfitler
會創建所有屬於當前net namespace
的表,並將其記錄到自己的net namespace
中。
從圖中可以看出,創建一個包含默認rule
的table
分兩步
- 根據已有的模板,生成默認
rule
- 註冊
table
到Netfilter
框架中
生成默認rule
如果你使用過iptables
,可能會知道每張table
的每條chain
都有一個默認POLICY
,它表示chain
中的所有的rule
都不匹配,則執行默認的行爲。這個默認行爲可以通過iptables
配置,在系統啓動時默認行爲都被設置爲NF_ACCEPT
.而這裏的默認rule
就是這個意思,Netfilter
會爲每個chain
創建一條默認的rule
,並將它們加入到table
ipt_replace
上圖創建默認rule
的時候使用了一個struct ipt_replace
的結構,這個結構的來歷和iptables
的配置方法是緊密相連的:iptables
採用的是讀-修改-寫
的方式進行配置的!
舉個例子,當你使用iptables
向Netfilter
的filter
表添加一條新的rule
時,iptables
會將filter
整個表讀取到用戶空間,在用戶空間修改完成後,再將其重新設置到Netfilter
。所以,這是一個替換(Replace
)的過程。
因此,ipt_replace
一般就是指用戶使用iptables
下發的表。典型的結構如下:
hook_entry
和underflow
分別表示各個HOOK
上的第一條rule
和最後一條rule
的偏移(具體的規則在最後一個ipt_entry
的柔性數組裏!)
但在這裏,由於還處於初始化階段,所以這裏的repl
是內核自己由packet_filter
模板生成的,它會爲filter
所在的LOCAL_IN
、FORWARD
、LOCAL_OUT
這幾個HOOK
點各創建一條默認rule
.
ipt_entry
內核使用struct ipt_entry
表示一條用戶使用iptables
配置的rule
. 這個結構後面會緊跟若干個ipt_entry_match
結構和1個ipt_standard_target
結構。它與一條用戶配置的iptables
的關係如下:
其中
ipt_entry
:表示標準匹配結構。包括報文的源IP、目的IP、入接口、出接口等條件ipt_entry_match
:表示擴展匹配。一條完整的rule
包含零個到多個該結構ipt_standard_target
:表示匹配後的動作
如果對iptables
的匹配規則不太熟悉,建議點此擴展匹配瞭解一下
註冊 table 到 Netfilter 框架
在完成了默認規則的創建之後(保存在ipt_replace
),接下來就是應該註冊新的表了。
xt_table
中保存規則的private
指針類型是struct xt_table_info
,因此這裏第一部就是把repl
轉換爲newinfo
。接下來就是調用xt_register_table
創建新的表並註冊到框架了
註冊完成之後,Netfilter
可以通過net->xt.tables[af]
鏈表遍歷到所有註冊的表,也可以通過net->ipv4.
快速訪問到具體的表。