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