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