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

Commit 0ca743a5 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: add compatibility layer for x_tables



This patch adds the x_tables compatibility layer. This allows you
to use existing x_tables matches and targets from nf_tables.

This compatibility later allows us to use existing matches/targets
for features that are still missing in nf_tables. We can progressively
replace them with native nf_tables extensions. It also provides the
userspace compatibility software that allows you to express the
rule-set using the iptables syntax but using the nf_tables kernel
components.

In order to get this compatibility layer working, I've done the
following things:

* add NFNL_SUBSYS_NFT_COMPAT: this new nfnetlink subsystem is used
to query the x_tables match/target revision, so we don't need to
use the native x_table getsockopt interface.

* emulate xt structures: this required extending the struct nft_pktinfo
to include the fragment offset, which is already obtained from
ip[6]_tables and that is used by some matches/targets.

* add support for default policy to base chains, required to emulate
  x_tables.

* add NFTA_CHAIN_USE attribute to obtain the number of references to
  chains, required by x_tables emulation.

* add chain packet/byte counters using per-cpu.

* support 32-64 bits compat.

For historical reasons, this patch includes the following patches
that were posted in the netfilter-devel mailing list.

From Pablo Neira Ayuso:
* nf_tables: add default policy to base chains
* netfilter: nf_tables: add NFTA_CHAIN_USE attribute
* nf_tables: nft_compat: private data of target and matches in contiguous area
* nf_tables: validate hooks for compat match/target
* nf_tables: nft_compat: release cached matches/targets
* nf_tables: x_tables support as a compile time option
* nf_tables: fix alias for xtables over nftables module
* nf_tables: add packet and byte counters per chain
* nf_tables: fix per-chain counter stats if no counters are passed
* nf_tables: don't bump chain stats
* nf_tables: add protocol and flags for xtables over nf_tables
* nf_tables: add ip[6]t_entry emulation
* nf_tables: move specific layer 3 compat code to nf_tables_ipv[4|6]
* nf_tables: support 32bits-64bits x_tables compat
* nf_tables: fix compilation if CONFIG_COMPAT is disabled

From Patrick McHardy:
* nf_tables: move policy to struct nft_base_chain
* nf_tables: send notifications for base chain policy changes

From Alexander Primak:
* nf_tables: remove the duplicate NF_INET_LOCAL_OUT

From Nicolas Dichtel:
* nf_tables: fix compilation when nf-netlink is a module

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 9370761c
Loading
Loading
Loading
Loading
+37 −7
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <linux/list.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netlink.h>

@@ -15,8 +16,23 @@ struct nft_pktinfo {
	u8				hooknum;
	u8				nhoff;
	u8				thoff;
	/* for x_tables compatibility */
	struct xt_action_param		xt;
};

static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
				   const struct nf_hook_ops *ops,
				   struct sk_buff *skb,
				   const struct net_device *in,
				   const struct net_device *out)
{
	pkt->skb = skb;
	pkt->in = pkt->xt.in = in;
	pkt->out = pkt->xt.out = out;
	pkt->hooknum = pkt->xt.hooknum = ops->hooknum;
	pkt->xt.family = ops->pf;
}

struct nft_data {
	union {
		u32				data[4];
@@ -57,6 +73,7 @@ static inline void nft_data_debug(const struct nft_data *data)
 * 	@afi: address family info
 * 	@table: the table the chain is contained in
 * 	@chain: the chain the rule is contained in
 *	@nla: netlink attributes
 */
struct nft_ctx {
	const struct sk_buff		*skb;
@@ -64,6 +81,7 @@ struct nft_ctx {
	const struct nft_af_info	*afi;
	const struct nft_table		*table;
	const struct nft_chain		*chain;
	const struct nlattr * const 	*nla;
};

struct nft_data_desc {
@@ -235,7 +253,8 @@ extern void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
 *	@maxattr: highest netlink attribute number
 */
struct nft_expr_type {
	const struct nft_expr_ops	*(*select_ops)(const struct nlattr * const tb[]);
	const struct nft_expr_ops	*(*select_ops)(const struct nft_ctx *,
						       const struct nlattr * const tb[]);
	const struct nft_expr_ops	*ops;
	struct list_head		list;
	const char			*name;
@@ -253,6 +272,8 @@ struct nft_expr_type {
 *	@destroy: destruction function
 *	@dump: function to dump parameters
 *	@type: expression type
 *	@validate: validate expression, called during loop detection
 *	@data: extra data to attach to this expression operation
 */
struct nft_expr;
struct nft_expr_ops {
@@ -267,8 +288,11 @@ struct nft_expr_ops {
	void				(*destroy)(const struct nft_expr *expr);
	int				(*dump)(struct sk_buff *skb,
						const struct nft_expr *expr);
	const struct nft_data *		(*get_verdict)(const struct nft_expr *expr);
	int				(*validate)(const struct nft_ctx *ctx,
						    const struct nft_expr *expr,
						    const struct nft_data **data);
	const struct nft_expr_type	*type;
	void				*data;
};

#define NFT_EXPR_MAXATTR		16
@@ -368,16 +392,25 @@ enum nft_chain_type {
	NFT_CHAIN_T_MAX
};

struct nft_stats {
	u64 bytes;
	u64 pkts;
};

/**
 *	struct nft_base_chain - nf_tables base chain
 *
 *	@ops: netfilter hook ops
 *	@type: chain type
 *	@policy: default policy
 *	@stats: per-cpu chain stats
 *	@chain: the chain
 */
struct nft_base_chain {
	struct nf_hook_ops		ops;
	enum nft_chain_type		type;
	u8				policy;
	struct nft_stats __percpu	*stats;
	struct nft_chain		chain;
};

@@ -386,11 +419,8 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
	return container_of(chain, struct nft_base_chain, chain);
}

extern unsigned int nft_do_chain(const struct nf_hook_ops *ops,
				 struct sk_buff *skb,
				 const struct net_device *in,
				 const struct net_device *out,
				 int (*okfn)(struct sk_buff *));
extern unsigned int nft_do_chain_pktinfo(struct nft_pktinfo *pkt,
					 const struct nf_hook_ops *ops);

/**
 *	struct nft_table - nf_tables table
+23 −0
Original line number Diff line number Diff line
#ifndef _NF_TABLES_IPV4_H_
#define _NF_TABLES_IPV4_H_

#include <net/netfilter/nf_tables.h>
#include <net/ip.h>

static inline void
nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt,
		     const struct nf_hook_ops *ops,
		     struct sk_buff *skb,
		     const struct net_device *in,
		     const struct net_device *out)
{
	struct iphdr *ip;

	nft_set_pktinfo(pkt, ops, skb, in, out);

	pkt->xt.thoff = ip_hdrlen(pkt->skb);
	ip = ip_hdr(pkt->skb);
	pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
}

#endif
+30 −0
Original line number Diff line number Diff line
#ifndef _NF_TABLES_IPV6_H_
#define _NF_TABLES_IPV6_H_

#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ipv6.h>

static inline int
nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
		     const struct nf_hook_ops *ops,
		     struct sk_buff *skb,
		     const struct net_device *in,
		     const struct net_device *out)
{
	int protohdr, thoff = 0;
	unsigned short frag_off;

	nft_set_pktinfo(pkt, ops, skb, in, out);

	protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL);
	/* If malformed, drop it */
	if (protohdr < 0)
		return -1;

	pkt->xt.thoff = thoff;
	pkt->xt.fragoff = frag_off;

	return 0;
}

#endif
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ header-y += nf_conntrack_sctp.h
header-y += nf_conntrack_tcp.h
header-y += nf_conntrack_tuple_common.h
header-y += nf_tables.h
header-y += nf_tables_compat.h
header-y += nf_nat.h
header-y += nfnetlink.h
header-y += nfnetlink_acct.h
+32 −0
Original line number Diff line number Diff line
@@ -115,7 +115,10 @@ enum nft_table_attributes {
 * @NFTA_CHAIN_HANDLE: numeric handle of the chain (NLA_U64)
 * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING)
 * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes)
 * @NFTA_CHAIN_POLICY: numeric policy of the chain (NLA_U32)
 * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32)
 * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
 * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
 */
enum nft_chain_attributes {
	NFTA_CHAIN_UNSPEC,
@@ -123,7 +126,10 @@ enum nft_chain_attributes {
	NFTA_CHAIN_HANDLE,
	NFTA_CHAIN_NAME,
	NFTA_CHAIN_HOOK,
	NFTA_CHAIN_POLICY,
	NFTA_CHAIN_USE,
	NFTA_CHAIN_TYPE,
	NFTA_CHAIN_COUNTERS,
	__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX		(__NFTA_CHAIN_MAX - 1)
@@ -135,6 +141,7 @@ enum nft_chain_attributes {
 * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING)
 * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U64)
 * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
 * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
 */
enum nft_rule_attributes {
	NFTA_RULE_UNSPEC,
@@ -142,10 +149,35 @@ enum nft_rule_attributes {
	NFTA_RULE_CHAIN,
	NFTA_RULE_HANDLE,
	NFTA_RULE_EXPRESSIONS,
	NFTA_RULE_COMPAT,
	__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)

/**
 * enum nft_rule_compat_flags - nf_tables rule compat flags
 *
 * @NFT_RULE_COMPAT_F_INV: invert the check result
 */
enum nft_rule_compat_flags {
	NFT_RULE_COMPAT_F_INV	= (1 << 1),
	NFT_RULE_COMPAT_F_MASK	= NFT_RULE_COMPAT_F_INV,
};

/**
 * enum nft_rule_compat_attributes - nf_tables rule compat attributes
 *
 * @NFTA_RULE_COMPAT_PROTO: numerice value of handled protocol (NLA_U32)
 * @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32)
 */
enum nft_rule_compat_attributes {
	NFTA_RULE_COMPAT_UNSPEC,
	NFTA_RULE_COMPAT_PROTO,
	NFTA_RULE_COMPAT_FLAGS,
	__NFTA_RULE_COMPAT_MAX
};
#define NFTA_RULE_COMPAT_MAX	(__NFTA_RULE_COMPAT_MAX - 1)

/**
 * enum nft_set_flags - nf_tables set flags
 *
Loading