ip6tables.c revision efcdba41ca6bde51c8753cb30c869c370f0a3b93
1/* Code to take an ip6tables-style command line and do it. */ 2 3/* 4 * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au 5 * 6 * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>: 7 * Paul 'Rusty' Russell <rusty@rustcorp.com.au> 8 * Marc Boucher <marc+nf@mbsi.ca> 9 * James Morris <jmorris@intercode.com.au> 10 * Harald Welte <laforge@gnumonks.org> 11 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 */ 27 28#include <getopt.h> 29#include <string.h> 30#include <netdb.h> 31#include <errno.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <ctype.h> 35#include <stdarg.h> 36#include <stdbool.h> 37#include <limits.h> 38#include <ip6tables.h> 39#include <xtables.h> 40#include <arpa/inet.h> 41#include <unistd.h> 42#include <fcntl.h> 43#include <sys/types.h> 44#include <sys/socket.h> 45#include "ip6tables-multi.h" 46#include "xshared.h" 47 48#ifndef TRUE 49#define TRUE 1 50#endif 51#ifndef FALSE 52#define FALSE 0 53#endif 54 55#define CMD_NONE 0x0000U 56#define CMD_INSERT 0x0001U 57#define CMD_DELETE 0x0002U 58#define CMD_DELETE_NUM 0x0004U 59#define CMD_REPLACE 0x0008U 60#define CMD_APPEND 0x0010U 61#define CMD_LIST 0x0020U 62#define CMD_FLUSH 0x0040U 63#define CMD_ZERO 0x0080U 64#define CMD_NEW_CHAIN 0x0100U 65#define CMD_DELETE_CHAIN 0x0200U 66#define CMD_SET_POLICY 0x0400U 67#define CMD_RENAME_CHAIN 0x0800U 68#define CMD_LIST_RULES 0x1000U 69#define CMD_ZERO_NUM 0x2000U 70#define CMD_CHECK 0x4000U 71#define NUMBER_OF_CMD 16 72static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', 73 'N', 'X', 'P', 'E', 'S', 'Z', 'C' }; 74 75#define NUMBER_OF_OPT ARRAY_SIZE(optflags) 76static const char optflags[] 77= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'}; 78 79static struct option original_opts[] = { 80 {.name = "append", .has_arg = 1, .val = 'A'}, 81 {.name = "delete", .has_arg = 1, .val = 'D'}, 82 {.name = "check" , .has_arg = 1, .val = 'C'}, 83 {.name = "insert", .has_arg = 1, .val = 'I'}, 84 {.name = "replace", .has_arg = 1, .val = 'R'}, 85 {.name = "list", .has_arg = 2, .val = 'L'}, 86 {.name = "list-rules", .has_arg = 2, .val = 'S'}, 87 {.name = "flush", .has_arg = 2, .val = 'F'}, 88 {.name = "zero", .has_arg = 2, .val = 'Z'}, 89 {.name = "new-chain", .has_arg = 1, .val = 'N'}, 90 {.name = "delete-chain", .has_arg = 2, .val = 'X'}, 91 {.name = "rename-chain", .has_arg = 1, .val = 'E'}, 92 {.name = "policy", .has_arg = 1, .val = 'P'}, 93 {.name = "source", .has_arg = 1, .val = 's'}, 94 {.name = "destination", .has_arg = 1, .val = 'd'}, 95 {.name = "src", .has_arg = 1, .val = 's'}, /* synonym */ 96 {.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */ 97 {.name = "protocol", .has_arg = 1, .val = 'p'}, 98 {.name = "in-interface", .has_arg = 1, .val = 'i'}, 99 {.name = "jump", .has_arg = 1, .val = 'j'}, 100 {.name = "table", .has_arg = 1, .val = 't'}, 101 {.name = "match", .has_arg = 1, .val = 'm'}, 102 {.name = "numeric", .has_arg = 0, .val = 'n'}, 103 {.name = "out-interface", .has_arg = 1, .val = 'o'}, 104 {.name = "verbose", .has_arg = 0, .val = 'v'}, 105 {.name = "exact", .has_arg = 0, .val = 'x'}, 106 {.name = "version", .has_arg = 0, .val = 'V'}, 107 {.name = "help", .has_arg = 2, .val = 'h'}, 108 {.name = "line-numbers", .has_arg = 0, .val = '0'}, 109 {.name = "modprobe", .has_arg = 1, .val = 'M'}, 110 {.name = "set-counters", .has_arg = 1, .val = 'c'}, 111 {.name = "goto", .has_arg = 1, .val = 'g'}, 112 {.name = "ipv4", .has_arg = 0, .val = '4'}, 113 {.name = "ipv6", .has_arg = 0, .val = '6'}, 114 {NULL}, 115}; 116 117void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); 118struct xtables_globals ip6tables_globals = { 119 .option_offset = 0, 120 .program_version = IPTABLES_VERSION, 121 .orig_opts = original_opts, 122 .exit_err = ip6tables_exit_error, 123}; 124 125/* Table of legal combinations of commands and options. If any of the 126 * given commands make an option legal, that option is legal (applies to 127 * CMD_LIST and CMD_ZERO only). 128 * Key: 129 * + compulsory 130 * x illegal 131 * optional 132 */ 133 134static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = 135/* Well, it's better than "Re: Linux vs FreeBSD" */ 136{ 137 /* -n -s -d -p -j -v -x -i -o --line -c */ 138/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '}, 139/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'}, 140/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, 141/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '}, 142/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '}, 143/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x'}, 144/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 145/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 146/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 147/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 148/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 149/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' '}, 150/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 151/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x'}, 152/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'}, 153}; 154 155static const unsigned int inverse_for_options[NUMBER_OF_OPT] = 156{ 157/* -n */ 0, 158/* -s */ IP6T_INV_SRCIP, 159/* -d */ IP6T_INV_DSTIP, 160/* -p */ XT_INV_PROTO, 161/* -j */ 0, 162/* -v */ 0, 163/* -x */ 0, 164/* -i */ IP6T_INV_VIA_IN, 165/* -o */ IP6T_INV_VIA_OUT, 166/*--line*/ 0, 167/* -c */ 0, 168}; 169 170#define opts ip6tables_globals.opts 171#define prog_name ip6tables_globals.program_name 172#define prog_vers ip6tables_globals.program_version 173/* A few hardcoded protocols for 'all' and in case the user has no 174 /etc/protocols */ 175struct pprot { 176 const char *name; 177 uint8_t num; 178}; 179 180static void __attribute__((noreturn)) 181exit_tryhelp(int status) 182{ 183 if (line != -1) 184 fprintf(stderr, "Error occurred at line: %d\n", line); 185 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", 186 prog_name, prog_name); 187 xtables_free_opts(1); 188 exit(status); 189} 190 191static void 192exit_printhelp(const struct xtables_rule_match *matches) 193{ 194 printf("%s v%s\n\n" 195"Usage: %s -[ACD] chain rule-specification [options]\n" 196" %s -I chain [rulenum] rule-specification [options]\n" 197" %s -R chain rulenum rule-specification [options]\n" 198" %s -D chain rulenum [options]\n" 199" %s -[LS] [chain [rulenum]] [options]\n" 200" %s -[FZ] [chain] [options]\n" 201" %s -[NX] chain\n" 202" %s -E old-chain-name new-chain-name\n" 203" %s -P chain target [options]\n" 204" %s -h (print this help information)\n\n", 205 prog_name, prog_vers, prog_name, prog_name, 206 prog_name, prog_name, prog_name, prog_name, 207 prog_name, prog_name, prog_name, prog_name); 208 209 printf( 210"Commands:\n" 211"Either long or short options are allowed.\n" 212" --append -A chain Append to chain\n" 213" --check -C chain Check for the existence of a rule\n" 214" --delete -D chain Delete matching rule from chain\n" 215" --delete -D chain rulenum\n" 216" Delete rule rulenum (1 = first) from chain\n" 217" --insert -I chain [rulenum]\n" 218" Insert in chain as rulenum (default 1=first)\n" 219" --replace -R chain rulenum\n" 220" Replace rule rulenum (1 = first) in chain\n" 221" --list -L [chain [rulenum]]\n" 222" List the rules in a chain or all chains\n" 223" --list-rules -S [chain [rulenum]]\n" 224" Print the rules in a chain or all chains\n" 225" --flush -F [chain] Delete all rules in chain or all chains\n" 226" --zero -Z [chain [rulenum]]\n" 227" Zero counters in chain or all chains\n" 228" --new -N chain Create a new user-defined chain\n" 229" --delete-chain\n" 230" -X [chain] Delete a user-defined chain\n" 231" --policy -P chain target\n" 232" Change policy on chain to target\n" 233" --rename-chain\n" 234" -E old-chain new-chain\n" 235" Change chain name, (moving any references)\n" 236 237"Options:\n" 238" --ipv4 -4 Error (line is ignored by ip6tables-restore)\n" 239" --ipv6 -6 Nothing (line is ignored by iptables-restore)\n" 240"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n" 241"[!] --source -s address[/mask][,...]\n" 242" source specification\n" 243"[!] --destination -d address[/mask][,...]\n" 244" destination specification\n" 245"[!] --in-interface -i input name[+]\n" 246" network interface name ([+] for wildcard)\n" 247" --jump -j target\n" 248" target for rule (may load target extension)\n" 249#ifdef IP6T_F_GOTO 250" --goto -g chain\n" 251" jump to chain with no return\n" 252#endif 253" --match -m match\n" 254" extended match (may load extension)\n" 255" --numeric -n numeric output of addresses and ports\n" 256"[!] --out-interface -o output name[+]\n" 257" network interface name ([+] for wildcard)\n" 258" --table -t table table to manipulate (default: `filter')\n" 259" --verbose -v verbose mode\n" 260" --line-numbers print line numbers when listing\n" 261" --exact -x expand numbers (display exact values)\n" 262/*"[!] --fragment -f match second or further fragments only\n"*/ 263" --modprobe=<command> try to insert modules using this command\n" 264" --set-counters PKTS BYTES set the counter during insert/append\n" 265"[!] --version -V print package version.\n"); 266 267 print_extension_helps(xtables_targets, matches); 268 exit(0); 269} 270 271void 272ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) 273{ 274 va_list args; 275 276 va_start(args, msg); 277 fprintf(stderr, "%s v%s: ", prog_name, prog_vers); 278 vfprintf(stderr, msg, args); 279 va_end(args); 280 fprintf(stderr, "\n"); 281 if (status == PARAMETER_PROBLEM) 282 exit_tryhelp(status); 283 if (status == VERSION_PROBLEM) 284 fprintf(stderr, 285 "Perhaps ip6tables or your kernel needs to be upgraded.\n"); 286 /* On error paths, make sure that we don't leak memory */ 287 xtables_free_opts(1); 288 exit(status); 289} 290 291static void 292generic_opt_check(int command, int options) 293{ 294 int i, j, legal = 0; 295 296 /* Check that commands are valid with options. Complicated by the 297 * fact that if an option is legal with *any* command given, it is 298 * legal overall (ie. -z and -l). 299 */ 300 for (i = 0; i < NUMBER_OF_OPT; i++) { 301 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ 302 303 for (j = 0; j < NUMBER_OF_CMD; j++) { 304 if (!(command & (1<<j))) 305 continue; 306 307 if (!(options & (1<<i))) { 308 if (commands_v_options[j][i] == '+') 309 xtables_error(PARAMETER_PROBLEM, 310 "You need to supply the `-%c' " 311 "option for this command\n", 312 optflags[i]); 313 } else { 314 if (commands_v_options[j][i] != 'x') 315 legal = 1; 316 else if (legal == 0) 317 legal = -1; 318 } 319 } 320 if (legal == -1) 321 xtables_error(PARAMETER_PROBLEM, 322 "Illegal option `-%c' with this command\n", 323 optflags[i]); 324 } 325} 326 327static char 328opt2char(int option) 329{ 330 const char *ptr; 331 for (ptr = optflags; option > 1; option >>= 1, ptr++); 332 333 return *ptr; 334} 335 336static char 337cmd2char(int option) 338{ 339 const char *ptr; 340 for (ptr = cmdflags; option > 1; option >>= 1, ptr++); 341 342 return *ptr; 343} 344 345static void 346add_command(unsigned int *cmd, const int newcmd, const int othercmds, 347 int invert) 348{ 349 if (invert) 350 xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag"); 351 if (*cmd & (~othercmds)) 352 xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n", 353 cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); 354 *cmd |= newcmd; 355} 356 357/* 358 * All functions starting with "parse" should succeed, otherwise 359 * the program fails. 360 * Most routines return pointers to static data that may change 361 * between calls to the same or other routines with a few exceptions: 362 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" 363 * return global static data. 364*/ 365 366/* These are invalid numbers as upper layer protocol */ 367static int is_exthdr(uint16_t proto) 368{ 369 return (proto == IPPROTO_ROUTING || 370 proto == IPPROTO_FRAGMENT || 371 proto == IPPROTO_AH || 372 proto == IPPROTO_DSTOPTS); 373} 374 375/* Can't be zero. */ 376static int 377parse_rulenumber(const char *rule) 378{ 379 unsigned int rulenum; 380 381 if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX)) 382 xtables_error(PARAMETER_PROBLEM, 383 "Invalid rule number `%s'", rule); 384 385 return rulenum; 386} 387 388static const char * 389parse_target(const char *targetname) 390{ 391 const char *ptr; 392 393 if (strlen(targetname) < 1) 394 xtables_error(PARAMETER_PROBLEM, 395 "Invalid target name (too short)"); 396 397 if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN) 398 xtables_error(PARAMETER_PROBLEM, 399 "Invalid target name `%s' (%u chars max)", 400 targetname, XT_EXTENSION_MAXNAMELEN - 1); 401 402 for (ptr = targetname; *ptr; ptr++) 403 if (isspace(*ptr)) 404 xtables_error(PARAMETER_PROBLEM, 405 "Invalid target name `%s'", targetname); 406 return targetname; 407} 408 409static void 410set_option(unsigned int *options, unsigned int option, uint8_t *invflg, 411 int invert) 412{ 413 if (*options & option) 414 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", 415 opt2char(option)); 416 *options |= option; 417 418 if (invert) { 419 unsigned int i; 420 for (i = 0; 1 << i != option; i++); 421 422 if (!inverse_for_options[i]) 423 xtables_error(PARAMETER_PROBLEM, 424 "cannot have ! before -%c", 425 opt2char(option)); 426 *invflg |= inverse_for_options[i]; 427 } 428} 429 430 431static void 432print_header(unsigned int format, const char *chain, struct xtc_handle *handle) 433{ 434 struct xt_counters counters; 435 const char *pol = ip6tc_get_policy(chain, &counters, handle); 436 printf("Chain %s", chain); 437 if (pol) { 438 printf(" (policy %s", pol); 439 if (!(format & FMT_NOCOUNTS)) { 440 fputc(' ', stdout); 441 xtables_print_num(counters.pcnt, (format|FMT_NOTABLE)); 442 fputs("packets, ", stdout); 443 xtables_print_num(counters.bcnt, (format|FMT_NOTABLE)); 444 fputs("bytes", stdout); 445 } 446 printf(")\n"); 447 } else { 448 unsigned int refs; 449 if (!ip6tc_get_references(&refs, chain, handle)) 450 printf(" (ERROR obtaining refs)\n"); 451 else 452 printf(" (%u references)\n", refs); 453 } 454 455 if (format & FMT_LINENUMBERS) 456 printf(FMT("%-4s ", "%s "), "num"); 457 if (!(format & FMT_NOCOUNTS)) { 458 if (format & FMT_KILOMEGAGIGA) { 459 printf(FMT("%5s ","%s "), "pkts"); 460 printf(FMT("%5s ","%s "), "bytes"); 461 } else { 462 printf(FMT("%8s ","%s "), "pkts"); 463 printf(FMT("%10s ","%s "), "bytes"); 464 } 465 } 466 if (!(format & FMT_NOTARGET)) 467 printf(FMT("%-9s ","%s "), "target"); 468 fputs(" prot ", stdout); 469 if (format & FMT_OPTIONS) 470 fputs("opt", stdout); 471 if (format & FMT_VIA) { 472 printf(FMT(" %-6s ","%s "), "in"); 473 printf(FMT("%-6s ","%s "), "out"); 474 } 475 printf(FMT(" %-19s ","%s "), "source"); 476 printf(FMT(" %-19s "," %s "), "destination"); 477 printf("\n"); 478} 479 480 481static int 482print_match(const struct xt_entry_match *m, 483 const struct ip6t_ip6 *ip, 484 int numeric) 485{ 486 const struct xtables_match *match = 487 xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL); 488 489 if (match) { 490 if (match->print) 491 match->print(ip, m, numeric); 492 else 493 printf("%s ", match->name); 494 } else { 495 if (m->u.user.name[0]) 496 printf("UNKNOWN match `%s' ", m->u.user.name); 497 } 498 /* Don't stop iterating. */ 499 return 0; 500} 501 502/* e is called `fw' here for historical reasons */ 503static void 504print_firewall(const struct ip6t_entry *fw, 505 const char *targname, 506 unsigned int num, 507 unsigned int format, 508 struct xtc_handle *const handle) 509{ 510 const struct xtables_target *target = NULL; 511 const struct xt_entry_target *t; 512 char buf[BUFSIZ]; 513 514 if (!ip6tc_is_chain(targname, handle)) 515 target = xtables_find_target(targname, XTF_TRY_LOAD); 516 else 517 target = xtables_find_target(XT_STANDARD_TARGET, 518 XTF_LOAD_MUST_SUCCEED); 519 520 t = ip6t_get_target((struct ip6t_entry *)fw); 521 522 if (format & FMT_LINENUMBERS) 523 printf(FMT("%-4u ", "%u "), num); 524 525 if (!(format & FMT_NOCOUNTS)) { 526 xtables_print_num(fw->counters.pcnt, format); 527 xtables_print_num(fw->counters.bcnt, format); 528 } 529 530 if (!(format & FMT_NOTARGET)) 531 printf(FMT("%-9s ", "%s "), targname); 532 533 fputc(fw->ipv6.invflags & XT_INV_PROTO ? '!' : ' ', stdout); 534 { 535 const char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC); 536 if (pname) 537 printf(FMT("%-5s", "%s "), pname); 538 else 539 printf(FMT("%-5hu", "%hu "), fw->ipv6.proto); 540 } 541 542 if (format & FMT_OPTIONS) { 543 if (format & FMT_NOTABLE) 544 fputs("opt ", stdout); 545 fputc(' ', stdout); /* Invert flag of FRAG */ 546 fputc(' ', stdout); /* -f */ 547 fputc(' ', stdout); 548 } 549 550 if (format & FMT_VIA) { 551 char iface[IFNAMSIZ+2]; 552 553 if (fw->ipv6.invflags & IP6T_INV_VIA_IN) { 554 iface[0] = '!'; 555 iface[1] = '\0'; 556 } 557 else iface[0] = '\0'; 558 559 if (fw->ipv6.iniface[0] != '\0') { 560 strcat(iface, fw->ipv6.iniface); 561 } 562 else if (format & FMT_NUMERIC) strcat(iface, "*"); 563 else strcat(iface, "any"); 564 printf(FMT(" %-6s ","in %s "), iface); 565 566 if (fw->ipv6.invflags & IP6T_INV_VIA_OUT) { 567 iface[0] = '!'; 568 iface[1] = '\0'; 569 } 570 else iface[0] = '\0'; 571 572 if (fw->ipv6.outiface[0] != '\0') { 573 strcat(iface, fw->ipv6.outiface); 574 } 575 else if (format & FMT_NUMERIC) strcat(iface, "*"); 576 else strcat(iface, "any"); 577 printf(FMT("%-6s ","out %s "), iface); 578 } 579 580 fputc(fw->ipv6.invflags & IP6T_INV_SRCIP ? '!' : ' ', stdout); 581 if (!memcmp(&fw->ipv6.smsk, &in6addr_any, sizeof in6addr_any) 582 && !(format & FMT_NUMERIC)) 583 printf(FMT("%-19s ","%s "), "anywhere"); 584 else { 585 if (format & FMT_NUMERIC) 586 strcpy(buf, xtables_ip6addr_to_numeric(&fw->ipv6.src)); 587 else 588 strcpy(buf, xtables_ip6addr_to_anyname(&fw->ipv6.src)); 589 strcat(buf, xtables_ip6mask_to_numeric(&fw->ipv6.smsk)); 590 printf(FMT("%-19s ","%s "), buf); 591 } 592 593 fputc(fw->ipv6.invflags & IP6T_INV_DSTIP ? '!' : ' ', stdout); 594 if (!memcmp(&fw->ipv6.dmsk, &in6addr_any, sizeof in6addr_any) 595 && !(format & FMT_NUMERIC)) 596 printf(FMT("%-19s ","-> %s"), "anywhere"); 597 else { 598 if (format & FMT_NUMERIC) 599 strcpy(buf, xtables_ip6addr_to_numeric(&fw->ipv6.dst)); 600 else 601 strcpy(buf, xtables_ip6addr_to_anyname(&fw->ipv6.dst)); 602 strcat(buf, xtables_ip6mask_to_numeric(&fw->ipv6.dmsk)); 603 printf(FMT("%-19s ","-> %s"), buf); 604 } 605 606 if (format & FMT_NOTABLE) 607 fputs(" ", stdout); 608 609#ifdef IP6T_F_GOTO 610 if(fw->ipv6.flags & IP6T_F_GOTO) 611 printf("[goto] "); 612#endif 613 614 IP6T_MATCH_ITERATE(fw, print_match, &fw->ipv6, format & FMT_NUMERIC); 615 616 if (target) { 617 if (target->print) 618 /* Print the target information. */ 619 target->print(&fw->ipv6, t, format & FMT_NUMERIC); 620 } else if (t->u.target_size != sizeof(*t)) 621 printf("[%u bytes of unknown target data] ", 622 (unsigned int)(t->u.target_size - sizeof(*t))); 623 624 if (!(format & FMT_NONEWLINE)) 625 fputc('\n', stdout); 626} 627 628static void 629print_firewall_line(const struct ip6t_entry *fw, 630 struct xtc_handle *const h) 631{ 632 struct xt_entry_target *t; 633 634 t = ip6t_get_target((struct ip6t_entry *)fw); 635 print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); 636} 637 638static int 639append_entry(const xt_chainlabel chain, 640 struct ip6t_entry *fw, 641 unsigned int nsaddrs, 642 const struct in6_addr saddrs[], 643 const struct in6_addr smasks[], 644 unsigned int ndaddrs, 645 const struct in6_addr daddrs[], 646 const struct in6_addr dmasks[], 647 int verbose, 648 struct xtc_handle *handle) 649{ 650 unsigned int i, j; 651 int ret = 1; 652 653 for (i = 0; i < nsaddrs; i++) { 654 fw->ipv6.src = saddrs[i]; 655 fw->ipv6.smsk = smasks[i]; 656 for (j = 0; j < ndaddrs; j++) { 657 fw->ipv6.dst = daddrs[j]; 658 fw->ipv6.dmsk = dmasks[j]; 659 if (verbose) 660 print_firewall_line(fw, handle); 661 ret &= ip6tc_append_entry(chain, fw, handle); 662 } 663 } 664 665 return ret; 666} 667 668static int 669replace_entry(const xt_chainlabel chain, 670 struct ip6t_entry *fw, 671 unsigned int rulenum, 672 const struct in6_addr *saddr, const struct in6_addr *smask, 673 const struct in6_addr *daddr, const struct in6_addr *dmask, 674 int verbose, 675 struct xtc_handle *handle) 676{ 677 fw->ipv6.src = *saddr; 678 fw->ipv6.dst = *daddr; 679 fw->ipv6.smsk = *smask; 680 fw->ipv6.dmsk = *dmask; 681 682 if (verbose) 683 print_firewall_line(fw, handle); 684 return ip6tc_replace_entry(chain, fw, rulenum, handle); 685} 686 687static int 688insert_entry(const xt_chainlabel chain, 689 struct ip6t_entry *fw, 690 unsigned int rulenum, 691 unsigned int nsaddrs, 692 const struct in6_addr saddrs[], 693 const struct in6_addr smasks[], 694 unsigned int ndaddrs, 695 const struct in6_addr daddrs[], 696 const struct in6_addr dmasks[], 697 int verbose, 698 struct xtc_handle *handle) 699{ 700 unsigned int i, j; 701 int ret = 1; 702 703 for (i = 0; i < nsaddrs; i++) { 704 fw->ipv6.src = saddrs[i]; 705 fw->ipv6.smsk = smasks[i]; 706 for (j = 0; j < ndaddrs; j++) { 707 fw->ipv6.dst = daddrs[j]; 708 fw->ipv6.dmsk = dmasks[j]; 709 if (verbose) 710 print_firewall_line(fw, handle); 711 ret &= ip6tc_insert_entry(chain, fw, rulenum, handle); 712 } 713 } 714 715 return ret; 716} 717 718static unsigned char * 719make_delete_mask(const struct xtables_rule_match *matches, 720 const struct xtables_target *target) 721{ 722 /* Establish mask for comparison */ 723 unsigned int size; 724 const struct xtables_rule_match *matchp; 725 unsigned char *mask, *mptr; 726 727 size = sizeof(struct ip6t_entry); 728 for (matchp = matches; matchp; matchp = matchp->next) 729 size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; 730 731 mask = xtables_calloc(1, size 732 + XT_ALIGN(sizeof(struct xt_entry_target)) 733 + target->size); 734 735 memset(mask, 0xFF, sizeof(struct ip6t_entry)); 736 mptr = mask + sizeof(struct ip6t_entry); 737 738 for (matchp = matches; matchp; matchp = matchp->next) { 739 memset(mptr, 0xFF, 740 XT_ALIGN(sizeof(struct xt_entry_match)) 741 + matchp->match->userspacesize); 742 mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; 743 } 744 745 memset(mptr, 0xFF, 746 XT_ALIGN(sizeof(struct xt_entry_target)) 747 + target->userspacesize); 748 749 return mask; 750} 751 752static int 753delete_entry(const xt_chainlabel chain, 754 struct ip6t_entry *fw, 755 unsigned int nsaddrs, 756 const struct in6_addr saddrs[], 757 const struct in6_addr smasks[], 758 unsigned int ndaddrs, 759 const struct in6_addr daddrs[], 760 const struct in6_addr dmasks[], 761 int verbose, 762 struct xtc_handle *handle, 763 struct xtables_rule_match *matches, 764 const struct xtables_target *target) 765{ 766 unsigned int i, j; 767 int ret = 1; 768 unsigned char *mask; 769 770 mask = make_delete_mask(matches, target); 771 for (i = 0; i < nsaddrs; i++) { 772 fw->ipv6.src = saddrs[i]; 773 fw->ipv6.smsk = smasks[i]; 774 for (j = 0; j < ndaddrs; j++) { 775 fw->ipv6.dst = daddrs[j]; 776 fw->ipv6.dmsk = dmasks[j]; 777 if (verbose) 778 print_firewall_line(fw, handle); 779 ret &= ip6tc_delete_entry(chain, fw, mask, handle); 780 } 781 } 782 free(mask); 783 784 return ret; 785} 786 787static int 788check_entry(const xt_chainlabel chain, struct ip6t_entry *fw, 789 unsigned int nsaddrs, const struct in6_addr *saddrs, 790 const struct in6_addr *smasks, unsigned int ndaddrs, 791 const struct in6_addr *daddrs, const struct in6_addr *dmasks, 792 bool verbose, struct xtc_handle *handle, 793 struct xtables_rule_match *matches, 794 const struct xtables_target *target) 795{ 796 unsigned int i, j; 797 int ret = 1; 798 unsigned char *mask; 799 800 mask = make_delete_mask(matches, target); 801 for (i = 0; i < nsaddrs; i++) { 802 fw->ipv6.src = saddrs[i]; 803 fw->ipv6.smsk = smasks[i]; 804 for (j = 0; j < ndaddrs; j++) { 805 fw->ipv6.dst = daddrs[j]; 806 fw->ipv6.dmsk = dmasks[j]; 807 if (verbose) 808 print_firewall_line(fw, handle); 809 ret &= ip6tc_check_entry(chain, fw, mask, handle); 810 } 811 } 812 813 free(mask); 814 return ret; 815} 816 817int 818for_each_chain6(int (*fn)(const xt_chainlabel, int, struct xtc_handle *), 819 int verbose, int builtinstoo, struct xtc_handle *handle) 820{ 821 int ret = 1; 822 const char *chain; 823 char *chains; 824 unsigned int i, chaincount = 0; 825 826 chain = ip6tc_first_chain(handle); 827 while (chain) { 828 chaincount++; 829 chain = ip6tc_next_chain(handle); 830 } 831 832 chains = xtables_malloc(sizeof(xt_chainlabel) * chaincount); 833 i = 0; 834 chain = ip6tc_first_chain(handle); 835 while (chain) { 836 strcpy(chains + i*sizeof(xt_chainlabel), chain); 837 i++; 838 chain = ip6tc_next_chain(handle); 839 } 840 841 for (i = 0; i < chaincount; i++) { 842 if (!builtinstoo 843 && ip6tc_builtin(chains + i*sizeof(xt_chainlabel), 844 handle) == 1) 845 continue; 846 ret &= fn(chains + i*sizeof(xt_chainlabel), verbose, handle); 847 } 848 849 free(chains); 850 return ret; 851} 852 853int 854flush_entries6(const xt_chainlabel chain, int verbose, 855 struct xtc_handle *handle) 856{ 857 if (!chain) 858 return for_each_chain6(flush_entries6, verbose, 1, handle); 859 860 if (verbose) 861 fprintf(stdout, "Flushing chain `%s'\n", chain); 862 return ip6tc_flush_entries(chain, handle); 863} 864 865static int 866zero_entries(const xt_chainlabel chain, int verbose, 867 struct xtc_handle *handle) 868{ 869 if (!chain) 870 return for_each_chain6(zero_entries, verbose, 1, handle); 871 872 if (verbose) 873 fprintf(stdout, "Zeroing chain `%s'\n", chain); 874 return ip6tc_zero_entries(chain, handle); 875} 876 877int 878delete_chain6(const xt_chainlabel chain, int verbose, 879 struct xtc_handle *handle) 880{ 881 if (!chain) 882 return for_each_chain6(delete_chain6, verbose, 0, handle); 883 884 if (verbose) 885 fprintf(stdout, "Deleting chain `%s'\n", chain); 886 return ip6tc_delete_chain(chain, handle); 887} 888 889static int 890list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, 891 int expanded, int linenumbers, struct xtc_handle *handle) 892{ 893 int found = 0; 894 unsigned int format; 895 const char *this; 896 897 format = FMT_OPTIONS; 898 if (!verbose) 899 format |= FMT_NOCOUNTS; 900 else 901 format |= FMT_VIA; 902 903 if (numeric) 904 format |= FMT_NUMERIC; 905 906 if (!expanded) 907 format |= FMT_KILOMEGAGIGA; 908 909 if (linenumbers) 910 format |= FMT_LINENUMBERS; 911 912 for (this = ip6tc_first_chain(handle); 913 this; 914 this = ip6tc_next_chain(handle)) { 915 const struct ip6t_entry *i; 916 unsigned int num; 917 918 if (chain && strcmp(chain, this) != 0) 919 continue; 920 921 if (found) printf("\n"); 922 923 if (!rulenum) 924 print_header(format, this, handle); 925 i = ip6tc_first_rule(this, handle); 926 927 num = 0; 928 while (i) { 929 num++; 930 if (!rulenum || num == rulenum) 931 print_firewall(i, 932 ip6tc_get_target(i, handle), 933 num, 934 format, 935 handle); 936 i = ip6tc_next_rule(i, handle); 937 } 938 found = 1; 939 } 940 941 errno = ENOENT; 942 return found; 943} 944 945/* This assumes that mask is contiguous, and byte-bounded. */ 946static void 947print_iface(char letter, const char *iface, const unsigned char *mask, 948 int invert) 949{ 950 unsigned int i; 951 952 if (mask[0] == 0) 953 return; 954 955 printf("%s -%c ", invert ? " !" : "", letter); 956 957 for (i = 0; i < IFNAMSIZ; i++) { 958 if (mask[i] != 0) { 959 if (iface[i] != '\0') 960 printf("%c", iface[i]); 961 } else { 962 /* we can access iface[i-1] here, because 963 * a few lines above we make sure that mask[0] != 0 */ 964 if (iface[i-1] != '\0') 965 printf("+"); 966 break; 967 } 968 } 969} 970 971/* The ip6tables looks up the /etc/protocols. */ 972static void print_proto(uint16_t proto, int invert) 973{ 974 if (proto) { 975 unsigned int i; 976 const char *invertstr = invert ? " !" : ""; 977 978 const struct protoent *pent = getprotobynumber(proto); 979 if (pent) { 980 printf("%s -p %s", 981 invertstr, pent->p_name); 982 return; 983 } 984 985 for (i = 0; xtables_chain_protos[i].name != NULL; ++i) 986 if (xtables_chain_protos[i].num == proto) { 987 printf("%s -p %s", 988 invertstr, xtables_chain_protos[i].name); 989 return; 990 } 991 992 printf("%s -p %u", invertstr, proto); 993 } 994} 995 996static int print_match_save(const struct xt_entry_match *e, 997 const struct ip6t_ip6 *ip) 998{ 999 const struct xtables_match *match = 1000 xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL); 1001 1002 if (match) { 1003 printf(" -m %s", 1004 match->alias ? match->alias(e) : e->u.user.name); 1005 1006 /* some matches don't provide a save function */ 1007 if (match->save) 1008 match->save(ip, e); 1009 } else { 1010 if (e->u.match_size) { 1011 fprintf(stderr, 1012 "Can't find library for match `%s'\n", 1013 e->u.user.name); 1014 exit(1); 1015 } 1016 } 1017 return 0; 1018} 1019 1020/* print a given ip including mask if neccessary */ 1021static void print_ip(const char *prefix, const struct in6_addr *ip, 1022 const struct in6_addr *mask, int invert) 1023{ 1024 char buf[51]; 1025 int l = ipv6_prefix_length(mask); 1026 1027 if (l == 0 && !invert) 1028 return; 1029 1030 printf("%s %s %s", 1031 invert ? " !" : "", 1032 prefix, 1033 inet_ntop(AF_INET6, ip, buf, sizeof buf)); 1034 1035 if (l == -1) 1036 printf("/%s", inet_ntop(AF_INET6, mask, buf, sizeof buf)); 1037 else 1038 printf("/%d", l); 1039} 1040 1041/* We want this to be readable, so only print out neccessary fields. 1042 * Because that's the kind of world I want to live in. */ 1043void print_rule6(const struct ip6t_entry *e, 1044 struct xtc_handle *h, const char *chain, int counters) 1045{ 1046 const struct xt_entry_target *t; 1047 const char *target_name; 1048 1049 /* print counters for iptables-save */ 1050 if (counters > 0) 1051 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); 1052 1053 /* print chain name */ 1054 printf("-A %s", chain); 1055 1056 /* Print IP part. */ 1057 print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk), 1058 e->ipv6.invflags & IP6T_INV_SRCIP); 1059 1060 print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), 1061 e->ipv6.invflags & IP6T_INV_DSTIP); 1062 1063 print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, 1064 e->ipv6.invflags & IP6T_INV_VIA_IN); 1065 1066 print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, 1067 e->ipv6.invflags & IP6T_INV_VIA_OUT); 1068 1069 print_proto(e->ipv6.proto, e->ipv6.invflags & XT_INV_PROTO); 1070 1071#if 0 1072 /* not definied in ipv6 1073 * FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? */ 1074 if (e->ipv6.flags & IPT_F_FRAG) 1075 printf("%s -f", 1076 e->ipv6.invflags & IP6T_INV_FRAG ? " !" : ""); 1077#endif 1078 1079 if (e->ipv6.flags & IP6T_F_TOS) 1080 printf("%s -? %d", 1081 e->ipv6.invflags & IP6T_INV_TOS ? " !" : "", 1082 e->ipv6.tos); 1083 1084 /* Print matchinfo part */ 1085 if (e->target_offset) { 1086 IP6T_MATCH_ITERATE(e, print_match_save, &e->ipv6); 1087 } 1088 1089 /* print counters for iptables -R */ 1090 if (counters < 0) 1091 printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); 1092 1093 /* Print target name and targinfo part */ 1094 target_name = ip6tc_get_target(e, h); 1095 t = ip6t_get_target((struct ip6t_entry *)e); 1096 if (t->u.user.name[0]) { 1097 struct xtables_target *target = 1098 xtables_find_target(t->u.user.name, XTF_TRY_LOAD); 1099 1100 if (!target) { 1101 fprintf(stderr, "Can't find library for target `%s'\n", 1102 t->u.user.name); 1103 exit(1); 1104 } 1105 1106 printf(" -j %s", target->alias ? target->alias(t) : target_name); 1107 if (target->save) 1108 target->save(&e->ipv6, t); 1109 else { 1110 /* If the target size is greater than xt_entry_target 1111 * there is something to be saved, we just don't know 1112 * how to print it */ 1113 if (t->u.target_size != 1114 sizeof(struct xt_entry_target)) { 1115 fprintf(stderr, "Target `%s' is missing " 1116 "save function\n", 1117 t->u.user.name); 1118 exit(1); 1119 } 1120 } 1121 } else if (target_name && (*target_name != '\0')) 1122#ifdef IP6T_F_GOTO 1123 printf(" -%c %s", e->ipv6.flags & IP6T_F_GOTO ? 'g' : 'j', target_name); 1124#else 1125 printf(" -j %s", target_name); 1126#endif 1127 1128 printf("\n"); 1129} 1130 1131static int 1132list_rules(const xt_chainlabel chain, int rulenum, int counters, 1133 struct xtc_handle *handle) 1134{ 1135 const char *this = NULL; 1136 int found = 0; 1137 1138 if (counters) 1139 counters = -1; /* iptables -c format */ 1140 1141 /* Dump out chain names first, 1142 * thereby preventing dependency conflicts */ 1143 if (!rulenum) for (this = ip6tc_first_chain(handle); 1144 this; 1145 this = ip6tc_next_chain(handle)) { 1146 if (chain && strcmp(this, chain) != 0) 1147 continue; 1148 1149 if (ip6tc_builtin(this, handle)) { 1150 struct xt_counters count; 1151 printf("-P %s %s", this, ip6tc_get_policy(this, &count, handle)); 1152 if (counters) 1153 printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); 1154 printf("\n"); 1155 } else { 1156 printf("-N %s\n", this); 1157 } 1158 } 1159 1160 for (this = ip6tc_first_chain(handle); 1161 this; 1162 this = ip6tc_next_chain(handle)) { 1163 const struct ip6t_entry *e; 1164 int num = 0; 1165 1166 if (chain && strcmp(this, chain) != 0) 1167 continue; 1168 1169 /* Dump out rules */ 1170 e = ip6tc_first_rule(this, handle); 1171 while(e) { 1172 num++; 1173 if (!rulenum || num == rulenum) 1174 print_rule6(e, handle, this, counters); 1175 e = ip6tc_next_rule(e, handle); 1176 } 1177 found = 1; 1178 } 1179 1180 errno = ENOENT; 1181 return found; 1182} 1183 1184static struct ip6t_entry * 1185generate_entry(const struct ip6t_entry *fw, 1186 struct xtables_rule_match *matches, 1187 struct xt_entry_target *target) 1188{ 1189 unsigned int size; 1190 struct xtables_rule_match *matchp; 1191 struct ip6t_entry *e; 1192 1193 size = sizeof(struct ip6t_entry); 1194 for (matchp = matches; matchp; matchp = matchp->next) 1195 size += matchp->match->m->u.match_size; 1196 1197 e = xtables_malloc(size + target->u.target_size); 1198 *e = *fw; 1199 e->target_offset = size; 1200 e->next_offset = size + target->u.target_size; 1201 1202 size = 0; 1203 for (matchp = matches; matchp; matchp = matchp->next) { 1204 memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size); 1205 size += matchp->match->m->u.match_size; 1206 } 1207 memcpy(e->elems + size, target, target->u.target_size); 1208 1209 return e; 1210} 1211 1212static void command_jump(struct iptables_command_state *cs) 1213{ 1214 size_t size; 1215 1216 set_option(&cs->options, OPT_JUMP, &cs->fw6.ipv6.invflags, cs->invert); 1217 cs->jumpto = parse_target(optarg); 1218 /* TRY_LOAD (may be chain name) */ 1219 cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); 1220 1221 if (cs->target == NULL) 1222 return; 1223 1224 size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size; 1225 1226 cs->target->t = xtables_calloc(1, size); 1227 cs->target->t->u.target_size = size; 1228 if (cs->target->real_name == NULL) { 1229 strcpy(cs->target->t->u.user.name, cs->jumpto); 1230 } else { 1231 strcpy(cs->target->t->u.user.name, cs->target->real_name); 1232 if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS)) 1233 fprintf(stderr, "Notice: The %s target is converted into %s target " 1234 "in rule listing and saving.\n", 1235 cs->jumpto, cs->target->real_name); 1236 } 1237 cs->target->t->u.user.revision = cs->target->revision; 1238 1239 xs_init_target(cs->target); 1240 if (cs->target->x6_options != NULL) 1241 opts = xtables_options_xfrm(ip6tables_globals.orig_opts, opts, 1242 cs->target->x6_options, 1243 &cs->target->option_offset); 1244 else 1245 opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, 1246 cs->target->extra_opts, 1247 &cs->target->option_offset); 1248 if (opts == NULL) 1249 xtables_error(OTHER_PROBLEM, "can't alloc memory!"); 1250} 1251 1252static void command_match(struct iptables_command_state *cs) 1253{ 1254 struct xtables_match *m; 1255 size_t size; 1256 1257 if (cs->invert) 1258 xtables_error(PARAMETER_PROBLEM, 1259 "unexpected ! flag before --match"); 1260 1261 m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches); 1262 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size; 1263 m->m = xtables_calloc(1, size); 1264 m->m->u.match_size = size; 1265 if (m->real_name == NULL) { 1266 strcpy(m->m->u.user.name, m->name); 1267 } else { 1268 strcpy(m->m->u.user.name, m->real_name); 1269 if (!(m->ext_flags & XTABLES_EXT_ALIAS)) 1270 fprintf(stderr, "Notice: The %s match is converted into %s match " 1271 "in rule listing and saving.\n", m->name, m->real_name); 1272 } 1273 m->m->u.user.revision = m->revision; 1274 1275 xs_init_match(m); 1276 if (m == m->next) 1277 return; 1278 /* Merge options for non-cloned matches */ 1279 if (m->x6_options != NULL) 1280 opts = xtables_options_xfrm(ip6tables_globals.orig_opts, opts, 1281 m->x6_options, &m->option_offset); 1282 else if (m->extra_opts != NULL) 1283 opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, 1284 m->extra_opts, &m->option_offset); 1285} 1286 1287int do_command6(int argc, char *argv[], char **table, struct xtc_handle **handle) 1288{ 1289 struct iptables_command_state cs; 1290 struct ip6t_entry *e = NULL; 1291 unsigned int nsaddrs = 0, ndaddrs = 0; 1292 struct in6_addr *saddrs = NULL, *daddrs = NULL; 1293 struct in6_addr *smasks = NULL, *dmasks = NULL; 1294 1295 int verbose = 0; 1296 const char *chain = NULL; 1297 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; 1298 const char *policy = NULL, *newname = NULL; 1299 unsigned int rulenum = 0, command = 0; 1300 const char *pcnt = NULL, *bcnt = NULL; 1301 int ret = 1; 1302 struct xtables_match *m; 1303 struct xtables_rule_match *matchp; 1304 struct xtables_target *t; 1305 unsigned long long cnt; 1306 1307 memset(&cs, 0, sizeof(cs)); 1308 cs.jumpto = ""; 1309 cs.argv = argv; 1310 1311 /* re-set optind to 0 in case do_command6 gets called 1312 * a second time */ 1313 optind = 0; 1314 1315 /* clear mflags in case do_command6 gets called a second time 1316 * (we clear the global list of all matches for security)*/ 1317 for (m = xtables_matches; m; m = m->next) 1318 m->mflags = 0; 1319 1320 for (t = xtables_targets; t; t = t->next) { 1321 t->tflags = 0; 1322 t->used = 0; 1323 } 1324 1325 /* Suppress error messages: we may add new options if we 1326 demand-load a protocol. */ 1327 opterr = 0; 1328 1329 opts = xt_params->orig_opts; 1330 while ((cs.c = getopt_long(argc, argv, 1331 "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:g:46", 1332 opts, NULL)) != -1) { 1333 switch (cs.c) { 1334 /* 1335 * Command selection 1336 */ 1337 case 'A': 1338 add_command(&command, CMD_APPEND, CMD_NONE, 1339 cs.invert); 1340 chain = optarg; 1341 break; 1342 1343 case 'C': 1344 add_command(&command, CMD_CHECK, CMD_NONE, 1345 cs.invert); 1346 chain = optarg; 1347 break; 1348 1349 case 'D': 1350 add_command(&command, CMD_DELETE, CMD_NONE, 1351 cs.invert); 1352 chain = optarg; 1353 if (optind < argc && argv[optind][0] != '-' 1354 && argv[optind][0] != '!') { 1355 rulenum = parse_rulenumber(argv[optind++]); 1356 command = CMD_DELETE_NUM; 1357 } 1358 break; 1359 1360 case 'R': 1361 add_command(&command, CMD_REPLACE, CMD_NONE, 1362 cs.invert); 1363 chain = optarg; 1364 if (optind < argc && argv[optind][0] != '-' 1365 && argv[optind][0] != '!') 1366 rulenum = parse_rulenumber(argv[optind++]); 1367 else 1368 xtables_error(PARAMETER_PROBLEM, 1369 "-%c requires a rule number", 1370 cmd2char(CMD_REPLACE)); 1371 break; 1372 1373 case 'I': 1374 add_command(&command, CMD_INSERT, CMD_NONE, 1375 cs.invert); 1376 chain = optarg; 1377 if (optind < argc && argv[optind][0] != '-' 1378 && argv[optind][0] != '!') 1379 rulenum = parse_rulenumber(argv[optind++]); 1380 else rulenum = 1; 1381 break; 1382 1383 case 'L': 1384 add_command(&command, CMD_LIST, 1385 CMD_ZERO | CMD_ZERO_NUM, cs.invert); 1386 if (optarg) chain = optarg; 1387 else if (optind < argc && argv[optind][0] != '-' 1388 && argv[optind][0] != '!') 1389 chain = argv[optind++]; 1390 if (optind < argc && argv[optind][0] != '-' 1391 && argv[optind][0] != '!') 1392 rulenum = parse_rulenumber(argv[optind++]); 1393 break; 1394 1395 case 'S': 1396 add_command(&command, CMD_LIST_RULES, 1397 CMD_ZERO | CMD_ZERO_NUM, cs.invert); 1398 if (optarg) chain = optarg; 1399 else if (optind < argc && argv[optind][0] != '-' 1400 && argv[optind][0] != '!') 1401 chain = argv[optind++]; 1402 if (optind < argc && argv[optind][0] != '-' 1403 && argv[optind][0] != '!') 1404 rulenum = parse_rulenumber(argv[optind++]); 1405 break; 1406 1407 case 'F': 1408 add_command(&command, CMD_FLUSH, CMD_NONE, 1409 cs.invert); 1410 if (optarg) chain = optarg; 1411 else if (optind < argc && argv[optind][0] != '-' 1412 && argv[optind][0] != '!') 1413 chain = argv[optind++]; 1414 break; 1415 1416 case 'Z': 1417 add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, 1418 cs.invert); 1419 if (optarg) chain = optarg; 1420 else if (optind < argc && argv[optind][0] != '-' 1421 && argv[optind][0] != '!') 1422 chain = argv[optind++]; 1423 if (optind < argc && argv[optind][0] != '-' 1424 && argv[optind][0] != '!') { 1425 rulenum = parse_rulenumber(argv[optind++]); 1426 command = CMD_ZERO_NUM; 1427 } 1428 break; 1429 1430 case 'N': 1431 if (optarg && (*optarg == '-' || *optarg == '!')) 1432 xtables_error(PARAMETER_PROBLEM, 1433 "chain name not allowed to start " 1434 "with `%c'\n", *optarg); 1435 if (xtables_find_target(optarg, XTF_TRY_LOAD)) 1436 xtables_error(PARAMETER_PROBLEM, 1437 "chain name may not clash " 1438 "with target name\n"); 1439 add_command(&command, CMD_NEW_CHAIN, CMD_NONE, 1440 cs.invert); 1441 chain = optarg; 1442 break; 1443 1444 case 'X': 1445 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, 1446 cs.invert); 1447 if (optarg) chain = optarg; 1448 else if (optind < argc && argv[optind][0] != '-' 1449 && argv[optind][0] != '!') 1450 chain = argv[optind++]; 1451 break; 1452 1453 case 'E': 1454 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, 1455 cs.invert); 1456 chain = optarg; 1457 if (optind < argc && argv[optind][0] != '-' 1458 && argv[optind][0] != '!') 1459 newname = argv[optind++]; 1460 else 1461 xtables_error(PARAMETER_PROBLEM, 1462 "-%c requires old-chain-name and " 1463 "new-chain-name", 1464 cmd2char(CMD_RENAME_CHAIN)); 1465 break; 1466 1467 case 'P': 1468 add_command(&command, CMD_SET_POLICY, CMD_NONE, 1469 cs.invert); 1470 chain = optarg; 1471 if (optind < argc && argv[optind][0] != '-' 1472 && argv[optind][0] != '!') 1473 policy = argv[optind++]; 1474 else 1475 xtables_error(PARAMETER_PROBLEM, 1476 "-%c requires a chain and a policy", 1477 cmd2char(CMD_SET_POLICY)); 1478 break; 1479 1480 case 'h': 1481 if (!optarg) 1482 optarg = argv[optind]; 1483 1484 /* ip6tables -p icmp -h */ 1485 if (!cs.matches && cs.protocol) 1486 xtables_find_match(cs.protocol, XTF_TRY_LOAD, 1487 &cs.matches); 1488 1489 exit_printhelp(cs.matches); 1490 1491 /* 1492 * Option selection 1493 */ 1494 case 'p': 1495 set_option(&cs.options, OPT_PROTOCOL, &cs.fw6.ipv6.invflags, 1496 cs.invert); 1497 1498 /* Canonicalize into lower case */ 1499 for (cs.protocol = optarg; *cs.protocol; cs.protocol++) 1500 *cs.protocol = tolower(*cs.protocol); 1501 1502 cs.protocol = optarg; 1503 cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol); 1504 cs.fw6.ipv6.flags |= IP6T_F_PROTO; 1505 1506 if (cs.fw6.ipv6.proto == 0 1507 && (cs.fw6.ipv6.invflags & XT_INV_PROTO)) 1508 xtables_error(PARAMETER_PROBLEM, 1509 "rule would never match protocol"); 1510 1511 if (is_exthdr(cs.fw6.ipv6.proto) 1512 && (cs.fw6.ipv6.invflags & XT_INV_PROTO) == 0) 1513 fprintf(stderr, 1514 "Warning: never matched protocol: %s. " 1515 "use extension match instead.\n", 1516 cs.protocol); 1517 break; 1518 1519 case 's': 1520 set_option(&cs.options, OPT_SOURCE, &cs.fw6.ipv6.invflags, 1521 cs.invert); 1522 shostnetworkmask = optarg; 1523 break; 1524 1525 case 'd': 1526 set_option(&cs.options, OPT_DESTINATION, &cs.fw6.ipv6.invflags, 1527 cs.invert); 1528 dhostnetworkmask = optarg; 1529 break; 1530 1531#ifdef IP6T_F_GOTO 1532 case 'g': 1533 set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, 1534 cs.invert); 1535 cs.fw6.ipv6.flags |= IP6T_F_GOTO; 1536 cs.jumpto = parse_target(optarg); 1537 break; 1538#endif 1539 1540 case 'j': 1541 command_jump(&cs); 1542 break; 1543 1544 1545 case 'i': 1546 if (*optarg == '\0') 1547 xtables_error(PARAMETER_PROBLEM, 1548 "Empty interface is likely to be " 1549 "undesired"); 1550 set_option(&cs.options, OPT_VIANAMEIN, &cs.fw6.ipv6.invflags, 1551 cs.invert); 1552 xtables_parse_interface(optarg, 1553 cs.fw6.ipv6.iniface, 1554 cs.fw6.ipv6.iniface_mask); 1555 break; 1556 1557 case 'o': 1558 if (*optarg == '\0') 1559 xtables_error(PARAMETER_PROBLEM, 1560 "Empty interface is likely to be " 1561 "undesired"); 1562 set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw6.ipv6.invflags, 1563 cs.invert); 1564 xtables_parse_interface(optarg, 1565 cs.fw6.ipv6.outiface, 1566 cs.fw6.ipv6.outiface_mask); 1567 break; 1568 1569 case 'v': 1570 if (!verbose) 1571 set_option(&cs.options, OPT_VERBOSE, 1572 &cs.fw6.ipv6.invflags, cs.invert); 1573 verbose++; 1574 break; 1575 1576 case 'm': 1577 command_match(&cs); 1578 break; 1579 1580 case 'n': 1581 set_option(&cs.options, OPT_NUMERIC, &cs.fw6.ipv6.invflags, 1582 cs.invert); 1583 break; 1584 1585 case 't': 1586 if (cs.invert) 1587 xtables_error(PARAMETER_PROBLEM, 1588 "unexpected ! flag before --table"); 1589 *table = optarg; 1590 break; 1591 1592 case 'x': 1593 set_option(&cs.options, OPT_EXPANDED, &cs.fw6.ipv6.invflags, 1594 cs.invert); 1595 break; 1596 1597 case 'V': 1598 if (cs.invert) 1599 printf("Not %s ;-)\n", prog_vers); 1600 else 1601 printf("%s v%s\n", 1602 prog_name, prog_vers); 1603 exit(0); 1604 1605 case '0': 1606 set_option(&cs.options, OPT_LINENUMBERS, &cs.fw6.ipv6.invflags, 1607 cs.invert); 1608 break; 1609 1610 case 'M': 1611 xtables_modprobe_program = optarg; 1612 break; 1613 1614 case 'c': 1615 1616 set_option(&cs.options, OPT_COUNTERS, &cs.fw6.ipv6.invflags, 1617 cs.invert); 1618 pcnt = optarg; 1619 bcnt = strchr(pcnt + 1, ','); 1620 if (bcnt) 1621 bcnt++; 1622 if (!bcnt && optind < argc && argv[optind][0] != '-' 1623 && argv[optind][0] != '!') 1624 bcnt = argv[optind++]; 1625 if (!bcnt) 1626 xtables_error(PARAMETER_PROBLEM, 1627 "-%c requires packet and byte counter", 1628 opt2char(OPT_COUNTERS)); 1629 1630 if (sscanf(pcnt, "%llu", &cnt) != 1) 1631 xtables_error(PARAMETER_PROBLEM, 1632 "-%c packet counter not numeric", 1633 opt2char(OPT_COUNTERS)); 1634 cs.fw6.counters.pcnt = cnt; 1635 1636 if (sscanf(bcnt, "%llu", &cnt) != 1) 1637 xtables_error(PARAMETER_PROBLEM, 1638 "-%c byte counter not numeric", 1639 opt2char(OPT_COUNTERS)); 1640 cs.fw6.counters.bcnt = cnt; 1641 break; 1642 1643 case '4': 1644 /* This is not the IPv4 iptables */ 1645 if (line != -1) 1646 return 1; /* success: line ignored */ 1647 fprintf(stderr, "This is the IPv6 version of ip6tables.\n"); 1648 exit_tryhelp(2); 1649 1650 case '6': 1651 /* This is indeed the IPv6 ip6tables */ 1652 break; 1653 1654 case 1: /* non option */ 1655 if (optarg[0] == '!' && optarg[1] == '\0') { 1656 if (cs.invert) 1657 xtables_error(PARAMETER_PROBLEM, 1658 "multiple consecutive ! not" 1659 " allowed"); 1660 cs.invert = TRUE; 1661 optarg[0] = '\0'; 1662 continue; 1663 } 1664 fprintf(stderr, "Bad argument `%s'\n", optarg); 1665 exit_tryhelp(2); 1666 1667 default: 1668 if (command_default(&cs, &ip6tables_globals) == 1) 1669 /* 1670 * If new options were loaded, we must retry 1671 * getopt immediately and not allow 1672 * cs.invert=FALSE to be executed. 1673 */ 1674 continue; 1675 break; 1676 } 1677 cs.invert = FALSE; 1678 } 1679 1680 for (matchp = cs.matches; matchp; matchp = matchp->next) 1681 xtables_option_mfcall(matchp->match); 1682 if (cs.target != NULL) 1683 xtables_option_tfcall(cs.target); 1684 1685 /* Fix me: must put inverse options checking here --MN */ 1686 1687 if (optind < argc) 1688 xtables_error(PARAMETER_PROBLEM, 1689 "unknown arguments found on commandline"); 1690 if (!command) 1691 xtables_error(PARAMETER_PROBLEM, "no command specified"); 1692 if (cs.invert) 1693 xtables_error(PARAMETER_PROBLEM, 1694 "nothing appropriate following !"); 1695 1696 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { 1697 if (!(cs.options & OPT_DESTINATION)) 1698 dhostnetworkmask = "::0/0"; 1699 if (!(cs.options & OPT_SOURCE)) 1700 shostnetworkmask = "::0/0"; 1701 } 1702 1703 if (shostnetworkmask) 1704 xtables_ip6parse_multiple(shostnetworkmask, &saddrs, 1705 &smasks, &nsaddrs); 1706 1707 if (dhostnetworkmask) 1708 xtables_ip6parse_multiple(dhostnetworkmask, &daddrs, 1709 &dmasks, &ndaddrs); 1710 1711 if ((nsaddrs > 1 || ndaddrs > 1) && 1712 (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) 1713 xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" 1714 " source or destination IP addresses"); 1715 1716 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) 1717 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " 1718 "specify a unique address"); 1719 1720 generic_opt_check(command, cs.options); 1721 1722 if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN) 1723 xtables_error(PARAMETER_PROBLEM, 1724 "chain name `%s' too long (must be under %u chars)", 1725 chain, XT_EXTENSION_MAXNAMELEN); 1726 1727 /* only allocate handle if we weren't called with a handle */ 1728 if (!*handle) 1729 *handle = ip6tc_init(*table); 1730 1731 /* try to insmod the module if iptc_init failed */ 1732 if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1) 1733 *handle = ip6tc_init(*table); 1734 1735 if (!*handle) 1736 xtables_error(VERSION_PROBLEM, 1737 "can't initialize ip6tables table `%s': %s", 1738 *table, ip6tc_strerror(errno)); 1739 1740 if (command == CMD_APPEND 1741 || command == CMD_DELETE 1742 || command == CMD_CHECK 1743 || command == CMD_INSERT 1744 || command == CMD_REPLACE) { 1745 if (strcmp(chain, "PREROUTING") == 0 1746 || strcmp(chain, "INPUT") == 0) { 1747 /* -o not valid with incoming packets. */ 1748 if (cs.options & OPT_VIANAMEOUT) 1749 xtables_error(PARAMETER_PROBLEM, 1750 "Can't use -%c with %s\n", 1751 opt2char(OPT_VIANAMEOUT), 1752 chain); 1753 } 1754 1755 if (strcmp(chain, "POSTROUTING") == 0 1756 || strcmp(chain, "OUTPUT") == 0) { 1757 /* -i not valid with outgoing packets */ 1758 if (cs.options & OPT_VIANAMEIN) 1759 xtables_error(PARAMETER_PROBLEM, 1760 "Can't use -%c with %s\n", 1761 opt2char(OPT_VIANAMEIN), 1762 chain); 1763 } 1764 1765 if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) { 1766 fprintf(stderr, 1767 "Warning: using chain %s, not extension\n", 1768 cs.jumpto); 1769 1770 if (cs.target->t) 1771 free(cs.target->t); 1772 1773 cs.target = NULL; 1774 } 1775 1776 /* If they didn't specify a target, or it's a chain 1777 name, use standard. */ 1778 if (!cs.target 1779 && (strlen(cs.jumpto) == 0 1780 || ip6tc_is_chain(cs.jumpto, *handle))) { 1781 size_t size; 1782 1783 cs.target = xtables_find_target(XT_STANDARD_TARGET, 1784 XTF_LOAD_MUST_SUCCEED); 1785 1786 size = sizeof(struct xt_entry_target) 1787 + cs.target->size; 1788 cs.target->t = xtables_calloc(1, size); 1789 cs.target->t->u.target_size = size; 1790 strcpy(cs.target->t->u.user.name, cs.jumpto); 1791 xs_init_target(cs.target); 1792 } 1793 1794 if (!cs.target) { 1795 /* it is no chain, and we can't load a plugin. 1796 * We cannot know if the plugin is corrupt, non 1797 * existant OR if the user just misspelled a 1798 * chain. */ 1799#ifdef IP6T_F_GOTO 1800 if (cs.fw6.ipv6.flags & IP6T_F_GOTO) 1801 xtables_error(PARAMETER_PROBLEM, 1802 "goto '%s' is not a chain\n", 1803 cs.jumpto); 1804#endif 1805 xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); 1806 } else { 1807 e = generate_entry(&cs.fw6, cs.matches, cs.target->t); 1808 free(cs.target->t); 1809 } 1810 } 1811 1812 switch (command) { 1813 case CMD_APPEND: 1814 ret = append_entry(chain, e, 1815 nsaddrs, saddrs, smasks, 1816 ndaddrs, daddrs, dmasks, 1817 cs.options&OPT_VERBOSE, 1818 *handle); 1819 break; 1820 case CMD_DELETE: 1821 ret = delete_entry(chain, e, 1822 nsaddrs, saddrs, smasks, 1823 ndaddrs, daddrs, dmasks, 1824 cs.options&OPT_VERBOSE, 1825 *handle, cs.matches, cs.target); 1826 break; 1827 case CMD_DELETE_NUM: 1828 ret = ip6tc_delete_num_entry(chain, rulenum - 1, *handle); 1829 break; 1830 case CMD_CHECK: 1831 ret = check_entry(chain, e, 1832 nsaddrs, saddrs, smasks, 1833 ndaddrs, daddrs, dmasks, 1834 cs.options&OPT_VERBOSE, 1835 *handle, cs.matches, cs.target); 1836 break; 1837 case CMD_REPLACE: 1838 ret = replace_entry(chain, e, rulenum - 1, 1839 saddrs, smasks, daddrs, dmasks, 1840 cs.options&OPT_VERBOSE, *handle); 1841 break; 1842 case CMD_INSERT: 1843 ret = insert_entry(chain, e, rulenum - 1, 1844 nsaddrs, saddrs, smasks, 1845 ndaddrs, daddrs, dmasks, 1846 cs.options&OPT_VERBOSE, 1847 *handle); 1848 break; 1849 case CMD_FLUSH: 1850 ret = flush_entries6(chain, cs.options&OPT_VERBOSE, *handle); 1851 break; 1852 case CMD_ZERO: 1853 ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle); 1854 break; 1855 case CMD_ZERO_NUM: 1856 ret = ip6tc_zero_counter(chain, rulenum, *handle); 1857 break; 1858 case CMD_LIST: 1859 case CMD_LIST|CMD_ZERO: 1860 case CMD_LIST|CMD_ZERO_NUM: 1861 ret = list_entries(chain, 1862 rulenum, 1863 cs.options&OPT_VERBOSE, 1864 cs.options&OPT_NUMERIC, 1865 cs.options&OPT_EXPANDED, 1866 cs.options&OPT_LINENUMBERS, 1867 *handle); 1868 if (ret && (command & CMD_ZERO)) 1869 ret = zero_entries(chain, 1870 cs.options&OPT_VERBOSE, *handle); 1871 if (ret && (command & CMD_ZERO_NUM)) 1872 ret = ip6tc_zero_counter(chain, rulenum, *handle); 1873 break; 1874 case CMD_LIST_RULES: 1875 case CMD_LIST_RULES|CMD_ZERO: 1876 case CMD_LIST_RULES|CMD_ZERO_NUM: 1877 ret = list_rules(chain, 1878 rulenum, 1879 cs.options&OPT_VERBOSE, 1880 *handle); 1881 if (ret && (command & CMD_ZERO)) 1882 ret = zero_entries(chain, 1883 cs.options&OPT_VERBOSE, *handle); 1884 if (ret && (command & CMD_ZERO_NUM)) 1885 ret = ip6tc_zero_counter(chain, rulenum, *handle); 1886 break; 1887 case CMD_NEW_CHAIN: 1888 ret = ip6tc_create_chain(chain, *handle); 1889 break; 1890 case CMD_DELETE_CHAIN: 1891 ret = delete_chain6(chain, cs.options&OPT_VERBOSE, *handle); 1892 break; 1893 case CMD_RENAME_CHAIN: 1894 ret = ip6tc_rename_chain(chain, newname, *handle); 1895 break; 1896 case CMD_SET_POLICY: 1897 ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle); 1898 break; 1899 default: 1900 /* We should never reach this... */ 1901 exit_tryhelp(2); 1902 } 1903 1904 if (verbose > 1) 1905 dump_entries6(*handle); 1906 1907 xtables_rule_matches_free(&cs.matches); 1908 1909 if (e != NULL) { 1910 free(e); 1911 e = NULL; 1912 } 1913 1914 free(saddrs); 1915 free(smasks); 1916 free(daddrs); 1917 free(dmasks); 1918 xtables_free_opts(1); 1919 1920 return ret; 1921} 1922