Commit 115a60b173af0170e0db26b9a3fd6a911fba70a3
Committed by
Pablo Neira Ayuso
1 parent
c9484874e7
Exists in
master
and in
16 other branches
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>
Showing 7 changed files with 45 additions and 25 deletions Side-by-side Diff
include/net/netfilter/nf_tables.h
... | ... | @@ -422,6 +422,8 @@ |
422 | 422 | u64 pkts; |
423 | 423 | }; |
424 | 424 | |
425 | +#define NFT_HOOK_OPS_MAX 2 | |
426 | + | |
425 | 427 | /** |
426 | 428 | * struct nft_base_chain - nf_tables base chain |
427 | 429 | * |
... | ... | @@ -432,7 +434,7 @@ |
432 | 434 | * @chain: the chain |
433 | 435 | */ |
434 | 436 | struct nft_base_chain { |
435 | - struct nf_hook_ops ops; | |
437 | + struct nf_hook_ops ops[NFT_HOOK_OPS_MAX]; | |
436 | 438 | enum nft_chain_type type; |
437 | 439 | u8 policy; |
438 | 440 | struct nft_stats __percpu *stats; |
... | ... | @@ -476,6 +478,8 @@ |
476 | 478 | * @nhooks: number of hooks in this family |
477 | 479 | * @owner: module owner |
478 | 480 | * @tables: used internally |
481 | + * @nops: number of hook ops in this family | |
482 | + * @hook_ops_init: initialization function for chain hook ops | |
479 | 483 | * @hooks: hookfn overrides for packet validation |
480 | 484 | */ |
481 | 485 | struct nft_af_info { |
... | ... | @@ -484,6 +488,9 @@ |
484 | 488 | unsigned int nhooks; |
485 | 489 | struct module *owner; |
486 | 490 | struct list_head tables; |
491 | + unsigned int nops; | |
492 | + void (*hook_ops_init)(struct nf_hook_ops *, | |
493 | + unsigned int); | |
487 | 494 | nf_hookfn *hooks[NF_MAX_HOOKS]; |
488 | 495 | }; |
489 | 496 |
net/bridge/netfilter/nf_tables_bridge.c
net/ipv4/netfilter/nf_tables_arp.c
net/ipv4/netfilter/nf_tables_ipv4.c
net/ipv6/netfilter/nf_tables_ipv6.c
net/netfilter/nf_tables_api.c
... | ... | @@ -307,7 +307,8 @@ |
307 | 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 | 313 | struct nft_chain *chain; |
313 | 314 | int err, i = 0; |
... | ... | @@ -316,7 +317,7 @@ |
316 | 317 | if (!(chain->flags & NFT_BASE_CHAIN)) |
317 | 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 | 321 | if (err < 0) |
321 | 322 | goto err; |
322 | 323 | |
323 | 324 | |
324 | 325 | |
... | ... | @@ -331,18 +332,20 @@ |
331 | 332 | if (i-- <= 0) |
332 | 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 | 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 | 343 | struct nft_chain *chain; |
342 | 344 | |
343 | 345 | list_for_each_entry(chain, &table->chains, list) { |
344 | 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 | 351 | return 0; |
349 | 352 | |
... | ... | @@ -365,12 +368,12 @@ |
365 | 368 | |
366 | 369 | if ((flags & NFT_TABLE_F_DORMANT) && |
367 | 370 | !(table->flags & NFT_TABLE_F_DORMANT)) { |
368 | - ret = nf_tables_table_disable(table); | |
371 | + ret = nf_tables_table_disable(afi, table); | |
369 | 372 | if (ret >= 0) |
370 | 373 | table->flags |= NFT_TABLE_F_DORMANT; |
371 | 374 | } else if (!(flags & NFT_TABLE_F_DORMANT) && |
372 | 375 | table->flags & NFT_TABLE_F_DORMANT) { |
373 | - ret = nf_tables_table_enable(table); | |
376 | + ret = nf_tables_table_enable(afi, table); | |
374 | 377 | if (ret >= 0) |
375 | 378 | table->flags &= ~NFT_TABLE_F_DORMANT; |
376 | 379 | } |
... | ... | @@ -598,7 +601,7 @@ |
598 | 601 | |
599 | 602 | if (chain->flags & NFT_BASE_CHAIN) { |
600 | 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 | 605 | struct nlattr *nest; |
603 | 606 | |
604 | 607 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); |
... | ... | @@ -832,6 +835,7 @@ |
832 | 835 | struct net *net = sock_net(skb->sk); |
833 | 836 | int family = nfmsg->nfgen_family; |
834 | 837 | u64 handle = 0; |
838 | + unsigned int i; | |
835 | 839 | int err; |
836 | 840 | bool create; |
837 | 841 | |
... | ... | @@ -904,7 +908,7 @@ |
904 | 908 | if (nla[NFTA_CHAIN_HOOK]) { |
905 | 909 | struct nf_hook_ops *ops; |
906 | 910 | nf_hookfn *hookfn; |
907 | - u32 hooknum; | |
911 | + u32 hooknum, priority; | |
908 | 912 | int type = NFT_CHAIN_T_DEFAULT; |
909 | 913 | |
910 | 914 | if (nla[NFTA_CHAIN_TYPE]) { |
... | ... | @@ -926,6 +930,7 @@ |
926 | 930 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); |
927 | 931 | if (hooknum >= afi->nhooks) |
928 | 932 | return -EINVAL; |
933 | + priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | |
929 | 934 | |
930 | 935 | if (!(chain_type[family][type]->hook_mask & (1 << hooknum))) |
931 | 936 | return -EOPNOTSUPP; |
... | ... | @@ -938,15 +943,19 @@ |
938 | 943 | basechain->type = type; |
939 | 944 | chain = &basechain->chain; |
940 | 945 | |
941 | - ops = &basechain->ops; | |
942 | - ops->pf = family; | |
943 | - ops->owner = afi->owner; | |
944 | - ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | |
945 | - ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | |
946 | - ops->priv = chain; | |
947 | - ops->hook = afi->hooks[ops->hooknum]; | |
948 | - if (hookfn) | |
949 | - ops->hook = hookfn; | |
946 | + for (i = 0; i < afi->nops; i++) { | |
947 | + ops = &basechain->ops[i]; | |
948 | + ops->pf = family; | |
949 | + ops->owner = afi->owner; | |
950 | + ops->hooknum = hooknum; | |
951 | + ops->priority = priority; | |
952 | + ops->priv = chain; | |
953 | + ops->hook = afi->hooks[ops->hooknum]; | |
954 | + if (hookfn) | |
955 | + ops->hook = hookfn; | |
956 | + if (afi->hook_ops_init) | |
957 | + afi->hook_ops_init(ops, i); | |
958 | + } | |
950 | 959 | |
951 | 960 | chain->flags |= NFT_BASE_CHAIN; |
952 | 961 | |
... | ... | @@ -993,7 +1002,7 @@ |
993 | 1002 | |
994 | 1003 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
995 | 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 | 1006 | if (err < 0) { |
998 | 1007 | free_percpu(basechain->stats); |
999 | 1008 | kfree(basechain); |
... | ... | @@ -1052,7 +1061,7 @@ |
1052 | 1061 | |
1053 | 1062 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
1054 | 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 | 1066 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, |
1058 | 1067 | family); |
net/netfilter/nft_compat.c
... | ... | @@ -92,7 +92,7 @@ |
92 | 92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
93 | 93 | const struct nft_base_chain *basechain = |
94 | 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 | 97 | par->hook_mask = 1 << ops->hooknum; |
98 | 98 | } |
... | ... | @@ -253,7 +253,7 @@ |
253 | 253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
254 | 254 | const struct nft_base_chain *basechain = |
255 | 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 | 258 | hook_mask = 1 << ops->hooknum; |
259 | 259 | if (hook_mask & target->hooks) |
... | ... | @@ -323,7 +323,7 @@ |
323 | 323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
324 | 324 | const struct nft_base_chain *basechain = |
325 | 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 | 328 | par->hook_mask = 1 << ops->hooknum; |
329 | 329 | } |
... | ... | @@ -449,7 +449,7 @@ |
449 | 449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
450 | 450 | const struct nft_base_chain *basechain = |
451 | 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 | 454 | hook_mask = 1 << ops->hooknum; |
455 | 455 | if (hook_mask & match->hooks) |