X-Git-Url: http://git.onelab.eu/?p=ipfw.git;a=blobdiff_plain;f=ipfw%2Fipfw2.c;h=bf3a9b1ab52716650d1c48585436b8a8c6fb94b2;hp=571ff39950b8afccbb624aace757b3dd6fc8f442;hb=HEAD;hpb=5ad9fec40da13c449d50def12f9cea6e24b6a708 diff --git a/ipfw/ipfw2.c b/ipfw/ipfw2.c index 571ff39..bf3a9b1 100644 --- a/ipfw/ipfw2.c +++ b/ipfw/ipfw2.c @@ -17,7 +17,7 @@ * * NEW command line interface for IP firewall facility * - * $FreeBSD: head/sbin/ipfw/ipfw2.c 187983 2009-02-01 16:00:49Z luigi $ + * $FreeBSD: head/sbin/ipfw/ipfw2.c 206843 2010-04-19 15:11:45Z luigi $ */ #include @@ -40,7 +40,14 @@ #include /* ctime */ #include /* _long_to_time */ #include +/* + * FreeBSD uses __unused as a shorthand for __attribute__ ((__unused__)) + * whereas Linux sometimes uses __unused as a variable name. + * undefine the macro around problematic places. + */ +#undef __unused #include +#define __unused __attribute__ ((__unused__)) #include #include /* only IFNAMSIZ */ @@ -57,7 +64,7 @@ struct cmdline_opts co; /* global options */ int resvd_set_number = RESVD_SET; #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ - if (!ac) \ + if (!av[0]) \ errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ if (_substrcmp(*av, "tablearg") == 0) { \ arg = IP_FW_TABLEARG; \ @@ -65,23 +72,23 @@ int resvd_set_number = RESVD_SET; } \ \ { \ - long val; \ + long _xval; \ char *end; \ \ - val = strtol(*av, &end, 10); \ + _xval = strtol(*av, &end, 10); \ \ - if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) \ + if (!isdigit(**av) || *end != '\0' || (_xval == 0 && errno == EINVAL)) \ errx(EX_DATAERR, "%s: invalid argument: %s", \ match_value(s_x, tok), *av); \ \ - if (errno == ERANGE || val < min || val > max) \ + if (errno == ERANGE || _xval < min || _xval > max) \ errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ match_value(s_x, tok), min, max, *av); \ \ - if (val == IP_FW_TABLEARG) \ + if (_xval == IP_FW_TABLEARG) \ errx(EX_DATAERR, "%s: illegal argument value: %s", \ match_value(s_x, tok), *av); \ - arg = val; \ + arg = _xval; \ } \ } while (0) @@ -224,11 +231,14 @@ static struct _s_x rule_action_params[] = { { NULL, 0 } /* terminator */ }; -/* index of 'lookup ... ' keys in the kernel */ +/* + * The 'lookup' instruction accepts one of the following arguments. + * -1 is a terminator for the list. + * Arguments are passed as v[1] in O_DST_LOOKUP options. + */ static int lookup_key[] = { TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT, - TOK_UID, TOK_GID, TOK_JAIL, - TOK_PROTO, TOK_MACTYPE, 0, }; + TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; static struct _s_x rule_options[] = { { "tagged", TOK_TAGGED }, @@ -255,6 +265,7 @@ static struct _s_x rule_options[] = { { "iplen", TOK_IPLEN }, { "ipid", TOK_IPID }, { "ipprecedence", TOK_IPPRECEDENCE }, + { "dscp", TOK_DSCP }, { "iptos", TOK_IPTOS }, { "ipttl", TOK_IPTTL }, { "ipversion", TOK_IPVER }, @@ -310,22 +321,29 @@ static struct _s_x rule_options[] = { { NULL, 0 } /* terminator */ }; -/* - * The following is used to generate a printable argument for - * 64-bit numbers, irrespective of platform alignment and bit size. - * Because all the printf in this program use %llu as a format, - * we just return an unsigned long long, which is larger than - * we need in certain cases, but saves the hassle of using - * PRIu64 as a format specifier. - * We don't care about inlining, this is not performance critical code. +/* + * Helper routine to print a possibly unaligned uint64_t on + * various platform. If width > 0, print the value with + * the desired width, followed by a space; + * otherwise, return the required width. */ -unsigned long long -align_uint64(const uint64_t *pll) +int +pr_u64(uint64_t *pd, int width) { - uint64_t ret; - - bcopy (pll, &ret, sizeof(ret)); - return ret; +#ifdef TCC +#define U64_FMT "I64" +#else +#define U64_FMT "llu" +#endif + uint64_t u; + unsigned long long d; + + bcopy (pd, &u, sizeof(u)); + d = u; + return (width > 0) ? + printf("%*" U64_FMT " ", width, d) : + snprintf(NULL, 0, "%" U64_FMT, d) ; +#undef U64_FMT } void * @@ -350,6 +368,7 @@ safe_realloc(void *ptr, size_t size) /* * conditionally runs the command. + * Selected options or negative -> getsockopt */ int do_cmd(int optname, void *optval, uintptr_t optlen) @@ -365,16 +384,19 @@ do_cmd(int optname, void *optval, uintptr_t optlen) if (s < 0) err(EX_UNAVAILABLE, "socket"); - if (optname == IP_FW_GET || optname == IP_FW_DYN_GET || - optname == IP_DUMMYNET_GET || + if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || optname == IP_FW_TABLE_GETSIZE || optname == IP_FW_NAT_GET_CONFIG || - optname == IP_FW_NAT_GET_LOG) + optname < 0 || + optname == IP_FW_NAT_GET_LOG) { + if (optname < 0) + optname = -optname; i = getsockopt(s, IPPROTO_IP, optname, optval, (socklen_t *)optlen); - else + } else { i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); + } return i; } @@ -747,7 +769,7 @@ static void print_ip(ipfw_insn_ip *cmd, char const *s) { struct hostent *he = NULL; - int len = F_LEN((ipfw_insn *)cmd); + uint32_t len = F_LEN((ipfw_insn *)cmd); uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) { @@ -756,8 +778,8 @@ print_ip(ipfw_insn_ip *cmd, char const *s) if (d < sizeof(lookup_key)/sizeof(lookup_key[0])) arg = match_value(rule_options, lookup_key[d]); - printf("%s lookup %s %d,%d", cmd->o.len & F_NOT ? " not": "", - arg, cmd->o.arg1, a[0]); + printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "", + arg, cmd->o.arg1); return; } printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); @@ -913,9 +935,9 @@ print_icmptypes(ipfw_insn_u32 *cmd) #define HAVE_DSTIP 0x0004 #define HAVE_PROTO4 0x0008 #define HAVE_PROTO6 0x0010 +#define HAVE_IP 0x0100 #define HAVE_OPTIONS 0x8000 -#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) static void show_prerequisites(int *flags, int want, int cmd __unused) { @@ -965,9 +987,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) } printf("%05u ", rule->rulenum); - if (pcwidth>0 || bcwidth>0) - printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), - bcwidth, align_uint64(&rule->bcnt)); + if (pcwidth > 0 || bcwidth > 0) { + pr_u64(&rule->pcnt, pcwidth); + pr_u64(&rule->bcnt, bcwidth); + } if (co.do_time == 2) printf("%10u ", rule->timestamp); @@ -1016,7 +1039,9 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) switch(cmd->opcode) { case O_CHECK_STATE: printf("check-state"); - flags = HAVE_IP; /* avoid printing anything else */ + /* avoid printing anything else */ + flags = HAVE_PROTO | HAVE_SRCIP | + HAVE_DSTIP | HAVE_IP; break; case O_ACCEPT: @@ -1108,7 +1133,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) case O_SETFIB: PRINT_UINT_ARG("setfib ", cmd->arg1); break; - + case O_REASS: printf("reass"); break; @@ -1124,9 +1149,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) else printf(" log"); } +#ifndef NO_ALTQ if (altqptr) { print_altq_cmd(altqptr); } +#endif if (tagptr) { if (tagptr->len & F_NOT) PRINT_UINT_ARG(" untag ", tagptr->arg1); @@ -1154,7 +1181,8 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) show_prerequisites(&flags, HAVE_PROTO, 0); printf(" from any to any"); } - flags |= HAVE_IP | HAVE_OPTIONS; + flags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO | + HAVE_SRCIP | HAVE_DSTIP; } if (co.comment_only) @@ -1243,9 +1271,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; case O_IP_DSTPORT: - show_prerequisites(&flags, HAVE_IP, 0); + show_prerequisites(&flags, + HAVE_PROTO | HAVE_SRCIP | + HAVE_DSTIP | HAVE_IP, 0); case O_IP_SRCPORT: - show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); + show_prerequisites(&flags, + HAVE_PROTO | HAVE_SRCIP, 0); if ((cmd->len & F_OR) && !or_block) printf(" {"); if (cmd->len & F_NOT) @@ -1266,7 +1297,8 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && !(flags & HAVE_PROTO)) show_prerequisites(&flags, - HAVE_IP | HAVE_OPTIONS, 0); + HAVE_PROTO | HAVE_IP | HAVE_SRCIP | + HAVE_DSTIP | HAVE_OPTIONS, 0); if (flags & HAVE_OPTIONS) printf(" proto"); if (pe) @@ -1284,7 +1316,8 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) ((cmd->opcode == O_IP4) && (flags & HAVE_PROTO4))) break; - show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); + show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | + HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0); if ((cmd->len & F_OR) && !or_block) printf(" {"); if (cmd->len & F_NOT && cmd->opcode != O_IN) @@ -1538,7 +1571,8 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) or_block = 0; } } - show_prerequisites(&flags, HAVE_IP, 0); + show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP + | HAVE_IP, 0); if (comment) printf(" // %s", comment); printf("\n"); @@ -1558,10 +1592,12 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) } bcopy(&d->rule, &rulenum, sizeof(rulenum)); printf("%05d", rulenum); - if (pcwidth>0 || bcwidth>0) - printf(" %*llu %*llu (%ds)", pcwidth, - align_uint64(&d->pcnt), bcwidth, - align_uint64(&d->bcnt), d->expire); + if (pcwidth > 0 || bcwidth > 0) { + printf(" "); + pr_u64(&d->pcnt, pcwidth); + pr_u64(&d->bcnt, bcwidth); + printf("(%ds)", d->expire); + } switch (d->dyn_type) { case O_LIMIT_PARENT: printf(" PARENT %d", d->count); @@ -1604,26 +1640,33 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) * ipfw set move rule X to Y */ void -ipfw_sets_handler(int ac, char *av[]) +ipfw_sets_handler(char *av[]) { uint32_t set_disable, masks[2]; int i, nbytes; uint16_t rulenum; uint8_t cmd, new_set; - ac--; av++; - if (!ac) + if (av[0] == NULL) errx(EX_USAGE, "set needs command"); if (_substrcmp(*av, "show") == 0) { - void *data; + void *data = NULL; char const *msg; + int nalloc; + + nalloc = nbytes = sizeof(struct ip_fw); + while (nbytes >= nalloc) { + if (data) + free(data); + nalloc = nalloc * 2 + 200; + nbytes = nalloc; + data = safe_calloc(1, nbytes); + if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) + err(EX_OSERR, "getsockopt(IP_FW_GET)"); + } - nbytes = sizeof(struct ip_fw); - data = safe_calloc(1, nbytes); - if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) - err(EX_OSERR, "getsockopt(IP_FW_GET)"); bcopy(&((struct ip_fw *)data)->next_rule, &set_disable, sizeof(set_disable)); @@ -1640,8 +1683,8 @@ ipfw_sets_handler(int ac, char *av[]) } printf("\n"); } else if (_substrcmp(*av, "swap") == 0) { - ac--; av++; - if (ac != 2) + av++; + if ( av[0] == NULL || av[1] == NULL ) errx(EX_USAGE, "set swap needs 2 set numbers\n"); rulenum = atoi(av[0]); new_set = atoi(av[1]); @@ -1652,13 +1695,14 @@ ipfw_sets_handler(int ac, char *av[]) masks[0] = (4 << 24) | (new_set << 16) | (rulenum); i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); } else if (_substrcmp(*av, "move") == 0) { - ac--; av++; - if (ac && _substrcmp(*av, "rule") == 0) { + av++; + if (av[0] && _substrcmp(*av, "rule") == 0) { cmd = 2; - ac--; av++; + av++; } else cmd = 3; - if (ac != 3 || _substrcmp(av[1], "to") != 0) + if (av[0] == NULL || av[1] == NULL || av[2] == NULL || + av[3] != NULL || _substrcmp(av[1], "to") != 0) errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); rulenum = atoi(av[0]); new_set = atoi(av[2]); @@ -1673,10 +1717,10 @@ ipfw_sets_handler(int ac, char *av[]) _substrcmp(*av, "enable") == 0 ) { int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; - ac--; av++; + av++; masks[0] = masks[1] = 0; - while (ac) { + while (av[0]) { if (isdigit(**av)) { i = atoi(*av); if (i < 0 || i > RESVD_SET) @@ -1690,7 +1734,7 @@ ipfw_sets_handler(int ac, char *av[]) else errx(EX_DATAERR, "invalid set command %s\n", *av); - av++; ac--; + av++; } if ( (masks[0] & masks[1]) != 0 ) errx(EX_DATAERR, @@ -1704,16 +1748,17 @@ ipfw_sets_handler(int ac, char *av[]) } void -ipfw_sysctl_handler(int ac, char *av[], int which) +ipfw_sysctl_handler(char *av[], int which) { - ac--; av++; - if (ac == 0) { + if (av[0] == NULL) { warnx("missing keyword to enable/disable\n"); } else if (_substrcmp(*av, "firewall") == 0) { sysctlbyname("net.inet.ip.fw.enable", NULL, 0, &which, sizeof(which)); + sysctlbyname("net.inet6.ip6.fw.enable", NULL, 0, + &which, sizeof(which)); } else if (_substrcmp(*av, "one_pass") == 0) { sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, &which, sizeof(which)); @@ -1726,8 +1771,10 @@ ipfw_sysctl_handler(int ac, char *av[], int which) } else if (_substrcmp(*av, "dyn_keepalive") == 0) { sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, &which, sizeof(which)); +#ifndef NO_ALTQ } else if (_substrcmp(*av, "altq") == 0) { altq_set_enabled(which); +#endif } else { warnx("unrecognize enable/disable keyword: %s\n", *av); } @@ -1737,14 +1784,12 @@ void ipfw_list(int ac, char *av[], int show_counters) { struct ip_fw *r; - ipfw_dyn_rule *dynrules = NULL; - ipfw_dyn_rule *d; + ipfw_dyn_rule *dynrules, *d; #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) char *lim; void *data = NULL; - int bcwidth, n, nbytes, pcwidth, width, nstat; - int ndyn = 0; + int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; int exitval = EX_OK; int lac; char **lav; @@ -1752,13 +1797,8 @@ ipfw_list(int ac, char *av[], int show_counters) char *endptr; int seen = 0; uint8_t set; - int ocmd = IP_FW_GET; - - if (co.do_pipe) - ocmd = IP_DUMMYNET_GET; - else if (co.do_dynamic) - ocmd = IP_FW_DYN_GET; + const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; int nalloc = 1024; /* start somewhere... */ last = 0; @@ -1767,6 +1807,10 @@ ipfw_list(int ac, char *av[], int show_counters) fprintf(stderr, "Testing only, list disabled\n"); return; } + if (co.do_pipe) { + dummynet_list(ac, av, show_counters); + return; + } ac--; av++; @@ -1783,34 +1827,23 @@ ipfw_list(int ac, char *av[], int show_counters) co.do_pipe ? "DUMMYNET" : "FW"); } - if (co.do_pipe) { - ipfw_list_pipes(data, nbytes, ac, av); - goto done; - } - /* * Count static rules. They have variable size so we * need to scan the list to count them. */ - nstat = 0; - r = data; - - if (!co.do_dynamic) { for (nstat = 1, r = data, lim = (char *)data + nbytes; r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim; ++nstat, r = NEXT(r) ) ; /* nothing */ - } /* * Count dynamic rules. This is easier as they have * fixed size. */ - if (co.do_dynamic) { - dynrules = (ipfw_dyn_rule *)r ; - n = (char *)r - (char *)data; - ndyn = (nbytes - n) / sizeof *dynrules; - } + r = NEXT(r); + dynrules = (ipfw_dyn_rule *)r ; + n = (char *)r - (char *)data; + ndyn = (nbytes - n) / sizeof *dynrules; /* if showing stats, figure out column widths ahead of time */ bcwidth = pcwidth = 0; @@ -1821,14 +1854,12 @@ ipfw_list(int ac, char *av[], int show_counters) continue; /* packet counter */ - width = snprintf(NULL, 0, "%llu", - align_uint64(&r->pcnt)); + width = pr_u64(&r->pcnt, 0); if (width > pcwidth) pcwidth = width; /* byte counter */ - width = snprintf(NULL, 0, "%llu", - align_uint64(&r->bcnt)); + width = pr_u64(&r->bcnt, 0); if (width > bcwidth) bcwidth = width; } @@ -1842,13 +1873,11 @@ ipfw_list(int ac, char *av[], int show_counters) if (set != co.use_set - 1) continue; } - width = snprintf(NULL, 0, "%llu", - align_uint64(&d->pcnt)); + width = pr_u64(&d->pcnt, 0); if (width > pcwidth) pcwidth = width; - width = snprintf(NULL, 0, "%llu", - align_uint64(&d->bcnt)); + width = pr_u64(&d->bcnt, 0); if (width > bcwidth) bcwidth = width; } @@ -1878,7 +1907,6 @@ ipfw_list(int ac, char *av[], int show_counters) /* display specific rules requested on command line */ - if (!co.do_dynamic) { for (lac = ac, lav = av; lac != 0; lac--) { /* convert command line rule # */ last = rnum = strtoul(*lav++, &endptr, 10); @@ -1906,7 +1934,6 @@ ipfw_list(int ac, char *av[], int show_counters) warnx("rule %lu does not exist", rnum); } } - } if (co.do_dynamic && ndyn) { printf("## Dynamic rules:\n"); @@ -2143,7 +2170,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av) return; } /* A single IP can be stored in an optimized format */ - if (d[1] == ~0 && av == NULL && len == 0) { + if (d[1] == (uint32_t)~0 && av == NULL && len == 0) { cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); return; } @@ -2212,29 +2239,28 @@ fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, void -ipfw_delete(int ac, char *av[]) +ipfw_delete(char *av[]) { uint32_t rulenum; int i; int exitval = EX_OK; int do_set = 0; - - av++; ac--; + av++; NEED1("missing rule specification"); - if (ac > 0 && _substrcmp(*av, "set") == 0) { + if ( *av && _substrcmp(*av, "set") == 0) { /* Do not allow using the following syntax: * ipfw set N delete set M */ if (co.use_set) errx(EX_DATAERR, "invalid syntax"); do_set = 1; /* delete set */ - ac--; av++; + av++; } /* Rule number */ - while (ac && isdigit(**av)) { - i = atoi(*av); av++; ac--; + while (*av && isdigit(**av)) { + i = atoi(*av); av++; if (co.do_nat) { exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); if (exitval) { @@ -2288,7 +2314,8 @@ fill_iface(ipfw_insn_if *cmd, char *arg) static void get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) { - int i, l; + int i; + size_t l; char *ap, *ptr, *optr; struct ether_addr *mac; const char *macset = "0123456789abcdefABCDEF:"; @@ -2310,11 +2337,11 @@ get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) if (ptr != NULL) { /* we have mask? */ if (p[ptr - optr - 1] == '/') { /* mask len */ - l = strtol(ptr, &ap, 10); - if (*ap != 0 || l > ETHER_ADDR_LEN * 8 || l < 0) + long ml = strtol(ptr, &ap, 10); + if (*ap != 0 || ml > ETHER_ADDR_LEN * 8 || ml < 0) errx(EX_DATAERR, "Incorrect mask length"); - for (i = 0; l > 0 && i < ETHER_ADDR_LEN; l -= 8, i++) - mask[i] = (l >= 8) ? 0xff: (~0) << (8 - l); + for (i = 0; ml > 0 && i < ETHER_ADDR_LEN; ml -= 8, i++) + mask[i] = (ml >= 8) ? 0xff: (~0) << (8 - ml); } else { /* mask */ l = strlen(ptr); if (strspn(ptr, macset) != l || @@ -2349,7 +2376,7 @@ next_cmd(ipfw_insn *cmd) * Takes arguments and copies them into a comment */ static void -fill_comment(ipfw_insn *cmd, int ac, char **av) +fill_comment(ipfw_insn *cmd, char **av) { int i, l; char *p = (char *)(cmd + 1); @@ -2358,7 +2385,7 @@ fill_comment(ipfw_insn *cmd, int ac, char **av) cmd->len = (cmd->len & (F_NOT | F_OR)); /* Compute length of comment string. */ - for (i = 0, l = 0; i < ac; i++) + for (i = 0, l = 0; av[i] != NULL; i++) l += strlen(av[i]) + 1; if (l == 0) return; @@ -2367,7 +2394,7 @@ fill_comment(ipfw_insn *cmd, int ac, char **av) "comment too long (max 80 chars)"); l = 1 + (l+3)/4; cmd->len = (cmd->len & (F_NOT | F_OR)) | l; - for (i = 0; i < ac; i++) { + for (i = 0; av[i] != NULL; i++) { strcpy(p, av[i]); p += strlen(av[i]); *p++ = ' '; @@ -2392,11 +2419,11 @@ fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) * two microinstructions, and returns the pointer to the last one. */ static ipfw_insn * -add_mac(ipfw_insn *cmd, int ac, char *av[]) +add_mac(ipfw_insn *cmd, char *av[]) { ipfw_insn_mac *mac; - if (ac < 2) + if ( ( av[0] == NULL ) || ( av[1] == NULL ) ) errx(EX_DATAERR, "MAC dst src"); cmd->opcode = O_MACADDR2; @@ -2410,9 +2437,9 @@ add_mac(ipfw_insn *cmd, int ac, char *av[]) } static ipfw_insn * -add_mactype(ipfw_insn *cmd, int ac, char *av) +add_mactype(ipfw_insn *cmd, char *av) { - if (ac < 1) + if (!av) errx(EX_DATAERR, "missing MAC type"); if (strcmp(av, "any") != 0) { /* we have a non-null type */ fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); @@ -2520,6 +2547,7 @@ add_dstip(ipfw_insn *cmd, char *av) static ipfw_insn * add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) { + /* XXX "any" is trapped before. Perhaps "to" */ if (_substrcmp(av, "any") == 0) { return NULL; } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { @@ -2543,11 +2571,11 @@ add_src(ipfw_insn *cmd, char *av, u_char proto) *ch = '\0'; if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || - inet_pton(AF_INET6, host, &a)) + inet_pton(AF_INET6, host, &a) == 1) ret = add_srcip6(cmd, av); /* XXX: should check for IPv4, not !IPv6 */ if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || - !inet_pton(AF_INET6, host, &a))) + inet_pton(AF_INET6, host, &a) != 1)) ret = add_srcip(cmd, av); if (ret == NULL && strcmp(av, "any") != 0) ret = cmd; @@ -2569,11 +2597,11 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto) *ch = '\0'; if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || - inet_pton(AF_INET6, host, &a)) + inet_pton(AF_INET6, host, &a) == 1) ret = add_dstip6(cmd, av); /* XXX: should check for IPv4, not !IPv6 */ if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || - !inet_pton(AF_INET6, host, &a))) + inet_pton(AF_INET6, host, &a) != 1)) ret = add_dstip(cmd, av); if (ret == NULL && strcmp(av, "any") != 0) ret = cmd; @@ -2595,7 +2623,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto) * */ void -ipfw_add(int ac, char *av[]) +ipfw_add(char *av[]) { /* * rules are added into the 'rulebuf' and then copied in @@ -2634,37 +2662,36 @@ ipfw_add(int ac, char *av[]) cmd = (ipfw_insn *)cmdbuf; action = (ipfw_insn *)actbuf; - av++; ac--; + av++; /* [rule N] -- Rule number optional */ - if (ac && isdigit(**av)) { + if (av[0] && isdigit(**av)) { rule->rulenum = atoi(*av); av++; - ac--; } /* [set N] -- set number (0..RESVD_SET), optional */ - if (ac > 1 && _substrcmp(*av, "set") == 0) { + if (av[0] && av[1] && _substrcmp(*av, "set") == 0) { int set = strtoul(av[1], NULL, 10); if (set < 0 || set > RESVD_SET) errx(EX_DATAERR, "illegal set %s", av[1]); rule->set = set; - av += 2; ac -= 2; + av += 2; } /* [prob D] -- match probability, optional */ - if (ac > 1 && _substrcmp(*av, "prob") == 0) { + if (av[0] && av[1] && _substrcmp(*av, "prob") == 0) { match_prob = strtod(av[1], NULL); if (match_prob <= 0 || match_prob > 1) errx(EX_DATAERR, "illegal match prob. %s", av[1]); - av += 2; ac -= 2; + av += 2; } /* action -- mandatory */ NEED1("missing action"); i = match_token(rule_actions, *av); - ac--; av++; + av++; action->len = 1; /* default */ switch(i) { case TOK_CHECKSTATE: @@ -2700,14 +2727,14 @@ ipfw_add(int ac, char *av[]) action->opcode = O_REJECT; NEED1("missing reject code"); fill_reject_code(&action->arg1, *av); - ac--; av++; + av++; break; case TOK_UNREACH6: action->opcode = O_UNREACH6; NEED1("missing unreach code"); fill_unreach6_code(&action->arg1, *av); - ac--; av++; + av++; break; case TOK_COUNT: @@ -2740,7 +2767,7 @@ ipfw_add(int ac, char *av[]) case TOK_TEE: action->opcode = O_TEE; chkarg: - if (!ac) + if (!av[0]) errx(EX_USAGE, "missing argument for %s", *(av - 1)); if (isdigit(**av)) { action->arg1 = strtoul(*av, NULL, 10); @@ -2759,7 +2786,7 @@ chkarg: errx(EX_DATAERR, "illegal divert/tee port"); } else errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); - ac--; av++; + av++; break; case TOK_FORWARD: { @@ -2777,7 +2804,7 @@ chkarg: * the routing code seems to use it too. */ p->sa.sin_family = AF_INET; - //p->sa.sin_len = sizeof(struct sockaddr_in); + p->sa.sin_len = sizeof(struct sockaddr_in); p->sa.sin_port = 0; /* * locate the address-port separator (':' or ',') @@ -2797,13 +2824,13 @@ chkarg: p->sa.sin_addr.s_addr = INADDR_ANY; else lookup_host(*av, &(p->sa.sin_addr)); - ac--; av++; + av++; break; } case TOK_COMMENT: /* pretend it is a 'count' rule followed by the comment */ action->opcode = O_COUNT; - ac++; av--; /* go back... */ + av--; /* go back... */ break; case TOK_SETFIB: @@ -2818,10 +2845,10 @@ chkarg: errx(EX_DATAERR, "fibs not suported.\n"); if (action->arg1 >= numfibs) /* Temporary */ errx(EX_DATAERR, "fib too large.\n"); - ac--; av++; + av++; break; } - + case TOK_REASS: action->opcode = O_REASS; break; @@ -2838,8 +2865,8 @@ chkarg: * If they exist, it go first in the cmdbuf, but then it is * skipped in the copy section to the end of the buffer. */ - while (ac != 0 && (i = match_token(rule_action_params, *av)) != -1) { - ac--; av++; + while (av[0] != NULL && (i = match_token(rule_action_params, *av)) != -1) { + av++; switch (i) { case TOK_LOG: { @@ -2852,15 +2879,15 @@ chkarg: have_log = (ipfw_insn *)c; cmd->len = F_INSN_SIZE(ipfw_insn_log); cmd->opcode = O_LOG; - if (ac && _substrcmp(*av, "logamount") == 0) { - ac--; av++; + if (av[0] && _substrcmp(*av, "logamount") == 0) { + av++; NEED1("logamount requires argument"); l = atoi(*av); if (l < 0) errx(EX_DATAERR, "logamount must be positive"); c->max_log = l; - ac--; av++; + av++; } else { len = sizeof(c->max_log); if (sysctlbyname("net.inet.ip.fw.verbose_limit", @@ -2871,6 +2898,7 @@ chkarg: } break; +#ifndef NO_ALTQ case TOK_ALTQ: { ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; @@ -2883,9 +2911,10 @@ chkarg: cmd->len = F_INSN_SIZE(ipfw_insn_altq); cmd->opcode = O_ALTQ; a->qid = altq_name_to_qid(*av); - ac--; av++; + av++; } break; +#endif case TOK_TAG: case TOK_UNTAG: { @@ -2898,7 +2927,7 @@ chkarg: rule_action_params); have_tag = cmd; fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); - ac--; av++; + av++; break; } @@ -2912,13 +2941,13 @@ chkarg: goto done; #define OR_START(target) \ - if (ac && (*av[0] == '(' || *av[0] == '{')) { \ + if (av[0] && (*av[0] == '(' || *av[0] == '{')) { \ if (open_par) \ errx(EX_USAGE, "nested \"(\" not allowed\n"); \ prev = NULL; \ open_par = 1; \ if ( (av[0])[1] == '\0') { \ - ac--; av++; \ + av++; \ } else \ (*av)++; \ } \ @@ -2927,30 +2956,30 @@ chkarg: #define CLOSE_PAR \ if (open_par) { \ - if (ac && ( \ + if (av[0] && ( \ strcmp(*av, ")") == 0 || \ strcmp(*av, "}") == 0)) { \ prev = NULL; \ open_par = 0; \ - ac--; av++; \ + av++; \ } else \ errx(EX_USAGE, "missing \")\"\n"); \ } #define NOT_BLOCK \ - if (ac && _substrcmp(*av, "not") == 0) { \ + if (av[0] && _substrcmp(*av, "not") == 0) { \ if (cmd->len & F_NOT) \ errx(EX_USAGE, "double \"not\" not allowed\n"); \ cmd->len |= F_NOT; \ - ac--; av++; \ + av++; \ } #define OR_BLOCK(target) \ - if (ac && _substrcmp(*av, "or") == 0) { \ + if (av[0] && _substrcmp(*av, "or") == 0) { \ if (prev == NULL || open_par == 0) \ errx(EX_DATAERR, "invalid OR block"); \ prev->len |= F_OR; \ - ac--; av++; \ + av++; \ goto target; \ } \ CLOSE_PAR; @@ -2967,15 +2996,15 @@ chkarg: NEED1("missing protocol"); if (_substrcmp(*av, "MAC") == 0 || _substrcmp(*av, "mac") == 0) { - ac--; av++; /* the "MAC" keyword */ - add_mac(cmd, ac, av); /* exits in case of errors */ + av++; /* the "MAC" keyword */ + add_mac(cmd, av); /* exits in case of errors */ cmd = next_cmd(cmd); - ac -= 2; av += 2; /* dst-mac and src-mac */ + av += 2; /* dst-mac and src-mac */ NOT_BLOCK; NEED1("missing mac type"); - if (add_mactype(cmd, ac, av[0])) + if (add_mactype(cmd, av[0])) cmd = next_cmd(cmd); - ac--; av++; /* any or mac-type */ + av++; /* any or mac-type */ goto read_options; } #endif @@ -2987,7 +3016,7 @@ chkarg: NOT_BLOCK; NEED1("missing protocol"); if (add_proto_compat(cmd, *av, &proto)) { - av++; ac--; + av++; if (F_LEN(cmd) != 0) { prev = cmd; cmd = next_cmd(cmd); @@ -3001,9 +3030,9 @@ chkarg: /* * "from", mandatory */ - if (!ac || _substrcmp(*av, "from") != 0) + if ((av[0] == NULL) || _substrcmp(*av, "from") != 0) errx(EX_USAGE, "missing ``from''"); - ac--; av++; + av++; /* * source IP, mandatory @@ -3012,7 +3041,7 @@ chkarg: NOT_BLOCK; /* optional "not" */ NEED1("missing source address"); if (add_src(cmd, *av, proto)) { - ac--; av++; + av++; if (F_LEN(cmd) != 0) { /* ! any */ prev = cmd; cmd = next_cmd(cmd); @@ -3025,10 +3054,10 @@ chkarg: * source ports, optional */ NOT_BLOCK; /* optional "not" */ - if (ac) { + if ( av[0] != NULL ) { if (_substrcmp(*av, "any") == 0 || add_ports(cmd, *av, proto, O_IP_SRCPORT)) { - ac--; av++; + av++; if (F_LEN(cmd) != 0) cmd = next_cmd(cmd); } @@ -3037,9 +3066,9 @@ chkarg: /* * "to", mandatory */ - if (!ac || _substrcmp(*av, "to") != 0) + if ( (av[0] == NULL) || _substrcmp(*av, "to") != 0 ) errx(EX_USAGE, "missing ``to''"); - av++; ac--; + av++; /* * destination, mandatory @@ -3048,7 +3077,7 @@ chkarg: NOT_BLOCK; /* optional "not" */ NEED1("missing dst address"); if (add_dst(cmd, *av, proto)) { - ac--; av++; + av++; if (F_LEN(cmd) != 0) { /* ! any */ prev = cmd; cmd = next_cmd(cmd); @@ -3061,17 +3090,17 @@ chkarg: * dest. ports, optional */ NOT_BLOCK; /* optional "not" */ - if (ac) { + if (av[0]) { if (_substrcmp(*av, "any") == 0 || add_ports(cmd, *av, proto, O_IP_DSTPORT)) { - ac--; av++; + av++; if (F_LEN(cmd) != 0) cmd = next_cmd(cmd); } } read_options: - if (ac && first_cmd == cmd) { + if (av[0] && first_cmd == cmd) { /* * nothing specified so far, store in the rule to ease * printout later. @@ -3079,7 +3108,7 @@ read_options: rule->_pad = 1; } prev = NULL; - while (ac) { + while ( av[0] != NULL ) { char *s; ipfw_insn_u32 *cmd32; /* alias for cmd */ @@ -3093,7 +3122,7 @@ read_options: s++; } i = match_token(rule_options, s); - ac--; av++; + av++; switch(i) { case TOK_NOT: if (cmd->len & F_NOT) @@ -3155,7 +3184,7 @@ read_options: NEED1("recv, xmit, via require interface name" " or address"); fill_iface((ipfw_insn_if *)cmd, av[0]); - ac--; av++; + av++; if (F_LEN(cmd) == 0) /* not a valid address */ break; if (i == TOK_XMIT) @@ -3169,13 +3198,13 @@ read_options: case TOK_ICMPTYPES: NEED1("icmptypes requires list of types"); fill_icmptypes((ipfw_insn_u32 *)cmd, *av); - av++; ac--; + av++; break; case TOK_ICMP6TYPES: NEED1("icmptypes requires list of types"); fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); - av++; ac--; + av++; break; case TOK_IPTTL: @@ -3185,7 +3214,7 @@ read_options: errx(EX_DATAERR, "invalid ipttl %s", *av); } else fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_IPID: @@ -3195,7 +3224,7 @@ read_options: errx(EX_DATAERR, "invalid ipid %s", *av); } else fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_IPLEN: @@ -3205,32 +3234,32 @@ read_options: errx(EX_DATAERR, "invalid ip len %s", *av); } else fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_IPVER: NEED1("ipver requires version"); fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_IPPRECEDENCE: NEED1("ipprecedence requires value"); fill_cmd(cmd, O_IPPRECEDENCE, 0, (strtoul(*av, NULL, 0) & 7) << 5); - ac--; av++; + av++; break; case TOK_IPOPTS: NEED1("missing argument for ipoptions"); fill_flags(cmd, O_IPOPT, f_ipopts, *av); - ac--; av++; + av++; break; case TOK_IPTOS: NEED1("missing argument for iptos"); fill_flags(cmd, O_IPTOS, f_iptos, *av); - ac--; av++; + av++; break; case TOK_UID: @@ -3247,7 +3276,7 @@ read_options: errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); cmd32->d[0] = pwd->pw_uid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); - ac--; av++; + av++; } break; @@ -3265,7 +3294,7 @@ read_options: errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); cmd32->d[0] = grp->gr_gid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); - ac--; av++; + av++; } break; @@ -3281,7 +3310,7 @@ read_options: errx(EX_DATAERR, "jail requires prison ID"); cmd32->d[0] = (uint32_t)jid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); - ac--; av++; + av++; } break; @@ -3302,13 +3331,13 @@ read_options: } else fill_cmd(cmd, O_TCPDATALEN, 0, strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_TCPOPTS: NEED1("missing argument for tcpoptions"); fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); - ac--; av++; + av++; break; case TOK_TCPSEQ: @@ -3317,21 +3346,21 @@ read_options: cmd->len = F_INSN_SIZE(ipfw_insn_u32); cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_TCPWIN: NEED1("tcpwin requires length"); fill_cmd(cmd, O_TCPWIN, 0, htons(strtoul(*av, NULL, 0))); - ac--; av++; + av++; break; case TOK_TCPFLAGS: NEED1("missing argument for tcpflags"); cmd->opcode = O_TCPFLAGS; fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); - ac--; av++; + av++; break; case TOK_KEEPSTATE: @@ -3361,11 +3390,11 @@ read_options: cmd->opcode = O_LIMIT; c->limit_mask = c->conn_limit = 0; - while (ac > 0) { + while ( av[0] != NULL ) { if ((val = match_token(limit_masks, *av)) <= 0) break; c->limit_mask |= val; - ac--; av++; + av++; } if (c->limit_mask == 0) @@ -3374,14 +3403,14 @@ read_options: GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX, TOK_LIMIT, rule_options); - ac--; av++; + av++; break; } case TOK_PROTO: NEED1("missing protocol"); if (add_proto(cmd, *av, &proto)) { - ac--; av++; + av++; } else errx(EX_DATAERR, "invalid protocol ``%s''", *av); @@ -3390,28 +3419,28 @@ read_options: case TOK_SRCIP: NEED1("missing source IP"); if (add_srcip(cmd, *av)) { - ac--; av++; + av++; } break; case TOK_DSTIP: NEED1("missing destination IP"); if (add_dstip(cmd, *av)) { - ac--; av++; + av++; } break; case TOK_SRCIP6: NEED1("missing source IP6"); if (add_srcip6(cmd, *av)) { - ac--; av++; + av++; } break; case TOK_DSTIP6: NEED1("missing destination IP6"); if (add_dstip6(cmd, *av)) { - ac--; av++; + av++; } break; @@ -3419,7 +3448,7 @@ read_options: NEED1("missing source port"); if (_substrcmp(*av, "any") == 0 || add_ports(cmd, *av, proto, O_IP_SRCPORT)) { - ac--; av++; + av++; } else errx(EX_DATAERR, "invalid source port %s", *av); break; @@ -3428,23 +3457,22 @@ read_options: NEED1("missing destination port"); if (_substrcmp(*av, "any") == 0 || add_ports(cmd, *av, proto, O_IP_DSTPORT)) { - ac--; av++; + av++; } else errx(EX_DATAERR, "invalid destination port %s", *av); break; case TOK_MAC: - if (add_mac(cmd, ac, av)) { - ac -= 2; av += 2; - } + if (add_mac(cmd, av)) + av += 2; break; case TOK_MACTYPE: NEED1("missing mac type"); - if (!add_mactype(cmd, ac, *av)) + if (!add_mactype(cmd, *av)) errx(EX_DATAERR, "invalid mac type %s", *av); - ac--; av++; + av++; break; case TOK_VERREVPATH: @@ -3473,7 +3501,7 @@ read_options: case TOK_EXT6HDR: fill_ext6hdr( cmd, *av ); - ac--; av++; + av++; break; case TOK_FLOWID: @@ -3481,17 +3509,16 @@ read_options: errx( EX_USAGE, "flow-id filter is active " "only for ipv6 protocol\n"); fill_flow6( (ipfw_insn_u32 *) cmd, *av ); - ac--; av++; + av++; break; case TOK_COMMENT: - fill_comment(cmd, ac, av); - av += ac; - ac = 0; + fill_comment(cmd, av); + av[0]=NULL; break; case TOK_TAGGED: - if (ac > 0 && strpbrk(*av, "-,")) { + if (av[0] && strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_TAGGED)) errx(EX_DATAERR, "tagged: invalid tag" " list: %s", *av); @@ -3503,13 +3530,13 @@ read_options: TOK_TAGGED, rule_options); fill_cmd(cmd, O_TAGGED, 0, tag); } - ac--; av++; + av++; break; case TOK_FIB: NEED1("fib requires fib number"); fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0)); - ac--; av++; + av++; break; case TOK_LOOKUP: { @@ -3517,28 +3544,23 @@ read_options: char *p; int j; - if (ac < 2) - errx(EX_USAGE, "format: lookup argument tablenum[,arg]"); + if (!av[0] || !av[1]) + errx(EX_USAGE, "format: lookup argument tablenum"); cmd->opcode = O_IP_DST_LOOKUP; cmd->len |= F_INSN_SIZE(ipfw_insn) + 2; i = match_token(rule_options, *av); - for (j = 0; lookup_key[j] ; j++) { + for (j = 0; lookup_key[j] >= 0 ; j++) { if (i == lookup_key[j]) break; } - if (lookup_key[j] == 0) + if (lookup_key[j] <= 0) errx(EX_USAGE, "format: cannot lookup on %s", *av); c->d[1] = j; // i converted to option - ac--; av++; - p = strchr(*av, ','); - if (p) { - *p++ = '\0'; - c->d[0] = strtoul(p, NULL, 0); - } else { - c->d[0] = ~0; - } - cmd->arg1 = strtoul(*av, NULL, 0); - ac--; av++; + av++; + cmd->arg1 = strtoul(*av, &p, 0); + if (p && *p) + errx(EX_USAGE, "format: lookup argument tablenum"); + av++; } break; @@ -3716,6 +3738,10 @@ ipfw_flush(int force) if (c == 'N') /* user said no */ return; } + if (co.do_pipe) { + dummynet_flush(); + return; + } /* `ipfw set N flush` - is the same that `ipfw delete set N` */ if (co.use_set) { uint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24); @@ -3829,14 +3855,14 @@ ipfw_table_handler(int ac, char *av[]) } } } else if (_substrcmp(*av, "flush") == 0) { - a = is_all ? tables_max : (ent.tbl + 1); + a = is_all ? tables_max : (uint32_t)(ent.tbl + 1); do { if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); } while (++ent.tbl < a); } else if (_substrcmp(*av, "list") == 0) { - a = is_all ? tables_max : (ent.tbl + 1); + a = is_all ? tables_max : (uint32_t)(ent.tbl + 1); do { table_list(ent, is_all); } while (++ent.tbl < a);