]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/netfilter/nfnetlink_cthelper.c
netfilter: nf_tables: add nft_is_base_chain() helper
[mirror_ubuntu-artful-kernel.git] / net / netfilter / nfnetlink_cthelper.c
CommitLineData
12f7a505
PNA
1/*
2 * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation (or any later at your option).
7 *
8 * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
9 */
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/skbuff.h>
14#include <linux/netlink.h>
15#include <linux/rculist.h>
16#include <linux/slab.h>
17#include <linux/types.h>
18#include <linux/list.h>
19#include <linux/errno.h>
20#include <net/netlink.h>
21#include <net/sock.h>
22
23#include <net/netfilter/nf_conntrack_helper.h>
24#include <net/netfilter/nf_conntrack_expect.h>
25#include <net/netfilter/nf_conntrack_ecache.h>
26
27#include <linux/netfilter/nfnetlink.h>
28#include <linux/netfilter/nfnetlink_conntrack.h>
29#include <linux/netfilter/nfnetlink_cthelper.h>
30
31MODULE_LICENSE("GPL");
32MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
33MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
34
83d90219
LZ
35struct nfnl_cthelper {
36 struct list_head list;
37 struct nf_conntrack_helper helper;
38};
39
40static LIST_HEAD(nfnl_cthelper_list);
41
12f7a505
PNA
42static int
43nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
44 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
45{
46 const struct nf_conn_help *help;
47 struct nf_conntrack_helper *helper;
48
49 help = nfct_help(ct);
50 if (help == NULL)
51 return NF_DROP;
52
e2361cb9 53 /* rcu_read_lock()ed by nf_hook_thresh */
12f7a505
PNA
54 helper = rcu_dereference(help->helper);
55 if (helper == NULL)
56 return NF_DROP;
57
9332ef9d 58 /* This is a user-space helper not yet configured, skip. */
12f7a505
PNA
59 if ((helper->flags &
60 (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
61 NF_CT_HELPER_F_USERSPACE)
62 return NF_ACCEPT;
63
64 /* If the user-space helper is not available, don't block traffic. */
65 return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
66}
67
68static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
69 [NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
70 [NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
71};
72
73static int
74nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
75 const struct nlattr *attr)
76{
130ffbc2 77 int err;
12f7a505
PNA
78 struct nlattr *tb[NFCTH_TUPLE_MAX+1];
79
130ffbc2
DB
80 err = nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr, nfnl_cthelper_tuple_pol);
81 if (err < 0)
82 return err;
12f7a505
PNA
83
84 if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
85 return -EINVAL;
86
78146572
IW
87 /* Not all fields are initialized so first zero the tuple */
88 memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
89
fe31d1a8 90 tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
12f7a505
PNA
91 tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
92
93 return 0;
94}
95
96static int
97nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
98{
b18c5d15 99 struct nf_conn_help *help = nfct_help(ct);
12f7a505 100
7be54ca4
PNA
101 if (attr == NULL)
102 return -EINVAL;
103
12f7a505
PNA
104 if (help->helper->data_len == 0)
105 return -EINVAL;
106
b18c5d15 107 memcpy(help->data, nla_data(attr), help->helper->data_len);
12f7a505
PNA
108 return 0;
109}
110
111static int
112nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
113{
114 const struct nf_conn_help *help = nfct_help(ct);
115
116 if (help->helper->data_len &&
117 nla_put(skb, CTA_HELP_INFO, help->helper->data_len, &help->data))
118 goto nla_put_failure;
119
120 return 0;
121
122nla_put_failure:
123 return -ENOSPC;
124}
125
126static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
127 [NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
128 .len = NF_CT_HELPER_NAME_LEN-1 },
129 [NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
130 [NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
131};
132
133static int
134nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
135 const struct nlattr *attr)
136{
130ffbc2 137 int err;
12f7a505
PNA
138 struct nlattr *tb[NFCTH_POLICY_MAX+1];
139
130ffbc2
DB
140 err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, nfnl_cthelper_expect_pol);
141 if (err < 0)
142 return err;
12f7a505
PNA
143
144 if (!tb[NFCTH_POLICY_NAME] ||
145 !tb[NFCTH_POLICY_EXPECT_MAX] ||
146 !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
147 return -EINVAL;
148
149 strncpy(expect_policy->name,
150 nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN);
151 expect_policy->max_expected =
152 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
153 expect_policy->timeout =
154 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
155
156 return 0;
157}
158
159static const struct nla_policy
160nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
161 [NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
162};
163
164static int
165nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
166 const struct nlattr *attr)
167{
168 int i, ret;
169 struct nf_conntrack_expect_policy *expect_policy;
170 struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
ae5c6821 171 unsigned int class_max;
12f7a505 172
130ffbc2
DB
173 ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
174 nfnl_cthelper_expect_policy_set);
175 if (ret < 0)
176 return ret;
12f7a505
PNA
177
178 if (!tb[NFCTH_POLICY_SET_NUM])
179 return -EINVAL;
180
ae5c6821
LZ
181 class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
182 if (class_max == 0)
183 return -EINVAL;
184 if (class_max > NF_CT_MAX_EXPECT_CLASSES)
12f7a505
PNA
185 return -EOVERFLOW;
186
187 expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) *
ae5c6821 188 class_max, GFP_KERNEL);
12f7a505
PNA
189 if (expect_policy == NULL)
190 return -ENOMEM;
191
ae5c6821 192 for (i = 0; i < class_max; i++) {
12f7a505
PNA
193 if (!tb[NFCTH_POLICY_SET+i])
194 goto err;
195
196 ret = nfnl_cthelper_expect_policy(&expect_policy[i],
197 tb[NFCTH_POLICY_SET+i]);
198 if (ret < 0)
199 goto err;
200 }
ae5c6821
LZ
201
202 helper->expect_class_max = class_max - 1;
12f7a505
PNA
203 helper->expect_policy = expect_policy;
204 return 0;
205err:
206 kfree(expect_policy);
207 return -EINVAL;
208}
209
210static int
211nfnl_cthelper_create(const struct nlattr * const tb[],
212 struct nf_conntrack_tuple *tuple)
213{
214 struct nf_conntrack_helper *helper;
83d90219 215 struct nfnl_cthelper *nfcth;
12f7a505
PNA
216 int ret;
217
218 if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
219 return -EINVAL;
220
83d90219
LZ
221 nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL);
222 if (nfcth == NULL)
12f7a505 223 return -ENOMEM;
83d90219 224 helper = &nfcth->helper;
12f7a505
PNA
225
226 ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
227 if (ret < 0)
f83bf8da 228 goto err1;
12f7a505
PNA
229
230 strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN);
231 helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
232 helper->flags |= NF_CT_HELPER_F_USERSPACE;
233 memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
234
235 helper->me = THIS_MODULE;
236 helper->help = nfnl_userspace_cthelper;
237 helper->from_nlattr = nfnl_cthelper_from_nlattr;
238 helper->to_nlattr = nfnl_cthelper_to_nlattr;
239
240 /* Default to queue number zero, this can be updated at any time. */
241 if (tb[NFCTH_QUEUE_NUM])
242 helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
243
244 if (tb[NFCTH_STATUS]) {
245 int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
246
247 switch(status) {
248 case NFCT_HELPER_STATUS_ENABLED:
249 helper->flags |= NF_CT_HELPER_F_CONFIGURED;
250 break;
251 case NFCT_HELPER_STATUS_DISABLED:
252 helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
253 break;
254 }
255 }
256
257 ret = nf_conntrack_helper_register(helper);
258 if (ret < 0)
f83bf8da 259 goto err2;
12f7a505 260
83d90219 261 list_add_tail(&nfcth->list, &nfnl_cthelper_list);
12f7a505 262 return 0;
f83bf8da
JC
263err2:
264 kfree(helper->expect_policy);
265err1:
83d90219 266 kfree(nfcth);
12f7a505
PNA
267 return ret;
268}
269
2c422257
PNA
270static int
271nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy,
272 struct nf_conntrack_expect_policy *new_policy,
273 const struct nlattr *attr)
274{
275 struct nlattr *tb[NFCTH_POLICY_MAX + 1];
276 int err;
277
278 err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr,
279 nfnl_cthelper_expect_pol);
280 if (err < 0)
281 return err;
282
283 if (!tb[NFCTH_POLICY_NAME] ||
284 !tb[NFCTH_POLICY_EXPECT_MAX] ||
285 !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
286 return -EINVAL;
287
288 if (nla_strcmp(tb[NFCTH_POLICY_NAME], policy->name))
289 return -EBUSY;
290
291 new_policy->max_expected =
292 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
293 new_policy->timeout =
294 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
295
296 return 0;
297}
298
299static int nfnl_cthelper_update_policy_all(struct nlattr *tb[],
300 struct nf_conntrack_helper *helper)
301{
302 struct nf_conntrack_expect_policy new_policy[helper->expect_class_max + 1];
303 struct nf_conntrack_expect_policy *policy;
304 int i, err;
305
306 /* Check first that all policy attributes are well-formed, so we don't
307 * leave things in inconsistent state on errors.
308 */
309 for (i = 0; i < helper->expect_class_max + 1; i++) {
310
311 if (!tb[NFCTH_POLICY_SET + i])
312 return -EINVAL;
313
314 err = nfnl_cthelper_update_policy_one(&helper->expect_policy[i],
315 &new_policy[i],
316 tb[NFCTH_POLICY_SET + i]);
317 if (err < 0)
318 return err;
319 }
320 /* Now we can safely update them. */
321 for (i = 0; i < helper->expect_class_max + 1; i++) {
322 policy = (struct nf_conntrack_expect_policy *)
323 &helper->expect_policy[i];
324 policy->max_expected = new_policy->max_expected;
325 policy->timeout = new_policy->timeout;
326 }
327
328 return 0;
329}
330
331static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper,
332 const struct nlattr *attr)
333{
334 struct nlattr *tb[NFCTH_POLICY_SET_MAX + 1];
335 unsigned int class_max;
336 int err;
337
338 err = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
339 nfnl_cthelper_expect_policy_set);
340 if (err < 0)
341 return err;
342
343 if (!tb[NFCTH_POLICY_SET_NUM])
344 return -EINVAL;
345
346 class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
347 if (helper->expect_class_max + 1 != class_max)
348 return -EBUSY;
349
350 return nfnl_cthelper_update_policy_all(tb, helper);
351}
352
12f7a505
PNA
353static int
354nfnl_cthelper_update(const struct nlattr * const tb[],
355 struct nf_conntrack_helper *helper)
356{
357 int ret;
358
359 if (tb[NFCTH_PRIV_DATA_LEN])
360 return -EBUSY;
361
362 if (tb[NFCTH_POLICY]) {
2c422257 363 ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]);
12f7a505
PNA
364 if (ret < 0)
365 return ret;
366 }
367 if (tb[NFCTH_QUEUE_NUM])
368 helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
369
370 if (tb[NFCTH_STATUS]) {
371 int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
372
373 switch(status) {
374 case NFCT_HELPER_STATUS_ENABLED:
375 helper->flags |= NF_CT_HELPER_F_CONFIGURED;
376 break;
377 case NFCT_HELPER_STATUS_DISABLED:
378 helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
379 break;
380 }
381 }
382 return 0;
383}
384
7b8002a1
PNA
385static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
386 struct sk_buff *skb, const struct nlmsghdr *nlh,
387 const struct nlattr * const tb[])
12f7a505
PNA
388{
389 const char *helper_name;
390 struct nf_conntrack_helper *cur, *helper = NULL;
391 struct nf_conntrack_tuple tuple;
83d90219
LZ
392 struct nfnl_cthelper *nlcth;
393 int ret = 0;
12f7a505
PNA
394
395 if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
396 return -EINVAL;
397
398 helper_name = nla_data(tb[NFCTH_NAME]);
399
400 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
401 if (ret < 0)
402 return ret;
403
83d90219
LZ
404 list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
405 cur = &nlcth->helper;
12f7a505 406
83d90219
LZ
407 if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
408 continue;
12f7a505 409
83d90219
LZ
410 if ((tuple.src.l3num != cur->tuple.src.l3num ||
411 tuple.dst.protonum != cur->tuple.dst.protonum))
412 continue;
12f7a505 413
83d90219
LZ
414 if (nlh->nlmsg_flags & NLM_F_EXCL)
415 return -EEXIST;
12f7a505 416
83d90219
LZ
417 helper = cur;
418 break;
12f7a505 419 }
12f7a505
PNA
420
421 if (helper == NULL)
422 ret = nfnl_cthelper_create(tb, &tuple);
423 else
424 ret = nfnl_cthelper_update(tb, helper);
425
426 return ret;
12f7a505
PNA
427}
428
429static int
430nfnl_cthelper_dump_tuple(struct sk_buff *skb,
431 struct nf_conntrack_helper *helper)
432{
433 struct nlattr *nest_parms;
434
435 nest_parms = nla_nest_start(skb, NFCTH_TUPLE | NLA_F_NESTED);
436 if (nest_parms == NULL)
437 goto nla_put_failure;
438
439 if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
440 htons(helper->tuple.src.l3num)))
441 goto nla_put_failure;
442
443 if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
444 goto nla_put_failure;
445
446 nla_nest_end(skb, nest_parms);
447 return 0;
448
449nla_put_failure:
450 return -1;
451}
452
453static int
454nfnl_cthelper_dump_policy(struct sk_buff *skb,
455 struct nf_conntrack_helper *helper)
456{
457 int i;
458 struct nlattr *nest_parms1, *nest_parms2;
459
460 nest_parms1 = nla_nest_start(skb, NFCTH_POLICY | NLA_F_NESTED);
461 if (nest_parms1 == NULL)
462 goto nla_put_failure;
463
464 if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
ae5c6821 465 htonl(helper->expect_class_max + 1)))
12f7a505
PNA
466 goto nla_put_failure;
467
ae5c6821 468 for (i = 0; i < helper->expect_class_max + 1; i++) {
12f7a505
PNA
469 nest_parms2 = nla_nest_start(skb,
470 (NFCTH_POLICY_SET+i) | NLA_F_NESTED);
471 if (nest_parms2 == NULL)
472 goto nla_put_failure;
473
474 if (nla_put_string(skb, NFCTH_POLICY_NAME,
475 helper->expect_policy[i].name))
476 goto nla_put_failure;
477
478 if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
479 htonl(helper->expect_policy[i].max_expected)))
480 goto nla_put_failure;
481
482 if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
483 htonl(helper->expect_policy[i].timeout)))
484 goto nla_put_failure;
485
486 nla_nest_end(skb, nest_parms2);
487 }
488 nla_nest_end(skb, nest_parms1);
489 return 0;
490
491nla_put_failure:
492 return -1;
493}
494
495static int
15e47304 496nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
12f7a505
PNA
497 int event, struct nf_conntrack_helper *helper)
498{
499 struct nlmsghdr *nlh;
500 struct nfgenmsg *nfmsg;
15e47304 501 unsigned int flags = portid ? NLM_F_MULTI : 0;
12f7a505
PNA
502 int status;
503
504 event |= NFNL_SUBSYS_CTHELPER << 8;
15e47304 505 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
12f7a505
PNA
506 if (nlh == NULL)
507 goto nlmsg_failure;
508
509 nfmsg = nlmsg_data(nlh);
510 nfmsg->nfgen_family = AF_UNSPEC;
511 nfmsg->version = NFNETLINK_V0;
512 nfmsg->res_id = 0;
513
514 if (nla_put_string(skb, NFCTH_NAME, helper->name))
515 goto nla_put_failure;
516
517 if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
518 goto nla_put_failure;
519
520 if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
521 goto nla_put_failure;
522
523 if (nfnl_cthelper_dump_policy(skb, helper) < 0)
524 goto nla_put_failure;
525
526 if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
527 goto nla_put_failure;
528
529 if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
530 status = NFCT_HELPER_STATUS_ENABLED;
531 else
532 status = NFCT_HELPER_STATUS_DISABLED;
533
534 if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
535 goto nla_put_failure;
536
537 nlmsg_end(skb, nlh);
538 return skb->len;
539
540nlmsg_failure:
541nla_put_failure:
542 nlmsg_cancel(skb, nlh);
543 return -1;
544}
545
546static int
547nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
548{
549 struct nf_conntrack_helper *cur, *last;
12f7a505
PNA
550
551 rcu_read_lock();
552 last = (struct nf_conntrack_helper *)cb->args[1];
553 for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
554restart:
b67bfe0d 555 hlist_for_each_entry_rcu(cur,
12f7a505
PNA
556 &nf_ct_helper_hash[cb->args[0]], hnode) {
557
558 /* skip non-userspace conntrack helpers. */
559 if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
560 continue;
561
562 if (cb->args[1]) {
563 if (cur != last)
564 continue;
565 cb->args[1] = 0;
566 }
567 if (nfnl_cthelper_fill_info(skb,
15e47304 568 NETLINK_CB(cb->skb).portid,
12f7a505
PNA
569 cb->nlh->nlmsg_seq,
570 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
571 NFNL_MSG_CTHELPER_NEW, cur) < 0) {
572 cb->args[1] = (unsigned long)cur;
573 goto out;
574 }
575 }
576 }
577 if (cb->args[1]) {
578 cb->args[1] = 0;
579 goto restart;
580 }
581out:
582 rcu_read_unlock();
583 return skb->len;
584}
585
7b8002a1
PNA
586static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
587 struct sk_buff *skb, const struct nlmsghdr *nlh,
588 const struct nlattr * const tb[])
12f7a505 589{
83d90219 590 int ret = -ENOENT;
12f7a505 591 struct nf_conntrack_helper *cur;
12f7a505
PNA
592 struct sk_buff *skb2;
593 char *helper_name = NULL;
594 struct nf_conntrack_tuple tuple;
83d90219 595 struct nfnl_cthelper *nlcth;
12f7a505
PNA
596 bool tuple_set = false;
597
598 if (nlh->nlmsg_flags & NLM_F_DUMP) {
599 struct netlink_dump_control c = {
600 .dump = nfnl_cthelper_dump_table,
601 };
602 return netlink_dump_start(nfnl, skb, nlh, &c);
603 }
604
605 if (tb[NFCTH_NAME])
606 helper_name = nla_data(tb[NFCTH_NAME]);
607
608 if (tb[NFCTH_TUPLE]) {
609 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
610 if (ret < 0)
611 return ret;
612
613 tuple_set = true;
614 }
615
83d90219
LZ
616 list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
617 cur = &nlcth->helper;
618 if (helper_name &&
619 strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
620 continue;
12f7a505 621
83d90219
LZ
622 if (tuple_set &&
623 (tuple.src.l3num != cur->tuple.src.l3num ||
624 tuple.dst.protonum != cur->tuple.dst.protonum))
625 continue;
12f7a505 626
83d90219
LZ
627 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
628 if (skb2 == NULL) {
629 ret = -ENOMEM;
630 break;
631 }
12f7a505 632
83d90219
LZ
633 ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
634 nlh->nlmsg_seq,
635 NFNL_MSG_TYPE(nlh->nlmsg_type),
636 NFNL_MSG_CTHELPER_NEW, cur);
637 if (ret <= 0) {
638 kfree_skb(skb2);
639 break;
640 }
12f7a505 641
83d90219
LZ
642 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
643 MSG_DONTWAIT);
644 if (ret > 0)
645 ret = 0;
12f7a505 646
83d90219
LZ
647 /* this avoids a loop in nfnetlink. */
648 return ret == -EAGAIN ? -ENOBUFS : ret;
12f7a505
PNA
649 }
650 return ret;
651}
652
7b8002a1
PNA
653static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
654 struct sk_buff *skb, const struct nlmsghdr *nlh,
655 const struct nlattr * const tb[])
12f7a505
PNA
656{
657 char *helper_name = NULL;
658 struct nf_conntrack_helper *cur;
12f7a505
PNA
659 struct nf_conntrack_tuple tuple;
660 bool tuple_set = false, found = false;
83d90219
LZ
661 struct nfnl_cthelper *nlcth, *n;
662 int j = 0, ret;
12f7a505
PNA
663
664 if (tb[NFCTH_NAME])
665 helper_name = nla_data(tb[NFCTH_NAME]);
666
667 if (tb[NFCTH_TUPLE]) {
668 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
669 if (ret < 0)
670 return ret;
671
672 tuple_set = true;
673 }
674
83d90219
LZ
675 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
676 cur = &nlcth->helper;
677 j++;
12f7a505 678
83d90219
LZ
679 if (helper_name &&
680 strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
681 continue;
12f7a505 682
83d90219
LZ
683 if (tuple_set &&
684 (tuple.src.l3num != cur->tuple.src.l3num ||
685 tuple.dst.protonum != cur->tuple.dst.protonum))
686 continue;
12f7a505 687
83d90219
LZ
688 found = true;
689 nf_conntrack_helper_unregister(cur);
690 kfree(cur->expect_policy);
691
692 list_del(&nlcth->list);
693 kfree(nlcth);
12f7a505 694 }
83d90219 695
12f7a505
PNA
696 /* Make sure we return success if we flush and there is no helpers */
697 return (found || j == 0) ? 0 : -ENOENT;
698}
699
700static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
701 [NFCTH_NAME] = { .type = NLA_NUL_STRING,
702 .len = NF_CT_HELPER_NAME_LEN-1 },
703 [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
704};
705
706static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
707 [NFNL_MSG_CTHELPER_NEW] = { .call = nfnl_cthelper_new,
708 .attr_count = NFCTH_MAX,
709 .policy = nfnl_cthelper_policy },
710 [NFNL_MSG_CTHELPER_GET] = { .call = nfnl_cthelper_get,
711 .attr_count = NFCTH_MAX,
712 .policy = nfnl_cthelper_policy },
713 [NFNL_MSG_CTHELPER_DEL] = { .call = nfnl_cthelper_del,
714 .attr_count = NFCTH_MAX,
715 .policy = nfnl_cthelper_policy },
716};
717
718static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
719 .name = "cthelper",
720 .subsys_id = NFNL_SUBSYS_CTHELPER,
721 .cb_count = NFNL_MSG_CTHELPER_MAX,
722 .cb = nfnl_cthelper_cb,
723};
724
725MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
726
727static int __init nfnl_cthelper_init(void)
728{
729 int ret;
730
731 ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
732 if (ret < 0) {
733 pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
734 goto err_out;
735 }
736 return 0;
737err_out:
738 return ret;
739}
740
741static void __exit nfnl_cthelper_exit(void)
742{
743 struct nf_conntrack_helper *cur;
83d90219 744 struct nfnl_cthelper *nlcth, *n;
12f7a505
PNA
745
746 nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
747
83d90219
LZ
748 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
749 cur = &nlcth->helper;
12f7a505 750
83d90219
LZ
751 nf_conntrack_helper_unregister(cur);
752 kfree(cur->expect_policy);
753 kfree(nlcth);
12f7a505
PNA
754 }
755}
756
757module_init(nfnl_cthelper_init);
758module_exit(nfnl_cthelper_exit);