Subject: Re: ip_nat MSS clamping
To: Andrey Petrov <petrov@netbsd.org>
From: Martin Husemann <martin@duskware.de>
List: tech-net
Date: 06/03/2002 20:40:28
> This is quite dangerous construction for any platform with strict
> alignment.

True.

Index: ip_nat.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_nat.c,v
retrieving revision 1.48
diff -c -u -r1.48 ip_nat.c
--- ip_nat.c	2002/05/02 17:13:29	1.48
+++ ip_nat.c	2002/06/03 18:37:24
@@ -1147,34 +1147,45 @@
 	fr_info_t *fin;
 	u_short *csump;
 {
-	uint8_t *cp;
+	uint8_t *cp, *ep;
 	uint32_t opt, mss, sumd;
+	uint16_t netmss;
 	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) {
-			case TCPOPT_MAXSEG:
-				++cp;
-				mss = (uint32_t)ntohs(*(short *)cp);
+		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;
+			if (opt == TCPOPT_MAXSEG) {
+				if (advance != 4)
+					break;
+				memcpy(&netmss, &cp[2], 2);
+				mss = (uint32_t)ntohs(netmss);
 				if (mss > maxmss) {
-					*(short *)cp = htons((short)(maxmss));
+					netmss = htons((short)(maxmss));
+					memcpy(&cp[2], &netmss, 2);
 					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;
 			}
+			cp += advance;
 		}
 	}
 }