Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / ebtables / extensions / ebt_ip6.c
blob0465e77b5d906f553f359e394bc48c6ff7bb7b4e
1 /* ebt_ip6
2 *
3 * Authors:
4 * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
5 * Manohar Castelino <manohar.castelino@intel.com>
7 * Summary:
8 * This is just a modification of the IPv4 code written by
9 * Bart De Schuymer <bdschuym@pandora.be>
10 * with the changes required to support IPv6
14 #include <errno.h>
15 #include <inttypes.h>
16 #include <limits.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <getopt.h>
21 #include <netdb.h>
22 #include "../include/ebtables_u.h"
23 #include <linux/netfilter_bridge/ebt_ip6.h>
27 #define IP_SOURCE '1'
28 #define IP_DEST '2'
29 #define IP_TCLASS '3'
30 #define IP_PROTO '4'
31 #define IP_SPORT '5'
32 #define IP_DPORT '6'
33 #define IP_ICMP6 '7'
35 static const struct option opts[] =
37 { "ip6-source" , required_argument, 0, IP_SOURCE },
38 { "ip6-src" , required_argument, 0, IP_SOURCE },
39 { "ip6-destination" , required_argument, 0, IP_DEST },
40 { "ip6-dst" , required_argument, 0, IP_DEST },
41 { "ip6-traffic-class" , required_argument, 0, IP_TCLASS },
42 { "ip6-tclass" , required_argument, 0, IP_TCLASS },
43 { "ip6-protocol" , required_argument, 0, IP_PROTO },
44 { "ip6-proto" , required_argument, 0, IP_PROTO },
45 { "ip6-source-port" , required_argument, 0, IP_SPORT },
46 { "ip6-sport" , required_argument, 0, IP_SPORT },
47 { "ip6-destination-port" , required_argument, 0, IP_DPORT },
48 { "ip6-dport" , required_argument, 0, IP_DPORT },
49 { "ip6-icmp-type" , required_argument, 0, IP_ICMP6 },
50 { 0 }
54 struct icmpv6_names {
55 const char *name;
56 u_int8_t type;
57 u_int8_t code_min, code_max;
60 static const struct icmpv6_names icmpv6_codes[] = {
61 { "destination-unreachable", 1, 0, 0xFF },
62 { "no-route", 1, 0, 0 },
63 { "communication-prohibited", 1, 1, 1 },
64 { "address-unreachable", 1, 3, 3 },
65 { "port-unreachable", 1, 4, 4 },
67 { "packet-too-big", 2, 0, 0xFF },
69 { "time-exceeded", 3, 0, 0xFF },
70 /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
71 { "ttl-zero-during-transit", 3, 0, 0 },
72 { "ttl-zero-during-reassembly", 3, 1, 1 },
74 { "parameter-problem", 4, 0, 0xFF },
75 { "bad-header", 4, 0, 0 },
76 { "unknown-header-type", 4, 1, 1 },
77 { "unknown-option", 4, 2, 2 },
79 { "echo-request", 128, 0, 0xFF },
80 /* Alias */ { "ping", 128, 0, 0xFF },
82 { "echo-reply", 129, 0, 0xFF },
83 /* Alias */ { "pong", 129, 0, 0xFF },
85 { "router-solicitation", 133, 0, 0xFF },
87 { "router-advertisement", 134, 0, 0xFF },
89 { "neighbour-solicitation", 135, 0, 0xFF },
90 /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
92 { "neighbour-advertisement", 136, 0, 0xFF },
93 /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
95 { "redirect", 137, 0, 0xFF },
98 /* transform a protocol and service name into a port number */
99 static uint16_t parse_port(const char *protocol, const char *name)
101 struct servent *service;
102 char *end;
103 int port;
105 port = strtol(name, &end, 10);
106 if (*end != '\0') {
107 if (protocol &&
108 (service = getservbyname(name, protocol)) != NULL)
109 return ntohs(service->s_port);
111 else if (port >= 0 || port <= 0xFFFF) {
112 return port;
114 ebt_print_error("Problem with specified %s port '%s'",
115 protocol?protocol:"", name);
116 return 0;
119 static void
120 parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
122 char *buffer;
123 char *cp;
125 buffer = strdup(portstring);
126 if ((cp = strchr(buffer, ':')) == NULL)
127 ports[0] = ports[1] = parse_port(protocol, buffer);
128 else {
129 *cp = '\0';
130 cp++;
131 ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0;
132 if (ebt_errormsg[0] != '\0')
133 return;
134 ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF;
135 if (ebt_errormsg[0] != '\0')
136 return;
138 if (ports[0] > ports[1])
139 ebt_print_error("Invalid portrange (min > max)");
141 free(buffer);
144 static char*
145 parse_num(const char *str, long min, long max, long *num)
147 char *end;
149 errno = 0;
150 *num = strtol(str, &end, 10);
151 if (errno && (*num == LONG_MIN || *num == LONG_MAX)) {
152 ebt_print_error("Invalid number %s: %s", str, strerror(errno));
153 return NULL;
155 if (min <= max) {
156 if (*num > max || *num < min) {
157 ebt_print_error("Value %ld out of range (%ld, %ld)", *num, min, max);
158 return NULL;
161 if (*num == 0 && str == end)
162 return NULL;
163 return end;
166 static char *
167 parse_range(const char *str, long min, long max, long num[])
169 char *next;
171 next = parse_num(str, min, max, num);
172 if (next == NULL)
173 return NULL;
174 if (next && *next == ':')
175 next = parse_num(next+1, min, max, &num[1]);
176 else
177 num[1] = num[0];
178 return next;
181 static int
182 parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[])
184 static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
185 unsigned int match = limit;
186 unsigned int i;
187 long number[2];
189 for (i = 0; i < limit; i++) {
190 if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)))
191 continue;
192 if (match != limit)
193 ebt_print_error("Ambiguous ICMPv6 type `%s':"
194 " `%s' or `%s'?",
195 icmpv6type, icmpv6_codes[match].name,
196 icmpv6_codes[i].name);
197 match = i;
200 if (match < limit) {
201 type[0] = type[1] = icmpv6_codes[match].type;
202 code[0] = icmpv6_codes[match].code_min;
203 code[1] = icmpv6_codes[match].code_max;
204 } else {
205 char *next = parse_range(icmpv6type, 0, 255, number);
206 if (!next) {
207 ebt_print_error("Unknown ICMPv6 type `%s'",
208 icmpv6type);
209 return -1;
211 type[0] = (uint8_t) number[0];
212 type[1] = (uint8_t) number[1];
213 switch (*next) {
214 case 0:
215 code[0] = 0;
216 code[1] = 255;
217 return 0;
218 case '/':
219 next = parse_range(next+1, 0, 255, number);
220 code[0] = (uint8_t) number[0];
221 code[1] = (uint8_t) number[1];
222 if (next == NULL)
223 return -1;
224 if (next && *next == 0)
225 return 0;
226 /* fallthrough */
227 default:
228 ebt_print_error("unknown character %c", *next);
229 return -1;
232 return 0;
235 static void print_port_range(uint16_t *ports)
237 if (ports[0] == ports[1])
238 printf("%d ", ports[0]);
239 else
240 printf("%d:%d ", ports[0], ports[1]);
243 static void print_icmp_code(uint8_t *code)
245 if (code[0] == code[1])
246 printf("/%"PRIu8 " ", code[0]);
247 else
248 printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
251 static void print_icmp_type(uint8_t *type, uint8_t *code)
253 unsigned int i;
255 if (type[0] != type[1]) {
256 printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
257 print_icmp_code(code);
258 return;
261 for (i = 0; i < ARRAY_SIZE(icmpv6_codes); i++) {
262 if (icmpv6_codes[i].type != type[0])
263 continue;
265 if (icmpv6_codes[i].code_min == code[0] &&
266 icmpv6_codes[i].code_max == code[1]) {
267 printf("%s ", icmpv6_codes[i].name);
268 return;
271 printf("%"PRIu8, type[0]);
272 print_icmp_code(code);
275 static void print_icmpv6types(void)
277 unsigned int i;
278 printf("Valid ICMPv6 Types:");
280 for (i=0; i < ARRAY_SIZE(icmpv6_codes); i++) {
281 if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
282 if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
283 && (icmpv6_codes[i].code_max
284 == icmpv6_codes[i-1].code_max))
285 printf(" (%s)", icmpv6_codes[i].name);
286 else
287 printf("\n %s", icmpv6_codes[i].name);
289 else
290 printf("\n%s", icmpv6_codes[i].name);
292 printf("\n");
295 static void print_help()
297 printf(
298 "ip6 options:\n"
299 "--ip6-src [!] address[/mask]: ipv6 source specification\n"
300 "--ip6-dst [!] address[/mask]: ipv6 destination specification\n"
301 "--ip6-tclass [!] tclass : ipv6 traffic class specification\n"
302 "--ip6-proto [!] protocol : ipv6 protocol specification\n"
303 "--ip6-sport [!] port[:port] : tcp/udp source port or port range\n"
304 "--ip6-dport [!] port[:port] : tcp/udp destination port or port range\n"
305 "--ip6-icmp-type [!] type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
306 print_icmpv6types();
309 static void init(struct ebt_entry_match *match)
311 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
313 ipinfo->invflags = 0;
314 ipinfo->bitmask = 0;
317 #define OPT_SOURCE 0x01
318 #define OPT_DEST 0x02
319 #define OPT_TCLASS 0x04
320 #define OPT_PROTO 0x08
321 #define OPT_SPORT 0x10
322 #define OPT_DPORT 0x20
323 static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
324 unsigned int *flags, struct ebt_entry_match **match)
326 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)(*match)->data;
327 char *end;
328 long int i;
330 switch (c) {
331 case IP_SOURCE:
332 ebt_check_option2(flags, OPT_SOURCE);
333 ipinfo->bitmask |= EBT_IP6_SOURCE;
334 if (ebt_check_inverse2(optarg)) {
335 ipinfo->invflags |= EBT_IP6_SOURCE;
337 ebt_parse_ip6_address(optarg, &ipinfo->saddr, &ipinfo->smsk);
338 break;
340 case IP_DEST:
341 ebt_check_option2(flags, OPT_DEST);
342 ipinfo->bitmask |= EBT_IP6_DEST;
343 if (ebt_check_inverse2(optarg)) {
344 ipinfo->invflags |= EBT_IP6_DEST;
346 ebt_parse_ip6_address(optarg, &ipinfo->daddr, &ipinfo->dmsk);
347 break;
349 case IP_SPORT:
350 case IP_DPORT:
351 if (c == IP_SPORT) {
352 ebt_check_option2(flags, OPT_SPORT);
353 ipinfo->bitmask |= EBT_IP6_SPORT;
354 if (ebt_check_inverse2(optarg))
355 ipinfo->invflags |= EBT_IP6_SPORT;
356 } else {
357 ebt_check_option2(flags, OPT_DPORT);
358 ipinfo->bitmask |= EBT_IP6_DPORT;
359 if (ebt_check_inverse2(optarg))
360 ipinfo->invflags |= EBT_IP6_DPORT;
362 if (c == IP_SPORT)
363 parse_port_range(NULL, optarg, ipinfo->sport);
364 else
365 parse_port_range(NULL, optarg, ipinfo->dport);
366 break;
368 case IP_ICMP6:
369 ebt_check_option2(flags, EBT_IP6_ICMP6);
370 ipinfo->bitmask |= EBT_IP6_ICMP6;
371 if (ebt_check_inverse2(optarg))
372 ipinfo->invflags |= EBT_IP6_ICMP6;
373 if (parse_icmpv6(optarg, ipinfo->icmpv6_type, ipinfo->icmpv6_code))
374 return 0;
375 break;
377 case IP_TCLASS:
378 ebt_check_option2(flags, OPT_TCLASS);
379 if (ebt_check_inverse2(optarg))
380 ipinfo->invflags |= EBT_IP6_TCLASS;
381 i = strtol(optarg, &end, 16);
382 if (i < 0 || i > 255 || *end != '\0')
383 ebt_print_error2("Problem with specified IPv6 traffic class");
384 ipinfo->tclass = i;
385 ipinfo->bitmask |= EBT_IP6_TCLASS;
386 break;
388 case IP_PROTO:
389 ebt_check_option2(flags, OPT_PROTO);
390 if (ebt_check_inverse2(optarg))
391 ipinfo->invflags |= EBT_IP6_PROTO;
392 i = strtoul(optarg, &end, 10);
393 if (*end != '\0') {
394 struct protoent *pe;
396 pe = getprotobyname(optarg);
397 if (pe == NULL)
398 ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]);
399 ipinfo->protocol = pe->p_proto;
400 } else {
401 ipinfo->protocol = (unsigned char) i;
403 ipinfo->bitmask |= EBT_IP6_PROTO;
404 break;
405 default:
406 return 0;
408 return 1;
411 static void final_check(const struct ebt_u_entry *entry,
412 const struct ebt_entry_match *match, const char *name,
413 unsigned int hookmask, unsigned int time)
415 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
417 if (entry->ethproto != ETH_P_IPV6 || entry->invflags & EBT_IPROTO) {
418 ebt_print_error("For IPv6 filtering the protocol must be "
419 "specified as IPv6");
420 } else if (ipinfo->bitmask & (EBT_IP6_SPORT|EBT_IP6_DPORT) &&
421 (!(ipinfo->bitmask & EBT_IP6_PROTO) ||
422 ipinfo->invflags & EBT_IP6_PROTO ||
423 (ipinfo->protocol!=IPPROTO_TCP &&
424 ipinfo->protocol!=IPPROTO_UDP &&
425 ipinfo->protocol!=IPPROTO_SCTP &&
426 ipinfo->protocol!=IPPROTO_DCCP)))
427 ebt_print_error("For port filtering the IP protocol must be "
428 "either 6 (tcp), 17 (udp), 33 (dccp) or "
429 "132 (sctp)");
430 if ((ipinfo->bitmask & EBT_IP6_ICMP6) &&
431 (!(ipinfo->bitmask & EBT_IP6_PROTO) ||
432 ipinfo->invflags & EBT_IP6_PROTO ||
433 ipinfo->protocol != IPPROTO_ICMPV6))
434 ebt_print_error("For ipv6-icmp filtering the IP protocol must be "
435 "58 (ipv6-icmp)");
438 static void print(const struct ebt_u_entry *entry,
439 const struct ebt_entry_match *match)
441 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
443 if (ipinfo->bitmask & EBT_IP6_SOURCE) {
444 printf("--ip6-src ");
445 if (ipinfo->invflags & EBT_IP6_SOURCE)
446 printf("! ");
447 printf("%s", ebt_ip6_to_numeric(&ipinfo->saddr));
448 printf("/%s ", ebt_ip6_to_numeric(&ipinfo->smsk));
450 if (ipinfo->bitmask & EBT_IP6_DEST) {
451 printf("--ip6-dst ");
452 if (ipinfo->invflags & EBT_IP6_DEST)
453 printf("! ");
454 printf("%s", ebt_ip6_to_numeric(&ipinfo->daddr));
455 printf("/%s ", ebt_ip6_to_numeric(&ipinfo->dmsk));
457 if (ipinfo->bitmask & EBT_IP6_TCLASS) {
458 printf("--ip6-tclass ");
459 if (ipinfo->invflags & EBT_IP6_TCLASS)
460 printf("! ");
461 printf("0x%02X ", ipinfo->tclass);
463 if (ipinfo->bitmask & EBT_IP6_PROTO) {
464 struct protoent *pe;
466 printf("--ip6-proto ");
467 if (ipinfo->invflags & EBT_IP6_PROTO)
468 printf("! ");
469 pe = getprotobynumber(ipinfo->protocol);
470 if (pe == NULL) {
471 printf("%d ", ipinfo->protocol);
472 } else {
473 printf("%s ", pe->p_name);
476 if (ipinfo->bitmask & EBT_IP6_SPORT) {
477 printf("--ip6-sport ");
478 if (ipinfo->invflags & EBT_IP6_SPORT)
479 printf("! ");
480 print_port_range(ipinfo->sport);
482 if (ipinfo->bitmask & EBT_IP6_DPORT) {
483 printf("--ip6-dport ");
484 if (ipinfo->invflags & EBT_IP6_DPORT)
485 printf("! ");
486 print_port_range(ipinfo->dport);
488 if (ipinfo->bitmask & EBT_IP6_ICMP6) {
489 printf("--ip6-icmp-type ");
490 if (ipinfo->invflags & EBT_IP6_ICMP6)
491 printf("! ");
492 print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
496 static int compare(const struct ebt_entry_match *m1,
497 const struct ebt_entry_match *m2)
499 struct ebt_ip6_info *ipinfo1 = (struct ebt_ip6_info *)m1->data;
500 struct ebt_ip6_info *ipinfo2 = (struct ebt_ip6_info *)m2->data;
502 if (ipinfo1->bitmask != ipinfo2->bitmask)
503 return 0;
504 if (ipinfo1->invflags != ipinfo2->invflags)
505 return 0;
506 if (ipinfo1->bitmask & EBT_IP6_SOURCE) {
507 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->saddr, &ipinfo2->saddr))
508 return 0;
509 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->smsk, &ipinfo2->smsk))
510 return 0;
512 if (ipinfo1->bitmask & EBT_IP6_DEST) {
513 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->daddr, &ipinfo2->daddr))
514 return 0;
515 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->dmsk, &ipinfo2->dmsk))
516 return 0;
518 if (ipinfo1->bitmask & EBT_IP6_TCLASS) {
519 if (ipinfo1->tclass != ipinfo2->tclass)
520 return 0;
522 if (ipinfo1->bitmask & EBT_IP6_PROTO) {
523 if (ipinfo1->protocol != ipinfo2->protocol)
524 return 0;
526 if (ipinfo1->bitmask & EBT_IP6_SPORT) {
527 if (ipinfo1->sport[0] != ipinfo2->sport[0] ||
528 ipinfo1->sport[1] != ipinfo2->sport[1])
529 return 0;
531 if (ipinfo1->bitmask & EBT_IP6_DPORT) {
532 if (ipinfo1->dport[0] != ipinfo2->dport[0] ||
533 ipinfo1->dport[1] != ipinfo2->dport[1])
534 return 0;
536 if (ipinfo1->bitmask & EBT_IP6_ICMP6) {
537 if (ipinfo1->icmpv6_type[0] != ipinfo2->icmpv6_type[0] ||
538 ipinfo1->icmpv6_type[1] != ipinfo2->icmpv6_type[1] ||
539 ipinfo1->icmpv6_code[0] != ipinfo2->icmpv6_code[0] ||
540 ipinfo1->icmpv6_code[1] != ipinfo2->icmpv6_code[1])
541 return 0;
543 return 1;
546 static struct ebt_u_match ip6_match =
548 .name = EBT_IP6_MATCH,
549 .size = sizeof(struct ebt_ip6_info),
550 .help = print_help,
551 .init = init,
552 .parse = parse,
553 .final_check = final_check,
554 .print = print,
555 .compare = compare,
556 .extra_ops = opts,
559 void _init(void)
561 ebt_register_match(&ip6_match);