13c0c8717SLuigi Rizzo /* 23c0c8717SLuigi Rizzo * Copyright (c) 2002-2003 Luigi Rizzo 33c0c8717SLuigi Rizzo * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 43c0c8717SLuigi Rizzo * Copyright (c) 1994 Ugen J.S.Antsilevich 53c0c8717SLuigi Rizzo * 63c0c8717SLuigi Rizzo * Idea and grammar partially left from: 73c0c8717SLuigi Rizzo * Copyright (c) 1993 Daniel Boulet 83c0c8717SLuigi Rizzo * 93c0c8717SLuigi Rizzo * Redistribution and use in source forms, with and without modification, 103c0c8717SLuigi Rizzo * are permitted provided that this entire comment appears intact. 113c0c8717SLuigi Rizzo * 123c0c8717SLuigi Rizzo * Redistribution in binary form may occur without any restrictions. 133c0c8717SLuigi Rizzo * Obviously, it would be nice if you gave credit where credit is due 143c0c8717SLuigi Rizzo * but requiring it would be too onerous. 153c0c8717SLuigi Rizzo * 163c0c8717SLuigi Rizzo * This software is provided ``AS IS'' without any warranties of any kind. 173c0c8717SLuigi Rizzo * 183c0c8717SLuigi Rizzo * Command line interface for IP firewall facility 193c0c8717SLuigi Rizzo * 203c0c8717SLuigi Rizzo * $FreeBSD$ 213c0c8717SLuigi Rizzo */ 223c0c8717SLuigi Rizzo 233c0c8717SLuigi Rizzo #include <sys/wait.h> 243c0c8717SLuigi Rizzo #include <ctype.h> 253c0c8717SLuigi Rizzo #include <err.h> 263c0c8717SLuigi Rizzo #include <errno.h> 273c0c8717SLuigi Rizzo #include <signal.h> 283c0c8717SLuigi Rizzo #include <stdio.h> 293c0c8717SLuigi Rizzo #include <stdlib.h> 303c0c8717SLuigi Rizzo #include <string.h> 313c0c8717SLuigi Rizzo #include <sysexits.h> 323c0c8717SLuigi Rizzo #include <unistd.h> 333c0c8717SLuigi Rizzo 343c0c8717SLuigi Rizzo #include "ipfw2.h" 353c0c8717SLuigi Rizzo 363c0c8717SLuigi Rizzo static void 373c0c8717SLuigi Rizzo help(void) 383c0c8717SLuigi Rizzo { 393c0c8717SLuigi Rizzo fprintf(stderr, 403c0c8717SLuigi Rizzo "ipfw syntax summary (but please do read the ipfw(8) manpage):\n\n" 413c0c8717SLuigi Rizzo "\tipfw [-abcdefhnNqStTv] <command>\n\n" 423c0c8717SLuigi Rizzo "where <command> is one of the following:\n\n" 433c0c8717SLuigi Rizzo "add [num] [set N] [prob x] RULE-BODY\n" 443c0c8717SLuigi Rizzo "{pipe|queue} N config PIPE-BODY\n" 453c0c8717SLuigi Rizzo "[pipe|queue] {zero|delete|show} [N{,N}]\n" 463c0c8717SLuigi Rizzo "nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|reset|\n" 473c0c8717SLuigi Rizzo " reverse|proxy_only|redirect_addr linkspec|\n" 483c0c8717SLuigi Rizzo " redirect_port linkspec|redirect_proto linkspec}\n" 493c0c8717SLuigi Rizzo "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 503c0c8717SLuigi Rizzo "set N {show|list|zero|resetlog|delete} [N{,N}] | flush\n" 513c0c8717SLuigi Rizzo "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" 523c0c8717SLuigi Rizzo "table all {flush | list}\n" 533c0c8717SLuigi Rizzo "\n" 543c0c8717SLuigi Rizzo "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" 553c0c8717SLuigi Rizzo "ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n" 563c0c8717SLuigi Rizzo " skipto N | {divert|tee} PORT | forward ADDR |\n" 573c0c8717SLuigi Rizzo " pipe N | queue N | nat N | setfib FIB\n" 583c0c8717SLuigi Rizzo "PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n" 593c0c8717SLuigi Rizzo "ADDR: [ MAC dst src ether_type ] \n" 603c0c8717SLuigi Rizzo " [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 613c0c8717SLuigi Rizzo " [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n" 623c0c8717SLuigi Rizzo "IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n" 633c0c8717SLuigi Rizzo "IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n" 643c0c8717SLuigi Rizzo "IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n" 653c0c8717SLuigi Rizzo "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 663c0c8717SLuigi Rizzo "OPTION_LIST: OPTION [OPTION_LIST]\n" 673c0c8717SLuigi Rizzo "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" 683c0c8717SLuigi Rizzo " {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" 693c0c8717SLuigi Rizzo " {dst-port|src-port} LIST |\n" 703c0c8717SLuigi Rizzo " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 713c0c8717SLuigi Rizzo " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 723c0c8717SLuigi Rizzo " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 733c0c8717SLuigi Rizzo " icmp6types LIST | ext6hdr LIST | flow-id N[,N] | fib FIB |\n" 743c0c8717SLuigi Rizzo " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 753c0c8717SLuigi Rizzo " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 763c0c8717SLuigi Rizzo " tcpdatalen LIST | verrevpath | versrcreach | antispoof\n" 773c0c8717SLuigi Rizzo ); 783c0c8717SLuigi Rizzo 793c0c8717SLuigi Rizzo exit(0); 803c0c8717SLuigi Rizzo } 813c0c8717SLuigi Rizzo 823c0c8717SLuigi Rizzo /* 833c0c8717SLuigi Rizzo * Free a the (locally allocated) copy of command line arguments. 843c0c8717SLuigi Rizzo */ 853c0c8717SLuigi Rizzo static void 863c0c8717SLuigi Rizzo free_args(int ac, char **av) 873c0c8717SLuigi Rizzo { 883c0c8717SLuigi Rizzo int i; 893c0c8717SLuigi Rizzo 903c0c8717SLuigi Rizzo for (i=0; i < ac; i++) 913c0c8717SLuigi Rizzo free(av[i]); 923c0c8717SLuigi Rizzo free(av); 933c0c8717SLuigi Rizzo } 943c0c8717SLuigi Rizzo 953c0c8717SLuigi Rizzo /* 963c0c8717SLuigi Rizzo * Called with the arguments, including program name because getopt 973c0c8717SLuigi Rizzo * wants it to be present. 983c0c8717SLuigi Rizzo * Returns 0 if successful, 1 if empty command, errx() in case of errors. 993c0c8717SLuigi Rizzo */ 1003c0c8717SLuigi Rizzo static int 1013c0c8717SLuigi Rizzo ipfw_main(int oldac, char **oldav) 1023c0c8717SLuigi Rizzo { 1033c0c8717SLuigi Rizzo int ch, ac, save_ac; 1043c0c8717SLuigi Rizzo const char *errstr; 1053c0c8717SLuigi Rizzo char **av, **save_av; 1063c0c8717SLuigi Rizzo int do_acct = 0; /* Show packet/byte count */ 1073c0c8717SLuigi Rizzo 1083c0c8717SLuigi Rizzo #define WHITESP " \t\f\v\n\r" 1093c0c8717SLuigi Rizzo if (oldac < 2) 1103c0c8717SLuigi Rizzo return 1; /* need at least one argument */ 1113c0c8717SLuigi Rizzo 1123c0c8717SLuigi Rizzo if (oldac == 2) { 1133c0c8717SLuigi Rizzo /* 1143c0c8717SLuigi Rizzo * If we are called with a single string, try to split it into 1153c0c8717SLuigi Rizzo * arguments for subsequent parsing. 1163c0c8717SLuigi Rizzo * But first, remove spaces after a ',', by copying the string 1173c0c8717SLuigi Rizzo * in-place. 1183c0c8717SLuigi Rizzo */ 1193c0c8717SLuigi Rizzo char *arg = oldav[1]; /* The string is the first arg. */ 1203c0c8717SLuigi Rizzo int l = strlen(arg); 1213c0c8717SLuigi Rizzo int copy = 0; /* 1 if we need to copy, 0 otherwise */ 1223c0c8717SLuigi Rizzo int i, j; 1233c0c8717SLuigi Rizzo 1243c0c8717SLuigi Rizzo for (i = j = 0; i < l; i++) { 1253c0c8717SLuigi Rizzo if (arg[i] == '#') /* comment marker */ 1263c0c8717SLuigi Rizzo break; 1273c0c8717SLuigi Rizzo if (copy) { 1283c0c8717SLuigi Rizzo arg[j++] = arg[i]; 1293c0c8717SLuigi Rizzo copy = !index("," WHITESP, arg[i]); 1303c0c8717SLuigi Rizzo } else { 1313c0c8717SLuigi Rizzo copy = !index(WHITESP, arg[i]); 1323c0c8717SLuigi Rizzo if (copy) 1333c0c8717SLuigi Rizzo arg[j++] = arg[i]; 1343c0c8717SLuigi Rizzo } 1353c0c8717SLuigi Rizzo } 1363c0c8717SLuigi Rizzo if (!copy && j > 0) /* last char was a 'blank', remove it */ 1373c0c8717SLuigi Rizzo j--; 1383c0c8717SLuigi Rizzo l = j; /* the new argument length */ 1393c0c8717SLuigi Rizzo arg[j++] = '\0'; 1403c0c8717SLuigi Rizzo if (l == 0) /* empty string! */ 1413c0c8717SLuigi Rizzo return 1; 1423c0c8717SLuigi Rizzo 1433c0c8717SLuigi Rizzo /* 1443c0c8717SLuigi Rizzo * First, count number of arguments. Because of the previous 1453c0c8717SLuigi Rizzo * processing, this is just the number of blanks plus 1. 1463c0c8717SLuigi Rizzo */ 1473c0c8717SLuigi Rizzo for (i = 0, ac = 1; i < l; i++) 1483c0c8717SLuigi Rizzo if (index(WHITESP, arg[i]) != NULL) 1493c0c8717SLuigi Rizzo ac++; 1503c0c8717SLuigi Rizzo 1513c0c8717SLuigi Rizzo /* 1523c0c8717SLuigi Rizzo * Allocate the argument list, including one entry for 1533c0c8717SLuigi Rizzo * the program name because getopt expects it. 1543c0c8717SLuigi Rizzo */ 1553c0c8717SLuigi Rizzo av = safe_calloc(ac + 1, sizeof(char *)); 1563c0c8717SLuigi Rizzo 1573c0c8717SLuigi Rizzo /* 1583c0c8717SLuigi Rizzo * Second, copy arguments from arg[] to av[]. For each one, 1593c0c8717SLuigi Rizzo * j is the initial character, i is the one past the end. 1603c0c8717SLuigi Rizzo */ 1613c0c8717SLuigi Rizzo for (ac = 1, i = j = 0; i < l; i++) 1623c0c8717SLuigi Rizzo if (index(WHITESP, arg[i]) != NULL || i == l-1) { 1633c0c8717SLuigi Rizzo if (i == l-1) 1643c0c8717SLuigi Rizzo i++; 1653c0c8717SLuigi Rizzo av[ac] = safe_calloc(i-j+1, 1); 1663c0c8717SLuigi Rizzo bcopy(arg+j, av[ac], i-j); 1673c0c8717SLuigi Rizzo ac++; 1683c0c8717SLuigi Rizzo j = i + 1; 1693c0c8717SLuigi Rizzo } 1703c0c8717SLuigi Rizzo } else { 1713c0c8717SLuigi Rizzo /* 1723c0c8717SLuigi Rizzo * If an argument ends with ',' join with the next one. 1733c0c8717SLuigi Rizzo */ 1743c0c8717SLuigi Rizzo int first, i, l; 1753c0c8717SLuigi Rizzo 1763c0c8717SLuigi Rizzo av = safe_calloc(oldac, sizeof(char *)); 1773c0c8717SLuigi Rizzo for (first = i = ac = 1, l = 0; i < oldac; i++) { 1783c0c8717SLuigi Rizzo char *arg = oldav[i]; 1793c0c8717SLuigi Rizzo int k = strlen(arg); 1803c0c8717SLuigi Rizzo 1813c0c8717SLuigi Rizzo l += k; 1823c0c8717SLuigi Rizzo if (arg[k-1] != ',' || i == oldac-1) { 1833c0c8717SLuigi Rizzo /* Time to copy. */ 1843c0c8717SLuigi Rizzo av[ac] = safe_calloc(l+1, 1); 1853c0c8717SLuigi Rizzo for (l=0; first <= i; first++) { 1863c0c8717SLuigi Rizzo strcat(av[ac]+l, oldav[first]); 1873c0c8717SLuigi Rizzo l += strlen(oldav[first]); 1883c0c8717SLuigi Rizzo } 1893c0c8717SLuigi Rizzo ac++; 1903c0c8717SLuigi Rizzo l = 0; 1913c0c8717SLuigi Rizzo first = i+1; 1923c0c8717SLuigi Rizzo } 1933c0c8717SLuigi Rizzo } 1943c0c8717SLuigi Rizzo } 1953c0c8717SLuigi Rizzo 1963c0c8717SLuigi Rizzo av[0] = strdup(oldav[0]); /* copy progname from the caller */ 1973c0c8717SLuigi Rizzo /* Set the force flag for non-interactive processes */ 1983c0c8717SLuigi Rizzo if (!co.do_force) 1993c0c8717SLuigi Rizzo co.do_force = !isatty(STDIN_FILENO); 2003c0c8717SLuigi Rizzo 2013c0c8717SLuigi Rizzo /* Save arguments for final freeing of memory. */ 2023c0c8717SLuigi Rizzo save_ac = ac; 2033c0c8717SLuigi Rizzo save_av = av; 2043c0c8717SLuigi Rizzo 2053c0c8717SLuigi Rizzo optind = optreset = 1; /* restart getopt() */ 2063c0c8717SLuigi Rizzo while ((ch = getopt(ac, av, "abcdefhinNqs:STtv")) != -1) 2073c0c8717SLuigi Rizzo switch (ch) { 2083c0c8717SLuigi Rizzo case 'a': 2093c0c8717SLuigi Rizzo do_acct = 1; 2103c0c8717SLuigi Rizzo break; 2113c0c8717SLuigi Rizzo 2123c0c8717SLuigi Rizzo case 'b': 2133c0c8717SLuigi Rizzo co.comment_only = 1; 2143c0c8717SLuigi Rizzo co.do_compact = 1; 2153c0c8717SLuigi Rizzo break; 2163c0c8717SLuigi Rizzo 2173c0c8717SLuigi Rizzo case 'c': 2183c0c8717SLuigi Rizzo co.do_compact = 1; 2193c0c8717SLuigi Rizzo break; 2203c0c8717SLuigi Rizzo 2213c0c8717SLuigi Rizzo case 'd': 2223c0c8717SLuigi Rizzo co.do_dynamic = 1; 2233c0c8717SLuigi Rizzo break; 2243c0c8717SLuigi Rizzo 2253c0c8717SLuigi Rizzo case 'e': 2263c0c8717SLuigi Rizzo co.do_expired = 1; 2273c0c8717SLuigi Rizzo break; 2283c0c8717SLuigi Rizzo 2293c0c8717SLuigi Rizzo case 'f': 2303c0c8717SLuigi Rizzo co.do_force = 1; 2313c0c8717SLuigi Rizzo break; 2323c0c8717SLuigi Rizzo 2333c0c8717SLuigi Rizzo case 'h': /* help */ 2343c0c8717SLuigi Rizzo free_args(save_ac, save_av); 2353c0c8717SLuigi Rizzo help(); 2363c0c8717SLuigi Rizzo break; /* NOTREACHED */ 2373c0c8717SLuigi Rizzo 2383c0c8717SLuigi Rizzo case 'i': 2393c0c8717SLuigi Rizzo co.do_value_as_ip = 1; 2403c0c8717SLuigi Rizzo break; 2413c0c8717SLuigi Rizzo 2423c0c8717SLuigi Rizzo case 'n': 2433c0c8717SLuigi Rizzo co.test_only = 1; 2443c0c8717SLuigi Rizzo break; 2453c0c8717SLuigi Rizzo 2463c0c8717SLuigi Rizzo case 'N': 2473c0c8717SLuigi Rizzo co.do_resolv = 1; 2483c0c8717SLuigi Rizzo break; 2493c0c8717SLuigi Rizzo 2503c0c8717SLuigi Rizzo case 'q': 2513c0c8717SLuigi Rizzo co.do_quiet = 1; 2523c0c8717SLuigi Rizzo break; 2533c0c8717SLuigi Rizzo 2543c0c8717SLuigi Rizzo case 's': /* sort */ 2553c0c8717SLuigi Rizzo co.do_sort = atoi(optarg); 2563c0c8717SLuigi Rizzo break; 2573c0c8717SLuigi Rizzo 2583c0c8717SLuigi Rizzo case 'S': 2593c0c8717SLuigi Rizzo co.show_sets = 1; 2603c0c8717SLuigi Rizzo break; 2613c0c8717SLuigi Rizzo 2623c0c8717SLuigi Rizzo case 't': 2633c0c8717SLuigi Rizzo co.do_time = 1; 2643c0c8717SLuigi Rizzo break; 2653c0c8717SLuigi Rizzo 2663c0c8717SLuigi Rizzo case 'T': 2673c0c8717SLuigi Rizzo co.do_time = 2; /* numeric timestamp */ 2683c0c8717SLuigi Rizzo break; 2693c0c8717SLuigi Rizzo 2703c0c8717SLuigi Rizzo case 'v': /* verbose */ 2713c0c8717SLuigi Rizzo co.verbose = 1; 2723c0c8717SLuigi Rizzo break; 2733c0c8717SLuigi Rizzo 2743c0c8717SLuigi Rizzo default: 2753c0c8717SLuigi Rizzo free_args(save_ac, save_av); 2763c0c8717SLuigi Rizzo return 1; 2773c0c8717SLuigi Rizzo } 2783c0c8717SLuigi Rizzo 2793c0c8717SLuigi Rizzo ac -= optind; 2803c0c8717SLuigi Rizzo av += optind; 2813c0c8717SLuigi Rizzo NEED1("bad arguments, for usage summary ``ipfw''"); 2823c0c8717SLuigi Rizzo 2833c0c8717SLuigi Rizzo /* 2843c0c8717SLuigi Rizzo * An undocumented behaviour of ipfw1 was to allow rule numbers first, 2853c0c8717SLuigi Rizzo * e.g. "100 add allow ..." instead of "add 100 allow ...". 2863c0c8717SLuigi Rizzo * In case, swap first and second argument to get the normal form. 2873c0c8717SLuigi Rizzo */ 2883c0c8717SLuigi Rizzo if (ac > 1 && isdigit(*av[0])) { 2893c0c8717SLuigi Rizzo char *p = av[0]; 2903c0c8717SLuigi Rizzo 2913c0c8717SLuigi Rizzo av[0] = av[1]; 2923c0c8717SLuigi Rizzo av[1] = p; 2933c0c8717SLuigi Rizzo } 2943c0c8717SLuigi Rizzo 2953c0c8717SLuigi Rizzo /* 2963c0c8717SLuigi Rizzo * Optional: pipe, queue or nat. 2973c0c8717SLuigi Rizzo */ 2983c0c8717SLuigi Rizzo co.do_nat = 0; 2993c0c8717SLuigi Rizzo co.do_pipe = 0; 3003c0c8717SLuigi Rizzo if (!strncmp(*av, "nat", strlen(*av))) 3013c0c8717SLuigi Rizzo co.do_nat = 1; 3023c0c8717SLuigi Rizzo else if (!strncmp(*av, "pipe", strlen(*av))) 3033c0c8717SLuigi Rizzo co.do_pipe = 1; 3043c0c8717SLuigi Rizzo else if (_substrcmp(*av, "queue") == 0) 3053c0c8717SLuigi Rizzo co.do_pipe = 2; 3063c0c8717SLuigi Rizzo else if (!strncmp(*av, "set", strlen(*av))) { 3073c0c8717SLuigi Rizzo if (ac > 1 && isdigit(av[1][0])) { 3083c0c8717SLuigi Rizzo co.use_set = strtonum(av[1], 0, resvd_set_number, 3093c0c8717SLuigi Rizzo &errstr); 3103c0c8717SLuigi Rizzo if (errstr) 3113c0c8717SLuigi Rizzo errx(EX_DATAERR, 3123c0c8717SLuigi Rizzo "invalid set number %s\n", av[1]); 3133c0c8717SLuigi Rizzo ac -= 2; av += 2; co.use_set++; 3143c0c8717SLuigi Rizzo } 3153c0c8717SLuigi Rizzo } 3163c0c8717SLuigi Rizzo 3173c0c8717SLuigi Rizzo if (co.do_pipe || co.do_nat) { 3183c0c8717SLuigi Rizzo ac--; 3193c0c8717SLuigi Rizzo av++; 3203c0c8717SLuigi Rizzo } 3213c0c8717SLuigi Rizzo NEED1("missing command"); 3223c0c8717SLuigi Rizzo 3233c0c8717SLuigi Rizzo /* 3243c0c8717SLuigi Rizzo * For pipes, queues and nats we normally say 'nat|pipe NN config' 3253c0c8717SLuigi Rizzo * but the code is easier to parse as 'nat|pipe config NN' 3263c0c8717SLuigi Rizzo * so we swap the two arguments. 3273c0c8717SLuigi Rizzo */ 3283c0c8717SLuigi Rizzo if ((co.do_pipe || co.do_nat) && ac > 1 && isdigit(*av[0])) { 3293c0c8717SLuigi Rizzo char *p = av[0]; 3303c0c8717SLuigi Rizzo 3313c0c8717SLuigi Rizzo av[0] = av[1]; 3323c0c8717SLuigi Rizzo av[1] = p; 3333c0c8717SLuigi Rizzo } 3343c0c8717SLuigi Rizzo 3353c0c8717SLuigi Rizzo int try_next = 0; 3363c0c8717SLuigi Rizzo if (co.use_set == 0) { 3373c0c8717SLuigi Rizzo if (_substrcmp(*av, "add") == 0) 3383c0c8717SLuigi Rizzo ipfw_add(ac, av); 3393c0c8717SLuigi Rizzo else if (co.do_nat && _substrcmp(*av, "show") == 0) 3403c0c8717SLuigi Rizzo ipfw_show_nat(ac, av); 3413c0c8717SLuigi Rizzo else if (co.do_pipe && _substrcmp(*av, "config") == 0) 3423c0c8717SLuigi Rizzo ipfw_config_pipe(ac, av); 3433c0c8717SLuigi Rizzo else if (co.do_nat && _substrcmp(*av, "config") == 0) 3443c0c8717SLuigi Rizzo ipfw_config_nat(ac, av); 3453c0c8717SLuigi Rizzo else if (_substrcmp(*av, "set") == 0) 3463c0c8717SLuigi Rizzo ipfw_sets_handler(ac, av); 3473c0c8717SLuigi Rizzo else if (_substrcmp(*av, "table") == 0) 3483c0c8717SLuigi Rizzo ipfw_table_handler(ac, av); 3493c0c8717SLuigi Rizzo else if (_substrcmp(*av, "enable") == 0) 3503c0c8717SLuigi Rizzo ipfw_sysctl_handler(ac, av, 1); 3513c0c8717SLuigi Rizzo else if (_substrcmp(*av, "disable") == 0) 3523c0c8717SLuigi Rizzo ipfw_sysctl_handler(ac, av, 0); 3533c0c8717SLuigi Rizzo else 3543c0c8717SLuigi Rizzo try_next = 1; 3553c0c8717SLuigi Rizzo } 3563c0c8717SLuigi Rizzo 3573c0c8717SLuigi Rizzo if (co.use_set || try_next) { 3583c0c8717SLuigi Rizzo if (_substrcmp(*av, "delete") == 0) 3593c0c8717SLuigi Rizzo ipfw_delete(ac, av); 3603c0c8717SLuigi Rizzo else if (_substrcmp(*av, "flush") == 0) 3613c0c8717SLuigi Rizzo ipfw_flush(co.do_force); 3623c0c8717SLuigi Rizzo else if (_substrcmp(*av, "zero") == 0) 3633c0c8717SLuigi Rizzo ipfw_zero(ac, av, 0 /* IP_FW_ZERO */); 3643c0c8717SLuigi Rizzo else if (_substrcmp(*av, "resetlog") == 0) 3653c0c8717SLuigi Rizzo ipfw_zero(ac, av, 1 /* IP_FW_RESETLOG */); 3663c0c8717SLuigi Rizzo else if (_substrcmp(*av, "print") == 0 || 3673c0c8717SLuigi Rizzo _substrcmp(*av, "list") == 0) 3683c0c8717SLuigi Rizzo ipfw_list(ac, av, do_acct); 3693c0c8717SLuigi Rizzo else if (_substrcmp(*av, "show") == 0) 3703c0c8717SLuigi Rizzo ipfw_list(ac, av, 1 /* show counters */); 3713c0c8717SLuigi Rizzo else 3723c0c8717SLuigi Rizzo errx(EX_USAGE, "bad command `%s'", *av); 3733c0c8717SLuigi Rizzo } 3743c0c8717SLuigi Rizzo 3753c0c8717SLuigi Rizzo /* Free memory allocated in the argument parsing. */ 3763c0c8717SLuigi Rizzo free_args(save_ac, save_av); 3773c0c8717SLuigi Rizzo return 0; 3783c0c8717SLuigi Rizzo } 3793c0c8717SLuigi Rizzo 3803c0c8717SLuigi Rizzo 3813c0c8717SLuigi Rizzo static void 3823c0c8717SLuigi Rizzo ipfw_readfile(int ac, char *av[]) 3833c0c8717SLuigi Rizzo { 3843c0c8717SLuigi Rizzo #define MAX_ARGS 32 3853c0c8717SLuigi Rizzo char buf[BUFSIZ]; 3863c0c8717SLuigi Rizzo char *progname = av[0]; /* original program name */ 3873c0c8717SLuigi Rizzo const char *cmd = NULL; /* preprocessor name, if any */ 3883c0c8717SLuigi Rizzo const char *filename = av[ac-1]; /* file to read */ 3893c0c8717SLuigi Rizzo int c, lineno=0; 3903c0c8717SLuigi Rizzo FILE *f = NULL; 3913c0c8717SLuigi Rizzo pid_t preproc = 0; 3923c0c8717SLuigi Rizzo 3933c0c8717SLuigi Rizzo while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { 3943c0c8717SLuigi Rizzo switch(c) { 3953c0c8717SLuigi Rizzo case 'c': 3963c0c8717SLuigi Rizzo co.do_compact = 1; 3973c0c8717SLuigi Rizzo break; 3983c0c8717SLuigi Rizzo 3993c0c8717SLuigi Rizzo case 'f': 4003c0c8717SLuigi Rizzo co.do_force = 1; 4013c0c8717SLuigi Rizzo break; 4023c0c8717SLuigi Rizzo 4033c0c8717SLuigi Rizzo case 'N': 4043c0c8717SLuigi Rizzo co.do_resolv = 1; 4053c0c8717SLuigi Rizzo break; 4063c0c8717SLuigi Rizzo 4073c0c8717SLuigi Rizzo case 'n': 4083c0c8717SLuigi Rizzo co.test_only = 1; 4093c0c8717SLuigi Rizzo break; 4103c0c8717SLuigi Rizzo 4113c0c8717SLuigi Rizzo case 'p': 4123c0c8717SLuigi Rizzo /* 4133c0c8717SLuigi Rizzo * ipfw -p cmd [args] filename 4143c0c8717SLuigi Rizzo * 4153c0c8717SLuigi Rizzo * We are done with getopt(). All arguments 4163c0c8717SLuigi Rizzo * except the filename go to the preprocessor, 4173c0c8717SLuigi Rizzo * so we need to do the following: 4183c0c8717SLuigi Rizzo * - check that a filename is actually present; 4193c0c8717SLuigi Rizzo * - advance av by optind-1 to skip arguments 4203c0c8717SLuigi Rizzo * already processed; 4213c0c8717SLuigi Rizzo * - decrease ac by optind, to remove the args 4223c0c8717SLuigi Rizzo * already processed and the final filename; 4233c0c8717SLuigi Rizzo * - set the last entry in av[] to NULL so 4243c0c8717SLuigi Rizzo * popen() can detect the end of the array; 4253c0c8717SLuigi Rizzo * - set optind=ac to let getopt() terminate. 4263c0c8717SLuigi Rizzo */ 4273c0c8717SLuigi Rizzo if (optind == ac) 4283c0c8717SLuigi Rizzo errx(EX_USAGE, "no filename argument"); 4293c0c8717SLuigi Rizzo cmd = optarg; 4303c0c8717SLuigi Rizzo av[ac-1] = NULL; 4313c0c8717SLuigi Rizzo av += optind - 1; 4323c0c8717SLuigi Rizzo ac -= optind; 4333c0c8717SLuigi Rizzo optind = ac; 4343c0c8717SLuigi Rizzo break; 4353c0c8717SLuigi Rizzo 4363c0c8717SLuigi Rizzo case 'q': 4373c0c8717SLuigi Rizzo co.do_quiet = 1; 4383c0c8717SLuigi Rizzo break; 4393c0c8717SLuigi Rizzo 4403c0c8717SLuigi Rizzo case 'S': 4413c0c8717SLuigi Rizzo co.show_sets = 1; 4423c0c8717SLuigi Rizzo break; 4433c0c8717SLuigi Rizzo 4443c0c8717SLuigi Rizzo default: 4453c0c8717SLuigi Rizzo errx(EX_USAGE, "bad arguments, for usage" 4463c0c8717SLuigi Rizzo " summary ``ipfw''"); 4473c0c8717SLuigi Rizzo } 4483c0c8717SLuigi Rizzo 4493c0c8717SLuigi Rizzo } 4503c0c8717SLuigi Rizzo 4513c0c8717SLuigi Rizzo if (cmd == NULL && ac != optind + 1) 4523c0c8717SLuigi Rizzo errx(EX_USAGE, "extraneous filename arguments %s", av[ac-1]); 4533c0c8717SLuigi Rizzo 4543c0c8717SLuigi Rizzo if ((f = fopen(filename, "r")) == NULL) 4553c0c8717SLuigi Rizzo err(EX_UNAVAILABLE, "fopen: %s", filename); 4563c0c8717SLuigi Rizzo 4573c0c8717SLuigi Rizzo if (cmd != NULL) { /* pipe through preprocessor */ 4583c0c8717SLuigi Rizzo int pipedes[2]; 4593c0c8717SLuigi Rizzo 4603c0c8717SLuigi Rizzo if (pipe(pipedes) == -1) 4613c0c8717SLuigi Rizzo err(EX_OSERR, "cannot create pipe"); 4623c0c8717SLuigi Rizzo 4633c0c8717SLuigi Rizzo preproc = fork(); 4643c0c8717SLuigi Rizzo if (preproc == -1) 4653c0c8717SLuigi Rizzo err(EX_OSERR, "cannot fork"); 4663c0c8717SLuigi Rizzo 4673c0c8717SLuigi Rizzo if (preproc == 0) { 4683c0c8717SLuigi Rizzo /* 4693c0c8717SLuigi Rizzo * Child, will run the preprocessor with the 4703c0c8717SLuigi Rizzo * file on stdin and the pipe on stdout. 4713c0c8717SLuigi Rizzo */ 4723c0c8717SLuigi Rizzo if (dup2(fileno(f), 0) == -1 4733c0c8717SLuigi Rizzo || dup2(pipedes[1], 1) == -1) 4743c0c8717SLuigi Rizzo err(EX_OSERR, "dup2()"); 4753c0c8717SLuigi Rizzo fclose(f); 4763c0c8717SLuigi Rizzo close(pipedes[1]); 4773c0c8717SLuigi Rizzo close(pipedes[0]); 4783c0c8717SLuigi Rizzo execvp(cmd, av); 4793c0c8717SLuigi Rizzo err(EX_OSERR, "execvp(%s) failed", cmd); 4803c0c8717SLuigi Rizzo } else { /* parent, will reopen f as the pipe */ 4813c0c8717SLuigi Rizzo fclose(f); 4823c0c8717SLuigi Rizzo close(pipedes[1]); 4833c0c8717SLuigi Rizzo if ((f = fdopen(pipedes[0], "r")) == NULL) { 4843c0c8717SLuigi Rizzo int savederrno = errno; 4853c0c8717SLuigi Rizzo 4863c0c8717SLuigi Rizzo (void)kill(preproc, SIGTERM); 4873c0c8717SLuigi Rizzo errno = savederrno; 4883c0c8717SLuigi Rizzo err(EX_OSERR, "fdopen()"); 4893c0c8717SLuigi Rizzo } 4903c0c8717SLuigi Rizzo } 4913c0c8717SLuigi Rizzo } 4923c0c8717SLuigi Rizzo 4933c0c8717SLuigi Rizzo while (fgets(buf, BUFSIZ, f)) { /* read commands */ 4943c0c8717SLuigi Rizzo char linename[10]; 4953c0c8717SLuigi Rizzo char *args[2]; 4963c0c8717SLuigi Rizzo 4973c0c8717SLuigi Rizzo lineno++; 4983c0c8717SLuigi Rizzo sprintf(linename, "Line %d", lineno); 4993c0c8717SLuigi Rizzo setprogname(linename); /* XXX */ 5003c0c8717SLuigi Rizzo args[0] = progname; 5013c0c8717SLuigi Rizzo args[1] = buf; 5023c0c8717SLuigi Rizzo ipfw_main(2, args); 5033c0c8717SLuigi Rizzo } 5043c0c8717SLuigi Rizzo fclose(f); 5053c0c8717SLuigi Rizzo if (cmd != NULL) { 5063c0c8717SLuigi Rizzo int status; 5073c0c8717SLuigi Rizzo 5083c0c8717SLuigi Rizzo if (waitpid(preproc, &status, 0) == -1) 5093c0c8717SLuigi Rizzo errx(EX_OSERR, "waitpid()"); 5103c0c8717SLuigi Rizzo if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 5113c0c8717SLuigi Rizzo errx(EX_UNAVAILABLE, 5123c0c8717SLuigi Rizzo "preprocessor exited with status %d", 5133c0c8717SLuigi Rizzo WEXITSTATUS(status)); 5143c0c8717SLuigi Rizzo else if (WIFSIGNALED(status)) 5153c0c8717SLuigi Rizzo errx(EX_UNAVAILABLE, 5163c0c8717SLuigi Rizzo "preprocessor exited with signal %d", 5173c0c8717SLuigi Rizzo WTERMSIG(status)); 5183c0c8717SLuigi Rizzo } 5193c0c8717SLuigi Rizzo } 5203c0c8717SLuigi Rizzo 5213c0c8717SLuigi Rizzo int 5223c0c8717SLuigi Rizzo main(int ac, char *av[]) 5233c0c8717SLuigi Rizzo { 5243c0c8717SLuigi Rizzo /* 5253c0c8717SLuigi Rizzo * If the last argument is an absolute pathname, interpret it 5263c0c8717SLuigi Rizzo * as a file to be preprocessed. 5273c0c8717SLuigi Rizzo */ 5283c0c8717SLuigi Rizzo 5293c0c8717SLuigi Rizzo if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 5303c0c8717SLuigi Rizzo ipfw_readfile(ac, av); 5313c0c8717SLuigi Rizzo else { 5323c0c8717SLuigi Rizzo if (ipfw_main(ac, av)) { 5333c0c8717SLuigi Rizzo errx(EX_USAGE, 5343c0c8717SLuigi Rizzo "usage: ipfw [options]\n" 5353c0c8717SLuigi Rizzo "do \"ipfw -h\" or \"man ipfw\" for details"); 5363c0c8717SLuigi Rizzo } 5373c0c8717SLuigi Rizzo } 5383c0c8717SLuigi Rizzo return EX_OK; 5393c0c8717SLuigi Rizzo } 540