Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 Sep 2000 23:08:46 -0400
From:      Bill Fumerola <billf@chimesnet.com>
To:        freebsd-ipfw@freebsd.org
Cc:        luigi@freebsd.org
Subject:   REVIEW REQUEST - new ipfw options
Message-ID:  <20000926230846.H34501@jade.chc-chimes.com>

next in thread | raw e-mail | index | archive | help
[ sent to net@ and ipfw@, discussion in ipfw@ ]

Please review the following patch for ipfw, adding more fields to provide
the firewall administrator with a higher level of granularity. This patch also
introduces a new flags member to struct ip_fw as I ran out of space in that, and
I feel that splitting up things that change the operation of ipfw internally
and things that define where we poke around belong in different locations. Its
possible that more things now belong in the new flag member.

Everything should be pretty straightforward. One thing notably absent is
the diff to ipfw.8 in this patch. That's not due to incompetence with cvs,
that's due to incompetence with mdoc. It should be very easy for someone with
any mdoc clue to add these options in ipfw.8, and I'd ask that someone do that.

Thanks,

-- 
Bill Fumerola - Network Architect, BOFH / Chimes, Inc.
                billf@chimesnet.com / billf@FreeBSD.org



----- Forwarded message from Bill Fumerola <billf@dummy2.internal.chc-chimes.com> -----

Index: ipfw.c
===================================================================
RCS file: /home/ncvs/src/sbin/ipfw/ipfw.c,v
retrieving revision 1.89
diff -u -r1.89 ipfw.c
--- ipfw.c	2000/08/16 07:36:29	1.89
+++ ipfw.c	2000/09/27 02:38:43
@@ -412,7 +412,7 @@
 	if (chain->fw_flg & IP_FW_F_FRAG)
 		printf(" frag");
 
-	if (chain->fw_ipopt || chain->fw_ipnopt) {
+	if (chain->fw_ipflg & IP_FW_IF_IPOPT) {
 		int 	_opt_printed = 0;
 #define PRINTOPT(x)	{if (_opt_printed) printf(",");\
 			printf(x); _opt_printed = 1;}
@@ -428,12 +428,39 @@
 		if (chain->fw_ipnopt & IP_FW_IPOPT_TS)   PRINTOPT("!ts");
 	} 
 
+	if (chain->fw_ipflg & IP_FW_IF_IPLEN)
+		printf(" iplen %u", chain->fw_iplen);
+	if (chain->fw_ipflg & IP_FW_IF_IPID)
+		printf(" ipid 0x%04x", chain->fw_ipid);
+
+	if (chain->fw_ipflg & IP_FW_IF_IPTOS) {
+		int 	_opt_printed = 0;
+
+		printf(" iptos ");
+		if (chain->fw_iptos  & IPTOS_LOWDELAY) PRINTOPT("lowdelay");
+		if (chain->fw_ipntos & IPTOS_LOWDELAY) PRINTOPT("!lowdelay");
+		if (chain->fw_iptos  & IPTOS_THROUGHPUT) PRINTOPT("throughput");
+		if (chain->fw_ipntos & IPTOS_THROUGHPUT) PRINTOPT("!throughput");
+		if (chain->fw_iptos  & IPTOS_RELIABILITY)   PRINTOPT("reliability");
+		if (chain->fw_ipntos & IPTOS_RELIABILITY)   PRINTOPT("!reliability");
+		if (chain->fw_iptos  & IPTOS_MINCOST)   PRINTOPT("mincost");
+		if (chain->fw_ipntos & IPTOS_MINCOST)   PRINTOPT("!mincost");
+		if (chain->fw_iptos  & IPTOS_CE)   PRINTOPT("congestion");
+		if (chain->fw_ipntos & IPTOS_CE)   PRINTOPT("!congestion");
+	} 
+
+	if (chain->fw_ipflg & IP_FW_IF_IPTTL)
+		printf(" ipttl %u", chain->fw_ipttl);
+
+	if (chain->fw_ipflg & IP_FW_IF_IPVER)
+		printf(" ipversion %u", chain->fw_ipver);
+
 	if (chain->fw_tcpf & IP_FW_TCPF_ESTAB) 
 		printf(" established");
 	else if (chain->fw_tcpf == IP_FW_TCPF_SYN &&
 	    chain->fw_tcpnf == IP_FW_TCPF_ACK)
 		printf(" setup");
-	else if (chain->fw_tcpf || chain->fw_tcpnf) {
+	else if (chain->fw_ipflg & IP_FW_IF_TCPOPT) {
 		int 	_flg_printed = 0;
 #define PRINTFLG(x)	{if (_flg_printed) printf(",");\
 			printf(x); _flg_printed = 1;}
@@ -452,7 +479,7 @@
 		if (chain->fw_tcpf  & IP_FW_TCPF_URG)  PRINTFLG("urg");
 		if (chain->fw_tcpnf & IP_FW_TCPF_URG)  PRINTFLG("!urg");
 	} 
-	if (chain->fw_tcpopt || chain->fw_tcpnopt) {
+	if (chain->fw_ipflg & IP_FW_IF_TCPOPT) {
 		int 	_opt_printed = 0;
 #define PRINTTOPT(x)	{if (_opt_printed) printf(",");\
 			printf(x); _opt_printed = 1;}
@@ -470,6 +497,13 @@
 		if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC)  PRINTTOPT("!cc");
 	} 
 
+	if (chain->fw_ipflg & IP_FW_IF_TCPSEQ)
+		printf(" tcpseq %lu", ntohl(chain->fw_tcpseq));
+	if (chain->fw_ipflg & IP_FW_IF_TCPACK)
+		printf(" tcpack %lu", ntohl(chain->fw_tcpack));
+	if (chain->fw_ipflg & IP_FW_IF_TCPWIN)
+		printf(" tcpwin %hu", ntohs(chain->fw_tcpwin));
+
 	if (chain->fw_flg & IP_FW_F_ICMPBIT) {
 		int type_index;
 		int first = 1;
@@ -837,7 +871,15 @@
 "    {established|setup}\n"
 "    tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
 "    ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
+"    iplen {length}\n"
+"    ipid {identification number (in hex)}\n"
+"    iptos [!]{lowdelay|throughput|reliability|mincost|congestion}\n"
+"    ipttl {time to live}\n"
+"    ipversion {version number}\n"
 "    tcpoptions [!]{mss|window|sack|ts|cc},...\n"
+"    tcpseq {sequence number}\n"
+"    tcpack {acknowledgement number}\n"
+"    tcpwin {window size}\n"
 "    icmptypes {type[,type]}...\n"
 "  pipeconfig:\n"
 "    {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
@@ -1148,6 +1190,40 @@
 }
 
 static void
+fill_iptos(u_char *set, u_char *reset, char **vp)
+{
+	char *p = *vp,*q;
+	u_char *d;
+
+	while (p && *p) {
+		if (*p == '!') {
+			p++;
+			d = reset;
+		} else {
+			d = set;
+		}
+		q = strchr(p, ',');
+		if (q) 
+			*q++ = '\0';
+		if (!strncmp(p,"lowdelay",strlen(p)))
+			*d |= IPTOS_LOWDELAY;
+		if (!strncmp(p,"throughput",strlen(p)))
+			*d |= IPTOS_THROUGHPUT;
+		if (!strncmp(p,"reliability",strlen(p)))
+			*d |= IPTOS_RELIABILITY;
+		if (!strncmp(p,"mincost",strlen(p)))
+			*d |= IPTOS_MINCOST;
+		if (!strncmp(p,"congestion",strlen(p)))
+			*d |= IPTOS_CE;
+#if 0 /* conflicting! */
+		if (!strncmp(p,"ecntransport",strlen(p)))
+			*d |= IPTOS_ECT;
+#endif
+		p = q;
+	}
+}
+
+static void
 fill_icmptypes(types, vp, fw_flg)
 	u_long *types;
 	char **vp;
@@ -1878,22 +1954,78 @@
 			rule.fw_flg |= IP_FW_F_FRAG;
 			av++; ac--; continue;
 		}
-		if (!strncmp(*av,"ipoptions",strlen(*av))) { 
+		if (!strncmp(*av,"ipoptions",strlen(*av)) ||
+			!strncmp(*av,"ipopts",strlen(*av))) { 
 			av++; ac--; 
 			if (!ac)
 				show_usage("missing argument"
 				    " for ``ipoptions''");
+			rule.fw_ipflg |= IP_FW_IF_IPOPT;
 			fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av);
 			av++; ac--; continue;
 		}
+		if (!strncmp(*av,"iplen",strlen(*av))) {
+ 			av++; ac--;
+			if (!ac)
+ 				show_usage("missing arguement"
+ 					" for ``iplen''");
+ 			rule.fw_ipflg |= IP_FW_IF_IPLEN;
+ 			rule.fw_iplen = (u_short)strtoul(*av, NULL, 0);
+  			av++; ac--; continue;
+ 		}
+		if (!strncmp(*av,"ipid",strlen(*av))) {
+ 			av++; ac--;
+			if (!ac)
+ 				show_usage("missing arguement"
+ 					" for ``ipid''");
+ 			rule.fw_ipflg |= IP_FW_IF_IPID;
+			if (strlen(*av) != 6 || (*av)[0] != '0' || (*av)[1] != 'x' ||
+				isxdigit((*av)[2]) == 0 ||
+				isxdigit((*av)[3]) == 0 ||
+				isxdigit((*av)[4]) == 0 ||
+				isxdigit((*av)[5]) == 0)
+				show_usage("arguement to ipid must be in hex");
+ 			rule.fw_ipid = (u_short)strtoul(*av, NULL, 0);
+  			av++; ac--; continue;
+ 		}
+		if (!strncmp(*av,"iptos",strlen(*av))) {
+ 			av++; ac--;
+			if (!ac)
+ 				show_usage("missing arguement"
+ 					" for ``iptos''");
+ 			rule.fw_ipflg |= IP_FW_IF_IPTOS;
+			fill_iptos(&rule.fw_iptos, &rule.fw_ipntos, av);
+  			av++; ac--; continue;
+ 		}
+		if (!strncmp(*av,"ipttl",strlen(*av))) {
+ 			av++; ac--;
+			if (!ac)
+ 				show_usage("missing arguement"
+ 					" for ``ipttl''");
+ 			rule.fw_ipflg |= IP_FW_IF_IPTTL;
+ 			rule.fw_ipttl = (u_short)strtoul(*av, NULL, 0);
+  			av++; ac--; continue;
+ 		}
+		if (!strncmp(*av,"ipversion",strlen(*av)) ||
+			!strncmp(*av,"ipver",strlen(*av))) {
+ 			av++; ac--;
+			if (!ac)
+ 				show_usage("missing arguement"
+ 					" for ``ipversion''");
+ 			rule.fw_ipflg |= IP_FW_IF_IPVER;
+ 			rule.fw_ipver = (u_short)strtoul(*av, NULL, 0);
+  			av++; ac--; continue;
+ 		}
 		if (rule.fw_prot == IPPROTO_TCP) {
 			if (!strncmp(*av,"established",strlen(*av))) { 
 				rule.fw_tcpf  |= IP_FW_TCPF_ESTAB;
+ 				rule.fw_ipflg |= IP_FW_IF_TCPFLG;
 				av++; ac--; continue;
 			}
 			if (!strncmp(*av,"setup",strlen(*av))) { 
 				rule.fw_tcpf  |= IP_FW_TCPF_SYN;
 				rule.fw_tcpnf  |= IP_FW_TCPF_ACK;
+ 				rule.fw_ipflg |= IP_FW_IF_TCPFLG;
 				av++; ac--; continue;
 			}
 			if (!strncmp(*av,"tcpflags",strlen(*av)) || !strncmp(*av,"tcpflgs",strlen(*av))) { 
@@ -1901,6 +2033,7 @@
 				if (!ac)
 					show_usage("missing argument"
 					    " for ``tcpflags''");
+ 				rule.fw_ipflg |= IP_FW_IF_TCPFLG;
 				fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
 				av++; ac--; continue;
 			}
@@ -1909,9 +2042,37 @@
 				if (!ac)
 					show_usage("missing argument"
 					    " for ``tcpoptions''");
+ 				rule.fw_ipflg |= IP_FW_IF_TCPOPT;
 				fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av);
 				av++; ac--; continue;
 			}
+			if (!strncmp(*av,"tcpseq",strlen(*av))) {
+				av++; ac--;
+ 				if (!ac)
+ 					show_usage("missing arguement"
+ 						" for ``tcpseq''");
+ 				rule.fw_ipflg |= IP_FW_IF_TCPSEQ;
+ 				rule.fw_tcpseq = htonl((u_int32_t)strtoul(*av, NULL, 0));
+ 				av++; ac--; continue;
+ 			}
+ 			if (!strncmp(*av,"tcpack",strlen(*av))) {
+ 				av++; ac--;
+ 				if (!ac)
+ 					show_usage("missing arguement"
+ 						" for ``tcpack''");
+ 				rule.fw_ipflg |= IP_FW_IF_TCPACK;
+ 				rule.fw_tcpack = htonl((u_int32_t)strtoul(*av, NULL, 0));
+ 				av++; ac--; continue;
+ 			}
+ 			if (!strncmp(*av,"tcpwin",strlen(*av))) {
+ 				av++; ac--;
+				if (!ac)
+ 					show_usage("missing arguement"
+ 						" for ``tcpwin''");
+ 				rule.fw_ipflg |= IP_FW_IF_TCPWIN;
+ 				rule.fw_tcpwin = htons((u_short)strtoul(*av, NULL, 0));
+  				av++; ac--; continue;
+  			}
 		}
 		if (rule.fw_prot == IPPROTO_ICMP) {
 			if (!strncmp(*av,"icmptypes",strlen(*av))) {
Index: /sys/netinet/ip_fw.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw.c,v
retrieving revision 1.140
diff -u -r1.140 ip_fw.c
--- /sys/netinet/ip_fw.c	2000/09/12 02:38:05	1.140
+++ /sys/netinet/ip_fw.c	2000/09/26 07:14:14
@@ -193,6 +193,7 @@
 		iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu,
 				 int byname));
 static int	ipopts_match __P((struct ip *ip, struct ip_fw *f));
+static int	iptos_match __P((struct ip *ip, struct ip_fw *f));
 static __inline int
 		port_match __P((u_short *portptr, int nports, u_short port,
 				int range_flag, int mask));
@@ -354,6 +355,33 @@
 }
 
 static int
+iptos_match(struct ip *ip, struct ip_fw *f)
+{
+
+	u_int flags = (ip->ip_tos & 0x1f);
+	u_char opts, nopts, nopts_sve;
+
+	opts = f->fw_iptos;
+	nopts = nopts_sve = f->fw_ipntos;
+
+	while (flags != 0) {
+		u_int flag;
+
+		flag = 1 << (ffs(flags) -1);
+		opts &= ~flag;
+		nopts &= ~flag;
+		flags &= ~flag;
+	}
+
+	if (opts == 0 && nopts == nopts_sve)
+		return 1;
+	else
+		return 0;
+
+}
+
+
+static int
 tcpopts_match(struct tcphdr *tcp, struct ip_fw *f)
 {
 	register u_char *cp;
@@ -1108,9 +1136,19 @@
 				continue;
 		}
 
-		/* Check IP options */
-		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
+		/* Check IP header values */
+		if (f->fw_ipflg & IP_FW_IF_IPOPT && !ipopts_match(ip, f))
+			continue;
+		if (f->fw_ipflg & IP_FW_IF_IPLEN && f->fw_iplen != ip->ip_len)
+			continue;
+		if (f->fw_ipflg & IP_FW_IF_IPID && f->fw_ipid != ip->ip_id)
 			continue;
+		if (f->fw_ipflg & IP_FW_IF_IPTOS && !iptos_match(ip, f))
+			continue;
+		if (f->fw_ipflg & IP_FW_IF_IPTTL && f->fw_ipttl != ip->ip_ttl)
+			continue;
+		if (f->fw_ipflg & IP_FW_IF_IPVER && f->fw_ipver != ip->ip_v)
+			continue;
 
 		/* Check protocol; if wildcard, and no [ug]id, match */
 		if (f->fw_prot == IPPROTO_IP) {
@@ -1211,9 +1249,15 @@
 			}
 			tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
 
-			if (f->fw_tcpopt != f->fw_tcpnopt && !tcpopts_match(tcp, f))
+			if (f->fw_ipflg & IP_FW_IF_TCPOPT && !tcpopts_match(tcp, f))
+				continue;
+			if (f->fw_ipflg & IP_FW_IF_TCPFLG && !tcpflg_match(tcp, f))
+				continue;
+			if (f->fw_ipflg & IP_FW_IF_TCPSEQ && tcp->th_seq != f->fw_tcpseq)
+				continue;
+			if (f->fw_ipflg & IP_FW_IF_TCPACK && tcp->th_ack != f->fw_tcpack)
 				continue;
-			if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
+			if (f->fw_ipflg & IP_FW_IF_TCPWIN && tcp->th_win != f->fw_tcpwin)
 				continue;
 			goto check_ports;
 		    }
Index: /sys/netinet/ip_fw.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
retrieving revision 1.52
diff -u -r1.52 ip_fw.h
--- /sys/netinet/ip_fw.h	2000/08/22 00:32:52	1.52
+++ /sys/netinet/ip_fw.h	2000/09/26 07:14:42
@@ -54,7 +54,7 @@
     struct in_addr fw_src, fw_dst;	/* Source and destination IP addr */
     struct in_addr fw_smsk, fw_dmsk;	/* Mask for src and dest IP addr */
     u_short fw_number;			/* Rule number */
-    u_int fw_flg;			/* Flags word */
+    u_int fw_flg;			/* Operational Flags word */
 #define IP_FW_MAX_PORTS	10		/* A reasonable maximum */
 	union {
 	u_short fw_pts[IP_FW_MAX_PORTS];	/* Array of port numbers to match */
@@ -62,9 +62,16 @@
 #define IP_FW_ICMPTYPES_DIM	(IP_FW_ICMPTYPES_MAX / (sizeof(unsigned) * 8))
 	unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */
 	} fw_uar;
+    u_int fw_ipflg;			/* IP flags word */
     u_char fw_ipopt,fw_ipnopt;		/* IP options set/unset */
+    u_short fw_iplen, fw_ipid;		/* IP length, identification */
+    u_char fw_iptos, fw_ipntos;		/* IP type of service set/unset */
+    u_char fw_ipttl;			/* IP time to live */
+    u_int fw_ipver:4;			/* IP version */
     u_char fw_tcpopt,fw_tcpnopt;	/* TCP options set/unset */
     u_char fw_tcpf,fw_tcpnf;		/* TCP flags set/unset */
+    u_int32_t fw_tcpseq, fw_tcpack;	/* TCP sequence and acknowledgement */
+    u_short fw_tcpwin;			/* TCP window size */
     long timestamp;			/* timestamp (tv_sec) of last match */
     union ip_fw_if fw_in_if, fw_out_if;	/* Incoming and outgoing interfaces */
     union {
@@ -206,6 +213,26 @@
 #define IP_FW_F_CHECK_S	0x10000000	/* check state	 			*/
 
 #define IP_FW_F_MASK	0x1FFFFFFF	/* All possible flag bits mask		*/
+
+/* 
+ * Flags for the 'fw_ipflg' field, for comparing values of ip and its protocols.
+ */
+#define IP_FW_IF_TCPOPT	0x00000001      /* tcp options			*/
+#define IP_FW_IF_TCPFLG	0x00000002      /* tcp flags			*/
+#define IP_FW_IF_TCPSEQ	0x00000004      /* tcp sequence number		*/
+#define IP_FW_IF_TCPACK	0x00000008      /* tcp acknowledgement number	*/
+#define IP_FW_IF_TCPWIN	0x00000010      /* tcp window size		*/
+#define IP_FW_IF_TCPMSK	0x0000001f      /* mask of all tcp values	*/
+
+#define IP_FW_IF_IPOPT	0x00000100	/* ip options			*/
+#define IP_FW_IF_IPLEN	0x00000200	/* ip length			*/
+#define IP_FW_IF_IPID	0x00000400	/* ip identification		*/
+#define IP_FW_IF_IPTOS	0x00000800	/* ip type of service		*/
+#define IP_FW_IF_IPTTL	0x00001000	/* ip time to live		*/
+#define IP_FW_IF_IPVER	0x00002000	/* ip version			*/
+#define IP_FW_IF_IPMSK	0x00003f00	/* mask of all ip values	*/
+
+#define IP_FW_IF_MSK	0x0000ffff	/* All possible bits mask	*/
 
 /*
  * For backwards compatibility with rules specifying "via iface" but

----- End forwarded message -----


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ipfw" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000926230846.H34501>