Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2cbce139 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: attach net_device to basechain



The device is part of the hook configuration, so instead of a global
configuration per table, set it to each of the basechain that we create.

This patch reworks ebddf1a8 ("netfilter: nf_tables: allow to bind table to
net_device").

Note that this adds a dev_name field in the nft_base_chain structure which is
required the netdev notification subscription that follows up in a patch to
handle gone net_devices.

Suggested-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 711bdde6
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -791,6 +791,7 @@ struct nft_stats {
 *	@policy: default policy
 *	@stats: per-cpu chain stats
 *	@chain: the chain
 *	@dev_name: device name that this base chain is attached to (if any)
 */
struct nft_base_chain {
	struct nf_hook_ops		ops[NFT_HOOK_OPS_MAX];
@@ -799,6 +800,7 @@ struct nft_base_chain {
	u8				policy;
	struct nft_stats __percpu	*stats;
	struct nft_chain		chain;
	char 				dev_name[IFNAMSIZ];
};

static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chain)
@@ -819,7 +821,6 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt,
 *	@use: number of chain references to this table
 *	@flags: table flag (see enum nft_table_flags)
 *	@name: name of the table
 *	@dev: this table is bound to this device (if any)
 */
struct nft_table {
	struct list_head		list;
@@ -829,7 +830,6 @@ struct nft_table {
	u32				use;
	u16				flags;
	char				name[NFT_TABLE_MAXNAMELEN];
	struct net_device		*dev;
};

enum nft_af_flags {
+2 −2
Original line number Diff line number Diff line
@@ -122,11 +122,13 @@ enum nft_list_attributes {
 *
 * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
 * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
 * @NFTA_HOOK_DEV: netdevice name (NLA_STRING)
 */
enum nft_hook_attributes {
	NFTA_HOOK_UNSPEC,
	NFTA_HOOK_HOOKNUM,
	NFTA_HOOK_PRIORITY,
	NFTA_HOOK_DEV,
	__NFTA_HOOK_MAX
};
#define NFTA_HOOK_MAX		(__NFTA_HOOK_MAX - 1)
@@ -146,14 +148,12 @@ enum nft_table_flags {
 * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
 * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (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 {
	NFTA_TABLE_UNSPEC,
	NFTA_TABLE_NAME,
	NFTA_TABLE_FLAGS,
	NFTA_TABLE_USE,
	NFTA_TABLE_DEV,
	__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX		(__NFTA_TABLE_MAX - 1)
+42 −37
Original line number Diff line number Diff line
@@ -399,8 +399,6 @@ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
	[NFTA_TABLE_NAME]	= { .type = NLA_STRING,
				    .len = NFT_TABLE_MAXNAMELEN - 1 },
	[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,
@@ -425,10 +423,6 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
	    nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
		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);
	return 0;

@@ -614,11 +608,6 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
	if (flags == ctx->table->flags)
		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,
				sizeof(struct nft_trans_table));
	if (trans == NULL)
@@ -656,7 +645,6 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
	struct nft_table *table;
	struct net *net = sock_net(skb->sk);
	int family = nfmsg->nfgen_family;
	struct net_device *dev = NULL;
	u32 flags = 0;
	struct nft_ctx ctx;
	int err;
@@ -691,20 +679,6 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
			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))
		goto err1;
@@ -718,7 +692,6 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
	INIT_LIST_HEAD(&table->chains);
	INIT_LIST_HEAD(&table->sets);
	table->flags = flags;
	table->dev   = dev;

	nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
	err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
@@ -732,9 +705,6 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
err2:
	module_put(afi->owner);
err1:
	if (dev != NULL)
		dev_put(dev);

	return err;
}

@@ -838,9 +808,6 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx)
{
	BUG_ON(ctx->table->use > 0);

	if (ctx->table->dev)
		dev_put(ctx->table->dev);

	kfree(ctx->table);
	module_put(ctx->afi->owner);
}
@@ -916,6 +883,8 @@ static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
	[NFTA_HOOK_HOOKNUM]	= { .type = NLA_U32 },
	[NFTA_HOOK_PRIORITY]	= { .type = NLA_U32 },
	[NFTA_HOOK_DEV]		= { .type = NLA_STRING,
				    .len = IFNAMSIZ - 1 },
};

static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
@@ -989,6 +958,9 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
			goto nla_put_failure;
		if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
			goto nla_put_failure;
		if (basechain->dev_name[0] &&
		    nla_put_string(skb, NFTA_HOOK_DEV, basechain->dev_name))
			goto nla_put_failure;
		nla_nest_end(skb, nest);

		if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
@@ -1200,9 +1172,13 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
	BUG_ON(chain->use > 0);

	if (chain->flags & NFT_BASE_CHAIN) {
		module_put(nft_base_chain(chain)->type->owner);
		free_percpu(nft_base_chain(chain)->stats);
		kfree(nft_base_chain(chain));
		struct nft_base_chain *basechain = nft_base_chain(chain);

		module_put(basechain->type->owner);
		free_percpu(basechain->stats);
		if (basechain->ops[0].dev != NULL)
			dev_put(basechain->ops[0].dev);
		kfree(basechain);
	} else {
		kfree(chain);
	}
@@ -1221,6 +1197,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
	struct nlattr *ha[NFTA_HOOK_MAX + 1];
	struct net *net = sock_net(skb->sk);
	int family = nfmsg->nfgen_family;
	struct net_device *dev = NULL;
	u8 policy = NF_ACCEPT;
	u64 handle = 0;
	unsigned int i;
@@ -1360,17 +1337,43 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
			return -ENOENT;
		hookfn = type->hooks[hooknum];

		if (afi->flags & NFT_AF_NEEDS_DEV) {
			char ifname[IFNAMSIZ];

			if (!ha[NFTA_HOOK_DEV]) {
				module_put(type->owner);
				return -EOPNOTSUPP;
			}

			nla_strlcpy(ifname, ha[NFTA_HOOK_DEV], IFNAMSIZ);
			dev = dev_get_by_name(net, ifname);
			if (!dev) {
				module_put(type->owner);
				return -ENOENT;
			}
		} else if (ha[NFTA_HOOK_DEV]) {
			module_put(type->owner);
			return -EOPNOTSUPP;
		}

		basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
		if (basechain == NULL) {
			module_put(type->owner);
			if (dev != NULL)
				dev_put(dev);
			return -ENOMEM;
		}

		if (dev != NULL)
			strncpy(basechain->dev_name, dev->name, IFNAMSIZ);

		if (nla[NFTA_CHAIN_COUNTERS]) {
			stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
			if (IS_ERR(stats)) {
				module_put(type->owner);
				kfree(basechain);
				if (dev != NULL)
					dev_put(dev);
				return PTR_ERR(stats);
			}
			basechain->stats = stats;
@@ -1379,6 +1382,8 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
			if (stats == NULL) {
				module_put(type->owner);
				kfree(basechain);
				if (dev != NULL)
					dev_put(dev);
				return -ENOMEM;
			}
			rcu_assign_pointer(basechain->stats, stats);
@@ -1396,7 +1401,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
			ops->priority	= priority;
			ops->priv	= chain;
			ops->hook	= afi->hooks[ops->hooknum];
			ops->dev	= table->dev;
			ops->dev	= dev;
			if (hookfn)
				ops->hook = hookfn;
			if (afi->hook_ops_init)