xref: /aosp_15_r20/external/iptables/extensions/libip6t_ipv6header.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1*a71a9546SAutomerger Merge Worker /* ipv6header match - matches IPv6 packets based
2*a71a9546SAutomerger Merge Worker on whether they contain certain headers */
3*a71a9546SAutomerger Merge Worker 
4*a71a9546SAutomerger Merge Worker /* Original idea: Brad Chapman
5*a71a9546SAutomerger Merge Worker  * Rewritten by: Andras Kis-Szabo <[email protected]> */
6*a71a9546SAutomerger Merge Worker #include <stdint.h>
7*a71a9546SAutomerger Merge Worker #include <stdio.h>
8*a71a9546SAutomerger Merge Worker #include <stdlib.h>
9*a71a9546SAutomerger Merge Worker #include <string.h>
10*a71a9546SAutomerger Merge Worker #include <netdb.h>
11*a71a9546SAutomerger Merge Worker #include <xtables.h>
12*a71a9546SAutomerger Merge Worker #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
13*a71a9546SAutomerger Merge Worker 
14*a71a9546SAutomerger Merge Worker enum {
15*a71a9546SAutomerger Merge Worker 	O_HEADER = 0,
16*a71a9546SAutomerger Merge Worker 	O_SOFT,
17*a71a9546SAutomerger Merge Worker };
18*a71a9546SAutomerger Merge Worker 
19*a71a9546SAutomerger Merge Worker /* A few hardcoded protocols for 'all' and in case the user has no
20*a71a9546SAutomerger Merge Worker  *    /etc/protocols */
21*a71a9546SAutomerger Merge Worker struct pprot {
22*a71a9546SAutomerger Merge Worker 	char *name;
23*a71a9546SAutomerger Merge Worker 	uint8_t num;
24*a71a9546SAutomerger Merge Worker };
25*a71a9546SAutomerger Merge Worker 
26*a71a9546SAutomerger Merge Worker struct numflag {
27*a71a9546SAutomerger Merge Worker 	uint8_t proto;
28*a71a9546SAutomerger Merge Worker 	uint8_t flag;
29*a71a9546SAutomerger Merge Worker };
30*a71a9546SAutomerger Merge Worker 
31*a71a9546SAutomerger Merge Worker static const struct pprot chain_protos[] = {
32*a71a9546SAutomerger Merge Worker 	{ "hop-by-hop", IPPROTO_HOPOPTS },
33*a71a9546SAutomerger Merge Worker 	{ "protocol", IPPROTO_RAW },
34*a71a9546SAutomerger Merge Worker 	{ "hop", IPPROTO_HOPOPTS },
35*a71a9546SAutomerger Merge Worker 	{ "dst", IPPROTO_DSTOPTS },
36*a71a9546SAutomerger Merge Worker 	{ "route", IPPROTO_ROUTING },
37*a71a9546SAutomerger Merge Worker 	{ "frag", IPPROTO_FRAGMENT },
38*a71a9546SAutomerger Merge Worker 	{ "auth", IPPROTO_AH },
39*a71a9546SAutomerger Merge Worker 	{ "esp", IPPROTO_ESP },
40*a71a9546SAutomerger Merge Worker 	{ "none", IPPROTO_NONE },
41*a71a9546SAutomerger Merge Worker 	{ "prot", IPPROTO_RAW },
42*a71a9546SAutomerger Merge Worker 	{ "0", IPPROTO_HOPOPTS },
43*a71a9546SAutomerger Merge Worker 	{ "60", IPPROTO_DSTOPTS },
44*a71a9546SAutomerger Merge Worker 	{ "43", IPPROTO_ROUTING },
45*a71a9546SAutomerger Merge Worker 	{ "44", IPPROTO_FRAGMENT },
46*a71a9546SAutomerger Merge Worker 	{ "51", IPPROTO_AH },
47*a71a9546SAutomerger Merge Worker 	{ "50", IPPROTO_ESP },
48*a71a9546SAutomerger Merge Worker 	{ "59", IPPROTO_NONE },
49*a71a9546SAutomerger Merge Worker 	{ "255", IPPROTO_RAW },
50*a71a9546SAutomerger Merge Worker 	/* { "all", 0 }, */
51*a71a9546SAutomerger Merge Worker };
52*a71a9546SAutomerger Merge Worker 
53*a71a9546SAutomerger Merge Worker static const struct numflag chain_flags[] = {
54*a71a9546SAutomerger Merge Worker 	{ IPPROTO_HOPOPTS, MASK_HOPOPTS },
55*a71a9546SAutomerger Merge Worker 	{ IPPROTO_DSTOPTS, MASK_DSTOPTS },
56*a71a9546SAutomerger Merge Worker 	{ IPPROTO_ROUTING, MASK_ROUTING },
57*a71a9546SAutomerger Merge Worker 	{ IPPROTO_FRAGMENT, MASK_FRAGMENT },
58*a71a9546SAutomerger Merge Worker 	{ IPPROTO_AH, MASK_AH },
59*a71a9546SAutomerger Merge Worker 	{ IPPROTO_ESP, MASK_ESP },
60*a71a9546SAutomerger Merge Worker 	{ IPPROTO_NONE, MASK_NONE },
61*a71a9546SAutomerger Merge Worker 	{ IPPROTO_RAW, MASK_PROTO },
62*a71a9546SAutomerger Merge Worker };
63*a71a9546SAutomerger Merge Worker 
64*a71a9546SAutomerger Merge Worker static const char *
proto_to_name(uint8_t proto,int nolookup)65*a71a9546SAutomerger Merge Worker proto_to_name(uint8_t proto, int nolookup)
66*a71a9546SAutomerger Merge Worker {
67*a71a9546SAutomerger Merge Worker         unsigned int i;
68*a71a9546SAutomerger Merge Worker 
69*a71a9546SAutomerger Merge Worker         if (proto && !nolookup) {
70*a71a9546SAutomerger Merge Worker 		const struct protoent *pent = getprotobynumber(proto);
71*a71a9546SAutomerger Merge Worker                 if (pent)
72*a71a9546SAutomerger Merge Worker                         return pent->p_name;
73*a71a9546SAutomerger Merge Worker         }
74*a71a9546SAutomerger Merge Worker 
75*a71a9546SAutomerger Merge Worker         for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
76*a71a9546SAutomerger Merge Worker                 if (chain_protos[i].num == proto)
77*a71a9546SAutomerger Merge Worker                         return chain_protos[i].name;
78*a71a9546SAutomerger Merge Worker 
79*a71a9546SAutomerger Merge Worker         return NULL;
80*a71a9546SAutomerger Merge Worker }
81*a71a9546SAutomerger Merge Worker 
82*a71a9546SAutomerger Merge Worker static uint16_t
name_to_proto(const char * s)83*a71a9546SAutomerger Merge Worker name_to_proto(const char *s)
84*a71a9546SAutomerger Merge Worker {
85*a71a9546SAutomerger Merge Worker         unsigned int proto=0;
86*a71a9546SAutomerger Merge Worker 	const struct protoent *pent;
87*a71a9546SAutomerger Merge Worker 
88*a71a9546SAutomerger Merge Worker         if ((pent = getprotobyname(s)))
89*a71a9546SAutomerger Merge Worker         	proto = pent->p_proto;
90*a71a9546SAutomerger Merge Worker         else {
91*a71a9546SAutomerger Merge Worker         	unsigned int i;
92*a71a9546SAutomerger Merge Worker         	for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
93*a71a9546SAutomerger Merge Worker         		if (strcmp(s, chain_protos[i].name) == 0) {
94*a71a9546SAutomerger Merge Worker         			proto = chain_protos[i].num;
95*a71a9546SAutomerger Merge Worker         			break;
96*a71a9546SAutomerger Merge Worker         		}
97*a71a9546SAutomerger Merge Worker 
98*a71a9546SAutomerger Merge Worker 		if (i == ARRAY_SIZE(chain_protos))
99*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM,
100*a71a9546SAutomerger Merge Worker         			"unknown header `%s' specified",
101*a71a9546SAutomerger Merge Worker         			s);
102*a71a9546SAutomerger Merge Worker         }
103*a71a9546SAutomerger Merge Worker 
104*a71a9546SAutomerger Merge Worker         return proto;
105*a71a9546SAutomerger Merge Worker }
106*a71a9546SAutomerger Merge Worker 
107*a71a9546SAutomerger Merge Worker static unsigned int
add_proto_to_mask(int proto)108*a71a9546SAutomerger Merge Worker add_proto_to_mask(int proto){
109*a71a9546SAutomerger Merge Worker 	unsigned int i=0, flag=0;
110*a71a9546SAutomerger Merge Worker 
111*a71a9546SAutomerger Merge Worker 	for (i = 0; i < ARRAY_SIZE(chain_flags); ++i)
112*a71a9546SAutomerger Merge Worker 			if (proto == chain_flags[i].proto){
113*a71a9546SAutomerger Merge Worker 				flag = chain_flags[i].flag;
114*a71a9546SAutomerger Merge Worker 				break;
115*a71a9546SAutomerger Merge Worker 			}
116*a71a9546SAutomerger Merge Worker 
117*a71a9546SAutomerger Merge Worker 	if (i == ARRAY_SIZE(chain_flags))
118*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
119*a71a9546SAutomerger Merge Worker 		"unknown header `%d' specified",
120*a71a9546SAutomerger Merge Worker 		proto);
121*a71a9546SAutomerger Merge Worker 
122*a71a9546SAutomerger Merge Worker 	return flag;
123*a71a9546SAutomerger Merge Worker }
124*a71a9546SAutomerger Merge Worker 
ipv6header_help(void)125*a71a9546SAutomerger Merge Worker static void ipv6header_help(void)
126*a71a9546SAutomerger Merge Worker {
127*a71a9546SAutomerger Merge Worker 	printf(
128*a71a9546SAutomerger Merge Worker "ipv6header match options:\n"
129*a71a9546SAutomerger Merge Worker "[!] --header headers     Type of header to match, by name\n"
130*a71a9546SAutomerger Merge Worker "                         names: hop,dst,route,frag,auth,esp,none,prot\n"
131*a71a9546SAutomerger Merge Worker "                    long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
132*a71a9546SAutomerger Merge Worker "                                ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
133*a71a9546SAutomerger Merge Worker "                       numbers: 0,60,43,44,51,50,59\n"
134*a71a9546SAutomerger Merge Worker "--soft                    The header CONTAINS the specified extensions\n");
135*a71a9546SAutomerger Merge Worker }
136*a71a9546SAutomerger Merge Worker 
137*a71a9546SAutomerger Merge Worker static const struct xt_option_entry ipv6header_opts[] = {
138*a71a9546SAutomerger Merge Worker 	{.name = "header", .id = O_HEADER, .type = XTTYPE_STRING,
139*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_MAND | XTOPT_INVERT},
140*a71a9546SAutomerger Merge Worker 	{.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE},
141*a71a9546SAutomerger Merge Worker 	XTOPT_TABLEEND,
142*a71a9546SAutomerger Merge Worker };
143*a71a9546SAutomerger Merge Worker 
144*a71a9546SAutomerger Merge Worker static unsigned int
parse_header(const char * flags)145*a71a9546SAutomerger Merge Worker parse_header(const char *flags) {
146*a71a9546SAutomerger Merge Worker         unsigned int ret = 0;
147*a71a9546SAutomerger Merge Worker         char *ptr;
148*a71a9546SAutomerger Merge Worker         char *buffer;
149*a71a9546SAutomerger Merge Worker 
150*a71a9546SAutomerger Merge Worker         buffer = xtables_strdup(flags);
151*a71a9546SAutomerger Merge Worker 
152*a71a9546SAutomerger Merge Worker         for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
153*a71a9546SAutomerger Merge Worker 		ret |= add_proto_to_mask(name_to_proto(ptr));
154*a71a9546SAutomerger Merge Worker 
155*a71a9546SAutomerger Merge Worker         free(buffer);
156*a71a9546SAutomerger Merge Worker         return ret;
157*a71a9546SAutomerger Merge Worker }
158*a71a9546SAutomerger Merge Worker 
ipv6header_parse(struct xt_option_call * cb)159*a71a9546SAutomerger Merge Worker static void ipv6header_parse(struct xt_option_call *cb)
160*a71a9546SAutomerger Merge Worker {
161*a71a9546SAutomerger Merge Worker 	struct ip6t_ipv6header_info *info = cb->data;
162*a71a9546SAutomerger Merge Worker 
163*a71a9546SAutomerger Merge Worker 	xtables_option_parse(cb);
164*a71a9546SAutomerger Merge Worker 	switch (cb->entry->id) {
165*a71a9546SAutomerger Merge Worker 	case O_HEADER:
166*a71a9546SAutomerger Merge Worker 		if (!(info->matchflags = parse_header(cb->arg)))
167*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
168*a71a9546SAutomerger Merge Worker 		if (cb->invert)
169*a71a9546SAutomerger Merge Worker 			info->invflags |= 0xFF;
170*a71a9546SAutomerger Merge Worker 		break;
171*a71a9546SAutomerger Merge Worker 	case O_SOFT:
172*a71a9546SAutomerger Merge Worker 		info->modeflag |= 0xFF;
173*a71a9546SAutomerger Merge Worker 		break;
174*a71a9546SAutomerger Merge Worker 	}
175*a71a9546SAutomerger Merge Worker }
176*a71a9546SAutomerger Merge Worker 
177*a71a9546SAutomerger Merge Worker static void
print_header(uint8_t flags)178*a71a9546SAutomerger Merge Worker print_header(uint8_t flags){
179*a71a9546SAutomerger Merge Worker         int have_flag = 0;
180*a71a9546SAutomerger Merge Worker 
181*a71a9546SAutomerger Merge Worker         while (flags) {
182*a71a9546SAutomerger Merge Worker                 unsigned int i;
183*a71a9546SAutomerger Merge Worker 
184*a71a9546SAutomerger Merge Worker                 for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
185*a71a9546SAutomerger Merge Worker 
186*a71a9546SAutomerger Merge Worker                 if (have_flag)
187*a71a9546SAutomerger Merge Worker                         printf(",");
188*a71a9546SAutomerger Merge Worker 
189*a71a9546SAutomerger Merge Worker                 printf("%s", proto_to_name(chain_flags[i].proto,0));
190*a71a9546SAutomerger Merge Worker                 have_flag = 1;
191*a71a9546SAutomerger Merge Worker 
192*a71a9546SAutomerger Merge Worker                 flags &= ~chain_flags[i].flag;
193*a71a9546SAutomerger Merge Worker         }
194*a71a9546SAutomerger Merge Worker 
195*a71a9546SAutomerger Merge Worker         if (!have_flag)
196*a71a9546SAutomerger Merge Worker                 printf("NONE");
197*a71a9546SAutomerger Merge Worker }
198*a71a9546SAutomerger Merge Worker 
ipv6header_print(const void * ip,const struct xt_entry_match * match,int numeric)199*a71a9546SAutomerger Merge Worker static void ipv6header_print(const void *ip,
200*a71a9546SAutomerger Merge Worker                              const struct xt_entry_match *match, int numeric)
201*a71a9546SAutomerger Merge Worker {
202*a71a9546SAutomerger Merge Worker 	const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
203*a71a9546SAutomerger Merge Worker 	printf(" ipv6header");
204*a71a9546SAutomerger Merge Worker 
205*a71a9546SAutomerger Merge Worker         if (info->matchflags || info->invflags) {
206*a71a9546SAutomerger Merge Worker 		printf(" flags:%s", info->invflags ? "!" : "");
207*a71a9546SAutomerger Merge Worker                 if (numeric)
208*a71a9546SAutomerger Merge Worker 			printf("0x%02X", info->matchflags);
209*a71a9546SAutomerger Merge Worker                 else {
210*a71a9546SAutomerger Merge Worker                         print_header(info->matchflags);
211*a71a9546SAutomerger Merge Worker                 }
212*a71a9546SAutomerger Merge Worker         }
213*a71a9546SAutomerger Merge Worker 
214*a71a9546SAutomerger Merge Worker 	if (info->modeflag)
215*a71a9546SAutomerger Merge Worker 		printf(" soft");
216*a71a9546SAutomerger Merge Worker }
217*a71a9546SAutomerger Merge Worker 
ipv6header_save(const void * ip,const struct xt_entry_match * match)218*a71a9546SAutomerger Merge Worker static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
219*a71a9546SAutomerger Merge Worker {
220*a71a9546SAutomerger Merge Worker 
221*a71a9546SAutomerger Merge Worker 	const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
222*a71a9546SAutomerger Merge Worker 
223*a71a9546SAutomerger Merge Worker 	printf("%s --header ", info->invflags ? " !" : "");
224*a71a9546SAutomerger Merge Worker 	print_header(info->matchflags);
225*a71a9546SAutomerger Merge Worker 	if (info->modeflag)
226*a71a9546SAutomerger Merge Worker 		printf(" --soft");
227*a71a9546SAutomerger Merge Worker }
228*a71a9546SAutomerger Merge Worker 
229*a71a9546SAutomerger Merge Worker static struct xtables_match ipv6header_mt6_reg = {
230*a71a9546SAutomerger Merge Worker 	.name		= "ipv6header",
231*a71a9546SAutomerger Merge Worker 	.version	= XTABLES_VERSION,
232*a71a9546SAutomerger Merge Worker 	.family		= NFPROTO_IPV6,
233*a71a9546SAutomerger Merge Worker 	.size		= XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
234*a71a9546SAutomerger Merge Worker 	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
235*a71a9546SAutomerger Merge Worker 	.help		= ipv6header_help,
236*a71a9546SAutomerger Merge Worker 	.print		= ipv6header_print,
237*a71a9546SAutomerger Merge Worker 	.save		= ipv6header_save,
238*a71a9546SAutomerger Merge Worker 	.x6_parse	= ipv6header_parse,
239*a71a9546SAutomerger Merge Worker 	.x6_options	= ipv6header_opts,
240*a71a9546SAutomerger Merge Worker };
241*a71a9546SAutomerger Merge Worker 
_init(void)242*a71a9546SAutomerger Merge Worker void _init(void)
243*a71a9546SAutomerger Merge Worker {
244*a71a9546SAutomerger Merge Worker 	xtables_register_match(&ipv6header_mt6_reg);
245*a71a9546SAutomerger Merge Worker }
246