0001
0002
0003
0004
0005
0006
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/kernel.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/netlink.h>
0012 #include <linux/rculist.h>
0013 #include <linux/slab.h>
0014 #include <linux/types.h>
0015 #include <linux/list.h>
0016 #include <linux/errno.h>
0017 #include <linux/capability.h>
0018 #include <net/netlink.h>
0019 #include <net/sock.h>
0020
0021 #include <net/netfilter/nf_conntrack_helper.h>
0022 #include <net/netfilter/nf_conntrack_expect.h>
0023 #include <net/netfilter/nf_conntrack_ecache.h>
0024
0025 #include <linux/netfilter/nfnetlink.h>
0026 #include <linux/netfilter/nfnetlink_conntrack.h>
0027 #include <linux/netfilter/nfnetlink_cthelper.h>
0028
0029 MODULE_LICENSE("GPL");
0030 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
0031 MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
0032
0033 struct nfnl_cthelper {
0034 struct list_head list;
0035 struct nf_conntrack_helper helper;
0036 };
0037
0038 static LIST_HEAD(nfnl_cthelper_list);
0039
0040 static int
0041 nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
0042 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
0043 {
0044 const struct nf_conn_help *help;
0045 struct nf_conntrack_helper *helper;
0046
0047 help = nfct_help(ct);
0048 if (help == NULL)
0049 return NF_DROP;
0050
0051
0052 helper = rcu_dereference(help->helper);
0053 if (helper == NULL)
0054 return NF_DROP;
0055
0056
0057 if ((helper->flags &
0058 (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
0059 NF_CT_HELPER_F_USERSPACE)
0060 return NF_ACCEPT;
0061
0062
0063 return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
0064 }
0065
0066 static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
0067 [NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
0068 [NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
0069 };
0070
0071 static int
0072 nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
0073 const struct nlattr *attr)
0074 {
0075 int err;
0076 struct nlattr *tb[NFCTH_TUPLE_MAX+1];
0077
0078 err = nla_parse_nested_deprecated(tb, NFCTH_TUPLE_MAX, attr,
0079 nfnl_cthelper_tuple_pol, NULL);
0080 if (err < 0)
0081 return err;
0082
0083 if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
0084 return -EINVAL;
0085
0086
0087 memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
0088
0089 tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
0090 tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
0091
0092 return 0;
0093 }
0094
0095 static int
0096 nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
0097 {
0098 struct nf_conn_help *help = nfct_help(ct);
0099 const struct nf_conntrack_helper *helper;
0100
0101 if (attr == NULL)
0102 return -EINVAL;
0103
0104 helper = rcu_dereference(help->helper);
0105 if (!helper || helper->data_len == 0)
0106 return -EINVAL;
0107
0108 nla_memcpy(help->data, attr, sizeof(help->data));
0109 return 0;
0110 }
0111
0112 static int
0113 nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
0114 {
0115 const struct nf_conn_help *help = nfct_help(ct);
0116 const struct nf_conntrack_helper *helper;
0117
0118 helper = rcu_dereference(help->helper);
0119 if (helper && helper->data_len &&
0120 nla_put(skb, CTA_HELP_INFO, helper->data_len, &help->data))
0121 goto nla_put_failure;
0122
0123 return 0;
0124
0125 nla_put_failure:
0126 return -ENOSPC;
0127 }
0128
0129 static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
0130 [NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
0131 .len = NF_CT_HELPER_NAME_LEN-1 },
0132 [NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
0133 [NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
0134 };
0135
0136 static int
0137 nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
0138 const struct nlattr *attr)
0139 {
0140 int err;
0141 struct nlattr *tb[NFCTH_POLICY_MAX+1];
0142
0143 err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_MAX, attr,
0144 nfnl_cthelper_expect_pol, NULL);
0145 if (err < 0)
0146 return err;
0147
0148 if (!tb[NFCTH_POLICY_NAME] ||
0149 !tb[NFCTH_POLICY_EXPECT_MAX] ||
0150 !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
0151 return -EINVAL;
0152
0153 nla_strscpy(expect_policy->name,
0154 tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
0155 expect_policy->max_expected =
0156 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
0157 if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
0158 return -EINVAL;
0159
0160 expect_policy->timeout =
0161 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
0162
0163 return 0;
0164 }
0165
0166 static const struct nla_policy
0167 nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
0168 [NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
0169 };
0170
0171 static int
0172 nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
0173 const struct nlattr *attr)
0174 {
0175 int i, ret;
0176 struct nf_conntrack_expect_policy *expect_policy;
0177 struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
0178 unsigned int class_max;
0179
0180 ret = nla_parse_nested_deprecated(tb, NFCTH_POLICY_SET_MAX, attr,
0181 nfnl_cthelper_expect_policy_set,
0182 NULL);
0183 if (ret < 0)
0184 return ret;
0185
0186 if (!tb[NFCTH_POLICY_SET_NUM])
0187 return -EINVAL;
0188
0189 class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
0190 if (class_max == 0)
0191 return -EINVAL;
0192 if (class_max > NF_CT_MAX_EXPECT_CLASSES)
0193 return -EOVERFLOW;
0194
0195 expect_policy = kcalloc(class_max,
0196 sizeof(struct nf_conntrack_expect_policy),
0197 GFP_KERNEL);
0198 if (expect_policy == NULL)
0199 return -ENOMEM;
0200
0201 for (i = 0; i < class_max; i++) {
0202 if (!tb[NFCTH_POLICY_SET+i])
0203 goto err;
0204
0205 ret = nfnl_cthelper_expect_policy(&expect_policy[i],
0206 tb[NFCTH_POLICY_SET+i]);
0207 if (ret < 0)
0208 goto err;
0209 }
0210
0211 helper->expect_class_max = class_max - 1;
0212 helper->expect_policy = expect_policy;
0213 return 0;
0214 err:
0215 kfree(expect_policy);
0216 return -EINVAL;
0217 }
0218
0219 static int
0220 nfnl_cthelper_create(const struct nlattr * const tb[],
0221 struct nf_conntrack_tuple *tuple)
0222 {
0223 struct nf_conntrack_helper *helper;
0224 struct nfnl_cthelper *nfcth;
0225 unsigned int size;
0226 int ret;
0227
0228 if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
0229 return -EINVAL;
0230
0231 nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL);
0232 if (nfcth == NULL)
0233 return -ENOMEM;
0234 helper = &nfcth->helper;
0235
0236 ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
0237 if (ret < 0)
0238 goto err1;
0239
0240 nla_strscpy(helper->name,
0241 tb[NFCTH_NAME], NF_CT_HELPER_NAME_LEN);
0242 size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
0243 if (size > sizeof_field(struct nf_conn_help, data)) {
0244 ret = -ENOMEM;
0245 goto err2;
0246 }
0247 helper->data_len = size;
0248
0249 helper->flags |= NF_CT_HELPER_F_USERSPACE;
0250 memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
0251
0252 helper->me = THIS_MODULE;
0253 helper->help = nfnl_userspace_cthelper;
0254 helper->from_nlattr = nfnl_cthelper_from_nlattr;
0255 helper->to_nlattr = nfnl_cthelper_to_nlattr;
0256
0257
0258 if (tb[NFCTH_QUEUE_NUM])
0259 helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
0260
0261 if (tb[NFCTH_STATUS]) {
0262 int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
0263
0264 switch(status) {
0265 case NFCT_HELPER_STATUS_ENABLED:
0266 helper->flags |= NF_CT_HELPER_F_CONFIGURED;
0267 break;
0268 case NFCT_HELPER_STATUS_DISABLED:
0269 helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
0270 break;
0271 }
0272 }
0273
0274 ret = nf_conntrack_helper_register(helper);
0275 if (ret < 0)
0276 goto err2;
0277
0278 list_add_tail(&nfcth->list, &nfnl_cthelper_list);
0279 return 0;
0280 err2:
0281 kfree(helper->expect_policy);
0282 err1:
0283 kfree(nfcth);
0284 return ret;
0285 }
0286
0287 static int
0288 nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy,
0289 struct nf_conntrack_expect_policy *new_policy,
0290 const struct nlattr *attr)
0291 {
0292 struct nlattr *tb[NFCTH_POLICY_MAX + 1];
0293 int err;
0294
0295 err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_MAX, attr,
0296 nfnl_cthelper_expect_pol, NULL);
0297 if (err < 0)
0298 return err;
0299
0300 if (!tb[NFCTH_POLICY_NAME] ||
0301 !tb[NFCTH_POLICY_EXPECT_MAX] ||
0302 !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
0303 return -EINVAL;
0304
0305 if (nla_strcmp(tb[NFCTH_POLICY_NAME], policy->name))
0306 return -EBUSY;
0307
0308 new_policy->max_expected =
0309 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
0310 if (new_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
0311 return -EINVAL;
0312
0313 new_policy->timeout =
0314 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
0315
0316 return 0;
0317 }
0318
0319 static int nfnl_cthelper_update_policy_all(struct nlattr *tb[],
0320 struct nf_conntrack_helper *helper)
0321 {
0322 struct nf_conntrack_expect_policy *new_policy;
0323 struct nf_conntrack_expect_policy *policy;
0324 int i, ret = 0;
0325
0326 new_policy = kmalloc_array(helper->expect_class_max + 1,
0327 sizeof(*new_policy), GFP_KERNEL);
0328 if (!new_policy)
0329 return -ENOMEM;
0330
0331
0332
0333
0334 for (i = 0; i < helper->expect_class_max + 1; i++) {
0335
0336 if (!tb[NFCTH_POLICY_SET + i]) {
0337 ret = -EINVAL;
0338 goto err;
0339 }
0340
0341 ret = nfnl_cthelper_update_policy_one(&helper->expect_policy[i],
0342 &new_policy[i],
0343 tb[NFCTH_POLICY_SET + i]);
0344 if (ret < 0)
0345 goto err;
0346 }
0347
0348 for (i = 0; i < helper->expect_class_max + 1; i++) {
0349 policy = (struct nf_conntrack_expect_policy *)
0350 &helper->expect_policy[i];
0351 policy->max_expected = new_policy->max_expected;
0352 policy->timeout = new_policy->timeout;
0353 }
0354
0355 err:
0356 kfree(new_policy);
0357 return ret;
0358 }
0359
0360 static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper,
0361 const struct nlattr *attr)
0362 {
0363 struct nlattr *tb[NFCTH_POLICY_SET_MAX + 1];
0364 unsigned int class_max;
0365 int err;
0366
0367 err = nla_parse_nested_deprecated(tb, NFCTH_POLICY_SET_MAX, attr,
0368 nfnl_cthelper_expect_policy_set,
0369 NULL);
0370 if (err < 0)
0371 return err;
0372
0373 if (!tb[NFCTH_POLICY_SET_NUM])
0374 return -EINVAL;
0375
0376 class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
0377 if (helper->expect_class_max + 1 != class_max)
0378 return -EBUSY;
0379
0380 return nfnl_cthelper_update_policy_all(tb, helper);
0381 }
0382
0383 static int
0384 nfnl_cthelper_update(const struct nlattr * const tb[],
0385 struct nf_conntrack_helper *helper)
0386 {
0387 u32 size;
0388 int ret;
0389
0390 if (tb[NFCTH_PRIV_DATA_LEN]) {
0391 size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
0392 if (size != helper->data_len)
0393 return -EBUSY;
0394 }
0395
0396 if (tb[NFCTH_POLICY]) {
0397 ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]);
0398 if (ret < 0)
0399 return ret;
0400 }
0401 if (tb[NFCTH_QUEUE_NUM])
0402 helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
0403
0404 if (tb[NFCTH_STATUS]) {
0405 int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
0406
0407 switch(status) {
0408 case NFCT_HELPER_STATUS_ENABLED:
0409 helper->flags |= NF_CT_HELPER_F_CONFIGURED;
0410 break;
0411 case NFCT_HELPER_STATUS_DISABLED:
0412 helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
0413 break;
0414 }
0415 }
0416 return 0;
0417 }
0418
0419 static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
0420 const struct nlattr * const tb[])
0421 {
0422 const char *helper_name;
0423 struct nf_conntrack_helper *cur, *helper = NULL;
0424 struct nf_conntrack_tuple tuple;
0425 struct nfnl_cthelper *nlcth;
0426 int ret = 0;
0427
0428 if (!capable(CAP_NET_ADMIN))
0429 return -EPERM;
0430
0431 if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
0432 return -EINVAL;
0433
0434 helper_name = nla_data(tb[NFCTH_NAME]);
0435
0436 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
0437 if (ret < 0)
0438 return ret;
0439
0440 list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
0441 cur = &nlcth->helper;
0442
0443 if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
0444 continue;
0445
0446 if ((tuple.src.l3num != cur->tuple.src.l3num ||
0447 tuple.dst.protonum != cur->tuple.dst.protonum))
0448 continue;
0449
0450 if (info->nlh->nlmsg_flags & NLM_F_EXCL)
0451 return -EEXIST;
0452
0453 helper = cur;
0454 break;
0455 }
0456
0457 if (helper == NULL)
0458 ret = nfnl_cthelper_create(tb, &tuple);
0459 else
0460 ret = nfnl_cthelper_update(tb, helper);
0461
0462 return ret;
0463 }
0464
0465 static int
0466 nfnl_cthelper_dump_tuple(struct sk_buff *skb,
0467 struct nf_conntrack_helper *helper)
0468 {
0469 struct nlattr *nest_parms;
0470
0471 nest_parms = nla_nest_start(skb, NFCTH_TUPLE);
0472 if (nest_parms == NULL)
0473 goto nla_put_failure;
0474
0475 if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
0476 htons(helper->tuple.src.l3num)))
0477 goto nla_put_failure;
0478
0479 if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
0480 goto nla_put_failure;
0481
0482 nla_nest_end(skb, nest_parms);
0483 return 0;
0484
0485 nla_put_failure:
0486 return -1;
0487 }
0488
0489 static int
0490 nfnl_cthelper_dump_policy(struct sk_buff *skb,
0491 struct nf_conntrack_helper *helper)
0492 {
0493 int i;
0494 struct nlattr *nest_parms1, *nest_parms2;
0495
0496 nest_parms1 = nla_nest_start(skb, NFCTH_POLICY);
0497 if (nest_parms1 == NULL)
0498 goto nla_put_failure;
0499
0500 if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
0501 htonl(helper->expect_class_max + 1)))
0502 goto nla_put_failure;
0503
0504 for (i = 0; i < helper->expect_class_max + 1; i++) {
0505 nest_parms2 = nla_nest_start(skb, (NFCTH_POLICY_SET + i));
0506 if (nest_parms2 == NULL)
0507 goto nla_put_failure;
0508
0509 if (nla_put_string(skb, NFCTH_POLICY_NAME,
0510 helper->expect_policy[i].name))
0511 goto nla_put_failure;
0512
0513 if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
0514 htonl(helper->expect_policy[i].max_expected)))
0515 goto nla_put_failure;
0516
0517 if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
0518 htonl(helper->expect_policy[i].timeout)))
0519 goto nla_put_failure;
0520
0521 nla_nest_end(skb, nest_parms2);
0522 }
0523 nla_nest_end(skb, nest_parms1);
0524 return 0;
0525
0526 nla_put_failure:
0527 return -1;
0528 }
0529
0530 static int
0531 nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
0532 int event, struct nf_conntrack_helper *helper)
0533 {
0534 struct nlmsghdr *nlh;
0535 unsigned int flags = portid ? NLM_F_MULTI : 0;
0536 int status;
0537
0538 event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
0539 nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
0540 NFNETLINK_V0, 0);
0541 if (!nlh)
0542 goto nlmsg_failure;
0543
0544 if (nla_put_string(skb, NFCTH_NAME, helper->name))
0545 goto nla_put_failure;
0546
0547 if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
0548 goto nla_put_failure;
0549
0550 if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
0551 goto nla_put_failure;
0552
0553 if (nfnl_cthelper_dump_policy(skb, helper) < 0)
0554 goto nla_put_failure;
0555
0556 if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
0557 goto nla_put_failure;
0558
0559 if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
0560 status = NFCT_HELPER_STATUS_ENABLED;
0561 else
0562 status = NFCT_HELPER_STATUS_DISABLED;
0563
0564 if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
0565 goto nla_put_failure;
0566
0567 nlmsg_end(skb, nlh);
0568 return skb->len;
0569
0570 nlmsg_failure:
0571 nla_put_failure:
0572 nlmsg_cancel(skb, nlh);
0573 return -1;
0574 }
0575
0576 static int
0577 nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
0578 {
0579 struct nf_conntrack_helper *cur, *last;
0580
0581 rcu_read_lock();
0582 last = (struct nf_conntrack_helper *)cb->args[1];
0583 for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
0584 restart:
0585 hlist_for_each_entry_rcu(cur,
0586 &nf_ct_helper_hash[cb->args[0]], hnode) {
0587
0588
0589 if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
0590 continue;
0591
0592 if (cb->args[1]) {
0593 if (cur != last)
0594 continue;
0595 cb->args[1] = 0;
0596 }
0597 if (nfnl_cthelper_fill_info(skb,
0598 NETLINK_CB(cb->skb).portid,
0599 cb->nlh->nlmsg_seq,
0600 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
0601 NFNL_MSG_CTHELPER_NEW, cur) < 0) {
0602 cb->args[1] = (unsigned long)cur;
0603 goto out;
0604 }
0605 }
0606 }
0607 if (cb->args[1]) {
0608 cb->args[1] = 0;
0609 goto restart;
0610 }
0611 out:
0612 rcu_read_unlock();
0613 return skb->len;
0614 }
0615
0616 static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
0617 const struct nlattr * const tb[])
0618 {
0619 int ret = -ENOENT;
0620 struct nf_conntrack_helper *cur;
0621 struct sk_buff *skb2;
0622 char *helper_name = NULL;
0623 struct nf_conntrack_tuple tuple;
0624 struct nfnl_cthelper *nlcth;
0625 bool tuple_set = false;
0626
0627 if (!capable(CAP_NET_ADMIN))
0628 return -EPERM;
0629
0630 if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
0631 struct netlink_dump_control c = {
0632 .dump = nfnl_cthelper_dump_table,
0633 };
0634 return netlink_dump_start(info->sk, skb, info->nlh, &c);
0635 }
0636
0637 if (tb[NFCTH_NAME])
0638 helper_name = nla_data(tb[NFCTH_NAME]);
0639
0640 if (tb[NFCTH_TUPLE]) {
0641 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
0642 if (ret < 0)
0643 return ret;
0644
0645 tuple_set = true;
0646 }
0647
0648 list_for_each_entry(nlcth, &nfnl_cthelper_list, list) {
0649 cur = &nlcth->helper;
0650 if (helper_name &&
0651 strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
0652 continue;
0653
0654 if (tuple_set &&
0655 (tuple.src.l3num != cur->tuple.src.l3num ||
0656 tuple.dst.protonum != cur->tuple.dst.protonum))
0657 continue;
0658
0659 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0660 if (skb2 == NULL) {
0661 ret = -ENOMEM;
0662 break;
0663 }
0664
0665 ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
0666 info->nlh->nlmsg_seq,
0667 NFNL_MSG_TYPE(info->nlh->nlmsg_type),
0668 NFNL_MSG_CTHELPER_NEW, cur);
0669 if (ret <= 0) {
0670 kfree_skb(skb2);
0671 break;
0672 }
0673
0674 ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
0675 break;
0676 }
0677
0678 return ret;
0679 }
0680
0681 static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
0682 const struct nlattr * const tb[])
0683 {
0684 char *helper_name = NULL;
0685 struct nf_conntrack_helper *cur;
0686 struct nf_conntrack_tuple tuple;
0687 bool tuple_set = false, found = false;
0688 struct nfnl_cthelper *nlcth, *n;
0689 int j = 0, ret;
0690
0691 if (!capable(CAP_NET_ADMIN))
0692 return -EPERM;
0693
0694 if (tb[NFCTH_NAME])
0695 helper_name = nla_data(tb[NFCTH_NAME]);
0696
0697 if (tb[NFCTH_TUPLE]) {
0698 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
0699 if (ret < 0)
0700 return ret;
0701
0702 tuple_set = true;
0703 }
0704
0705 ret = -ENOENT;
0706 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
0707 cur = &nlcth->helper;
0708 j++;
0709
0710 if (helper_name &&
0711 strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN))
0712 continue;
0713
0714 if (tuple_set &&
0715 (tuple.src.l3num != cur->tuple.src.l3num ||
0716 tuple.dst.protonum != cur->tuple.dst.protonum))
0717 continue;
0718
0719 if (refcount_dec_if_one(&cur->refcnt)) {
0720 found = true;
0721 nf_conntrack_helper_unregister(cur);
0722 kfree(cur->expect_policy);
0723
0724 list_del(&nlcth->list);
0725 kfree(nlcth);
0726 } else {
0727 ret = -EBUSY;
0728 }
0729 }
0730
0731
0732 return (found || j == 0) ? 0 : ret;
0733 }
0734
0735 static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
0736 [NFCTH_NAME] = { .type = NLA_NUL_STRING,
0737 .len = NF_CT_HELPER_NAME_LEN-1 },
0738 [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
0739 [NFCTH_PRIV_DATA_LEN] = { .type = NLA_U32, },
0740 [NFCTH_STATUS] = { .type = NLA_U32, },
0741 };
0742
0743 static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
0744 [NFNL_MSG_CTHELPER_NEW] = {
0745 .call = nfnl_cthelper_new,
0746 .type = NFNL_CB_MUTEX,
0747 .attr_count = NFCTH_MAX,
0748 .policy = nfnl_cthelper_policy
0749 },
0750 [NFNL_MSG_CTHELPER_GET] = {
0751 .call = nfnl_cthelper_get,
0752 .type = NFNL_CB_MUTEX,
0753 .attr_count = NFCTH_MAX,
0754 .policy = nfnl_cthelper_policy
0755 },
0756 [NFNL_MSG_CTHELPER_DEL] = {
0757 .call = nfnl_cthelper_del,
0758 .type = NFNL_CB_MUTEX,
0759 .attr_count = NFCTH_MAX,
0760 .policy = nfnl_cthelper_policy
0761 },
0762 };
0763
0764 static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
0765 .name = "cthelper",
0766 .subsys_id = NFNL_SUBSYS_CTHELPER,
0767 .cb_count = NFNL_MSG_CTHELPER_MAX,
0768 .cb = nfnl_cthelper_cb,
0769 };
0770
0771 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
0772
0773 static int __init nfnl_cthelper_init(void)
0774 {
0775 int ret;
0776
0777 ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
0778 if (ret < 0) {
0779 pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
0780 goto err_out;
0781 }
0782 return 0;
0783 err_out:
0784 return ret;
0785 }
0786
0787 static void __exit nfnl_cthelper_exit(void)
0788 {
0789 struct nf_conntrack_helper *cur;
0790 struct nfnl_cthelper *nlcth, *n;
0791
0792 nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
0793
0794 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
0795 cur = &nlcth->helper;
0796
0797 nf_conntrack_helper_unregister(cur);
0798 kfree(cur->expect_policy);
0799 kfree(nlcth);
0800 }
0801 }
0802
0803 module_init(nfnl_cthelper_init);
0804 module_exit(nfnl_cthelper_exit);