11b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt#include <stdint.h>
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h>
45d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h>
51b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt#include <limits.h> /* INT_MAX in ip6_tables.h */
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <linux/netfilter_ipv4/ip_tables.h>
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
8fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte/* special hack for icmp-type 'any':
9fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte * Up to kernel <=2.4.20 the problem was:
10fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte * '-p icmp ' matches all icmp packets
11fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte * '-p icmp -m icmp' matches _only_ ICMP type 0 :(
12fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte * This is now fixed by initializing the field * to icmp type 0xFF
13fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte * See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37
14fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte */
15fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte
161b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardtenum {
171b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	O_ICMP_TYPE = 0,
181b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt};
191b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt
20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct icmp_names {
21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *name;
227ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardt	uint8_t type;
237ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardt	uint8_t code_min, code_max;
24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const struct icmp_names icmp_codes[] = {
27fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte	{ "any", 0xFF, 0, 0xFF },
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "echo-reply", 0, 0, 0xFF },
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Alias */ { "pong", 0, 0, 0xFF },
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "destination-unreachable", 3, 0, 0xFF },
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "network-unreachable", 3, 0, 0 },
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "host-unreachable", 3, 1, 1 },
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "protocol-unreachable", 3, 2, 2 },
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "port-unreachable", 3, 3, 3 },
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "fragmentation-needed", 3, 4, 4 },
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "source-route-failed", 3, 5, 5 },
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "network-unknown", 3, 6, 6 },
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "host-unknown", 3, 7, 7 },
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "network-prohibited", 3, 9, 9 },
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "host-prohibited", 3, 10, 10 },
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "TOS-network-unreachable", 3, 11, 11 },
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "TOS-host-unreachable", 3, 12, 12 },
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "communication-prohibited", 3, 13, 13 },
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "host-precedence-violation", 3, 14, 14 },
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "precedence-cutoff", 3, 15, 15 },
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "source-quench", 4, 0, 0xFF },
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "redirect", 5, 0, 0xFF },
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "network-redirect", 5, 0, 0 },
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "host-redirect", 5, 1, 1 },
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "TOS-network-redirect", 5, 2, 2 },
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "TOS-host-redirect", 5, 3, 3 },
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "echo-request", 8, 0, 0xFF },
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Alias */ { "ping", 8, 0, 0xFF },
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "router-advertisement", 9, 0, 0xFF },
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "router-solicitation", 10, 0, 0xFF },
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "time-exceeded", 11, 0, 0xFF },
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "ttl-zero-during-transit", 11, 0, 0 },
66e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "ttl-zero-during-reassembly", 11, 1, 1 },
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "parameter-problem", 12, 0, 0xFF },
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "ip-header-bad", 12, 0, 0 },
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{   "required-option-missing", 12, 1, 1 },
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "timestamp-request", 13, 0, 0xFF },
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "timestamp-reply", 14, 0, 0xFF },
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "address-mask-request", 17, 0, 0xFF },
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "address-mask-reply", 18, 0, 0xFF }
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
82500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardyprint_icmptypes(void)
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Valid ICMP Types:");
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
872c69b55e55f2efc5a334b87ccdceaa9de0ecb658Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i) {
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && (icmp_codes[i].code_max
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				== icmp_codes[i-1].code_max))
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf(" (%s)", icmp_codes[i].name);
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("\n   %s", icmp_codes[i].name);
95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("\n%s", icmp_codes[i].name);
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
10259d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void icmp_help(void)
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf(
1058b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"icmp match options:\n"
106967279231a9ecfa99f26694a954afc535c63db1dJan Engelhardt"[!] --icmp-type typename	match icmp type\n"
1073d12c3bbffb43182df9ac5c0ad549b095d30d021Jan Engelhardt"[!] --icmp-type type[/code]	(or numeric type or type/code)\n");
108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_icmptypes();
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1111b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardtstatic const struct xt_option_entry icmp_opts[] = {
1121b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	{.name = "icmp-type", .id = O_ICMP_TYPE, .type = XTTYPE_STRING,
1131b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	 .flags = XTOPT_MAND | XTOPT_INVERT},
1141b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	XTOPT_TABLEEND,
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1178115e5425721cd610b6390c3d4c24540773b0520Pablo Neirastatic void
1187ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtparse_icmp(const char *icmptype, uint8_t *type, uint8_t code[])
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1202c69b55e55f2efc5a334b87ccdceaa9de0ecb658Jan Engelhardt	static const unsigned int limit = ARRAY_SIZE(icmp_codes);
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int match = limit;
122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < limit; i++) {
125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype))
126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    == 0) {
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (match != limit)
1281829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "Ambiguous ICMP type `%s':"
130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   " `%s' or `%s'?",
131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   icmptype,
132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   icmp_codes[match].name,
133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   icmp_codes[i].name);
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			match = i;
135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (match != limit) {
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*type = icmp_codes[match].type;
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		code[0] = icmp_codes[match].code_min;
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		code[1] = icmp_codes[match].code_max;
142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		char *slash;
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		char buffer[strlen(icmptype) + 1];
145b47197629735fa1cb93112dfd7d1c4fbcdb24a95Harald Welte		unsigned int number;
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		strcpy(buffer, icmptype);
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		slash = strchr(buffer, '/');
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (slash)
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			*slash = '\0';
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1535f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
1541829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Invalid ICMP type `%s'\n", buffer);
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*type = number;
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (slash) {
1585f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt			if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
1591829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt				xtables_error(PARAMETER_PROBLEM,
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "Invalid ICMP code `%s'\n",
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   slash+1);
162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			code[0] = code[1] = number;
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else {
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			code[0] = 0;
165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			code[1] = 0xFF;
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
17059d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void icmp_init(struct xt_entry_match *m)
171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
174fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte	icmpinfo->type = 0xFF;
175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	icmpinfo->code[1] = 0xFF;
176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1781b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardtstatic void icmp_parse(struct xt_option_call *cb)
179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1801b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	struct ipt_icmp *icmpinfo = cb->data;
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1821b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	xtables_option_parse(cb);
1831b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
1841b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	if (cb->invert)
1851b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt		icmpinfo->invflags |= IPT_ICMP_INV;
186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1887ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtstatic void print_icmptype(uint8_t type,
1897ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardt			   uint8_t code_min, uint8_t code_max,
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   int invert,
191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   int numeric)
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!numeric) {
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1962c69b55e55f2efc5a334b87ccdceaa9de0ecb658Jan Engelhardt		for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i)
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (icmp_codes[i].type == type
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && icmp_codes[i].code_min == code_min
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && icmp_codes[i].code_max == code_max)
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				break;
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2022c69b55e55f2efc5a334b87ccdceaa9de0ecb658Jan Engelhardt		if (i != ARRAY_SIZE(icmp_codes)) {
20373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" %s%s",
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       invert ? "!" : "",
205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       icmp_codes[i].name);
206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return;
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (invert)
21173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" !");
212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("type %u", type);
21473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	if (code_min == code_max)
21573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" code %u", code_min);
21673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	else if (code_min != 0 || code_max != 0xFF)
21773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" codes %u-%u", code_min, code_max);
218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
22059d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void icmp_print(const void *ip, const struct xt_entry_match *match,
22159d164019340d110d302634e429320577f0db7beJan Engelhardt                       int numeric)
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
22573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" icmp");
226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_icmptype(icmp->type, icmp->code[0], icmp->code[1],
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       icmp->invflags & IPT_ICMP_INV,
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       numeric);
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (icmp->invflags & ~IPT_ICMP_INV)
23173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" Unknown invflags: 0x%X",
232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       icmp->invflags & ~IPT_ICMP_INV);
233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
23559d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void icmp_save(const void *ip, const struct xt_entry_match *match)
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (icmp->invflags & IPT_ICMP_INV)
24073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" !");
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
242fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte	/* special hack for 'any' case */
243fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte	if (icmp->type == 0xFF) {
24473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --icmp-type any");
245fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte	} else {
24673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --icmp-type %u", icmp->type);
247fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte		if (icmp->code[0] != 0 || icmp->code[1] != 0xFF)
248fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte			printf("/%u", icmp->code[0]);
249fc9237da4e8455e34193a56e56e561d7cd0b31baHarald Welte	}
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2528b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_match icmp_mt_reg = {
2538caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira	.name		= "icmp",
2548b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.version	= XTABLES_VERSION,
25503d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt	.family		= NFPROTO_IPV4,
2568b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.size		= XT_ALIGN(sizeof(struct ipt_icmp)),
2578b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.userspacesize	= XT_ALIGN(sizeof(struct ipt_icmp)),
25859d164019340d110d302634e429320577f0db7beJan Engelhardt	.help		= icmp_help,
25959d164019340d110d302634e429320577f0db7beJan Engelhardt	.init		= icmp_init,
26059d164019340d110d302634e429320577f0db7beJan Engelhardt	.print		= icmp_print,
26159d164019340d110d302634e429320577f0db7beJan Engelhardt	.save		= icmp_save,
2621b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	.x6_parse	= icmp_parse,
2631b8db4f4ca250f13a0e7edddb31cfc1f82d42806Jan Engelhardt	.x6_options	= icmp_opts,
264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid _init(void)
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2688b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	xtables_register_match(&icmp_mt_reg);
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
270