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