[NETFILTER]: ctnetlink: fix NAT configuration
[deliverable/linux.git] / net / ipv4 / netfilter / ip_conntrack_netlink.c
CommitLineData
080774a2
HW
1/* Connection tracking via netlink socket. Allows for user space
2 * protocol helpers and general trouble making from userspace.
3 *
4 * (C) 2001 by Jay Schulist <jschlst@samba.org>
5 * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
6 * (C) 2003 by Patrick Mchardy <kaber@trash.net>
1cde6436 7 * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net>
080774a2
HW
8 *
9 * I've reworked this stuff to use attributes instead of conntrack
10 * structures. 5.44 am. I need more tea. --pablo 05/07/11.
11 *
12 * Initial connection tracking via netlink development funded and
13 * generally made possible by Network Robots, Inc. (www.networkrobots.com)
14 *
15 * Further development of this code funded by Astaro AG (http://www.astaro.com)
16 *
17 * This software may be used and distributed according to the terms
18 * of the GNU General Public License, incorporated herein by reference.
19 */
20
21#include <linux/init.h>
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/timer.h>
26#include <linux/skbuff.h>
27#include <linux/errno.h>
28#include <linux/netlink.h>
29#include <linux/spinlock.h>
de919820 30#include <linux/interrupt.h>
080774a2 31#include <linux/notifier.h>
080774a2
HW
32
33#include <linux/netfilter.h>
080774a2
HW
34#include <linux/netfilter_ipv4/ip_conntrack.h>
35#include <linux/netfilter_ipv4/ip_conntrack_core.h>
36#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
37#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
38#include <linux/netfilter_ipv4/ip_nat_protocol.h>
39
40#include <linux/netfilter/nfnetlink.h>
41#include <linux/netfilter/nfnetlink_conntrack.h>
42
43MODULE_LICENSE("GPL");
44
45static char __initdata version[] = "0.90";
46
47#if 0
48#define DEBUGP printk
49#else
50#define DEBUGP(format, args...)
51#endif
52
53
54static inline int
55ctnetlink_dump_tuples_proto(struct sk_buff *skb,
1cde6436
PNA
56 const struct ip_conntrack_tuple *tuple,
57 struct ip_conntrack_protocol *proto)
080774a2 58{
eaae4fa4 59 int ret = 0;
1cde6436 60 struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
080774a2
HW
61
62 NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
63
00cb277a 64 if (likely(proto->tuple_to_nfattr))
eaae4fa4 65 ret = proto->tuple_to_nfattr(skb, tuple);
00cb277a 66
1cde6436 67 NFA_NEST_END(skb, nest_parms);
080774a2 68
eaae4fa4 69 return ret;
080774a2
HW
70
71nfattr_failure:
72 return -1;
73}
74
75static inline int
1cde6436
PNA
76ctnetlink_dump_tuples_ip(struct sk_buff *skb,
77 const struct ip_conntrack_tuple *tuple)
080774a2 78{
1cde6436 79 struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
080774a2 80
080774a2
HW
81 NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
82 NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
080774a2 83
080774a2
HW
84 NFA_NEST_END(skb, nest_parms);
85
1cde6436 86 return 0;
080774a2
HW
87
88nfattr_failure:
89 return -1;
90}
91
1cde6436
PNA
92static inline int
93ctnetlink_dump_tuples(struct sk_buff *skb,
94 const struct ip_conntrack_tuple *tuple)
95{
96 int ret;
97 struct ip_conntrack_protocol *proto;
98
99 ret = ctnetlink_dump_tuples_ip(skb, tuple);
100 if (unlikely(ret < 0))
101 return ret;
102
103 proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
104 ret = ctnetlink_dump_tuples_proto(skb, tuple, proto);
105 ip_conntrack_proto_put(proto);
106
107 return ret;
108}
109
080774a2
HW
110static inline int
111ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
112{
113 u_int32_t status = htonl((u_int32_t) ct->status);
114 NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
115 return 0;
116
117nfattr_failure:
118 return -1;
119}
120
121static inline int
122ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
123{
124 long timeout_l = ct->timeout.expires - jiffies;
125 u_int32_t timeout;
126
127 if (timeout_l < 0)
128 timeout = 0;
129 else
130 timeout = htonl(timeout_l / HZ);
131
132 NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
133 return 0;
134
135nfattr_failure:
136 return -1;
137}
138
139static inline int
140ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
141{
142 struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
143
144 struct nfattr *nest_proto;
145 int ret;
00cb277a
PNA
146
147 if (!proto->to_nfattr) {
148 ip_conntrack_proto_put(proto);
080774a2 149 return 0;
00cb277a 150 }
080774a2
HW
151
152 nest_proto = NFA_NEST(skb, CTA_PROTOINFO);
153
154 ret = proto->to_nfattr(skb, nest_proto, ct);
155
156 ip_conntrack_proto_put(proto);
157
158 NFA_NEST_END(skb, nest_proto);
159
160 return ret;
161
162nfattr_failure:
163 return -1;
164}
165
166static inline int
167ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
168{
169 struct nfattr *nest_helper;
170
171 if (!ct->helper)
172 return 0;
173
174 nest_helper = NFA_NEST(skb, CTA_HELP);
a9b305c4 175 NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name);
080774a2
HW
176
177 if (ct->helper->to_nfattr)
178 ct->helper->to_nfattr(skb, ct);
179
180 NFA_NEST_END(skb, nest_helper);
181
182 return 0;
183
184nfattr_failure:
185 return -1;
186}
187
188#ifdef CONFIG_IP_NF_CT_ACCT
189static inline int
190ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct,
191 enum ip_conntrack_dir dir)
192{
193 enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
194 struct nfattr *nest_count = NFA_NEST(skb, type);
46998f59 195 u_int32_t tmp;
080774a2 196
a051a8f7
HW
197 tmp = htonl(ct->counters[dir].packets);
198 NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
080774a2 199
a051a8f7
HW
200 tmp = htonl(ct->counters[dir].bytes);
201 NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
080774a2
HW
202
203 NFA_NEST_END(skb, nest_count);
204
205 return 0;
206
207nfattr_failure:
208 return -1;
209}
210#else
211#define ctnetlink_dump_counters(a, b, c) (0)
212#endif
213
214#ifdef CONFIG_IP_NF_CONNTRACK_MARK
215static inline int
216ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
217{
218 u_int32_t mark = htonl(ct->mark);
219
220 NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
221 return 0;
222
223nfattr_failure:
224 return -1;
225}
226#else
227#define ctnetlink_dump_mark(a, b) (0)
228#endif
229
230static inline int
231ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
232{
233 u_int32_t id = htonl(ct->id);
234 NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
235 return 0;
236
237nfattr_failure:
238 return -1;
239}
240
241static inline int
242ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
243{
47116eb2 244 u_int32_t use = htonl(atomic_read(&ct->ct_general.use));
080774a2
HW
245
246 NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
247 return 0;
248
249nfattr_failure:
250 return -1;
251}
252
253#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)
254
255static int
256ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
257 int event, int nowait,
258 const struct ip_conntrack *ct)
259{
260 struct nlmsghdr *nlh;
261 struct nfgenmsg *nfmsg;
262 struct nfattr *nest_parms;
263 unsigned char *b;
264
265 b = skb->tail;
266
267 event |= NFNL_SUBSYS_CTNETLINK << 8;
268 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
269 nfmsg = NLMSG_DATA(nlh);
270
271 nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
272 nfmsg->nfgen_family = AF_INET;
273 nfmsg->version = NFNETLINK_V0;
274 nfmsg->res_id = 0;
275
276 nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
277 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
278 goto nfattr_failure;
279 NFA_NEST_END(skb, nest_parms);
280
281 nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
282 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
283 goto nfattr_failure;
284 NFA_NEST_END(skb, nest_parms);
285
286 if (ctnetlink_dump_status(skb, ct) < 0 ||
287 ctnetlink_dump_timeout(skb, ct) < 0 ||
288 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
289 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
290 ctnetlink_dump_protoinfo(skb, ct) < 0 ||
291 ctnetlink_dump_helpinfo(skb, ct) < 0 ||
292 ctnetlink_dump_mark(skb, ct) < 0 ||
293 ctnetlink_dump_id(skb, ct) < 0 ||
294 ctnetlink_dump_use(skb, ct) < 0)
295 goto nfattr_failure;
296
297 nlh->nlmsg_len = skb->tail - b;
298 return skb->len;
299
300nlmsg_failure:
301nfattr_failure:
302 skb_trim(skb, b - skb->data);
303 return -1;
304}
305
306#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
307static int ctnetlink_conntrack_event(struct notifier_block *this,
308 unsigned long events, void *ptr)
309{
310 struct nlmsghdr *nlh;
311 struct nfgenmsg *nfmsg;
312 struct nfattr *nest_parms;
313 struct ip_conntrack *ct = (struct ip_conntrack *)ptr;
314 struct sk_buff *skb;
315 unsigned int type;
316 unsigned char *b;
ac6d439d 317 unsigned int flags = 0, group;
080774a2
HW
318
319 /* ignore our fake conntrack entry */
320 if (ct == &ip_conntrack_untracked)
321 return NOTIFY_DONE;
322
323 if (events & IPCT_DESTROY) {
324 type = IPCTNL_MSG_CT_DELETE;
ac6d439d 325 group = NFNLGRP_CONNTRACK_DESTROY;
0368309c 326 } else if (events & (IPCT_NEW | IPCT_RELATED)) {
080774a2
HW
327 type = IPCTNL_MSG_CT_NEW;
328 flags = NLM_F_CREATE|NLM_F_EXCL;
329 /* dump everything */
330 events = ~0UL;
ac6d439d 331 group = NFNLGRP_CONNTRACK_NEW;
0368309c 332 } else if (events & (IPCT_STATUS |
080774a2
HW
333 IPCT_PROTOINFO |
334 IPCT_HELPER |
335 IPCT_HELPINFO |
336 IPCT_NATINFO)) {
337 type = IPCTNL_MSG_CT_NEW;
ac6d439d 338 group = NFNLGRP_CONNTRACK_UPDATE;
0368309c
PNA
339 } else
340 return NOTIFY_DONE;
a2427692
PM
341
342 if (!nfnetlink_has_listeners(group))
343 return NOTIFY_DONE;
344
080774a2
HW
345 skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
346 if (!skb)
347 return NOTIFY_DONE;
348
349 b = skb->tail;
350
351 type |= NFNL_SUBSYS_CTNETLINK << 8;
352 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
353 nfmsg = NLMSG_DATA(nlh);
354
355 nlh->nlmsg_flags = flags;
356 nfmsg->nfgen_family = AF_INET;
357 nfmsg->version = NFNETLINK_V0;
358 nfmsg->res_id = 0;
359
360 nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
361 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
362 goto nfattr_failure;
363 NFA_NEST_END(skb, nest_parms);
364
365 nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
366 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
367 goto nfattr_failure;
368 NFA_NEST_END(skb, nest_parms);
369
370 /* NAT stuff is now a status flag */
371 if ((events & IPCT_STATUS || events & IPCT_NATINFO)
372 && ctnetlink_dump_status(skb, ct) < 0)
373 goto nfattr_failure;
374 if (events & IPCT_REFRESH
375 && ctnetlink_dump_timeout(skb, ct) < 0)
376 goto nfattr_failure;
377 if (events & IPCT_PROTOINFO
378 && ctnetlink_dump_protoinfo(skb, ct) < 0)
379 goto nfattr_failure;
380 if (events & IPCT_HELPINFO
381 && ctnetlink_dump_helpinfo(skb, ct) < 0)
382 goto nfattr_failure;
383
384 if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
385 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
386 goto nfattr_failure;
387
388 nlh->nlmsg_len = skb->tail - b;
ac6d439d 389 nfnetlink_send(skb, 0, group, 0);
080774a2
HW
390 return NOTIFY_DONE;
391
392nlmsg_failure:
393nfattr_failure:
394 kfree_skb(skb);
395 return NOTIFY_DONE;
396}
397#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
398
399static int ctnetlink_done(struct netlink_callback *cb)
400{
401 DEBUGP("entered %s\n", __FUNCTION__);
402 return 0;
403}
404
405static int
406ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
407{
408 struct ip_conntrack *ct = NULL;
409 struct ip_conntrack_tuple_hash *h;
410 struct list_head *i;
411 u_int32_t *id = (u_int32_t *) &cb->args[1];
412
413 DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
414 cb->args[0], *id);
415
416 read_lock_bh(&ip_conntrack_lock);
417 for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
ff21d577 418 list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
080774a2
HW
419 h = (struct ip_conntrack_tuple_hash *) i;
420 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
421 continue;
422 ct = tuplehash_to_ctrack(h);
423 if (ct->id <= *id)
424 continue;
425 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
426 cb->nlh->nlmsg_seq,
427 IPCTNL_MSG_CT_NEW,
428 1, ct) < 0)
429 goto out;
430 *id = ct->id;
431 }
432 }
433out:
434 read_unlock_bh(&ip_conntrack_lock);
435
436 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
437
438 return skb->len;
439}
440
441#ifdef CONFIG_IP_NF_CT_ACCT
442static int
443ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
444{
445 struct ip_conntrack *ct = NULL;
446 struct ip_conntrack_tuple_hash *h;
447 struct list_head *i;
448 u_int32_t *id = (u_int32_t *) &cb->args[1];
449
450 DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__,
451 cb->args[0], *id);
452
453 write_lock_bh(&ip_conntrack_lock);
454 for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
ff21d577 455 list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
080774a2
HW
456 h = (struct ip_conntrack_tuple_hash *) i;
457 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
458 continue;
459 ct = tuplehash_to_ctrack(h);
460 if (ct->id <= *id)
461 continue;
462 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
463 cb->nlh->nlmsg_seq,
464 IPCTNL_MSG_CT_NEW,
465 1, ct) < 0)
466 goto out;
467 *id = ct->id;
468
469 memset(&ct->counters, 0, sizeof(ct->counters));
470 }
471 }
472out:
473 write_unlock_bh(&ip_conntrack_lock);
474
475 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
476
477 return skb->len;
478}
479#endif
480
dbd36ea4 481static const size_t cta_min_ip[CTA_IP_MAX] = {
080774a2
HW
482 [CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
483 [CTA_IP_V4_DST-1] = sizeof(u_int32_t),
484};
485
486static inline int
487ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
488{
489 struct nfattr *tb[CTA_IP_MAX];
490
491 DEBUGP("entered %s\n", __FUNCTION__);
492
a2506c04 493 nfattr_parse_nested(tb, CTA_IP_MAX, attr);
080774a2
HW
494
495 if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
496 return -EINVAL;
497
498 if (!tb[CTA_IP_V4_SRC-1])
499 return -EINVAL;
500 tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
501
502 if (!tb[CTA_IP_V4_DST-1])
503 return -EINVAL;
504 tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
505
506 DEBUGP("leaving\n");
507
508 return 0;
080774a2
HW
509}
510
dbd36ea4 511static const size_t cta_min_proto[CTA_PROTO_MAX] = {
0be7fa92 512 [CTA_PROTO_NUM-1] = sizeof(u_int8_t),
080774a2
HW
513 [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t),
514 [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t),
515 [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
516 [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t),
517 [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t),
518};
519
520static inline int
521ctnetlink_parse_tuple_proto(struct nfattr *attr,
522 struct ip_conntrack_tuple *tuple)
523{
524 struct nfattr *tb[CTA_PROTO_MAX];
525 struct ip_conntrack_protocol *proto;
526 int ret = 0;
527
528 DEBUGP("entered %s\n", __FUNCTION__);
529
a2506c04 530 nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
080774a2
HW
531
532 if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
533 return -EINVAL;
534
535 if (!tb[CTA_PROTO_NUM-1])
536 return -EINVAL;
0be7fa92 537 tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
080774a2
HW
538
539 proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
540
00cb277a 541 if (likely(proto->nfattr_to_tuple))
080774a2 542 ret = proto->nfattr_to_tuple(tb, tuple);
00cb277a
PNA
543
544 ip_conntrack_proto_put(proto);
080774a2
HW
545
546 return ret;
080774a2
HW
547}
548
549static inline int
550ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
551 enum ctattr_tuple type)
552{
553 struct nfattr *tb[CTA_TUPLE_MAX];
554 int err;
555
556 DEBUGP("entered %s\n", __FUNCTION__);
557
080774a2
HW
558 memset(tuple, 0, sizeof(*tuple));
559
a2506c04 560 nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
080774a2
HW
561
562 if (!tb[CTA_TUPLE_IP-1])
563 return -EINVAL;
564
565 err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple);
566 if (err < 0)
567 return err;
568
569 if (!tb[CTA_TUPLE_PROTO-1])
570 return -EINVAL;
571
572 err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple);
573 if (err < 0)
574 return err;
575
576 /* orig and expect tuples get DIR_ORIGINAL */
577 if (type == CTA_TUPLE_REPLY)
578 tuple->dst.dir = IP_CT_DIR_REPLY;
579 else
580 tuple->dst.dir = IP_CT_DIR_ORIGINAL;
581
582 DUMP_TUPLE(tuple);
583
584 DEBUGP("leaving\n");
585
586 return 0;
080774a2
HW
587}
588
589#ifdef CONFIG_IP_NF_NAT_NEEDED
dbd36ea4 590static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
080774a2
HW
591 [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t),
592 [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),
593};
594
595static int ctnetlink_parse_nat_proto(struct nfattr *attr,
596 const struct ip_conntrack *ct,
597 struct ip_nat_range *range)
598{
599 struct nfattr *tb[CTA_PROTONAT_MAX];
600 struct ip_nat_protocol *npt;
601
602 DEBUGP("entered %s\n", __FUNCTION__);
603
a2506c04 604 nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
080774a2
HW
605
606 if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
fe902a91 607 return -EINVAL;
080774a2
HW
608
609 npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
080774a2
HW
610
611 if (!npt->nfattr_to_range) {
612 ip_nat_proto_put(npt);
613 return 0;
614 }
615
616 /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
617 if (npt->nfattr_to_range(tb, range) > 0)
618 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
619
620 ip_nat_proto_put(npt);
621
622 DEBUGP("leaving\n");
623 return 0;
080774a2
HW
624}
625
56558208
PNA
626static const size_t cta_min_nat[CTA_NAT_MAX] = {
627 [CTA_NAT_MINIP-1] = sizeof(u_int32_t),
628 [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),
629};
630
080774a2 631static inline int
3726add7 632ctnetlink_parse_nat(struct nfattr *nat,
080774a2
HW
633 const struct ip_conntrack *ct, struct ip_nat_range *range)
634{
635 struct nfattr *tb[CTA_NAT_MAX];
636 int err;
637
638 DEBUGP("entered %s\n", __FUNCTION__);
639
080774a2
HW
640 memset(range, 0, sizeof(*range));
641
3726add7 642 nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
080774a2 643
56558208
PNA
644 if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
645 return -EINVAL;
646
080774a2
HW
647 if (tb[CTA_NAT_MINIP-1])
648 range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
649
650 if (!tb[CTA_NAT_MAXIP-1])
651 range->max_ip = range->min_ip;
652 else
653 range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
654
655 if (range->min_ip)
656 range->flags |= IP_NAT_RANGE_MAP_IPS;
657
658 if (!tb[CTA_NAT_PROTO-1])
659 return 0;
660
661 err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
662 if (err < 0)
663 return err;
664
665 DEBUGP("leaving\n");
666 return 0;
080774a2
HW
667}
668#endif
669
670static inline int
671ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
672{
673 struct nfattr *tb[CTA_HELP_MAX];
674
675 DEBUGP("entered %s\n", __FUNCTION__);
080774a2 676
a2506c04 677 nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
080774a2
HW
678
679 if (!tb[CTA_HELP_NAME-1])
680 return -EINVAL;
681
682 *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
683
684 return 0;
080774a2
HW
685}
686
56558208
PNA
687static const size_t cta_min[CTA_MAX] = {
688 [CTA_STATUS-1] = sizeof(u_int32_t),
689 [CTA_TIMEOUT-1] = sizeof(u_int32_t),
690 [CTA_MARK-1] = sizeof(u_int32_t),
691 [CTA_USE-1] = sizeof(u_int32_t),
692 [CTA_ID-1] = sizeof(u_int32_t)
693};
694
080774a2
HW
695static int
696ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
697 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
698{
699 struct ip_conntrack_tuple_hash *h;
700 struct ip_conntrack_tuple tuple;
701 struct ip_conntrack *ct;
702 int err = 0;
703
704 DEBUGP("entered %s\n", __FUNCTION__);
705
56558208
PNA
706 if (nfattr_bad_size(cda, CTA_MAX, cta_min))
707 return -EINVAL;
708
080774a2
HW
709 if (cda[CTA_TUPLE_ORIG-1])
710 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
711 else if (cda[CTA_TUPLE_REPLY-1])
712 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
713 else {
714 /* Flush the whole table */
715 ip_conntrack_flush();
716 return 0;
717 }
718
719 if (err < 0)
720 return err;
721
722 h = ip_conntrack_find_get(&tuple, NULL);
723 if (!h) {
724 DEBUGP("tuple not found in conntrack hash\n");
725 return -ENOENT;
726 }
727
728 ct = tuplehash_to_ctrack(h);
729
730 if (cda[CTA_ID-1]) {
731 u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
732 if (ct->id != id) {
733 ip_conntrack_put(ct);
734 return -ENOENT;
735 }
736 }
2fdf1faa 737 if (del_timer(&ct->timeout))
080774a2 738 ct->timeout.function((unsigned long)ct);
2fdf1faa 739
080774a2
HW
740 ip_conntrack_put(ct);
741 DEBUGP("leaving\n");
742
743 return 0;
744}
745
746static int
747ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
748 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
749{
750 struct ip_conntrack_tuple_hash *h;
751 struct ip_conntrack_tuple tuple;
752 struct ip_conntrack *ct;
753 struct sk_buff *skb2 = NULL;
754 int err = 0;
755
756 DEBUGP("entered %s\n", __FUNCTION__);
757
758 if (nlh->nlmsg_flags & NLM_F_DUMP) {
759 struct nfgenmsg *msg = NLMSG_DATA(nlh);
760 u32 rlen;
761
762 if (msg->nfgen_family != AF_INET)
763 return -EAFNOSUPPORT;
764
765 if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
766 IPCTNL_MSG_CT_GET_CTRZERO) {
767#ifdef CONFIG_IP_NF_CT_ACCT
768 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
769 ctnetlink_dump_table_w,
770 ctnetlink_done)) != 0)
771 return -EINVAL;
772#else
773 return -ENOTSUPP;
774#endif
775 } else {
776 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
777 ctnetlink_dump_table,
778 ctnetlink_done)) != 0)
779 return -EINVAL;
780 }
781
782 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
783 if (rlen > skb->len)
784 rlen = skb->len;
785 skb_pull(skb, rlen);
786 return 0;
787 }
788
56558208
PNA
789 if (nfattr_bad_size(cda, CTA_MAX, cta_min))
790 return -EINVAL;
791
080774a2
HW
792 if (cda[CTA_TUPLE_ORIG-1])
793 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
794 else if (cda[CTA_TUPLE_REPLY-1])
795 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
796 else
797 return -EINVAL;
798
799 if (err < 0)
800 return err;
801
802 h = ip_conntrack_find_get(&tuple, NULL);
803 if (!h) {
804 DEBUGP("tuple not found in conntrack hash");
805 return -ENOENT;
806 }
807 DEBUGP("tuple found\n");
808 ct = tuplehash_to_ctrack(h);
809
810 err = -ENOMEM;
81e5c27d 811 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
080774a2
HW
812 if (!skb2) {
813 ip_conntrack_put(ct);
814 return -ENOMEM;
815 }
816 NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
817
818 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
819 IPCTNL_MSG_CT_NEW, 1, ct);
820 ip_conntrack_put(ct);
821 if (err <= 0)
0f81eb4d 822 goto free;
080774a2
HW
823
824 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
825 if (err < 0)
826 goto out;
827
828 DEBUGP("leaving\n");
829 return 0;
830
0f81eb4d
HW
831free:
832 kfree_skb(skb2);
080774a2 833out:
fcda4612 834 return err;
080774a2
HW
835}
836
837static inline int
838ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
839{
d000eaf7
HW
840 unsigned long d;
841 unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
080774a2
HW
842 d = ct->status ^ status;
843
844 if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
845 /* unchangeable */
846 return -EINVAL;
847
848 if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
849 /* SEEN_REPLY bit can only be set */
850 return -EINVAL;
851
852
853 if (d & IPS_ASSURED && !(status & IPS_ASSURED))
854 /* ASSURED bit can only be set */
855 return -EINVAL;
856
3726add7 857 if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
080774a2
HW
858#ifndef CONFIG_IP_NF_NAT_NEEDED
859 return -EINVAL;
860#else
080774a2
HW
861 struct ip_nat_range range;
862
3726add7
PM
863 if (cda[CTA_NAT_DST-1]) {
864 if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
865 &range) < 0)
866 return -EINVAL;
867 if (ip_nat_initialized(ct,
868 HOOK2MANIP(NF_IP_PRE_ROUTING)))
869 return -EEXIST;
870 ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
871 }
872 if (cda[CTA_NAT_SRC-1]) {
873 if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
874 &range) < 0)
875 return -EINVAL;
876 if (ip_nat_initialized(ct,
877 HOOK2MANIP(NF_IP_POST_ROUTING)))
878 return -EEXIST;
879 ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
880 }
080774a2
HW
881#endif
882 }
883
884 /* Be careful here, modifying NAT bits can screw up things,
885 * so don't let users modify them directly if they don't pass
886 * ip_nat_range. */
887 ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
888 return 0;
889}
890
891
892static inline int
893ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
894{
895 struct ip_conntrack_helper *helper;
896 char *helpname;
897 int err;
898
899 DEBUGP("entered %s\n", __FUNCTION__);
900
901 /* don't change helper of sibling connections */
902 if (ct->master)
903 return -EINVAL;
904
905 err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);
906 if (err < 0)
907 return err;
908
909 helper = __ip_conntrack_helper_find_byname(helpname);
910 if (!helper) {
911 if (!strcmp(helpname, ""))
912 helper = NULL;
913 else
914 return -EINVAL;
915 }
916
917 if (ct->helper) {
918 if (!helper) {
919 /* we had a helper before ... */
920 ip_ct_remove_expectations(ct);
921 ct->helper = NULL;
922 } else {
923 /* need to zero data of old helper */
924 memset(&ct->help, 0, sizeof(ct->help));
925 }
926 }
927
928 ct->helper = helper;
929
930 return 0;
931}
932
933static inline int
934ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
935{
936 u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
937
938 if (!del_timer(&ct->timeout))
939 return -ETIME;
940
941 ct->timeout.expires = jiffies + timeout * HZ;
942 add_timer(&ct->timeout);
943
944 return 0;
945}
946
061cb4a0
PNA
947static inline int
948ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
949{
950 struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
951 struct ip_conntrack_protocol *proto;
952 u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
953 int err = 0;
954
a2506c04 955 nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
061cb4a0
PNA
956
957 proto = ip_conntrack_proto_find_get(npt);
061cb4a0
PNA
958
959 if (proto->from_nfattr)
960 err = proto->from_nfattr(tb, ct);
961 ip_conntrack_proto_put(proto);
962
963 return err;
061cb4a0
PNA
964}
965
080774a2
HW
966static int
967ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
968{
969 int err;
970
971 DEBUGP("entered %s\n", __FUNCTION__);
972
973 if (cda[CTA_HELP-1]) {
974 err = ctnetlink_change_helper(ct, cda);
975 if (err < 0)
976 return err;
977 }
978
979 if (cda[CTA_TIMEOUT-1]) {
980 err = ctnetlink_change_timeout(ct, cda);
981 if (err < 0)
982 return err;
983 }
984
985 if (cda[CTA_STATUS-1]) {
986 err = ctnetlink_change_status(ct, cda);
987 if (err < 0)
988 return err;
989 }
990
061cb4a0
PNA
991 if (cda[CTA_PROTOINFO-1]) {
992 err = ctnetlink_change_protoinfo(ct, cda);
993 if (err < 0)
994 return err;
995 }
996
02a78cdf
PNA
997#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
998 if (cda[CTA_MARK-1])
999 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1000#endif
1001
080774a2
HW
1002 DEBUGP("all done\n");
1003 return 0;
1004}
1005
1006static int
1007ctnetlink_create_conntrack(struct nfattr *cda[],
1008 struct ip_conntrack_tuple *otuple,
1009 struct ip_conntrack_tuple *rtuple)
1010{
1011 struct ip_conntrack *ct;
1012 int err = -EINVAL;
1013
1014 DEBUGP("entered %s\n", __FUNCTION__);
1015
1016 ct = ip_conntrack_alloc(otuple, rtuple);
1017 if (ct == NULL || IS_ERR(ct))
1018 return -ENOMEM;
1019
1020 if (!cda[CTA_TIMEOUT-1])
1021 goto err;
1022 ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
1023
1024 ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
1025 ct->status |= IPS_CONFIRMED;
1026
1027 err = ctnetlink_change_status(ct, cda);
1028 if (err < 0)
1029 goto err;
1030
061cb4a0
PNA
1031 if (cda[CTA_PROTOINFO-1]) {
1032 err = ctnetlink_change_protoinfo(ct, cda);
1033 if (err < 0)
1034 return err;
1035 }
1036
d4d6bb41
PNA
1037#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1038 if (cda[CTA_MARK-1])
1039 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1040#endif
1041
080774a2
HW
1042 ct->helper = ip_conntrack_helper_find_get(rtuple);
1043
1044 add_timer(&ct->timeout);
1045 ip_conntrack_hash_insert(ct);
1046
1047 if (ct->helper)
1048 ip_conntrack_helper_put(ct->helper);
1049
1050 DEBUGP("conntrack with id %u inserted\n", ct->id);
1051 return 0;
1052
1053err:
1054 ip_conntrack_free(ct);
1055 return err;
1056}
1057
1058static int
1059ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1060 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1061{
1062 struct ip_conntrack_tuple otuple, rtuple;
1063 struct ip_conntrack_tuple_hash *h = NULL;
1064 int err = 0;
1065
1066 DEBUGP("entered %s\n", __FUNCTION__);
1067
56558208
PNA
1068 if (nfattr_bad_size(cda, CTA_MAX, cta_min))
1069 return -EINVAL;
1070
080774a2
HW
1071 if (cda[CTA_TUPLE_ORIG-1]) {
1072 err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
1073 if (err < 0)
1074 return err;
1075 }
1076
1077 if (cda[CTA_TUPLE_REPLY-1]) {
1078 err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY);
1079 if (err < 0)
1080 return err;
1081 }
1082
1083 write_lock_bh(&ip_conntrack_lock);
1084 if (cda[CTA_TUPLE_ORIG-1])
1085 h = __ip_conntrack_find(&otuple, NULL);
1086 else if (cda[CTA_TUPLE_REPLY-1])
1087 h = __ip_conntrack_find(&rtuple, NULL);
1088
1089 if (h == NULL) {
1090 write_unlock_bh(&ip_conntrack_lock);
1091 DEBUGP("no such conntrack, create new\n");
1092 err = -ENOENT;
1093 if (nlh->nlmsg_flags & NLM_F_CREATE)
1094 err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
88aa0429
PN
1095 return err;
1096 }
1097 /* implicit 'else' */
1098
1099 /* we only allow nat config for new conntracks */
3726add7 1100 if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
88aa0429 1101 err = -EINVAL;
080774a2 1102 goto out_unlock;
080774a2
HW
1103 }
1104
1105 /* We manipulate the conntrack inside the global conntrack table lock,
1106 * so there's no need to increase the refcount */
1107 DEBUGP("conntrack found\n");
1108 err = -EEXIST;
1109 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1110 err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
1111
1112out_unlock:
1113 write_unlock_bh(&ip_conntrack_lock);
1114 return err;
1115}
1116
1117/***********************************************************************
1118 * EXPECT
1119 ***********************************************************************/
1120
1121static inline int
1122ctnetlink_exp_dump_tuple(struct sk_buff *skb,
1123 const struct ip_conntrack_tuple *tuple,
1124 enum ctattr_expect type)
1125{
1126 struct nfattr *nest_parms = NFA_NEST(skb, type);
1127
1128 if (ctnetlink_dump_tuples(skb, tuple) < 0)
1129 goto nfattr_failure;
1130
1131 NFA_NEST_END(skb, nest_parms);
1132
1133 return 0;
1134
1135nfattr_failure:
1136 return -1;
1137}
1138
1cde6436
PNA
1139static inline int
1140ctnetlink_exp_dump_mask(struct sk_buff *skb,
1141 const struct ip_conntrack_tuple *tuple,
1142 const struct ip_conntrack_tuple *mask)
1143{
1144 int ret;
1145 struct ip_conntrack_protocol *proto;
1146 struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK);
1147
1148 ret = ctnetlink_dump_tuples_ip(skb, mask);
1149 if (unlikely(ret < 0))
1150 goto nfattr_failure;
1151
1152 proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
1153 ret = ctnetlink_dump_tuples_proto(skb, mask, proto);
1154 ip_conntrack_proto_put(proto);
1155 if (unlikely(ret < 0))
1156 goto nfattr_failure;
1157
1158 NFA_NEST_END(skb, nest_parms);
1159
1160 return 0;
1161
1162nfattr_failure:
1163 return -1;
1164}
1165
080774a2
HW
1166static inline int
1167ctnetlink_exp_dump_expect(struct sk_buff *skb,
1168 const struct ip_conntrack_expect *exp)
1169{
1444fc55 1170 struct ip_conntrack *master = exp->master;
080774a2
HW
1171 u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
1172 u_int32_t id = htonl(exp->id);
080774a2
HW
1173
1174 if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
1175 goto nfattr_failure;
1cde6436 1176 if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
080774a2 1177 goto nfattr_failure;
1444fc55
HW
1178 if (ctnetlink_exp_dump_tuple(skb,
1179 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
1180 CTA_EXPECT_MASTER) < 0)
1181 goto nfattr_failure;
080774a2
HW
1182
1183 NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
1184 NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
080774a2
HW
1185
1186 return 0;
1187
1188nfattr_failure:
1189 return -1;
1190}
1191
1192static int
1193ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
1194 int event,
1195 int nowait,
1196 const struct ip_conntrack_expect *exp)
1197{
1198 struct nlmsghdr *nlh;
1199 struct nfgenmsg *nfmsg;
1200 unsigned char *b;
1201
1202 b = skb->tail;
1203
1204 event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
1205 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
1206 nfmsg = NLMSG_DATA(nlh);
1207
1208 nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
1209 nfmsg->nfgen_family = AF_INET;
1210 nfmsg->version = NFNETLINK_V0;
1211 nfmsg->res_id = 0;
1212
1213 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1214 goto nfattr_failure;
1215
1216 nlh->nlmsg_len = skb->tail - b;
1217 return skb->len;
1218
1219nlmsg_failure:
1220nfattr_failure:
1221 skb_trim(skb, b - skb->data);
1222 return -1;
1223}
1224
1225#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1226static int ctnetlink_expect_event(struct notifier_block *this,
1227 unsigned long events, void *ptr)
1228{
1229 struct nlmsghdr *nlh;
1230 struct nfgenmsg *nfmsg;
1231 struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr;
1232 struct sk_buff *skb;
1233 unsigned int type;
1234 unsigned char *b;
1235 int flags = 0;
080774a2
HW
1236
1237 if (events & IPEXP_NEW) {
1238 type = IPCTNL_MSG_EXP_NEW;
1239 flags = NLM_F_CREATE|NLM_F_EXCL;
1240 } else
1241 return NOTIFY_DONE;
1242
1243 skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
1244 if (!skb)
1245 return NOTIFY_DONE;
1246
1247 b = skb->tail;
1248
b633ad5f 1249 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
080774a2
HW
1250 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
1251 nfmsg = NLMSG_DATA(nlh);
1252
1253 nlh->nlmsg_flags = flags;
1254 nfmsg->nfgen_family = AF_INET;
1255 nfmsg->version = NFNETLINK_V0;
1256 nfmsg->res_id = 0;
1257
1258 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1259 goto nfattr_failure;
1260
1261 nlh->nlmsg_len = skb->tail - b;
ac6d439d 1262 nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
080774a2
HW
1263 return NOTIFY_DONE;
1264
1265nlmsg_failure:
1266nfattr_failure:
1267 kfree_skb(skb);
1268 return NOTIFY_DONE;
1269}
1270#endif
1271
1272static int
1273ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
1274{
1275 struct ip_conntrack_expect *exp = NULL;
1276 struct list_head *i;
1277 u_int32_t *id = (u_int32_t *) &cb->args[0];
1278
1279 DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
1280
1281 read_lock_bh(&ip_conntrack_lock);
ff21d577 1282 list_for_each_prev(i, &ip_conntrack_expect_list) {
080774a2
HW
1283 exp = (struct ip_conntrack_expect *) i;
1284 if (exp->id <= *id)
1285 continue;
1286 if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
1287 cb->nlh->nlmsg_seq,
1288 IPCTNL_MSG_EXP_NEW,
1289 1, exp) < 0)
1290 goto out;
1291 *id = exp->id;
1292 }
1293out:
1294 read_unlock_bh(&ip_conntrack_lock);
1295
1296 DEBUGP("leaving, last id=%llu\n", *id);
1297
1298 return skb->len;
1299}
1300
56558208
PNA
1301static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
1302 [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t),
1303 [CTA_EXPECT_ID-1] = sizeof(u_int32_t)
1304};
1305
080774a2
HW
1306static int
1307ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
1308 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1309{
1310 struct ip_conntrack_tuple tuple;
1311 struct ip_conntrack_expect *exp;
1312 struct sk_buff *skb2;
1313 int err = 0;
1314
1315 DEBUGP("entered %s\n", __FUNCTION__);
1316
56558208
PNA
1317 if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1318 return -EINVAL;
1319
080774a2
HW
1320 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1321 struct nfgenmsg *msg = NLMSG_DATA(nlh);
1322 u32 rlen;
1323
1324 if (msg->nfgen_family != AF_INET)
1325 return -EAFNOSUPPORT;
1326
1327 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
1328 ctnetlink_exp_dump_table,
1329 ctnetlink_done)) != 0)
1330 return -EINVAL;
1331 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1332 if (rlen > skb->len)
1333 rlen = skb->len;
1334 skb_pull(skb, rlen);
1335 return 0;
1336 }
1337
1444fc55
HW
1338 if (cda[CTA_EXPECT_MASTER-1])
1339 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER);
080774a2
HW
1340 else
1341 return -EINVAL;
1342
1343 if (err < 0)
1344 return err;
1345
a41bc002 1346 exp = ip_conntrack_expect_find(&tuple);
080774a2
HW
1347 if (!exp)
1348 return -ENOENT;
1349
a856a19a
PNA
1350 if (cda[CTA_EXPECT_ID-1]) {
1351 u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1352 if (exp->id != ntohl(id)) {
1353 ip_conntrack_expect_put(exp);
1354 return -ENOENT;
1355 }
1356 }
1357
080774a2
HW
1358 err = -ENOMEM;
1359 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1360 if (!skb2)
1361 goto out;
1362 NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
1363
1364 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
1365 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1366 1, exp);
1367 if (err <= 0)
0f81eb4d 1368 goto free;
080774a2
HW
1369
1370 ip_conntrack_expect_put(exp);
1371
0f81eb4d 1372 return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
080774a2 1373
0f81eb4d
HW
1374free:
1375 kfree_skb(skb2);
080774a2
HW
1376out:
1377 ip_conntrack_expect_put(exp);
080774a2
HW
1378 return err;
1379}
1380
1381static int
1382ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1383 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1384{
1385 struct ip_conntrack_expect *exp, *tmp;
1386 struct ip_conntrack_tuple tuple;
1387 struct ip_conntrack_helper *h;
1388 int err;
1389
56558208
PNA
1390 if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1391 return -EINVAL;
1392
1444fc55
HW
1393 if (cda[CTA_EXPECT_TUPLE-1]) {
1394 /* delete a single expect by tuple */
1395 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1396 if (err < 0)
1397 return err;
1398
1399 /* bump usage count to 2 */
a41bc002 1400 exp = ip_conntrack_expect_find(&tuple);
1444fc55
HW
1401 if (!exp)
1402 return -ENOENT;
1403
1404 if (cda[CTA_EXPECT_ID-1]) {
1405 u_int32_t id =
1406 *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1407 if (exp->id != ntohl(id)) {
1408 ip_conntrack_expect_put(exp);
1409 return -ENOENT;
1410 }
1411 }
1412
1413 /* after list removal, usage count == 1 */
1414 ip_conntrack_unexpect_related(exp);
1415 /* have to put what we 'get' above.
1416 * after this line usage count == 0 */
1417 ip_conntrack_expect_put(exp);
1418 } else if (cda[CTA_EXPECT_HELP_NAME-1]) {
1419 char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
080774a2
HW
1420
1421 /* delete all expectations for this helper */
1422 write_lock_bh(&ip_conntrack_lock);
1423 h = __ip_conntrack_helper_find_byname(name);
1424 if (!h) {
1425 write_unlock_bh(&ip_conntrack_lock);
1426 return -EINVAL;
1427 }
1428 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1429 list) {
1430 if (exp->master->helper == h
49719eb3
PNA
1431 && del_timer(&exp->timeout)) {
1432 ip_ct_unlink_expect(exp);
1433 ip_conntrack_expect_put(exp);
1434 }
080774a2 1435 }
9fb9cbb1 1436 write_unlock_bh(&ip_conntrack_lock);
080774a2
HW
1437 } else {
1438 /* This basically means we have to flush everything*/
1439 write_lock_bh(&ip_conntrack_lock);
1440 list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
1441 list) {
49719eb3
PNA
1442 if (del_timer(&exp->timeout)) {
1443 ip_ct_unlink_expect(exp);
1444 ip_conntrack_expect_put(exp);
1445 }
080774a2
HW
1446 }
1447 write_unlock_bh(&ip_conntrack_lock);
080774a2
HW
1448 }
1449
080774a2
HW
1450 return 0;
1451}
1452static int
1453ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[])
1454{
1455 return -EOPNOTSUPP;
1456}
1457
1458static int
1459ctnetlink_create_expect(struct nfattr *cda[])
1460{
1461 struct ip_conntrack_tuple tuple, mask, master_tuple;
1462 struct ip_conntrack_tuple_hash *h = NULL;
1463 struct ip_conntrack_expect *exp;
1464 struct ip_conntrack *ct;
1465 int err = 0;
1466
1467 DEBUGP("entered %s\n", __FUNCTION__);
1468
1444fc55 1469 /* caller guarantees that those three CTA_EXPECT_* exist */
080774a2
HW
1470 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1471 if (err < 0)
1472 return err;
bd9a26b7 1473 err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK);
080774a2
HW
1474 if (err < 0)
1475 return err;
1444fc55 1476 err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER);
080774a2
HW
1477 if (err < 0)
1478 return err;
1479
1480 /* Look for master conntrack of this expectation */
1481 h = ip_conntrack_find_get(&master_tuple, NULL);
1482 if (!h)
1483 return -ENOENT;
1484 ct = tuplehash_to_ctrack(h);
1485
1486 if (!ct->helper) {
1487 /* such conntrack hasn't got any helper, abort */
1488 err = -EINVAL;
1489 goto out;
1490 }
1491
1492 exp = ip_conntrack_expect_alloc(ct);
1493 if (!exp) {
1494 err = -ENOMEM;
1495 goto out;
1496 }
1497
1498 exp->expectfn = NULL;
2248bcfc 1499 exp->flags = 0;
080774a2
HW
1500 exp->master = ct;
1501 memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
1502 memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
1503
1504 err = ip_conntrack_expect_related(exp);
1505 ip_conntrack_expect_put(exp);
1506
1507out:
1508 ip_conntrack_put(tuplehash_to_ctrack(h));
1509 return err;
1510}
1511
1512static int
1513ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1514 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1515{
1516 struct ip_conntrack_tuple tuple;
1517 struct ip_conntrack_expect *exp;
1518 int err = 0;
1519
1520 DEBUGP("entered %s\n", __FUNCTION__);
1521
56558208
PNA
1522 if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1523 return -EINVAL;
1524
1444fc55
HW
1525 if (!cda[CTA_EXPECT_TUPLE-1]
1526 || !cda[CTA_EXPECT_MASK-1]
1527 || !cda[CTA_EXPECT_MASTER-1])
080774a2
HW
1528 return -EINVAL;
1529
1530 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
1531 if (err < 0)
1532 return err;
1533
1534 write_lock_bh(&ip_conntrack_lock);
1535 exp = __ip_conntrack_expect_find(&tuple);
1536
1537 if (!exp) {
1538 write_unlock_bh(&ip_conntrack_lock);
1539 err = -ENOENT;
1540 if (nlh->nlmsg_flags & NLM_F_CREATE)
1541 err = ctnetlink_create_expect(cda);
1542 return err;
1543 }
1544
1545 err = -EEXIST;
1546 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1547 err = ctnetlink_change_expect(exp, cda);
1548 write_unlock_bh(&ip_conntrack_lock);
1549
1550 DEBUGP("leaving\n");
1551
1552 return err;
1553}
1554
1555#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1556static struct notifier_block ctnl_notifier = {
1557 .notifier_call = ctnetlink_conntrack_event,
1558};
1559
1560static struct notifier_block ctnl_notifier_exp = {
1561 .notifier_call = ctnetlink_expect_event,
1562};
1563#endif
1564
1565static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
1566 [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
37d2e7a2 1567 .attr_count = CTA_MAX, },
080774a2 1568 [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
37d2e7a2 1569 .attr_count = CTA_MAX, },
080774a2 1570 [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
37d2e7a2 1571 .attr_count = CTA_MAX, },
080774a2 1572 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
37d2e7a2 1573 .attr_count = CTA_MAX, },
080774a2
HW
1574};
1575
28b19d99 1576static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
080774a2 1577 [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
37d2e7a2 1578 .attr_count = CTA_EXPECT_MAX, },
080774a2 1579 [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
37d2e7a2 1580 .attr_count = CTA_EXPECT_MAX, },
080774a2 1581 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
37d2e7a2 1582 .attr_count = CTA_EXPECT_MAX, },
080774a2
HW
1583};
1584
1585static struct nfnetlink_subsystem ctnl_subsys = {
1586 .name = "conntrack",
1587 .subsys_id = NFNL_SUBSYS_CTNETLINK,
1588 .cb_count = IPCTNL_MSG_MAX,
080774a2
HW
1589 .cb = ctnl_cb,
1590};
1591
1592static struct nfnetlink_subsystem ctnl_exp_subsys = {
1593 .name = "conntrack_expect",
1594 .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP,
1595 .cb_count = IPCTNL_MSG_EXP_MAX,
080774a2
HW
1596 .cb = ctnl_exp_cb,
1597};
1598
119a3184 1599MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
34f9a2e4 1600MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
119a3184 1601
080774a2
HW
1602static int __init ctnetlink_init(void)
1603{
1604 int ret;
1605
1606 printk("ctnetlink v%s: registering with nfnetlink.\n", version);
1607 ret = nfnetlink_subsys_register(&ctnl_subsys);
1608 if (ret < 0) {
1609 printk("ctnetlink_init: cannot register with nfnetlink.\n");
1610 goto err_out;
1611 }
1612
1613 ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
1614 if (ret < 0) {
1615 printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
1616 goto err_unreg_subsys;
1617 }
1618
1619#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1620 ret = ip_conntrack_register_notifier(&ctnl_notifier);
1621 if (ret < 0) {
1622 printk("ctnetlink_init: cannot register notifier.\n");
1623 goto err_unreg_exp_subsys;
1624 }
1625
1626 ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp);
1627 if (ret < 0) {
1628 printk("ctnetlink_init: cannot expect register notifier.\n");
1629 goto err_unreg_notifier;
1630 }
1631#endif
1632
1633 return 0;
1634
1635#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1636err_unreg_notifier:
1637 ip_conntrack_unregister_notifier(&ctnl_notifier);
1638err_unreg_exp_subsys:
1639 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1640#endif
1641err_unreg_subsys:
1642 nfnetlink_subsys_unregister(&ctnl_subsys);
1643err_out:
1644 return ret;
1645}
1646
1647static void __exit ctnetlink_exit(void)
1648{
1649 printk("ctnetlink: unregistering from nfnetlink.\n");
1650
1651#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
e64a70be 1652 ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
080774a2
HW
1653 ip_conntrack_unregister_notifier(&ctnl_notifier);
1654#endif
1655
1656 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1657 nfnetlink_subsys_unregister(&ctnl_subsys);
1658 return;
1659}
1660
1661module_init(ctnetlink_init);
1662module_exit(ctnetlink_exit);
This page took 0.186665 seconds and 5 git commands to generate.