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