Commit ebddf1a8 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nf_tables: allow to bind table to net_device

This patch adds the internal NFT_AF_NEEDS_DEV flag to indicate that you must
attach this table to a net_device.

This change is required by the follow up patch that introduces the new netdev
table.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 529985de
...@@ -819,6 +819,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, ...@@ -819,6 +819,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt,
* @use: number of chain references to this table * @use: number of chain references to this table
* @flags: table flag (see enum nft_table_flags) * @flags: table flag (see enum nft_table_flags)
* @name: name of the table * @name: name of the table
* @dev: this table is bound to this device (if any)
*/ */
struct nft_table { struct nft_table {
struct list_head list; struct list_head list;
...@@ -828,6 +829,11 @@ struct nft_table { ...@@ -828,6 +829,11 @@ struct nft_table {
u32 use; u32 use;
u16 flags; u16 flags;
char name[NFT_TABLE_MAXNAMELEN]; char name[NFT_TABLE_MAXNAMELEN];
struct net_device *dev;
};
enum nft_af_flags {
NFT_AF_NEEDS_DEV = (1 << 0),
}; };
/** /**
...@@ -838,6 +844,7 @@ struct nft_table { ...@@ -838,6 +844,7 @@ struct nft_table {
* @nhooks: number of hooks in this family * @nhooks: number of hooks in this family
* @owner: module owner * @owner: module owner
* @tables: used internally * @tables: used internally
* @flags: family flags
* @nops: number of hook ops in this family * @nops: number of hook ops in this family
* @hook_ops_init: initialization function for chain hook ops * @hook_ops_init: initialization function for chain hook ops
* @hooks: hookfn overrides for packet validation * @hooks: hookfn overrides for packet validation
...@@ -848,6 +855,7 @@ struct nft_af_info { ...@@ -848,6 +855,7 @@ struct nft_af_info {
unsigned int nhooks; unsigned int nhooks;
struct module *owner; struct module *owner;
struct list_head tables; struct list_head tables;
u32 flags;
unsigned int nops; unsigned int nops;
void (*hook_ops_init)(struct nf_hook_ops *, void (*hook_ops_init)(struct nf_hook_ops *,
unsigned int); unsigned int);
......
...@@ -146,12 +146,14 @@ enum nft_table_flags { ...@@ -146,12 +146,14 @@ enum nft_table_flags {
* @NFTA_TABLE_NAME: name of the table (NLA_STRING) * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
* @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
* @NFTA_TABLE_USE: number of chains in this table (NLA_U32) * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
* @NFTA_TABLE_DEV: net device name (NLA_STRING)
*/ */
enum nft_table_attributes { enum nft_table_attributes {
NFTA_TABLE_UNSPEC, NFTA_TABLE_UNSPEC,
NFTA_TABLE_NAME, NFTA_TABLE_NAME,
NFTA_TABLE_FLAGS, NFTA_TABLE_FLAGS,
NFTA_TABLE_USE, NFTA_TABLE_USE,
NFTA_TABLE_DEV,
__NFTA_TABLE_MAX __NFTA_TABLE_MAX
}; };
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
......
...@@ -399,6 +399,8 @@ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { ...@@ -399,6 +399,8 @@ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
[NFTA_TABLE_NAME] = { .type = NLA_STRING, [NFTA_TABLE_NAME] = { .type = NLA_STRING,
.len = NFT_TABLE_MAXNAMELEN - 1 }, .len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
[NFTA_TABLE_DEV] = { .type = NLA_STRING,
.len = IFNAMSIZ - 1 },
}; };
static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
...@@ -423,6 +425,10 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, ...@@ -423,6 +425,10 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
goto nla_put_failure; goto nla_put_failure;
if (table->dev &&
nla_put_string(skb, NFTA_TABLE_DEV, table->dev->name))
goto nla_put_failure;
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
return 0; return 0;
...@@ -608,6 +614,11 @@ static int nf_tables_updtable(struct nft_ctx *ctx) ...@@ -608,6 +614,11 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
if (flags == ctx->table->flags) if (flags == ctx->table->flags)
return 0; return 0;
if ((ctx->afi->flags & NFT_AF_NEEDS_DEV) &&
ctx->nla[NFTA_TABLE_DEV] &&
nla_strcmp(ctx->nla[NFTA_TABLE_DEV], ctx->table->dev->name))
return -EOPNOTSUPP;
trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
sizeof(struct nft_trans_table)); sizeof(struct nft_trans_table));
if (trans == NULL) if (trans == NULL)
...@@ -645,6 +656,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, ...@@ -645,6 +656,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
struct nft_table *table; struct nft_table *table;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family; int family = nfmsg->nfgen_family;
struct net_device *dev = NULL;
u32 flags = 0; u32 flags = 0;
struct nft_ctx ctx; struct nft_ctx ctx;
int err; int err;
...@@ -679,30 +691,50 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, ...@@ -679,30 +691,50 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
return -EINVAL; return -EINVAL;
} }
if (afi->flags & NFT_AF_NEEDS_DEV) {
char ifname[IFNAMSIZ];
if (!nla[NFTA_TABLE_DEV])
return -EOPNOTSUPP;
nla_strlcpy(ifname, nla[NFTA_TABLE_DEV], IFNAMSIZ);
dev = dev_get_by_name(net, ifname);
if (!dev)
return -ENOENT;
} else if (nla[NFTA_TABLE_DEV]) {
return -EOPNOTSUPP;
}
err = -EAFNOSUPPORT;
if (!try_module_get(afi->owner)) if (!try_module_get(afi->owner))
return -EAFNOSUPPORT; goto err1;
err = -ENOMEM; err = -ENOMEM;
table = kzalloc(sizeof(*table), GFP_KERNEL); table = kzalloc(sizeof(*table), GFP_KERNEL);
if (table == NULL) if (table == NULL)
goto err1; goto err2;
nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN); nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN);
INIT_LIST_HEAD(&table->chains); INIT_LIST_HEAD(&table->chains);
INIT_LIST_HEAD(&table->sets); INIT_LIST_HEAD(&table->sets);
table->flags = flags; table->flags = flags;
table->dev = dev;
nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE); err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
if (err < 0) if (err < 0)
goto err2; goto err3;
list_add_tail_rcu(&table->list, &afi->tables); list_add_tail_rcu(&table->list, &afi->tables);
return 0; return 0;
err2: err3:
kfree(table); kfree(table);
err1: err2:
module_put(afi->owner); module_put(afi->owner);
err1:
if (dev != NULL)
dev_put(dev);
return err; return err;
} }
...@@ -806,6 +838,9 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx) ...@@ -806,6 +838,9 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx)
{ {
BUG_ON(ctx->table->use > 0); BUG_ON(ctx->table->use > 0);
if (ctx->table->dev)
dev_put(ctx->table->dev);
kfree(ctx->table); kfree(ctx->table);
module_put(ctx->afi->owner); module_put(ctx->afi->owner);
} }
...@@ -1361,6 +1396,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, ...@@ -1361,6 +1396,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
ops->priority = priority; ops->priority = priority;
ops->priv = chain; ops->priv = chain;
ops->hook = afi->hooks[ops->hooknum]; ops->hook = afi->hooks[ops->hooknum];
ops->dev = table->dev;
if (hookfn) if (hookfn)
ops->hook = hookfn; ops->hook = hookfn;
if (afi->hook_ops_init) if (afi->hook_ops_init)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment