xref: /aosp_15_r20/external/iptables/extensions/libipt_icmp.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_ipv4/ip_tables.h>
7 
8 #include "libxt_icmp.h"
9 
10 /* special hack for icmp-type 'any':
11  * Up to kernel <=2.4.20 the problem was:
12  * '-p icmp ' matches all icmp packets
13  * '-p icmp -m icmp' matches _only_ ICMP type 0 :(
14  * This is now fixed by initializing the field * to icmp type 0xFF
15  * See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37
16  */
17 
18 enum {
19 	O_ICMP_TYPE = 0,
20 };
21 
icmp_help(void)22 static void icmp_help(void)
23 {
24 	printf(
25 "icmp match options:\n"
26 "[!] --icmp-type typename	match icmp type\n"
27 "[!] --icmp-type type[/code]	(or numeric type or type/code)\n");
28 	printf("Valid ICMP Types:");
29 	xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
30 }
31 
32 static const struct xt_option_entry icmp_opts[] = {
33 	{.name = "icmp-type", .id = O_ICMP_TYPE, .type = XTTYPE_STRING,
34 	 .flags = XTOPT_MAND | XTOPT_INVERT},
35 	XTOPT_TABLEEND,
36 };
37 
icmp_init(struct xt_entry_match * m)38 static void icmp_init(struct xt_entry_match *m)
39 {
40 	struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
41 
42 	icmpinfo->type = 0xFF;
43 	icmpinfo->code[1] = 0xFF;
44 }
45 
icmp_parse(struct xt_option_call * cb)46 static void icmp_parse(struct xt_option_call *cb)
47 {
48 	struct ipt_icmp *icmpinfo = cb->data;
49 
50 	xtables_option_parse(cb);
51 	ipt_parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
52 	if (cb->invert)
53 		icmpinfo->invflags |= IPT_ICMP_INV;
54 }
55 
print_icmptype(uint8_t type,uint8_t code_min,uint8_t code_max,int invert,int numeric)56 static void print_icmptype(uint8_t type,
57 			   uint8_t code_min, uint8_t code_max,
58 			   int invert,
59 			   int numeric)
60 {
61 	if (!numeric) {
62 		unsigned int i;
63 
64 		for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i)
65 			if (icmp_codes[i].type == type
66 			    && icmp_codes[i].code_min == code_min
67 			    && icmp_codes[i].code_max == code_max)
68 				break;
69 
70 		if (i != ARRAY_SIZE(icmp_codes)) {
71 			printf(" %s%s",
72 			       invert ? "!" : "",
73 			       icmp_codes[i].name);
74 			return;
75 		}
76 	}
77 
78 	if (invert)
79 		printf(" !");
80 
81 	printf("type %u", type);
82 	if (code_min == code_max)
83 		printf(" code %u", code_min);
84 	else if (code_min != 0 || code_max != 0xFF)
85 		printf(" codes %u-%u", code_min, code_max);
86 }
87 
icmp_print(const void * ip,const struct xt_entry_match * match,int numeric)88 static void icmp_print(const void *ip, const struct xt_entry_match *match,
89                        int numeric)
90 {
91 	const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
92 
93 	printf(" icmp");
94 	print_icmptype(icmp->type, icmp->code[0], icmp->code[1],
95 		       icmp->invflags & IPT_ICMP_INV,
96 		       numeric);
97 
98 	if (icmp->invflags & ~IPT_ICMP_INV)
99 		printf(" Unknown invflags: 0x%X",
100 		       icmp->invflags & ~IPT_ICMP_INV);
101 }
102 
icmp_save(const void * ip,const struct xt_entry_match * match)103 static void icmp_save(const void *ip, const struct xt_entry_match *match)
104 {
105 	const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
106 
107 	if (icmp->invflags & IPT_ICMP_INV)
108 		printf(" !");
109 
110 	/* special hack for 'any' case */
111 	if (icmp->type == 0xFF &&
112 	    icmp->code[0] == 0 && icmp->code[1] == 0xFF) {
113 		printf(" --icmp-type any");
114 	} else {
115 		printf(" --icmp-type %u", icmp->type);
116 		if (icmp->code[0] != 0 || icmp->code[1] != 0xFF)
117 			printf("/%u", icmp->code[0]);
118 	}
119 }
120 
type_xlate_print(struct xt_xlate * xl,unsigned int icmptype,unsigned int code_min,unsigned int code_max)121 static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
122 				     unsigned int code_min,
123 				     unsigned int code_max)
124 {
125 	unsigned int i;
126 
127 	if (code_min != code_max) {
128 		for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i)
129 			if (icmp_codes[i].type == icmptype &&
130 			    icmp_codes[i].code_min == code_min &&
131 			    icmp_codes[i].code_max == code_max) {
132 				xt_xlate_add(xl, "%s", icmp_codes[i].name);
133 				return 1;
134 			}
135 	}
136 
137 	return 0;
138 }
139 
icmp_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)140 static int icmp_xlate(struct xt_xlate *xl,
141 		      const struct xt_xlate_mt_params *params)
142 {
143 	const struct ipt_icmp *info = (struct ipt_icmp *)params->match->data;
144 
145 	if (info->type != 0xFF) {
146 		xt_xlate_add(xl, "icmp type%s ",
147 			     (info->invflags & IPT_ICMP_INV) ? " !=" : "");
148 
149 		if (!type_xlate_print(xl, info->type, info->code[0],
150 				      info->code[1]))
151 			return 0;
152 	} else {
153 		/* '-m icmp --icmp-type any' is a noop by itself,
154 		 * but it eats a (mandatory) previous '-p icmp' so
155 		 * emit it here */
156 		xt_xlate_add(xl, "ip protocol icmp");
157 	}
158 	return 1;
159 }
160 
161 static struct xtables_match icmp_mt_reg = {
162 	.name		= "icmp",
163 	.version	= XTABLES_VERSION,
164 	.family		= NFPROTO_IPV4,
165 	.size		= XT_ALIGN(sizeof(struct ipt_icmp)),
166 	.userspacesize	= XT_ALIGN(sizeof(struct ipt_icmp)),
167 	.help		= icmp_help,
168 	.init		= icmp_init,
169 	.print		= icmp_print,
170 	.save		= icmp_save,
171 	.x6_parse	= icmp_parse,
172 	.x6_options	= icmp_opts,
173 	.xlate		= icmp_xlate,
174 };
175 
_init(void)176 void _init(void)
177 {
178 	xtables_register_match(&icmp_mt_reg);
179 }
180