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