一般在 Linux kernel 中看見的 Netfilter
主要是在 IPv4 封包所會經過的五大掛鉤點
分別是 PREROUTING、INPUT、FORWARD、OUTPUT 和 POSTROUTING
封包進來後會先通過 PREROUTING 這個掛鉤
接下來會進行查表的動作來判斷封包是要往上送給本機端還是要轉送
如果是要轉送就會通過 FORWARD 這個掛鉤
如果是要往上送給本機端的就會通過 INPUT 這個掛鉤
通過 FORWARD 的封包會再往下通過 POSTROUTING 後往外傳送
至於從本機端產生的封包會先查表確定要往哪裡傳送
然後分別通過 OUTPUT 和 POSTROUTING 這兩個掛鉤後往外傳送
以上看到的是封包在 Netfilter 運作大致的流向
那麼 Netfilter 這些掛鉤是如何實作出來的呢
要知道
Linux kernel 中很多資料結構是使用所謂的 doubly linked list 去串起來的
這些掛鉤也不例外
(以下 kernel 版本為 2.6.29)
首先要先指出在 Netfilter 掛鉤中有兩個資料結構要去維持
第一個是只有 list head 的 nf_hooks
另外一個是掛鉤本身真正存放資料的資料結構 nf_hook_ops
nf_hooks 他只是一個頭的作用
用來把 nf_hook_ops 以及指示說他是哪個 protocol family
怎麼說呢?
因為 nf_hooks 它是一個二維的陣列
他被宣告成
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
其中 NFPROTO_NUMPROTO 是 13,NF_MAX_HOOKS 是 8
所以如果 protocol family 是 IPv4,然後我這個掛鉤是 PREROUTING
那這個資料結構就會被放置在以 nf_hooks[NFPROTO_IPV4][NF_INET_PRE_ROUTING] 為首的 list 之下
嗯嗯
就是靠這種方式把這些 nf_hook_ops 給串起來
那麼安插在 list 中的順序靠的是 priority
priority 愈高,安插的位置就會愈前面
至於被放到 list 之前則是要做所謂的「註冊」和「註銷」的動作
透過 nf_register_hook() 或 nf_register_hooks() 把 nf_hook_ops 加到 list 裡面
透過 nf_unregister_hook() 或 nf_unregister_hooks() 把 nf_hook_ops 從 list 中刪除
以 ip_rcv() 來看
在其底部呼叫了 NF_HOOK() 這個巨集以調用掛鉤
其中最後一個參數為 okfn()
表示當封包通過此掛鉤後
會去叫用 okfn() 以做進一步的處理
此例為 ip_rcv_finish()
NF_HOOK() 這個巨集被定義為 NF_HOOK_THRESH()
但是 NF_HOOK_THRESH() 實際上被定義為一個回傳值
假設叫用 nf_hook_thresh() 所回傳的值為一(允許通過)
則 NF_HOOK_THRESH() 的回傳值將定義為 okfn() 的回傳值
那麼 nf_hook_thresh() 是做什麼用的呢?
它的目的其實就是要叫用 Netfilter 掛鉤
因此 nf_hook_thresh() 是一個重要的分界點
假設使用者沒有以 iptables 設定任何規則
表示掛鉤為空、不存在
封包自然而然就會被允許通過
一切很合理
假設使用者有以 iptables 中設定一些規則
那麼在 nf_hooks 的某一個元素就會有 nf_hook_ops 被串聯在該 list 之下
則 nf_hook_slow() 會被呼叫用來處理串聯該 list 的掛鉤
nf_hook_slow() 裡面有一個重要的函式稱做 nf_iterate()
它會一一地去處理該 list 中每個掛鉤
每次處理一個掛鉤
會有一個回傳值存在 verdict 這個變數當中
可能是 NF_ACCEPT 或 NF_STOP 表示接收
可能是 NF_DROP 表示丟棄
可能是 NF_QUEUE 表示這個封包是要直接丟給應用層的
那重點是 nf_iterate() 又做了什麼事
nf_iterate() 會去一一叫用定義在 nf_hook_ops 中的 hook 來處理
這是 Netfilter 它程式碼連續呼叫的最底層
至於 hook 是什麼東西就是 iptables 的範圍了
在 net/ipv4/netfilter/iptable_filter.c 即有宣告 filter TABLE 中的三個掛鉤點
該 nf_hook_ops 應該被給定什麼值
這是屬於 iptables 這邊的範疇而不是 Netfilter
因為這兩個是分開實作的
注意到這些 nf_hook_ops 中的 hook
最後都會去叫用到 ipt_do_table() 這個函式
該函式才是真正去處理規則比對的部分
也就是做 packet match 的動作
然後取出 target
看是要接收、丟棄還是其它的動作
留言列表