--- sys/netinet/ip_fw.h.orig Tue Feb 1 02:26:35 2005 +++ sys/netinet/ip_fw.h Sat May 21 22:49:15 2005 @@ -135,6 +135,9 @@ O_ANTISPOOF, /* none */ O_JAIL, /* u32 = id */ + O_BOUND, /* u64 = bound in bytes */ + O_CHECK_BOUND, /* u16 = rule number */ + O_LAST_OPCODE /* not an opcode! */ }; @@ -200,6 +203,14 @@ } ipfw_insn_u32; /* + * This is used to store 64-bit bound value. + */ +typedef struct _ipfw_insn_u64 { + ipfw_insn o; + u_int64_t bound; +} ipfw_insn_u64; + +/* * This is used to store IP addr-mask pairs. */ typedef struct _ipfw_insn_ip { @@ -289,10 +300,15 @@ * * When assembling instruction, remember the following: * + * + if a rule has a "bound" option, then the first instruction + * (at r->cmd) MUST BE an O_BOUND * + if a rule has a "keep-state" (or "limit") option, then the * first instruction (at r->cmd) MUST BE an O_PROBE_STATE * + if a rule has a "log" option, then the first action * (at ACTION_PTR(r)) MUST be O_LOG + * + * NOTE: actually, O_PROB instruction may be first too. But O_BOUND + * MUST BE always first (at r->cmd). * * NOTE: we use a simple linked list of rules because we never need * to delete a rule without scanning the list. We do not use --- sys/netinet/ip_fw2.c.orig Sun Feb 6 19:16:20 2005 +++ sys/netinet/ip_fw2.c Sat May 21 22:53:52 2005 @@ -1971,6 +1971,26 @@ * logic to deal with F_NOT and F_OR flags associated * with the opcode. */ + case O_BOUND: + match = (f->bcnt < ((ipfw_insn_u64 *)cmd)->bound); + break; + + case O_CHECK_BOUND: + { + struct ip_fw* rule; + for (rule = f->next; + rule && cmd->arg1 >= rule->rulenum; + rule = rule->next) + if (rule->rulenum == cmd->arg1 && + rule->cmd->opcode == O_BOUND ) + { + match = (rule->bcnt < + ((ipfw_insn_u64 *)(rule->cmd))->bound); + break; + } + } + break; + case O_NOP: match = 1; break; @@ -2923,6 +2943,7 @@ case O_VERSRCREACH: case O_ANTISPOOF: case O_IPSEC: + case O_CHECK_BOUND: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; break; @@ -2939,6 +2960,16 @@ if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) goto bad_size; break; + + case O_BOUND: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u64)) + goto bad_size; + if (cmd != rule->cmd) { + printf("ipfw: bogus rule, opcode %d must be first\n", + cmd->opcode); + return EINVAL; + } + break; case O_LIMIT: if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) --- sbin/ipfw/ipfw2.c.orig Tue Jan 25 10:23:34 2005 +++ sbin/ipfw/ipfw2.c Sat May 21 23:03:00 2005 @@ -67,6 +67,8 @@ show_sets, /* display rule sets */ test_only, /* only check syntax */ comment_only, /* only print action and comment */ + not_humanval, /* don't use human-readable unit suffixes + when show boundary values */ verbose; #define IP_MASK_ALL 0xffffffff @@ -253,6 +255,9 @@ TOK_DROPTAIL, TOK_PROTO, TOK_WEIGHT, + + TOK_BOUND, + TOK_CHECK_BOUND, }; struct _s_x dummynet_params[] = { @@ -351,6 +356,8 @@ { "antispoof", TOK_ANTISPOOF }, { "ipsec", TOK_IPSEC }, { "//", TOK_COMMENT }, + { "bound", TOK_BOUND }, + { "check-bound", TOK_CHECK_BOUND }, { "not", TOK_NOT }, /* pseudo option */ { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ @@ -1159,6 +1166,9 @@ flags |= HAVE_PROTO; break; + case O_BOUND: + break; + default: /*options ... */ show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); if ((cmd->len & F_OR) && !or_block) @@ -1334,6 +1344,10 @@ } break; + case O_CHECK_BOUND: + printf(" check-bound %d", cmd->arg1); + break; + default: printf(" [opcode %d len %d]", cmd->opcode, cmd->len); @@ -1348,6 +1362,23 @@ } } show_prerequisites(&flags, HAVE_IP, 0); + if (rule->cmd->opcode == O_BOUND) { + uint64_t bound = ((ipfw_insn_u64 *)(rule->cmd))->bound; + printf(" bound "); + if (!not_humanval) { + if ((bound >> 10) && !(bound & 0x2FF)) { + if ((bound >> 20) && !(bound & 0xFFFFF)) { + if ((bound >> 30) && !(bound & 0x3FFFFFFF)) + printf("%uGB", bound >> 30); + else + printf("%uMB", bound >> 20); + } else + printf("%uKB", bound >> 10); + } else + printf("%uB", bound); + } else + printf("%u", bound); + } if (comment) printf(" // %s", comment); printf("\n"); @@ -1917,7 +1948,7 @@ " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" -" verrevpath | versrcreach | antispoof\n" +" bound VALUE | check-bound NUM | verrevpath | versrcreach | antispoof\n" ); exit(0); } @@ -2783,6 +2814,7 @@ * various flags used to record that we entered some fields. */ ipfw_insn *have_state = NULL; /* check-state or keep-state */ + ipfw_insn *have_bound = NULL; size_t len; int i; @@ -3496,6 +3528,39 @@ ac = 0; break; + case TOK_BOUND: + NEED1("bound requires numeric value"); + if (open_par) + errx(EX_USAGE, "bound cannot be part " + "of an or block"); + if (have_bound) + errx(EX_USAGE, "only one of bound is allowed"); + if (cmd->len & F_NOT) + errx(EX_USAGE, + "\"not\" not allowed with bound option"); + { + char *end = NULL; + uint64_t bound = strtoull(*av, &end, 0); + if (bound) + switch (*end){ + case 'G': bound *= 1024; + case 'M': bound *= 1024; + case 'K': bound *= 1024; + }; + cmd->opcode = O_BOUND; + ((ipfw_insn_u64 *)cmd)->bound = bound; + cmd->len = F_INSN_SIZE(ipfw_insn_u64) & F_LEN_MASK; + have_bound = cmd; + ac--; av++; + } + break; + + case TOK_CHECK_BOUND: + NEED1("check-bound requires rule number"); + fill_cmd(cmd, O_CHECK_BOUND, 0, strtoul(*av, NULL, 0)); + ac--; av++; + break; + default: errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } @@ -3508,6 +3573,8 @@ done: /* * Now copy stuff into the rule. + * If we have a bound option, the first instruction MUST BE + * a O_BOUND. * If we have a keep-state option, the first instruction * must be a PROBE_STATE (which is generated here). * If we have a LOG option, it was stored as the first command, @@ -3516,7 +3583,15 @@ dst = (ipfw_insn *)rule->cmd; /* - * First thing to write into the command stream is the match probability. + * First write into the command stream bound instruction + */ + if (have_bound) { + bcopy(have_bound, dst, F_LEN(have_bound) * sizeof(uint32_t)); + dst = next_cmd(dst); + } + + /* + * write the match probability */ if (match_prob != 1) { /* 1 means always match */ dst->opcode = O_PROB; @@ -3542,6 +3617,7 @@ case O_LOG: case O_KEEP_STATE: case O_LIMIT: + case O_BOUND: break; default: bcopy(src, dst, i * sizeof(uint32_t)); @@ -3845,7 +3921,7 @@ save_av = av; optind = optreset = 0; - while ((ch = getopt(ac, av, "abcdefhnNqs:STtv")) != -1) + while ((ch = getopt(ac, av, "abcdefhHnNqs:STtv")) != -1) switch (ch) { case 'a': do_acct = 1; @@ -3876,6 +3952,10 @@ free_args(save_ac, save_av); help(); break; /* NOTREACHED */ + + case 'H': /* don't use human-readable output */ + not_humanval = 1; + break; case 'n': test_only = 1;