成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Netfileter & Iptables 實現之 Netfilter實現

開發 前端
在《Netfilter & iptables 原理》一文中,我們介紹了 Netfilter 和 iptables 的原理,而本文主要通過源碼分析來介紹一下 Netfilter 與 iptables 的實現過程。

 [[393194]]

本文轉載自微信公眾號「Linux內核那些事」,作者songsong001。轉載本文請聯系Linux內核那些事公眾號。

在《Netfilter & iptables 原理》一文中,我們介紹了 Netfilter 和 iptables 的原理,而本文主要通過源碼分析來介紹一下 Netfilter 與 iptables 的實現過程。

一、Netfilter 掛載點

我們先來回顧一下 Netfilter 的原理,Netfilter 是通過在網絡協議棧的不同階段注冊鉤子函數來實現對數據包的處理與過濾,如 圖1 所示:

(圖1 Netfilter掛載點)

在 圖1 中,藍色部分就是 Netfilter 掛載鉤子函數的位置,所以 Netfilter 定義了 5 個常量來表示這 5 個位置,如下代碼:

  1. // 文件:include/linux/netfilter_ipv4.h 
  2.  
  3. #define NF_IP_PRE_ROUTING   0 
  4. #define NF_IP_LOCAL_IN      1 
  5. #define NF_IP_FORWARD       2 
  6. #define NF_IP_LOCAL_OUT     3 
  7. #define NF_IP_POST_ROUTING  4 

上面代碼中的常量與 圖1 中掛載鉤子函數的位置一一對應,如常量 NF_IP_PRE_ROUTING 對應著 圖1 的 PRE_ROUTING 處。

二、Netfilter 鉤子函數鏈

前面說過,Netfilter 是通過在網絡協議中的不同位置掛載鉤子函數來對數據包進行過濾和處理,而且每個掛載點能夠掛載多個鉤子函數,所以 Netfilter 使用鏈表結構來存儲這些鉤子函數,如 圖2 所示:

(圖2 Netfilter鉤子函數鏈)

如 圖2 所示,Netfilter 的每個掛載點都使用一個鏈表來存儲鉤子函數列表。在內核中,定義了一個名為 nf_hooks 的數組來存儲這些鏈表,如下代碼:

  1. // 文件:net/core/netfilter.c 
  2.  
  3. struct list_head nf_hooks[32][5]; 

struct list_head 結構是內核的通用鏈表結構。

從 nf_hooks 變量定義為一個二維數組,第一維是用來表示不同的協議(如 IPv4 或者 IPv6,本文只討論 IPv4,所以可以把 nf_hooks 當成是一維數組),而第二維用于表示不同的掛載點,如 圖2 中的 5 個掛載點。

三、鉤子函數

接下來我們介紹一下鉤子函數在 Netfilter 中的存儲方式。

前面我們介紹過,Netfilter 通過鏈表來存儲鉤子函數,而鉤子函數是通過結構 nf_hook_ops 來描述的,其定義如下:

  1. // 文件:include/linux/netfilter.h 
  2.  
  3. struct nf_hook_ops 
  4.     struct list_head list; // 連接相同掛載點的鉤子函數 
  5.     nf_hookfn *hook;       // 鉤子函數指針 
  6.     int pf;                // 協議類型 
  7.     int hooknum;           // 鉤子函數所在鏈 
  8.     int priority;          // 優先級 
  9. }; 

下面我們對 nf_hook_ops 結構的各個字段進行說明:

  • list:用于把處于相同掛載點的鉤子函數鏈接起來。
  • hook:鉤子函數指針,就是用于處理或者過濾數據包的函數。
  • pf:協議類型,用于指定鉤子函數掛載在 nf_hooks 數組第一維的位置,如 IPv4 協議設置為 PF_INET。
  • hooknum:鉤子函數所在鏈(掛載點),如 NF_IP_PRE_ROUTING。
  • priority:鉤子函數的優先級,用于管理鉤子函數的調用順序。

其中 hook 字段的類型為 nf_hookfn,nf_hookfn 類型的定義如下:

  1. // 文件:include/linux/netfilter.h 
  2.  
  3. typedef unsigned int nf_hookfn(unsigned int hooknum, 
  4.                                struct sk_buff **skb, 
  5.                                const struct net_device *in
  6.                                const struct net_device *out
  7.                                int (*okfn)(struct sk_buff *)); 

我們也介紹一下 nf_hookfn 函數的各個參數的作用:

  • hooknum:鉤子函數所在鏈(掛載點),如 NF_IP_PRE_ROUTING。
  • skb:數據包對象,就是要處理或者過濾的數據包。
  • in:接收數據包的設備對象。
  • out:發送數據包的設備對象。
  • okfn:當掛載點上所有的鉤子函數都處理過數據包后,將會調用這個函數來對數據包進行下一步處理。

四、注冊鉤子函數

當定義好一個鉤子函數結構后,需要調用 nf_register_hook 函數來將其注冊到 nf_hooks 數組中,nf_register_hook 函數的實現如下:

  1. // 文件:net/core/netfilter.c 
  2.  
  3. int nf_register_hook(struct nf_hook_ops *reg) 
  4.     struct list_head *i; 
  5.  
  6.     br_write_lock_bh(BR_NETPROTO_LOCK); // 對 nf_hooks 進行上鎖 
  7.  
  8.     // priority 字段表示鉤子函數的優先級 
  9.     // 所以通過 priority 字段來找到鉤子函數的合適位置 
  10.     for (i = nf_hooks[reg->pf][reg->hooknum].next
  11.          i != &nf_hooks[reg->pf][reg->hooknum]; 
  12.          i = i->next
  13.     { 
  14.         if (reg->priority < ((struct nf_hook_ops *)i)->priority) 
  15.             break; 
  16.     } 
  17.  
  18.     list_add(&reg->list, i->prev); // 把鉤子函數添加到鏈表中 
  19.  
  20.     br_write_unlock_bh(BR_NETPROTO_LOCK); // 對 nf_hooks 進行解鎖 
  21.  
  22.     return 0; 

nf_register_hook 函數的實現比較簡單,步驟如下:

  • 對 nf_hooks 進行上鎖操作,用于保護 nf_hooks 變量不受并發競爭。
  • 通過鉤子函數的優先級來找到其在鉤子函數鏈表中的正確位置。
  • 把鉤子函數插入到鏈表中。
  • 對 nf_hooks 進行解鎖操作。

插入過程如 圖3 所示:

(圖3 鉤子函數插入過程)

如 圖3 所示,我們要把優先級為 20 的鉤子函數插入到 PRE_ROUTING 這個鏈中,而 PRE_ROUTING 鏈已經存在兩個鉤子函數,一個優先級為 10, 另外一個優先級為 30。

通過與鏈表中的鉤子函數的優先級進行對比,發現新的鉤子函數應該插入到優先級為 10 的鉤子函數后面,所以就 如圖3 所示就把新的鉤子函數插入到優先級為 10 的鉤子函數后面。

五、觸發調用鉤子函數

鉤子函數已經被保存到不同的鏈上,那么什么時候才會觸發調用這些鉤子函數來處理數據包呢?

要觸發調用某個掛載點上(鏈)的所有鉤子函數,需要使用 NF_HOOK 宏來實現,其定義如下:

  1. // 文件:include/linux/netfilter.h 
  2.  
  3. #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)    \ 
  4.     (list_empty(&nf_hooks[(pf)][(hook)])               \ 
  5.         ? (okfn)(skb)                                  \ 
  6.         : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn))) 

首先介紹一下 NF_HOOK 宏的各個參數的作用:

  • pf:協議類型,就是 nf_hooks 數組的第一個維度,如 IPv4 協議就是 PF_INET。
  • hook:要調用哪一條鏈(掛載點)上的鉤子函數,如 NF_IP_PRE_ROUTING。
  • indev:接收數據包的設備對象。
  • outdev:發送數據包的設備對象。
  • okfn:當鏈上的所有鉤子函數都處理完成,將會調用此函數繼續對數據包進行處理。

而 NF_HOOK 宏的實現也比較簡單,首先判斷一下鉤子函數鏈表是否為空,如果是空的話,就直接調用 okfn 函數來處理數據包,否則就調用 nf_hook_slow 函數來處理數據包。我們來看看 nf_hook_slow 函數的實現:

  1. // 文件:net/core/netfilter.c 
  2.  
  3. int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, 
  4.                  struct net_device *indev, struct net_device *outdev, 
  5.                  int (*okfn)(struct sk_buff *)) 
  6.     struct list_head *elem; 
  7.     unsigned int verdict; 
  8.     int ret = 0; 
  9.  
  10.     elem = &nf_hooks[pf][hook]; // 獲取要調用的鉤子函數鏈表 
  11.  
  12.     // 遍歷鉤子函數鏈表,并且調用鉤子函數對數據包進行處理 
  13.     verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, outdev, &elem, okfn); 
  14.     ... 
  15.     // 如果處理結果為 NF_ACCEPT, 表示數據包通過所有鉤子函數的處理, 那么就調用 okfn 函數繼續處理數據包 
  16.     // 如果處理結果為 NF_DROP, 表示數據包被拒絕, 應該丟棄此數據包 
  17.     switch (verdict) { 
  18.     case NF_ACCEPT: 
  19.         ret = okfn(skb); 
  20.         break; 
  21.     case NF_DROP: 
  22.         kfree_skb(skb); 
  23.         ret = -EPERM; 
  24.         break; 
  25.     } 
  26.  
  27.     return ret; 

nf_hook_slow 函數的實現也比較簡單,過程如下:

  • 首先調用 nf_iterate 函數來遍歷鉤子函數鏈表,并調用鏈表上的鉤子函數來處理數據包。
  • 如果處理結果為 NF_ACCEPT,表示數據包通過所有鉤子函數的處理, 那么就調用 okfn 函數繼續處理數據包。
  • 如果處理結果為 NF_DROP,表示數據包沒有通過鉤子函數的處理,應該丟棄此數據包。

既然 Netfilter 是通過調用 NF_HOOK 宏來調用鉤子函數鏈表上的鉤子函數,那么內核在什么地方調用這個宏呢?

比如數據包進入 IPv4 協議層的處理函數 ip_rcv 函數中就調用了 NF_HOOK 宏來處理數據包,代碼如下:

  1. // 文件:net/ipv4/ip_input.c 
  2.  
  3. int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) 
  4.     ... 
  5.     return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish); 

如上代碼所示,在 ip_rcv 函數中調用了 NF_HOOK 宏來處理輸入的數據包,其調用的鉤子函數鏈(掛載點)為 NF_IP_PRE_ROUTING。而 okfn 設置為 ip_rcv_finish,也就是說,當 NF_IP_PRE_ROUTING 鏈上的所有鉤子函數都成功對數據包進行處理后,將會調用 ip_rcv_finish 函數來繼續對數據包進行處理。

六、總結

本文主要介紹了 Netfilter 的實現,因為 Netfilter 是 Linux 網絡數據包過濾的框架,而 iptables 就是建立在 Netfilter 之上的。所以,先了解 Netfilter 的實現對分析 iptables 的實現有非常大的幫助。

而在下一章中,我們將會繼續分析 iptables 的實現。

責任編輯:武曉燕 來源: Linux內核那些事
相關推薦

2011-03-15 12:47:11

netfilteriptables

2011-03-15 15:47:30

netfilteriptables安裝

2011-03-15 10:00:01

NetfilterIPTables

2011-03-15 15:47:26

netfilteriptables

2011-03-15 09:10:43

iptables防火墻

2011-03-15 15:51:12

netfilteriptables

2010-12-07 09:51:43

Linux安全性netfilteriptables

2011-03-15 15:47:34

netfilteriptables

2011-03-15 10:48:47

2011-03-15 09:10:47

iptablesNAT

2011-03-15 14:26:23

iptablesNAT

2011-03-16 09:05:32

RedhatiptablesNAT

2011-03-16 09:05:29

iptablesNAT

2011-03-16 13:29:33

iptables 端口

2011-03-16 10:52:20

2011-03-16 09:05:33

2011-03-16 09:05:53

NATiptables

2011-07-05 14:34:23

2011-07-13 10:30:09

2022-10-27 20:31:19

iptablesnetfilter
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99re在线视频| 久久久久一区 | 国产激情一区二区三区 | 老外黄色一级片 | 国产精品久久久久久久7电影 | 伊人久久国产 | 欧美成人性生活 | 日本久久福利 | 国产精品免费在线 | 成人久久18免费网站图片 | 日本一区二区三区在线观看 | h视频在线免费 | 久久网站免费视频 | 色偷偷人人澡人人爽人人模 | 国产精品久久99 | 香蕉视频在线播放 | 三级在线视频 | av网站在线免费观看 | 亚洲日本欧美日韩高观看 | 国产成人久久精品 | 99精品亚洲国产精品久久不卡 | 欧美老妇交乱视频 | 四虎免费视频 | 欧美激情综合五月色丁香小说 | jlzzjlzz国产精品久久 | 免费中文字幕 | 91精品国产91久久综合桃花 | 日韩在线观看中文字幕 | 久久久久久久久久久爱 | 18av在线播放 | 99re在线免费视频 | 欧美在线观看网站 | 欧美多人在线 | 国产精品免费一区二区三区四区 | 亚洲a在线观看 | 亚洲有码转帖 | 亚洲欧美激情精品一区二区 | 成人天堂| 一区二区三区电影网 | 精品视频免费 | 国产成人精品一区二区三 |