【推荐阅读】
通过注册流程代码的分析,能够明确钩子函数的注册流程,理解存储钩子函数的数据结构,如下图(点击图片可查看原图);

废话不多说,开始分析;
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的原型为:
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实例的链表的形式存在的,其成员如下;
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为钩子函数注册的主流程,首先找到钩子点函数的入口,然后根据优先级将当前注册的钩子函数插入到链表中;
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;
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;
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 };
注册流程到此为止;