aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2014-01-03 07:16:15 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2014-01-07 17:55:46 -0500
commit115a60b173af0170e0db26b9a3fd6a911fba70a3 (patch)
tree83fac6bf34087f357d9fe30ff916dfa2448a5d40
parentc9484874e7596d6c890e4130336f5379f6a59c5f (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.h9
-rw-r--r--net/bridge/netfilter/nf_tables_bridge.c1
-rw-r--r--net/ipv4/netfilter/nf_tables_arp.c1
-rw-r--r--net/ipv4/netfilter/nf_tables_ipv4.c1
-rw-r--r--net/ipv6/netfilter/nf_tables_ipv6.c1
-rw-r--r--net/netfilter/nf_tables_api.c49
-rw-r--r--net/netfilter/nft_compat.c8
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 */
434struct nft_base_chain { 436struct 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 */
481struct nft_af_info { 485struct 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
310static int nf_tables_table_enable(struct nft_table *table) 310static 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
339static int nf_tables_table_disable(struct nft_table *table) 340static 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)