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