Netfilter-iptabes報文過濾框架(一)

什麼是Netfilter/iptable

Netfilter/iptables是Linux內核內置的報文過濾框架,程序能夠經過該框架完成報文過濾、地址轉換(NAT)以及鏈接跟蹤等功能。html

Netfilter/iptables由兩部分組成,一部分是Netfilter的"鉤子(hook)",這些"鉤子"由Linux內核協議棧提供,內核模塊能夠經過註冊"鉤子"來完成各類各樣的功能。 另外一部分是iptables的規則,這些規則規定了"鉤子"如何工做。linux

下圖很直觀的說明了用戶空間的iptables和內核空間的ip_tables模塊、Netfilter之間的關係。數組

Netfilter

Netfilter是嵌入Linux內核協議棧的,設置在報文處理路徑上的一系列調用入口。 Netfilter一共有5個"鉤子"設置在IP協議棧的報文處理路徑上,這5個"鉤子"就是內嵌在內核協議棧的檢查點。 咱們能夠把處理函數註冊到各個檢查點,當報文通過各個檢查點時,就能夠經過"鉤子"函數對報文進行處理完成相應功能。框架

下圖說明了5個"鉤子"在內核協議棧的位置。 函數

"鉤子"的存儲及管理機制

在內核中,"鉤子"函數由一個全局二維數組nf_hooks按照協議族歸類存儲,在每一個協議族中,根據鉤子點順序排列,在鉤子點內則根據鉤子函數的優先級排列。 例如ipv4和ipv6就是兩個協議族,每一個協議族都包含5個"鉤子",每一個"鉤子"下面保存了註冊在這個"鉤子"上的函數地址。 學習

  • 這個二維數組的每一項表明了一個鉤子被調用的點,NF_PROTO表明協議棧,NF_HOOK表明協議棧中某個路徑點。
  • 全部模塊均可以經過nf_register_hook()函數將一個鉤子函數掛入想要被調用點的鏈表中(經過Protocol和hook指定一個點)。 這樣,該鉤子函數就可以處理從指定Protocol和指定hook點流過的數據包。
  • Netfilter在不一樣協議棧的不一樣點上放置鉤子函數,當數據包通過某個協議棧(NF_PROTO)的某個點(NF_HOOK)時,該協議棧會經過NF_HOOK()函數調用對應鉤子鏈表(nf_hooks[NF_PROTO][NF_HOOK])中註冊的每個鉤子項來處理該數據包。

Netfilter定義了每一個鉤子函數的返回值,每一個鉤子函數只能返回下面的返回值,而不能自定義返回值。.net

  • NF_DROP(0):數據包被丟棄,即不被下一個鉤子函數處理,同時也再也不被協議棧處理,並釋放數據包。
  • NF_ACCEPT(1):數據包被接受,即交給下一個鉤子或協議棧繼續處理。
  • NF_STOLEN(2):數據包被中止處理,即不被下一個鉤子函數處理,同時也再也不被協議棧處理,但不釋放數據包。
  • NF_QUEUE(3):將數據包交給nf_queue子系統處理,即不被下一個鉤子函數處理,同時也再也不被協議棧處理,也不釋放數據包。
  • NF_REPEAT(4):數據包將被該返回值的鉤子函數再次處理一遍。
  • NF_STOP(5): 數據包中止被該HOOK點的後續鉤子函數處理,交給協議棧繼續處理。

"鉤子"的使用方法

"鉤子"的使用首先實例化一個nf_hook_ops對象,而後對其進行必要的初始化設置,最後經過nf_register_hook()函數將其註冊到二維數組nf_hooks中。 咱們首先初始化nf_hook_ops中的經常使用字段:unix

<!-- lang: c -->
static struct nf_hook_ops nf_hook_test_ops = 
{
    .hook     = test_hook_func;
    .hooknum  = NF_INET_PRE_ROUTING;
    .pf       = PF_INET;
    .owner    = THIS_MODULE;
    .priority = NF_IP_PRI_FIRST;
}

其中:code

  • hook是鉤子函數
  • hooknum是鉤子點
  • pf是協議棧
  • priority是鉤子函數的優先級

而後在模塊加載和退出函數中註冊和移除鉤子函數:htm

<!-- lang: c -->
int init_module(void)
{
    nf_register_hook(&nf_hook_test_ops);
}
void cleanup_module() 
{
    nf_unregister_hook(&nf_hook_test_ops);
}

下面是回調函數的聲明:

<!-- lang: c -->
static unsigned int test_hook(unsigned int hooknum, struct sk_buff *skb,
	const struct net_device *in, const struct net_device *out,
	int (*okfn)(struct sk_buff*)

從上述過程能夠看出,鉤子函數的使用與iptables沒有任何關係,也就是說若是某個模塊須要對協議棧的報文進行處理,但不須要用戶空間的參數,那麼徹底能夠只註冊鉤子函數,而不須要編寫iptables的模塊。

即便須要用戶空間的參數,也能夠經過proc或者netlink等其餘用戶態和內核態通訊方式來傳遞參數,這樣就能夠更靈活的使用Netfilter了。

參考資料:

相關文章
相關標籤/搜索