1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2022 Pablo Neira Ayuso <pablo@netfilter.org>
6 #include <linux/kernel.h>
7 #include <linux/if_vlan.h>
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/netlink.h>
11 #include <linux/netfilter.h>
12 #include <linux/netfilter/nf_tables.h>
13 #include <net/netfilter/nf_tables_core.h>
14 #include <net/netfilter/nf_tables.h>
15 #include <net/netfilter/nft_meta.h>
16 #include <net/netfilter/nf_tables_offload.h>
17 #include <linux/tcp.h>
18 #include <linux/udp.h>
20 #include <net/geneve.h>
22 #include <linux/icmpv6.h>
24 #include <linux/ipv6.h>
26 static DEFINE_PER_CPU(struct nft_inner_tun_ctx
, nft_pcpu_tun_ctx
);
28 /* Same layout as nft_expr but it embeds the private expression data area. */
30 const struct nft_expr_ops
*ops
;
32 struct nft_payload payload
;
34 } __attribute__((aligned(__alignof__(u64
))));
38 NFT_INNER_EXPR_PAYLOAD
,
48 struct __nft_expr expr
;
51 static int nft_inner_parse_l2l3(const struct nft_inner
*priv
,
52 const struct nft_pktinfo
*pkt
,
53 struct nft_inner_tun_ctx
*ctx
, u32 off
)
55 __be16 llproto
, outer_llproto
;
58 if (priv
->flags
& NFT_INNER_LL
) {
59 struct vlan_ethhdr
*veth
, _veth
;
60 struct ethhdr
*eth
, _eth
;
63 eth
= skb_header_pointer(pkt
->skb
, off
, sizeof(_eth
), &_eth
);
67 switch (eth
->h_proto
) {
69 case htons(ETH_P_IPV6
):
70 llproto
= eth
->h_proto
;
71 hdrsize
= sizeof(_eth
);
73 case htons(ETH_P_8021Q
):
74 veth
= skb_header_pointer(pkt
->skb
, off
, sizeof(_veth
), &_veth
);
78 outer_llproto
= veth
->h_vlan_encapsulated_proto
;
79 llproto
= veth
->h_vlan_proto
;
80 hdrsize
= sizeof(_veth
);
86 ctx
->inner_lloff
= off
;
87 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_LL
;
93 iph
= skb_header_pointer(pkt
->skb
, off
, sizeof(_version
), &_version
);
97 switch (iph
->version
) {
99 llproto
= htons(ETH_P_IP
);
102 llproto
= htons(ETH_P_IPV6
);
109 ctx
->llproto
= llproto
;
110 if (llproto
== htons(ETH_P_8021Q
))
111 llproto
= outer_llproto
;
116 case htons(ETH_P_IP
): {
117 struct iphdr
*iph
, _iph
;
119 iph
= skb_header_pointer(pkt
->skb
, nhoff
, sizeof(_iph
), &_iph
);
123 if (iph
->ihl
< 5 || iph
->version
!= 4)
126 ctx
->inner_nhoff
= nhoff
;
127 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_NH
;
129 thoff
= nhoff
+ (iph
->ihl
* 4);
130 if ((ntohs(iph
->frag_off
) & IP_OFFSET
) == 0) {
131 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_TH
;
132 ctx
->inner_thoff
= thoff
;
133 ctx
->l4proto
= iph
->protocol
;
137 case htons(ETH_P_IPV6
): {
138 struct ipv6hdr
*ip6h
, _ip6h
;
139 int fh_flags
= IP6_FH_F_AUTH
;
140 unsigned short fragoff
;
143 ip6h
= skb_header_pointer(pkt
->skb
, nhoff
, sizeof(_ip6h
), &_ip6h
);
147 if (ip6h
->version
!= 6)
150 ctx
->inner_nhoff
= nhoff
;
151 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_NH
;
154 l4proto
= ipv6_find_hdr(pkt
->skb
, &thoff
, -1, &fragoff
, &fh_flags
);
155 if (l4proto
< 0 || thoff
> U16_MAX
)
159 thoff
= nhoff
+ sizeof(_ip6h
);
160 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_TH
;
161 ctx
->inner_thoff
= thoff
;
162 ctx
->l4proto
= l4proto
;
173 static int nft_inner_parse_tunhdr(const struct nft_inner
*priv
,
174 const struct nft_pktinfo
*pkt
,
175 struct nft_inner_tun_ctx
*ctx
, u32
*off
)
177 if (pkt
->tprot
== IPPROTO_GRE
) {
178 ctx
->inner_tunoff
= pkt
->thoff
;
179 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_TUN
;
183 if (pkt
->tprot
!= IPPROTO_UDP
)
186 ctx
->inner_tunoff
= *off
;
187 ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_TUN
;
188 *off
+= priv
->hdrsize
;
190 switch (priv
->type
) {
191 case NFT_INNER_GENEVE
: {
192 struct genevehdr
*gnvh
, _gnvh
;
194 gnvh
= skb_header_pointer(pkt
->skb
, pkt
->inneroff
,
195 sizeof(_gnvh
), &_gnvh
);
199 *off
+= gnvh
->opt_len
* 4;
209 static int nft_inner_parse(const struct nft_inner
*priv
,
210 struct nft_pktinfo
*pkt
,
211 struct nft_inner_tun_ctx
*tun_ctx
)
213 struct nft_inner_tun_ctx ctx
= {};
214 u32 off
= pkt
->inneroff
;
216 if (priv
->flags
& NFT_INNER_HDRSIZE
&&
217 nft_inner_parse_tunhdr(priv
, pkt
, &ctx
, &off
) < 0)
220 if (priv
->flags
& (NFT_INNER_LL
| NFT_INNER_NH
)) {
221 if (nft_inner_parse_l2l3(priv
, pkt
, &ctx
, off
) < 0)
223 } else if (priv
->flags
& NFT_INNER_TH
) {
224 ctx
.inner_thoff
= off
;
225 ctx
.flags
|= NFT_PAYLOAD_CTX_INNER_TH
;
229 tun_ctx
->type
= priv
->type
;
230 pkt
->flags
|= NFT_PKTINFO_INNER_FULL
;
235 static bool nft_inner_parse_needed(const struct nft_inner
*priv
,
236 const struct nft_pktinfo
*pkt
,
237 const struct nft_inner_tun_ctx
*tun_ctx
)
239 if (!(pkt
->flags
& NFT_PKTINFO_INNER_FULL
))
242 if (priv
->type
!= tun_ctx
->type
)
248 static void nft_inner_eval(const struct nft_expr
*expr
, struct nft_regs
*regs
,
249 const struct nft_pktinfo
*pkt
)
251 struct nft_inner_tun_ctx
*tun_ctx
= this_cpu_ptr(&nft_pcpu_tun_ctx
);
252 const struct nft_inner
*priv
= nft_expr_priv(expr
);
254 if (nft_payload_inner_offset(pkt
) < 0)
257 if (nft_inner_parse_needed(priv
, pkt
, tun_ctx
) &&
258 nft_inner_parse(priv
, (struct nft_pktinfo
*)pkt
, tun_ctx
) < 0)
261 switch (priv
->expr_type
) {
262 case NFT_INNER_EXPR_PAYLOAD
:
263 nft_payload_inner_eval((struct nft_expr
*)&priv
->expr
, regs
, pkt
, tun_ctx
);
265 case NFT_INNER_EXPR_META
:
266 nft_meta_inner_eval((struct nft_expr
*)&priv
->expr
, regs
, pkt
, tun_ctx
);
274 regs
->verdict
.code
= NFT_BREAK
;
277 static const struct nla_policy nft_inner_policy
[NFTA_INNER_MAX
+ 1] = {
278 [NFTA_INNER_NUM
] = { .type
= NLA_U32
},
279 [NFTA_INNER_FLAGS
] = { .type
= NLA_U32
},
280 [NFTA_INNER_HDRSIZE
] = { .type
= NLA_U32
},
281 [NFTA_INNER_TYPE
] = { .type
= NLA_U32
},
282 [NFTA_INNER_EXPR
] = { .type
= NLA_NESTED
},
285 struct nft_expr_info
{
286 const struct nft_expr_ops
*ops
;
287 const struct nlattr
*attr
;
288 struct nlattr
*tb
[NFT_EXPR_MAXATTR
+ 1];
291 static int nft_inner_init(const struct nft_ctx
*ctx
,
292 const struct nft_expr
*expr
,
293 const struct nlattr
* const tb
[])
295 struct nft_inner
*priv
= nft_expr_priv(expr
);
296 u32 flags
, hdrsize
, type
, num
;
297 struct nft_expr_info expr_info
;
300 if (!tb
[NFTA_INNER_FLAGS
] ||
301 !tb
[NFTA_INNER_NUM
] ||
302 !tb
[NFTA_INNER_HDRSIZE
] ||
303 !tb
[NFTA_INNER_TYPE
] ||
304 !tb
[NFTA_INNER_EXPR
])
307 flags
= ntohl(nla_get_be32(tb
[NFTA_INNER_FLAGS
]));
308 if (flags
& ~NFT_INNER_MASK
)
311 num
= ntohl(nla_get_be32(tb
[NFTA_INNER_NUM
]));
315 hdrsize
= ntohl(nla_get_be32(tb
[NFTA_INNER_HDRSIZE
]));
316 type
= ntohl(nla_get_be32(tb
[NFTA_INNER_TYPE
]));
321 if (flags
& NFT_INNER_HDRSIZE
) {
322 if (hdrsize
== 0 || hdrsize
> 64)
327 priv
->hdrsize
= hdrsize
;
330 err
= nft_expr_inner_parse(ctx
, tb
[NFTA_INNER_EXPR
], &expr_info
);
334 priv
->expr
.ops
= expr_info
.ops
;
336 if (!strcmp(expr_info
.ops
->type
->name
, "payload"))
337 priv
->expr_type
= NFT_INNER_EXPR_PAYLOAD
;
338 else if (!strcmp(expr_info
.ops
->type
->name
, "meta"))
339 priv
->expr_type
= NFT_INNER_EXPR_META
;
343 err
= expr_info
.ops
->init(ctx
, (struct nft_expr
*)&priv
->expr
,
344 (const struct nlattr
* const*)expr_info
.tb
);
351 static int nft_inner_dump(struct sk_buff
*skb
,
352 const struct nft_expr
*expr
, bool reset
)
354 const struct nft_inner
*priv
= nft_expr_priv(expr
);
356 if (nla_put_be32(skb
, NFTA_INNER_NUM
, htonl(0)) ||
357 nla_put_be32(skb
, NFTA_INNER_TYPE
, htonl(priv
->type
)) ||
358 nla_put_be32(skb
, NFTA_INNER_FLAGS
, htonl(priv
->flags
)) ||
359 nla_put_be32(skb
, NFTA_INNER_HDRSIZE
, htonl(priv
->hdrsize
)))
360 goto nla_put_failure
;
362 if (nft_expr_dump(skb
, NFTA_INNER_EXPR
,
363 (struct nft_expr
*)&priv
->expr
, reset
) < 0)
364 goto nla_put_failure
;
372 static const struct nft_expr_ops nft_inner_ops
= {
373 .type
= &nft_inner_type
,
374 .size
= NFT_EXPR_SIZE(sizeof(struct nft_inner
)),
375 .eval
= nft_inner_eval
,
376 .init
= nft_inner_init
,
377 .dump
= nft_inner_dump
,
380 struct nft_expr_type nft_inner_type __read_mostly
= {
382 .ops
= &nft_inner_ops
,
383 .policy
= nft_inner_policy
,
384 .maxattr
= NFTA_INNER_MAX
,
385 .owner
= THIS_MODULE
,