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 u32 off
= pkt
->inneroff
;
215 if (priv
->flags
& NFT_INNER_HDRSIZE
&&
216 nft_inner_parse_tunhdr(priv
, pkt
, tun_ctx
, &off
) < 0)
219 if (priv
->flags
& (NFT_INNER_LL
| NFT_INNER_NH
)) {
220 if (nft_inner_parse_l2l3(priv
, pkt
, tun_ctx
, off
) < 0)
222 } else if (priv
->flags
& NFT_INNER_TH
) {
223 tun_ctx
->inner_thoff
= off
;
224 tun_ctx
->flags
|= NFT_PAYLOAD_CTX_INNER_TH
;
227 tun_ctx
->type
= priv
->type
;
228 tun_ctx
->cookie
= (unsigned long)pkt
->skb
;
229 pkt
->flags
|= NFT_PKTINFO_INNER_FULL
;
234 static bool nft_inner_restore_tun_ctx(const struct nft_pktinfo
*pkt
,
235 struct nft_inner_tun_ctx
*tun_ctx
)
237 struct nft_inner_tun_ctx
*this_cpu_tun_ctx
;
240 this_cpu_tun_ctx
= this_cpu_ptr(&nft_pcpu_tun_ctx
);
241 if (this_cpu_tun_ctx
->cookie
!= (unsigned long)pkt
->skb
) {
245 *tun_ctx
= *this_cpu_tun_ctx
;
251 static void nft_inner_save_tun_ctx(const struct nft_pktinfo
*pkt
,
252 const struct nft_inner_tun_ctx
*tun_ctx
)
254 struct nft_inner_tun_ctx
*this_cpu_tun_ctx
;
257 this_cpu_tun_ctx
= this_cpu_ptr(&nft_pcpu_tun_ctx
);
258 if (this_cpu_tun_ctx
->cookie
!= tun_ctx
->cookie
)
259 *this_cpu_tun_ctx
= *tun_ctx
;
263 static bool nft_inner_parse_needed(const struct nft_inner
*priv
,
264 const struct nft_pktinfo
*pkt
,
265 struct nft_inner_tun_ctx
*tun_ctx
)
267 if (!(pkt
->flags
& NFT_PKTINFO_INNER_FULL
))
270 if (!nft_inner_restore_tun_ctx(pkt
, tun_ctx
))
273 if (priv
->type
!= tun_ctx
->type
)
279 static void nft_inner_eval(const struct nft_expr
*expr
, struct nft_regs
*regs
,
280 const struct nft_pktinfo
*pkt
)
282 const struct nft_inner
*priv
= nft_expr_priv(expr
);
283 struct nft_inner_tun_ctx tun_ctx
= {};
285 if (nft_payload_inner_offset(pkt
) < 0)
288 if (nft_inner_parse_needed(priv
, pkt
, &tun_ctx
) &&
289 nft_inner_parse(priv
, (struct nft_pktinfo
*)pkt
, &tun_ctx
) < 0)
292 switch (priv
->expr_type
) {
293 case NFT_INNER_EXPR_PAYLOAD
:
294 nft_payload_inner_eval((struct nft_expr
*)&priv
->expr
, regs
, pkt
, &tun_ctx
);
296 case NFT_INNER_EXPR_META
:
297 nft_meta_inner_eval((struct nft_expr
*)&priv
->expr
, regs
, pkt
, &tun_ctx
);
303 nft_inner_save_tun_ctx(pkt
, &tun_ctx
);
307 regs
->verdict
.code
= NFT_BREAK
;
310 static const struct nla_policy nft_inner_policy
[NFTA_INNER_MAX
+ 1] = {
311 [NFTA_INNER_NUM
] = { .type
= NLA_U32
},
312 [NFTA_INNER_FLAGS
] = { .type
= NLA_U32
},
313 [NFTA_INNER_HDRSIZE
] = { .type
= NLA_U32
},
314 [NFTA_INNER_TYPE
] = { .type
= NLA_U32
},
315 [NFTA_INNER_EXPR
] = { .type
= NLA_NESTED
},
318 struct nft_expr_info
{
319 const struct nft_expr_ops
*ops
;
320 const struct nlattr
*attr
;
321 struct nlattr
*tb
[NFT_EXPR_MAXATTR
+ 1];
324 static int nft_inner_init(const struct nft_ctx
*ctx
,
325 const struct nft_expr
*expr
,
326 const struct nlattr
* const tb
[])
328 struct nft_inner
*priv
= nft_expr_priv(expr
);
329 u32 flags
, hdrsize
, type
, num
;
330 struct nft_expr_info expr_info
;
333 if (!tb
[NFTA_INNER_FLAGS
] ||
334 !tb
[NFTA_INNER_NUM
] ||
335 !tb
[NFTA_INNER_HDRSIZE
] ||
336 !tb
[NFTA_INNER_TYPE
] ||
337 !tb
[NFTA_INNER_EXPR
])
340 flags
= ntohl(nla_get_be32(tb
[NFTA_INNER_FLAGS
]));
341 if (flags
& ~NFT_INNER_MASK
)
344 num
= ntohl(nla_get_be32(tb
[NFTA_INNER_NUM
]));
348 hdrsize
= ntohl(nla_get_be32(tb
[NFTA_INNER_HDRSIZE
]));
349 type
= ntohl(nla_get_be32(tb
[NFTA_INNER_TYPE
]));
354 if (flags
& NFT_INNER_HDRSIZE
) {
355 if (hdrsize
== 0 || hdrsize
> 64)
360 priv
->hdrsize
= hdrsize
;
363 err
= nft_expr_inner_parse(ctx
, tb
[NFTA_INNER_EXPR
], &expr_info
);
367 priv
->expr
.ops
= expr_info
.ops
;
369 if (!strcmp(expr_info
.ops
->type
->name
, "payload"))
370 priv
->expr_type
= NFT_INNER_EXPR_PAYLOAD
;
371 else if (!strcmp(expr_info
.ops
->type
->name
, "meta"))
372 priv
->expr_type
= NFT_INNER_EXPR_META
;
376 err
= expr_info
.ops
->init(ctx
, (struct nft_expr
*)&priv
->expr
,
377 (const struct nlattr
* const*)expr_info
.tb
);
384 static int nft_inner_dump(struct sk_buff
*skb
,
385 const struct nft_expr
*expr
, bool reset
)
387 const struct nft_inner
*priv
= nft_expr_priv(expr
);
389 if (nla_put_be32(skb
, NFTA_INNER_NUM
, htonl(0)) ||
390 nla_put_be32(skb
, NFTA_INNER_TYPE
, htonl(priv
->type
)) ||
391 nla_put_be32(skb
, NFTA_INNER_FLAGS
, htonl(priv
->flags
)) ||
392 nla_put_be32(skb
, NFTA_INNER_HDRSIZE
, htonl(priv
->hdrsize
)))
393 goto nla_put_failure
;
395 if (nft_expr_dump(skb
, NFTA_INNER_EXPR
,
396 (struct nft_expr
*)&priv
->expr
, reset
) < 0)
397 goto nla_put_failure
;
405 static const struct nft_expr_ops nft_inner_ops
= {
406 .type
= &nft_inner_type
,
407 .size
= NFT_EXPR_SIZE(sizeof(struct nft_inner
)),
408 .eval
= nft_inner_eval
,
409 .init
= nft_inner_init
,
410 .dump
= nft_inner_dump
,
413 struct nft_expr_type nft_inner_type __read_mostly
= {
415 .ops
= &nft_inner_ops
,
416 .policy
= nft_inner_policy
,
417 .maxattr
= NFTA_INNER_MAX
,
418 .owner
= THIS_MODULE
,