http://www.bairimeng.net/2012/11/28/netfilter_iptables_hook_1/
一、说明
Netfilter通过挂载在Hook链上的函数,来对经过链的数据包进行逐一处理,这一篇笔记记录了开发一个最简单的Hook函数的过程,这是一个内核模块,直接加载在内核,只要载入即可生效。
我的Linux内核版本为2.6.27.41。
二、模块描述
这个模块的作用很简单,每收到4个ICMP报文,就丢弃一个报文,也就是逢5就丢,这个笔记不记录任何对于Linux网络编程有直接提高的信息,那些需要系统的不断的学习。
OK,我们开始动手。
三、代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/atomic.h>
#include <linux/ip.h>
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/moduleparam.h>
#include <linux/netfilter_ipv4/ip_tables.h>
MODULE_LICENSE(
"GPL"
);
MODULE_AUTHOR(
"Sekai"
);
MODULE_DESCRIPTION(
"My hook"
);
static
atomic_t pktcnt =
{
.counter = 0,
};
// 我们自己定义的hook回调函数,每隔4个丢弃1个icmp报文
static
unsigned
int
myhook_func(unsigned
int
hooknum,
struct
sk_buff* skb,
const
struct
net_device* in,
const
struct
net_device* out,
int
(*okfn)(
struct
sk_buff*))
{
const
struct
iphdr* iph = ip_hdr(skb);
if
(iph->protocol == 1)
{
atomic_inc(&pktcnt);
if
(atomic_read(&pktcnt) % 5 == 0)
{
printk(KERN_INFO
"%d: drop an ICMP to %u.%u.%u.%u!\n"
,
atomic_read(&pktcnt), NIPQUAD(iph->daddr));
return
NF_DROP;
}
}
return
NF_ACCEPT;
}
// <linux/netfilter.h>
static
struct
nf_hook_ops nfho =
{
.hook = myhook_func,
// 回调函数
.owner = THIS_MODULE,
.pf = PF_INET,
// <linux/netfilter_ipv4.h> NF_IP_LOCAL_OUT 不知道为什么识别不了
.hooknum = 3,
// 挂载在本地出口处
.priority = NF_IP_PRI_FIRST,
// 优先级最高
};
static
int
__init myhook_init(
void
)
{
return
nf_register_hook(&nfho);
}
static
void
__exit myhook_fini(
void
)
{
nf_unregister_hook(&nfho);
}
module_init(myhook_init);
module_exit(myhook_fini);
|
四、代码详解
我们使用nf_hook_ops来实例化一个hook函数,这个结构体有一系列成员,具体定义在linux/netfilter.h中,可以注意到.hook成员就是我们自己编写的回调函数,.hooknum是挂载点,也就是Netfilter定义的5个挂载点,具体定义在linux/netfilter_ipv4.h中,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/* IP Hooks */
/* After promisc drops, checksum checks. */
#define NF_IP_PRE_ROUTING 0
/* If the packet is destined for this box. */
#define NF_IP_LOCAL_IN 1
/* If the packet is destined for another interface. */
#define NF_IP_FORWARD 2
/* Packets coming from a local process. */
#define NF_IP_LOCAL_OUT 3
/* Packets about to hit the wire. */
#define NF_IP_POST_ROUTING 4
#define NF_IP_NUMHOOKS 5
#endif /* ! __KERNEL__ */
|
我们将这个函数挂载在NF_IP_LOCAL_OUT上,可以直接使用这个宏。
我们使用 nf_register_hook()来挂载我们这个Hook函数,然后定义了一个atomic_t来作为计数器,使用atomic的函数来对它进行原子操作,实现进程间同步。
值得注意的是在myhook_func()中使用的atomic_inc()在2.6.27.41使用atomic_t作为传入参数,而某个版本之前,传入参数还是简单的int。
五、挂载
我们稍微修改下之前一篇笔记写的那个Makefile,然后编译成为.ko内核库之后,使用insmod命令安装。
接着使用Ping www.baidu.com来测试。
我们发现每隔4个包就会被抛弃1个包,目标达成。