diff options
author | Patrick McHardy <kaber@trash.net> | 2014-01-03 07:16:15 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-01-07 17:55:46 -0500 |
commit | 115a60b173af0170e0db26b9a3fd6a911fba70a3 (patch) | |
tree | 83fac6bf34087f357d9fe30ff916dfa2448a5d40 | |
parent | c9484874e7596d6c890e4130336f5379f6a59c5f (diff) |
netfilter: nf_tables: add support for multi family tables
Add support to register chains to multiple hooks for different address
families for mixed IPv4/IPv6 tables.
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | include/net/netfilter/nf_tables.h | 9 | ||||
-rw-r--r-- | net/bridge/netfilter/nf_tables_bridge.c | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_tables_arp.c | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_tables_ipv4.c | 1 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_tables_ipv6.c | 1 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 49 | ||||
-rw-r--r-- | net/netfilter/nft_compat.c | 8 |
7 files changed, 45 insertions, 25 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index c9e63167f9a2..f066f252e5e5 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -422,6 +422,8 @@ struct nft_stats { | |||
422 | u64 pkts; | 422 | u64 pkts; |
423 | }; | 423 | }; |
424 | 424 | ||
425 | #define NFT_HOOK_OPS_MAX 2 | ||
426 | |||
425 | /** | 427 | /** |
426 | * struct nft_base_chain - nf_tables base chain | 428 | * struct nft_base_chain - nf_tables base chain |
427 | * | 429 | * |
@@ -432,7 +434,7 @@ struct nft_stats { | |||
432 | * @chain: the chain | 434 | * @chain: the chain |
433 | */ | 435 | */ |
434 | struct nft_base_chain { | 436 | struct nft_base_chain { |
435 | struct nf_hook_ops ops; | 437 | struct nf_hook_ops ops[NFT_HOOK_OPS_MAX]; |
436 | enum nft_chain_type type; | 438 | enum nft_chain_type type; |
437 | u8 policy; | 439 | u8 policy; |
438 | struct nft_stats __percpu *stats; | 440 | struct nft_stats __percpu *stats; |
@@ -476,6 +478,8 @@ struct nft_table { | |||
476 | * @nhooks: number of hooks in this family | 478 | * @nhooks: number of hooks in this family |
477 | * @owner: module owner | 479 | * @owner: module owner |
478 | * @tables: used internally | 480 | * @tables: used internally |
481 | * @nops: number of hook ops in this family | ||
482 | * @hook_ops_init: initialization function for chain hook ops | ||
479 | * @hooks: hookfn overrides for packet validation | 483 | * @hooks: hookfn overrides for packet validation |
480 | */ | 484 | */ |
481 | struct nft_af_info { | 485 | struct nft_af_info { |
@@ -484,6 +488,9 @@ struct nft_af_info { | |||
484 | unsigned int nhooks; | 488 | unsigned int nhooks; |
485 | struct module *owner; | 489 | struct module *owner; |
486 | struct list_head tables; | 490 | struct list_head tables; |
491 | unsigned int nops; | ||
492 | void (*hook_ops_init)(struct nf_hook_ops *, | ||
493 | unsigned int); | ||
487 | nf_hookfn *hooks[NF_MAX_HOOKS]; | 494 | nf_hookfn *hooks[NF_MAX_HOOKS]; |
488 | }; | 495 | }; |
489 | 496 | ||
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c index c5fdd9a693be..003c1e9a8b0c 100644 --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c | |||
@@ -32,6 +32,7 @@ static struct nft_af_info nft_af_bridge __read_mostly = { | |||
32 | .family = NFPROTO_BRIDGE, | 32 | .family = NFPROTO_BRIDGE, |
33 | .nhooks = NF_BR_NUMHOOKS, | 33 | .nhooks = NF_BR_NUMHOOKS, |
34 | .owner = THIS_MODULE, | 34 | .owner = THIS_MODULE, |
35 | .nops = 1, | ||
35 | .hooks = { | 36 | .hooks = { |
36 | [NF_BR_LOCAL_IN] = nft_do_chain_bridge, | 37 | [NF_BR_LOCAL_IN] = nft_do_chain_bridge, |
37 | [NF_BR_FORWARD] = nft_do_chain_bridge, | 38 | [NF_BR_FORWARD] = nft_do_chain_bridge, |
diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c index 31bb778cebb8..36d27fc7e859 100644 --- a/net/ipv4/netfilter/nf_tables_arp.c +++ b/net/ipv4/netfilter/nf_tables_arp.c | |||
@@ -32,6 +32,7 @@ static struct nft_af_info nft_af_arp __read_mostly = { | |||
32 | .family = NFPROTO_ARP, | 32 | .family = NFPROTO_ARP, |
33 | .nhooks = NF_ARP_NUMHOOKS, | 33 | .nhooks = NF_ARP_NUMHOOKS, |
34 | .owner = THIS_MODULE, | 34 | .owner = THIS_MODULE, |
35 | .nops = 1, | ||
35 | .hooks = { | 36 | .hooks = { |
36 | [NF_ARP_IN] = nft_do_chain_arp, | 37 | [NF_ARP_IN] = nft_do_chain_arp, |
37 | [NF_ARP_OUT] = nft_do_chain_arp, | 38 | [NF_ARP_OUT] = nft_do_chain_arp, |
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c index ed7e15a93410..177c3bceb7ca 100644 --- a/net/ipv4/netfilter/nf_tables_ipv4.c +++ b/net/ipv4/netfilter/nf_tables_ipv4.c | |||
@@ -52,6 +52,7 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = { | |||
52 | .family = NFPROTO_IPV4, | 52 | .family = NFPROTO_IPV4, |
53 | .nhooks = NF_INET_NUMHOOKS, | 53 | .nhooks = NF_INET_NUMHOOKS, |
54 | .owner = THIS_MODULE, | 54 | .owner = THIS_MODULE, |
55 | .nops = 1, | ||
55 | .hooks = { | 56 | .hooks = { |
56 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, | 57 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, |
57 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, | 58 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, |
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c index 54a2bcdc8a17..642280e44b65 100644 --- a/net/ipv6/netfilter/nf_tables_ipv6.c +++ b/net/ipv6/netfilter/nf_tables_ipv6.c | |||
@@ -51,6 +51,7 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = { | |||
51 | .family = NFPROTO_IPV6, | 51 | .family = NFPROTO_IPV6, |
52 | .nhooks = NF_INET_NUMHOOKS, | 52 | .nhooks = NF_INET_NUMHOOKS, |
53 | .owner = THIS_MODULE, | 53 | .owner = THIS_MODULE, |
54 | .nops = 1, | ||
54 | .hooks = { | 55 | .hooks = { |
55 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, | 56 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, |
56 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | 57 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index d568626bc0f9..572d88dd3e5f 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -307,7 +307,8 @@ err: | |||
307 | return err; | 307 | return err; |
308 | } | 308 | } |
309 | 309 | ||
310 | static int nf_tables_table_enable(struct nft_table *table) | 310 | static int nf_tables_table_enable(const struct nft_af_info *afi, |
311 | struct nft_table *table) | ||
311 | { | 312 | { |
312 | struct nft_chain *chain; | 313 | struct nft_chain *chain; |
313 | int err, i = 0; | 314 | int err, i = 0; |
@@ -316,7 +317,7 @@ static int nf_tables_table_enable(struct nft_table *table) | |||
316 | if (!(chain->flags & NFT_BASE_CHAIN)) | 317 | if (!(chain->flags & NFT_BASE_CHAIN)) |
317 | continue; | 318 | continue; |
318 | 319 | ||
319 | err = nf_register_hook(&nft_base_chain(chain)->ops); | 320 | err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops); |
320 | if (err < 0) | 321 | if (err < 0) |
321 | goto err; | 322 | goto err; |
322 | 323 | ||
@@ -331,18 +332,20 @@ err: | |||
331 | if (i-- <= 0) | 332 | if (i-- <= 0) |
332 | break; | 333 | break; |
333 | 334 | ||
334 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 335 | nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops); |
335 | } | 336 | } |
336 | return err; | 337 | return err; |
337 | } | 338 | } |
338 | 339 | ||
339 | static int nf_tables_table_disable(struct nft_table *table) | 340 | static int nf_tables_table_disable(const struct nft_af_info *afi, |
341 | struct nft_table *table) | ||
340 | { | 342 | { |
341 | struct nft_chain *chain; | 343 | struct nft_chain *chain; |
342 | 344 | ||
343 | list_for_each_entry(chain, &table->chains, list) { | 345 | list_for_each_entry(chain, &table->chains, list) { |
344 | if (chain->flags & NFT_BASE_CHAIN) | 346 | if (chain->flags & NFT_BASE_CHAIN) |
345 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 347 | nf_unregister_hooks(nft_base_chain(chain)->ops, |
348 | afi->nops); | ||
346 | } | 349 | } |
347 | 350 | ||
348 | return 0; | 351 | return 0; |
@@ -365,12 +368,12 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb, | |||
365 | 368 | ||
366 | if ((flags & NFT_TABLE_F_DORMANT) && | 369 | if ((flags & NFT_TABLE_F_DORMANT) && |
367 | !(table->flags & NFT_TABLE_F_DORMANT)) { | 370 | !(table->flags & NFT_TABLE_F_DORMANT)) { |
368 | ret = nf_tables_table_disable(table); | 371 | ret = nf_tables_table_disable(afi, table); |
369 | if (ret >= 0) | 372 | if (ret >= 0) |
370 | table->flags |= NFT_TABLE_F_DORMANT; | 373 | table->flags |= NFT_TABLE_F_DORMANT; |
371 | } else if (!(flags & NFT_TABLE_F_DORMANT) && | 374 | } else if (!(flags & NFT_TABLE_F_DORMANT) && |
372 | table->flags & NFT_TABLE_F_DORMANT) { | 375 | table->flags & NFT_TABLE_F_DORMANT) { |
373 | ret = nf_tables_table_enable(table); | 376 | ret = nf_tables_table_enable(afi, table); |
374 | if (ret >= 0) | 377 | if (ret >= 0) |
375 | table->flags &= ~NFT_TABLE_F_DORMANT; | 378 | table->flags &= ~NFT_TABLE_F_DORMANT; |
376 | } | 379 | } |
@@ -598,7 +601,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
598 | 601 | ||
599 | if (chain->flags & NFT_BASE_CHAIN) { | 602 | if (chain->flags & NFT_BASE_CHAIN) { |
600 | const struct nft_base_chain *basechain = nft_base_chain(chain); | 603 | const struct nft_base_chain *basechain = nft_base_chain(chain); |
601 | const struct nf_hook_ops *ops = &basechain->ops; | 604 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
602 | struct nlattr *nest; | 605 | struct nlattr *nest; |
603 | 606 | ||
604 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); | 607 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); |
@@ -832,6 +835,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
832 | struct net *net = sock_net(skb->sk); | 835 | struct net *net = sock_net(skb->sk); |
833 | int family = nfmsg->nfgen_family; | 836 | int family = nfmsg->nfgen_family; |
834 | u64 handle = 0; | 837 | u64 handle = 0; |
838 | unsigned int i; | ||
835 | int err; | 839 | int err; |
836 | bool create; | 840 | bool create; |
837 | 841 | ||
@@ -904,7 +908,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
904 | if (nla[NFTA_CHAIN_HOOK]) { | 908 | if (nla[NFTA_CHAIN_HOOK]) { |
905 | struct nf_hook_ops *ops; | 909 | struct nf_hook_ops *ops; |
906 | nf_hookfn *hookfn; | 910 | nf_hookfn *hookfn; |
907 | u32 hooknum; | 911 | u32 hooknum, priority; |
908 | int type = NFT_CHAIN_T_DEFAULT; | 912 | int type = NFT_CHAIN_T_DEFAULT; |
909 | 913 | ||
910 | if (nla[NFTA_CHAIN_TYPE]) { | 914 | if (nla[NFTA_CHAIN_TYPE]) { |
@@ -926,6 +930,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
926 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | 930 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); |
927 | if (hooknum >= afi->nhooks) | 931 | if (hooknum >= afi->nhooks) |
928 | return -EINVAL; | 932 | return -EINVAL; |
933 | priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | ||
929 | 934 | ||
930 | if (!(chain_type[family][type]->hook_mask & (1 << hooknum))) | 935 | if (!(chain_type[family][type]->hook_mask & (1 << hooknum))) |
931 | return -EOPNOTSUPP; | 936 | return -EOPNOTSUPP; |
@@ -938,15 +943,19 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
938 | basechain->type = type; | 943 | basechain->type = type; |
939 | chain = &basechain->chain; | 944 | chain = &basechain->chain; |
940 | 945 | ||
941 | ops = &basechain->ops; | 946 | for (i = 0; i < afi->nops; i++) { |
942 | ops->pf = family; | 947 | ops = &basechain->ops[i]; |
943 | ops->owner = afi->owner; | 948 | ops->pf = family; |
944 | ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | 949 | ops->owner = afi->owner; |
945 | ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | 950 | ops->hooknum = hooknum; |
946 | ops->priv = chain; | 951 | ops->priority = priority; |
947 | ops->hook = afi->hooks[ops->hooknum]; | 952 | ops->priv = chain; |
948 | if (hookfn) | 953 | ops->hook = afi->hooks[ops->hooknum]; |
949 | ops->hook = hookfn; | 954 | if (hookfn) |
955 | ops->hook = hookfn; | ||
956 | if (afi->hook_ops_init) | ||
957 | afi->hook_ops_init(ops, i); | ||
958 | } | ||
950 | 959 | ||
951 | chain->flags |= NFT_BASE_CHAIN; | 960 | chain->flags |= NFT_BASE_CHAIN; |
952 | 961 | ||
@@ -993,7 +1002,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
993 | 1002 | ||
994 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 1003 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
995 | chain->flags & NFT_BASE_CHAIN) { | 1004 | chain->flags & NFT_BASE_CHAIN) { |
996 | err = nf_register_hook(&nft_base_chain(chain)->ops); | 1005 | err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops); |
997 | if (err < 0) { | 1006 | if (err < 0) { |
998 | free_percpu(basechain->stats); | 1007 | free_percpu(basechain->stats); |
999 | kfree(basechain); | 1008 | kfree(basechain); |
@@ -1052,7 +1061,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
1052 | 1061 | ||
1053 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 1062 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
1054 | chain->flags & NFT_BASE_CHAIN) | 1063 | chain->flags & NFT_BASE_CHAIN) |
1055 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 1064 | nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops); |
1056 | 1065 | ||
1057 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, | 1066 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, |
1058 | family); | 1067 | family); |
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index da0c1f4ada12..82cb8236f8a1 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
@@ -92,7 +92,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, | |||
92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
93 | const struct nft_base_chain *basechain = | 93 | const struct nft_base_chain *basechain = |
94 | nft_base_chain(ctx->chain); | 94 | nft_base_chain(ctx->chain); |
95 | const struct nf_hook_ops *ops = &basechain->ops; | 95 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
96 | 96 | ||
97 | par->hook_mask = 1 << ops->hooknum; | 97 | par->hook_mask = 1 << ops->hooknum; |
98 | } | 98 | } |
@@ -253,7 +253,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
254 | const struct nft_base_chain *basechain = | 254 | const struct nft_base_chain *basechain = |
255 | nft_base_chain(ctx->chain); | 255 | nft_base_chain(ctx->chain); |
256 | const struct nf_hook_ops *ops = &basechain->ops; | 256 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
257 | 257 | ||
258 | hook_mask = 1 << ops->hooknum; | 258 | hook_mask = 1 << ops->hooknum; |
259 | if (hook_mask & target->hooks) | 259 | if (hook_mask & target->hooks) |
@@ -323,7 +323,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, | |||
323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
324 | const struct nft_base_chain *basechain = | 324 | const struct nft_base_chain *basechain = |
325 | nft_base_chain(ctx->chain); | 325 | nft_base_chain(ctx->chain); |
326 | const struct nf_hook_ops *ops = &basechain->ops; | 326 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
327 | 327 | ||
328 | par->hook_mask = 1 << ops->hooknum; | 328 | par->hook_mask = 1 << ops->hooknum; |
329 | } | 329 | } |
@@ -449,7 +449,7 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
450 | const struct nft_base_chain *basechain = | 450 | const struct nft_base_chain *basechain = |
451 | nft_base_chain(ctx->chain); | 451 | nft_base_chain(ctx->chain); |
452 | const struct nf_hook_ops *ops = &basechain->ops; | 452 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
453 | 453 | ||
454 | hook_mask = 1 << ops->hooknum; | 454 | hook_mask = 1 << ops->hooknum; |
455 | if (hook_mask & match->hooks) | 455 | if (hook_mask & match->hooks) |