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 v4.11-rc7 758 lines 19 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 <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 35struct nfnl_cthelper { 36 struct list_head list; 37 struct nf_conntrack_helper helper; 38}; 39 40static LIST_HEAD(nfnl_cthelper_list); 41 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 53 /* rcu_read_lock()ed by nf_hook_thresh */ 54 helper = rcu_dereference(help->helper); 55 if (helper == NULL) 56 return NF_DROP; 57 58 /* This is a user-space helper not yet configured, skip. */ 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{ 77 int err; 78 struct nlattr *tb[NFCTH_TUPLE_MAX+1]; 79 80 err = nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr, nfnl_cthelper_tuple_pol); 81 if (err < 0) 82 return err; 83 84 if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM]) 85 return -EINVAL; 86 87 /* Not all fields are initialized so first zero the tuple */ 88 memset(tuple, 0, sizeof(struct nf_conntrack_tuple)); 89 90 tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM])); 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{ 99 struct nf_conn_help *help = nfct_help(ct); 100 101 if (attr == NULL) 102 return -EINVAL; 103 104 if (help->helper->data_len == 0) 105 return -EINVAL; 106 107 memcpy(help->data, nla_data(attr), help->helper->data_len); 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{ 137 int err; 138 struct nlattr *tb[NFCTH_POLICY_MAX+1]; 139 140 err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, nfnl_cthelper_expect_pol); 141 if (err < 0) 142 return err; 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]; 171 unsigned int class_max; 172 173 ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, 174 nfnl_cthelper_expect_policy_set); 175 if (ret < 0) 176 return ret; 177 178 if (!tb[NFCTH_POLICY_SET_NUM]) 179 return -EINVAL; 180 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) 185 return -EOVERFLOW; 186 187 expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) * 188 class_max, GFP_KERNEL); 189 if (expect_policy == NULL) 190 return -ENOMEM; 191 192 for (i = 0; i < class_max; i++) { 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 } 201 202 helper->expect_class_max = class_max - 1; 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; 215 struct nfnl_cthelper *nfcth; 216 int ret; 217 218 if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN]) 219 return -EINVAL; 220 221 nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL); 222 if (nfcth == NULL) 223 return -ENOMEM; 224 helper = &nfcth->helper; 225 226 ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]); 227 if (ret < 0) 228 goto err1; 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) 259 goto err2; 260 261 list_add_tail(&nfcth->list, &nfnl_cthelper_list); 262 return 0; 263err2: 264 kfree(helper->expect_policy); 265err1: 266 kfree(nfcth); 267 return ret; 268} 269 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 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]) { 363 ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]); 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 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[]) 388{ 389 const char *helper_name; 390 struct nf_conntrack_helper *cur, *helper = NULL; 391 struct nf_conntrack_tuple tuple; 392 struct nfnl_cthelper *nlcth; 393 int ret = 0; 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 404 list_for_each_entry(nlcth, &nfnl_cthelper_list, list) { 405 cur = &nlcth->helper; 406 407 if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) 408 continue; 409 410 if ((tuple.src.l3num != cur->tuple.src.l3num || 411 tuple.dst.protonum != cur->tuple.dst.protonum)) 412 continue; 413 414 if (nlh->nlmsg_flags & NLM_F_EXCL) 415 return -EEXIST; 416 417 helper = cur; 418 break; 419 } 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; 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, 465 htonl(helper->expect_class_max + 1))) 466 goto nla_put_failure; 467 468 for (i = 0; i < helper->expect_class_max + 1; i++) { 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 496nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, 497 int event, struct nf_conntrack_helper *helper) 498{ 499 struct nlmsghdr *nlh; 500 struct nfgenmsg *nfmsg; 501 unsigned int flags = portid ? NLM_F_MULTI : 0; 502 int status; 503 504 event |= NFNL_SUBSYS_CTHELPER << 8; 505 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 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; 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: 555 hlist_for_each_entry_rcu(cur, 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, 568 NETLINK_CB(cb->skb).portid, 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 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[]) 589{ 590 int ret = -ENOENT; 591 struct nf_conntrack_helper *cur; 592 struct sk_buff *skb2; 593 char *helper_name = NULL; 594 struct nf_conntrack_tuple tuple; 595 struct nfnl_cthelper *nlcth; 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 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; 621 622 if (tuple_set && 623 (tuple.src.l3num != cur->tuple.src.l3num || 624 tuple.dst.protonum != cur->tuple.dst.protonum)) 625 continue; 626 627 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 628 if (skb2 == NULL) { 629 ret = -ENOMEM; 630 break; 631 } 632 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 } 641 642 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, 643 MSG_DONTWAIT); 644 if (ret > 0) 645 ret = 0; 646 647 /* this avoids a loop in nfnetlink. */ 648 return ret == -EAGAIN ? -ENOBUFS : ret; 649 } 650 return ret; 651} 652 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[]) 656{ 657 char *helper_name = NULL; 658 struct nf_conntrack_helper *cur; 659 struct nf_conntrack_tuple tuple; 660 bool tuple_set = false, found = false; 661 struct nfnl_cthelper *nlcth, *n; 662 int j = 0, ret; 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 675 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { 676 cur = &nlcth->helper; 677 j++; 678 679 if (helper_name && 680 strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) 681 continue; 682 683 if (tuple_set && 684 (tuple.src.l3num != cur->tuple.src.l3num || 685 tuple.dst.protonum != cur->tuple.dst.protonum)) 686 continue; 687 688 found = true; 689 nf_conntrack_helper_unregister(cur); 690 kfree(cur->expect_policy); 691 692 list_del(&nlcth->list); 693 kfree(nlcth); 694 } 695 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; 744 struct nfnl_cthelper *nlcth, *n; 745 746 nfnetlink_subsys_unregister(&nfnl_cthelper_subsys); 747 748 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { 749 cur = &nlcth->helper; 750 751 nf_conntrack_helper_unregister(cur); 752 kfree(cur->expect_policy); 753 kfree(nlcth); 754 } 755} 756 757module_init(nfnl_cthelper_init); 758module_exit(nfnl_cthelper_exit);