Blame view
net/netfilter/nfnetlink_queue.c
24.2 KB
7af4cc3fa [NETFILTER]: Add ... |
1 2 |
/* * This is a module which is used for queueing packets and communicating with |
67137f3cc nfnetlink_queue: ... |
3 |
* userspace via nfnetlink. |
7af4cc3fa [NETFILTER]: Add ... |
4 5 |
* * (C) 2005 by Harald Welte <laforge@netfilter.org> |
4ad9d4fa9 [NETFILTER]: nfne... |
6 |
* (C) 2007 by Patrick McHardy <kaber@trash.net> |
7af4cc3fa [NETFILTER]: Add ... |
7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
* * Based on the old ipv4-only ip_queue.c: * (C) 2000-2002 James Morris <jmorris@intercode.com.au> * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include <linux/module.h> #include <linux/skbuff.h> #include <linux/init.h> #include <linux/spinlock.h> |
5a0e3ad6a include cleanup: ... |
21 |
#include <linux/slab.h> |
7af4cc3fa [NETFILTER]: Add ... |
22 23 24 |
#include <linux/notifier.h> #include <linux/netdevice.h> #include <linux/netfilter.h> |
838ab6364 [NETFILTER]: Add ... |
25 |
#include <linux/proc_fs.h> |
7af4cc3fa [NETFILTER]: Add ... |
26 27 28 29 30 31 |
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv6.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_queue.h> #include <linux/list.h> #include <net/sock.h> |
c01cd429f [NETFILTER]: nf_q... |
32 |
#include <net/netfilter/nf_queue.h> |
7af4cc3fa [NETFILTER]: Add ... |
33 |
|
60063497a atomic: use <linu... |
34 |
#include <linux/atomic.h> |
7af4cc3fa [NETFILTER]: Add ... |
35 |
|
fbcd923c3 [NETFILTER]: add ... |
36 37 38 |
#ifdef CONFIG_BRIDGE_NETFILTER #include "../bridge/br_private.h" #endif |
7af4cc3fa [NETFILTER]: Add ... |
39 |
#define NFQNL_QMAX_DEFAULT 1024 |
7af4cc3fa [NETFILTER]: Add ... |
40 41 |
struct nfqnl_instance { struct hlist_node hlist; /* global list of queues */ |
9872bec77 [NETFILTER]: nfne... |
42 |
struct rcu_head rcu; |
7af4cc3fa [NETFILTER]: Add ... |
43 44 45 46 |
int peer_pid; unsigned int queue_maxlen; unsigned int copy_range; |
7af4cc3fa [NETFILTER]: Add ... |
47 48 |
unsigned int queue_dropped; unsigned int queue_user_dropped; |
7af4cc3fa [NETFILTER]: Add ... |
49 50 51 |
u_int16_t queue_num; /* number of this queue */ u_int8_t copy_mode; |
c463ac972 netfilter: nfnetl... |
52 53 54 55 56 57 |
/* * Following fields are dirtied for each queued packet, * keep them in same cache line if possible. */ spinlock_t lock; unsigned int queue_total; |
5863702a3 netfilter: nfnetl... |
58 |
unsigned int id_sequence; /* 'sequence' of pkt ids */ |
7af4cc3fa [NETFILTER]: Add ... |
59 60 |
struct list_head queue_list; /* packets in queue */ }; |
02f014d88 [NETFILTER]: nf_q... |
61 |
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); |
7af4cc3fa [NETFILTER]: Add ... |
62 |
|
9872bec77 [NETFILTER]: nfne... |
63 |
static DEFINE_SPINLOCK(instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
64 |
|
7af4cc3fa [NETFILTER]: Add ... |
65 |
#define INSTANCE_BUCKETS 16 |
9d6023ab8 [NETFILTER]: nfne... |
66 |
static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly; |
7af4cc3fa [NETFILTER]: Add ... |
67 68 69 70 71 72 73 |
static inline u_int8_t instance_hashfn(u_int16_t queue_num) { return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS; } static struct nfqnl_instance * |
9872bec77 [NETFILTER]: nfne... |
74 |
instance_lookup(u_int16_t queue_num) |
7af4cc3fa [NETFILTER]: Add ... |
75 76 77 78 79 80 |
{ struct hlist_head *head; struct hlist_node *pos; struct nfqnl_instance *inst; head = &instance_table[instance_hashfn(queue_num)]; |
9872bec77 [NETFILTER]: nfne... |
81 |
hlist_for_each_entry_rcu(inst, pos, head, hlist) { |
7af4cc3fa [NETFILTER]: Add ... |
82 83 84 85 86 87 88 |
if (inst->queue_num == queue_num) return inst; } return NULL; } static struct nfqnl_instance * |
7af4cc3fa [NETFILTER]: Add ... |
89 90 |
instance_create(u_int16_t queue_num, int pid) { |
baab2ce7d [NETFILTER]: nfne... |
91 |
struct nfqnl_instance *inst; |
9872bec77 [NETFILTER]: nfne... |
92 |
unsigned int h; |
baab2ce7d [NETFILTER]: nfne... |
93 |
int err; |
7af4cc3fa [NETFILTER]: Add ... |
94 |
|
9872bec77 [NETFILTER]: nfne... |
95 |
spin_lock(&instances_lock); |
baab2ce7d [NETFILTER]: nfne... |
96 97 |
if (instance_lookup(queue_num)) { err = -EEXIST; |
7af4cc3fa [NETFILTER]: Add ... |
98 |
goto out_unlock; |
baab2ce7d [NETFILTER]: nfne... |
99 |
} |
7af4cc3fa [NETFILTER]: Add ... |
100 |
|
10dfdc69e [NETFILTER] nfnet... |
101 |
inst = kzalloc(sizeof(*inst), GFP_ATOMIC); |
baab2ce7d [NETFILTER]: nfne... |
102 103 |
if (!inst) { err = -ENOMEM; |
7af4cc3fa [NETFILTER]: Add ... |
104 |
goto out_unlock; |
baab2ce7d [NETFILTER]: nfne... |
105 |
} |
7af4cc3fa [NETFILTER]: Add ... |
106 |
|
7af4cc3fa [NETFILTER]: Add ... |
107 108 109 110 111 |
inst->queue_num = queue_num; inst->peer_pid = pid; inst->queue_maxlen = NFQNL_QMAX_DEFAULT; inst->copy_range = 0xfffff; inst->copy_mode = NFQNL_COPY_NONE; |
181a46a56 [NETFILTER]: Use ... |
112 |
spin_lock_init(&inst->lock); |
7af4cc3fa [NETFILTER]: Add ... |
113 |
INIT_LIST_HEAD(&inst->queue_list); |
baab2ce7d [NETFILTER]: nfne... |
114 115 |
if (!try_module_get(THIS_MODULE)) { err = -EAGAIN; |
7af4cc3fa [NETFILTER]: Add ... |
116 |
goto out_free; |
baab2ce7d [NETFILTER]: nfne... |
117 |
} |
7af4cc3fa [NETFILTER]: Add ... |
118 |
|
9872bec77 [NETFILTER]: nfne... |
119 120 |
h = instance_hashfn(queue_num); hlist_add_head_rcu(&inst->hlist, &instance_table[h]); |
7af4cc3fa [NETFILTER]: Add ... |
121 |
|
9872bec77 [NETFILTER]: nfne... |
122 |
spin_unlock(&instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
123 |
|
7af4cc3fa [NETFILTER]: Add ... |
124 125 126 127 128 |
return inst; out_free: kfree(inst); out_unlock: |
9872bec77 [NETFILTER]: nfne... |
129 |
spin_unlock(&instances_lock); |
baab2ce7d [NETFILTER]: nfne... |
130 |
return ERR_PTR(err); |
7af4cc3fa [NETFILTER]: Add ... |
131 |
} |
b43d8d859 [NETFILTER]: nfne... |
132 133 |
static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data); |
7af4cc3fa [NETFILTER]: Add ... |
134 135 |
static void |
9872bec77 [NETFILTER]: nfne... |
136 |
instance_destroy_rcu(struct rcu_head *head) |
7af4cc3fa [NETFILTER]: Add ... |
137 |
{ |
9872bec77 [NETFILTER]: nfne... |
138 139 |
struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance, rcu); |
7af4cc3fa [NETFILTER]: Add ... |
140 |
|
b43d8d859 [NETFILTER]: nfne... |
141 |
nfqnl_flush(inst, NULL, 0); |
9872bec77 [NETFILTER]: nfne... |
142 |
kfree(inst); |
7af4cc3fa [NETFILTER]: Add ... |
143 144 |
module_put(THIS_MODULE); } |
9872bec77 [NETFILTER]: nfne... |
145 |
static void |
7af4cc3fa [NETFILTER]: Add ... |
146 147 |
__instance_destroy(struct nfqnl_instance *inst) { |
9872bec77 [NETFILTER]: nfne... |
148 149 |
hlist_del_rcu(&inst->hlist); call_rcu(&inst->rcu, instance_destroy_rcu); |
7af4cc3fa [NETFILTER]: Add ... |
150 |
} |
9872bec77 [NETFILTER]: nfne... |
151 |
static void |
7af4cc3fa [NETFILTER]: Add ... |
152 153 |
instance_destroy(struct nfqnl_instance *inst) { |
9872bec77 [NETFILTER]: nfne... |
154 155 156 |
spin_lock(&instances_lock); __instance_destroy(inst); spin_unlock(&instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
157 |
} |
7af4cc3fa [NETFILTER]: Add ... |
158 |
static inline void |
02f014d88 [NETFILTER]: nf_q... |
159 |
__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) |
7af4cc3fa [NETFILTER]: Add ... |
160 |
{ |
0ac41e814 [NETFILTER]: {nf_... |
161 |
list_add_tail(&entry->list, &queue->queue_list); |
7af4cc3fa [NETFILTER]: Add ... |
162 163 |
queue->queue_total++; } |
97d32cf94 netfilter: nfnetl... |
164 165 166 167 168 169 |
static void __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) { list_del(&entry->list); queue->queue_total--; } |
02f014d88 [NETFILTER]: nf_q... |
170 |
static struct nf_queue_entry * |
b43d8d859 [NETFILTER]: nfne... |
171 |
find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) |
7af4cc3fa [NETFILTER]: Add ... |
172 |
{ |
02f014d88 [NETFILTER]: nf_q... |
173 |
struct nf_queue_entry *entry = NULL, *i; |
601e68e10 [NETFILTER]: Fix ... |
174 |
|
7af4cc3fa [NETFILTER]: Add ... |
175 |
spin_lock_bh(&queue->lock); |
b43d8d859 [NETFILTER]: nfne... |
176 177 178 179 180 181 182 |
list_for_each_entry(i, &queue->queue_list, list) { if (i->id == id) { entry = i; break; } } |
97d32cf94 netfilter: nfnetl... |
183 184 |
if (entry) __dequeue_entry(queue, entry); |
b43d8d859 [NETFILTER]: nfne... |
185 |
|
7af4cc3fa [NETFILTER]: Add ... |
186 187 188 189 190 191 |
spin_unlock_bh(&queue->lock); return entry; } static void |
b43d8d859 [NETFILTER]: nfne... |
192 |
nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) |
7af4cc3fa [NETFILTER]: Add ... |
193 |
{ |
02f014d88 [NETFILTER]: nf_q... |
194 |
struct nf_queue_entry *entry, *next; |
b43d8d859 [NETFILTER]: nfne... |
195 |
|
7af4cc3fa [NETFILTER]: Add ... |
196 |
spin_lock_bh(&queue->lock); |
b43d8d859 [NETFILTER]: nfne... |
197 198 199 200 |
list_for_each_entry_safe(entry, next, &queue->queue_list, list) { if (!cmpfn || cmpfn(entry, data)) { list_del(&entry->list); queue->queue_total--; |
4b3d15ef4 [NETFILTER]: {nfn... |
201 |
nf_reinject(entry, NF_DROP); |
b43d8d859 [NETFILTER]: nfne... |
202 203 |
} } |
7af4cc3fa [NETFILTER]: Add ... |
204 205 206 207 208 |
spin_unlock_bh(&queue->lock); } static struct sk_buff * nfqnl_build_packet_message(struct nfqnl_instance *queue, |
5863702a3 netfilter: nfnetl... |
209 210 |
struct nf_queue_entry *entry, __be32 **packet_id_ptr) |
7af4cc3fa [NETFILTER]: Add ... |
211 |
{ |
27a884dc3 [SK_BUFF]: Conver... |
212 |
sk_buff_data_t old_tail; |
7af4cc3fa [NETFILTER]: Add ... |
213 214 215 |
size_t size; size_t data_len = 0; struct sk_buff *skb; |
5863702a3 netfilter: nfnetl... |
216 217 |
struct nlattr *nla; struct nfqnl_msg_packet_hdr *pmsg; |
7af4cc3fa [NETFILTER]: Add ... |
218 219 |
struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; |
3e4ead4fe [NETFILTER]: Decr... |
220 221 222 |
struct sk_buff *entskb = entry->skb; struct net_device *indev; struct net_device *outdev; |
7af4cc3fa [NETFILTER]: Add ... |
223 |
|
cabaa9bfb [NETFILTER]: nfne... |
224 |
size = NLMSG_SPACE(sizeof(struct nfgenmsg)) |
df6fb868d [NETFILTER]: nfne... |
225 226 227 |
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr)) + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + nla_total_size(sizeof(u_int32_t)) /* ifindex */ |
fbcd923c3 [NETFILTER]: add ... |
228 |
#ifdef CONFIG_BRIDGE_NETFILTER |
df6fb868d [NETFILTER]: nfne... |
229 230 |
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */ + nla_total_size(sizeof(u_int32_t)) /* ifindex */ |
fbcd923c3 [NETFILTER]: add ... |
231 |
#endif |
df6fb868d [NETFILTER]: nfne... |
232 233 234 |
+ nla_total_size(sizeof(u_int32_t)) /* mark */ + nla_total_size(sizeof(struct nfqnl_msg_packet_hw)) + nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)); |
7af4cc3fa [NETFILTER]: Add ... |
235 |
|
02f014d88 [NETFILTER]: nf_q... |
236 |
outdev = entry->outdev; |
3e4ead4fe [NETFILTER]: Decr... |
237 |
|
c463ac972 netfilter: nfnetl... |
238 |
switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) { |
7af4cc3fa [NETFILTER]: Add ... |
239 240 |
case NFQNL_COPY_META: case NFQNL_COPY_NONE: |
7af4cc3fa [NETFILTER]: Add ... |
241 |
break; |
601e68e10 [NETFILTER]: Fix ... |
242 |
|
7af4cc3fa [NETFILTER]: Add ... |
243 |
case NFQNL_COPY_PACKET: |
e9f13cab4 netfilter: only d... |
244 |
if (entskb->ip_summed == CHECKSUM_PARTIAL && |
c463ac972 netfilter: nfnetl... |
245 |
skb_checksum_help(entskb)) |
e7dfb09a3 [NETFILTER]: Fix ... |
246 |
return NULL; |
c463ac972 netfilter: nfnetl... |
247 248 249 |
data_len = ACCESS_ONCE(queue->copy_range); if (data_len == 0 || data_len > entskb->len) |
3e4ead4fe [NETFILTER]: Decr... |
250 |
data_len = entskb->len; |
601e68e10 [NETFILTER]: Fix ... |
251 |
|
df6fb868d [NETFILTER]: nfne... |
252 |
size += nla_total_size(data_len); |
7af4cc3fa [NETFILTER]: Add ... |
253 |
break; |
7af4cc3fa [NETFILTER]: Add ... |
254 |
} |
7af4cc3fa [NETFILTER]: Add ... |
255 256 257 258 |
skb = alloc_skb(size, GFP_ATOMIC); if (!skb) goto nlmsg_failure; |
601e68e10 [NETFILTER]: Fix ... |
259 |
|
27a884dc3 [SK_BUFF]: Conver... |
260 |
old_tail = skb->tail; |
601e68e10 [NETFILTER]: Fix ... |
261 |
nlh = NLMSG_PUT(skb, 0, 0, |
7af4cc3fa [NETFILTER]: Add ... |
262 263 264 |
NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); |
02f014d88 [NETFILTER]: nf_q... |
265 |
nfmsg->nfgen_family = entry->pf; |
7af4cc3fa [NETFILTER]: Add ... |
266 267 |
nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(queue->queue_num); |
5863702a3 netfilter: nfnetl... |
268 269 270 271 272 |
nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg)); pmsg = nla_data(nla); pmsg->hw_protocol = entskb->protocol; pmsg->hook = entry->hook; *packet_id_ptr = &pmsg->packet_id; |
7af4cc3fa [NETFILTER]: Add ... |
273 |
|
02f014d88 [NETFILTER]: nf_q... |
274 |
indev = entry->indev; |
3e4ead4fe [NETFILTER]: Decr... |
275 |
if (indev) { |
fbcd923c3 [NETFILTER]: add ... |
276 |
#ifndef CONFIG_BRIDGE_NETFILTER |
ea3a66ff5 [NETFILTER]: nfne... |
277 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
278 |
#else |
02f014d88 [NETFILTER]: nf_q... |
279 |
if (entry->pf == PF_BRIDGE) { |
fbcd923c3 [NETFILTER]: add ... |
280 |
/* Case 1: indev is physical input device, we need to |
601e68e10 [NETFILTER]: Fix ... |
281 |
* look for bridge group (when called from |
fbcd923c3 [NETFILTER]: add ... |
282 |
* netfilter_bridge) */ |
ea3a66ff5 [NETFILTER]: nfne... |
283 284 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV, htonl(indev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
285 |
/* this is the bridge group "brX" */ |
f350a0a87 bridge: use rx_ha... |
286 |
/* rcu_read_lock()ed by __nf_queue */ |
ea3a66ff5 [NETFILTER]: nfne... |
287 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV, |
f350a0a87 bridge: use rx_ha... |
288 |
htonl(br_port_get_rcu(indev)->br->dev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
289 290 291 |
} else { /* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ |
ea3a66ff5 [NETFILTER]: nfne... |
292 293 294 295 296 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)); if (entskb->nf_bridge && entskb->nf_bridge->physindev) NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV, htonl(entskb->nf_bridge->physindev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
297 298 |
} #endif |
7af4cc3fa [NETFILTER]: Add ... |
299 |
} |
3e4ead4fe [NETFILTER]: Decr... |
300 |
if (outdev) { |
fbcd923c3 [NETFILTER]: add ... |
301 |
#ifndef CONFIG_BRIDGE_NETFILTER |
ea3a66ff5 [NETFILTER]: nfne... |
302 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
303 |
#else |
02f014d88 [NETFILTER]: nf_q... |
304 |
if (entry->pf == PF_BRIDGE) { |
fbcd923c3 [NETFILTER]: add ... |
305 |
/* Case 1: outdev is physical output device, we need to |
601e68e10 [NETFILTER]: Fix ... |
306 |
* look for bridge group (when called from |
fbcd923c3 [NETFILTER]: add ... |
307 |
* netfilter_bridge) */ |
ea3a66ff5 [NETFILTER]: nfne... |
308 309 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV, htonl(outdev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
310 |
/* this is the bridge group "brX" */ |
f350a0a87 bridge: use rx_ha... |
311 |
/* rcu_read_lock()ed by __nf_queue */ |
ea3a66ff5 [NETFILTER]: nfne... |
312 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV, |
f350a0a87 bridge: use rx_ha... |
313 |
htonl(br_port_get_rcu(outdev)->br->dev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
314 315 316 |
} else { /* Case 2: outdev is bridge group, we need to look for * physical output device (when called from ipv4) */ |
ea3a66ff5 [NETFILTER]: nfne... |
317 318 319 320 321 |
NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)); if (entskb->nf_bridge && entskb->nf_bridge->physoutdev) NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV, htonl(entskb->nf_bridge->physoutdev->ifindex)); |
fbcd923c3 [NETFILTER]: add ... |
322 323 |
} #endif |
7af4cc3fa [NETFILTER]: Add ... |
324 |
} |
ea3a66ff5 [NETFILTER]: nfne... |
325 326 |
if (entskb->mark) NLA_PUT_BE32(skb, NFQA_MARK, htonl(entskb->mark)); |
7af4cc3fa [NETFILTER]: Add ... |
327 |
|
2c38de4c1 netfilter: fix lo... |
328 329 |
if (indev && entskb->dev && entskb->mac_header != entskb->network_header) { |
7af4cc3fa [NETFILTER]: Add ... |
330 |
struct nfqnl_msg_packet_hw phw; |
b95cce357 [NET]: Wrap hard_... |
331 332 333 |
int len = dev_parse_header(entskb, phw.hw_addr); if (len) { phw.hw_addrlen = htons(len); |
df6fb868d [NETFILTER]: nfne... |
334 |
NLA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); |
b95cce357 [NET]: Wrap hard_... |
335 |
} |
7af4cc3fa [NETFILTER]: Add ... |
336 |
} |
b7aa0bf70 [NET]: convert ne... |
337 |
if (entskb->tstamp.tv64) { |
7af4cc3fa [NETFILTER]: Add ... |
338 |
struct nfqnl_msg_packet_timestamp ts; |
b7aa0bf70 [NET]: convert ne... |
339 340 341 |
struct timeval tv = ktime_to_timeval(entskb->tstamp); ts.sec = cpu_to_be64(tv.tv_sec); ts.usec = cpu_to_be64(tv.tv_usec); |
7af4cc3fa [NETFILTER]: Add ... |
342 |
|
df6fb868d [NETFILTER]: nfne... |
343 |
NLA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); |
7af4cc3fa [NETFILTER]: Add ... |
344 345 346 |
} if (data_len) { |
df6fb868d [NETFILTER]: nfne... |
347 |
struct nlattr *nla; |
ca7c48ca9 [NETFILTER]: Supr... |
348 |
int sz = nla_attr_size(data_len); |
7af4cc3fa [NETFILTER]: Add ... |
349 |
|
df6fb868d [NETFILTER]: nfne... |
350 |
if (skb_tailroom(skb) < nla_total_size(data_len)) { |
7af4cc3fa [NETFILTER]: Add ... |
351 352 353 354 |
printk(KERN_WARNING "nf_queue: no tailroom! "); goto nlmsg_failure; } |
df6fb868d [NETFILTER]: nfne... |
355 356 |
nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len)); nla->nla_type = NFQA_PAYLOAD; |
ca7c48ca9 [NETFILTER]: Supr... |
357 |
nla->nla_len = sz; |
7af4cc3fa [NETFILTER]: Add ... |
358 |
|
df6fb868d [NETFILTER]: nfne... |
359 |
if (skb_copy_bits(entskb, 0, nla_data(nla), data_len)) |
7af4cc3fa [NETFILTER]: Add ... |
360 361 |
BUG(); } |
601e68e10 [NETFILTER]: Fix ... |
362 |
|
7af4cc3fa [NETFILTER]: Add ... |
363 364 365 366 |
nlh->nlmsg_len = skb->tail - old_tail; return skb; nlmsg_failure: |
df6fb868d [NETFILTER]: nfne... |
367 |
nla_put_failure: |
7af4cc3fa [NETFILTER]: Add ... |
368 369 |
if (skb) kfree_skb(skb); |
7af4cc3fa [NETFILTER]: Add ... |
370 371 372 373 374 375 376 |
if (net_ratelimit()) printk(KERN_ERR "nf_queue: error creating packet message "); return NULL; } static int |
02f014d88 [NETFILTER]: nf_q... |
377 |
nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) |
7af4cc3fa [NETFILTER]: Add ... |
378 |
{ |
7af4cc3fa [NETFILTER]: Add ... |
379 380 |
struct sk_buff *nskb; struct nfqnl_instance *queue; |
f15850861 netfilter: nfnetl... |
381 |
int err = -ENOBUFS; |
5863702a3 netfilter: nfnetl... |
382 |
__be32 *packet_id_ptr; |
7af4cc3fa [NETFILTER]: Add ... |
383 |
|
9872bec77 [NETFILTER]: nfne... |
384 385 |
/* rcu_read_lock()ed by nf_hook_slow() */ queue = instance_lookup(queuenum); |
f15850861 netfilter: nfnetl... |
386 387 |
if (!queue) { err = -ESRCH; |
0ef0f4658 [NETFILTER]: nfne... |
388 |
goto err_out; |
f15850861 netfilter: nfnetl... |
389 |
} |
7af4cc3fa [NETFILTER]: Add ... |
390 |
|
f15850861 netfilter: nfnetl... |
391 392 |
if (queue->copy_mode == NFQNL_COPY_NONE) { err = -EINVAL; |
0ef0f4658 [NETFILTER]: nfne... |
393 |
goto err_out; |
f15850861 netfilter: nfnetl... |
394 |
} |
7af4cc3fa [NETFILTER]: Add ... |
395 |
|
5863702a3 netfilter: nfnetl... |
396 |
nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr); |
f15850861 netfilter: nfnetl... |
397 398 |
if (nskb == NULL) { err = -ENOMEM; |
0ef0f4658 [NETFILTER]: nfne... |
399 |
goto err_out; |
f15850861 netfilter: nfnetl... |
400 |
} |
7af4cc3fa [NETFILTER]: Add ... |
401 |
spin_lock_bh(&queue->lock); |
601e68e10 [NETFILTER]: Fix ... |
402 |
|
f15850861 netfilter: nfnetl... |
403 404 |
if (!queue->peer_pid) { err = -EINVAL; |
601e68e10 [NETFILTER]: Fix ... |
405 |
goto err_out_free_nskb; |
f15850861 netfilter: nfnetl... |
406 |
} |
7af4cc3fa [NETFILTER]: Add ... |
407 |
if (queue->queue_total >= queue->queue_maxlen) { |
601e68e10 [NETFILTER]: Fix ... |
408 |
queue->queue_dropped++; |
7af4cc3fa [NETFILTER]: Add ... |
409 |
if (net_ratelimit()) |
601e68e10 [NETFILTER]: Fix ... |
410 |
printk(KERN_WARNING "nf_queue: full at %d entries, " |
a5d896adf netfilter: nfnetl... |
411 412 413 |
"dropping packets(s). ", queue->queue_total); |
7af4cc3fa [NETFILTER]: Add ... |
414 415 |
goto err_out_free_nskb; } |
5863702a3 netfilter: nfnetl... |
416 417 |
entry->id = ++queue->id_sequence; *packet_id_ptr = htonl(entry->id); |
7af4cc3fa [NETFILTER]: Add ... |
418 419 |
/* nfnetlink_unicast will either free the nskb or add it to a socket */ |
cd8c20b65 netfilter: nfnetl... |
420 |
err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); |
0ef0f4658 [NETFILTER]: nfne... |
421 |
if (err < 0) { |
601e68e10 [NETFILTER]: Fix ... |
422 |
queue->queue_user_dropped++; |
7af4cc3fa [NETFILTER]: Add ... |
423 424 425 426 427 428 |
goto err_out_unlock; } __enqueue_entry(queue, entry); spin_unlock_bh(&queue->lock); |
0ef0f4658 [NETFILTER]: nfne... |
429 |
return 0; |
7af4cc3fa [NETFILTER]: Add ... |
430 431 |
err_out_free_nskb: |
601e68e10 [NETFILTER]: Fix ... |
432 |
kfree_skb(nskb); |
7af4cc3fa [NETFILTER]: Add ... |
433 434 |
err_out_unlock: spin_unlock_bh(&queue->lock); |
0ef0f4658 [NETFILTER]: nfne... |
435 |
err_out: |
f15850861 netfilter: nfnetl... |
436 |
return err; |
7af4cc3fa [NETFILTER]: Add ... |
437 438 439 |
} static int |
02f014d88 [NETFILTER]: nf_q... |
440 |
nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) |
7af4cc3fa [NETFILTER]: Add ... |
441 |
{ |
e2b58a67b [NETFILTER]: {ip,... |
442 |
struct sk_buff *nskb; |
7af4cc3fa [NETFILTER]: Add ... |
443 444 445 |
int diff; diff = data_len - e->skb->len; |
d8a585d78 [NETFILTER]: Use ... |
446 447 448 449 |
if (diff < 0) { if (pskb_trim(e->skb, data_len)) return -ENOMEM; } else if (diff > 0) { |
7af4cc3fa [NETFILTER]: Add ... |
450 451 452 |
if (data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { |
9a732ed6d netfilter: {nfnet... |
453 454 |
nskb = skb_copy_expand(e->skb, skb_headroom(e->skb), diff, GFP_ATOMIC); |
e2b58a67b [NETFILTER]: {ip,... |
455 |
if (!nskb) { |
1158ba27b [NETFILTER]: nfne... |
456 |
printk(KERN_WARNING "nf_queue: OOM " |
7af4cc3fa [NETFILTER]: Add ... |
457 458 |
"in mangle, dropping packet "); |
e2b58a67b [NETFILTER]: {ip,... |
459 |
return -ENOMEM; |
7af4cc3fa [NETFILTER]: Add ... |
460 |
} |
e2b58a67b [NETFILTER]: {ip,... |
461 462 |
kfree_skb(e->skb); e->skb = nskb; |
7af4cc3fa [NETFILTER]: Add ... |
463 464 465 |
} skb_put(e->skb, diff); } |
37d418792 [NETFILTER]: Do n... |
466 |
if (!skb_make_writable(e->skb, data_len)) |
7af4cc3fa [NETFILTER]: Add ... |
467 |
return -ENOMEM; |
27d7ff46a [SK_BUFF]: Introd... |
468 |
skb_copy_to_linear_data(e->skb, data, data_len); |
e7dfb09a3 [NETFILTER]: Fix ... |
469 |
e->skb->ip_summed = CHECKSUM_NONE; |
7af4cc3fa [NETFILTER]: Add ... |
470 471 |
return 0; } |
7af4cc3fa [NETFILTER]: Add ... |
472 473 474 475 |
static int nfqnl_set_mode(struct nfqnl_instance *queue, unsigned char mode, unsigned int range) { |
c5de0dfde [NETFILTER]: nfne... |
476 |
int status = 0; |
7af4cc3fa [NETFILTER]: Add ... |
477 478 |
spin_lock_bh(&queue->lock); |
c5de0dfde [NETFILTER]: nfne... |
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
switch (mode) { case NFQNL_COPY_NONE: case NFQNL_COPY_META: queue->copy_mode = mode; queue->copy_range = 0; break; case NFQNL_COPY_PACKET: queue->copy_mode = mode; /* we're using struct nlattr which has 16bit nla_len */ if (range > 0xffff) queue->copy_range = 0xffff; else queue->copy_range = range; break; default: status = -EINVAL; } |
7af4cc3fa [NETFILTER]: Add ... |
499 500 501 502 503 504 |
spin_unlock_bh(&queue->lock); return status; } static int |
02f014d88 [NETFILTER]: nf_q... |
505 |
dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
506 |
{ |
02f014d88 [NETFILTER]: nf_q... |
507 508 |
if (entry->indev) if (entry->indev->ifindex == ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
509 |
return 1; |
02f014d88 [NETFILTER]: nf_q... |
510 511 |
if (entry->outdev) if (entry->outdev->ifindex == ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
512 |
return 1; |
ef47c6a7b [NETFILTER]: ip_q... |
513 514 515 516 517 518 519 520 521 522 |
#ifdef CONFIG_BRIDGE_NETFILTER if (entry->skb->nf_bridge) { if (entry->skb->nf_bridge->physindev && entry->skb->nf_bridge->physindev->ifindex == ifindex) return 1; if (entry->skb->nf_bridge->physoutdev && entry->skb->nf_bridge->physoutdev->ifindex == ifindex) return 1; } #endif |
7af4cc3fa [NETFILTER]: Add ... |
523 524 525 526 527 528 529 530 531 |
return 0; } /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void nfqnl_dev_drop(int ifindex) { int i; |
601e68e10 [NETFILTER]: Fix ... |
532 |
|
9872bec77 [NETFILTER]: nfne... |
533 |
rcu_read_lock(); |
7af4cc3fa [NETFILTER]: Add ... |
534 |
|
9872bec77 [NETFILTER]: nfne... |
535 |
for (i = 0; i < INSTANCE_BUCKETS; i++) { |
7af4cc3fa [NETFILTER]: Add ... |
536 537 538 |
struct hlist_node *tmp; struct nfqnl_instance *inst; struct hlist_head *head = &instance_table[i]; |
9872bec77 [NETFILTER]: nfne... |
539 |
hlist_for_each_entry_rcu(inst, tmp, head, hlist) |
b43d8d859 [NETFILTER]: nfne... |
540 |
nfqnl_flush(inst, dev_cmp, ifindex); |
7af4cc3fa [NETFILTER]: Add ... |
541 |
} |
9872bec77 [NETFILTER]: nfne... |
542 |
rcu_read_unlock(); |
7af4cc3fa [NETFILTER]: Add ... |
543 544 545 546 547 548 549 550 551 |
} #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static int nfqnl_rcv_dev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; |
721499e89 netns: Use net_eq... |
552 |
if (!net_eq(dev_net(dev), &init_net)) |
e9dc86534 [NET]: Make devic... |
553 |
return NOTIFY_DONE; |
7af4cc3fa [NETFILTER]: Add ... |
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
/* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) nfqnl_dev_drop(dev->ifindex); return NOTIFY_DONE; } static struct notifier_block nfqnl_dev_notifier = { .notifier_call = nfqnl_rcv_dev_event, }; static int nfqnl_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr) { struct netlink_notify *n = ptr; |
dee5817e8 netfilter: remove... |
569 |
if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { |
7af4cc3fa [NETFILTER]: Add ... |
570 571 572 |
int i; /* destroy all instances for this pid */ |
9872bec77 [NETFILTER]: nfne... |
573 574 |
spin_lock(&instances_lock); for (i = 0; i < INSTANCE_BUCKETS; i++) { |
7af4cc3fa [NETFILTER]: Add ... |
575 576 577 578 579 |
struct hlist_node *tmp, *t2; struct nfqnl_instance *inst; struct hlist_head *head = &instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { |
b4b510290 [NET]: Support mu... |
580 581 |
if ((n->net == &init_net) && (n->pid == inst->peer_pid)) |
7af4cc3fa [NETFILTER]: Add ... |
582 583 584 |
__instance_destroy(inst); } } |
9872bec77 [NETFILTER]: nfne... |
585 |
spin_unlock(&instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
586 587 588 589 590 591 592 |
} return NOTIFY_DONE; } static struct notifier_block nfqnl_rtnl_notifier = { .notifier_call = nfqnl_rcv_nl_event, }; |
5bf758539 [NETFILTER]: nfne... |
593 594 595 596 |
static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = { [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, [NFQA_MARK] = { .type = NLA_U32 }, [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, |
838ab6364 [NETFILTER]: Add ... |
597 |
}; |
97d32cf94 netfilter: nfnetl... |
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, [NFQA_MARK] = { .type = NLA_U32 }, }; static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid) { struct nfqnl_instance *queue; queue = instance_lookup(queue_num); if (!queue) return ERR_PTR(-ENODEV); if (queue->peer_pid != nlpid) return ERR_PTR(-EPERM); return queue; } static struct nfqnl_msg_verdict_hdr* verdicthdr_get(const struct nlattr * const nfqa[]) { struct nfqnl_msg_verdict_hdr *vhdr; unsigned int verdict; if (!nfqa[NFQA_VERDICT_HDR]) return NULL; vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); |
c6675233f netfilter: nf_que... |
627 628 |
verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK; if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN) |
97d32cf94 netfilter: nfnetl... |
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
return NULL; return vhdr; } static int nfq_id_after(unsigned int id, unsigned int max) { return (int)(id - max) > 0; } static int nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nfqa[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); struct nf_queue_entry *entry, *tmp; unsigned int verdict, maxid; struct nfqnl_msg_verdict_hdr *vhdr; struct nfqnl_instance *queue; LIST_HEAD(batch_list); u16 queue_num = ntohs(nfmsg->res_id); queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); if (IS_ERR(queue)) return PTR_ERR(queue); vhdr = verdicthdr_get(nfqa); if (!vhdr) return -EINVAL; verdict = ntohl(vhdr->verdict); maxid = ntohl(vhdr->id); spin_lock_bh(&queue->lock); list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) { if (nfq_id_after(entry->id, maxid)) break; __dequeue_entry(queue, entry); list_add_tail(&entry->list, &batch_list); } spin_unlock_bh(&queue->lock); if (list_empty(&batch_list)) return -ENOENT; list_for_each_entry_safe(entry, tmp, &batch_list, list) { if (nfqa[NFQA_MARK]) entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); nf_reinject(entry, verdict); } return 0; } |
7af4cc3fa [NETFILTER]: Add ... |
683 684 |
static int nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, |
399383246 netfilter: nfnetl... |
685 686 |
const struct nlmsghdr *nlh, const struct nlattr * const nfqa[]) |
7af4cc3fa [NETFILTER]: Add ... |
687 688 689 690 691 692 693 |
{ struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t queue_num = ntohs(nfmsg->res_id); struct nfqnl_msg_verdict_hdr *vhdr; struct nfqnl_instance *queue; unsigned int verdict; |
02f014d88 [NETFILTER]: nf_q... |
694 |
struct nf_queue_entry *entry; |
7af4cc3fa [NETFILTER]: Add ... |
695 |
|
9872bec77 [NETFILTER]: nfne... |
696 |
queue = instance_lookup(queue_num); |
84a797dd0 netfilter: nfnetl... |
697 |
if (!queue) |
7af4cc3fa [NETFILTER]: Add ... |
698 |
|
97d32cf94 netfilter: nfnetl... |
699 700 701 |
queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); if (IS_ERR(queue)) return PTR_ERR(queue); |
7af4cc3fa [NETFILTER]: Add ... |
702 |
|
97d32cf94 netfilter: nfnetl... |
703 704 |
vhdr = verdicthdr_get(nfqa); if (!vhdr) |
84a797dd0 netfilter: nfnetl... |
705 |
return -EINVAL; |
7af4cc3fa [NETFILTER]: Add ... |
706 |
|
7af4cc3fa [NETFILTER]: Add ... |
707 |
verdict = ntohl(vhdr->verdict); |
b43d8d859 [NETFILTER]: nfne... |
708 |
entry = find_dequeue_entry(queue, ntohl(vhdr->id)); |
84a797dd0 netfilter: nfnetl... |
709 710 |
if (entry == NULL) return -ENOENT; |
7af4cc3fa [NETFILTER]: Add ... |
711 |
|
df6fb868d [NETFILTER]: nfne... |
712 713 714 |
if (nfqa[NFQA_PAYLOAD]) { if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), nla_len(nfqa[NFQA_PAYLOAD]), entry) < 0) |
7af4cc3fa [NETFILTER]: Add ... |
715 716 |
verdict = NF_DROP; } |
df6fb868d [NETFILTER]: nfne... |
717 |
if (nfqa[NFQA_MARK]) |
ea3a66ff5 [NETFILTER]: nfne... |
718 |
entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); |
601e68e10 [NETFILTER]: Fix ... |
719 |
|
4b3d15ef4 [NETFILTER]: {nfn... |
720 |
nf_reinject(entry, verdict); |
7af4cc3fa [NETFILTER]: Add ... |
721 722 723 724 725 |
return 0; } static int nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, |
399383246 netfilter: nfnetl... |
726 727 |
const struct nlmsghdr *nlh, const struct nlattr * const nfqa[]) |
7af4cc3fa [NETFILTER]: Add ... |
728 729 730 |
{ return -ENOTSUPP; } |
5bf758539 [NETFILTER]: nfne... |
731 732 733 |
static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = { [NFQA_CFG_CMD] = { .len = sizeof(struct nfqnl_msg_config_cmd) }, [NFQA_CFG_PARAMS] = { .len = sizeof(struct nfqnl_msg_config_params) }, |
838ab6364 [NETFILTER]: Add ... |
734 |
}; |
e3ac52981 [NETFILTER]: nf_q... |
735 |
static const struct nf_queue_handler nfqh = { |
bbd86b9fc [NETFILTER]: add ... |
736 737 738 |
.name = "nf_queue", .outfn = &nfqnl_enqueue_packet, }; |
7af4cc3fa [NETFILTER]: Add ... |
739 740 |
static int nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, |
399383246 netfilter: nfnetl... |
741 742 |
const struct nlmsghdr *nlh, const struct nlattr * const nfqa[]) |
7af4cc3fa [NETFILTER]: Add ... |
743 744 745 746 |
{ struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t queue_num = ntohs(nfmsg->res_id); struct nfqnl_instance *queue; |
9872bec77 [NETFILTER]: nfne... |
747 |
struct nfqnl_msg_config_cmd *cmd = NULL; |
838ab6364 [NETFILTER]: Add ... |
748 |
int ret = 0; |
7af4cc3fa [NETFILTER]: Add ... |
749 |
|
9872bec77 [NETFILTER]: nfne... |
750 751 752 753 754 755 |
if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); /* Commands without queue context - might sleep */ switch (cmd->command) { case NFQNL_CFG_CMD_PF_BIND: |
914afea84 [NETFILTER]: nfne... |
756 757 |
return nf_register_queue_handler(ntohs(cmd->pf), &nfqh); |
9872bec77 [NETFILTER]: nfne... |
758 |
case NFQNL_CFG_CMD_PF_UNBIND: |
914afea84 [NETFILTER]: nfne... |
759 760 |
return nf_unregister_queue_handler(ntohs(cmd->pf), &nfqh); |
9872bec77 [NETFILTER]: nfne... |
761 |
} |
9872bec77 [NETFILTER]: nfne... |
762 763 764 765 |
} rcu_read_lock(); queue = instance_lookup(queue_num); |
a3c8e7fd4 [NETFILTER]: nfne... |
766 767 |
if (queue && queue->peer_pid != NETLINK_CB(skb).pid) { ret = -EPERM; |
9872bec77 [NETFILTER]: nfne... |
768 |
goto err_out_unlock; |
a3c8e7fd4 [NETFILTER]: nfne... |
769 |
} |
9872bec77 [NETFILTER]: nfne... |
770 |
if (cmd != NULL) { |
7af4cc3fa [NETFILTER]: Add ... |
771 772 |
switch (cmd->command) { case NFQNL_CFG_CMD_BIND: |
9872bec77 [NETFILTER]: nfne... |
773 774 775 776 |
if (queue) { ret = -EBUSY; goto err_out_unlock; } |
7af4cc3fa [NETFILTER]: Add ... |
777 |
queue = instance_create(queue_num, NETLINK_CB(skb).pid); |
baab2ce7d [NETFILTER]: nfne... |
778 779 |
if (IS_ERR(queue)) { ret = PTR_ERR(queue); |
9872bec77 [NETFILTER]: nfne... |
780 781 |
goto err_out_unlock; } |
7af4cc3fa [NETFILTER]: Add ... |
782 783 |
break; case NFQNL_CFG_CMD_UNBIND: |
9872bec77 [NETFILTER]: nfne... |
784 785 786 787 |
if (!queue) { ret = -ENODEV; goto err_out_unlock; } |
7af4cc3fa [NETFILTER]: Add ... |
788 789 790 |
instance_destroy(queue); break; case NFQNL_CFG_CMD_PF_BIND: |
7af4cc3fa [NETFILTER]: Add ... |
791 |
case NFQNL_CFG_CMD_PF_UNBIND: |
7af4cc3fa [NETFILTER]: Add ... |
792 793 |
break; default: |
cd21f0ac4 [NETFILTER]: nfne... |
794 |
ret = -ENOTSUPP; |
838ab6364 [NETFILTER]: Add ... |
795 |
break; |
7af4cc3fa [NETFILTER]: Add ... |
796 |
} |
7af4cc3fa [NETFILTER]: Add ... |
797 |
} |
df6fb868d [NETFILTER]: nfne... |
798 |
if (nfqa[NFQA_CFG_PARAMS]) { |
7af4cc3fa [NETFILTER]: Add ... |
799 |
struct nfqnl_msg_config_params *params; |
7af4cc3fa [NETFILTER]: Add ... |
800 |
|
406dbfc9a [NETFILTER]: nfne... |
801 |
if (!queue) { |
a3c8e7fd4 [NETFILTER]: nfne... |
802 |
ret = -ENODEV; |
9872bec77 [NETFILTER]: nfne... |
803 |
goto err_out_unlock; |
406dbfc9a [NETFILTER]: nfne... |
804 |
} |
df6fb868d [NETFILTER]: nfne... |
805 |
params = nla_data(nfqa[NFQA_CFG_PARAMS]); |
7af4cc3fa [NETFILTER]: Add ... |
806 807 808 |
nfqnl_set_mode(queue, params->copy_mode, ntohl(params->copy_range)); } |
df6fb868d [NETFILTER]: nfne... |
809 |
if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) { |
829e17a1a [NETFILTER]: nfne... |
810 |
__be32 *queue_maxlen; |
a3c8e7fd4 [NETFILTER]: nfne... |
811 812 813 |
if (!queue) { ret = -ENODEV; |
9872bec77 [NETFILTER]: nfne... |
814 |
goto err_out_unlock; |
a3c8e7fd4 [NETFILTER]: nfne... |
815 |
} |
df6fb868d [NETFILTER]: nfne... |
816 |
queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]); |
829e17a1a [NETFILTER]: nfne... |
817 818 819 820 |
spin_lock_bh(&queue->lock); queue->queue_maxlen = ntohl(*queue_maxlen); spin_unlock_bh(&queue->lock); } |
9872bec77 [NETFILTER]: nfne... |
821 822 |
err_out_unlock: rcu_read_unlock(); |
838ab6364 [NETFILTER]: Add ... |
823 |
return ret; |
7af4cc3fa [NETFILTER]: Add ... |
824 |
} |
7c8d4cb41 [NETFILTER]: nfne... |
825 |
static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { |
84a797dd0 netfilter: nfnetl... |
826 |
[NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp, |
37d2e7a20 [NETFILTER] nfnet... |
827 |
.attr_count = NFQA_MAX, }, |
84a797dd0 netfilter: nfnetl... |
828 |
[NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict, |
5bf758539 [NETFILTER]: nfne... |
829 830 |
.attr_count = NFQA_MAX, .policy = nfqa_verdict_policy }, |
7af4cc3fa [NETFILTER]: Add ... |
831 |
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, |
5bf758539 [NETFILTER]: nfne... |
832 833 |
.attr_count = NFQA_CFG_MAX, .policy = nfqa_cfg_policy }, |
97d32cf94 netfilter: nfnetl... |
834 835 836 |
[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch, .attr_count = NFQA_MAX, .policy = nfqa_verdict_batch_policy }, |
7af4cc3fa [NETFILTER]: Add ... |
837 |
}; |
7c8d4cb41 [NETFILTER]: nfne... |
838 |
static const struct nfnetlink_subsystem nfqnl_subsys = { |
7af4cc3fa [NETFILTER]: Add ... |
839 840 841 |
.name = "nf_queue", .subsys_id = NFNL_SUBSYS_QUEUE, .cb_count = NFQNL_MSG_MAX, |
7af4cc3fa [NETFILTER]: Add ... |
842 843 |
.cb = nfqnl_cb, }; |
838ab6364 [NETFILTER]: Add ... |
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 |
#ifdef CONFIG_PROC_FS struct iter_state { unsigned int bucket; }; static struct hlist_node *get_first(struct seq_file *seq) { struct iter_state *st = seq->private; if (!st) return NULL; for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { if (!hlist_empty(&instance_table[st->bucket])) return instance_table[st->bucket].first; } return NULL; } static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) { struct iter_state *st = seq->private; h = h->next; while (!h) { if (++st->bucket >= INSTANCE_BUCKETS) return NULL; h = instance_table[st->bucket].first; } return h; } static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) { struct hlist_node *head; head = get_first(seq); if (head) while (pos && (head = get_next(seq, head))) pos--; return pos ? NULL : head; } static void *seq_start(struct seq_file *seq, loff_t *pos) |
ca7c48ca9 [NETFILTER]: Supr... |
889 |
__acquires(instances_lock) |
838ab6364 [NETFILTER]: Add ... |
890 |
{ |
9872bec77 [NETFILTER]: nfne... |
891 |
spin_lock(&instances_lock); |
838ab6364 [NETFILTER]: Add ... |
892 893 894 895 896 897 898 899 900 901 |
return get_idx(seq, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; return get_next(s, v); } static void seq_stop(struct seq_file *s, void *v) |
ca7c48ca9 [NETFILTER]: Supr... |
902 |
__releases(instances_lock) |
838ab6364 [NETFILTER]: Add ... |
903 |
{ |
9872bec77 [NETFILTER]: nfne... |
904 |
spin_unlock(&instances_lock); |
838ab6364 [NETFILTER]: Add ... |
905 906 907 908 909 910 911 912 913 914 915 916 |
} static int seq_show(struct seq_file *s, void *v) { const struct nfqnl_instance *inst = v; return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d ", inst->queue_num, inst->peer_pid, inst->queue_total, inst->copy_mode, inst->copy_range, inst->queue_dropped, inst->queue_user_dropped, |
5863702a3 netfilter: nfnetl... |
917 |
inst->id_sequence, 1); |
838ab6364 [NETFILTER]: Add ... |
918 |
} |
56b3d975b [NET]: Make all i... |
919 |
static const struct seq_operations nfqnl_seq_ops = { |
838ab6364 [NETFILTER]: Add ... |
920 921 922 923 924 925 926 927 |
.start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show, }; static int nfqnl_open(struct inode *inode, struct file *file) { |
e2da59133 [NETFILTER]: Make... |
928 929 |
return seq_open_private(file, &nfqnl_seq_ops, sizeof(struct iter_state)); |
838ab6364 [NETFILTER]: Add ... |
930 |
} |
da7071d7e [PATCH] mark stru... |
931 |
static const struct file_operations nfqnl_file_ops = { |
838ab6364 [NETFILTER]: Add ... |
932 933 934 935 936 937 938 939 |
.owner = THIS_MODULE, .open = nfqnl_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, }; #endif /* PROC_FS */ |
32292a7ff [NETFILTER]: Fix ... |
940 |
static int __init nfnetlink_queue_init(void) |
7af4cc3fa [NETFILTER]: Add ... |
941 |
{ |
838ab6364 [NETFILTER]: Add ... |
942 |
int i, status = -ENOMEM; |
601e68e10 [NETFILTER]: Fix ... |
943 |
|
838ab6364 [NETFILTER]: Add ... |
944 945 |
for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); |
7af4cc3fa [NETFILTER]: Add ... |
946 947 948 949 950 951 952 |
netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { printk(KERN_ERR "nf_queue: failed to create netlink socket "); goto cleanup_netlink_notifier; } |
838ab6364 [NETFILTER]: Add ... |
953 |
#ifdef CONFIG_PROC_FS |
8eeee8b15 [NETFILTER]: Repl... |
954 955 |
if (!proc_create("nfnetlink_queue", 0440, proc_net_netfilter, &nfqnl_file_ops)) |
838ab6364 [NETFILTER]: Add ... |
956 |
goto cleanup_subsys; |
838ab6364 [NETFILTER]: Add ... |
957 |
#endif |
7af4cc3fa [NETFILTER]: Add ... |
958 959 |
register_netdevice_notifier(&nfqnl_dev_notifier); return status; |
838ab6364 [NETFILTER]: Add ... |
960 961 |
#ifdef CONFIG_PROC_FS cleanup_subsys: |
7af4cc3fa [NETFILTER]: Add ... |
962 |
nfnetlink_subsys_unregister(&nfqnl_subsys); |
32292a7ff [NETFILTER]: Fix ... |
963 |
#endif |
7af4cc3fa [NETFILTER]: Add ... |
964 965 966 967 |
cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); return status; } |
65b4b4e81 [NETFILTER]: Rena... |
968 |
static void __exit nfnetlink_queue_fini(void) |
7af4cc3fa [NETFILTER]: Add ... |
969 |
{ |
32292a7ff [NETFILTER]: Fix ... |
970 971 972 973 974 975 976 |
nf_unregister_queue_handlers(&nfqh); unregister_netdevice_notifier(&nfqnl_dev_notifier); #ifdef CONFIG_PROC_FS remove_proc_entry("nfnetlink_queue", proc_net_netfilter); #endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); |
67137f3cc nfnetlink_queue: ... |
977 978 |
rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
7af4cc3fa [NETFILTER]: Add ... |
979 980 981 982 983 984 |
} MODULE_DESCRIPTION("netfilter packet queue handler"); MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); MODULE_LICENSE("GPL"); MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE); |
65b4b4e81 [NETFILTER]: Rena... |
985 986 |
module_init(nfnetlink_queue_init); module_exit(nfnetlink_queue_fini); |