經過註冊流程代碼的分析,可以明確鉤子函數的註冊流程,理解存儲鉤子函數的數據結構,以下圖(點擊圖片可查看原圖);linux
廢話很少說,開始分析;數組
nf_hook_ops是註冊的鉤子函數的核心結構,字段含義以下所示,通常待註冊的鉤子函數會組成一個nf_hook_ops數組,在註冊過程當中調用nf_register_net_hooks將全部規則加入到指定的鉤子點;數據結構
1 struct nf_hook_ops { 2 struct list_head list; 3 4 /* User fills in from here down. */ 5 nf_hookfn *hook; /* 鉤子函數 */ 6 struct net_device *dev; /* 設備 */ 7 void *priv; /* 私有數據 */ 8 u_int8_t pf; /* 協議族 */ 9 unsigned int hooknum; /* 鉤子點 */ 10 /* Hooks are ordered in ascending priority. */ 11 int priority; /* 優先級 */ 12 };
鉤子函數nf_hookfn的原型爲:tcp
1 typedef unsigned int nf_hookfn(void *priv, 2 struct sk_buff *skb, 3 const struct nf_hook_state *state);
nf_register_net_hooks在註冊多個鉤子函數時使用,它對多個函數順序調用nf_register_net_hook進行註冊,而且在註冊失敗時進行回滾;函數
1 int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, 2 unsigned int n) 3 { 4 unsigned int i; 5 int err = 0; 6 7 /* 循環註冊鉤子函數 */ 8 for (i = 0; i < n; i++) { 9 err = nf_register_net_hook(net, ®[i]); 10 /* 失敗 */ 11 if (err) 12 goto err; 13 } 14 return err; 15 16 err: 17 /* 註銷本次已註冊的鉤子函數 */ 18 if (i > 0) 19 nf_unregister_net_hooks(net, reg, i); 20 return err; 21 }
多個鉤子函數在註冊以後,是以多個nf_hook_entry實例的鏈表的形式存在的,其成員以下;spa
1 struct nf_hook_entry { 2 struct nf_hook_entry __rcu *next; /* 下一節點 */ 3 nf_hookfn *hook; /* 鉤子函數 */ 4 void *priv; /* 私有數據 */ 5 const struct nf_hook_ops *orig_ops; /* 鉤子操做 */ 6 };
nf_register_net_hook爲鉤子函數註冊的主流程,首先找到鉤子點函數的入口,而後根據優先級將當前註冊的鉤子函數插入到鏈表中;nuxt
1 int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) 2 { 3 struct nf_hook_entry __rcu **pp; 4 struct nf_hook_entry *entry, *p; 5 6 if (reg->pf == NFPROTO_NETDEV) { 7 #ifndef CONFIG_NETFILTER_INGRESS 8 if (reg->hooknum == NF_NETDEV_INGRESS) 9 return -EOPNOTSUPP; 10 #endif 11 if (reg->hooknum != NF_NETDEV_INGRESS || 12 !reg->dev || dev_net(reg->dev) != net) 13 return -EINVAL; 14 } 15 16 /* 找到鉤子點鏈表頭部 */ 17 pp = nf_hook_entry_head(net, reg); 18 if (!pp) 19 return -EINVAL; 20 21 /* 分配鉤子入口結構 */ 22 entry = kmalloc(sizeof(*entry), GFP_KERNEL); 23 if (!entry) 24 return -ENOMEM; 25 26 /* 初始化 */ 27 nf_hook_entry_init(entry, reg); 28 29 mutex_lock(&nf_hook_mutex); 30 31 /* Find the spot in the list */ 32 /* 找到鉤子應該插入的位置 */ 33 for (; (p = nf_entry_dereference(*pp)) != NULL; pp = &p->next) { 34 if (reg->priority < nf_hook_entry_priority(p)) 35 break; 36 } 37 38 /* 插入鉤子點 */ 39 rcu_assign_pointer(entry->next, p); 40 rcu_assign_pointer(*pp, entry); 41 42 mutex_unlock(&nf_hook_mutex); 43 #ifdef CONFIG_NETFILTER_INGRESS 44 if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) 45 net_inc_ingress_queue(); 46 #endif 47 #ifdef HAVE_JUMP_LABEL 48 static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]); 49 #endif 50 return 0; 51 }
nf_hook_entry_head的做用爲查找鉤子點函數入口,從這個函數中,咱們能夠看到,鉤子函數存放位置爲net->nf.hooks[pf] + hooknum;code
1 static struct nf_hook_entry __rcu **nf_hook_entry_head(struct net *net, const struct nf_hook_ops *reg) 2 { 3 if (reg->pf != NFPROTO_NETDEV) 4 return net->nf.hooks[reg->pf]+reg->hooknum; 5 6 #ifdef CONFIG_NETFILTER_INGRESS 7 if (reg->hooknum == NF_NETDEV_INGRESS) { 8 if (reg->dev && dev_net(reg->dev) == net) 9 return ®->dev->nf_hooks_ingress; 10 } 11 #endif 12 return NULL; 13 }
進一步查看net結構,其成員爲struct netns_nf nf;blog
1 struct net { 2 3 #ifdef CONFIG_NETFILTER 4 struct netns_nf nf; 5 struct netns_xt xt; 6 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 7 struct netns_ct ct; 8 #endif 9 #if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE) 10 struct netns_nftables nft; 11 #endif 12 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) 13 struct netns_nf_frag nf_frag; 14 #endif 15 struct sock *nfnl; 16 struct sock *nfnl_stash; 17 #if IS_ENABLED(CONFIG_NETFILTER_NETLINK_ACCT) 18 struct list_head nfnl_acct_list; 19 #endif 20 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 21 struct list_head nfct_timeout_list; 22 #endif 23 24 };
進一步查看netns_nf結構,其中有以下成員,struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; 可見,其鉤子函數入口形式爲hooks[協議族][鉤子點],在二維數組的每一個節點都對應着一個鉤子函數鏈表,內部多個nf_hook_entry經過優先級從小到大排列;圖片
1 struct netns_nf { 2 #if defined CONFIG_PROC_FS 3 struct proc_dir_entry *proc_netfilter; 4 #endif 5 const struct nf_queue_handler __rcu *queue_handler; 6 const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO]; 7 #ifdef CONFIG_SYSCTL 8 struct ctl_table_header *nf_log_dir_header; 9 #endif 10 struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; 11 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) 12 bool defrag_ipv4; 13 #endif 14 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) 15 bool defrag_ipv6; 16 #endif 17 };
協議的定義以下:
1 enum { 2 NFPROTO_UNSPEC = 0, 3 NFPROTO_INET = 1, 4 NFPROTO_IPV4 = 2, 5 NFPROTO_ARP = 3, 6 NFPROTO_NETDEV = 5, 7 NFPROTO_BRIDGE = 7, 8 NFPROTO_IPV6 = 10, 9 NFPROTO_DECNET = 12, 10 NFPROTO_NUMPROTO, 11 };
IPv4鉤子點的定義以下:
1 enum nf_inet_hooks { 2 NF_INET_PRE_ROUTING, 3 NF_INET_LOCAL_IN, 4 NF_INET_FORWARD, 5 NF_INET_LOCAL_OUT, 6 NF_INET_POST_ROUTING, 7 NF_INET_NUMHOOKS 8 };
註冊流程到此爲止;