Subject: ip_nat MSS clamping
To: Darren Reed <darrenr@reed.wattle.id.au>
From: Jun-ichiro itojun Hagino <itojun@iijlab.net>
List: tech-net
Date: 06/03/2002 08:24:07
	sys/netinet/ip_nat.c has tcp option parsing bug in MSS clamping
	handling.
	- it does not stop at EOL
	- it does incorrect processing of NOP

	does the following look ok?

itojun


Index: ip_nat.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_nat.c,v
retrieving revision 1.48
diff -u -r1.48 ip_nat.c
--- ip_nat.c	2002/05/02 17:13:29	1.48
+++ ip_nat.c	2002/06/02 23:23:27
@@ -1147,34 +1147,46 @@
 	fr_info_t *fin;
 	u_short *csump;
 {
-	uint8_t *cp;
+	uint8_t *cp, *ep;
 	uint32_t opt, mss, sumd;
 	int hlen;
+	int advance;
 
 	hlen = tcp->th_off << 2;
 	if (hlen > sizeof(*tcp)) {
 		cp = (uint8_t *)tcp + sizeof(*tcp);
+		ep = cp + hlen;
 
-		while (hlen > 0) {
-			opt = *cp++;
-			switch(opt) {
+		while (cp < ep) {
+			opt = cp[0];
+			if (opt == TCPOPT_EOL)
+				break;
+			if (opt == TCPOPT_NOP) {
+				cp++;
+				continue;
+			}
+
+			if (&cp[1] > ep)
+				break;
+			advance = cp[1];
+			if (&cp[advance] > ep)
+				break;
+			switch (opt) {
 			case TCPOPT_MAXSEG:
-				++cp;
-				mss = (uint32_t)ntohs(*(short *)cp);
+				if (advance != 4)
+					break;
+				mss = (uint32_t)ntohs(*(short *)&cp[2]);
 				if (mss > maxmss) {
 					*(short *)cp = htons((short)(maxmss));
 					CALC_SUMD(mss, maxmss, sumd);
 					fix_outcksum(fin, csump, sumd);
 				}
-				hlen = 0;
 				break;
-			case TCPOPT_EOL:
-			case TCPOPT_NOP:
-				hlen--;
 			default:
-				hlen -= *cp;
-				cp += *cp - 2;
+				break;
 			}
+
+			cp += advance;
 		}
 	}
 }