核心版本:2.6.34
NetFilter在2.4.x核心中引入,成為linux平台下進行網路應用的主要擴充,不僅包括防火牆的實現 ,還包括報文的處理(如報文加密、報文分類統計等)等。
NetFilter資料結構 勾子struct nf_hook_ops[net\filter\core.c]
struct nf_hook_ops { struct list_head list; /* User fills in from here down. */ nf_hookfn *hook; struct module *owner; u_int8_t pf; unsigned int hooknum; /* Hooks are ordered in ascending priority. */ int priority; };
成員list用於鏈入全域勾子數組nf_hooks中,它一定在第一位,保證&nf_hook_ops->list的值與 &nf_hook_ops相同,稍後在使用時會用到這一技巧;
成員hook即使用者定義的勾子函數;owner表示註冊這個勾子函數的模 塊,因為netfilter是核心空間的,所以一般為模組來完成勾子函數註冊;pf與hooknum一起索引到特定協議特定編號的勾子函數 隊列,用於索引nf_hooks;priority決定在同一隊列(pf與hooknum相同)的順序,priority越小則排列越靠前。
struct nf_hook_ops只是儲存勾子的資料結構,而真正儲存這些勾子供協議棧調用的是nf_hooks,從定義可以看出,它其實就是二維數 組的鏈表。
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; [net\filter\core.c]
其中NFPROTO_NUMPROTO表示勾子關聯的協議,可取值:
enum { NFPROTO_UNSPEC = 0, NFPROTO_IPV4 = 2, NFPROTO_ARP = 3, NFPROTO_BRIDGE = 7, NFPROTO_IPV6 = 10, NFPROTO_DECNET = 12, NFPROTO_NUMPROTO, };
NF_MAX_HOOKS表示勾子應用的位置,可選值在每個協議模組內部定義,這些值代表了勾子函數在協議流程中應用的 位置(稍後會以bridge為例詳細說明),大致上都有以下值:
NF_XXX_PRE_ROUTING, NF_XXX_LOCAL_IN, NF_XXX_FORWARD, NF_XXX_LOCAL_OUT, NF_XXX_POST_ROUTING, NF_XXX_NUMHOOKS
NetFilter註冊
在瞭解了nf_hook_ops和nf_hooks後,來看下如何操作nf_hooks中的元素。
nf_register_hook()將nf_hook_ops註冊到nf_hooks中:
int nf_register_hook(struct nf_hook_ops *reg) { struct nf_hook_ops *elem; int err; err = mutex_lock_interruptible(&nf_hook_mutex); if (err < 0) return err; list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) { if (reg->priority < elem->priority) break; } list_add_rcu(?->list, elem->list.prev); mutex_unlock(&nf_hook_mutex); return 0; }
這個函數很簡單,從指定pf&hooknum的nf_hooks隊列遍曆,按priority從小到大順序,將reg插入相應位置,完 成勾子函數的註冊。
nf_unregister_hook()將nf_hook_ops從nf_hooks中登出掉:
void nf_unregister_hook(struct nf_hook_ops *reg) { mutex_lock(&nf_hook_mutex); list_del_rcu(?->list); mutex_unlock(&nf_hook_mutex); synchronize_net(); }
這個函數更簡單,從nf_hooks中刪除reg。
核心同時還提供了nf_register_hooks()和nf_unregister_hooks(),將reg重複註冊n次或將reg從nf_hooks中登出n次。當勾子函數註冊完成後,nf_hooks的結構如圖所示: