Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.13-rc5 841 lines 21 kB view raw
1/* 2 * (C) 2012-2013 by 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. 7 * 8 * This software has been sponsored by Sophos Astaro <http://www.sophos.com> 9 */ 10 11#include <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/netlink.h> 15#include <linux/netfilter.h> 16#include <linux/netfilter/nfnetlink.h> 17#include <linux/netfilter/nf_tables.h> 18#include <linux/netfilter/nf_tables_compat.h> 19#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter_ipv4/ip_tables.h> 21#include <linux/netfilter_ipv6/ip6_tables.h> 22#include <linux/netfilter_bridge/ebtables.h> 23#include <linux/netfilter_arp/arp_tables.h> 24#include <net/netfilter/nf_tables.h> 25 26struct nft_xt { 27 struct list_head head; 28 struct nft_expr_ops ops; 29 unsigned int refcnt; 30}; 31 32static void nft_xt_put(struct nft_xt *xt) 33{ 34 if (--xt->refcnt == 0) { 35 list_del(&xt->head); 36 kfree(xt); 37 } 38} 39 40static int nft_compat_chain_validate_dependency(const char *tablename, 41 const struct nft_chain *chain) 42{ 43 const struct nft_base_chain *basechain; 44 45 if (!tablename || 46 !nft_is_base_chain(chain)) 47 return 0; 48 49 basechain = nft_base_chain(chain); 50 if (strcmp(tablename, "nat") == 0 && 51 basechain->type->type != NFT_CHAIN_T_NAT) 52 return -EINVAL; 53 54 return 0; 55} 56 57union nft_entry { 58 struct ipt_entry e4; 59 struct ip6t_entry e6; 60 struct ebt_entry ebt; 61 struct arpt_entry arp; 62}; 63 64static inline void 65nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info) 66{ 67 par->target = xt; 68 par->targinfo = xt_info; 69 par->hotdrop = false; 70} 71 72static void nft_target_eval_xt(const struct nft_expr *expr, 73 struct nft_regs *regs, 74 const struct nft_pktinfo *pkt) 75{ 76 void *info = nft_expr_priv(expr); 77 struct xt_target *target = expr->ops->data; 78 struct sk_buff *skb = pkt->skb; 79 int ret; 80 81 nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); 82 83 ret = target->target(skb, &pkt->xt); 84 85 if (pkt->xt.hotdrop) 86 ret = NF_DROP; 87 88 switch (ret) { 89 case XT_CONTINUE: 90 regs->verdict.code = NFT_CONTINUE; 91 break; 92 default: 93 regs->verdict.code = ret; 94 break; 95 } 96} 97 98static void nft_target_eval_bridge(const struct nft_expr *expr, 99 struct nft_regs *regs, 100 const struct nft_pktinfo *pkt) 101{ 102 void *info = nft_expr_priv(expr); 103 struct xt_target *target = expr->ops->data; 104 struct sk_buff *skb = pkt->skb; 105 int ret; 106 107 nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); 108 109 ret = target->target(skb, &pkt->xt); 110 111 if (pkt->xt.hotdrop) 112 ret = NF_DROP; 113 114 switch (ret) { 115 case EBT_ACCEPT: 116 regs->verdict.code = NF_ACCEPT; 117 break; 118 case EBT_DROP: 119 regs->verdict.code = NF_DROP; 120 break; 121 case EBT_CONTINUE: 122 regs->verdict.code = NFT_CONTINUE; 123 break; 124 case EBT_RETURN: 125 regs->verdict.code = NFT_RETURN; 126 break; 127 default: 128 regs->verdict.code = ret; 129 break; 130 } 131} 132 133static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { 134 [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, 135 [NFTA_TARGET_REV] = { .type = NLA_U32 }, 136 [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, 137}; 138 139static void 140nft_target_set_tgchk_param(struct xt_tgchk_param *par, 141 const struct nft_ctx *ctx, 142 struct xt_target *target, void *info, 143 union nft_entry *entry, u16 proto, bool inv) 144{ 145 par->net = ctx->net; 146 par->table = ctx->table->name; 147 switch (ctx->afi->family) { 148 case AF_INET: 149 entry->e4.ip.proto = proto; 150 entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; 151 break; 152 case AF_INET6: 153 if (proto) 154 entry->e6.ipv6.flags |= IP6T_F_PROTO; 155 156 entry->e6.ipv6.proto = proto; 157 entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; 158 break; 159 case NFPROTO_BRIDGE: 160 entry->ebt.ethproto = (__force __be16)proto; 161 entry->ebt.invflags = inv ? EBT_IPROTO : 0; 162 break; 163 case NFPROTO_ARP: 164 break; 165 } 166 par->entryinfo = entry; 167 par->target = target; 168 par->targinfo = info; 169 if (nft_is_base_chain(ctx->chain)) { 170 const struct nft_base_chain *basechain = 171 nft_base_chain(ctx->chain); 172 const struct nf_hook_ops *ops = &basechain->ops[0]; 173 174 par->hook_mask = 1 << ops->hooknum; 175 } else { 176 par->hook_mask = 0; 177 } 178 par->family = ctx->afi->family; 179 par->nft_compat = true; 180} 181 182static void target_compat_from_user(struct xt_target *t, void *in, void *out) 183{ 184 int pad; 185 186 memcpy(out, in, t->targetsize); 187 pad = XT_ALIGN(t->targetsize) - t->targetsize; 188 if (pad > 0) 189 memset(out + t->targetsize, 0, pad); 190} 191 192static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = { 193 [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 }, 194 [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 }, 195}; 196 197static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv) 198{ 199 struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1]; 200 u32 flags; 201 int err; 202 203 err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr, 204 nft_rule_compat_policy, NULL); 205 if (err < 0) 206 return err; 207 208 if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS]) 209 return -EINVAL; 210 211 flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS])); 212 if (flags & ~NFT_RULE_COMPAT_F_MASK) 213 return -EINVAL; 214 if (flags & NFT_RULE_COMPAT_F_INV) 215 *inv = true; 216 217 *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO])); 218 return 0; 219} 220 221static int 222nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 223 const struct nlattr * const tb[]) 224{ 225 void *info = nft_expr_priv(expr); 226 struct xt_target *target = expr->ops->data; 227 struct xt_tgchk_param par; 228 size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); 229 u16 proto = 0; 230 bool inv = false; 231 union nft_entry e = {}; 232 int ret; 233 234 target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); 235 236 if (ctx->nla[NFTA_RULE_COMPAT]) { 237 ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); 238 if (ret < 0) 239 goto err; 240 } 241 242 nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); 243 244 ret = xt_check_target(&par, size, proto, inv); 245 if (ret < 0) 246 goto err; 247 248 /* The standard target cannot be used */ 249 if (target->target == NULL) { 250 ret = -EINVAL; 251 goto err; 252 } 253 254 return 0; 255err: 256 module_put(target->me); 257 return ret; 258} 259 260static void 261nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) 262{ 263 struct xt_target *target = expr->ops->data; 264 void *info = nft_expr_priv(expr); 265 struct xt_tgdtor_param par; 266 267 par.net = ctx->net; 268 par.target = target; 269 par.targinfo = info; 270 par.family = ctx->afi->family; 271 if (par.target->destroy != NULL) 272 par.target->destroy(&par); 273 274 nft_xt_put(container_of(expr->ops, struct nft_xt, ops)); 275 module_put(target->me); 276} 277 278static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) 279{ 280 const struct xt_target *target = expr->ops->data; 281 void *info = nft_expr_priv(expr); 282 283 if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) || 284 nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) || 285 nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(target->targetsize), info)) 286 goto nla_put_failure; 287 288 return 0; 289 290nla_put_failure: 291 return -1; 292} 293 294static int nft_target_validate(const struct nft_ctx *ctx, 295 const struct nft_expr *expr, 296 const struct nft_data **data) 297{ 298 struct xt_target *target = expr->ops->data; 299 unsigned int hook_mask = 0; 300 int ret; 301 302 if (nft_is_base_chain(ctx->chain)) { 303 const struct nft_base_chain *basechain = 304 nft_base_chain(ctx->chain); 305 const struct nf_hook_ops *ops = &basechain->ops[0]; 306 307 hook_mask = 1 << ops->hooknum; 308 if (!(hook_mask & target->hooks)) 309 return -EINVAL; 310 311 ret = nft_compat_chain_validate_dependency(target->table, 312 ctx->chain); 313 if (ret < 0) 314 return ret; 315 } 316 return 0; 317} 318 319static void nft_match_eval(const struct nft_expr *expr, 320 struct nft_regs *regs, 321 const struct nft_pktinfo *pkt) 322{ 323 void *info = nft_expr_priv(expr); 324 struct xt_match *match = expr->ops->data; 325 struct sk_buff *skb = pkt->skb; 326 bool ret; 327 328 nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info); 329 330 ret = match->match(skb, (struct xt_action_param *)&pkt->xt); 331 332 if (pkt->xt.hotdrop) { 333 regs->verdict.code = NF_DROP; 334 return; 335 } 336 337 switch (ret ? 1 : 0) { 338 case 1: 339 regs->verdict.code = NFT_CONTINUE; 340 break; 341 case 0: 342 regs->verdict.code = NFT_BREAK; 343 break; 344 } 345} 346 347static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { 348 [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, 349 [NFTA_MATCH_REV] = { .type = NLA_U32 }, 350 [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, 351}; 352 353/* struct xt_mtchk_param and xt_tgchk_param look very similar */ 354static void 355nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, 356 struct xt_match *match, void *info, 357 union nft_entry *entry, u16 proto, bool inv) 358{ 359 par->net = ctx->net; 360 par->table = ctx->table->name; 361 switch (ctx->afi->family) { 362 case AF_INET: 363 entry->e4.ip.proto = proto; 364 entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; 365 break; 366 case AF_INET6: 367 if (proto) 368 entry->e6.ipv6.flags |= IP6T_F_PROTO; 369 370 entry->e6.ipv6.proto = proto; 371 entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; 372 break; 373 case NFPROTO_BRIDGE: 374 entry->ebt.ethproto = (__force __be16)proto; 375 entry->ebt.invflags = inv ? EBT_IPROTO : 0; 376 break; 377 case NFPROTO_ARP: 378 break; 379 } 380 par->entryinfo = entry; 381 par->match = match; 382 par->matchinfo = info; 383 if (nft_is_base_chain(ctx->chain)) { 384 const struct nft_base_chain *basechain = 385 nft_base_chain(ctx->chain); 386 const struct nf_hook_ops *ops = &basechain->ops[0]; 387 388 par->hook_mask = 1 << ops->hooknum; 389 } else { 390 par->hook_mask = 0; 391 } 392 par->family = ctx->afi->family; 393 par->nft_compat = true; 394} 395 396static void match_compat_from_user(struct xt_match *m, void *in, void *out) 397{ 398 int pad; 399 400 memcpy(out, in, m->matchsize); 401 pad = XT_ALIGN(m->matchsize) - m->matchsize; 402 if (pad > 0) 403 memset(out + m->matchsize, 0, pad); 404} 405 406static int 407nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 408 const struct nlattr * const tb[]) 409{ 410 void *info = nft_expr_priv(expr); 411 struct xt_match *match = expr->ops->data; 412 struct xt_mtchk_param par; 413 size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); 414 u16 proto = 0; 415 bool inv = false; 416 union nft_entry e = {}; 417 int ret; 418 419 match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); 420 421 if (ctx->nla[NFTA_RULE_COMPAT]) { 422 ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); 423 if (ret < 0) 424 goto err; 425 } 426 427 nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv); 428 429 ret = xt_check_match(&par, size, proto, inv); 430 if (ret < 0) 431 goto err; 432 433 return 0; 434err: 435 module_put(match->me); 436 return ret; 437} 438 439static void 440nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) 441{ 442 struct xt_match *match = expr->ops->data; 443 void *info = nft_expr_priv(expr); 444 struct xt_mtdtor_param par; 445 446 par.net = ctx->net; 447 par.match = match; 448 par.matchinfo = info; 449 par.family = ctx->afi->family; 450 if (par.match->destroy != NULL) 451 par.match->destroy(&par); 452 453 nft_xt_put(container_of(expr->ops, struct nft_xt, ops)); 454 module_put(match->me); 455} 456 457static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr) 458{ 459 void *info = nft_expr_priv(expr); 460 struct xt_match *match = expr->ops->data; 461 462 if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || 463 nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) || 464 nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(match->matchsize), info)) 465 goto nla_put_failure; 466 467 return 0; 468 469nla_put_failure: 470 return -1; 471} 472 473static int nft_match_validate(const struct nft_ctx *ctx, 474 const struct nft_expr *expr, 475 const struct nft_data **data) 476{ 477 struct xt_match *match = expr->ops->data; 478 unsigned int hook_mask = 0; 479 int ret; 480 481 if (nft_is_base_chain(ctx->chain)) { 482 const struct nft_base_chain *basechain = 483 nft_base_chain(ctx->chain); 484 const struct nf_hook_ops *ops = &basechain->ops[0]; 485 486 hook_mask = 1 << ops->hooknum; 487 if (!(hook_mask & match->hooks)) 488 return -EINVAL; 489 490 ret = nft_compat_chain_validate_dependency(match->table, 491 ctx->chain); 492 if (ret < 0) 493 return ret; 494 } 495 return 0; 496} 497 498static int 499nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, 500 int event, u16 family, const char *name, 501 int rev, int target) 502{ 503 struct nlmsghdr *nlh; 504 struct nfgenmsg *nfmsg; 505 unsigned int flags = portid ? NLM_F_MULTI : 0; 506 507 event = nfnl_msg_type(NFNL_SUBSYS_NFT_COMPAT, event); 508 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 509 if (nlh == NULL) 510 goto nlmsg_failure; 511 512 nfmsg = nlmsg_data(nlh); 513 nfmsg->nfgen_family = family; 514 nfmsg->version = NFNETLINK_V0; 515 nfmsg->res_id = 0; 516 517 if (nla_put_string(skb, NFTA_COMPAT_NAME, name) || 518 nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) || 519 nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target))) 520 goto nla_put_failure; 521 522 nlmsg_end(skb, nlh); 523 return skb->len; 524 525nlmsg_failure: 526nla_put_failure: 527 nlmsg_cancel(skb, nlh); 528 return -1; 529} 530 531static int nfnl_compat_get(struct net *net, struct sock *nfnl, 532 struct sk_buff *skb, const struct nlmsghdr *nlh, 533 const struct nlattr * const tb[], 534 struct netlink_ext_ack *extack) 535{ 536 int ret = 0, target; 537 struct nfgenmsg *nfmsg; 538 const char *fmt; 539 const char *name; 540 u32 rev; 541 struct sk_buff *skb2; 542 543 if (tb[NFTA_COMPAT_NAME] == NULL || 544 tb[NFTA_COMPAT_REV] == NULL || 545 tb[NFTA_COMPAT_TYPE] == NULL) 546 return -EINVAL; 547 548 name = nla_data(tb[NFTA_COMPAT_NAME]); 549 rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); 550 target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); 551 552 nfmsg = nlmsg_data(nlh); 553 554 switch(nfmsg->nfgen_family) { 555 case AF_INET: 556 fmt = "ipt_%s"; 557 break; 558 case AF_INET6: 559 fmt = "ip6t_%s"; 560 break; 561 case NFPROTO_BRIDGE: 562 fmt = "ebt_%s"; 563 break; 564 case NFPROTO_ARP: 565 fmt = "arpt_%s"; 566 break; 567 default: 568 pr_err("nft_compat: unsupported protocol %d\n", 569 nfmsg->nfgen_family); 570 return -EINVAL; 571 } 572 573 try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name, 574 rev, target, &ret), 575 fmt, name); 576 577 if (ret < 0) 578 return ret; 579 580 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 581 if (skb2 == NULL) 582 return -ENOMEM; 583 584 /* include the best revision for this extension in the message */ 585 if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid, 586 nlh->nlmsg_seq, 587 NFNL_MSG_TYPE(nlh->nlmsg_type), 588 NFNL_MSG_COMPAT_GET, 589 nfmsg->nfgen_family, 590 name, ret, target) <= 0) { 591 kfree_skb(skb2); 592 return -ENOSPC; 593 } 594 595 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, 596 MSG_DONTWAIT); 597 if (ret > 0) 598 ret = 0; 599 600 return ret == -EAGAIN ? -ENOBUFS : ret; 601} 602 603static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = { 604 [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING, 605 .len = NFT_COMPAT_NAME_MAX-1 }, 606 [NFTA_COMPAT_REV] = { .type = NLA_U32 }, 607 [NFTA_COMPAT_TYPE] = { .type = NLA_U32 }, 608}; 609 610static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = { 611 [NFNL_MSG_COMPAT_GET] = { .call = nfnl_compat_get, 612 .attr_count = NFTA_COMPAT_MAX, 613 .policy = nfnl_compat_policy_get }, 614}; 615 616static const struct nfnetlink_subsystem nfnl_compat_subsys = { 617 .name = "nft-compat", 618 .subsys_id = NFNL_SUBSYS_NFT_COMPAT, 619 .cb_count = NFNL_MSG_COMPAT_MAX, 620 .cb = nfnl_nft_compat_cb, 621}; 622 623static LIST_HEAD(nft_match_list); 624 625static struct nft_expr_type nft_match_type; 626 627static bool nft_match_cmp(const struct xt_match *match, 628 const char *name, u32 rev, u32 family) 629{ 630 return strcmp(match->name, name) == 0 && match->revision == rev && 631 (match->family == NFPROTO_UNSPEC || match->family == family); 632} 633 634static const struct nft_expr_ops * 635nft_match_select_ops(const struct nft_ctx *ctx, 636 const struct nlattr * const tb[]) 637{ 638 struct nft_xt *nft_match; 639 struct xt_match *match; 640 char *mt_name; 641 u32 rev, family; 642 int err; 643 644 if (tb[NFTA_MATCH_NAME] == NULL || 645 tb[NFTA_MATCH_REV] == NULL || 646 tb[NFTA_MATCH_INFO] == NULL) 647 return ERR_PTR(-EINVAL); 648 649 mt_name = nla_data(tb[NFTA_MATCH_NAME]); 650 rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); 651 family = ctx->afi->family; 652 653 /* Re-use the existing match if it's already loaded. */ 654 list_for_each_entry(nft_match, &nft_match_list, head) { 655 struct xt_match *match = nft_match->ops.data; 656 657 if (nft_match_cmp(match, mt_name, rev, family)) { 658 if (!try_module_get(match->me)) 659 return ERR_PTR(-ENOENT); 660 661 nft_match->refcnt++; 662 return &nft_match->ops; 663 } 664 } 665 666 match = xt_request_find_match(family, mt_name, rev); 667 if (IS_ERR(match)) 668 return ERR_PTR(-ENOENT); 669 670 if (match->matchsize > nla_len(tb[NFTA_MATCH_INFO])) { 671 err = -EINVAL; 672 goto err; 673 } 674 675 /* This is the first time we use this match, allocate operations */ 676 nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); 677 if (nft_match == NULL) { 678 err = -ENOMEM; 679 goto err; 680 } 681 682 nft_match->refcnt = 1; 683 nft_match->ops.type = &nft_match_type; 684 nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize)); 685 nft_match->ops.eval = nft_match_eval; 686 nft_match->ops.init = nft_match_init; 687 nft_match->ops.destroy = nft_match_destroy; 688 nft_match->ops.dump = nft_match_dump; 689 nft_match->ops.validate = nft_match_validate; 690 nft_match->ops.data = match; 691 692 list_add(&nft_match->head, &nft_match_list); 693 694 return &nft_match->ops; 695err: 696 module_put(match->me); 697 return ERR_PTR(err); 698} 699 700static struct nft_expr_type nft_match_type __read_mostly = { 701 .name = "match", 702 .select_ops = nft_match_select_ops, 703 .policy = nft_match_policy, 704 .maxattr = NFTA_MATCH_MAX, 705 .owner = THIS_MODULE, 706}; 707 708static LIST_HEAD(nft_target_list); 709 710static struct nft_expr_type nft_target_type; 711 712static bool nft_target_cmp(const struct xt_target *tg, 713 const char *name, u32 rev, u32 family) 714{ 715 return strcmp(tg->name, name) == 0 && tg->revision == rev && 716 (tg->family == NFPROTO_UNSPEC || tg->family == family); 717} 718 719static const struct nft_expr_ops * 720nft_target_select_ops(const struct nft_ctx *ctx, 721 const struct nlattr * const tb[]) 722{ 723 struct nft_xt *nft_target; 724 struct xt_target *target; 725 char *tg_name; 726 u32 rev, family; 727 int err; 728 729 if (tb[NFTA_TARGET_NAME] == NULL || 730 tb[NFTA_TARGET_REV] == NULL || 731 tb[NFTA_TARGET_INFO] == NULL) 732 return ERR_PTR(-EINVAL); 733 734 tg_name = nla_data(tb[NFTA_TARGET_NAME]); 735 rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV])); 736 family = ctx->afi->family; 737 738 /* Re-use the existing target if it's already loaded. */ 739 list_for_each_entry(nft_target, &nft_target_list, head) { 740 struct xt_target *target = nft_target->ops.data; 741 742 if (nft_target_cmp(target, tg_name, rev, family)) { 743 if (!try_module_get(target->me)) 744 return ERR_PTR(-ENOENT); 745 746 nft_target->refcnt++; 747 return &nft_target->ops; 748 } 749 } 750 751 target = xt_request_find_target(family, tg_name, rev); 752 if (IS_ERR(target)) 753 return ERR_PTR(-ENOENT); 754 755 if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) { 756 err = -EINVAL; 757 goto err; 758 } 759 760 /* This is the first time we use this target, allocate operations */ 761 nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); 762 if (nft_target == NULL) { 763 err = -ENOMEM; 764 goto err; 765 } 766 767 nft_target->refcnt = 1; 768 nft_target->ops.type = &nft_target_type; 769 nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); 770 nft_target->ops.init = nft_target_init; 771 nft_target->ops.destroy = nft_target_destroy; 772 nft_target->ops.dump = nft_target_dump; 773 nft_target->ops.validate = nft_target_validate; 774 nft_target->ops.data = target; 775 776 if (family == NFPROTO_BRIDGE) 777 nft_target->ops.eval = nft_target_eval_bridge; 778 else 779 nft_target->ops.eval = nft_target_eval_xt; 780 781 list_add(&nft_target->head, &nft_target_list); 782 783 return &nft_target->ops; 784err: 785 module_put(target->me); 786 return ERR_PTR(err); 787} 788 789static struct nft_expr_type nft_target_type __read_mostly = { 790 .name = "target", 791 .select_ops = nft_target_select_ops, 792 .policy = nft_target_policy, 793 .maxattr = NFTA_TARGET_MAX, 794 .owner = THIS_MODULE, 795}; 796 797static int __init nft_compat_module_init(void) 798{ 799 int ret; 800 801 ret = nft_register_expr(&nft_match_type); 802 if (ret < 0) 803 return ret; 804 805 ret = nft_register_expr(&nft_target_type); 806 if (ret < 0) 807 goto err_match; 808 809 ret = nfnetlink_subsys_register(&nfnl_compat_subsys); 810 if (ret < 0) { 811 pr_err("nft_compat: cannot register with nfnetlink.\n"); 812 goto err_target; 813 } 814 815 pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n"); 816 817 return ret; 818 819err_target: 820 nft_unregister_expr(&nft_target_type); 821err_match: 822 nft_unregister_expr(&nft_match_type); 823 return ret; 824} 825 826static void __exit nft_compat_module_exit(void) 827{ 828 nfnetlink_subsys_unregister(&nfnl_compat_subsys); 829 nft_unregister_expr(&nft_target_type); 830 nft_unregister_expr(&nft_match_type); 831} 832 833MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); 834 835module_init(nft_compat_module_init); 836module_exit(nft_compat_module_exit); 837 838MODULE_LICENSE("GPL"); 839MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 840MODULE_ALIAS_NFT_EXPR("match"); 841MODULE_ALIAS_NFT_EXPR("target");