CFR: patch to ipfw2 iplen to match a range of lengths
Gregory P. Smith
greg at electricrain.com
Wed May 21 01:04:02 PDT 2003
Here's a patch (attached) to make RELENG_5_0's ipfw2 iplen match a range
of values rather than a single length.
IMHO its much more useful than the current method of only matching
an exact length. How often do you need to match only an exact packet
length rather than "all packets less than 128 bytes" or "all packets
over 500 bytes"?
The ipfw command syntax doesn't change for those using the existing
iplen rule. It adds the ability to say things like "iplen 28-128"
any comments?
Greg
-------------- next part --------------
--- sbin/ipfw/ipfw.8.saved Mon May 19 23:01:38 2003
+++ sbin/ipfw/ipfw.8 Wed May 21 00:25:07 2003
@@ -885,10 +885,13 @@
.Cm ip_id
field has value
.Ar id .
-.It Cm iplen Ar len
+.It Cm iplen Ar len | minlen-maxlen
Matches IP packets whose total length, including header and data, is
.Ar len
-bytes.
+bytes or, if a range is given, is >=
+.Ar minlen
+and <=
+.Ar maxlen.
.It Cm ipoptions Ar spec
Matches packets whose IP header contains the comma separated list of
options specified in
--- sbin/ipfw/ipfw2.c.saved Mon May 19 23:01:48 2003
+++ sbin/ipfw/ipfw2.c Wed May 21 00:44:54 2003
@@ -534,6 +534,42 @@
return i;
}
+/*
+ * fill the body of the command with the min & max u16s delimiting a range
+ */
+static void
+fill_minmax(ipfw_insn_u16 *cmd, enum ipfw_opcodes opcode, char *av)
+{
+ u_int16_t *p = cmd->ports;
+ char *s = av;
+ u_int16_t min, max;
+
+ min = strtol(av, &s, 0);
+ if (s == av) /* no parameter */
+ errx(EX_DATAERR, "missing minimum or only value\n");
+ if (*s == '-') { /* a range */
+ av = s+1;
+ max = strtol(av, &s, 0);
+ if (s == av) { /* no parameter */
+ errx(EX_DATAERR, "missing maximum value in range <%u->\n", min);
+ } else {
+ p[0] = min;
+ p[1] = max;
+ if (min > max)
+ errx(EX_DATAERR, "min > max in range <%u-%u>\n", min, max);
+ }
+ } else if (*s == '\0') {
+ p[0] = p[1] = min;
+ } else { /* invalid separator */
+ errx(EX_DATAERR, "invalid separator <%c> in <%s>\n",
+ *s, av);
+ }
+
+ cmd->o.opcode = opcode;
+ cmd->o.len |= 2; /* leave F_NOT and F_OR untouched */
+}
+
+
static struct _s_x icmpcodes[] = {
{ "net", ICMP_UNREACH_NET },
{ "host", ICMP_UNREACH_HOST },
@@ -1099,8 +1135,15 @@
printf(" ipprecedence %u", (cmd->arg1) >> 5 );
break;
- case O_IPLEN:
- printf(" iplen %u", cmd->arg1 );
+ case O_IPLEN: {
+ u_int16_t min, max;
+ min = ((ipfw_insn_u16 *)cmd)->ports[0];
+ max = ((ipfw_insn_u16 *)cmd)->ports[1];
+ if (max != min)
+ printf(" iplen %u-%u", min, max );
+ else
+ printf(" iplen %u", min );
+ }
break;
case O_IPOPT:
@@ -2903,8 +2946,8 @@
break;
case TOK_IPLEN:
- NEED1("iplen requires length");
- fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
+ NEED1("iplen requires length or a range of lengths");
+ fill_minmax((ipfw_insn_u16 *)cmd, O_IPLEN, *av);
ac--; av++;
break;
--- sys/netinet/ip_fw.h.saved Mon May 19 22:46:48 2003
+++ sys/netinet/ip_fw.h Mon May 19 23:00:50 2003
@@ -71,7 +71,7 @@
O_VIA, /* none */
O_IPOPT, /* arg1 = 2*u8 bitmap */
- O_IPLEN, /* arg1 = len */
+ O_IPLEN, /* u16 min, u16 max */
O_IPID, /* arg1 = id */
O_IPTOS, /* arg1 = id */
--- sys/netinet/ip_fw2.c.saved Mon May 19 22:46:58 2003
+++ sys/netinet/ip_fw2.c Mon May 19 23:10:03 2003
@@ -1686,7 +1686,10 @@
break;
case O_IPLEN:
- match = (hlen > 0 && cmd->arg1 == ip_len);
+ /* match if min <= iplen <= max */
+ match = (hlen > 0 &&
+ ((ipfw_insn_u16 *)cmd)->ports[0] <= ip_len &&
+ ((ipfw_insn_u16 *)cmd)->ports[1] >= ip_len);
break;
case O_IPPRECEDENCE:
@@ -2303,7 +2306,6 @@
case O_IN:
case O_FRAG:
case O_IPOPT:
- case O_IPLEN:
case O_IPID:
case O_IPTOS:
case O_IPPRECEDENCE:
@@ -2314,6 +2316,11 @@
case O_TCPOPTS:
case O_ESTAB:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
+ goto bad_size;
+ break;
+
+ case O_IPLEN:
+ if (cmdlen != F_INSN_SIZE(ipfw_insn_u16))
goto bad_size;
break;
More information about the freebsd-net
mailing list