xref: /aosp_15_r20/external/iptables/iptables/nft-ruleparse-ipv6.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /*
2  * (C) 2012-2014 by Pablo Neira Ayuso <[email protected]>
3  * (C) 2013 by Tomasz Bursztyka <[email protected]>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
11  */
12 
13 #include <stddef.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <netdb.h>
18 #include <net/if.h>
19 #include <netinet/if_ether.h>
20 #include <netinet/ip6.h>
21 
22 #include <libnftnl/rule.h>
23 #include <libnftnl/expr.h>
24 
25 #include "nft-shared.h"
26 #include "nft-ruleparse.h"
27 #include "xshared.h"
28 
nft_ipv6_parse_meta(struct nft_xt_ctx * ctx,const struct nft_xt_ctx_reg * reg,struct nftnl_expr * e,struct iptables_command_state * cs)29 static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx,
30 				const struct nft_xt_ctx_reg *reg,
31 				struct nftnl_expr *e,
32 				struct iptables_command_state *cs)
33 {
34 	switch (reg->meta_dreg.key) {
35 	case NFT_META_L4PROTO:
36 		cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
37 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
38 			cs->fw6.ipv6.invflags |= XT_INV_PROTO;
39 		return;
40 	default:
41 		break;
42 	}
43 
44 	if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface,
45 		   cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface,
46 		   cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags) == 0)
47 		return;
48 
49 	ctx->errmsg = "unknown ipv6 meta key";
50 }
51 
parse_mask_ipv6(const struct nft_xt_ctx_reg * reg,struct in6_addr * mask)52 static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg,
53 			    struct in6_addr *mask)
54 {
55 	memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr));
56 }
57 
nft_ipv6_parse_payload(struct nft_xt_ctx * ctx,const struct nft_xt_ctx_reg * reg,struct nftnl_expr * e,struct iptables_command_state * cs)58 static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
59 				   const struct nft_xt_ctx_reg *reg,
60 				   struct nftnl_expr *e,
61 				   struct iptables_command_state *cs)
62 {
63 	struct in6_addr addr;
64 	uint8_t proto;
65 	bool inv;
66 
67 	switch (reg->payload.offset) {
68 	case offsetof(struct ip6_hdr, ip6_src):
69 		get_cmp_data(e, &addr, sizeof(addr), &inv);
70 		memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
71 		if (reg->bitwise.set)
72 			parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk);
73 		else
74 			memset(&cs->fw6.ipv6.smsk, 0xff,
75 			       min(reg->payload.len, sizeof(struct in6_addr)));
76 
77 		if (inv)
78 			cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP;
79 		break;
80 	case offsetof(struct ip6_hdr, ip6_dst):
81 		get_cmp_data(e, &addr, sizeof(addr), &inv);
82 		memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
83 		if (reg->bitwise.set)
84 			parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk);
85 		else
86 			memset(&cs->fw6.ipv6.dmsk, 0xff,
87 			       min(reg->payload.len, sizeof(struct in6_addr)));
88 
89 		if (inv)
90 			cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP;
91 		break;
92 	case offsetof(struct ip6_hdr, ip6_nxt):
93 		get_cmp_data(e, &proto, sizeof(proto), &inv);
94 		cs->fw6.ipv6.proto = proto;
95 		if (inv)
96 			cs->fw6.ipv6.invflags |= IP6T_INV_PROTO;
97 	case offsetof(struct ip6_hdr, ip6_hlim):
98 		if (nft_parse_hl(ctx, e, cs) < 0)
99 			ctx->errmsg = "invalid ttl field match";
100 		break;
101 	default:
102 		DEBUGP("unknown payload offset %d\n", reg->payload.offset);
103 		ctx->errmsg = "unknown payload offset";
104 		break;
105 	}
106 }
107 
108 struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = {
109 	.meta		= nft_ipv6_parse_meta,
110 	.payload	= nft_ipv6_parse_payload,
111 };
112