From owner-freebsd-bugs@FreeBSD.ORG Tue Jun 5 19:50:01 2007 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id D43E316A46C for ; Tue, 5 Jun 2007 19:50:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id B646213C487 for ; Tue, 5 Jun 2007 19:50:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id l55Jo10F069192 for ; Tue, 5 Jun 2007 19:50:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id l55Jo1MN069189; Tue, 5 Jun 2007 19:50:01 GMT (envelope-from gnats) Resent-Date: Tue, 5 Jun 2007 19:50:01 GMT Resent-Message-Id: <200706051950.l55Jo1MN069189@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, "Andrey V. Elsukov" Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id C3A8F16A400; Tue, 5 Jun 2007 19:49:08 +0000 (UTC) (envelope-from bu7cher@yandex.ru) Received: from properlan.net (properlan.net [82.211.139.89]) by mx1.freebsd.org (Postfix) with ESMTP id 4CFCA13C44B; Tue, 5 Jun 2007 19:49:07 +0000 (UTC) (envelope-from bu7cher@yandex.ru) Received: from btr-nb.properlan.net ([10.0.12.48]) by properlan.net with esmtp (Exim 4.50) id 1Hveqs-0007ti-Cr; Tue, 05 Jun 2007 23:37:58 +0400 Received: by btr-nb.properlan.net (Postfix, from userid 1001) id C44DD1702C; Tue, 5 Jun 2007 23:37:52 +0400 (MSD) Message-Id: <20070605193752.C44DD1702C@btr-nb.properlan.net> Date: Tue, 5 Jun 2007 23:37:52 +0400 (MSD) From: "Andrey V. Elsukov" To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: julian@FreeBSD.org Subject: kern/113388: [ipfw][patch] Addition actions with rules within specified set's X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: "Andrey V. Elsukov" List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Jun 2007 19:50:01 -0000 >Number: 113388 >Category: kern >Synopsis: [ipfw][patch] Addition actions with rules within specified set's >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Tue Jun 05 19:50:01 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Andrey V. Elsukov >Release: FreeBSD 7.0-CURRENT i386 >Organization: >Environment: 7.0-CURRENT >Description: This patch extends a current actions that can be applied to rules from a specified sets. 1. List rules only from specified set: # ipfw set 3 show # ipfw set 19 list 2. Delete rules from specified set: # ipfw set 9 delete 100 200 300 3. Flush rules from specified set: # ipfw set 4 flush the old way not removed: # ipfw delete set 4 4. Reset rule counters: # ipfw set 1 zero # ipfw set 3 resetlog 500 >How-To-Repeat: >Fix: --- sets_patch.txt begins here --- --- sys/netinet/ip_fw2.c.orig Tue Jun 5 16:20:07 2007 +++ sys/netinet/ip_fw2.c Tue Jun 5 16:06:17 2007 @@ -3878,6 +3878,7 @@ * 2 move rules with given number to new set * 3 move rules with given set number to new set * 4 swap sets with given numbers + * 5 delete rules with given number and with given set number */ static int del_entry(struct ip_fw_chain *chain, u_int32_t arg) @@ -3890,16 +3891,14 @@ cmd = (arg >> 24) & 0xff; new_set = (arg >> 16) & 0xff; - if (cmd > 4) - return EINVAL; - if (new_set > RESVD_SET) - return EINVAL; - if (cmd == 0 || cmd == 2) { + if (cmd > 5 || new_set > RESVD_SET) + return (EINVAL); + if (cmd == 0 || cmd == 2 || cmd == 5) { if (rulenum >= IPFW_DEFAULT_RULE) - return EINVAL; + return (EINVAL); } else { if (rulenum > RESVD_SET) /* old_set */ - return EINVAL; + return (EINVAL); } IPFW_WLOCK(chain); @@ -3958,6 +3957,24 @@ else if (rule->set == new_set) rule->set = rulenum; break; + case 5: /* delete rules with given number and with given set number. + * rulenum - given rule number; + * new_set - given set number. + */ + for (; rule->rulenum < rulenum; prev = rule, rule = rule->next); + if (rule->rulenum != rulenum) { + IPFW_WUNLOCK(chain); + return (EINVAL); + } + flush_rule_ptrs(chain); + while (rule->rulenum == rulenum) { + if (rule->set == new_set) + rule = remove_rule(chain, rule, prev); + else { + prev = rule; + rule = rule->next; + } + } } /* * Look for rules to reclaim. We grab the list before @@ -3991,21 +4008,37 @@ /** * Reset some or all counters on firewall rules. - * @arg frwl is null to clear all entries, or contains a specific - * rule number. - * @arg log_only is 1 if we only want to reset logs, zero otherwise. + * The argument `arg' is an u_int32_t. The low 16 bit are the rule number, + * the next 8 bits are the set number, the top 8 bits are the command: + * 0 work with rules from all set's; + * 1 work with rules only from specified set. + * Specified rule number is zero if we want to clear all entries. + * log_only is 1 if we only want to reset logs, zero otherwise. */ static int -zero_entry(struct ip_fw_chain *chain, int rulenum, int log_only) +zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only) { struct ip_fw *rule; char *msg; + uint16_t rulenum = arg & 0xffff; + uint8_t set = (arg >> 16) & 0xff; + uint8_t cmd = (arg >> 24) & 0xff; + + if (cmd > 1) + return (EINVAL); + if (cmd == 1 && set > RESVD_SET) + return (EINVAL); + IPFW_WLOCK(chain); if (rulenum == 0) { norule_counter = 0; - for (rule = chain->rules; rule; rule = rule->next) + for (rule = chain->rules; rule; rule = rule->next) { + /* skip rules from another set */ + if (cmd == 1 && rule->set != set) + continue; clear_counters(rule, log_only); + } msg = log_only ? "ipfw: All logging counts reset.\n" : "ipfw: Accounting cleared.\n"; } else { @@ -4017,6 +4050,9 @@ for (rule = chain->rules; rule; rule = rule->next) if (rule->rulenum == rulenum) { while (rule && rule->rulenum == rulenum) { + if (cmd == 1 && rule->set != set) { + /* do nothing */ + } else clear_counters(rule, log_only); rule = rule->next; } @@ -4378,6 +4414,13 @@ bcopy(&(p->rule->rulenum), &(dst->rule), sizeof(p->rule->rulenum)); /* + * store set number into high word of + * dst->rule poiner. + */ + bcopy(&(p->rule->set), &dst->rule + + sizeof(p->rule->rulenum), + sizeof(p->rule->set)); + /* * store a non-null value in "next". * The userland code will interpret a * NULL here as a marker @@ -4406,7 +4449,7 @@ ipfw_ctl(struct sockopt *sopt) { #define RULE_MAXSIZE (256*sizeof(u_int32_t)) - int error, rule_num; + int error; size_t size; struct ip_fw *buf, *rule; u_int32_t rulenum[2]; @@ -4525,14 +4568,14 @@ case IP_FW_ZERO: case IP_FW_RESETLOG: /* argument is an int, the rule number */ - rule_num = 0; + rulenum[0] = 0; if (sopt->sopt_val != 0) { - error = sooptcopyin(sopt, &rule_num, - sizeof(int), sizeof(int)); + error = sooptcopyin(sopt, rulenum, + sizeof(u_int32_t), sizeof(u_int32_t)); if (error) break; } - error = zero_entry(&layer3_chain, rule_num, + error = zero_entry(&layer3_chain, rulenum[0], sopt->sopt_name == IP_FW_RESETLOG); break; --- sbin/ipfw/ipfw.8.orig Tue Jun 5 16:05:43 2007 +++ sbin/ipfw/ipfw.8 Tue Jun 5 16:28:18 2007 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD: src/sbin/ipfw/ipfw.8,v 1.200 2007/05/04 11:15:41 bz Exp $ .\" -.Dd May 4, 2007 +.Dd Jun 5, 2007 .Dt IPFW 8 .Os .Sh NAME @@ -14,15 +14,17 @@ .Ar rule .Nm .Op Fl acdefnNStT +.Op Cm set Ar N .Brq Cm list | show .Op Ar rule | first-last ... .Nm .Op Fl f | q +.Op Cm set Ar N .Cm flush .Nm .Op Fl q +.Op Cm set Ar N .Brq Cm delete | zero | resetlog -.Op Cm set .Op Ar number ... .Nm .Cm enable --- sbin/ipfw/ipfw2.c.orig Tue Jun 5 13:56:00 2007 +++ sbin/ipfw/ipfw2.c Tue Jun 5 16:15:11 2007 @@ -74,6 +74,7 @@ do_expired, /* display expired dynamic rules */ do_compact, /* show rules in compact mode */ do_force, /* do not ask for confirmation */ + use_set, /* work with specified set number */ show_sets, /* display rule sets */ test_only, /* only check syntax */ comment_only, /* only print action and comment */ @@ -2498,6 +2499,7 @@ u_long rnum, last; char *endptr; int seen = 0; + uint8_t set; const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; int nalloc = 1024; /* start somewhere... */ @@ -2552,6 +2554,10 @@ bcwidth = pcwidth = 0; if (show_counters) { for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { + /* skip rules from another set */ + if (use_set && r->set != use_set - 1) + continue; + /* packet counter */ width = snprintf(NULL, 0, "%llu", align_uint64(&r->pcnt)); @@ -2567,6 +2573,13 @@ } if (do_dynamic && ndyn) { for (n = 0, d = dynrules; n < ndyn; n++, d++) { + if (use_set) { + /* skip rules from another set */ + bcopy(&d->rule + sizeof(uint16_t), + &set, sizeof(uint8_t)); + if (set != use_set - 1) + continue; + } width = snprintf(NULL, 0, "%llu", align_uint64(&d->pcnt)); if (width > pcwidth) @@ -2580,14 +2593,24 @@ } /* if no rule numbers were specified, list all rules */ if (ac == 0) { - for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) + for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { + if (use_set && r->set != use_set - 1) + continue; show_ipfw(r, pcwidth, bcwidth); + } if (do_dynamic && ndyn) { printf("## Dynamic rules (%d):\n", ndyn); - for (n = 0, d = dynrules; n < ndyn; n++, d++) + for (n = 0, d = dynrules; n < ndyn; n++, d++) { + if (use_set) { + bcopy(&d->rule + sizeof(uint16_t), + &set, sizeof(uint8_t)); + if (set != use_set - 1) + continue; + } show_dyn_ipfw(d, pcwidth, bcwidth); } + } goto done; } @@ -2606,6 +2629,8 @@ for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { if (r->rulenum > last) break; + if (use_set && r->set != use_set - 1) + continue; if (r->rulenum >= rnum && r->rulenum <= last) { show_ipfw(r, pcwidth, bcwidth); seen = 1; @@ -2634,6 +2659,12 @@ bcopy(&d->rule, &rulenum, sizeof(rulenum)); if (rulenum > rnum) break; + if (use_set) { + bcopy(&d->rule + sizeof(uint16_t), + &set, sizeof(uint8_t)); + if (set != use_set - 1) + continue; + } if (r->rulenum >= rnum && r->rulenum <= last) show_dyn_ipfw(d, pcwidth, bcwidth); } @@ -2672,6 +2703,7 @@ " reverse|proxy_only|redirect_addr linkspec|\n" " redirect_port linkspec|redirect_proto linkspec}\n" "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" +"set N {show|list|zero|resetlog|delete} [N{,N}] | flush\n" "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" "\n" "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" @@ -3189,6 +3221,11 @@ av++; ac--; NEED1("missing rule specification"); if (ac > 0 && _substrcmp(*av, "set") == 0) { + /* don't allow using the following syntax: + * ipfw set N delete set M + */ + if (use_set) + errx(EX_DATAERR, "invalid syntax"); do_set = 1; /* delete set */ ac--; av++; } @@ -3214,6 +3251,10 @@ do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); } } else { + if (use_set) + rulenum = (i & 0xffff) | (5 << 24) | + ((use_set - 1) << 16); + else rulenum = (i & 0xffff) | (do_set << 24); i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); if (i) { @@ -5674,7 +5715,7 @@ static void zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) { - int rulenum; + uint32_t arg; int failed = EX_OK; char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; @@ -5694,15 +5735,17 @@ while (ac) { /* Rule number */ if (isdigit(**av)) { - rulenum = atoi(*av); + arg = strtol(*av, (char **)NULL, 10) & 0xffff; + if (use_set) + arg |= (1 << 24) | ((use_set - 1) << 16); av++; ac--; - if (do_cmd(optname, &rulenum, sizeof rulenum)) { + if (do_cmd(optname, &arg, sizeof(arg))) { warn("rule %u: setsockopt(IP_FW_%s)", - rulenum, name); + arg, name); failed = EX_UNAVAILABLE; } else if (!do_quiet) - printf("Entry %d %s.\n", rulenum, + printf("Entry %d %s.\n", arg, optname == IP_FW_ZERO ? "cleared" : "logging count reset"); } else { @@ -5733,7 +5776,12 @@ if (c == 'N') /* user said no */ return; } - if (do_cmd(cmd, NULL, 0) < 0) + /* `ipfw set N flush` - is the same that `ipfw delete set N` */ + if (use_set) { + uint32_t arg = ((use_set - 1) & 0xffff) | (1 << 24); + if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0) + err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)"); + } else if (do_cmd(cmd, NULL, 0) < 0) err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", do_pipe ? "DUMMYNET" : "FW"); if (!do_quiet) @@ -6134,6 +6182,15 @@ do_pipe = 1; else if (_substrcmp(*av, "queue") == 0) do_pipe = 2; + else if (!strncmp(*av, "set", strlen(*av))) { + if (ac > 1 && isdigit(av[1][0])) { + use_set = strtol(av[1], (char **)NULL, 10); + if (use_set > RESVD_SET) + errx(EX_DATAERR, "invalid set number %s\n", av[1]); + ac -= 2; av += 2; use_set++; + } + } + if (do_pipe || do_nat) { ac--; av++; @@ -6152,6 +6209,8 @@ av[1] = p; } + int try_next = 0; + if (use_set == 0) { if (_substrcmp(*av, "add") == 0) add(ac, av); else if (do_nat && _substrcmp(*av, "show") == 0) @@ -6160,7 +6219,20 @@ config_pipe(ac, av); else if (do_nat && _substrcmp(*av, "config") == 0) config_nat(ac, av); - else if (_substrcmp(*av, "delete") == 0) + else if (_substrcmp(*av, "set") == 0) + sets_handler(ac, av); + else if (_substrcmp(*av, "table") == 0) + table_handler(ac, av); + else if (_substrcmp(*av, "enable") == 0) + sysctl_handler(ac, av, 1); + else if (_substrcmp(*av, "disable") == 0) + sysctl_handler(ac, av, 0); + else + try_next = 1; + } + + if (use_set || try_next) { + if (_substrcmp(*av, "delete") == 0) delete(ac, av); else if (_substrcmp(*av, "flush") == 0) flush(do_force); @@ -6171,18 +6243,11 @@ else if (_substrcmp(*av, "print") == 0 || _substrcmp(*av, "list") == 0) list(ac, av, do_acct); - else if (_substrcmp(*av, "set") == 0) - sets_handler(ac, av); - else if (_substrcmp(*av, "table") == 0) - table_handler(ac, av); - else if (_substrcmp(*av, "enable") == 0) - sysctl_handler(ac, av, 1); - else if (_substrcmp(*av, "disable") == 0) - sysctl_handler(ac, av, 0); else if (_substrcmp(*av, "show") == 0) list(ac, av, 1 /* show counters */); else errx(EX_USAGE, "bad command `%s'", *av); + } /* Free memory allocated in the argument parsing. */ free_args(save_ac, save_av); --- sets_patch.txt ends here --- >Release-Note: >Audit-Trail: >Unformatted: