blob: 0678aac3939c675a56ea47dbe5e29ebc230b7886 [file] [log] [blame]
Jan Engelhardtddac6c52008-09-01 14:22:19 +02001/* Shared library add-on to ip6tables to add ICMP support. */
Philip Blundellb47050c2000-06-04 17:38:47 +00002#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01007#include <xtables.h>
Jan Engelhardt4e418542009-02-21 03:46:37 +01008#include <limits.h> /* INT_MAX in ip6_tables.h */
Philip Blundellb47050c2000-06-04 17:38:47 +00009#include <linux/netfilter_ipv6/ip6_tables.h>
10
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000011struct icmpv6_names {
Philip Blundellb47050c2000-06-04 17:38:47 +000012 const char *name;
13 u_int8_t type;
14 u_int8_t code_min, code_max;
15};
16
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000017static const struct icmpv6_names icmpv6_codes[] = {
Philip Blundellb47050c2000-06-04 17:38:47 +000018 { "destination-unreachable", 1, 0, 0xFF },
19 { "no-route", 1, 0, 0 },
20 { "communication-prohibited", 1, 1, 1 },
21 { "address-unreachable", 1, 3, 3 },
22 { "port-unreachable", 1, 4, 4 },
23
24 { "packet-too-big", 2, 0, 0xFF },
25
26 { "time-exceeded", 3, 0, 0xFF },
27 /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
28 { "ttl-zero-during-transit", 3, 0, 0 },
29 { "ttl-zero-during-reassembly", 3, 1, 1 },
30
31 { "parameter-problem", 4, 0, 0xFF },
32 { "bad-header", 4, 0, 0 },
33 { "unknown-header-type", 4, 1, 1 },
34 { "unknown-option", 4, 2, 2 },
35
36 { "echo-request", 128, 0, 0xFF },
37 /* Alias */ { "ping", 128, 0, 0xFF },
38
39 { "echo-reply", 129, 0, 0xFF },
40 /* Alias */ { "pong", 129, 0, 0xFF },
41
42 { "router-solicitation", 133, 0, 0xFF },
43
44 { "router-advertisement", 134, 0, 0xFF },
45
46 { "neighbour-solicitation", 135, 0, 0xFF },
47 /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
48
49 { "neighbour-advertisement", 136, 0, 0xFF },
50 /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
51
52 { "redirect", 137, 0, 0xFF },
53
54};
55
56static void
Patrick McHardy500f4832007-09-08 15:59:04 +000057print_icmpv6types(void)
Philip Blundellb47050c2000-06-04 17:38:47 +000058{
59 unsigned int i;
60 printf("Valid ICMPv6 Types:");
61
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000062 for (i = 0; i < sizeof(icmpv6_codes)/sizeof(struct icmpv6_names); i++) {
63 if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
64 if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
65 && (icmpv6_codes[i].code_max
66 == icmpv6_codes[i-1].code_max))
67 printf(" (%s)", icmpv6_codes[i].name);
Philip Blundellb47050c2000-06-04 17:38:47 +000068 else
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000069 printf("\n %s", icmpv6_codes[i].name);
Philip Blundellb47050c2000-06-04 17:38:47 +000070 }
71 else
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000072 printf("\n%s", icmpv6_codes[i].name);
Philip Blundellb47050c2000-06-04 17:38:47 +000073 }
74 printf("\n");
75}
76
Jan Engelhardt997045f2007-10-04 16:29:21 +000077static void icmp6_help(void)
Philip Blundellb47050c2000-06-04 17:38:47 +000078{
79 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020080"icmpv6 match options:\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020081"[!] --icmpv6-type typename match icmpv6 type\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020082" (or numeric type or type/code)\n");
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000083 print_icmpv6types();
Philip Blundellb47050c2000-06-04 17:38:47 +000084}
85
Jan Engelhardt997045f2007-10-04 16:29:21 +000086static const struct option icmp6_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000087 { "icmpv6-type", 1, NULL, '1' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000088 { .name = NULL }
Philip Blundellb47050c2000-06-04 17:38:47 +000089};
90
Pablo Neira8115e542005-02-14 13:13:04 +000091static void
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000092parse_icmpv6(const char *icmpv6type, u_int8_t *type, u_int8_t code[])
Philip Blundellb47050c2000-06-04 17:38:47 +000093{
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000094 unsigned int limit = sizeof(icmpv6_codes)/sizeof(struct icmpv6_names);
Philip Blundellb47050c2000-06-04 17:38:47 +000095 unsigned int match = limit;
96 unsigned int i;
97
98 for (i = 0; i < limit; i++) {
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +000099 if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
Philip Blundellb47050c2000-06-04 17:38:47 +0000100 == 0) {
101 if (match != limit)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100102 xtables_error(PARAMETER_PROBLEM,
Philip Blundellb47050c2000-06-04 17:38:47 +0000103 "Ambiguous ICMPv6 type `%s':"
104 " `%s' or `%s'?",
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000105 icmpv6type,
106 icmpv6_codes[match].name,
107 icmpv6_codes[i].name);
Philip Blundellb47050c2000-06-04 17:38:47 +0000108 match = i;
109 }
110 }
111
112 if (match != limit) {
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000113 *type = icmpv6_codes[match].type;
114 code[0] = icmpv6_codes[match].code_min;
115 code[1] = icmpv6_codes[match].code_max;
Philip Blundellb47050c2000-06-04 17:38:47 +0000116 } else {
117 char *slash;
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000118 char buffer[strlen(icmpv6type) + 1];
Harald Welteb4719762001-07-23 02:14:22 +0000119 unsigned int number;
Philip Blundellb47050c2000-06-04 17:38:47 +0000120
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000121 strcpy(buffer, icmpv6type);
Philip Blundellb47050c2000-06-04 17:38:47 +0000122 slash = strchr(buffer, '/');
123
124 if (slash)
125 *slash = '\0';
126
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100127 if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100128 xtables_error(PARAMETER_PROBLEM,
Philip Blundellb47050c2000-06-04 17:38:47 +0000129 "Invalid ICMPv6 type `%s'\n", buffer);
130 *type = number;
131 if (slash) {
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100132 if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100133 xtables_error(PARAMETER_PROBLEM,
Philip Blundellb47050c2000-06-04 17:38:47 +0000134 "Invalid ICMPv6 code `%s'\n",
135 slash+1);
136 code[0] = code[1] = number;
137 } else {
138 code[0] = 0;
139 code[1] = 0xFF;
140 }
141 }
Philip Blundellb47050c2000-06-04 17:38:47 +0000142}
143
Jan Engelhardt997045f2007-10-04 16:29:21 +0000144static void icmp6_init(struct xt_entry_match *m)
Philip Blundellb47050c2000-06-04 17:38:47 +0000145{
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000146 struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
Philip Blundellb47050c2000-06-04 17:38:47 +0000147
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000148 icmpv6info->code[1] = 0xFF;
Philip Blundellb47050c2000-06-04 17:38:47 +0000149}
150
Jan Engelhardt997045f2007-10-04 16:29:21 +0000151static int icmp6_parse(int c, char **argv, int invert, unsigned int *flags,
152 const void *entry, struct xt_entry_match **match)
Philip Blundellb47050c2000-06-04 17:38:47 +0000153{
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000154 struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)(*match)->data;
Philip Blundellb47050c2000-06-04 17:38:47 +0000155
156 switch (c) {
157 case '1':
Yasuyuki KOZAKAIb1cda882006-07-04 10:23:26 +0000158 if (*flags == 1)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100159 xtables_error(PARAMETER_PROBLEM,
Yasuyuki KOZAKAIb1cda882006-07-04 10:23:26 +0000160 "icmpv6 match: only use --icmpv6-type once!");
Jan Engelhardt0f16c722009-01-30 04:55:38 +0100161 xtables_check_inverse(optarg, &invert, &optind, 0);
Pablo Neira8115e542005-02-14 13:13:04 +0000162 parse_icmpv6(argv[optind-1], &icmpv6info->type,
163 icmpv6info->code);
Philip Blundellb47050c2000-06-04 17:38:47 +0000164 if (invert)
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000165 icmpv6info->invflags |= IP6T_ICMP_INV;
Yasuyuki KOZAKAIb1cda882006-07-04 10:23:26 +0000166 *flags = 1;
Philip Blundellb47050c2000-06-04 17:38:47 +0000167 break;
168
169 default:
170 return 0;
171 }
172
173 return 1;
174}
175
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000176static void print_icmpv6type(u_int8_t type,
Philip Blundellb47050c2000-06-04 17:38:47 +0000177 u_int8_t code_min, u_int8_t code_max,
178 int invert,
179 int numeric)
180{
181 if (!numeric) {
182 unsigned int i;
183
184 for (i = 0;
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000185 i < sizeof(icmpv6_codes)/sizeof(struct icmpv6_names);
Philip Blundellb47050c2000-06-04 17:38:47 +0000186 i++) {
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000187 if (icmpv6_codes[i].type == type
188 && icmpv6_codes[i].code_min == code_min
189 && icmpv6_codes[i].code_max == code_max)
Philip Blundellb47050c2000-06-04 17:38:47 +0000190 break;
191 }
192
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000193 if (i != sizeof(icmpv6_codes)/sizeof(struct icmpv6_names)) {
Philip Blundellb47050c2000-06-04 17:38:47 +0000194 printf("%s%s ",
195 invert ? "!" : "",
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000196 icmpv6_codes[i].name);
Philip Blundellb47050c2000-06-04 17:38:47 +0000197 return;
198 }
199 }
200
201 if (invert)
202 printf("!");
203
204 printf("type %u", type);
205 if (code_min == 0 && code_max == 0xFF)
206 printf(" ");
207 else if (code_min == code_max)
208 printf(" code %u ", code_min);
209 else
210 printf(" codes %u-%u ", code_min, code_max);
211}
212
Jan Engelhardt997045f2007-10-04 16:29:21 +0000213static void icmp6_print(const void *ip, const struct xt_entry_match *match,
214 int numeric)
Philip Blundellb47050c2000-06-04 17:38:47 +0000215{
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000216 const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
Philip Blundellb47050c2000-06-04 17:38:47 +0000217
Harald Weltecfaed1f2001-10-04 08:11:44 +0000218 printf("ipv6-icmp ");
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000219 print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1],
220 icmpv6->invflags & IP6T_ICMP_INV,
Philip Blundellb47050c2000-06-04 17:38:47 +0000221 numeric);
222
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000223 if (icmpv6->invflags & ~IP6T_ICMP_INV)
Philip Blundellb47050c2000-06-04 17:38:47 +0000224 printf("Unknown invflags: 0x%X ",
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000225 icmpv6->invflags & ~IP6T_ICMP_INV);
Philip Blundellb47050c2000-06-04 17:38:47 +0000226}
227
Jan Engelhardt997045f2007-10-04 16:29:21 +0000228static void icmp6_save(const void *ip, const struct xt_entry_match *match)
Philip Blundellb47050c2000-06-04 17:38:47 +0000229{
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000230 const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
Philip Blundellb47050c2000-06-04 17:38:47 +0000231
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000232 if (icmpv6->invflags & IP6T_ICMP_INV)
Philip Blundellb47050c2000-06-04 17:38:47 +0000233 printf("! ");
234
András Kis-Szabóe0bc7a42001-07-14 20:21:46 +0000235 printf("--icmpv6-type %u", icmpv6->type);
236 if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF)
237 printf("/%u", icmpv6->code[0]);
Philip Blundellb47050c2000-06-04 17:38:47 +0000238 printf(" ");
239}
240
Jan Engelhardt997045f2007-10-04 16:29:21 +0000241static void icmp6_check(unsigned int flags)
Philip Blundellb47050c2000-06-04 17:38:47 +0000242{
Yasuyuki KOZAKAIb1cda882006-07-04 10:23:26 +0000243 if (!flags)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100244 xtables_error(PARAMETER_PROBLEM,
Yasuyuki KOZAKAIb1cda882006-07-04 10:23:26 +0000245 "icmpv6 match: You must specify `--icmpv6-type'");
Philip Blundellb47050c2000-06-04 17:38:47 +0000246}
247
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200248static struct xtables_match icmp6_mt6_reg = {
Harald Welte02aa7332005-02-01 15:38:20 +0000249 .name = "icmp6",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200250 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100251 .family = NFPROTO_IPV6,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200252 .size = XT_ALIGN(sizeof(struct ip6t_icmp)),
253 .userspacesize = XT_ALIGN(sizeof(struct ip6t_icmp)),
Jan Engelhardt997045f2007-10-04 16:29:21 +0000254 .help = icmp6_help,
255 .init = icmp6_init,
256 .parse = icmp6_parse,
257 .final_check = icmp6_check,
258 .print = icmp6_print,
259 .save = icmp6_save,
260 .extra_opts = icmp6_opts,
Philip Blundellb47050c2000-06-04 17:38:47 +0000261};
262
263void _init(void)
264{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200265 xtables_register_match(&icmp6_mt6_reg);
Philip Blundellb47050c2000-06-04 17:38:47 +0000266}