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