Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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