Netfilter是如何工作的(一) HOOK點

寫在前面

本系列不是介紹How to配置iptables的文章。因爲網絡上已經有很多這類型的教程了,其中一些還不錯(比如鏈接).

本系列也不是一般意義上的Netfilter源碼分析文章。因爲大段粘貼代碼也會讓人心生畏懼和厭煩!

本系列文章的目標是,用盡量少的文字和圖片講明白How Netfilter work

Netfilter 的基本概念

Netfilter是一套融入Linux內核網絡協議棧中的報文處理(過濾或者修改)框架。它在內核中報文的關鍵流動路徑上定義了5HOOK點(下圖藍色方框),各個協議(如IPv4IPv6ARP)可以在這些HOOK點安裝鉤子函數,報文流經此地,內核會按照優先級調用這些鉤子函數,這些鉤子函數最終會決定報文是被NF_ACCEPT(放行)還是NF_DROP(丟棄)。

forward

圖中紅色虛線表示內核最常見的報文流經的路徑:本機接收轉發本機發送
5HOOK點分別是:路由前本地上送轉發本地發送路由後1

鏈(chain) & 表(table)

初次接觸iptables的同學可能會被四表五鏈這個名字嚇到,特別是這個名字真的很容易令人困惑! 而當你瞭解了Netfilter的實現細節後,纔會發現:噢,原來就是HOOK點,HOOK點就是,因爲有5HOOK點,所以有五鏈

那麼,爲什麼要叫呢?

因爲一個HOOK點可以上可以安裝多個鉤子, 內核用“鏈條”將這些鉤子串起來!

chain-rule

相比之下,四表(table)就沒那麼神祕了: 起過濾作用的filter表、起NAT作用的nat表,用於修改報文的mangle表,用於取消連接跟蹤的raw表。

Netfilter設計多個表的目的,一方面是方便分類管理,另一方面,更重要的是爲了限定各個鉤子(或者說用戶規則)執行的順序!

PREROUTING這個HOOK點爲例,用戶使用iptables設置的NAT規則和mangle會分別掛到nat hookmangle hookNAT表的優先級天生比mangle表低,因此報文一定會先執行mangle表的規則。

table-priority

這就是 四表五鏈 的概念。我個人認爲的比重要多了. 因爲就算Netfilter沒有表的概念,那麼通過小心翼翼地設置各個rule的順序其實也可以達到相同的效果。但(也就是HOOK點)的作用是獨一無二的。換個角度,用戶在配置iptables規則時,更多的精力也是放在**“應該在哪個HOOK點進行操作”**,至於用的是filter表、nat表還是其他表,其實都是順理成章的事情。

Hook

HOOK 點的位置

用戶通過iptables配置的規則最終會記錄在HOOK點。HOOK點定義在struct net結構中,即HOOK點是各個net namespace中獨立的。所以,在使用容器的場景中,每個容器的防火牆規則是獨立的。

struct net {
    /* code omitted */
    struct netns_nf		nf;
    /* code omitted */
}

struct netns_nf {
    /* code omitted */
	struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
};

從上面的定義可以看到,HOOK點是一個二維數組,每個元素都是一個鏈表頭。它的第一個維度是協議類型,其中最常用的NFPROTO_IPV4,我們使用的iptables命令都是將這個鉤子安裝到這個協議的hook,而使用ip6tables就是將鉤子安裝到NFPROTO_IPV6hook;第二個維度是,對於IPV4來說,它的取值範圍如下:

enum nf_inet_hooks{
    NF_INET_PRE_ROUTING,
    NF_INET_LOCAL_IN,
    NF_INET_FORWARD,
    NF_INET_LOCAL_OUT,
    NF_INET_POST_ROUTING,
    NF_INET_NUMHOOKS,
}

HOOK 點的元素

hooks的每個元素都是鏈表頭,鏈表上掛的元素類型是struct nf_hook_ops,這些元素有兩個來源,一類來自於Netfilter初始化時各個表(如filter)的初始化,另一類來自於如連接跟蹤這樣的內部模塊。下圖展示了第一類來源的元素的掛接情況,它們按優先級排列(數字越小優先級越高),而.hook就是報文到達對應的路徑時會執行的鉤子函數。

chain-list

附:相關內核函數的例子

iptable_filter_init 
  |--xt_hook_link
    |-- nf_register_hooks
       |-- nf_register_hook

HOOK 點的調用

Netfilter框架已經完全融入內核協議棧了,所以在協議棧代碼中常常可以看到NF_HOOK宏的調用,這個宏的參數指定了HOOK點。

以本機收到IPv4報文爲例

int ip_rcv(struct sk_buff* skb,...)
{
   // code omitted
   return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, net, NULL, skb, dev, NULL, ip_rcv_finish); 
   // code omitted
}

它指定要遍歷的鉤子函數是net namespacenethooks[NFPROTO_IPV4][NF_INET_PRE_ROUTING]鏈表上的元素,也就是上面圖中的第一行的鏈表。如果三個鉤子函數執行的結果(verdict)都是NF_ACCEPT,那麼NF_HOOK指定的ip_rcv_finish就會被執行。

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