linux 网络 如何 注册 钩子,注册钩子函数

[TOC]

### **简介**

每个钩子点的钩子函数是以链表的形式进行存储的。链表节点的结构为

```

struct nf_hook_ops {

struct list_head list;

/* User fills in from here down. */

nf_hookfn*hook;

struct net_device*dev;

void*priv;

u_int8_tpf;

unsigned inthooknum;

/* Hooks are ordered in ascending priority. */

intpriority;

};

```

`struct list_head`是一个普通的双向链表。`nf_hookfn`用来指向钩子函数的地址。`priority`表示该钩子函数的优先级,该值越小,优先级越高;在这个双向链表中,钩子函数是按照该值进行升序排序的。

注册钩子函数的函数为`nf_register_hooks`,它会将`n`个钩子函数分别注册到对应的钩子处,该函数里面做了一个for循环,调用真正的注册函数`nf_register_hook`。

> net/netfilter/core.c

```

int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n) {

...

for (i = 0; i < n; i++) {

err = nf_register_hook(&reg[i]);

if (err)

goto err;

}

...

}

```

### **各个模块的钩子函数**

根据上面的分析,注册钩子函数的函数为`nf_register_hooks()`,我们根据这个函数的关键字来搜索conntrack、nat等模块注册的钩子函数。

##### **Conntrack**

我们在[页面](https://elixir.bootlin.com/linux/v4.4.249/source)上搜索关键字`nf_register_hooks`,会有如下的返回,再根据`conntrack`关键字基本可以定位到conntrack模块注册钩子函数的位置在下面的文件的第472行

![](https://img.kancloud.cn/fa/83/fa838793adb491fedeaf37be0a012b90_1341x642.png)

我们点开这个文件链接,去到对应位置,发现如下代码

```

static int __init nf_conntrack_l3proto_ipv4_init(void)

{

...

ret = nf_register_hooks(ipv4_conntrack_ops,

ARRAY_SIZE(ipv4_conntrack_ops));

...

}

```

可以看出,IPv4协议注册的钩子函数在`ipv4_conntrack_ops`这个数组中。我们继续点击这个数组的链接,打开这个数组,如下:

```

/* Connection tracking may drop packets, but never alters them, so

make it the first hook. */

static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {

{

.hook= ipv4_conntrack_in,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_PRE_ROUTING,

.priority= NF_IP_PRI_CONNTRACK,

},

{

.hook= ipv4_conntrack_local,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_LOCAL_OUT,

.priority= NF_IP_PRI_CONNTRACK,

},

{

.hook= ipv4_helper,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_POST_ROUTING,

.priority= NF_IP_PRI_CONNTRACK_HELPER,

},

{

.hook= ipv4_confirm,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_POST_ROUTING,

.priority= NF_IP_PRI_CONNTRACK_CONFIRM,

},

{

.hook= ipv4_helper,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_LOCAL_IN,

.priority= NF_IP_PRI_CONNTRACK_HELPER,

},

{

.hook= ipv4_confirm,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_LOCAL_IN,

.priority= NF_IP_PRI_CONNTRACK_CONFIRM,

},

};

```

到这里,我们可以看出,Conntrack模块在不同的钩子点注册的钩子函数分别有:

| 钩子点 | 钩子函数 |

| --- | --- |

| NF_INET_PRE_ROUTING | ipv4_conntrack_in() |

| NF_INET_LOCAL_OUT | ipv4_conntrack_local() |

| NF_INET_POST_ROUTING | ipv4_confirm()、ipv4_helper() |

| NF_INET_LOCAL_IN | ipv4_confrim()、ipv4_helper() |

##### **NAT**

根据上面的方法,我们也可以找到nat模块在每个钩子点处注册的钩子函数,如下:

> net/ipv4/netfilter/iptable_nat.c

```

static int __init iptable_nat_init(void)

{

...

err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));

...

}

```

> net/ipv4/netfilter/iptable_nat.c

```

static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {

/* Before packet filtering, change destination */

{

.hook= iptable_nat_ipv4_in,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_PRE_ROUTING,

.priority= NF_IP_PRI_NAT_DST,

},

/* After packet filtering, change source */

{

.hook= iptable_nat_ipv4_out,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_POST_ROUTING,

.priority= NF_IP_PRI_NAT_SRC,

},

/* Before packet filtering, change destination */

{

.hook= iptable_nat_ipv4_local_fn,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_LOCAL_OUT,

.priority= NF_IP_PRI_NAT_DST,

},

/* After packet filtering, change source */

{

.hook= iptable_nat_ipv4_fn,

.pf= NFPROTO_IPV4,

.hooknum= NF_INET_LOCAL_IN,

.priority= NF_IP_PRI_NAT_SRC,

},

};

```

| 钩子点 | 钩子函数 |

| --- | --- |

| NF_INET_PRE_ROUTING | iptable_nat_ipv4_in() |

| NF_INET_POST_ROUTING | iptable_nat_ipv4_out() |

| NF_INET_LOCAL_OUT | iptable_nat_ipv4_local_fn() |

| NF_INET_LOCAL_IN | iptable_nat_ipv4_fn() |

### **参考**

http://wiki.dreamrunner.org/public_html/Linux/Networks/netfilter.html

https://blog.csdn.net/wenqian1991/article/details/50365689

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值