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