iptables.c revision bf75fc041b35c75c2c592e01f1906771e00ce4eb
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"[!] --protocol -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", 995 match->alias ? match->alias(e) : e->u.user.name); 996 997 /* some matches don't provide a save function */ 998 if (match->save) 999 match->save(ip, e); 1000 } else { 1001 if (e->u.match_size) { 1002 fprintf(stderr, 1003 "Can't find library for match `%s'\n", 1004 e->u.user.name); 1005 exit(1); 1006 } 1007 } 1008 return 0; 1009} 1010 1011/* print a given ip including mask if neccessary */ 1012static void print_ip(const char *prefix, uint32_t ip, 1013 uint32_t mask, int invert) 1014{ 1015 uint32_t bits, hmask = ntohl(mask); 1016 int i; 1017 1018 if (!mask && !ip && !invert) 1019 return; 1020 1021 printf("%s %s %u.%u.%u.%u", 1022 invert ? " !" : "", 1023 prefix, 1024 IP_PARTS(ip)); 1025 1026 if (mask == 0xFFFFFFFFU) { 1027 printf("/32"); 1028 return; 1029 } 1030 1031 i = 32; 1032 bits = 0xFFFFFFFEU; 1033 while (--i >= 0 && hmask != bits) 1034 bits <<= 1; 1035 if (i >= 0) 1036 printf("/%u", i); 1037 else 1038 printf("/%u.%u.%u.%u", IP_PARTS(mask)); 1039} 1040 1041/* We want this to be readable, so only print out neccessary fields. 1042 * Because that's the kind of world I want to live in. */ 1043void print_rule4(const struct ipt_entry *e, 1044 struct xtc_handle *h, const char *chain, int counters) 1045{ 1046 const struct xt_entry_target *t; 1047 const char *target_name; 1048 1049 /* print counters for iptables-save */ 1050 if (counters > 0) 1051 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); 1052 1053 /* print chain name */ 1054 printf("-A %s", chain); 1055 1056 /* Print IP part. */ 1057 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr, 1058 e->ip.invflags & IPT_INV_SRCIP); 1059 1060 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, 1061 e->ip.invflags & IPT_INV_DSTIP); 1062 1063 print_iface('i', e->ip.iniface, e->ip.iniface_mask, 1064 e->ip.invflags & IPT_INV_VIA_IN); 1065 1066 print_iface('o', e->ip.outiface, e->ip.outiface_mask, 1067 e->ip.invflags & IPT_INV_VIA_OUT); 1068 1069 print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO); 1070 1071 if (e->ip.flags & IPT_F_FRAG) 1072 printf("%s -f", 1073 e->ip.invflags & IPT_INV_FRAG ? " !" : ""); 1074 1075 /* Print matchinfo part */ 1076 if (e->target_offset) { 1077 IPT_MATCH_ITERATE(e, print_match_save, &e->ip); 1078 } 1079 1080 /* print counters for iptables -R */ 1081 if (counters < 0) 1082 printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); 1083 1084 /* Print target name and targinfo part */ 1085 target_name = iptc_get_target(e, h); 1086 t = ipt_get_target((struct ipt_entry *)e); 1087 if (t->u.user.name[0]) { 1088 const struct xtables_target *target = 1089 xtables_find_target(t->u.user.name, XTF_TRY_LOAD); 1090 1091 if (!target) { 1092 fprintf(stderr, "Can't find library for target `%s'\n", 1093 t->u.user.name); 1094 exit(1); 1095 } 1096 1097 printf(" -j %s", target->alias ? target->alias(t) : target_name); 1098 if (target->save) 1099 target->save(&e->ip, t); 1100 else { 1101 /* If the target size is greater than xt_entry_target 1102 * there is something to be saved, we just don't know 1103 * how to print it */ 1104 if (t->u.target_size != 1105 sizeof(struct xt_entry_target)) { 1106 fprintf(stderr, "Target `%s' is missing " 1107 "save function\n", 1108 t->u.user.name); 1109 exit(1); 1110 } 1111 } 1112 } else if (target_name && (*target_name != '\0')) 1113#ifdef IPT_F_GOTO 1114 printf(" -%c %s", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name); 1115#else 1116 printf(" -j %s", target_name); 1117#endif 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 if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS)) 1226 fprintf(stderr, "Notice: The %s target is converted into %s target " 1227 "in rule listing and saving.\n", 1228 cs->jumpto, cs->target->real_name); 1229 } 1230 cs->target->t->u.user.revision = cs->target->revision; 1231 1232 xs_init_target(cs->target); 1233 1234 if (cs->target->x6_options != NULL) 1235 opts = xtables_options_xfrm(iptables_globals.orig_opts, opts, 1236 cs->target->x6_options, 1237 &cs->target->option_offset); 1238 else 1239 opts = xtables_merge_options(iptables_globals.orig_opts, opts, 1240 cs->target->extra_opts, 1241 &cs->target->option_offset); 1242 if (opts == NULL) 1243 xtables_error(OTHER_PROBLEM, "can't alloc memory!"); 1244} 1245 1246static void command_match(struct iptables_command_state *cs) 1247{ 1248 struct xtables_match *m; 1249 size_t size; 1250 1251 if (cs->invert) 1252 xtables_error(PARAMETER_PROBLEM, 1253 "unexpected ! flag before --match"); 1254 1255 m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches); 1256 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size; 1257 m->m = xtables_calloc(1, size); 1258 m->m->u.match_size = size; 1259 if (m->real_name == NULL) { 1260 strcpy(m->m->u.user.name, m->name); 1261 } else { 1262 strcpy(m->m->u.user.name, m->real_name); 1263 if (!(m->ext_flags & XTABLES_EXT_ALIAS)) 1264 fprintf(stderr, "Notice: the %s match is converted into %s match " 1265 "in rule listing and saving.\n", m->name, m->real_name); 1266 } 1267 m->m->u.user.revision = m->revision; 1268 1269 xs_init_match(m); 1270 if (m == m->next) 1271 return; 1272 /* Merge options for non-cloned matches */ 1273 if (m->x6_options != NULL) 1274 opts = xtables_options_xfrm(iptables_globals.orig_opts, opts, 1275 m->x6_options, &m->option_offset); 1276 else if (m->extra_opts != NULL) 1277 opts = xtables_merge_options(iptables_globals.orig_opts, opts, 1278 m->extra_opts, &m->option_offset); 1279 if (opts == NULL) 1280 xtables_error(OTHER_PROBLEM, "can't alloc memory!"); 1281} 1282 1283int do_command4(int argc, char *argv[], char **table, struct xtc_handle **handle) 1284{ 1285 struct iptables_command_state cs; 1286 struct ipt_entry *e = NULL; 1287 unsigned int nsaddrs = 0, ndaddrs = 0; 1288 struct in_addr *saddrs = NULL, *smasks = NULL; 1289 struct in_addr *daddrs = NULL, *dmasks = NULL; 1290 1291 int verbose = 0; 1292 const char *chain = NULL; 1293 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; 1294 const char *policy = NULL, *newname = NULL; 1295 unsigned int rulenum = 0, command = 0; 1296 const char *pcnt = NULL, *bcnt = NULL; 1297 int ret = 1; 1298 struct xtables_match *m; 1299 struct xtables_rule_match *matchp; 1300 struct xtables_target *t; 1301 unsigned long long cnt; 1302 1303 memset(&cs, 0, sizeof(cs)); 1304 cs.jumpto = ""; 1305 cs.argv = argv; 1306 1307 /* re-set optind to 0 in case do_command4 gets called 1308 * a second time */ 1309 optind = 0; 1310 1311 /* clear mflags in case do_command4 gets called a second time 1312 * (we clear the global list of all matches for security)*/ 1313 for (m = xtables_matches; m; m = m->next) 1314 m->mflags = 0; 1315 1316 for (t = xtables_targets; t; t = t->next) { 1317 t->tflags = 0; 1318 t->used = 0; 1319 } 1320 1321 /* Suppress error messages: we may add new options if we 1322 demand-load a protocol. */ 1323 opterr = 0; 1324 1325 opts = xt_params->orig_opts; 1326 while ((cs.c = getopt_long(argc, argv, 1327 "-: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", 1328 opts, NULL)) != -1) { 1329 switch (cs.c) { 1330 /* 1331 * Command selection 1332 */ 1333 case 'A': 1334 add_command(&command, CMD_APPEND, CMD_NONE, 1335 cs.invert); 1336 chain = optarg; 1337 break; 1338 1339 case 'C': 1340 add_command(&command, CMD_CHECK, CMD_NONE, 1341 cs.invert); 1342 chain = optarg; 1343 break; 1344 1345 case 'D': 1346 add_command(&command, CMD_DELETE, CMD_NONE, 1347 cs.invert); 1348 chain = optarg; 1349 if (optind < argc && argv[optind][0] != '-' 1350 && argv[optind][0] != '!') { 1351 rulenum = parse_rulenumber(argv[optind++]); 1352 command = CMD_DELETE_NUM; 1353 } 1354 break; 1355 1356 case 'R': 1357 add_command(&command, CMD_REPLACE, CMD_NONE, 1358 cs.invert); 1359 chain = optarg; 1360 if (optind < argc && argv[optind][0] != '-' 1361 && argv[optind][0] != '!') 1362 rulenum = parse_rulenumber(argv[optind++]); 1363 else 1364 xtables_error(PARAMETER_PROBLEM, 1365 "-%c requires a rule number", 1366 cmd2char(CMD_REPLACE)); 1367 break; 1368 1369 case 'I': 1370 add_command(&command, CMD_INSERT, CMD_NONE, 1371 cs.invert); 1372 chain = optarg; 1373 if (optind < argc && argv[optind][0] != '-' 1374 && argv[optind][0] != '!') 1375 rulenum = parse_rulenumber(argv[optind++]); 1376 else rulenum = 1; 1377 break; 1378 1379 case 'L': 1380 add_command(&command, CMD_LIST, 1381 CMD_ZERO | CMD_ZERO_NUM, cs.invert); 1382 if (optarg) chain = optarg; 1383 else if (optind < argc && argv[optind][0] != '-' 1384 && argv[optind][0] != '!') 1385 chain = argv[optind++]; 1386 if (optind < argc && argv[optind][0] != '-' 1387 && argv[optind][0] != '!') 1388 rulenum = parse_rulenumber(argv[optind++]); 1389 break; 1390 1391 case 'S': 1392 add_command(&command, CMD_LIST_RULES, 1393 CMD_ZERO|CMD_ZERO_NUM, cs.invert); 1394 if (optarg) chain = optarg; 1395 else if (optind < argc && argv[optind][0] != '-' 1396 && argv[optind][0] != '!') 1397 chain = argv[optind++]; 1398 if (optind < argc && argv[optind][0] != '-' 1399 && argv[optind][0] != '!') 1400 rulenum = parse_rulenumber(argv[optind++]); 1401 break; 1402 1403 case 'F': 1404 add_command(&command, CMD_FLUSH, CMD_NONE, 1405 cs.invert); 1406 if (optarg) chain = optarg; 1407 else if (optind < argc && argv[optind][0] != '-' 1408 && argv[optind][0] != '!') 1409 chain = argv[optind++]; 1410 break; 1411 1412 case 'Z': 1413 add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, 1414 cs.invert); 1415 if (optarg) chain = optarg; 1416 else if (optind < argc && argv[optind][0] != '-' 1417 && argv[optind][0] != '!') 1418 chain = argv[optind++]; 1419 if (optind < argc && argv[optind][0] != '-' 1420 && argv[optind][0] != '!') { 1421 rulenum = parse_rulenumber(argv[optind++]); 1422 command = CMD_ZERO_NUM; 1423 } 1424 break; 1425 1426 case 'N': 1427 if (optarg && (*optarg == '-' || *optarg == '!')) 1428 xtables_error(PARAMETER_PROBLEM, 1429 "chain name not allowed to start " 1430 "with `%c'\n", *optarg); 1431 if (xtables_find_target(optarg, XTF_TRY_LOAD)) 1432 xtables_error(PARAMETER_PROBLEM, 1433 "chain name may not clash " 1434 "with target name\n"); 1435 add_command(&command, CMD_NEW_CHAIN, CMD_NONE, 1436 cs.invert); 1437 chain = optarg; 1438 break; 1439 1440 case 'X': 1441 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, 1442 cs.invert); 1443 if (optarg) chain = optarg; 1444 else if (optind < argc && argv[optind][0] != '-' 1445 && argv[optind][0] != '!') 1446 chain = argv[optind++]; 1447 break; 1448 1449 case 'E': 1450 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, 1451 cs.invert); 1452 chain = optarg; 1453 if (optind < argc && argv[optind][0] != '-' 1454 && argv[optind][0] != '!') 1455 newname = argv[optind++]; 1456 else 1457 xtables_error(PARAMETER_PROBLEM, 1458 "-%c requires old-chain-name and " 1459 "new-chain-name", 1460 cmd2char(CMD_RENAME_CHAIN)); 1461 break; 1462 1463 case 'P': 1464 add_command(&command, CMD_SET_POLICY, CMD_NONE, 1465 cs.invert); 1466 chain = optarg; 1467 if (optind < argc && argv[optind][0] != '-' 1468 && argv[optind][0] != '!') 1469 policy = argv[optind++]; 1470 else 1471 xtables_error(PARAMETER_PROBLEM, 1472 "-%c requires a chain and a policy", 1473 cmd2char(CMD_SET_POLICY)); 1474 break; 1475 1476 case 'h': 1477 if (!optarg) 1478 optarg = argv[optind]; 1479 1480 /* iptables -p icmp -h */ 1481 if (!cs.matches && cs.protocol) 1482 xtables_find_match(cs.protocol, 1483 XTF_TRY_LOAD, &cs.matches); 1484 1485 exit_printhelp(cs.matches); 1486 1487 /* 1488 * Option selection 1489 */ 1490 case 'p': 1491 set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags, 1492 cs.invert); 1493 1494 /* Canonicalize into lower case */ 1495 for (cs.protocol = optarg; *cs.protocol; cs.protocol++) 1496 *cs.protocol = tolower(*cs.protocol); 1497 1498 cs.protocol = optarg; 1499 cs.fw.ip.proto = xtables_parse_protocol(cs.protocol); 1500 1501 if (cs.fw.ip.proto == 0 1502 && (cs.fw.ip.invflags & XT_INV_PROTO)) 1503 xtables_error(PARAMETER_PROBLEM, 1504 "rule would never match protocol"); 1505 break; 1506 1507 case 's': 1508 set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags, 1509 cs.invert); 1510 shostnetworkmask = optarg; 1511 break; 1512 1513 case 'd': 1514 set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags, 1515 cs.invert); 1516 dhostnetworkmask = optarg; 1517 break; 1518 1519#ifdef IPT_F_GOTO 1520 case 'g': 1521 set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, 1522 cs.invert); 1523 cs.fw.ip.flags |= IPT_F_GOTO; 1524 cs.jumpto = parse_target(optarg); 1525 break; 1526#endif 1527 1528 case 'j': 1529 command_jump(&cs); 1530 break; 1531 1532 1533 case 'i': 1534 if (*optarg == '\0') 1535 xtables_error(PARAMETER_PROBLEM, 1536 "Empty interface is likely to be " 1537 "undesired"); 1538 set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags, 1539 cs.invert); 1540 xtables_parse_interface(optarg, 1541 cs.fw.ip.iniface, 1542 cs.fw.ip.iniface_mask); 1543 break; 1544 1545 case 'o': 1546 if (*optarg == '\0') 1547 xtables_error(PARAMETER_PROBLEM, 1548 "Empty interface is likely to be " 1549 "undesired"); 1550 set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags, 1551 cs.invert); 1552 xtables_parse_interface(optarg, 1553 cs.fw.ip.outiface, 1554 cs.fw.ip.outiface_mask); 1555 break; 1556 1557 case 'f': 1558 set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags, 1559 cs.invert); 1560 cs.fw.ip.flags |= IPT_F_FRAG; 1561 break; 1562 1563 case 'v': 1564 if (!verbose) 1565 set_option(&cs.options, OPT_VERBOSE, 1566 &cs.fw.ip.invflags, cs.invert); 1567 verbose++; 1568 break; 1569 1570 case 'm': 1571 command_match(&cs); 1572 break; 1573 1574 case 'n': 1575 set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags, 1576 cs.invert); 1577 break; 1578 1579 case 't': 1580 if (cs.invert) 1581 xtables_error(PARAMETER_PROBLEM, 1582 "unexpected ! flag before --table"); 1583 *table = optarg; 1584 break; 1585 1586 case 'x': 1587 set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags, 1588 cs.invert); 1589 break; 1590 1591 case 'V': 1592 if (cs.invert) 1593 printf("Not %s ;-)\n", prog_vers); 1594 else 1595 printf("%s v%s\n", 1596 prog_name, prog_vers); 1597 exit(0); 1598 1599 case '0': 1600 set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags, 1601 cs.invert); 1602 break; 1603 1604 case 'M': 1605 xtables_modprobe_program = optarg; 1606 break; 1607 1608 case 'c': 1609 1610 set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags, 1611 cs.invert); 1612 pcnt = optarg; 1613 bcnt = strchr(pcnt + 1, ','); 1614 if (bcnt) 1615 bcnt++; 1616 if (!bcnt && optind < argc && argv[optind][0] != '-' 1617 && argv[optind][0] != '!') 1618 bcnt = argv[optind++]; 1619 if (!bcnt) 1620 xtables_error(PARAMETER_PROBLEM, 1621 "-%c requires packet and byte counter", 1622 opt2char(OPT_COUNTERS)); 1623 1624 if (sscanf(pcnt, "%llu", &cnt) != 1) 1625 xtables_error(PARAMETER_PROBLEM, 1626 "-%c packet counter not numeric", 1627 opt2char(OPT_COUNTERS)); 1628 cs.fw.counters.pcnt = cnt; 1629 1630 if (sscanf(bcnt, "%llu", &cnt) != 1) 1631 xtables_error(PARAMETER_PROBLEM, 1632 "-%c byte counter not numeric", 1633 opt2char(OPT_COUNTERS)); 1634 cs.fw.counters.bcnt = cnt; 1635 break; 1636 1637 case '4': 1638 /* This is indeed the IPv4 iptables */ 1639 break; 1640 1641 case '6': 1642 /* This is not the IPv6 ip6tables */ 1643 if (line != -1) 1644 return 1; /* success: line ignored */ 1645 fprintf(stderr, "This is the IPv4 version of iptables.\n"); 1646 exit_tryhelp(2); 1647 1648 case 1: /* non option */ 1649 if (optarg[0] == '!' && optarg[1] == '\0') { 1650 if (cs.invert) 1651 xtables_error(PARAMETER_PROBLEM, 1652 "multiple consecutive ! not" 1653 " allowed"); 1654 cs.invert = TRUE; 1655 optarg[0] = '\0'; 1656 continue; 1657 } 1658 fprintf(stderr, "Bad argument `%s'\n", optarg); 1659 exit_tryhelp(2); 1660 1661 default: 1662 if (command_default(&cs, &iptables_globals) == 1) 1663 /* cf. ip6tables.c */ 1664 continue; 1665 break; 1666 } 1667 cs.invert = FALSE; 1668 } 1669 1670 if (strcmp(*table, "nat") == 0 && 1671 ((policy != NULL && strcmp(policy, "DROP") == 0) || 1672 (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) 1673 xtables_error(PARAMETER_PROBLEM, 1674 "\nThe \"nat\" table is not intended for filtering, " 1675 "the use of DROP is therefore inhibited.\n\n"); 1676 1677 for (matchp = cs.matches; matchp; matchp = matchp->next) 1678 xtables_option_mfcall(matchp->match); 1679 if (cs.target != NULL) 1680 xtables_option_tfcall(cs.target); 1681 1682 /* Fix me: must put inverse options checking here --MN */ 1683 1684 if (optind < argc) 1685 xtables_error(PARAMETER_PROBLEM, 1686 "unknown arguments found on commandline"); 1687 if (!command) 1688 xtables_error(PARAMETER_PROBLEM, "no command specified"); 1689 if (cs.invert) 1690 xtables_error(PARAMETER_PROBLEM, 1691 "nothing appropriate following !"); 1692 1693 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { 1694 if (!(cs.options & OPT_DESTINATION)) 1695 dhostnetworkmask = "0.0.0.0/0"; 1696 if (!(cs.options & OPT_SOURCE)) 1697 shostnetworkmask = "0.0.0.0/0"; 1698 } 1699 1700 if (shostnetworkmask) 1701 xtables_ipparse_multiple(shostnetworkmask, &saddrs, 1702 &smasks, &nsaddrs); 1703 1704 if (dhostnetworkmask) 1705 xtables_ipparse_multiple(dhostnetworkmask, &daddrs, 1706 &dmasks, &ndaddrs); 1707 1708 if ((nsaddrs > 1 || ndaddrs > 1) && 1709 (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) 1710 xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" 1711 " source or destination IP addresses"); 1712 1713 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) 1714 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " 1715 "specify a unique address"); 1716 1717 generic_opt_check(command, cs.options); 1718 1719 if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN) 1720 xtables_error(PARAMETER_PROBLEM, 1721 "chain name `%s' too long (must be under %u chars)", 1722 chain, XT_EXTENSION_MAXNAMELEN); 1723 1724 /* only allocate handle if we weren't called with a handle */ 1725 if (!*handle) 1726 *handle = iptc_init(*table); 1727 1728 /* try to insmod the module if iptc_init failed */ 1729 if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1) 1730 *handle = iptc_init(*table); 1731 1732 if (!*handle) 1733 xtables_error(VERSION_PROBLEM, 1734 "can't initialize iptables table `%s': %s", 1735 *table, iptc_strerror(errno)); 1736 1737 if (command == CMD_APPEND 1738 || command == CMD_DELETE 1739 || command == CMD_CHECK 1740 || command == CMD_INSERT 1741 || command == CMD_REPLACE) { 1742 if (strcmp(chain, "PREROUTING") == 0 1743 || strcmp(chain, "INPUT") == 0) { 1744 /* -o not valid with incoming packets. */ 1745 if (cs.options & OPT_VIANAMEOUT) 1746 xtables_error(PARAMETER_PROBLEM, 1747 "Can't use -%c with %s\n", 1748 opt2char(OPT_VIANAMEOUT), 1749 chain); 1750 } 1751 1752 if (strcmp(chain, "POSTROUTING") == 0 1753 || strcmp(chain, "OUTPUT") == 0) { 1754 /* -i not valid with outgoing packets */ 1755 if (cs.options & OPT_VIANAMEIN) 1756 xtables_error(PARAMETER_PROBLEM, 1757 "Can't use -%c with %s\n", 1758 opt2char(OPT_VIANAMEIN), 1759 chain); 1760 } 1761 1762 if (cs.target && iptc_is_chain(cs.jumpto, *handle)) { 1763 fprintf(stderr, 1764 "Warning: using chain %s, not extension\n", 1765 cs.jumpto); 1766 1767 if (cs.target->t) 1768 free(cs.target->t); 1769 1770 cs.target = NULL; 1771 } 1772 1773 /* If they didn't specify a target, or it's a chain 1774 name, use standard. */ 1775 if (!cs.target 1776 && (strlen(cs.jumpto) == 0 1777 || iptc_is_chain(cs.jumpto, *handle))) { 1778 size_t size; 1779 1780 cs.target = xtables_find_target(XT_STANDARD_TARGET, 1781 XTF_LOAD_MUST_SUCCEED); 1782 1783 size = sizeof(struct xt_entry_target) 1784 + cs.target->size; 1785 cs.target->t = xtables_calloc(1, size); 1786 cs.target->t->u.target_size = size; 1787 strcpy(cs.target->t->u.user.name, cs.jumpto); 1788 if (!iptc_is_chain(cs.jumpto, *handle)) 1789 cs.target->t->u.user.revision = cs.target->revision; 1790 xs_init_target(cs.target); 1791 } 1792 1793 if (!cs.target) { 1794 /* it is no chain, and we can't load a plugin. 1795 * We cannot know if the plugin is corrupt, non 1796 * existant OR if the user just misspelled a 1797 * chain. */ 1798#ifdef IPT_F_GOTO 1799 if (cs.fw.ip.flags & IPT_F_GOTO) 1800 xtables_error(PARAMETER_PROBLEM, 1801 "goto '%s' is not a chain\n", 1802 cs.jumpto); 1803#endif 1804 xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); 1805 } else { 1806 e = generate_entry(&cs.fw, cs.matches, cs.target->t); 1807 free(cs.target->t); 1808 } 1809 } 1810 1811 switch (command) { 1812 case CMD_APPEND: 1813 ret = append_entry(chain, e, 1814 nsaddrs, saddrs, smasks, 1815 ndaddrs, daddrs, dmasks, 1816 cs.options&OPT_VERBOSE, 1817 *handle); 1818 break; 1819 case CMD_DELETE: 1820 ret = delete_entry(chain, e, 1821 nsaddrs, saddrs, smasks, 1822 ndaddrs, daddrs, dmasks, 1823 cs.options&OPT_VERBOSE, 1824 *handle, cs.matches, cs.target); 1825 break; 1826 case CMD_DELETE_NUM: 1827 ret = iptc_delete_num_entry(chain, rulenum - 1, *handle); 1828 break; 1829 case CMD_CHECK: 1830 ret = check_entry(chain, e, 1831 nsaddrs, saddrs, smasks, 1832 ndaddrs, daddrs, dmasks, 1833 cs.options&OPT_VERBOSE, 1834 *handle, cs.matches, cs.target); 1835 break; 1836 case CMD_REPLACE: 1837 ret = replace_entry(chain, e, rulenum - 1, 1838 saddrs, smasks, daddrs, dmasks, 1839 cs.options&OPT_VERBOSE, *handle); 1840 break; 1841 case CMD_INSERT: 1842 ret = insert_entry(chain, e, rulenum - 1, 1843 nsaddrs, saddrs, smasks, 1844 ndaddrs, daddrs, dmasks, 1845 cs.options&OPT_VERBOSE, 1846 *handle); 1847 break; 1848 case CMD_FLUSH: 1849 ret = flush_entries4(chain, cs.options&OPT_VERBOSE, *handle); 1850 break; 1851 case CMD_ZERO: 1852 ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle); 1853 break; 1854 case CMD_ZERO_NUM: 1855 ret = iptc_zero_counter(chain, rulenum, *handle); 1856 break; 1857 case CMD_LIST: 1858 case CMD_LIST|CMD_ZERO: 1859 case CMD_LIST|CMD_ZERO_NUM: 1860 ret = list_entries(chain, 1861 rulenum, 1862 cs.options&OPT_VERBOSE, 1863 cs.options&OPT_NUMERIC, 1864 cs.options&OPT_EXPANDED, 1865 cs.options&OPT_LINENUMBERS, 1866 *handle); 1867 if (ret && (command & CMD_ZERO)) 1868 ret = zero_entries(chain, 1869 cs.options&OPT_VERBOSE, *handle); 1870 if (ret && (command & CMD_ZERO_NUM)) 1871 ret = iptc_zero_counter(chain, rulenum, *handle); 1872 break; 1873 case CMD_LIST_RULES: 1874 case CMD_LIST_RULES|CMD_ZERO: 1875 case CMD_LIST_RULES|CMD_ZERO_NUM: 1876 ret = list_rules(chain, 1877 rulenum, 1878 cs.options&OPT_VERBOSE, 1879 *handle); 1880 if (ret && (command & CMD_ZERO)) 1881 ret = zero_entries(chain, 1882 cs.options&OPT_VERBOSE, *handle); 1883 if (ret && (command & CMD_ZERO_NUM)) 1884 ret = iptc_zero_counter(chain, rulenum, *handle); 1885 break; 1886 case CMD_NEW_CHAIN: 1887 ret = iptc_create_chain(chain, *handle); 1888 break; 1889 case CMD_DELETE_CHAIN: 1890 ret = delete_chain4(chain, cs.options&OPT_VERBOSE, *handle); 1891 break; 1892 case CMD_RENAME_CHAIN: 1893 ret = iptc_rename_chain(chain, newname, *handle); 1894 break; 1895 case CMD_SET_POLICY: 1896 ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle); 1897 break; 1898 default: 1899 /* We should never reach this... */ 1900 exit_tryhelp(2); 1901 } 1902 1903 if (verbose > 1) 1904 dump_entries(*handle); 1905 1906 xtables_rule_matches_free(&cs.matches); 1907 1908 if (e != NULL) { 1909 free(e); 1910 e = NULL; 1911 } 1912 1913 free(saddrs); 1914 free(smasks); 1915 free(daddrs); 1916 free(dmasks); 1917 xtables_free_opts(1); 1918 1919 return ret; 1920} 1921