xref: /aosp_15_r20/external/iptables/extensions/libip6t_icmp6.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <xtables.h>
5 #include <limits.h> /* INT_MAX in ip6_tables.h */
6 #include <linux/netfilter_ipv6/ip6_tables.h>
7 #include <netinet/icmp6.h>
8 
9 #include "libxt_icmp.h"
10 
11 enum {
12 	O_ICMPV6_TYPE = 0,
13 };
14 
icmp6_help(void)15 static void icmp6_help(void)
16 {
17 	printf(
18 "icmpv6 match options:\n"
19 "[!] --icmpv6-type typename	match icmpv6 type\n"
20 "				(or numeric type or type/code)\n");
21 	printf("Valid ICMPv6 Types:");
22 	xt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
23 }
24 
25 static const struct xt_option_entry icmp6_opts[] = {
26 	{.name = "icmpv6-type", .id = O_ICMPV6_TYPE, .type = XTTYPE_STRING,
27 	 .flags = XTOPT_MAND | XTOPT_INVERT},
28 	XTOPT_TABLEEND,
29 };
30 
icmp6_init(struct xt_entry_match * m)31 static void icmp6_init(struct xt_entry_match *m)
32 {
33 	struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
34 
35 	icmpv6info->code[1] = 0xFF;
36 }
37 
icmp6_parse(struct xt_option_call * cb)38 static void icmp6_parse(struct xt_option_call *cb)
39 {
40 	struct ip6t_icmp *icmpv6info = cb->data;
41 
42 	xtables_option_parse(cb);
43 	ipt_parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
44 	if (cb->invert)
45 		icmpv6info->invflags |= IP6T_ICMP_INV;
46 }
47 
print_icmpv6type(uint8_t type,uint8_t code_min,uint8_t code_max,int invert,int numeric)48 static void print_icmpv6type(uint8_t type,
49 			   uint8_t code_min, uint8_t code_max,
50 			   int invert,
51 			   int numeric)
52 {
53 	if (!numeric) {
54 		unsigned int i;
55 
56 		for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
57 			if (icmpv6_codes[i].type == type
58 			    && icmpv6_codes[i].code_min == code_min
59 			    && icmpv6_codes[i].code_max == code_max)
60 				break;
61 
62 		if (i != ARRAY_SIZE(icmpv6_codes)) {
63 			printf(" %s%s",
64 			       invert ? "!" : "",
65 			       icmpv6_codes[i].name);
66 			return;
67 		}
68 	}
69 
70 	if (invert)
71 		printf(" !");
72 
73 	printf("type %u", type);
74 	if (code_min == code_max)
75 		printf(" code %u", code_min);
76 	else if (code_min != 0 || code_max != 0xFF)
77 		printf(" codes %u-%u", code_min, code_max);
78 }
79 
icmp6_print(const void * ip,const struct xt_entry_match * match,int numeric)80 static void icmp6_print(const void *ip, const struct xt_entry_match *match,
81                         int numeric)
82 {
83 	const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
84 
85 	printf(" ipv6-icmp");
86 	print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1],
87 		       icmpv6->invflags & IP6T_ICMP_INV,
88 		       numeric);
89 
90 	if (icmpv6->invflags & ~IP6T_ICMP_INV)
91 		printf(" Unknown invflags: 0x%X",
92 		       icmpv6->invflags & ~IP6T_ICMP_INV);
93 }
94 
icmp6_save(const void * ip,const struct xt_entry_match * match)95 static void icmp6_save(const void *ip, const struct xt_entry_match *match)
96 {
97 	const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
98 
99 	if (icmpv6->invflags & IP6T_ICMP_INV)
100 		printf(" !");
101 
102 	printf(" --icmpv6-type %u", icmpv6->type);
103 	if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF)
104 		printf("/%u", icmpv6->code[0]);
105 }
106 
107 #define XT_ICMPV6_TYPE(type)	(type - ND_ROUTER_SOLICIT)
108 
109 static const char *icmp6_type_xlate_array[] = {
110 	[XT_ICMPV6_TYPE(ND_ROUTER_SOLICIT)]	= "nd-router-solicit",
111 	[XT_ICMPV6_TYPE(ND_ROUTER_ADVERT)]	= "nd-router-advert",
112 	[XT_ICMPV6_TYPE(ND_NEIGHBOR_SOLICIT)]	= "nd-neighbor-solicit",
113 	[XT_ICMPV6_TYPE(ND_NEIGHBOR_ADVERT)]	= "nd-neighbor-advert",
114 	[XT_ICMPV6_TYPE(ND_REDIRECT)]		= "nd-redirect",
115 };
116 
icmp6_type_xlate(unsigned int type)117 static const char *icmp6_type_xlate(unsigned int type)
118 {
119 	if (type < ND_ROUTER_SOLICIT || type > ND_REDIRECT)
120 		return NULL;
121 
122 	return icmp6_type_xlate_array[XT_ICMPV6_TYPE(type)];
123 }
124 
type_xlate_print(struct xt_xlate * xl,unsigned int icmptype,unsigned int code_min,unsigned int code_max)125 static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
126 				     unsigned int code_min,
127 				     unsigned int code_max)
128 {
129 	unsigned int i;
130 	const char *type_name;
131 
132 	if (code_min == code_max)
133 		return 0;
134 
135 	type_name = icmp6_type_xlate(icmptype);
136 
137 	if (type_name) {
138 		xt_xlate_add(xl, "%s", type_name);
139 	} else {
140 		for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
141 			if (icmpv6_codes[i].type == icmptype &&
142 			    icmpv6_codes[i].code_min == code_min &&
143 			    icmpv6_codes[i].code_max == code_max)
144 				break;
145 
146 		if (i != ARRAY_SIZE(icmpv6_codes))
147 			xt_xlate_add(xl, "%s", icmpv6_codes[i].name);
148 		else
149 			return 0;
150 	}
151 
152 	return 1;
153 }
154 
icmp6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)155 static int icmp6_xlate(struct xt_xlate *xl,
156 		       const struct xt_xlate_mt_params *params)
157 {
158 	const struct ip6t_icmp *info = (struct ip6t_icmp *)params->match->data;
159 
160 	xt_xlate_add(xl, "icmpv6 type%s ",
161 		     (info->invflags & IP6T_ICMP_INV) ? " !=" : "");
162 
163 	if (!type_xlate_print(xl, info->type, info->code[0], info->code[1]))
164 		return 0;
165 
166 	return 1;
167 }
168 
169 static struct xtables_match icmp6_mt6_reg = {
170 	.name 		= "icmp6",
171 	.version 	= XTABLES_VERSION,
172 	.family		= NFPROTO_IPV6,
173 	.size		= XT_ALIGN(sizeof(struct ip6t_icmp)),
174 	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_icmp)),
175 	.help		= icmp6_help,
176 	.init		= icmp6_init,
177 	.print		= icmp6_print,
178 	.save		= icmp6_save,
179 	.x6_parse	= icmp6_parse,
180 	.x6_options	= icmp6_opts,
181 	.xlate		= icmp6_xlate,
182 };
183 
_init(void)184 void _init(void)
185 {
186 	xtables_register_match(&icmp6_mt6_reg);
187 }
188