Skip to content

Commit 3a07327

Browse files
committed
netfilter: nft_inner: support for inner tunnel header matching
This new expression allows you to match on the inner headers that are encapsulated by any of the existing tunneling protocols. This expression parses the inner packet to set the link, network and transport offsets, so the existing expressions (with a few updates) can be reused to match on the inner headers. The inner expression supports for different tunnel combinations such as: - ethernet frame over IPv4/IPv6 packet, eg. VxLAN. - IPv4/IPv6 packet over IPv4/IPv6 packet, eg. IPIP. - IPv4/IPv6 packet over IPv4/IPv6 + transport header, eg. GRE. - transport header (ESP or SCTP) over transport header (usually UDP) The following fields are used to describe the tunnel protocol: - flags, which describe how to parse the inner headers: NFT_PAYLOAD_CTX_INNER_TUN, the tunnel provides its own header. NFT_PAYLOAD_CTX_INNER_ETHER, the ethernet frame is available as inner header. NFT_PAYLOAD_CTX_INNER_NH, the network header is available as inner header. NFT_PAYLOAD_CTX_INNER_TH, the transport header is available as inner header. For example, VxLAN sets on all of these flags. While GRE only sets on NFT_PAYLOAD_CTX_INNER_NH and NFT_PAYLOAD_CTX_INNER_TH. Then, ESP over UDP only sets on NFT_PAYLOAD_CTX_INNER_TH. The tunnel description is composed of the following attributes: - header size: in case the tunnel comes with its own header, eg. VxLAN. - type: this provides a hint to userspace on how to delinearize the rule. This is useful for VxLAN and Geneve since they run over UDP, since transport does not provide a hint. This is also useful in case hardware offload is ever supported. The type is not currently interpreted by the kernel. - expression: currently only payload supported. Follow up patch adds also inner meta support which is required by autogenerated dependencies. The exthdr expression should be supported too at some point. There is a new inner_ops operation that needs to be set on to allow to use an existing expression from the inner expression. This patch adds a new NFT_PAYLOAD_TUN_HEADER base which allows to match on the tunnel header fields, eg. vxlan vni. The payload expression is embedded into nft_inner private area and this private data area is passed to the payload inner eval function via direct call. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 3927ce8 commit 3a07327

File tree

8 files changed

+518
-2
lines changed

8 files changed

+518
-2
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,10 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
375375
return (void *)expr->data;
376376
}
377377

378+
struct nft_expr_info;
379+
380+
int nft_expr_inner_parse(const struct nft_ctx *ctx, const struct nlattr *nla,
381+
struct nft_expr_info *info);
378382
int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src);
379383
void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
380384
int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
@@ -864,6 +868,7 @@ struct nft_expr_type {
864868
const struct nlattr * const tb[]);
865869
void (*release_ops)(const struct nft_expr_ops *ops);
866870
const struct nft_expr_ops *ops;
871+
const struct nft_expr_ops *inner_ops;
867872
struct list_head list;
868873
const char *name;
869874
struct module *owner;

include/net/netfilter/nf_tables_core.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern struct nft_expr_type nft_rt_type;
1919
extern struct nft_expr_type nft_exthdr_type;
2020
extern struct nft_expr_type nft_last_type;
2121
extern struct nft_expr_type nft_objref_type;
22+
extern struct nft_expr_type nft_inner_type;
2223

2324
#ifdef CONFIG_NETWORK_SECMARK
2425
extern struct nft_object_type nft_secmark_obj_type;
@@ -139,4 +140,27 @@ void nft_rt_get_eval(const struct nft_expr *expr,
139140
struct nft_regs *regs, const struct nft_pktinfo *pkt);
140141
void nft_counter_eval(const struct nft_expr *expr, struct nft_regs *regs,
141142
const struct nft_pktinfo *pkt);
143+
144+
enum {
145+
NFT_PAYLOAD_CTX_INNER_TUN = (1 << 0),
146+
NFT_PAYLOAD_CTX_INNER_LL = (1 << 1),
147+
NFT_PAYLOAD_CTX_INNER_NH = (1 << 2),
148+
NFT_PAYLOAD_CTX_INNER_TH = (1 << 3),
149+
};
150+
151+
struct nft_inner_tun_ctx {
152+
u16 inner_tunoff;
153+
u16 inner_lloff;
154+
u16 inner_nhoff;
155+
u16 inner_thoff;
156+
__be16 llproto;
157+
u8 l4proto;
158+
u8 flags;
159+
};
160+
161+
int nft_payload_inner_offset(const struct nft_pktinfo *pkt);
162+
void nft_payload_inner_eval(const struct nft_expr *expr, struct nft_regs *regs,
163+
const struct nft_pktinfo *pkt,
164+
struct nft_inner_tun_ctx *ctx);
165+
142166
#endif /* _NET_NF_TABLES_CORE_H */

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ enum nft_payload_bases {
760760
NFT_PAYLOAD_NETWORK_HEADER,
761761
NFT_PAYLOAD_TRANSPORT_HEADER,
762762
NFT_PAYLOAD_INNER_HEADER,
763+
NFT_PAYLOAD_TUN_HEADER,
763764
};
764765

765766
/**
@@ -779,6 +780,31 @@ enum nft_payload_csum_flags {
779780
NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0),
780781
};
781782

783+
enum nft_inner_type {
784+
NFT_INNER_UNSPEC = 0,
785+
NFT_INNER_VXLAN,
786+
};
787+
788+
enum nft_inner_flags {
789+
NFT_INNER_HDRSIZE = (1 << 0),
790+
NFT_INNER_LL = (1 << 1),
791+
NFT_INNER_NH = (1 << 2),
792+
NFT_INNER_TH = (1 << 3),
793+
};
794+
#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \
795+
NFT_INNER_NH | NFT_INNER_TH)
796+
797+
enum nft_inner_attributes {
798+
NFTA_INNER_UNSPEC,
799+
NFTA_INNER_NUM,
800+
NFTA_INNER_TYPE,
801+
NFTA_INNER_FLAGS,
802+
NFTA_INNER_HDRSIZE,
803+
NFTA_INNER_EXPR,
804+
__NFTA_INNER_MAX
805+
};
806+
#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1)
807+
782808
/**
783809
* enum nft_payload_attributes - nf_tables payload expression netlink attributes
784810
*

net/netfilter/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \
8686
nf_tables_trace.o nft_immediate.o nft_cmp.o nft_range.o \
8787
nft_bitwise.o nft_byteorder.o nft_payload.o nft_lookup.o \
8888
nft_dynset.o nft_meta.o nft_rt.o nft_exthdr.o nft_last.o \
89-
nft_counter.o nft_objref.o \
89+
nft_counter.o nft_objref.o nft_inner.o \
9090
nft_chain_route.o nf_tables_offload.o \
9191
nft_set_hash.o nft_set_bitmap.o nft_set_rbtree.o \
9292
nft_set_pipapo.o

net/netfilter/nf_tables_api.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2857,6 +2857,43 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
28572857
return err;
28582858
}
28592859

2860+
int nft_expr_inner_parse(const struct nft_ctx *ctx, const struct nlattr *nla,
2861+
struct nft_expr_info *info)
2862+
{
2863+
struct nlattr *tb[NFTA_EXPR_MAX + 1];
2864+
const struct nft_expr_type *type;
2865+
int err;
2866+
2867+
err = nla_parse_nested_deprecated(tb, NFTA_EXPR_MAX, nla,
2868+
nft_expr_policy, NULL);
2869+
if (err < 0)
2870+
return err;
2871+
2872+
if (!tb[NFTA_EXPR_DATA])
2873+
return -EINVAL;
2874+
2875+
type = __nft_expr_type_get(ctx->family, tb[NFTA_EXPR_NAME]);
2876+
if (IS_ERR(type))
2877+
return PTR_ERR(type);
2878+
2879+
if (!type->inner_ops)
2880+
return -EOPNOTSUPP;
2881+
2882+
err = nla_parse_nested_deprecated(info->tb, type->maxattr,
2883+
tb[NFTA_EXPR_DATA],
2884+
type->policy, NULL);
2885+
if (err < 0)
2886+
goto err_nla_parse;
2887+
2888+
info->attr = nla;
2889+
info->ops = type->inner_ops;
2890+
2891+
return 0;
2892+
2893+
err_nla_parse:
2894+
return err;
2895+
}
2896+
28602897
static int nf_tables_newexpr(const struct nft_ctx *ctx,
28612898
const struct nft_expr_info *expr_info,
28622899
struct nft_expr *expr)

net/netfilter/nf_tables_core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ static struct nft_expr_type *nft_basic_types[] = {
341341
&nft_last_type,
342342
&nft_counter_type,
343343
&nft_objref_type,
344+
&nft_inner_type,
344345
};
345346

346347
static struct nft_object_type *nft_basic_objects[] = {

0 commit comments

Comments
 (0)