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