Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Jun 2000 07:55:03 +0930
From:      Ian West <ian@niw.com.au>
To:        freebsd-ipfw@freebsd.org
Subject:   A couple of possible changes to ipfw....
Message-ID:  <20000620075502.I400@rose.niw.com.au>

next in thread | raw e-mail | index | archive | help
I passed this briefly by Luigi, and the suggestion was to work up a
patch and pass it by the ipfw mailing list, so here it is. (two issues
are addressed in these patches actually) The first provides another rule
option for ipfw allowing a match to be made against the ip_tos byte,
which is used also for diffserv. The new option requires the addition of
two bytes to the ip_fw structure, the first being a 'mask' byte, the
second being a 'match' byte. Operation is very simple, if the
ip_tos_mask byte is non-zero, (a zero mask is silly, there is nothing to
match afterwards :-), the mask is applied to the ip_tos byte, the result
is then compared with the ip_tos_match value. If the result does not
match, then we continue on to the next rule. The kernel change for this
involves adding 2 bytes to the ip_fw structure, and a single compare
statement. The changes to ipfw.c are to allow these values to be set.
These changes have been running on a couple of machines locally for a
few days now without problems. Testing has been restricted so far to
logging packets with low delay set.

ipfw add 10 count log ip from any to any tos 0x1f:0x10

This seems to do pretty much what I expected, logging only ntp traffic,
and interactive traffic from ssh etc...

The second part of this patch is to make ipfw tee work as I believe the
origional aim was, to generate a copy of the packet, which is sent to a
tee port, but without disrupting normal flow. This appears to work for
me, and has been in operation for some time across several hosts. This
particular patch has been in operation for about 3 months on various
machines. (Both current and stable). Uptime on these machines has been >
90 days. (ie, since rebooting them with the patch applied.) If someone
could check/confirm that the htons for length and offset are correct I
would appreciate it, it seems to work for me, but I am not sure if my
test ap is doing the wrong thing. (ie should the packet come out of the
kernel in network order or host order...)

The section tagged @@ -1299,8 +1305,20 @@ can be independantly ignored
if you do not wish to affect the ipfw tee function.

The next change I would like to make, and would be interested to hear
feedback on is to define a new 'action' under ipfw which would change
the ip tos/ds byte. Use would be very simlar, in that we would have two
bytes, the first being a mask, the second being an 'or' value. (In
effect, reset/set values). Syntax would be something along the lines of

ipfw add 10 tag 0x1f:0x80 tcp from any 23 to any
(Which would tag outbound telnet traffic.)

Not sure if the 'command' should be 'tag', 'tos', or maybe even 'ds' ??

This is similar in fucntion to the changes that many (if not most)
routers allow these days using diffserv policies. It would be useful
though to be able to pre-classify traffic for diffserv streams based on
(for example) uid. A more specific example is where you have maybe a
background update process for a database, which runs periodically, and
does large transfers, but with low priority. A rule such as

ipfw add 10 tag 0x1f:0x80 tcp from any to any uid database
(This is untested, I have not yet done the patches for tagging packets)

should in effect allow traffic for this process to be handled on a
gateway box (or even a router) using diffserv with no knowledge of the
protocol or application. 

(Enough waffle, hopefully the idea is clear enough ;-)

The down side of this is it does involve 'changing' packets. Which I
believe will involve recalculating at least header checksums. I am not
yet sure of the impact on stuff like ipsec auth etc... This is stuff I
will need to test.

Can anybody see any good reason NOT to do this ? Otherwise I will go
ahead and work on it, and post patches for review once I have something
working.

Thanks to all who read this :-)
Regards,
Ian West

Index: sbin/ipfw/ipfw.c
===================================================================
RCS file: /cvs/freebsd/src/sbin/ipfw/ipfw.c,v
retrieving revision 1.86
diff -u -r1.86 ipfw.c
--- sbin/ipfw/ipfw.c	2000/06/18 02:48:19	1.86
+++ sbin/ipfw/ipfw.c	2000/06/18 13:17:08
@@ -362,6 +362,10 @@
 		}
 	}
 
+	if (chain->fw_tos_mask) {
+		printf(" tos %#x:%#x", chain->fw_tos_mask, chain->fw_tos_match);
+	}
+	
 	if (chain->fw_flg & IP_FW_F_UID) {
 		struct passwd *pwd = getpwuid(chain->fw_uid);
 
@@ -828,6 +832,7 @@
 "    src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
 "    dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
 "  extras:\n"
+"    tos {mask:match}\n"
 "    uid {user id}\n"
 "    gid {group id}\n"
 "    fragment     (may not be used with ports or tcpflags)\n"
@@ -1800,6 +1805,26 @@
 			if (grp == NULL)
 				show_usage("gid \"%s\" is nonexistant", *av);
 			rule.fw_gid = grp->gr_gid;
+			ac--; av++;
+			continue;
+		}
+		/* For the moment, we will accept either tos or ds as commands */
+		if (!strncmp(*av,"tos",strlen(*av)) || !strncmp(*av,"ds",strlen(*av))) {
+			char *end;
+			unsigned int mask,match;
+			mask=match=0;
+			ac--; av++;
+			if (!ac)
+				show_usage("``tos'' requires arguments");
+			mask = strtoul(*av, &end, 0);
+			if (*end == ':')
+				match = strtoul(++end, &end, 0);
+			else
+				show_usage("argument to ''tos'' should be mask:match (where mask and match are both numeric)");
+			if(*end != '\0')
+				show_usage("argument to ''tos'' should be mask:match (where mask and match are both numeric)");
+			rule.fw_tos_mask=mask;
+			rule.fw_tos_match=match;
 			ac--; av++;
 			continue;
 		}

Index: sys/netinet/ip_fw.c
===================================================================
RCS file: /cvs/freebsd/src/sys/netinet/ip_fw.c,v
retrieving revision 1.138
diff -u -r1.138 ip_fw.c
--- sys/netinet/ip_fw.c	2000/06/08 15:34:51	1.138
+++ sys/netinet/ip_fw.c	2000/06/18 13:04:24
@@ -914,6 +914,7 @@
 	struct ip_fw *f = NULL, *rule = NULL;
 	struct ip *ip = *pip;
 	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
+	u_char tos = 0;
 	u_short offset = 0 ;
 	u_short src_port = 0, dst_port = 0;
 	struct in_addr src_ip, dst_ip; /* XXX */
@@ -949,6 +950,7 @@
 	/*
 	 * Collect parameters into local variables for faster matching.
 	 */
+	tos = ip->ip_tos;
 	offset = (ip->ip_off & IP_OFFMASK);
 	{
 	    struct tcphdr *tcp;
@@ -1108,6 +1110,10 @@
 				continue;
 		}
 
+		/* Check tos/ds byte ONLY if mask is set in this rule */
+		if (f->fw_tos_mask && ((tos&f->fw_tos_mask) != f->fw_tos_match))
+			continue;
+		
 		/* Check IP options */
 		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
 			continue;
@@ -1299,8 +1305,20 @@
 			*cookie = f->fw_number;
 			return(f->fw_divert_port);
 		case IP_FW_F_TEE:
-			*cookie = f->fw_number;
-			return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
+			{
+				struct mbuf *clone;
+				struct ip *cip;
+				u_int16_t divert_cookie;
+				divert_cookie=ip_divert_cookie;
+				ip_divert_cookie = f->fw_number;
+				clone=m_dup(*m, M_DONTWAIT);
+				cip = mtod(clone, struct ip *);
+				HTONS(cip->ip_len);
+				HTONS(cip->ip_off);
+				divert_packet(clone,0,f->fw_divert_port);
+				ip_divert_cookie=divert_cookie;
+			}
+			continue;
 #endif
 		case IP_FW_F_SKIPTO: /* XXX check */
 			if ( f->next_rule_ptr )
Index: sys/netinet/ip_fw.h
===================================================================
RCS file: /cvs/freebsd/src/sys/netinet/ip_fw.h,v
retrieving revision 1.51
diff -u -r1.51 ip_fw.h
--- sys/netinet/ip_fw.h	2000/06/08 15:34:51	1.51
+++ sys/netinet/ip_fw.h	2000/06/18 11:47:24
@@ -73,6 +73,7 @@
 	u_short fu_pipe_nr;		/* queue number (option DUMMYNET) */
 	u_short fu_skipto_rule;		/* SKIPTO command rule number */
 	u_short fu_reject_code;		/* REJECT response code */
+	u_char fu_ds_mod[2];		/* Mask/Set data pair for tos byte change */
 	struct sockaddr_in fu_fwd_ip;
     } fw_un;
     u_char fw_prot;			/* IP protocol */
@@ -82,6 +83,8 @@
 	 * match all ports)
 	 */
     u_char fw_nports;
+    u_char fw_tos_mask;		/* Mask to apply to tos byte prior to compare */
+    u_char fw_tos_match;	/* Value to compare against tos byte after mask */
     void *pipe_ptr;                    /* flow_set ptr for dummynet pipe */
     void *next_rule_ptr ;              /* next rule in case of match */
     uid_t fw_uid;			/* uid to match */




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?20000620075502.I400>