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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
| /**
* Netfilter钩子点定义
*
* 这些钩子点定义了数据包在网络栈中的关键处理位置
*/
enum nf_inet_hooks {
NF_INET_PRE_ROUTING, /* 路由前处理 */
NF_INET_LOCAL_IN, /* 本地输入 */
NF_INET_FORWARD, /* 转发处理 */
NF_INET_LOCAL_OUT, /* 本地输出 */
NF_INET_POST_ROUTING, /* 路由后处理 */
NF_INET_NUMHOOKS, /* 钩子数量 */
NF_INET_INGRESS = NF_INET_NUMHOOKS, /* 入口钩子 */
};
/**
* nf_hook_ops - Netfilter钩子操作结构
*
* 定义在特定钩子点注册的处理函数
*/
struct nf_hook_ops {
/* 用户填充的字段 */
nf_hookfn *hook; /* 钩子处理函数 */
struct net_device *dev; /* 关联设备(可选) */
void *priv; /* 私有数据 */
u_int8_t pf; /* 协议族 */
unsigned int hooknum; /* 钩子编号 */
/* 钩子的优先级。 较低的数字 = 较早调用。 */
int priority; /* 优先级 */
/* 由netfilter核心填充 */
struct list_head list; /* 钩子链表 */
};
/**
* nf_hook_state - 钩子状态信息
*
* 传递给钩子函数的上下文信息
*/
struct nf_hook_state {
unsigned int hook; /* 当前钩子编号 */
u_int8_t pf; /* 协议族 */
struct net_device *in; /* 输入设备 */
struct net_device *out; /* 输出设备 */
struct sock *sk; /* 关联套接字 */
struct net *net; /* 网络命名空间 */
int (*okfn)(struct net *, struct sock *, struct sk_buff *); /* 继续处理函数 */
};
/**
* nf_register_net_hook - 注册网络钩子
* @net: 网络命名空间
* @reg: 钩子注册信息
*
* 在指定网络命名空间中注册netfilter钩子
* 返回值:成功返回0,失败返回负错误码
*/
int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
{
struct nf_hook_ops *elem;
struct nf_hook_entries *new_hooks;
struct nf_hook_entries __rcu **pp;
if (reg->pf == NFPROTO_NETDEV) {
if (reg->hooknum == NF_NETDEV_INGRESS)
return nf_register_netdev_hook(net, reg);
}
pp = nf_hook_entry_head(net, reg->pf, reg->hooknum, reg->dev);
if (!pp)
return -EINVAL;
mutex_lock(&nf_hook_mutex);
new_hooks = nf_hook_entries_grow(rcu_dereference_protected(*pp, lockdep_is_held(&nf_hook_mutex)), reg);
if (IS_ERR(new_hooks)) {
mutex_unlock(&nf_hook_mutex);
return PTR_ERR(new_hooks);
}
rcu_assign_pointer(*pp, new_hooks);
mutex_unlock(&nf_hook_mutex);
#ifdef CONFIG_NETFILTER_INGRESS
if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
net_inc_ingress_queue();
#endif
return 0;
}
/**
* NF_HOOK - Netfilter钩子调用宏
* @pf: 协议族
* @hook: 钩子编号
* @net: 网络命名空间
* @sk: 套接字
* @skb: 数据包
* @in: 输入设备
* @out: 输出设备
* @okfn: 继续处理函数
*
* 在指定钩子点执行注册的处理函数
*/
static inline int NF_HOOK(u_int8_t pf, unsigned int hook, struct net *net,
struct sock *sk, struct sk_buff *skb,
struct net_device *in, struct net_device *out,
int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{
int ret = nf_hook(pf, hook, net, sk, skb, in, out, okfn);
if (ret == 1)
ret = okfn(net, sk, skb);
return ret;
}
/**
* nf_hook - 执行netfilter钩子
* @pf: 协议族
* @hook: 钩子编号
* @net: 网络命名空间
* @sk: 套接字
* @skb: 数据包
* @indev: 输入设备
* @outdev: 输出设备
* @okfn: 继续处理函数
*
* 执行指定钩子点的所有注册处理函数
* 返回值:处理结果
*/
int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
struct sock *sk, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{
const struct nf_hook_entries *hook_head = NULL;
int ret = 1;
#ifdef HAVE_JUMP_LABEL
if (static_key_false(&nf_hooks_needed[pf][hook])) {
#endif
rcu_read_lock();
switch (pf) {
case NFPROTO_IPV4:
hook_head = rcu_dereference(net->nf.hooks_ipv4[hook]);
break;
case NFPROTO_IPV6:
hook_head = rcu_dereference(net->nf.hooks_ipv6[hook]);
break;
case NFPROTO_ARP:
if (WARN_ON_ONCE(hook >= ARRAY_SIZE(net->nf.hooks_arp)))
break;
hook_head = rcu_dereference(net->nf.hooks_arp[hook]);
break;
case NFPROTO_BRIDGE:
hook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
break;
default:
WARN_ON_ONCE(1);
break;
}
if (hook_head) {
struct nf_hook_state state;
nf_hook_state_init(&state, hook, pf, indev, outdev,
sk, net, okfn);
ret = nf_hook_slow(skb, &state, hook_head, 0);
}
rcu_read_unlock();
#ifdef HAVE_JUMP_LABEL
}
#endif
return ret;
}
|