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 <stdio.h> 33#include <stdlib.h> 34#include <dlfcn.h> 35#include <ctype.h> 36#include <stdarg.h> 37#include <limits.h> 38#include <unistd.h> 39#include <iptables.h> 40#include <fcntl.h> 41#include <sys/wait.h> 42 43#ifndef TRUE 44#define TRUE 1 45#endif 46#ifndef FALSE 47#define FALSE 0 48#endif 49 50#ifndef IPT_LIB_DIR 51#define IPT_LIB_DIR "/usr/local/lib/iptables" 52#endif 53 54#ifndef PROC_SYS_MODPROBE 55#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" 56#endif 57 58#define FMT_NUMERIC 0x0001 59#define FMT_NOCOUNTS 0x0002 60#define FMT_KILOMEGAGIGA 0x0004 61#define FMT_OPTIONS 0x0008 62#define FMT_NOTABLE 0x0010 63#define FMT_NOTARGET 0x0020 64#define FMT_VIA 0x0040 65#define FMT_NONEWLINE 0x0080 66#define FMT_LINENUMBERS 0x0100 67 68#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ 69 | FMT_NUMERIC | FMT_NOTABLE) 70#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) 71 72 73#define CMD_NONE 0x0000U 74#define CMD_INSERT 0x0001U 75#define CMD_DELETE 0x0002U 76#define CMD_DELETE_NUM 0x0004U 77#define CMD_REPLACE 0x0008U 78#define CMD_APPEND 0x0010U 79#define CMD_LIST 0x0020U 80#define CMD_FLUSH 0x0040U 81#define CMD_ZERO 0x0080U 82#define CMD_NEW_CHAIN 0x0100U 83#define CMD_DELETE_CHAIN 0x0200U 84#define CMD_SET_POLICY 0x0400U 85#define CMD_CHECK 0x0800U 86#define CMD_RENAME_CHAIN 0x1000U 87#define NUMBER_OF_CMD 13 88static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', 89 'N', 'X', 'P', 'E' }; 90 91#define OPTION_OFFSET 256 92 93#define OPT_NONE 0x00000U 94#define OPT_NUMERIC 0x00001U 95#define OPT_SOURCE 0x00002U 96#define OPT_DESTINATION 0x00004U 97#define OPT_PROTOCOL 0x00008U 98#define OPT_JUMP 0x00010U 99#define OPT_VERBOSE 0x00020U 100#define OPT_EXPANDED 0x00040U 101#define OPT_VIANAMEIN 0x00080U 102#define OPT_VIANAMEOUT 0x00100U 103#define OPT_FRAGMENT 0x00200U 104#define OPT_LINENUMBERS 0x00400U 105#define OPT_COUNTERS 0x00800U 106#define NUMBER_OF_OPT 12 107static const char optflags[NUMBER_OF_OPT] 108= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '3', 'c'}; 109 110static struct option original_opts[] = { 111 { "append", 1, 0, 'A' }, 112 { "delete", 1, 0, 'D' }, 113 { "insert", 1, 0, 'I' }, 114 { "replace", 1, 0, 'R' }, 115 { "list", 2, 0, 'L' }, 116 { "flush", 2, 0, 'F' }, 117 { "zero", 2, 0, 'Z' }, 118 { "new-chain", 1, 0, 'N' }, 119 { "delete-chain", 2, 0, 'X' }, 120 { "rename-chain", 2, 0, 'E' }, 121 { "policy", 1, 0, 'P' }, 122 { "source", 1, 0, 's' }, 123 { "destination", 1, 0, 'd' }, 124 { "src", 1, 0, 's' }, /* synonym */ 125 { "dst", 1, 0, 'd' }, /* synonym */ 126 { "protocol", 1, 0, 'p' }, 127 { "in-interface", 1, 0, 'i' }, 128 { "jump", 1, 0, 'j' }, 129 { "table", 1, 0, 't' }, 130 { "match", 1, 0, 'm' }, 131 { "numeric", 0, 0, 'n' }, 132 { "out-interface", 1, 0, 'o' }, 133 { "verbose", 0, 0, 'v' }, 134 { "exact", 0, 0, 'x' }, 135 { "fragments", 0, 0, 'f' }, 136 { "version", 0, 0, 'V' }, 137 { "help", 2, 0, 'h' }, 138 { "line-numbers", 0, 0, '0' }, 139 { "modprobe", 1, 0, 'M' }, 140 { "set-counters", 1, 0, 'c' }, 141 { 0 } 142}; 143 144#ifndef __OPTIMIZE__ 145struct ipt_entry_target * 146ipt_get_target(struct ipt_entry *e) 147{ 148 return (void *)e + e->target_offset; 149} 150#endif 151 152static struct option *opts = original_opts; 153static unsigned int global_option_offset = 0; 154 155/* Table of legal combinations of commands and options. If any of the 156 * given commands make an option legal, that option is legal (applies to 157 * CMD_LIST and CMD_ZERO only). 158 * Key: 159 * + compulsory 160 * x illegal 161 * optional 162 */ 163 164static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = 165/* Well, it's better than "Re: Linux vs FreeBSD" */ 166{ 167 /* -n -s -d -p -j -v -x -i -o -f --line */ 168/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 169/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 170/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'}, 171/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 172/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'}, 173/*LIST*/ {' ','x','x','x','x',' ',' ','x','x','x',' '}, 174/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 175/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 176/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 177/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'}, 178/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x'}, 179/*CHECK*/ {'x','+','+','+','x',' ','x',' ',' ',' ','x'}, 180/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'} 181}; 182 183static int inverse_for_options[NUMBER_OF_OPT] = 184{ 185/* -n */ 0, 186/* -s */ IPT_INV_SRCIP, 187/* -d */ IPT_INV_DSTIP, 188/* -p */ IPT_INV_PROTO, 189/* -j */ 0, 190/* -v */ 0, 191/* -x */ 0, 192/* -i */ IPT_INV_VIA_IN, 193/* -o */ IPT_INV_VIA_OUT, 194/* -f */ IPT_INV_FRAG, 195/*--line*/ 0 196}; 197 198const char *program_version; 199const char *program_name; 200 201/* Keeping track of external matches and targets: linked lists. */ 202struct iptables_match *iptables_matches = NULL; 203struct iptables_target *iptables_targets = NULL; 204 205/* Extra debugging from libiptc */ 206extern void dump_entries(const iptc_handle_t handle); 207 208/* A few hardcoded protocols for 'all' and in case the user has no 209 /etc/protocols */ 210struct pprot { 211 char *name; 212 u_int8_t num; 213}; 214 215/* Primitive headers... */ 216/* defined in netinet/in.h */ 217 218static const struct pprot chain_protos[] = { 219 { "tcp", IPPROTO_TCP }, 220 { "udp", IPPROTO_UDP }, 221 { "icmp", IPPROTO_ICMP }, 222 { "esp", IPPROTO_ESP }, 223 { "ah", IPPROTO_AH }, 224 { "all", 0 }, 225}; 226 227static char * 228proto_to_name(u_int8_t proto, int nolookup) 229{ 230 unsigned int i; 231 232 if (proto && !nolookup) { 233 struct protoent *pent = getprotobynumber(proto); 234 if (pent) 235 return pent->p_name; 236 } 237 238 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++) 239 if (chain_protos[i].num == proto) 240 return chain_protos[i].name; 241 242 return NULL; 243} 244 245struct in_addr * 246dotted_to_addr(const char *dotted) 247{ 248 static struct in_addr addr; 249 unsigned char *addrp; 250 char *p, *q; 251 unsigned int onebyte; 252 int i; 253 char buf[20]; 254 255 /* copy dotted string, because we need to modify it */ 256 strncpy(buf, dotted, sizeof(buf) - 1); 257 addrp = (unsigned char *) &(addr.s_addr); 258 259 p = buf; 260 for (i = 0; i < 3; i++) { 261 if ((q = strchr(p, '.')) == NULL) 262 return (struct in_addr *) NULL; 263 264 *q = '\0'; 265 if (string_to_number(p, 0, 255, &onebyte) == -1) 266 return (struct in_addr *) NULL; 267 268 addrp[i] = (unsigned char) onebyte; 269 p = q + 1; 270 } 271 272 /* we've checked 3 bytes, now we check the last one */ 273 if (string_to_number(p, 0, 255, &onebyte) == -1) 274 return (struct in_addr *) NULL; 275 276 addrp[3] = (unsigned char) onebyte; 277 278 return &addr; 279} 280 281static struct in_addr * 282network_to_addr(const char *name) 283{ 284 struct netent *net; 285 static struct in_addr addr; 286 287 if ((net = getnetbyname(name)) != NULL) { 288 if (net->n_addrtype != AF_INET) 289 return (struct in_addr *) NULL; 290 addr.s_addr = htonl((unsigned long) net->n_net); 291 return &addr; 292 } 293 294 return (struct in_addr *) NULL; 295} 296 297static void 298inaddrcpy(struct in_addr *dst, struct in_addr *src) 299{ 300 /* memcpy(dst, src, sizeof(struct in_addr)); */ 301 dst->s_addr = src->s_addr; 302} 303 304void 305exit_error(enum exittype status, char *msg, ...) 306{ 307 va_list args; 308 309 va_start(args, msg); 310 fprintf(stderr, "%s v%s: ", program_name, program_version); 311 vfprintf(stderr, msg, args); 312 va_end(args); 313 fprintf(stderr, "\n"); 314 if (status == PARAMETER_PROBLEM) 315 exit_tryhelp(status); 316 if (status == VERSION_PROBLEM) 317 fprintf(stderr, 318 "Perhaps iptables or your kernel needs to be upgraded.\n"); 319 exit(status); 320} 321 322void 323exit_tryhelp(int status) 324{ 325 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", 326 program_name, program_name ); 327 exit(status); 328} 329 330void 331exit_printhelp(void) 332{ 333 struct iptables_match *m = NULL; 334 struct iptables_target *t = NULL; 335 336 printf("%s v%s\n\n" 337"Usage: %s -[AD] chain rule-specification [options]\n" 338" %s -[RI] chain rulenum rule-specification [options]\n" 339" %s -D chain rulenum [options]\n" 340" %s -[LFZ] [chain] [options]\n" 341" %s -[NX] chain\n" 342" %s -E old-chain-name new-chain-name\n" 343" %s -P chain target [options]\n" 344" %s -h (print this help information)\n\n", 345 program_name, program_version, program_name, program_name, 346 program_name, program_name, program_name, program_name, 347 program_name, program_name); 348 349 printf( 350"Commands:\n" 351"Either long or short options are allowed.\n" 352" --append -A chain Append to chain\n" 353" --delete -D chain Delete matching rule from chain\n" 354" --delete -D chain rulenum\n" 355" Delete rule rulenum (1 = first) from chain\n" 356" --insert -I chain [rulenum]\n" 357" Insert in chain as rulenum (default 1=first)\n" 358" --replace -R chain rulenum\n" 359" Replace rule rulenum (1 = first) in chain\n" 360" --list -L [chain] List the rules in a chain or all chains\n" 361" --flush -F [chain] Delete all rules in chain or all chains\n" 362" --zero -Z [chain] Zero counters in chain or all chains\n" 363" --new -N chain Create a new user-defined chain\n" 364" --delete-chain\n" 365" -X [chain] Delete a user-defined chain\n" 366" --policy -P chain target\n" 367" Change policy on chain to target\n" 368" --rename-chain\n" 369" -E old-chain new-chain\n" 370" Change chain name, (moving any references)\n" 371 372"Options:\n" 373" --proto -p [!] proto protocol: by number or name, eg. `tcp'\n" 374" --source -s [!] address[/mask]\n" 375" source specification\n" 376" --destination -d [!] address[/mask]\n" 377" destination specification\n" 378" --in-interface -i [!] input name[+]\n" 379" network interface name ([+] for wildcard)\n" 380" --jump -j target\n" 381" target for rule (may load target extension)\n" 382" --match -m match\n" 383" extended match (may load extension)\n" 384" --numeric -n numeric output of addresses and ports\n" 385" --out-interface -o [!] output name[+]\n" 386" network interface name ([+] for wildcard)\n" 387" --table -t table table to manipulate (default: `filter')\n" 388" --verbose -v verbose mode\n" 389" --line-numbers print line numbers when listing\n" 390" --exact -x expand numbers (display exact values)\n" 391"[!] --fragment -f match second or further fragments only\n" 392" --modprobe=<command> try to insert modules using this command\n" 393" --set-counters PKTS BYTES set the counter during insert/append\n" 394"[!] --version -V print package version.\n"); 395 396 /* Print out any special helps. A user might like to be able 397 to add a --help to the commandline, and see expected 398 results. So we call help for all matches & targets */ 399 for (t=iptables_targets;t;t=t->next) { 400 printf("\n"); 401 t->help(); 402 } 403 for (m=iptables_matches;m;m=m->next) { 404 printf("\n"); 405 m->help(); 406 } 407 exit(0); 408} 409 410static void 411generic_opt_check(int command, int options) 412{ 413 int i, j, legal = 0; 414 415 /* Check that commands are valid with options. Complicated by the 416 * fact that if an option is legal with *any* command given, it is 417 * legal overall (ie. -z and -l). 418 */ 419 for (i = 0; i < NUMBER_OF_OPT; i++) { 420 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ 421 422 for (j = 0; j < NUMBER_OF_CMD; j++) { 423 if (!(command & (1<<j))) 424 continue; 425 426 if (!(options & (1<<i))) { 427 if (commands_v_options[j][i] == '+') 428 exit_error(PARAMETER_PROBLEM, 429 "You need to supply the `-%c' " 430 "option for this command\n", 431 optflags[i]); 432 } else { 433 if (commands_v_options[j][i] != 'x') 434 legal = 1; 435 else if (legal == 0) 436 legal = -1; 437 } 438 } 439 if (legal == -1) 440 exit_error(PARAMETER_PROBLEM, 441 "Illegal option `-%c' with this command\n", 442 optflags[i]); 443 } 444} 445 446static char 447opt2char(int option) 448{ 449 const char *ptr; 450 for (ptr = optflags; option > 1; option >>= 1, ptr++); 451 452 return *ptr; 453} 454 455static char 456cmd2char(int option) 457{ 458 const char *ptr; 459 for (ptr = cmdflags; option > 1; option >>= 1, ptr++); 460 461 return *ptr; 462} 463 464static void 465add_command(int *cmd, const int newcmd, const int othercmds, int invert) 466{ 467 if (invert) 468 exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); 469 if (*cmd & (~othercmds)) 470 exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n", 471 cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); 472 *cmd |= newcmd; 473} 474 475int 476check_inverse(const char option[], int *invert, int *optind, int argc) 477{ 478 if (option && strcmp(option, "!") == 0) { 479 if (*invert) 480 exit_error(PARAMETER_PROBLEM, 481 "Multiple `!' flags not allowed"); 482 *invert = TRUE; 483 if (optind) { 484 *optind = *optind+1; 485 if (argc && *optind > argc) 486 exit_error(PARAMETER_PROBLEM, 487 "no argument following `!'"); 488 } 489 490 return TRUE; 491 } 492 return FALSE; 493} 494 495static void * 496fw_calloc(size_t count, size_t size) 497{ 498 void *p; 499 500 if ((p = calloc(count, size)) == NULL) { 501 perror("iptables: calloc failed"); 502 exit(1); 503 } 504 return p; 505} 506 507static void * 508fw_malloc(size_t size) 509{ 510 void *p; 511 512 if ((p = malloc(size)) == NULL) { 513 perror("iptables: malloc failed"); 514 exit(1); 515 } 516 return p; 517} 518 519static struct in_addr * 520host_to_addr(const char *name, unsigned int *naddr) 521{ 522 struct hostent *host; 523 struct in_addr *addr; 524 unsigned int i; 525 526 *naddr = 0; 527 if ((host = gethostbyname(name)) != NULL) { 528 if (host->h_addrtype != AF_INET || 529 host->h_length != sizeof(struct in_addr)) 530 return (struct in_addr *) NULL; 531 532 while (host->h_addr_list[*naddr] != (char *) NULL) 533 (*naddr)++; 534 addr = fw_calloc(*naddr, sizeof(struct in_addr)); 535 for (i = 0; i < *naddr; i++) 536 inaddrcpy(&(addr[i]), 537 (struct in_addr *) host->h_addr_list[i]); 538 return addr; 539 } 540 541 return (struct in_addr *) NULL; 542} 543 544static char * 545addr_to_host(const struct in_addr *addr) 546{ 547 struct hostent *host; 548 549 if ((host = gethostbyaddr((char *) addr, 550 sizeof(struct in_addr), AF_INET)) != NULL) 551 return (char *) host->h_name; 552 553 return (char *) NULL; 554} 555 556/* 557 * All functions starting with "parse" should succeed, otherwise 558 * the program fails. 559 * Most routines return pointers to static data that may change 560 * between calls to the same or other routines with a few exceptions: 561 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" 562 * return global static data. 563*/ 564 565static struct in_addr * 566parse_hostnetwork(const char *name, unsigned int *naddrs) 567{ 568 struct in_addr *addrp, *addrptmp; 569 570 if ((addrptmp = dotted_to_addr(name)) != NULL || 571 (addrptmp = network_to_addr(name)) != NULL) { 572 addrp = fw_malloc(sizeof(struct in_addr)); 573 inaddrcpy(addrp, addrptmp); 574 *naddrs = 1; 575 return addrp; 576 } 577 if ((addrp = host_to_addr(name, naddrs)) != NULL) 578 return addrp; 579 580 exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name); 581} 582 583static struct in_addr * 584parse_mask(char *mask) 585{ 586 static struct in_addr maskaddr; 587 struct in_addr *addrp; 588 unsigned int bits; 589 590 if (mask == NULL) { 591 /* no mask at all defaults to 32 bits */ 592 maskaddr.s_addr = 0xFFFFFFFF; 593 return &maskaddr; 594 } 595 if ((addrp = dotted_to_addr(mask)) != NULL) 596 /* dotted_to_addr already returns a network byte order addr */ 597 return addrp; 598 if (string_to_number(mask, 0, 32, &bits) == -1) 599 exit_error(PARAMETER_PROBLEM, 600 "invalid mask `%s' specified", mask); 601 if (bits != 0) { 602 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); 603 return &maskaddr; 604 } 605 606 maskaddr.s_addr = 0L; 607 return &maskaddr; 608} 609 610void 611parse_hostnetworkmask(const char *name, struct in_addr **addrpp, 612 struct in_addr *maskp, unsigned int *naddrs) 613{ 614 struct in_addr *addrp; 615 char buf[256]; 616 char *p; 617 int i, j, k, n; 618 619 strncpy(buf, name, sizeof(buf) - 1); 620 if ((p = strrchr(buf, '/')) != NULL) { 621 *p = '\0'; 622 addrp = parse_mask(p + 1); 623 } else 624 addrp = parse_mask(NULL); 625 inaddrcpy(maskp, addrp); 626 627 /* if a null mask is given, the name is ignored, like in "any/0" */ 628 if (maskp->s_addr == 0L) 629 strcpy(buf, "0.0.0.0"); 630 631 addrp = *addrpp = parse_hostnetwork(buf, naddrs); 632 n = *naddrs; 633 for (i = 0, j = 0; i < n; i++) { 634 addrp[j++].s_addr &= maskp->s_addr; 635 for (k = 0; k < j - 1; k++) { 636 if (addrp[k].s_addr == addrp[j - 1].s_addr) { 637 (*naddrs)--; 638 j--; 639 break; 640 } 641 } 642 } 643} 644 645struct iptables_match * 646find_match(const char *name, enum ipt_tryload tryload) 647{ 648 struct iptables_match *ptr; 649 650 for (ptr = iptables_matches; ptr; ptr = ptr->next) { 651 if (strcmp(name, ptr->name) == 0) 652 break; 653 } 654 655#ifndef NO_SHARED_LIBS 656 if (!ptr && tryload != DONT_LOAD) { 657 char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") 658 + strlen(name)]; 659 sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name); 660 if (dlopen(path, RTLD_NOW)) { 661 /* Found library. If it didn't register itself, 662 maybe they specified target as match. */ 663 ptr = find_match(name, DONT_LOAD); 664 665 if (!ptr) 666 exit_error(PARAMETER_PROBLEM, 667 "Couldn't load match `%s'\n", 668 name); 669 } else if (tryload == LOAD_MUST_SUCCEED) 670 exit_error(PARAMETER_PROBLEM, 671 "Couldn't load match `%s':%s\n", 672 name, dlerror()); 673 } 674#else 675 if (ptr && !ptr->loaded) { 676 if (tryload != DONT_LOAD) 677 ptr->loaded = 1; 678 else 679 ptr = NULL; 680 } 681 if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { 682 exit_error(PARAMETER_PROBLEM, 683 "Couldn't find match `%s'\n", name); 684 } 685#endif 686 687 if (ptr) 688 ptr->used = 1; 689 690 return ptr; 691} 692 693/* Christophe Burki wants `-p 6' to imply `-m tcp'. */ 694static struct iptables_match * 695find_proto(const char *pname, enum ipt_tryload tryload, int nolookup) 696{ 697 unsigned int proto; 698 699 if (string_to_number(pname, 0, 255, &proto) != -1) { 700 char *protoname = proto_to_name(proto, nolookup); 701 702 if (protoname) 703 return find_match(protoname, tryload); 704 } else 705 return find_match(pname, tryload); 706 707 return NULL; 708} 709 710u_int16_t 711parse_protocol(const char *s) 712{ 713 unsigned int proto; 714 715 if (string_to_number(s, 0, 255, &proto) == -1) { 716 struct protoent *pent; 717 718 if ((pent = getprotobyname(s))) 719 proto = pent->p_proto; 720 else { 721 unsigned int i; 722 for (i = 0; 723 i < sizeof(chain_protos)/sizeof(struct pprot); 724 i++) { 725 if (strcmp(s, chain_protos[i].name) == 0) { 726 proto = chain_protos[i].num; 727 break; 728 } 729 } 730 if (i == sizeof(chain_protos)/sizeof(struct pprot)) 731 exit_error(PARAMETER_PROBLEM, 732 "unknown protocol `%s' specified", 733 s); 734 } 735 } 736 737 return (u_int16_t)proto; 738} 739 740static void 741parse_interface(const char *arg, char *vianame, unsigned char *mask) 742{ 743 int vialen = strlen(arg); 744 unsigned int i; 745 746 memset(mask, 0, IFNAMSIZ); 747 memset(vianame, 0, IFNAMSIZ); 748 749 if (vialen + 1 > IFNAMSIZ) 750 exit_error(PARAMETER_PROBLEM, 751 "interface name `%s' must be shorter than IFNAMSIZ" 752 " (%i)", arg, IFNAMSIZ-1); 753 754 strcpy(vianame, arg); 755 if (vialen == 0) 756 memset(mask, 0, IFNAMSIZ); 757 else if (vianame[vialen - 1] == '+') { 758 memset(mask, 0xFF, vialen - 1); 759 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1); 760 /* Don't remove `+' here! -HW */ 761 } else { 762 /* Include nul-terminator in match */ 763 memset(mask, 0xFF, vialen + 1); 764 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1); 765 for (i = 0; vianame[i]; i++) { 766 if (!isalnum(vianame[i]) 767 && vianame[i] != '_' 768 && vianame[i] != '.') { 769 printf("Warning: wierd character in interface" 770 " `%s' (No aliases, :, ! or *).\n", 771 vianame); 772 break; 773 } 774 } 775 } 776} 777 778/* Can't be zero. */ 779static int 780parse_rulenumber(const char *rule) 781{ 782 unsigned int rulenum; 783 784 if (string_to_number(rule, 1, INT_MAX, &rulenum) == -1) 785 exit_error(PARAMETER_PROBLEM, 786 "Invalid rule number `%s'", rule); 787 788 return rulenum; 789} 790 791static const char * 792parse_target(const char *targetname) 793{ 794 const char *ptr; 795 796 if (strlen(targetname) < 1) 797 exit_error(PARAMETER_PROBLEM, 798 "Invalid target name (too short)"); 799 800 if (strlen(targetname)+1 > sizeof(ipt_chainlabel)) 801 exit_error(PARAMETER_PROBLEM, 802 "Invalid target name `%s' (%i chars max)", 803 targetname, sizeof(ipt_chainlabel)-1); 804 805 for (ptr = targetname; *ptr; ptr++) 806 if (isspace(*ptr)) 807 exit_error(PARAMETER_PROBLEM, 808 "Invalid target name `%s'", targetname); 809 return targetname; 810} 811 812static char * 813addr_to_network(const struct in_addr *addr) 814{ 815 struct netent *net; 816 817 if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL) 818 return (char *) net->n_name; 819 820 return (char *) NULL; 821} 822 823char * 824addr_to_dotted(const struct in_addr *addrp) 825{ 826 static char buf[20]; 827 const unsigned char *bytep; 828 829 bytep = (const unsigned char *) &(addrp->s_addr); 830 sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); 831 return buf; 832} 833 834char * 835addr_to_anyname(const struct in_addr *addr) 836{ 837 char *name; 838 839 if ((name = addr_to_host(addr)) != NULL || 840 (name = addr_to_network(addr)) != NULL) 841 return name; 842 843 return addr_to_dotted(addr); 844} 845 846char * 847mask_to_dotted(const struct in_addr *mask) 848{ 849 int i; 850 static char buf[20]; 851 u_int32_t maskaddr, bits; 852 853 maskaddr = ntohl(mask->s_addr); 854 855 if (maskaddr == 0xFFFFFFFFL) 856 /* we don't want to see "/32" */ 857 return ""; 858 859 i = 32; 860 bits = 0xFFFFFFFEL; 861 while (--i >= 0 && maskaddr != bits) 862 bits <<= 1; 863 if (i >= 0) 864 sprintf(buf, "/%d", i); 865 else 866 /* mask was not a decent combination of 1's and 0's */ 867 sprintf(buf, "/%s", addr_to_dotted(mask)); 868 869 return buf; 870} 871 872int 873string_to_number(const char *s, unsigned int min, unsigned int max, 874 unsigned int *ret) 875{ 876 long number; 877 char *end; 878 879 /* Handle hex, octal, etc. */ 880 errno = 0; 881 number = strtol(s, &end, 0); 882 if (*end == '\0' && end != s) { 883 /* we parsed a number, let's see if we want this */ 884 if (errno != ERANGE && min <= number && number <= max) { 885 *ret = number; 886 return 0; 887 } 888 } 889 return -1; 890} 891 892static void 893set_option(unsigned int *options, unsigned int option, u_int8_t *invflg, 894 int invert) 895{ 896 if (*options & option) 897 exit_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", 898 opt2char(option)); 899 *options |= option; 900 901 if (invert) { 902 unsigned int i; 903 for (i = 0; 1 << i != option; i++); 904 905 if (!inverse_for_options[i]) 906 exit_error(PARAMETER_PROBLEM, 907 "cannot have ! before -%c", 908 opt2char(option)); 909 *invflg |= inverse_for_options[i]; 910 } 911} 912 913struct iptables_target * 914find_target(const char *name, enum ipt_tryload tryload) 915{ 916 struct iptables_target *ptr; 917 918 /* Standard target? */ 919 if (strcmp(name, "") == 0 920 || strcmp(name, IPTC_LABEL_ACCEPT) == 0 921 || strcmp(name, IPTC_LABEL_DROP) == 0 922 || strcmp(name, IPTC_LABEL_QUEUE) == 0 923 || strcmp(name, IPTC_LABEL_RETURN) == 0) 924 name = "standard"; 925 926 for (ptr = iptables_targets; ptr; ptr = ptr->next) { 927 if (strcmp(name, ptr->name) == 0) 928 break; 929 } 930 931#ifndef NO_SHARED_LIBS 932 if (!ptr && tryload != DONT_LOAD) { 933 char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so") 934 + strlen(name)]; 935 sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name); 936 if (dlopen(path, RTLD_NOW)) { 937 /* Found library. If it didn't register itself, 938 maybe they specified match as a target. */ 939 ptr = find_target(name, DONT_LOAD); 940 if (!ptr) 941 exit_error(PARAMETER_PROBLEM, 942 "Couldn't load target `%s'\n", 943 name); 944 } else if (tryload == LOAD_MUST_SUCCEED) 945 exit_error(PARAMETER_PROBLEM, 946 "Couldn't load target `%s':%s\n", 947 name, dlerror()); 948 } 949#else 950 if (ptr && !ptr->loaded) { 951 if (tryload != DONT_LOAD) 952 ptr->loaded = 1; 953 else 954 ptr = NULL; 955 } 956 if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { 957 exit_error(PARAMETER_PROBLEM, 958 "Couldn't find target `%s'\n", name); 959 } 960#endif 961 962 if (ptr) 963 ptr->used = 1; 964 965 return ptr; 966} 967 968static struct option * 969merge_options(struct option *oldopts, const struct option *newopts, 970 unsigned int *option_offset) 971{ 972 unsigned int num_old, num_new, i; 973 struct option *merge; 974 975 for (num_old = 0; oldopts[num_old].name; num_old++); 976 for (num_new = 0; newopts[num_new].name; num_new++); 977 978 global_option_offset += OPTION_OFFSET; 979 *option_offset = global_option_offset; 980 981 merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); 982 memcpy(merge, oldopts, num_old * sizeof(struct option)); 983 for (i = 0; i < num_new; i++) { 984 merge[num_old + i] = newopts[i]; 985 merge[num_old + i].val += *option_offset; 986 } 987 memset(merge + num_old + num_new, 0, sizeof(struct option)); 988 989 return merge; 990} 991 992void 993register_match(struct iptables_match *me) 994{ 995 struct iptables_match **i; 996 997 if (strcmp(me->version, program_version) != 0) { 998 fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n", 999 program_name, me->name, me->version, program_version); 1000 exit(1); 1001 } 1002 1003 if (find_match(me->name, DONT_LOAD)) { 1004 fprintf(stderr, "%s: match `%s' already registered.\n", 1005 program_name, me->name); 1006 exit(1); 1007 } 1008 1009 if (me->size != IPT_ALIGN(me->size)) { 1010 fprintf(stderr, "%s: match `%s' has invalid size %u.\n", 1011 program_name, me->name, me->size); 1012 exit(1); 1013 } 1014 1015 /* Append to list. */ 1016 for (i = &iptables_matches; *i; i = &(*i)->next); 1017 me->next = NULL; 1018 *i = me; 1019 1020 me->m = NULL; 1021 me->mflags = 0; 1022} 1023 1024void 1025register_target(struct iptables_target *me) 1026{ 1027 if (strcmp(me->version, program_version) != 0) { 1028 fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n", 1029 program_name, me->name, me->version, program_version); 1030 exit(1); 1031 } 1032 1033 if (find_target(me->name, DONT_LOAD)) { 1034 fprintf(stderr, "%s: target `%s' already registered.\n", 1035 program_name, me->name); 1036 exit(1); 1037 } 1038 1039 if (me->size != IPT_ALIGN(me->size)) { 1040 fprintf(stderr, "%s: target `%s' has invalid size %u.\n", 1041 program_name, me->name, me->size); 1042 exit(1); 1043 } 1044 1045 /* Prepend to list. */ 1046 me->next = iptables_targets; 1047 iptables_targets = me; 1048 me->t = NULL; 1049 me->tflags = 0; 1050} 1051 1052static void 1053print_num(u_int64_t number, unsigned int format) 1054{ 1055 if (format & FMT_KILOMEGAGIGA) { 1056 if (number > 99999) { 1057 number = (number + 500) / 1000; 1058 if (number > 9999) { 1059 number = (number + 500) / 1000; 1060 if (number > 9999) { 1061 number = (number + 500) / 1000; 1062 if (number > 9999) { 1063 number = (number + 500) / 1000; 1064 printf(FMT("%4lluT ","%lluT "), number); 1065 } 1066 else printf(FMT("%4lluG ","%lluG "), number); 1067 } 1068 else printf(FMT("%4lluM ","%lluM "), number); 1069 } else 1070 printf(FMT("%4lluK ","%lluK "), number); 1071 } else 1072 printf(FMT("%5llu ","%llu "), number); 1073 } else 1074 printf(FMT("%8llu ","%llu "), number); 1075} 1076 1077 1078static void 1079print_header(unsigned int format, const char *chain, iptc_handle_t *handle) 1080{ 1081 struct ipt_counters counters; 1082 const char *pol = iptc_get_policy(chain, &counters, handle); 1083 printf("Chain %s", chain); 1084 if (pol) { 1085 printf(" (policy %s", pol); 1086 if (!(format & FMT_NOCOUNTS)) { 1087 fputc(' ', stdout); 1088 print_num(counters.pcnt, (format|FMT_NOTABLE)); 1089 fputs("packets, ", stdout); 1090 print_num(counters.bcnt, (format|FMT_NOTABLE)); 1091 fputs("bytes", stdout); 1092 } 1093 printf(")\n"); 1094 } else { 1095 unsigned int refs; 1096 if (!iptc_get_references(&refs, chain, handle)) 1097 printf(" (ERROR obtaining refs)\n"); 1098 else 1099 printf(" (%u references)\n", refs); 1100 } 1101 1102 if (format & FMT_LINENUMBERS) 1103 printf(FMT("%-4s ", "%s "), "num"); 1104 if (!(format & FMT_NOCOUNTS)) { 1105 if (format & FMT_KILOMEGAGIGA) { 1106 printf(FMT("%5s ","%s "), "pkts"); 1107 printf(FMT("%5s ","%s "), "bytes"); 1108 } else { 1109 printf(FMT("%8s ","%s "), "pkts"); 1110 printf(FMT("%10s ","%s "), "bytes"); 1111 } 1112 } 1113 if (!(format & FMT_NOTARGET)) 1114 printf(FMT("%-9s ","%s "), "target"); 1115 fputs(" prot ", stdout); 1116 if (format & FMT_OPTIONS) 1117 fputs("opt", stdout); 1118 if (format & FMT_VIA) { 1119 printf(FMT(" %-6s ","%s "), "in"); 1120 printf(FMT("%-6s ","%s "), "out"); 1121 } 1122 printf(FMT(" %-19s ","%s "), "source"); 1123 printf(FMT(" %-19s "," %s "), "destination"); 1124 printf("\n"); 1125} 1126 1127 1128static int 1129print_match(const struct ipt_entry_match *m, 1130 const struct ipt_ip *ip, 1131 int numeric) 1132{ 1133 struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD); 1134 1135 if (match) { 1136 if (match->print) 1137 match->print(ip, m, numeric); 1138 else 1139 printf("%s ", match->name); 1140 } else { 1141 if (m->u.user.name[0]) 1142 printf("UNKNOWN match `%s' ", m->u.user.name); 1143 } 1144 /* Don't stop iterating. */ 1145 return 0; 1146} 1147 1148/* e is called `fw' here for hysterical raisins */ 1149static void 1150print_firewall(const struct ipt_entry *fw, 1151 const char *targname, 1152 unsigned int num, 1153 unsigned int format, 1154 const iptc_handle_t handle) 1155{ 1156 struct iptables_target *target = NULL; 1157 const struct ipt_entry_target *t; 1158 u_int8_t flags; 1159 char buf[BUFSIZ]; 1160 1161 if (!iptc_is_chain(targname, handle)) 1162 target = find_target(targname, TRY_LOAD); 1163 else 1164 target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED); 1165 1166 t = ipt_get_target((struct ipt_entry *)fw); 1167 flags = fw->ip.flags; 1168 1169 if (format & FMT_LINENUMBERS) 1170 printf(FMT("%-4u ", "%u "), num+1); 1171 1172 if (!(format & FMT_NOCOUNTS)) { 1173 print_num(fw->counters.pcnt, format); 1174 print_num(fw->counters.bcnt, format); 1175 } 1176 1177 if (!(format & FMT_NOTARGET)) 1178 printf(FMT("%-9s ", "%s "), targname); 1179 1180 fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout); 1181 { 1182 char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); 1183 if (pname) 1184 printf(FMT("%-5s", "%s "), pname); 1185 else 1186 printf(FMT("%-5hu", "%hu "), fw->ip.proto); 1187 } 1188 1189 if (format & FMT_OPTIONS) { 1190 if (format & FMT_NOTABLE) 1191 fputs("opt ", stdout); 1192 fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); 1193 fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); 1194 fputc(' ', stdout); 1195 } 1196 1197 if (format & FMT_VIA) { 1198 char iface[IFNAMSIZ+2]; 1199 1200 if (fw->ip.invflags & IPT_INV_VIA_IN) { 1201 iface[0] = '!'; 1202 iface[1] = '\0'; 1203 } 1204 else iface[0] = '\0'; 1205 1206 if (fw->ip.iniface[0] != '\0') { 1207 strcat(iface, fw->ip.iniface); 1208 } 1209 else if (format & FMT_NUMERIC) strcat(iface, "*"); 1210 else strcat(iface, "any"); 1211 printf(FMT(" %-6s ","in %s "), iface); 1212 1213 if (fw->ip.invflags & IPT_INV_VIA_OUT) { 1214 iface[0] = '!'; 1215 iface[1] = '\0'; 1216 } 1217 else iface[0] = '\0'; 1218 1219 if (fw->ip.outiface[0] != '\0') { 1220 strcat(iface, fw->ip.outiface); 1221 } 1222 else if (format & FMT_NUMERIC) strcat(iface, "*"); 1223 else strcat(iface, "any"); 1224 printf(FMT("%-6s ","out %s "), iface); 1225 } 1226 1227 fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout); 1228 if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC)) 1229 printf(FMT("%-19s ","%s "), "anywhere"); 1230 else { 1231 if (format & FMT_NUMERIC) 1232 sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src))); 1233 else 1234 sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src))); 1235 strcat(buf, mask_to_dotted(&(fw->ip.smsk))); 1236 printf(FMT("%-19s ","%s "), buf); 1237 } 1238 1239 fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout); 1240 if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC)) 1241 printf(FMT("%-19s","-> %s"), "anywhere"); 1242 else { 1243 if (format & FMT_NUMERIC) 1244 sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst))); 1245 else 1246 sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst))); 1247 strcat(buf, mask_to_dotted(&(fw->ip.dmsk))); 1248 printf(FMT("%-19s","-> %s"), buf); 1249 } 1250 1251 if (format & FMT_NOTABLE) 1252 fputs(" ", stdout); 1253 1254 IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); 1255 1256 if (target) { 1257 if (target->print) 1258 /* Print the target information. */ 1259 target->print(&fw->ip, t, format & FMT_NUMERIC); 1260 } else if (t->u.target_size != sizeof(*t)) 1261 printf("[%u bytes of unknown target data] ", 1262 t->u.target_size - sizeof(*t)); 1263 1264 if (!(format & FMT_NONEWLINE)) 1265 fputc('\n', stdout); 1266} 1267 1268static void 1269print_firewall_line(const struct ipt_entry *fw, 1270 const iptc_handle_t h) 1271{ 1272 struct ipt_entry_target *t; 1273 1274 t = ipt_get_target((struct ipt_entry *)fw); 1275 print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); 1276} 1277 1278static int 1279append_entry(const ipt_chainlabel chain, 1280 struct ipt_entry *fw, 1281 unsigned int nsaddrs, 1282 const struct in_addr saddrs[], 1283 unsigned int ndaddrs, 1284 const struct in_addr daddrs[], 1285 int verbose, 1286 iptc_handle_t *handle) 1287{ 1288 unsigned int i, j; 1289 int ret = 1; 1290 1291 for (i = 0; i < nsaddrs; i++) { 1292 fw->ip.src.s_addr = saddrs[i].s_addr; 1293 for (j = 0; j < ndaddrs; j++) { 1294 fw->ip.dst.s_addr = daddrs[j].s_addr; 1295 if (verbose) 1296 print_firewall_line(fw, *handle); 1297 ret &= iptc_append_entry(chain, fw, handle); 1298 } 1299 } 1300 1301 return ret; 1302} 1303 1304static int 1305replace_entry(const ipt_chainlabel chain, 1306 struct ipt_entry *fw, 1307 unsigned int rulenum, 1308 const struct in_addr *saddr, 1309 const struct in_addr *daddr, 1310 int verbose, 1311 iptc_handle_t *handle) 1312{ 1313 fw->ip.src.s_addr = saddr->s_addr; 1314 fw->ip.dst.s_addr = daddr->s_addr; 1315 1316 if (verbose) 1317 print_firewall_line(fw, *handle); 1318 return iptc_replace_entry(chain, fw, rulenum, handle); 1319} 1320 1321static int 1322insert_entry(const ipt_chainlabel chain, 1323 struct ipt_entry *fw, 1324 unsigned int rulenum, 1325 unsigned int nsaddrs, 1326 const struct in_addr saddrs[], 1327 unsigned int ndaddrs, 1328 const struct in_addr daddrs[], 1329 int verbose, 1330 iptc_handle_t *handle) 1331{ 1332 unsigned int i, j; 1333 int ret = 1; 1334 1335 for (i = 0; i < nsaddrs; i++) { 1336 fw->ip.src.s_addr = saddrs[i].s_addr; 1337 for (j = 0; j < ndaddrs; j++) { 1338 fw->ip.dst.s_addr = daddrs[j].s_addr; 1339 if (verbose) 1340 print_firewall_line(fw, *handle); 1341 ret &= iptc_insert_entry(chain, fw, rulenum, handle); 1342 } 1343 } 1344 1345 return ret; 1346} 1347 1348static unsigned char * 1349make_delete_mask(struct ipt_entry *fw) 1350{ 1351 /* Establish mask for comparison */ 1352 unsigned int size; 1353 struct iptables_match *m; 1354 unsigned char *mask, *mptr; 1355 1356 size = sizeof(struct ipt_entry); 1357 for (m = iptables_matches; m; m = m->next) { 1358 if (!m->used) 1359 continue; 1360 1361 size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; 1362 } 1363 1364 mask = fw_calloc(1, size 1365 + IPT_ALIGN(sizeof(struct ipt_entry_target)) 1366 + iptables_targets->size); 1367 1368 memset(mask, 0xFF, sizeof(struct ipt_entry)); 1369 mptr = mask + sizeof(struct ipt_entry); 1370 1371 for (m = iptables_matches; m; m = m->next) { 1372 if (!m->used) 1373 continue; 1374 1375 memset(mptr, 0xFF, 1376 IPT_ALIGN(sizeof(struct ipt_entry_match)) 1377 + m->userspacesize); 1378 mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; 1379 } 1380 1381 memset(mptr, 0xFF, 1382 IPT_ALIGN(sizeof(struct ipt_entry_target)) 1383 + iptables_targets->userspacesize); 1384 1385 return mask; 1386} 1387 1388static int 1389delete_entry(const ipt_chainlabel chain, 1390 struct ipt_entry *fw, 1391 unsigned int nsaddrs, 1392 const struct in_addr saddrs[], 1393 unsigned int ndaddrs, 1394 const struct in_addr daddrs[], 1395 int verbose, 1396 iptc_handle_t *handle) 1397{ 1398 unsigned int i, j; 1399 int ret = 1; 1400 unsigned char *mask; 1401 1402 mask = make_delete_mask(fw); 1403 for (i = 0; i < nsaddrs; i++) { 1404 fw->ip.src.s_addr = saddrs[i].s_addr; 1405 for (j = 0; j < ndaddrs; j++) { 1406 fw->ip.dst.s_addr = daddrs[j].s_addr; 1407 if (verbose) 1408 print_firewall_line(fw, *handle); 1409 ret &= iptc_delete_entry(chain, fw, mask, handle); 1410 } 1411 } 1412 return ret; 1413} 1414 1415int 1416for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *), 1417 int verbose, int builtinstoo, iptc_handle_t *handle) 1418{ 1419 int ret = 1; 1420 const char *chain; 1421 char *chains; 1422 unsigned int i, chaincount = 0; 1423 1424 chain = iptc_first_chain(handle); 1425 while (chain) { 1426 chaincount++; 1427 chain = iptc_next_chain(handle); 1428 } 1429 1430 chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount); 1431 i = 0; 1432 chain = iptc_first_chain(handle); 1433 while (chain) { 1434 strcpy(chains + i*sizeof(ipt_chainlabel), chain); 1435 i++; 1436 chain = iptc_next_chain(handle); 1437 } 1438 1439 for (i = 0; i < chaincount; i++) { 1440 if (!builtinstoo 1441 && iptc_builtin(chains + i*sizeof(ipt_chainlabel), 1442 *handle)) 1443 continue; 1444 ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle); 1445 } 1446 1447 free(chains); 1448 return ret; 1449} 1450 1451int 1452flush_entries(const ipt_chainlabel chain, int verbose, 1453 iptc_handle_t *handle) 1454{ 1455 if (!chain) 1456 return for_each_chain(flush_entries, verbose, 1, handle); 1457 1458 if (verbose) 1459 fprintf(stdout, "Flushing chain `%s'\n", chain); 1460 return iptc_flush_entries(chain, handle); 1461} 1462 1463static int 1464zero_entries(const ipt_chainlabel chain, int verbose, 1465 iptc_handle_t *handle) 1466{ 1467 if (!chain) 1468 return for_each_chain(zero_entries, verbose, 1, handle); 1469 1470 if (verbose) 1471 fprintf(stdout, "Zeroing chain `%s'\n", chain); 1472 return iptc_zero_entries(chain, handle); 1473} 1474 1475int 1476delete_chain(const ipt_chainlabel chain, int verbose, 1477 iptc_handle_t *handle) 1478{ 1479 if (!chain) 1480 return for_each_chain(delete_chain, verbose, 0, handle); 1481 1482 if (verbose) 1483 fprintf(stdout, "Deleting chain `%s'\n", chain); 1484 return iptc_delete_chain(chain, handle); 1485} 1486 1487static int 1488list_entries(const ipt_chainlabel chain, int verbose, int numeric, 1489 int expanded, int linenumbers, iptc_handle_t *handle) 1490{ 1491 int found = 0; 1492 unsigned int format; 1493 const char *this; 1494 1495 format = FMT_OPTIONS; 1496 if (!verbose) 1497 format |= FMT_NOCOUNTS; 1498 else 1499 format |= FMT_VIA; 1500 1501 if (numeric) 1502 format |= FMT_NUMERIC; 1503 1504 if (!expanded) 1505 format |= FMT_KILOMEGAGIGA; 1506 1507 if (linenumbers) 1508 format |= FMT_LINENUMBERS; 1509 1510 for (this = iptc_first_chain(handle); 1511 this; 1512 this = iptc_next_chain(handle)) { 1513 const struct ipt_entry *i; 1514 unsigned int num; 1515 1516 if (chain && strcmp(chain, this) != 0) 1517 continue; 1518 1519 if (found) printf("\n"); 1520 1521 print_header(format, this, handle); 1522 i = iptc_first_rule(this, handle); 1523 1524 num = 0; 1525 while (i) { 1526 print_firewall(i, 1527 iptc_get_target(i, handle), 1528 num++, 1529 format, 1530 *handle); 1531 i = iptc_next_rule(i, handle); 1532 } 1533 found = 1; 1534 } 1535 1536 errno = ENOENT; 1537 return found; 1538} 1539 1540static char *get_modprobe(void) 1541{ 1542 int procfile; 1543 char *ret; 1544 1545 procfile = open(PROC_SYS_MODPROBE, O_RDONLY); 1546 if (procfile < 0) 1547 return NULL; 1548 1549 ret = malloc(1024); 1550 if (ret) { 1551 switch (read(procfile, ret, 1024)) { 1552 case -1: goto fail; 1553 case 1024: goto fail; /* Partial read. Wierd */ 1554 } 1555 if (ret[strlen(ret)-1]=='\n') 1556 ret[strlen(ret)-1]=0; 1557 close(procfile); 1558 return ret; 1559 } 1560 fail: 1561 free(ret); 1562 close(procfile); 1563 return NULL; 1564} 1565 1566int iptables_insmod(const char *modname, const char *modprobe) 1567{ 1568 char *buf = NULL; 1569 char *argv[3]; 1570 1571 /* If they don't explicitly set it, read out of kernel */ 1572 if (!modprobe) { 1573 buf = get_modprobe(); 1574 if (!buf) 1575 return -1; 1576 modprobe = buf; 1577 } 1578 1579 switch (fork()) { 1580 case 0: 1581 argv[0] = (char *)modprobe; 1582 argv[1] = (char *)modname; 1583 argv[2] = NULL; 1584 execv(argv[0], argv); 1585 1586 /* not usually reached */ 1587 exit(0); 1588 case -1: 1589 return -1; 1590 1591 default: /* parent */ 1592 wait(NULL); 1593 } 1594 1595 free(buf); 1596 return 0; 1597} 1598 1599static struct ipt_entry * 1600generate_entry(const struct ipt_entry *fw, 1601 struct iptables_match *matches, 1602 struct ipt_entry_target *target) 1603{ 1604 unsigned int size; 1605 struct iptables_match *m; 1606 struct ipt_entry *e; 1607 1608 size = sizeof(struct ipt_entry); 1609 for (m = matches; m; m = m->next) { 1610 if (!m->used) 1611 continue; 1612 1613 size += m->m->u.match_size; 1614 } 1615 1616 e = fw_malloc(size + target->u.target_size); 1617 *e = *fw; 1618 e->target_offset = size; 1619 e->next_offset = size + target->u.target_size; 1620 1621 size = 0; 1622 for (m = matches; m; m = m->next) { 1623 if (!m->used) 1624 continue; 1625 1626 memcpy(e->elems + size, m->m, m->m->u.match_size); 1627 size += m->m->u.match_size; 1628 } 1629 memcpy(e->elems + size, target, target->u.target_size); 1630 1631 return e; 1632} 1633 1634int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) 1635{ 1636 struct ipt_entry fw, *e = NULL; 1637 int invert = 0; 1638 unsigned int nsaddrs = 0, ndaddrs = 0; 1639 struct in_addr *saddrs = NULL, *daddrs = NULL; 1640 1641 int c, verbose = 0; 1642 const char *chain = NULL; 1643 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; 1644 const char *policy = NULL, *newname = NULL; 1645 unsigned int rulenum = 0, options = 0, command = 0; 1646 const char *pcnt = NULL, *bcnt = NULL; 1647 int ret = 1; 1648 struct iptables_match *m; 1649 struct iptables_target *target = NULL; 1650 struct iptables_target *t; 1651 const char *jumpto = ""; 1652 char *protocol = NULL; 1653 const char *modprobe = NULL; 1654 int proto_used = 0; 1655 1656 memset(&fw, 0, sizeof(fw)); 1657 1658 opts = original_opts; 1659 global_option_offset = 0; 1660 1661 /* re-set optind to 0 in case do_command gets called 1662 * a second time */ 1663 optind = 0; 1664 1665 /* clear mflags in case do_command gets called a second time 1666 * (we clear the global list of all matches for security)*/ 1667 for (m = iptables_matches; m; m = m->next) { 1668 m->mflags = 0; 1669 m->used = 0; 1670 } 1671 1672 for (t = iptables_targets; t; t = t->next) { 1673 t->tflags = 0; 1674 t->used = 0; 1675 } 1676 1677 /* Suppress error messages: we may add new options if we 1678 demand-load a protocol. */ 1679 opterr = 0; 1680 1681 while ((c = getopt_long(argc, argv, 1682 "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:", 1683 opts, NULL)) != -1) { 1684 switch (c) { 1685 /* 1686 * Command selection 1687 */ 1688 case 'A': 1689 add_command(&command, CMD_APPEND, CMD_NONE, 1690 invert); 1691 chain = optarg; 1692 break; 1693 1694 case 'D': 1695 add_command(&command, CMD_DELETE, CMD_NONE, 1696 invert); 1697 chain = optarg; 1698 if (optind < argc && argv[optind][0] != '-' 1699 && argv[optind][0] != '!') { 1700 rulenum = parse_rulenumber(argv[optind++]); 1701 command = CMD_DELETE_NUM; 1702 } 1703 break; 1704 1705 case 'R': 1706 add_command(&command, CMD_REPLACE, CMD_NONE, 1707 invert); 1708 chain = optarg; 1709 if (optind < argc && argv[optind][0] != '-' 1710 && argv[optind][0] != '!') 1711 rulenum = parse_rulenumber(argv[optind++]); 1712 else 1713 exit_error(PARAMETER_PROBLEM, 1714 "-%c requires a rule number", 1715 cmd2char(CMD_REPLACE)); 1716 break; 1717 1718 case 'I': 1719 add_command(&command, CMD_INSERT, CMD_NONE, 1720 invert); 1721 chain = optarg; 1722 if (optind < argc && argv[optind][0] != '-' 1723 && argv[optind][0] != '!') 1724 rulenum = parse_rulenumber(argv[optind++]); 1725 else rulenum = 1; 1726 break; 1727 1728 case 'L': 1729 add_command(&command, CMD_LIST, CMD_ZERO, 1730 invert); 1731 if (optarg) chain = optarg; 1732 else if (optind < argc && argv[optind][0] != '-' 1733 && argv[optind][0] != '!') 1734 chain = argv[optind++]; 1735 break; 1736 1737 case 'F': 1738 add_command(&command, CMD_FLUSH, CMD_NONE, 1739 invert); 1740 if (optarg) chain = optarg; 1741 else if (optind < argc && argv[optind][0] != '-' 1742 && argv[optind][0] != '!') 1743 chain = argv[optind++]; 1744 break; 1745 1746 case 'Z': 1747 add_command(&command, CMD_ZERO, CMD_LIST, 1748 invert); 1749 if (optarg) chain = optarg; 1750 else if (optind < argc && argv[optind][0] != '-' 1751 && argv[optind][0] != '!') 1752 chain = argv[optind++]; 1753 break; 1754 1755 case 'N': 1756 if (optarg && *optarg == '-') 1757 exit_error(PARAMETER_PROBLEM, 1758 "chain name not allowed to start " 1759 "with `-'\n"); 1760 if (find_target(optarg, TRY_LOAD)) 1761 exit_error(PARAMETER_PROBLEM, 1762 "chain name may not clash " 1763 "with target name\n"); 1764 add_command(&command, CMD_NEW_CHAIN, CMD_NONE, 1765 invert); 1766 chain = optarg; 1767 break; 1768 1769 case 'X': 1770 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, 1771 invert); 1772 if (optarg) chain = optarg; 1773 else if (optind < argc && argv[optind][0] != '-' 1774 && argv[optind][0] != '!') 1775 chain = argv[optind++]; 1776 break; 1777 1778 case 'E': 1779 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, 1780 invert); 1781 chain = optarg; 1782 if (optind < argc && argv[optind][0] != '-' 1783 && argv[optind][0] != '!') 1784 newname = argv[optind++]; 1785 else 1786 exit_error(PARAMETER_PROBLEM, 1787 "-%c requires old-chain-name and " 1788 "new-chain-name", 1789 cmd2char(CMD_RENAME_CHAIN)); 1790 break; 1791 1792 case 'P': 1793 add_command(&command, CMD_SET_POLICY, CMD_NONE, 1794 invert); 1795 chain = optarg; 1796 if (optind < argc && argv[optind][0] != '-' 1797 && argv[optind][0] != '!') 1798 policy = argv[optind++]; 1799 else 1800 exit_error(PARAMETER_PROBLEM, 1801 "-%c requires a chain and a policy", 1802 cmd2char(CMD_SET_POLICY)); 1803 break; 1804 1805 case 'h': 1806 if (!optarg) 1807 optarg = argv[optind]; 1808 1809 /* iptables -p icmp -h */ 1810 if (!iptables_matches && protocol) 1811 find_match(protocol, TRY_LOAD); 1812 1813 exit_printhelp(); 1814 1815 /* 1816 * Option selection 1817 */ 1818 case 'p': 1819 check_inverse(optarg, &invert, &optind, argc); 1820 set_option(&options, OPT_PROTOCOL, &fw.ip.invflags, 1821 invert); 1822 1823 /* Canonicalize into lower case */ 1824 for (protocol = argv[optind-1]; *protocol; protocol++) 1825 *protocol = tolower(*protocol); 1826 1827 protocol = argv[optind-1]; 1828 fw.ip.proto = parse_protocol(protocol); 1829 1830 if (fw.ip.proto == 0 1831 && (fw.ip.invflags & IPT_INV_PROTO)) 1832 exit_error(PARAMETER_PROBLEM, 1833 "rule would never match protocol"); 1834 fw.nfcache |= NFC_IP_PROTO; 1835 break; 1836 1837 case 's': 1838 check_inverse(optarg, &invert, &optind, argc); 1839 set_option(&options, OPT_SOURCE, &fw.ip.invflags, 1840 invert); 1841 shostnetworkmask = argv[optind-1]; 1842 fw.nfcache |= NFC_IP_SRC; 1843 break; 1844 1845 case 'd': 1846 check_inverse(optarg, &invert, &optind, argc); 1847 set_option(&options, OPT_DESTINATION, &fw.ip.invflags, 1848 invert); 1849 dhostnetworkmask = argv[optind-1]; 1850 fw.nfcache |= NFC_IP_DST; 1851 break; 1852 1853 case 'j': 1854 set_option(&options, OPT_JUMP, &fw.ip.invflags, 1855 invert); 1856 jumpto = parse_target(optarg); 1857 /* TRY_LOAD (may be chain name) */ 1858 target = find_target(jumpto, TRY_LOAD); 1859 1860 if (target) { 1861 size_t size; 1862 1863 size = IPT_ALIGN(sizeof(struct ipt_entry_target)) 1864 + target->size; 1865 1866 target->t = fw_calloc(1, size); 1867 target->t->u.target_size = size; 1868 strcpy(target->t->u.user.name, jumpto); 1869 target->init(target->t, &fw.nfcache); 1870 opts = merge_options(opts, target->extra_opts, &target->option_offset); 1871 } 1872 break; 1873 1874 1875 case 'i': 1876 check_inverse(optarg, &invert, &optind, argc); 1877 set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags, 1878 invert); 1879 parse_interface(argv[optind-1], 1880 fw.ip.iniface, 1881 fw.ip.iniface_mask); 1882 fw.nfcache |= NFC_IP_IF_IN; 1883 break; 1884 1885 case 'o': 1886 check_inverse(optarg, &invert, &optind, argc); 1887 set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags, 1888 invert); 1889 parse_interface(argv[optind-1], 1890 fw.ip.outiface, 1891 fw.ip.outiface_mask); 1892 fw.nfcache |= NFC_IP_IF_OUT; 1893 break; 1894 1895 case 'f': 1896 set_option(&options, OPT_FRAGMENT, &fw.ip.invflags, 1897 invert); 1898 fw.ip.flags |= IPT_F_FRAG; 1899 fw.nfcache |= NFC_IP_FRAG; 1900 break; 1901 1902 case 'v': 1903 if (!verbose) 1904 set_option(&options, OPT_VERBOSE, 1905 &fw.ip.invflags, invert); 1906 verbose++; 1907 break; 1908 1909 case 'm': { 1910 size_t size; 1911 1912 if (invert) 1913 exit_error(PARAMETER_PROBLEM, 1914 "unexpected ! flag before --match"); 1915 1916 m = find_match(optarg, LOAD_MUST_SUCCEED); 1917 size = IPT_ALIGN(sizeof(struct ipt_entry_match)) 1918 + m->size; 1919 m->m = fw_calloc(1, size); 1920 m->m->u.match_size = size; 1921 strcpy(m->m->u.user.name, m->name); 1922 m->init(m->m, &fw.nfcache); 1923 opts = merge_options(opts, m->extra_opts, &m->option_offset); 1924 } 1925 break; 1926 1927 case 'n': 1928 set_option(&options, OPT_NUMERIC, &fw.ip.invflags, 1929 invert); 1930 break; 1931 1932 case 't': 1933 if (invert) 1934 exit_error(PARAMETER_PROBLEM, 1935 "unexpected ! flag before --table"); 1936 *table = argv[optind-1]; 1937 break; 1938 1939 case 'x': 1940 set_option(&options, OPT_EXPANDED, &fw.ip.invflags, 1941 invert); 1942 break; 1943 1944 case 'V': 1945 if (invert) 1946 printf("Not %s ;-)\n", program_version); 1947 else 1948 printf("%s v%s\n", 1949 program_name, program_version); 1950 exit(0); 1951 1952 case '0': 1953 set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags, 1954 invert); 1955 break; 1956 1957 case 'M': 1958 modprobe = optarg; 1959 break; 1960 1961 case 'c': 1962 1963 set_option(&options, OPT_COUNTERS, &fw.ip.invflags, 1964 invert); 1965 pcnt = optarg; 1966 if (optind < argc && argv[optind][0] != '-' 1967 && argv[optind][0] != '!') 1968 bcnt = argv[optind++]; 1969 else 1970 exit_error(PARAMETER_PROBLEM, 1971 "-%c requires packet and byte counter", 1972 opt2char(OPT_COUNTERS)); 1973 1974 if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1) 1975 exit_error(PARAMETER_PROBLEM, 1976 "-%c packet counter not numeric", 1977 opt2char(OPT_COUNTERS)); 1978 1979 if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1) 1980 exit_error(PARAMETER_PROBLEM, 1981 "-%c byte counter not numeric", 1982 opt2char(OPT_COUNTERS)); 1983 1984 break; 1985 1986 1987 case 1: /* non option */ 1988 if (optarg[0] == '!' && optarg[1] == '\0') { 1989 if (invert) 1990 exit_error(PARAMETER_PROBLEM, 1991 "multiple consecutive ! not" 1992 " allowed"); 1993 invert = TRUE; 1994 optarg[0] = '\0'; 1995 continue; 1996 } 1997 printf("Bad argument `%s'\n", optarg); 1998 exit_tryhelp(2); 1999 2000 default: 2001 if (!target 2002 || !(target->parse(c - target->option_offset, 2003 argv, invert, 2004 &target->tflags, 2005 &fw, &target->t))) { 2006 for (m = iptables_matches; m; m = m->next) { 2007 if (!m->used) 2008 continue; 2009 2010 if (m->parse(c - m->option_offset, 2011 argv, invert, 2012 &m->mflags, 2013 &fw, 2014 &fw.nfcache, 2015 &m->m)) 2016 break; 2017 } 2018 2019 /* If you listen carefully, you can 2020 actually hear this code suck. */ 2021 2022 /* some explanations (after four different bugs 2023 * in 3 different releases): If we encountere a 2024 * parameter, that has not been parsed yet, 2025 * it's not an option of an explicitly loaded 2026 * match or a target. However, we support 2027 * implicit loading of the protocol match 2028 * extension. '-p tcp' means 'l4 proto 6' and 2029 * at the same time 'load tcp protocol match on 2030 * demand if we specify --dport'. 2031 * 2032 * To make this work, we need to make sure: 2033 * - the parameter has not been parsed by 2034 * a match (m above) 2035 * - a protocol has been specified 2036 * - the protocol extension has not been 2037 * loaded yet, or is loaded and unused 2038 * [think of iptables-restore!] 2039 * - the protocol extension can be successively 2040 * loaded 2041 */ 2042 if (m == NULL 2043 && protocol 2044 && (!find_proto(protocol, DONT_LOAD, 2045 options&OPT_NUMERIC) 2046 || (find_proto(protocol, DONT_LOAD, 2047 options&OPT_NUMERIC) 2048 && (proto_used == 0)) 2049 ) 2050 && (m = find_proto(protocol, TRY_LOAD, 2051 options&OPT_NUMERIC))) { 2052 /* Try loading protocol */ 2053 size_t size; 2054 2055 proto_used = 1; 2056 2057 size = IPT_ALIGN(sizeof(struct ipt_entry_match)) 2058 + m->size; 2059 2060 m->m = fw_calloc(1, size); 2061 m->m->u.match_size = size; 2062 strcpy(m->m->u.user.name, m->name); 2063 m->init(m->m, &fw.nfcache); 2064 2065 opts = merge_options(opts, 2066 m->extra_opts, &m->option_offset); 2067 2068 optind--; 2069 continue; 2070 } 2071 if (!m) 2072 exit_error(PARAMETER_PROBLEM, 2073 "Unknown arg `%s'", 2074 argv[optind-1]); 2075 } 2076 } 2077 invert = FALSE; 2078 } 2079 2080 for (m = iptables_matches; m; m = m->next) { 2081 if (!m->used) 2082 continue; 2083 2084 m->final_check(m->mflags); 2085 } 2086 2087 if (target) 2088 target->final_check(target->tflags); 2089 2090 /* Fix me: must put inverse options checking here --MN */ 2091 2092 if (optind < argc) 2093 exit_error(PARAMETER_PROBLEM, 2094 "unknown arguments found on commandline"); 2095 if (!command) 2096 exit_error(PARAMETER_PROBLEM, "no command specified"); 2097 if (invert) 2098 exit_error(PARAMETER_PROBLEM, 2099 "nothing appropriate following !"); 2100 2101 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { 2102 if (!(options & OPT_DESTINATION)) 2103 dhostnetworkmask = "0.0.0.0/0"; 2104 if (!(options & OPT_SOURCE)) 2105 shostnetworkmask = "0.0.0.0/0"; 2106 } 2107 2108 if (shostnetworkmask) 2109 parse_hostnetworkmask(shostnetworkmask, &saddrs, 2110 &(fw.ip.smsk), &nsaddrs); 2111 2112 if (dhostnetworkmask) 2113 parse_hostnetworkmask(dhostnetworkmask, &daddrs, 2114 &(fw.ip.dmsk), &ndaddrs); 2115 2116 if ((nsaddrs > 1 || ndaddrs > 1) && 2117 (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) 2118 exit_error(PARAMETER_PROBLEM, "! not allowed with multiple" 2119 " source or destination IP addresses"); 2120 2121 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) 2122 exit_error(PARAMETER_PROBLEM, "Replacement rule does not " 2123 "specify a unique address"); 2124 2125 generic_opt_check(command, options); 2126 2127 if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN) 2128 exit_error(PARAMETER_PROBLEM, 2129 "chain name `%s' too long (must be under %i chars)", 2130 chain, IPT_FUNCTION_MAXNAMELEN); 2131 2132 /* only allocate handle if we weren't called with a handle */ 2133 if (!*handle) 2134 *handle = iptc_init(*table); 2135 2136 if (!*handle) { 2137 /* try to insmod the module if iptc_init failed */ 2138 iptables_insmod("ip_tables", modprobe); 2139 *handle = iptc_init(*table); 2140 } 2141 2142 if (!*handle) 2143 exit_error(VERSION_PROBLEM, 2144 "can't initialize iptables table `%s': %s", 2145 *table, iptc_strerror(errno)); 2146 2147 if (command == CMD_APPEND 2148 || command == CMD_DELETE 2149 || command == CMD_INSERT 2150 || command == CMD_REPLACE) { 2151 if (strcmp(chain, "PREROUTING") == 0 2152 || strcmp(chain, "INPUT") == 0) { 2153 /* -o not valid with incoming packets. */ 2154 if (options & OPT_VIANAMEOUT) 2155 exit_error(PARAMETER_PROBLEM, 2156 "Can't use -%c with %s\n", 2157 opt2char(OPT_VIANAMEOUT), 2158 chain); 2159 } 2160 2161 if (strcmp(chain, "POSTROUTING") == 0 2162 || strcmp(chain, "OUTPUT") == 0) { 2163 /* -i not valid with outgoing packets */ 2164 if (options & OPT_VIANAMEIN) 2165 exit_error(PARAMETER_PROBLEM, 2166 "Can't use -%c with %s\n", 2167 opt2char(OPT_VIANAMEIN), 2168 chain); 2169 } 2170 2171 if (target && iptc_is_chain(jumpto, *handle)) { 2172 printf("Warning: using chain %s, not extension\n", 2173 jumpto); 2174 2175 target = NULL; 2176 } 2177 2178 /* If they didn't specify a target, or it's a chain 2179 name, use standard. */ 2180 if (!target 2181 && (strlen(jumpto) == 0 2182 || iptc_is_chain(jumpto, *handle))) { 2183 size_t size; 2184 2185 target = find_target(IPT_STANDARD_TARGET, 2186 LOAD_MUST_SUCCEED); 2187 2188 size = sizeof(struct ipt_entry_target) 2189 + target->size; 2190 target->t = fw_calloc(1, size); 2191 target->t->u.target_size = size; 2192 strcpy(target->t->u.user.name, jumpto); 2193 target->init(target->t, &fw.nfcache); 2194 } 2195 2196 if (!target) { 2197 /* it is no chain, and we can't load a plugin. 2198 * We cannot know if the plugin is corrupt, non 2199 * existant OR if the user just misspelled a 2200 * chain. */ 2201 find_target(jumpto, LOAD_MUST_SUCCEED); 2202 } else { 2203 e = generate_entry(&fw, iptables_matches, target->t); 2204 } 2205 } 2206 2207 switch (command) { 2208 case CMD_APPEND: 2209 ret = append_entry(chain, e, 2210 nsaddrs, saddrs, ndaddrs, daddrs, 2211 options&OPT_VERBOSE, 2212 handle); 2213 break; 2214 case CMD_DELETE: 2215 ret = delete_entry(chain, e, 2216 nsaddrs, saddrs, ndaddrs, daddrs, 2217 options&OPT_VERBOSE, 2218 handle); 2219 break; 2220 case CMD_DELETE_NUM: 2221 ret = iptc_delete_num_entry(chain, rulenum - 1, handle); 2222 break; 2223 case CMD_REPLACE: 2224 ret = replace_entry(chain, e, rulenum - 1, 2225 saddrs, daddrs, options&OPT_VERBOSE, 2226 handle); 2227 break; 2228 case CMD_INSERT: 2229 ret = insert_entry(chain, e, rulenum - 1, 2230 nsaddrs, saddrs, ndaddrs, daddrs, 2231 options&OPT_VERBOSE, 2232 handle); 2233 break; 2234 case CMD_LIST: 2235 ret = list_entries(chain, 2236 options&OPT_VERBOSE, 2237 options&OPT_NUMERIC, 2238 options&OPT_EXPANDED, 2239 options&OPT_LINENUMBERS, 2240 handle); 2241 break; 2242 case CMD_FLUSH: 2243 ret = flush_entries(chain, options&OPT_VERBOSE, handle); 2244 break; 2245 case CMD_ZERO: 2246 ret = zero_entries(chain, options&OPT_VERBOSE, handle); 2247 break; 2248 case CMD_LIST|CMD_ZERO: 2249 ret = list_entries(chain, 2250 options&OPT_VERBOSE, 2251 options&OPT_NUMERIC, 2252 options&OPT_EXPANDED, 2253 options&OPT_LINENUMBERS, 2254 handle); 2255 if (ret) 2256 ret = zero_entries(chain, 2257 options&OPT_VERBOSE, handle); 2258 break; 2259 case CMD_NEW_CHAIN: 2260 ret = iptc_create_chain(chain, handle); 2261 break; 2262 case CMD_DELETE_CHAIN: 2263 ret = delete_chain(chain, options&OPT_VERBOSE, handle); 2264 break; 2265 case CMD_RENAME_CHAIN: 2266 ret = iptc_rename_chain(chain, newname, handle); 2267 break; 2268 case CMD_SET_POLICY: 2269 ret = iptc_set_policy(chain, policy, NULL, handle); 2270 break; 2271 default: 2272 /* We should never reach this... */ 2273 exit_tryhelp(2); 2274 } 2275 2276 if (verbose > 1) 2277 dump_entries(*handle); 2278 2279 return ret; 2280} 2281