--- sys/netinet/in.h.orig Fri May 20 12:35:40 2005 +++ sys/netinet/in.h Sun May 22 03:03:25 2005 @@ -402,6 +402,8 @@ #define IP_FW_TABLE_GETSIZE 43 /* get table size */ #define IP_FW_TABLE_LIST 44 /* list table contents */ +#define IP_FW_BOUND_CHANGE 45 /* change a boundary value */ + #define IP_FW_ADD 50 /* add a firewall rule to chain */ #define IP_FW_DEL 51 /* delete a firewall rule from chain */ #define IP_FW_FLUSH 52 /* flush firewall rule chain */ --- sys/netinet/ip_fw.h.orig Sun May 22 02:35:37 2005 +++ sys/netinet/ip_fw.h Sun May 22 03:03:25 2005 @@ -396,6 +396,18 @@ ipfw_insn cmd[1]; /* storage for commands */ }; +/* + * Argument for calling [gs]etsockopt with IP_FW_BOUND_CHANGE option + */ + +struct ip_fw_bound { + u_int16_t rulenum; /* rule number */ + u_int8_t set; /* rule set (0..31) */ + u_int8_t _pad; /* padding */ + + u_int64_t bound; /* new boundary value */ +}; + #define ACTION_PTR(rule) \ (ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) ) --- sys/netinet/ip_fw2.c.orig Sun May 22 02:52:52 2005 +++ sys/netinet/ip_fw2.c Sun May 22 03:03:25 2005 @@ -3620,7 +3620,7 @@ * Disallow modifications in really-really secure mode, but still allow * the logging counters to be reset. */ - if (sopt->sopt_name == IP_FW_ADD || + if (sopt->sopt_name == IP_FW_ADD || sopt->sopt_name == IP_FW_BOUND_CHANGE || (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { #if __FreeBSD_version >= 500034 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); @@ -3739,6 +3739,45 @@ } error = zero_entry(&layer3_chain, rule_num, sopt->sopt_name == IP_FW_RESETLOG); + break; + + case IP_FW_BOUND_CHANGE: + { + struct ip_fw_bound* opt; + + if (sopt->sopt_val == NULL) { + error = EINVAL; + break; + } + + opt = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); + error = sooptcopyin(sopt, opt, RULE_MAXSIZE, + sizeof(struct ip_fw_bound)); + if (!error && opt->set > 31) + error = EINVAL; + if (!error) { + IPFW_WLOCK(&layer3_chain); + for(rule = layer3_chain.rules; rule; rule = rule->next) { + if (rule->rulenum == opt->rulenum && + rule->set == opt->set && + rule->cmd->opcode == O_BOUND) + break; + if (rule->rulenum > opt->rulenum) { + /* we did not find any matching rules */ + error = EINVAL; + break; + } + } + if (!error && rule) { + ((ipfw_insn_u64*)rule->cmd)->bound = opt->bound; + size = RULESIZE(rule); + if (sopt->sopt_dir == SOPT_GET) + error = sooptcopyout(sopt, rule, size); + } + IPFW_WUNLOCK(&layer3_chain); + } + free(opt, M_TEMP); + } break; case IP_FW_TABLE_ADD: --- sbin/ipfw/ipfw2.c.orig Sun May 22 02:56:41 2005 +++ sbin/ipfw/ipfw2.c Sun May 22 03:03:25 2005 @@ -446,7 +446,7 @@ 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_TABLE_GETSIZE || optname == IP_FW_BOUND_CHANGE) i = getsockopt(s, IPPROTO_IP, optname, optval, (socklen_t *)optlen); else @@ -2488,6 +2488,7 @@ "[pipe|queue] {zero|delete|show} [N{,N}]\n" "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" +"bound num [set N] change VALUE\n" "\n" "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" "ACTION: check-state | allow | count | deny | unreach CODE | skipto N |\n" @@ -3026,6 +3027,60 @@ exit(exitval); } +static void +bound_change(int ac, char *av[]) +{ + /* + * Rule syntax: ipfw bound Rule_N [set N] change New_Bound + */ + static uint32_t optbuf[255]; + struct ip_fw_bound *opt; + struct ip_fw *rule; + int size; + + bzero(optbuf, sizeof(optbuf)); + opt = (struct ip_fw_opt *)optbuf; + rule = (struct ip_fw *)optbuf; + + av++; ac--; + + /* [rule N] -- Rule number */ + if (ac > 0 && isdigit(**av)) { + opt->rulenum = atoi(*av); + av++; ac--; + } else + errx(EX_USAGE, "missing rule number"); + + /* [set N] -- set number (0..RESVD_SET), optional */ + if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { + int set = strtoul(av[1], NULL, 10); + if (set < 0 || set > RESVD_SET) + errx(EX_DATAERR, "illegal set %s", av[1]); + opt->set = set; + av += 2; ac -= 2; + } /* else opt->set = 0; */ + + if (ac > 1 && !strncmp(*av, "change", strlen(*av))) { + char* end = NULL; + opt->bound = strtoull(av[1], &end, 0); + if (opt->bound) + switch (*end){ + case 'G': opt->bound *= 1024; + case 'M': opt->bound *= 1024; + case 'K': opt->bound *= 1024; + }; + ac -= 2; av += 2; + } else + errx(EX_USAGE, "missing rule specification"); + if (ac != 0) + errx(EX_USAGE, "too many arguments"); + + size = sizeof(optbuf); + if (do_cmd(IP_FW_BOUND_CHANGE, opt, (uintptr_t)&size) == -1) + err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_BOUND_CHANGE"); + if (!do_quiet) + show_ipfw(rule, 0, 0); +} /* * fill the interface structure. We do not check the name as we can @@ -5026,6 +5081,8 @@ sysctl_handler(ac, av, 0); else if (_substrcmp(*av, "show") == 0) list(ac, av, 1 /* show counters */); + else if (!strncmp(*av, "bound", strlen(*av))) + bound_change(ac, av); else errx(EX_USAGE, "bad command `%s'", *av); --- sys/netinet/raw_ip.c.orig Fri May 20 12:35:41 2005 +++ sys/netinet/raw_ip.c Sun May 22 03:03:25 2005 @@ -360,6 +360,7 @@ break; case IP_FW_ADD: /* ADD actually returns the body... */ + case IP_FW_BOUND_CHANGE: /* returns the body too */ case IP_FW_GET: case IP_FW_TABLE_GETSIZE: case IP_FW_TABLE_LIST: