From nobody@FreeBSD.org Sun Sep 2 09:58:48 2007 Return-Path: Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 946AB16A417 for ; Sun, 2 Sep 2007 09:58:48 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id 7697C13C45D for ; Sun, 2 Sep 2007 09:58:48 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.1/8.14.1) with ESMTP id l829wjRQ017471 for ; Sun, 2 Sep 2007 09:58:45 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.1/8.14.1/Submit) id l829wjEI017470; Sun, 2 Sep 2007 09:58:45 GMT (envelope-from nobody) Message-Id: <200709020958.l829wjEI017470@www.freebsd.org> Date: Sun, 2 Sep 2007 09:58:45 GMT From: Alter To: freebsd-gnats-submit@FreeBSD.org Subject: Ignore errors when loading ruleset from file + rule replacement command X-Send-Pr-Version: www-3.1 X-GNATS-Notify: >Number: 116009 >Category: kern >Synopsis: [ipfw] [patch] Ignore errors when loading ruleset from file + rule replacement command >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ipfw >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Sep 02 10:00:06 GMT 2007 >Closed-Date: >Last-Modified: Tue Sep 4 11:20:02 GMT 2007 >Originator: Alter >Release: 6.2-RELEASE-p5 >Organization: >Environment: FreeBSD homecat.alter.org.ua 6.2-RELEASE-p5 FreeBSD 6.2-RELEASE-p5 #0: Sat Aug 11 20:48:12 UTC 2007 root@homecat.alter.org.ua:/usr/src/sys/i386/compile/CAT_v8 i386 >Description: Sometimes it is convenient to ignore errors when loading ruleset from a file. For example if standalone rules must be replaced (or added if not exist yet) in definite order. To replace existing rules we must issue sequence of 'delete' and 'add' commands. If for some reason target rule doesn't exists (temporary or mistakenly removed, not generated due to bug in script on previous attempt, etc.), ruleset loading stops. Another case - when we need to re-apply subset of rules without 'flush' of entire ruleset. Running 'ipfw' multiple times (one call for each rule) is not good for system performance. Also, there is inconvenience inside 'ipfw.c': many functions calls 'errx()' when find some error instead of reporting error status to caller. This makes some difficulty in implementation of 'ignore errors' mode. >How-To-Repeat: >Fix: Attached patch adds '-i' switch to ipfw command, which turns ipfw into 'ignore errors' mode. In this mode all syntax errors in rule cause 'ipfw' to abort processing of current rule and start processing of the next one. '-i' switch can be used both in command line and inside ruleset file for particular rules. Patch replaces calls of 'errx()' to wrapping function. Normally, this function calls 'errx()'. But if 'ignore errors' mode is on, it calls 'warnx()' and returns error code back to caller. Implemented error handling in such cases and returning error status necessary places. Also, this patch adds 'replace' command. It can be used instead of pair -i delete NNN add NNN Patch attached with submission follows: *** ipfw2.orig.c Sat Sep 1 11:04:54 2007 --- ipfw2.c Sat Sep 1 22:09:31 2007 *************** *** 73,124 **** show_sets, /* display rule sets */ test_only, /* only check syntax */ comment_only, /* only print action and comment */ ! verbose; #define IP_MASK_ALL 0xffffffff - /* - * the following macro returns an error message if we run out of - * arguments. - */ - #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} ! #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ ! if (!ac) \ ! errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ ! if (_substrcmp(*av, "tablearg") == 0) { \ ! arg = IP_FW_TABLEARG; \ ! break; \ ! } \ ! \ ! { \ ! long val; \ ! char *end; \ ! \ ! val = strtol(*av, &end, 10); \ ! \ ! if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) \ ! errx(EX_DATAERR, "%s: invalid argument: %s", \ ! match_value(s_x, tok), *av); \ ! \ ! if (errno == ERANGE || val < min || val > 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) \ ! errx(EX_DATAERR, "%s: illegal argument value: %s", \ ! match_value(s_x, tok), *av); \ ! arg = val; \ ! } \ ! } while (0) - #define PRINT_UINT_ARG(str, arg) do { \ - if (str != NULL) \ - printf("%s",str); \ - if (arg == IP_FW_TABLEARG) \ - printf("tablearg"); \ - else \ - printf("%u", (uint32_t)arg); \ - } while (0) /* * _s_x is a structure that stores a string <-> token pairs, used in --- 73,85 ---- show_sets, /* display rule sets */ test_only, /* only check syntax */ comment_only, /* only print action and comment */ ! verbose, ! ignore_errors; #define IP_MASK_ALL 0xffffffff ! #define EX_BREAK 1 /* * _s_x is a structure that stores a string <-> token pairs, used in *************** *** 133,138 **** --- 94,194 ---- int x; }; + /* Some forward declarations */ + static char const * + match_value(struct _s_x *p, int value); + + static int + _substrcmp(const char *str1, const char* str2); + + int my_errx(int code, char* fmt, ...) + { + va_list args; + va_start(args, fmt); + + if(!ignore_errors) + verrx(code, fmt, args); + + vwarnx(fmt, args); + + va_end(args); + return code; + } + + int my_err(int code, char* fmt, ...) + { + va_list args; + va_start(args, fmt); + + if(!ignore_errors) + verr(code, fmt, args); + + vwarn(fmt, args); + + va_end(args); + return code; + } + + /* + * the following macro returns an error message if we run out of + * arguments. + */ + #define NEED1(msg) {if (!ac) { return my_errx(EX_USAGE, msg); } } + + int + _GET_UINT_ARG(char *av[], uint16_t* arg, long min, long max, int tok, struct _s_x* s_x) + { + if (_substrcmp(*av, "tablearg") == 0) { + (*arg) = IP_FW_TABLEARG; + return EX_BREAK; + } + + { + long val; + char *end; + + val = strtol(*av, &end, 10); + + if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) { + return my_errx(EX_DATAERR, "%s: invalid argument: %s", + match_value(s_x, tok), *av); + } + + if (errno == ERANGE || val < min || val > max) { + return my_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) { + return my_errx(EX_DATAERR, "%s: illegal argument value: %s", + match_value(s_x, tok), *av); + } + (*arg) = val; + } + return EX_OK; + } + + #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ + int r; \ + if (!ac) { \ + return my_errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ + } \ + r = _GET_UINT_ARG(av, &arg, min, max, tok, s_x); \ + if(r == EX_BREAK) \ + break; \ + if(r != EX_OK) \ + return r; \ + } while(0) + + #define PRINT_UINT_ARG(str, arg) do { \ + if (str != NULL) \ + printf("%s",str); \ + if (arg == IP_FW_TABLEARG) \ + printf("tablearg"); \ + else \ + printf("%u", (uint32_t)arg); \ + } while (0) + static struct _s_x f_tcpflags[] = { { "syn", TH_SYN }, { "fin", TH_FIN }, *************** *** 488,495 **** if (s == -1) s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); ! if (s < 0) ! err(EX_UNAVAILABLE, "socket"); if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || --- 544,553 ---- if (s == -1) s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); ! if (s < 0) { ! my_errx(EX_UNAVAILABLE, "socket"); ! return -1; ! } if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || *************** *** 724,746 **** static TAILQ_HEAD(, pf_altq) altq_entries = TAILQ_HEAD_INITIALIZER(altq_entries); ! static void altq_set_enabled(int enabled) { int pffd; pffd = open("/dev/pf", O_RDWR); ! if (pffd == -1) ! err(EX_UNAVAILABLE, ! "altq support opening pf(4) control device"); if (enabled) { ! if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST) ! err(EX_UNAVAILABLE, "enabling altq"); } else { ! if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT) ! err(EX_UNAVAILABLE, "disabling altq"); } close(pffd); } static void --- 782,807 ---- static TAILQ_HEAD(, pf_altq) altq_entries = TAILQ_HEAD_INITIALIZER(altq_entries); ! static int altq_set_enabled(int enabled) { int pffd; pffd = open("/dev/pf", O_RDWR); ! if (pffd == -1) { ! return my_err(EX_UNAVAILABLE, "altq support opening pf(4) control device"); ! } if (enabled) { ! if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST) { ! return my_err(EX_UNAVAILABLE, "enabling altq"); ! } } else { ! if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT) { ! return my_err(EX_UNAVAILABLE, "disabling altq"); ! } } close(pffd); + return EX_OK; } static void *************** *** 776,783 **** if (pfioc.altq.qid == 0) continue; altq = malloc(sizeof(*altq)); ! if (altq == NULL) err(EX_OSERR, "malloc"); *altq = pfioc.altq; TAILQ_INSERT_TAIL(&altq_entries, altq, entries); } --- 837,845 ---- if (pfioc.altq.qid == 0) continue; altq = malloc(sizeof(*altq)); ! if (altq == NULL) { err(EX_OSERR, "malloc"); + } *altq = pfioc.altq; TAILQ_INSERT_TAIL(&altq_entries, altq, entries); } *************** *** 785,791 **** } static u_int32_t ! altq_name_to_qid(const char *name) { struct pf_altq *altq; --- 847,853 ---- } static u_int32_t ! altq_name_to_qid(const char *name, u_int32_t *qid) { struct pf_altq *altq; *************** *** 793,801 **** TAILQ_FOREACH(altq, &altq_entries, entries) if (strcmp(name, altq->qname) == 0) break; ! if (altq == NULL) ! errx(EX_DATAERR, "altq has no queue named `%s'", name); ! return altq->qid; } static const char * --- 855,866 ---- TAILQ_FOREACH(altq, &altq_entries, entries) if (strcmp(name, altq->qname) == 0) break; ! if (altq == NULL) { ! warn("altq has no queue named `%s'", name); ! return EX_DATAERR; ! } ! (*qid) = altq->qid; ! return EX_OK; } static const char * *************** *** 812,821 **** return altq->qname; } ! static void fill_altq_qid(u_int32_t *qid, const char *av) { ! *qid = altq_name_to_qid(av); } /* --- 877,886 ---- return altq->qname; } ! static int fill_altq_qid(u_int32_t *qid, const char *av) { ! return altq_name_to_qid(av, qid); } /* *************** *** 858,865 **** av = s + 1; } if (i > 0) { ! if (i + 1 > F_LEN_MASK) ! errx(EX_DATAERR, "too many ports/ranges\n"); cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ } return (i); --- 923,932 ---- av = s + 1; } if (i > 0) { ! if (i + 1 > F_LEN_MASK) { ! my_errx(EX_DATAERR, "too many ports/ranges\n"); ! return 0; ! } cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ } return (i); *************** *** 885,891 **** { NULL, 0 } }; ! static void fill_reject_code(u_short *codep, char *str) { int val; --- 952,958 ---- { NULL, 0 } }; ! static int fill_reject_code(u_short *codep, char *str) { int val; *************** *** 894,903 **** val = strtoul(str, &s, 0); if (s == str || *s != '\0' || val >= 0x100) val = match_token(icmpcodes, str); ! if (val < 0) ! errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); *codep = val; ! return; } static void --- 961,971 ---- val = strtoul(str, &s, 0); if (s == str || *s != '\0' || val >= 0x100) val = match_token(icmpcodes, str); ! if (val < 0) { ! return my_errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); ! } *codep = val; ! return EX_OK; } static void *************** *** 919,925 **** { NULL, 0 } }; ! static void fill_unreach6_code(u_short *codep, char *str) { int val; --- 987,993 ---- { NULL, 0 } }; ! static int fill_unreach6_code(u_short *codep, char *str) { int val; *************** *** 928,937 **** val = strtoul(str, &s, 0); if (s == str || *s != '\0' || val >= 0x100) val = match_token(icmp6codes, str); ! if (val < 0) ! errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); *codep = val; ! return; } static void --- 996,1006 ---- val = strtoul(str, &s, 0); if (s == str || *s != '\0' || val >= 0x100) val = match_token(icmp6codes, str); ! if (val < 0) { ! return my_errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); ! } *codep = val; ! return EX_OK; } static void *************** *** 1108,1114 **** } } ! static void fill_icmptypes(ipfw_insn_u32 *cmd, char *av) { uint8_t type; --- 1177,1183 ---- } } ! static int fill_icmptypes(ipfw_insn_u32 *cmd, char *av) { uint8_t type; *************** *** 1120,1135 **** type = strtoul(av, &av, 0); ! if (*av != ',' && *av != '\0') ! errx(EX_DATAERR, "invalid ICMP type"); ! if (type > 31) ! errx(EX_DATAERR, "ICMP type out of range"); cmd->d[0] |= 1 << type; } cmd->o.opcode = O_ICMPTYPE; cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); } static void --- 1189,1207 ---- type = strtoul(av, &av, 0); ! if (*av != ',' && *av != '\0') { ! return my_errx(EX_DATAERR, "invalid ICMP type"); ! } ! if (type > 31) { ! return my_errx(EX_DATAERR, "ICMP type out of range"); ! } cmd->d[0] |= 1 << type; } cmd->o.opcode = O_ICMPTYPE; cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); + return EX_OK; } static void *************** *** 1201,1207 **** } } ! static void fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) { uint8_t type; --- 1273,1279 ---- } } ! static int fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) { uint8_t type; *************** *** 1211,1230 **** if (*av == ',') av++; type = strtoul(av, &av, 0); ! if (*av != ',' && *av != '\0') ! errx(EX_DATAERR, "invalid ICMP6 type"); /* * XXX: shouldn't this be 0xFF? I can't see any reason why * we shouldn't be able to filter all possiable values * regardless of the ability of the rest of the kernel to do * anything useful with them. */ ! if (type > ICMP6_MAXTYPE) ! errx(EX_DATAERR, "ICMP6 type out of range"); cmd->d[type / 32] |= ( 1 << (type % 32)); } cmd->o.opcode = O_ICMP6TYPE; cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); } --- 1283,1305 ---- if (*av == ',') av++; type = strtoul(av, &av, 0); ! if (*av != ',' && *av != '\0') { ! return my_errx(EX_DATAERR, "invalid ICMP6 type"); ! } /* * XXX: shouldn't this be 0xFF? I can't see any reason why * we shouldn't be able to filter all possiable values * regardless of the ability of the rest of the kernel to do * anything useful with them. */ ! if (type > ICMP6_MAXTYPE) { ! return my_errx(EX_DATAERR, "ICMP6 type out of range"); ! } cmd->d[type / 32] |= ( 1 << (type % 32)); } cmd->o.opcode = O_ICMP6TYPE; cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); + return EX_OK; } *************** *** 1307,1313 **** break; default: ! errx( EX_DATAERR, "invalid option for ipv6 exten header" ); break; } } --- 1382,1389 ---- break; default: ! my_errx( EX_DATAERR, "invalid option for ipv6 exten header" ); ! return -1; break; } } *************** *** 2308,2314 **** * ipfw set move X to Y * ipfw set move rule X to Y */ ! static void sets_handler(int ac, char *av[]) { uint32_t set_disable, masks[2]; --- 2384,2390 ---- * ipfw set move X to Y * ipfw set move rule X to Y */ ! static int sets_handler(int ac, char *av[]) { uint32_t set_disable, masks[2]; *************** *** 2319,2335 **** ac--; av++; ! if (!ac) ! errx(EX_USAGE, "set needs command"); if (_substrcmp(*av, "show") == 0) { void *data; char const *msg; nbytes = sizeof(struct ip_fw); ! if ((data = calloc(1, nbytes)) == NULL) ! err(EX_OSERR, "calloc"); ! 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)); --- 2395,2415 ---- ac--; av++; ! if (!ac) { ! warn("set needs command"); ! return EX_USAGE; ! } if (_substrcmp(*av, "show") == 0) { void *data; char const *msg; nbytes = sizeof(struct ip_fw); ! if ((data = calloc(1, nbytes)) == NULL) { ! my_err(EX_OSERR, "calloc"); ! } ! if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) { ! my_err(EX_OSERR, "getsockopt(IP_FW_GET)"); ! } bcopy(&((struct ip_fw *)data)->next_rule, &set_disable, sizeof(set_disable)); *************** *** 2347,2360 **** printf("\n"); } else if (_substrcmp(*av, "swap") == 0) { ac--; av++; ! if (ac != 2) ! errx(EX_USAGE, "set swap needs 2 set numbers\n"); rulenum = atoi(av[0]); new_set = atoi(av[1]); ! if (!isdigit(*(av[0])) || rulenum > RESVD_SET) ! errx(EX_DATAERR, "invalid set number %s\n", av[0]); ! if (!isdigit(*(av[1])) || new_set > RESVD_SET) ! errx(EX_DATAERR, "invalid set number %s\n", av[1]); masks[0] = (4 << 24) | (new_set << 16) | (rulenum); i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); } else if (_substrcmp(*av, "move") == 0) { --- 2427,2443 ---- printf("\n"); } else if (_substrcmp(*av, "swap") == 0) { ac--; av++; ! if (ac != 2) { ! return my_errx(EX_USAGE, "set swap needs 2 set numbers\n"); ! } rulenum = atoi(av[0]); new_set = atoi(av[1]); ! if (!isdigit(*(av[0])) || rulenum > RESVD_SET) { ! return my_errx(EX_DATAERR, "invalid set number %s\n", av[0]); ! } ! if (!isdigit(*(av[1])) || new_set > RESVD_SET) { ! return my_errx(EX_DATAERR, "invalid set number %s\n", av[1]); ! } masks[0] = (4 << 24) | (new_set << 16) | (rulenum); i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); } else if (_substrcmp(*av, "move") == 0) { *************** *** 2364,2378 **** ac--; av++; } else cmd = 3; ! if (ac != 3 || _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]); if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || ! (cmd == 2 && rulenum == 65535) ) ! errx(EX_DATAERR, "invalid source number %s\n", av[0]); ! if (!isdigit(*(av[2])) || new_set > RESVD_SET) ! errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); } else if (_substrcmp(*av, "disable") == 0 || --- 2447,2464 ---- ac--; av++; } else cmd = 3; ! if (ac != 3 || _substrcmp(av[1], "to") != 0) { ! return my_errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); ! } rulenum = atoi(av[0]); new_set = atoi(av[2]); if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || ! (cmd == 2 && rulenum == 65535) ) { ! return my_errx(EX_DATAERR, "invalid source number %s\n", av[0]); ! } ! if (!isdigit(*(av[2])) || new_set > RESVD_SET) { ! return my_errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); ! } masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); } else if (_substrcmp(*av, "disable") == 0 || *************** *** 2385,2417 **** while (ac) { if (isdigit(**av)) { i = atoi(*av); ! if (i < 0 || i > RESVD_SET) ! errx(EX_DATAERR, "invalid set number %d\n", i); masks[which] |= (1< RESVD_SET) { ! return my_errx(EX_DATAERR, "invalid set number %d\n", i); + } masks[which] |= (1<o.len &= ~F_LEN_MASK; /* zero len */ if (_substrcmp(av, "any") == 0) ! return; if (_substrcmp(av, "me") == 0) { cmd->o.len |= F_INSN_SIZE(ipfw_insn); ! return; } if (strncmp(av, "table(", 6) == 0) { --- 2784,2794 ---- cmd->o.len &= ~F_LEN_MASK; /* zero len */ if (_substrcmp(av, "any") == 0) ! return EX_OK; if (_substrcmp(av, "me") == 0) { cmd->o.len |= F_INSN_SIZE(ipfw_insn); ! return EX_OK; } if (strncmp(av, "table(", 6) == 0) { *************** *** 2708,2714 **** d[0] = strtoul(p, NULL, 0); } else cmd->o.len |= F_INSN_SIZE(ipfw_insn); ! return; } while (av) { --- 2803,2809 ---- d[0] = strtoul(p, NULL, 0); } else cmd->o.len |= F_INSN_SIZE(ipfw_insn); ! return EX_OK; } while (av) { *************** *** 2727,2746 **** } else md = '\0'; ! if (lookup_host(av, (struct in_addr *)&d[0]) != 0) ! errx(EX_NOHOST, "hostname ``%s'' unknown", av); switch (md) { case ':': ! if (!inet_aton(p, (struct in_addr *)&d[1])) ! errx(EX_DATAERR, "bad netmask ``%s''", p); break; case '/': masklen = atoi(p); if (masklen == 0) d[1] = htonl(0); /* mask */ ! else if (masklen > 32) ! errx(EX_DATAERR, "bad width ``%s''", p); ! else d[1] = htonl(~0 << (32 - masklen)); break; case '{': /* no mask, assume /24 and put back the '{' */ --- 2822,2843 ---- } else md = '\0'; ! if (lookup_host(av, (struct in_addr *)&d[0]) != 0) { ! return my_errx(EX_NOHOST, "hostname ``%s'' unknown", av); ! } switch (md) { case ':': ! if (!inet_aton(p, (struct in_addr *)&d[1])) { ! return my_errx(EX_DATAERR, "bad netmask ``%s''", p); ! } break; case '/': masklen = atoi(p); if (masklen == 0) d[1] = htonl(0); /* mask */ ! else if (masklen > 32) { ! return my_errx(EX_DATAERR, "bad width ``%s''", p); ! } else d[1] = htonl(~0 << (32 - masklen)); break; case '{': /* no mask, assume /24 and put back the '{' */ *************** *** 2773,2782 **** int low, high; int i = contigmask((uint8_t *)&(d[1]), 32); ! if (len > 0) ! errx(EX_DATAERR, "address set cannot be in a list"); ! if (i < 24 || i > 31) ! errx(EX_DATAERR, "invalid set with mask %d\n", i); cmd->o.arg1 = 1<<(32-i); /* map length */ d[0] = ntohl(d[0]); /* base addr in host format */ cmd->o.opcode = O_IP_DST_SET; /* default */ --- 2870,2881 ---- int low, high; int i = contigmask((uint8_t *)&(d[1]), 32); ! if (len > 0) { ! return my_errx(EX_DATAERR, "address set cannot be in a list"); ! } ! if (i < 24 || i > 31) { ! return my_errx(EX_DATAERR, "invalid set with mask %d\n", i); ! } cmd->o.arg1 = 1<<(32-i); /* map length */ d[0] = ntohl(d[0]); /* base addr in host format */ cmd->o.opcode = O_IP_DST_SET; /* default */ *************** *** 2798,2821 **** int a = strtol(av, &s, 0); if (s == av) { /* no parameter */ ! if (*av != '}') ! errx(EX_DATAERR, "set not closed\n"); ! if (i != -1) ! errx(EX_DATAERR, "incomplete range %d-", i); break; } ! if (a < low || a > high) ! errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", a, low, high); a -= low; if (i == -1) /* no previous in range */ i = a; else { /* check that range is valid */ ! if (i > a) ! errx(EX_DATAERR, "invalid range %d-%d", i+low, a+low); ! if (*s == '-') ! errx(EX_DATAERR, "double '-' in range"); } for (; i <= a; i++) map[i/32] |= 1<<(i & 31); --- 2897,2925 ---- int a = strtol(av, &s, 0); if (s == av) { /* no parameter */ ! if (*av != '}') { ! return my_errx(EX_DATAERR, "set not closed\n"); ! } ! if (i != -1) { ! return my_errx(EX_DATAERR, "incomplete range %d-", i); ! } break; } ! if (a < low || a > high) { ! return my_errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", a, low, high); + } a -= low; if (i == -1) /* no previous in range */ i = a; else { /* check that range is valid */ ! if (i > a) { ! return my_errx(EX_DATAERR, "invalid range %d-%d", i+low, a+low); ! } ! if (*s == '-') { ! return my_errx(EX_DATAERR, "double '-' in range"); ! } } for (; i <= a; i++) map[i/32] |= 1<<(i & 31); *************** *** 2826,2832 **** break; av = s+1; } ! return; } av = p; if (av) /* then *av must be a ',' */ --- 2930,2936 ---- break; av = s+1; } ! return EX_OK; } av = p; if (av) /* then *av must be a ',' */ *************** *** 2845,2856 **** errx(EX_DATAERR, "not any never matches"); } /* else do nothing and skip this entry */ ! return; } /* A single IP can be stored in an optimized format */ if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); ! return; } len += 2; /* two words... */ d += 2; --- 2949,2960 ---- errx(EX_DATAERR, "not any never matches"); } /* else do nothing and skip this entry */ ! return EX_OK; } /* A single IP can be stored in an optimized format */ if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); ! return EX_OK; } len += 2; /* two words... */ d += 2; *************** *** 2858,2863 **** --- 2962,2968 ---- if (len + 1 > F_LEN_MASK) errx(EX_DATAERR, "address list too long"); cmd->o.len |= len+1; + return EX_OK; } *************** *** 3092,3098 **** * helper function to process a set of flags and set bits in the * appropriate masks. */ ! static void fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, struct _s_x *flags, char *p) { --- 3197,3203 ---- * helper function to process a set of flags and set bits in the * appropriate masks. */ ! static int fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, struct _s_x *flags, char *p) { *************** *** 3113,3130 **** *q++ = '\0'; val = match_token(flags, p); if (val <= 0) ! errx(EX_DATAERR, "invalid flag %s", p); *which |= (uint8_t)val; p = q; } cmd->opcode = opcode; cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); } ! static void ! delete(int ac, char *av[]) { uint32_t rulenum; struct dn_pipe p; --- 3218,3236 ---- *q++ = '\0'; val = match_token(flags, p); if (val <= 0) ! return my_errx(EX_DATAERR, "invalid flag %s", p); *which |= (uint8_t)val; p = q; } cmd->opcode = opcode; cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); + return EX_OK; } ! static int ! delete(int ac, char *av[], int replace) { uint32_t rulenum; struct dn_pipe p; *************** *** 3159,3172 **** rulenum = (i & 0xffff) | (do_set << 24); i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); if (i) { ! exitval = EX_UNAVAILABLE; ! warn("rule %u: setsockopt(IP_FW_DEL)", ! rulenum); } } } ! if (exitval != EX_OK) exit(exitval); } --- 3265,3281 ---- rulenum = (i & 0xffff) | (do_set << 24); i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); if (i) { ! if(!replace) { ! exitval = EX_UNAVAILABLE; ! warn("rule %u: setsockopt(IP_FW_DEL)", ! rulenum); ! } } } } ! if (exitval != EX_OK && !ignore_errors) exit(exitval); + return exitval; } *************** *** 3177,3183 **** * Interface names containing '*', '?', or '[' are assumed to be shell * patterns which match interfaces. */ ! static void fill_iface(ipfw_insn_if *cmd, char *arg) { cmd->name[0] = '\0'; --- 3286,3292 ---- * Interface names containing '*', '?', or '[' are assumed to be shell * patterns which match interfaces. */ ! static int fill_iface(ipfw_insn_if *cmd, char *arg) { cmd->name[0] = '\0'; *************** *** 3190,3199 **** strlcpy(cmd->name, arg, sizeof(cmd->name)); cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; } else if (!inet_aton(arg, &cmd->p.ip)) ! errx(EX_DATAERR, "bad ip address ``%s''", arg); } ! static void config_pipe(int ac, char **av) { struct dn_pipe p; --- 3299,3309 ---- strlcpy(cmd->name, arg, sizeof(cmd->name)); cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; } else if (!inet_aton(arg, &cmd->p.ip)) ! return my_errx(EX_DATAERR, "bad ip address ``%s''", arg); ! return EX_OK; } ! static int config_pipe(int ac, char **av) { struct dn_pipe p; *************** *** 3325,3331 **** goto end_mask; } if (ac < 1) ! errx(EX_USAGE, "mask: value missing"); if (*av[0] == '/') { a = strtoul(av[0]+1, &end, 0); if (pa6 == NULL) --- 3435,3441 ---- goto end_mask; } if (ac < 1) ! return my_errx(EX_USAGE, "mask: value missing"); if (*av[0] == '/') { a = strtoul(av[0]+1, &end, 0); if (pa6 == NULL) *************** *** 3336,3358 **** *p32 = a; else if (p16 != NULL) { if (a > 0xFFFF) ! errx(EX_DATAERR, "port mask must be 16 bit"); *p16 = (uint16_t)a; } else if (p20 != NULL) { if (a > 0xfffff) ! errx(EX_DATAERR, "flow_id mask must be 20 bit"); *p20 = (uint32_t)a; } else if (pa6 != NULL) { if (a < 0 || a > 128) ! errx(EX_DATAERR, "in6addr invalid mask len"); else n2mask(pa6, a); } else { if (a > 0xFF) ! errx(EX_DATAERR, "proto mask must be 8 bit"); p.fs.flow_mask.proto = (uint8_t)a; } --- 3446,3468 ---- *p32 = a; else if (p16 != NULL) { if (a > 0xFFFF) ! return my_errx(EX_DATAERR, "port mask must be 16 bit"); *p16 = (uint16_t)a; } else if (p20 != NULL) { if (a > 0xfffff) ! return my_errx(EX_DATAERR, "flow_id mask must be 20 bit"); *p20 = (uint32_t)a; } else if (pa6 != NULL) { if (a < 0 || a > 128) ! return my_errx(EX_DATAERR, "in6addr invalid mask len"); else n2mask(pa6, a); } else { if (a > 0xFF) ! return my_errx(EX_DATAERR, "proto mask must be 8 bit"); p.fs.flow_mask.proto = (uint8_t)a; } *************** *** 3375,3381 **** if ((end = strsep(&av[0], "/"))) { double w_q = strtod(end, NULL); if (w_q > 1 || w_q <= 0) ! errx(EX_DATAERR, "0 < w_q <= 1"); p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); } if ((end = strsep(&av[0], "/"))) { --- 3485,3491 ---- if ((end = strsep(&av[0], "/"))) { double w_q = strtod(end, NULL); if (w_q > 1 || w_q <= 0) ! return my_errx(EX_DATAERR, "0 < w_q <= 1"); p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); } if ((end = strsep(&av[0], "/"))) { *************** *** 3391,3397 **** if ((end = strsep(&av[0], "/"))) { double max_p = strtod(end, NULL); if (max_p > 1 || max_p <= 0) ! errx(EX_DATAERR, "0 < max_p <= 1"); p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); } ac--; av++; --- 3501,3507 ---- if ((end = strsep(&av[0], "/"))) { double max_p = strtod(end, NULL); if (max_p > 1 || max_p <= 0) ! return my_errx(EX_DATAERR, "0 < max_p <= 1"); p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); } ac--; av++; *************** *** 3404,3410 **** case TOK_BW: NEED1("bw needs bandwidth or interface\n"); if (do_pipe != 1) ! errx(EX_DATAERR, "bandwidth only valid for pipes"); /* * set clocking interface or bandwidth value */ --- 3514,3520 ---- case TOK_BW: NEED1("bw needs bandwidth or interface\n"); if (do_pipe != 1) ! return my_errx(EX_DATAERR, "bandwidth only valid for pipes"); /* * set clocking interface or bandwidth value */ *************** *** 3429,3442 **** _substrcmp2(end, "by", "bytes") == 0) p.bandwidth *= 8; if (p.bandwidth < 0) ! errx(EX_DATAERR, "bandwidth too large"); } ac--; av++; break; case TOK_DELAY: if (do_pipe != 1) ! errx(EX_DATAERR, "delay only valid for pipes"); NEED1("delay needs argument 0..10000ms\n"); p.delay = strtoul(av[0], NULL, 0); ac--; av++; --- 3539,3552 ---- _substrcmp2(end, "by", "bytes") == 0) p.bandwidth *= 8; if (p.bandwidth < 0) ! return my_errx(EX_DATAERR, "bandwidth too large"); } ac--; av++; break; case TOK_DELAY: if (do_pipe != 1) ! return my_errx(EX_DATAERR, "delay only valid for pipes"); NEED1("delay needs argument 0..10000ms\n"); p.delay = strtoul(av[0], NULL, 0); ac--; av++; *************** *** 3444,3450 **** case TOK_WEIGHT: if (do_pipe == 1) ! errx(EX_DATAERR,"weight only valid for queues"); NEED1("weight needs argument 0..100\n"); p.fs.weight = strtoul(av[0], &end, 0); ac--; av++; --- 3554,3560 ---- case TOK_WEIGHT: if (do_pipe == 1) ! return my_errx(EX_DATAERR,"weight only valid for queues"); NEED1("weight needs argument 0..100\n"); p.fs.weight = strtoul(av[0], &end, 0); ac--; av++; *************** *** 3452,3484 **** case TOK_PIPE: if (do_pipe == 1) ! errx(EX_DATAERR,"pipe only valid for queues"); NEED1("pipe needs pipe_number\n"); p.fs.parent_nr = strtoul(av[0], &end, 0); ac--; av++; break; default: ! errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); } } if (do_pipe == 1) { if (p.pipe_nr == 0) ! errx(EX_DATAERR, "pipe_nr must be > 0"); if (p.delay > 10000) ! errx(EX_DATAERR, "delay must be < 10000"); } else { /* do_pipe == 2, queue */ if (p.fs.parent_nr == 0) ! errx(EX_DATAERR, "pipe must be > 0"); if (p.fs.weight >100) ! errx(EX_DATAERR, "weight must be <= 100"); } if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { if (p.fs.qsize > 1024*1024) ! errx(EX_DATAERR, "queue size must be < 1MB"); } else { if (p.fs.qsize > 100) ! errx(EX_DATAERR, "2 <= queue size <= 100"); } if (p.fs.flags_fs & DN_IS_RED) { size_t len; --- 3562,3594 ---- case TOK_PIPE: if (do_pipe == 1) ! return my_errx(EX_DATAERR,"pipe only valid for queues"); NEED1("pipe needs pipe_number\n"); p.fs.parent_nr = strtoul(av[0], &end, 0); ac--; av++; break; default: ! return my_errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); } } if (do_pipe == 1) { if (p.pipe_nr == 0) ! return my_errx(EX_DATAERR, "pipe_nr must be > 0"); if (p.delay > 10000) ! return my_errx(EX_DATAERR, "delay must be < 10000"); } else { /* do_pipe == 2, queue */ if (p.fs.parent_nr == 0) ! return my_errx(EX_DATAERR, "pipe must be > 0"); if (p.fs.weight >100) ! return my_errx(EX_DATAERR, "weight must be <= 100"); } if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { if (p.fs.qsize > 1024*1024) ! return my_errx(EX_DATAERR, "queue size must be < 1MB"); } else { if (p.fs.qsize > 100) ! return my_errx(EX_DATAERR, "2 <= queue size <= 100"); } if (p.fs.flags_fs & DN_IS_RED) { size_t len; *************** *** 3488,3522 **** int t; if (p.fs.min_th >= p.fs.max_th) ! errx(EX_DATAERR, "min_th %d must be < than max_th %d", p.fs.min_th, p.fs.max_th); if (p.fs.max_th == 0) ! errx(EX_DATAERR, "max_th must be > 0"); len = sizeof(int); if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", &lookup_depth, &len, NULL, 0) == -1) ! errx(1, "sysctlbyname(\"%s\")", "net.inet.ip.dummynet.red_lookup_depth"); if (lookup_depth == 0) ! errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" " must be greater than zero"); len = sizeof(int); if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", &avg_pkt_size, &len, NULL, 0) == -1) ! errx(1, "sysctlbyname(\"%s\")", "net.inet.ip.dummynet.red_avg_pkt_size"); if (avg_pkt_size == 0) ! errx(EX_DATAERR, "net.inet.ip.dummynet.red_avg_pkt_size must" " be greater than zero"); len = sizeof(struct clockinfo); if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) ! errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); /* * Ticks needed for sending a medium-sized packet. --- 3598,3632 ---- int t; if (p.fs.min_th >= p.fs.max_th) ! return my_errx(EX_DATAERR, "min_th %d must be < than max_th %d", p.fs.min_th, p.fs.max_th); if (p.fs.max_th == 0) ! return my_errx(EX_DATAERR, "max_th must be > 0"); len = sizeof(int); if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", &lookup_depth, &len, NULL, 0) == -1) ! return my_errx(1, "sysctlbyname(\"%s\")", "net.inet.ip.dummynet.red_lookup_depth"); if (lookup_depth == 0) ! return my_errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" " must be greater than zero"); len = sizeof(int); if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", &avg_pkt_size, &len, NULL, 0) == -1) ! return my_errx(1, "sysctlbyname(\"%s\")", "net.inet.ip.dummynet.red_avg_pkt_size"); if (avg_pkt_size == 0) ! return my_errx(EX_DATAERR, "net.inet.ip.dummynet.red_avg_pkt_size must" " be greater than zero"); len = sizeof(struct clockinfo); if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) ! return my_errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); /* * Ticks needed for sending a medium-sized packet. *************** *** 3549,3555 **** } i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); if (i) ! err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); } static void --- 3659,3666 ---- } i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); if (i) ! return my_err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); ! return EX_OK; } static void *************** *** 3601,3607 **** /* * Takes arguments and copies them into a comment */ ! static void fill_comment(ipfw_insn *cmd, int ac, char **av) { int i, l; --- 3712,3718 ---- /* * Takes arguments and copies them into a comment */ ! static int fill_comment(ipfw_insn *cmd, int ac, char **av) { int i, l; *************** *** 3614,3622 **** for (i = 0, l = 0; i < ac; i++) l += strlen(av[i]) + 1; if (l == 0) ! return; if (l > 84) ! errx(EX_DATAERR, "comment too long (max 80 chars)"); l = 1 + (l+3)/4; cmd->len = (cmd->len & (F_NOT | F_OR)) | l; --- 3725,3733 ---- for (i = 0, l = 0; i < ac; i++) l += strlen(av[i]) + 1; if (l == 0) ! return EX_OK; if (l > 84) ! return my_errx(EX_DATAERR, "comment too long (max 80 chars)"); l = 1 + (l+3)/4; cmd->len = (cmd->len & (F_NOT | F_OR)) | l; *************** *** 3626,3631 **** --- 3737,3743 ---- *p++ = ' '; } *(--p) = '\0'; + return EX_OK; } /* *************** *** 3640,3645 **** --- 3752,3759 ---- cmd->arg1 = arg; } + #define INV_INSN ((ipfw_insn *)(-1)) + /* * Fetch and add the MAC address and type, with masks. This generates one or * two microinstructions, and returns the pointer to the last one. *************** *** 3649,3656 **** { ipfw_insn_mac *mac; ! if (ac < 2) ! errx(EX_DATAERR, "MAC dst src"); cmd->opcode = O_MACADDR2; cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); --- 3763,3772 ---- { ipfw_insn_mac *mac; ! if (ac < 2) { ! my_errx(EX_DATAERR, "MAC dst src"); ! return INV_INSN; ! } cmd->opcode = O_MACADDR2; cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); *************** *** 3664,3671 **** static ipfw_insn * add_mactype(ipfw_insn *cmd, int ac, char *av) { ! if (ac < 1) ! 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); cmd->opcode = O_MAC_TYPE; --- 3780,3789 ---- static ipfw_insn * add_mactype(ipfw_insn *cmd, int ac, char *av) { ! if (ac < 1) { ! my_errx(EX_DATAERR, "missing MAC type"); ! return INV_INSN; ! } if (strcmp(av, "any") != 0) { /* we have a non-null type */ fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); cmd->opcode = O_MAC_TYPE; *************** *** 3738,3744 **** static ipfw_insn * add_srcip(ipfw_insn *cmd, char *av) { ! fill_ip((ipfw_insn_ip *)cmd, av); if (cmd->opcode == O_IP_DST_SET) /* set */ cmd->opcode = O_IP_SRC_SET; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ --- 3856,3863 ---- static ipfw_insn * add_srcip(ipfw_insn *cmd, char *av) { ! if(fill_ip((ipfw_insn_ip *)cmd, av) != EX_OK) ! return NULL; if (cmd->opcode == O_IP_DST_SET) /* set */ cmd->opcode = O_IP_SRC_SET; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ *************** *** 3755,3761 **** static ipfw_insn * add_dstip(ipfw_insn *cmd, char *av) { ! fill_ip((ipfw_insn_ip *)cmd, av); if (cmd->opcode == O_IP_DST_SET) /* set */ ; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ --- 3874,3881 ---- static ipfw_insn * add_dstip(ipfw_insn *cmd, char *av) { ! if(fill_ip((ipfw_insn_ip *)cmd, av) != EX_OK) ! return NULL; if (cmd->opcode == O_IP_DST_SET) /* set */ ; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ *************** *** 3846,3852 **** * various match patterns, log/altq actions, and the actual action. * */ ! static void add(int ac, char *av[]) { /* --- 3966,3972 ---- * various match patterns, log/altq actions, and the actual action. * */ ! static int add(int ac, char *av[]) { /* *************** *** 3870,3875 **** --- 3990,3996 ---- size_t len; int i; + int r; int open_par = 0; /* open parenthesis ( */ *************** *** 3898,3905 **** /* [set N] -- set number (0..RESVD_SET), optional */ if (ac > 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; } --- 4019,4028 ---- /* [set N] -- set number (0..RESVD_SET), optional */ if (ac > 1 && _substrcmp(*av, "set") == 0) { int set = strtoul(av[1], NULL, 10); ! if (set < 0 || set > RESVD_SET) { ! warn("illegal set %s", av[1]); ! return EX_DATAERR; ! } rule->set = set; av += 2; ac -= 2; } *************** *** 3909,3915 **** 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; } --- 4032,4038 ---- match_prob = strtod(av[1], NULL); if (match_prob <= 0 || match_prob > 1) ! return my_errx(EX_DATAERR, "illegal match prob. %s", av[1]); av += 2; ac -= 2; } *************** *** 3951,3964 **** case TOK_UNREACH: action->opcode = O_REJECT; NEED1("missing reject code"); ! fill_reject_code(&action->arg1, *av); ac--; av++; break; case TOK_UNREACH6: action->opcode = O_UNREACH6; NEED1("missing unreach code"); ! fill_unreach6_code(&action->arg1, *av); ac--; av++; break; --- 4074,4093 ---- case TOK_UNREACH: action->opcode = O_REJECT; NEED1("missing reject code"); ! r = fill_reject_code(&action->arg1, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; break; case TOK_UNREACH6: action->opcode = O_UNREACH6; NEED1("missing unreach code"); ! r = fill_unreach6_code(&action->arg1, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; break; *************** *** 3990,4000 **** action->opcode = O_TEE; chkarg: if (!ac) ! errx(EX_USAGE, "missing argument for %s", *(av - 1)); if (isdigit(**av)) { action->arg1 = strtoul(*av, NULL, 10); if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) ! errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); } else if (_substrcmp(*av, TABLEARG) == 0) { action->arg1 = IP_FW_TABLEARG; --- 4119,4129 ---- action->opcode = O_TEE; chkarg: if (!ac) ! return my_errx(EX_USAGE, "missing argument for %s", *(av - 1)); if (isdigit(**av)) { action->arg1 = strtoul(*av, NULL, 10); if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) ! return my_errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); } else if (_substrcmp(*av, TABLEARG) == 0) { action->arg1 = IP_FW_TABLEARG; *************** *** 4005,4013 **** if (s != NULL) action->arg1 = ntohs(s->s_port); else ! errx(EX_DATAERR, "illegal divert/tee port"); } else ! errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); ac--; av++; break; --- 4134,4142 ---- if (s != NULL) action->arg1 = ntohs(s->s_port); else ! return my_errx(EX_DATAERR, "illegal divert/tee port"); } else ! return my_errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); ac--; av++; break; *************** *** 4033,4039 **** *(s++) = '\0'; i = strtoport(s, &end, 0 /* base */, 0 /* proto */); if (s == end) ! errx(EX_DATAERR, "illegal forwarding port ``%s''", s); p->sa.sin_port = (u_short)i; } --- 4162,4168 ---- *(s++) = '\0'; i = strtoport(s, &end, 0 /* base */, 0 /* proto */); if (s == end) ! return my_errx(EX_DATAERR, "illegal forwarding port ``%s''", s); p->sa.sin_port = (u_short)i; } *************** *** 4049,4055 **** break; default: ! errx(EX_DATAERR, "invalid action %s\n", av[-1]); } action = next_cmd(action); --- 4178,4184 ---- break; default: ! return my_errx(EX_DATAERR, "invalid action %s\n", av[-1]); } action = next_cmd(action); *************** *** 4069,4075 **** int l; if (have_log) ! errx(EX_DATAERR, "log cannot be specified more than once"); have_log = (ipfw_insn *)c; cmd->len = F_INSN_SIZE(ipfw_insn_log); --- 4198,4204 ---- int l; if (have_log) ! return my_errx(EX_DATAERR, "log cannot be specified more than once"); have_log = (ipfw_insn *)c; cmd->len = F_INSN_SIZE(ipfw_insn_log); *************** *** 4079,4085 **** NEED1("logamount requires argument"); l = atoi(*av); if (l < 0) ! errx(EX_DATAERR, "logamount must be positive"); c->max_log = l; ac--; av++; --- 4208,4214 ---- NEED1("logamount requires argument"); l = atoi(*av); if (l < 0) ! return my_errx(EX_DATAERR, "logamount must be positive"); c->max_log = l; ac--; av++; *************** *** 4087,4093 **** len = sizeof(c->max_log); if (sysctlbyname("net.inet.ip.fw.verbose_limit", &c->max_log, &len, NULL, 0) == -1) ! errx(1, "sysctlbyname(\"%s\")", "net.inet.ip.fw.verbose_limit"); } } --- 4216,4222 ---- len = sizeof(c->max_log); if (sysctlbyname("net.inet.ip.fw.verbose_limit", &c->max_log, &len, NULL, 0) == -1) ! return my_errx(1, "sysctlbyname(\"%s\")", "net.inet.ip.fw.verbose_limit"); } } *************** *** 4099,4110 **** NEED1("missing altq queue name"); if (have_altq) ! errx(EX_DATAERR, "altq cannot be specified more than once"); have_altq = (ipfw_insn *)a; cmd->len = F_INSN_SIZE(ipfw_insn_altq); cmd->opcode = O_ALTQ; ! fill_altq_qid(&a->qid, *av); ac--; av++; } break; --- 4228,4242 ---- NEED1("missing altq queue name"); if (have_altq) ! return my_errx(EX_DATAERR, "altq cannot be specified more than once"); have_altq = (ipfw_insn *)a; cmd->len = F_INSN_SIZE(ipfw_insn_altq); cmd->opcode = O_ALTQ; ! r = fill_altq_qid(&a->qid, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; } break; *************** *** 4114,4120 **** uint16_t tag; if (have_tag) ! errx(EX_USAGE, "tag and untag cannot be " "specified more than once"); GET_UINT_ARG(tag, 1, 65534, i, rule_action_params); have_tag = cmd; --- 4246,4252 ---- uint16_t tag; if (have_tag) ! return my_errx(EX_USAGE, "tag and untag cannot be " "specified more than once"); GET_UINT_ARG(tag, 1, 65534, i, rule_action_params); have_tag = cmd; *************** *** 4124,4130 **** } default: ! abort(); } cmd = next_cmd(cmd); } --- 4256,4263 ---- } default: ! //abort(); ! return EX_SOFTWARE; } cmd = next_cmd(cmd); } *************** *** 4135,4141 **** #define OR_START(target) \ if (ac && (*av[0] == '(' || *av[0] == '{')) { \ if (open_par) \ ! errx(EX_USAGE, "nested \"(\" not allowed\n"); \ prev = NULL; \ open_par = 1; \ if ( (av[0])[1] == '\0') { \ --- 4268,4274 ---- #define OR_START(target) \ if (ac && (*av[0] == '(' || *av[0] == '{')) { \ if (open_par) \ ! return my_errx(EX_USAGE, "nested \"(\" not allowed\n"); \ prev = NULL; \ open_par = 1; \ if ( (av[0])[1] == '\0') { \ *************** *** 4155,4167 **** open_par = 0; \ ac--; av++; \ } else \ ! errx(EX_USAGE, "missing \")\"\n"); \ } #define NOT_BLOCK \ if (ac && _substrcmp(*av, "not") == 0) { \ if (cmd->len & F_NOT) \ ! errx(EX_USAGE, "double \"not\" not allowed\n"); \ cmd->len |= F_NOT; \ ac--; av++; \ } --- 4288,4300 ---- open_par = 0; \ ac--; av++; \ } else \ ! return my_errx(EX_USAGE, "missing \")\"\n"); \ } #define NOT_BLOCK \ if (ac && _substrcmp(*av, "not") == 0) { \ if (cmd->len & F_NOT) \ ! return my_errx(EX_USAGE, "double \"not\" not allowed\n"); \ cmd->len |= F_NOT; \ ac--; av++; \ } *************** *** 4169,4175 **** #define OR_BLOCK(target) \ if (ac && _substrcmp(*av, "or") == 0) { \ if (prev == NULL || open_par == 0) \ ! errx(EX_DATAERR, "invalid OR block"); \ prev->len |= F_OR; \ ac--; av++; \ goto target; \ --- 4302,4308 ---- #define OR_BLOCK(target) \ if (ac && _substrcmp(*av, "or") == 0) { \ if (prev == NULL || open_par == 0) \ ! return my_errx(EX_DATAERR, "invalid OR block"); \ prev->len |= F_OR; \ ac--; av++; \ goto target; \ *************** *** 4188,4201 **** 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 */ cmd = next_cmd(cmd); ac -= 2; av += 2; /* dst-mac and src-mac */ NOT_BLOCK; NEED1("missing mac type"); ! if (add_mactype(cmd, ac, av[0])) cmd = next_cmd(cmd); ac--; av++; /* any or mac-type */ goto read_options; } --- 4321,4345 ---- NEED1("missing protocol"); if (_substrcmp(*av, "MAC") == 0 || _substrcmp(*av, "mac") == 0) { + + ipfw_insn * insn; + ac--; av++; /* the "MAC" keyword */ ! insn = add_mac(cmd, ac, av); /* exits in case of errors if ignore_errors=0 */ ! if(insn == INV_INSN || !insn) { ! return EX_DATAERR; ! } cmd = next_cmd(cmd); ac -= 2; av += 2; /* dst-mac and src-mac */ NOT_BLOCK; NEED1("missing mac type"); ! insn = add_mactype(cmd, ac, av[0]); ! if(insn == INV_INSN) { ! return EX_DATAERR; ! } ! if(insn) { cmd = next_cmd(cmd); + } ac--; av++; /* any or mac-type */ goto read_options; } *************** *** 4214,4220 **** cmd = next_cmd(cmd); } } else if (first_cmd != cmd) { ! errx(EX_DATAERR, "invalid protocol ``%s''", *av); } else goto read_options; OR_BLOCK(get_proto); --- 4358,4364 ---- cmd = next_cmd(cmd); } } else if (first_cmd != cmd) { ! return my_errx(EX_DATAERR, "invalid protocol ``%s''", *av); } else goto read_options; OR_BLOCK(get_proto); *************** *** 4223,4229 **** * "from", mandatory */ if (!ac || _substrcmp(*av, "from") != 0) ! errx(EX_USAGE, "missing ``from''"); ac--; av++; /* --- 4367,4373 ---- * "from", mandatory */ if (!ac || _substrcmp(*av, "from") != 0) ! return my_errx(EX_USAGE, "missing ``from''"); ac--; av++; /* *************** *** 4239,4245 **** cmd = next_cmd(cmd); } } else ! errx(EX_USAGE, "bad source address %s", *av); OR_BLOCK(source_ip); /* --- 4383,4389 ---- cmd = next_cmd(cmd); } } else ! return my_errx(EX_USAGE, "bad source address %s", *av); OR_BLOCK(source_ip); /* *************** *** 4259,4265 **** * "to", mandatory */ if (!ac || _substrcmp(*av, "to") != 0) ! errx(EX_USAGE, "missing ``to''"); av++; ac--; /* --- 4403,4409 ---- * "to", mandatory */ if (!ac || _substrcmp(*av, "to") != 0) ! return my_errx(EX_USAGE, "missing ``to''"); av++; ac--; /* *************** *** 4275,4281 **** cmd = next_cmd(cmd); } } else ! errx( EX_USAGE, "bad destination address %s", *av); OR_BLOCK(dest_ip); /* --- 4419,4425 ---- cmd = next_cmd(cmd); } } else ! return my_errx( EX_USAGE, "bad destination address %s", *av); OR_BLOCK(dest_ip); /* *************** *** 4303,4315 **** while (ac) { char *s; ipfw_insn_u32 *cmd32; /* alias for cmd */ s = *av; cmd32 = (ipfw_insn_u32 *)cmd; if (*s == '!') { /* alternate syntax for NOT */ if (cmd->len & F_NOT) ! errx(EX_USAGE, "double \"not\" not allowed\n"); cmd->len = F_NOT; s++; } --- 4447,4460 ---- while (ac) { char *s; ipfw_insn_u32 *cmd32; /* alias for cmd */ + ipfw_insn * insn; s = *av; cmd32 = (ipfw_insn_u32 *)cmd; if (*s == '!') { /* alternate syntax for NOT */ if (cmd->len & F_NOT) ! return my_errx(EX_USAGE, "double \"not\" not allowed\n"); cmd->len = F_NOT; s++; } *************** *** 4318,4342 **** switch(i) { case TOK_NOT: if (cmd->len & F_NOT) ! errx(EX_USAGE, "double \"not\" not allowed\n"); cmd->len = F_NOT; break; case TOK_OR: if (open_par == 0 || prev == NULL) ! errx(EX_USAGE, "invalid \"or\" block\n"); prev->len |= F_OR; break; case TOK_STARTBRACE: if (open_par) ! errx(EX_USAGE, "+nested \"(\" not allowed\n"); open_par = 1; break; case TOK_ENDBRACE: if (!open_par) ! errx(EX_USAGE, "+missing \")\"\n"); open_par = 0; prev = NULL; break; --- 4463,4487 ---- switch(i) { case TOK_NOT: if (cmd->len & F_NOT) ! return my_errx(EX_USAGE, "double \"not\" not allowed\n"); cmd->len = F_NOT; break; case TOK_OR: if (open_par == 0 || prev == NULL) ! return my_errx(EX_USAGE, "invalid \"or\" block\n"); prev->len |= F_OR; break; case TOK_STARTBRACE: if (open_par) ! return my_errx(EX_USAGE, "+nested \"(\" not allowed\n"); open_par = 1; break; case TOK_ENDBRACE: if (!open_par) ! return my_errx(EX_USAGE, "+missing \")\"\n"); open_par = 0; prev = NULL; break; *************** *** 4375,4381 **** case TOK_VIA: NEED1("recv, xmit, via require interface name" " or address"); ! fill_iface((ipfw_insn_if *)cmd, av[0]); ac--; av++; if (F_LEN(cmd) == 0) /* not a valid address */ break; --- 4520,4529 ---- case TOK_VIA: NEED1("recv, xmit, via require interface name" " or address"); ! r = fill_iface((ipfw_insn_if *)cmd, av[0]); ! if(r != EX_OK) ! return r; ! ac--; av++; if (F_LEN(cmd) == 0) /* not a valid address */ break; *************** *** 4389,4401 **** case TOK_ICMPTYPES: NEED1("icmptypes requires list of types"); ! fill_icmptypes((ipfw_insn_u32 *)cmd, *av); av++; ac--; break; case TOK_ICMP6TYPES: NEED1("icmptypes requires list of types"); ! fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); av++; ac--; break; --- 4537,4555 ---- case TOK_ICMPTYPES: NEED1("icmptypes requires list of types"); ! r = fill_icmptypes((ipfw_insn_u32 *)cmd, *av); ! if(r != EX_OK) ! return r; ! av++; ac--; break; case TOK_ICMP6TYPES: NEED1("icmptypes requires list of types"); ! r = fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); ! if(r != EX_OK) ! return r; ! av++; ac--; break; *************** *** 4403,4409 **** NEED1("ipttl requires TTL"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_IPTTL)) ! errx(EX_DATAERR, "invalid ipttl %s", *av); } else fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); ac--; av++; --- 4557,4563 ---- NEED1("ipttl requires TTL"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_IPTTL)) ! return my_errx(EX_DATAERR, "invalid ipttl %s", *av); } else fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); ac--; av++; *************** *** 4413,4419 **** NEED1("ipid requires id"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_IPID)) ! errx(EX_DATAERR, "invalid ipid %s", *av); } else fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); ac--; av++; --- 4567,4573 ---- NEED1("ipid requires id"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_IPID)) ! return my_errx(EX_DATAERR, "invalid ipid %s", *av); } else fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); ac--; av++; *************** *** 4423,4429 **** NEED1("iplen requires length"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_IPLEN)) ! errx(EX_DATAERR, "invalid ip len %s", *av); } else fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); ac--; av++; --- 4577,4583 ---- NEED1("iplen requires length"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_IPLEN)) ! return my_errx(EX_DATAERR, "invalid ip len %s", *av); } else fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); ac--; av++; *************** *** 4444,4456 **** case TOK_IPOPTS: NEED1("missing argument for ipoptions"); ! fill_flags(cmd, O_IPOPT, f_ipopts, *av); ac--; av++; break; case TOK_IPTOS: NEED1("missing argument for iptos"); ! fill_flags(cmd, O_IPTOS, f_iptos, *av); ac--; av++; break; --- 4598,4616 ---- case TOK_IPOPTS: NEED1("missing argument for ipoptions"); ! r = fill_flags(cmd, O_IPOPT, f_ipopts, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; break; case TOK_IPTOS: NEED1("missing argument for iptos"); ! r = fill_flags(cmd, O_IPTOS, f_iptos, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; break; *************** *** 4465,4471 **** uid = strtoul(*av, &end, 0); pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); if (pwd == NULL) ! errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); cmd32->d[0] = pwd->pw_uid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); ac--; av++; --- 4625,4631 ---- uid = strtoul(*av, &end, 0); pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); if (pwd == NULL) ! return my_errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); cmd32->d[0] = pwd->pw_uid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); ac--; av++; *************** *** 4483,4489 **** gid = strtoul(*av, &end, 0); grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); if (grp == NULL) ! errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); cmd32->d[0] = grp->gr_gid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); ac--; av++; --- 4643,4649 ---- gid = strtoul(*av, &end, 0); grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); if (grp == NULL) ! return my_errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); cmd32->d[0] = grp->gr_gid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); ac--; av++; *************** *** 4499,4505 **** cmd->opcode = O_JAIL; jid = (int)strtol(*av, &end, 0); if (jid < 0 || *end != '\0') ! errx(EX_DATAERR, "jail requires prison ID"); cmd32->d[0] = (uint32_t)jid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); ac--; av++; --- 4659,4665 ---- cmd->opcode = O_JAIL; jid = (int)strtol(*av, &end, 0); if (jid < 0 || *end != '\0') ! return my_errx(EX_DATAERR, "jail requires prison ID"); cmd32->d[0] = (uint32_t)jid; cmd->len |= F_INSN_SIZE(ipfw_insn_u32); ac--; av++; *************** *** 4519,4525 **** NEED1("tcpdatalen requires length"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) ! errx(EX_DATAERR, "invalid tcpdata len %s", *av); } else fill_cmd(cmd, O_TCPDATALEN, 0, strtoul(*av, NULL, 0)); --- 4679,4685 ---- NEED1("tcpdatalen requires length"); if (strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) ! return my_errx(EX_DATAERR, "invalid tcpdata len %s", *av); } else fill_cmd(cmd, O_TCPDATALEN, 0, strtoul(*av, NULL, 0)); *************** *** 4528,4534 **** case TOK_TCPOPTS: NEED1("missing argument for tcpoptions"); ! fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); ac--; av++; break; --- 4688,4697 ---- case TOK_TCPOPTS: NEED1("missing argument for tcpoptions"); ! r = fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; break; *************** *** 4551,4566 **** case TOK_TCPFLAGS: NEED1("missing argument for tcpflags"); cmd->opcode = O_TCPFLAGS; ! fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); ac--; av++; break; case TOK_KEEPSTATE: if (open_par) ! errx(EX_USAGE, "keep-state cannot be part " "of an or block"); if (have_state) ! errx(EX_USAGE, "only one of keep-state " "and limit is allowed"); have_state = cmd; fill_cmd(cmd, O_KEEP_STATE, 0, 0); --- 4714,4732 ---- case TOK_TCPFLAGS: NEED1("missing argument for tcpflags"); cmd->opcode = O_TCPFLAGS; ! r = fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); ! if(r != EX_OK) ! return r; ! ac--; av++; break; case TOK_KEEPSTATE: if (open_par) ! return my_errx(EX_USAGE, "keep-state cannot be part " "of an or block"); if (have_state) ! return my_errx(EX_USAGE, "only one of keep-state " "and limit is allowed"); have_state = cmd; fill_cmd(cmd, O_KEEP_STATE, 0, 0); *************** *** 4571,4580 **** int val; if (open_par) ! errx(EX_USAGE, "limit cannot be part of an or block"); if (have_state) ! errx(EX_USAGE, "only one of keep-state and" "limit is allowed"); have_state = cmd; --- 4737,4746 ---- int val; if (open_par) ! return my_errx(EX_USAGE, "limit cannot be part of an or block"); if (have_state) ! return my_errx(EX_USAGE, "only one of keep-state and" "limit is allowed"); have_state = cmd; *************** *** 4590,4596 **** } if (c->limit_mask == 0) ! errx(EX_USAGE, "limit: missing limit mask"); GET_UINT_ARG(c->conn_limit, 1, 65534, TOK_LIMIT, rule_options); --- 4756,4762 ---- } if (c->limit_mask == 0) ! return my_errx(EX_USAGE, "limit: missing limit mask"); GET_UINT_ARG(c->conn_limit, 1, 65534, TOK_LIMIT, rule_options); *************** *** 4604,4610 **** if (add_proto(cmd, *av, &proto)) { ac--; av++; } else ! errx(EX_DATAERR, "invalid protocol ``%s''", *av); break; --- 4770,4776 ---- if (add_proto(cmd, *av, &proto)) { ac--; av++; } else ! return my_errx(EX_DATAERR, "invalid protocol ``%s''", *av); break; *************** *** 4642,4648 **** add_ports(cmd, *av, proto, O_IP_SRCPORT)) { ac--; av++; } else ! errx(EX_DATAERR, "invalid source port %s", *av); break; case TOK_DSTPORT: --- 4808,4814 ---- add_ports(cmd, *av, proto, O_IP_SRCPORT)) { ac--; av++; } else ! return my_errx(EX_DATAERR, "invalid source port %s", *av); break; case TOK_DSTPORT: *************** *** 4651,4670 **** add_ports(cmd, *av, proto, O_IP_DSTPORT)) { ac--; av++; } else ! errx(EX_DATAERR, "invalid destination port %s", *av); break; case TOK_MAC: ! if (add_mac(cmd, ac, av)) { ac -= 2; av += 2; } break; case TOK_MACTYPE: NEED1("missing mac type"); ! if (!add_mactype(cmd, ac, *av)) ! errx(EX_DATAERR, "invalid mac type %s", *av); ac--; av++; break; --- 4817,4842 ---- add_ports(cmd, *av, proto, O_IP_DSTPORT)) { ac--; av++; } else ! return my_errx(EX_DATAERR, "invalid destination port %s", *av); break; case TOK_MAC: ! insn = add_mac(cmd, ac, av); ! if(insn == INV_INSN) { ! return EX_DATAERR; ! } ! if(insn) { ac -= 2; av += 2; } break; case TOK_MACTYPE: NEED1("missing mac type"); ! insn = add_mactype(cmd, ac, *av); ! if(insn == INV_INSN || !insn) { ! return my_errx(EX_DATAERR, "invalid mac type %s", *av); ! } ac--; av++; break; *************** *** 4693,4712 **** break; case TOK_EXT6HDR: ! fill_ext6hdr( cmd, *av ); ac--; av++; break; case TOK_FLOWID: if (proto != IPPROTO_IPV6 ) ! errx( EX_USAGE, "flow-id filter is active " "only for ipv6 protocol\n"); fill_flow6( (ipfw_insn_u32 *) cmd, *av ); ac--; av++; break; case TOK_COMMENT: ! fill_comment(cmd, ac, av); av += ac; ac = 0; break; --- 4865,4888 ---- break; case TOK_EXT6HDR: ! r = fill_ext6hdr( cmd, *av ); ! if(r == -1) ! return EX_DATAERR; ac--; av++; break; case TOK_FLOWID: if (proto != IPPROTO_IPV6 ) ! return my_errx( EX_USAGE, "flow-id filter is active " "only for ipv6 protocol\n"); fill_flow6( (ipfw_insn_u32 *) cmd, *av ); ac--; av++; break; case TOK_COMMENT: ! r = fill_comment(cmd, ac, av); ! if(r != EX_OK) ! return r; av += ac; ac = 0; break; *************** *** 4714,4720 **** case TOK_TAGGED: if (ac > 0 && strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_TAGGED)) ! errx(EX_DATAERR, "tagged: invalid tag" " list: %s", *av); } else { --- 4890,4896 ---- case TOK_TAGGED: if (ac > 0 && strpbrk(*av, "-,")) { if (!add_ports(cmd, *av, 0, O_TAGGED)) ! return my_errx(EX_DATAERR, "tagged: invalid tag" " list: %s", *av); } else { *************** *** 4728,4734 **** break; default: ! errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } if (F_LEN(cmd) > 0) { /* prepare to advance */ prev = cmd; --- 4904,4910 ---- break; default: ! return my_errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } if (F_LEN(cmd) > 0) { /* prepare to advance */ prev = cmd; *************** *** 4821,4833 **** rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); i = (char *)dst - (char *)rule; ! if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) ! err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); if (!do_quiet) show_ipfw(rule, 0, 0); } ! static void zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) { int rulenum; --- 4997,5013 ---- rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); i = (char *)dst - (char *)rule; ! if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) { ! warn("getsockopt(%s)", "IP_FW_ADD"); ! return EX_UNAVAILABLE; ! } if (!do_quiet) show_ipfw(rule, 0, 0); + + return EX_OK; } ! static int zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) { int rulenum; *************** *** 4839,4850 **** if (!ac) { /* clear all entries */ if (do_cmd(optname, NULL, 0) < 0) ! err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); if (!do_quiet) printf("%s.\n", optname == IP_FW_ZERO ? "Accounting cleared":"Logging counts reset"); ! return; } while (ac) { --- 5019,5030 ---- if (!ac) { /* clear all entries */ if (do_cmd(optname, NULL, 0) < 0) ! return my_err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); if (!do_quiet) printf("%s.\n", optname == IP_FW_ZERO ? "Accounting cleared":"Logging counts reset"); ! return EX_OK; } while (ac) { *************** *** 4862,4875 **** optname == IP_FW_ZERO ? "cleared" : "logging count reset"); } else { ! errx(EX_USAGE, "invalid rule number ``%s''", *av); } } ! if (failed != EX_OK) exit(failed); } ! static void flush(int force) { int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; --- 5042,5056 ---- optname == IP_FW_ZERO ? "cleared" : "logging count reset"); } else { ! return my_errx(EX_USAGE, "invalid rule number ``%s''", *av); } } ! if (failed != EX_OK && !ignore_errors) exit(failed); + return EX_OK; } ! static int flush(int force) { int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; *************** *** 4890,4899 **** return; } if (do_cmd(cmd, NULL, 0) < 0) ! err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", do_pipe ? "DUMMYNET" : "FW"); if (!do_quiet) printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); } /* --- 5071,5081 ---- return; } if (do_cmd(cmd, NULL, 0) < 0) ! return my_err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", do_pipe ? "DUMMYNET" : "FW"); if (!do_quiet) printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); + return EX_OK; } /* *************** *** 4916,4922 **** * ipfw table N flush * ipfw table N list */ ! static void table_handler(int ac, char *av[]) { ipfw_table_entry ent; --- 5098,5104 ---- * ipfw table N flush * ipfw table N list */ ! static int table_handler(int ac, char *av[]) { ipfw_table_entry ent; *************** *** 4931,4954 **** ent.tbl = atoi(*av); ac--; av++; } else ! errx(EX_USAGE, "table number required"); NEED1("table needs command"); if (_substrcmp(*av, "add") == 0 || _substrcmp(*av, "delete") == 0) { do_add = **av == 'a'; ac--; av++; if (!ac) ! errx(EX_USAGE, "IP address required"); p = strchr(*av, '/'); if (p) { *p++ = '\0'; ent.masklen = atoi(p); if (ent.masklen > 32) ! errx(EX_DATAERR, "bad width ``%s''", p); } else ent.masklen = 32; if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) ! errx(EX_NOHOST, "hostname ``%s'' unknown", *av); ac--; av++; if (do_add && ac) ent.value = strtoul(*av, NULL, 0); --- 5113,5136 ---- ent.tbl = atoi(*av); ac--; av++; } else ! return my_errx(EX_USAGE, "table number required"); NEED1("table needs command"); if (_substrcmp(*av, "add") == 0 || _substrcmp(*av, "delete") == 0) { do_add = **av == 'a'; ac--; av++; if (!ac) ! return my_errx(EX_USAGE, "IP address required"); p = strchr(*av, '/'); if (p) { *p++ = '\0'; ent.masklen = atoi(p); if (ent.masklen > 32) ! return my_errx(EX_DATAERR, "bad width ``%s''", p); } else ent.masklen = 32; if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) ! return my_errx(EX_NOHOST, "hostname ``%s'' unknown", *av); ac--; av++; if (do_add && ac) ent.value = strtoul(*av, NULL, 0); *************** *** 4958,4996 **** &ent, sizeof(ent)) < 0) { /* If running silent, don't bomb out on these errors. */ if (!(do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) ! err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", do_add ? "ADD" : "DEL"); /* In silent mode, react to a failed add by deleting */ if (do_add) { do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)); if (do_cmd(IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) ! err(EX_OSERR, "setsockopt(IP_FW_TABLE_ADD)"); } } } else if (_substrcmp(*av, "flush") == 0) { if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) ! err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); } else if (_substrcmp(*av, "list") == 0) { a = ent.tbl; l = sizeof(a); if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) ! err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); tbl = malloc(l); if (tbl == NULL) ! err(EX_OSERR, "malloc"); tbl->tbl = ent.tbl; if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) ! err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); for (a = 0; a < tbl->cnt; a++) { printf("%s/%u %u\n", inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), tbl->ent[a].masklen, tbl->ent[a].value); } } else ! errx(EX_USAGE, "invalid table command %s", *av); } /* --- 5140,5179 ---- &ent, sizeof(ent)) < 0) { /* If running silent, don't bomb out on these errors. */ if (!(do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) ! return my_err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", do_add ? "ADD" : "DEL"); /* In silent mode, react to a failed add by deleting */ if (do_add) { do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)); if (do_cmd(IP_FW_TABLE_ADD, &ent, sizeof(ent)) < 0) ! return my_err(EX_OSERR, "setsockopt(IP_FW_TABLE_ADD)"); } } } else if (_substrcmp(*av, "flush") == 0) { if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) ! return my_err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); } else if (_substrcmp(*av, "list") == 0) { a = ent.tbl; l = sizeof(a); if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) ! return my_err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); tbl = malloc(l); if (tbl == NULL) ! return my_err(EX_OSERR, "malloc"); tbl->tbl = ent.tbl; if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) ! return my_err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); for (a = 0; a < tbl->cnt; a++) { printf("%s/%u %u\n", inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), tbl->ent[a].masklen, tbl->ent[a].value); } } else ! return my_errx(EX_USAGE, "invalid table command %s", *av); ! return EX_OK; } /* *************** *** 5095,5101 **** save_av = av; optind = optreset = 0; ! while ((ch = getopt(ac, av, "abcdefhnNqs:STtv")) != -1) switch (ch) { case 'a': do_acct = 1; --- 5278,5284 ---- save_av = av; optind = optreset = 0; ! while ((ch = getopt(ac, av, "abcdefhinNqs:STtv")) != -1) switch (ch) { case 'a': do_acct = 1; *************** *** 5127,5132 **** --- 5310,5319 ---- help(); break; /* NOTREACHED */ + case 'i': + ignore_errors = 1; + break; + case 'n': test_only = 1; break; *************** *** 5211,5218 **** else if (do_pipe && _substrcmp(*av, "config") == 0) config_pipe(ac, av); else if (_substrcmp(*av, "delete") == 0) ! delete(ac, av); ! else if (_substrcmp(*av, "flush") == 0) flush(do_force); else if (_substrcmp(*av, "zero") == 0) zero(ac, av, IP_FW_ZERO); --- 5398,5408 ---- else if (do_pipe && _substrcmp(*av, "config") == 0) config_pipe(ac, av); else if (_substrcmp(*av, "delete") == 0) ! delete(ac, av, 0); ! else if (_substrcmp(*av, "replace") == 0) { ! delete(ac, av, 1); ! add(ac, av); ! } else if (_substrcmp(*av, "flush") == 0) flush(do_force); else if (_substrcmp(*av, "zero") == 0) zero(ac, av, IP_FW_ZERO); *************** *** 5252,5258 **** filename = av[ac-1]; ! while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { switch(c) { case 'c': do_compact = 1; --- 5447,5453 ---- filename = av[ac-1]; ! while ((c = getopt(ac, av, "cfiNnp:qS")) != -1) { switch(c) { case 'c': do_compact = 1; *************** *** 5260,5265 **** --- 5455,5464 ---- case 'f': do_force = 1; + break; + + case 'i': + ignore_errors = 1; break; case 'N': >Release-Note: >Audit-Trail: Responsible-Changed-From-To: freebsd-bugs->freebsd-ipfw Responsible-Changed-By: linimon Responsible-Changed-When: Sun Sep 2 13:36:59 UTC 2007 Responsible-Changed-Why: Over to maintainer(s). http://www.freebsd.org/cgi/query-pr.cgi?pr=116009 From: Julian Elischer To: bug-followup@FreeBSD.org, alter@alter.org.ua Cc: Subject: Re: kern/116009: [ipfw] [patch] Ignore errors when loading ruleset from file + rule replacement command Date: Tue, 04 Sep 2007 04:06:25 -0700 I added some code already last year to allow ipfw to continue on after some failures if the -q option is in use (especially delete). I certainly do agree that bombing out is a less that optimal behaviour when automatic use is required. >Unformatted: