Index | Thread | Search

From:
Florian Obser <florian@openbsd.org>
Subject:
inet_aton(3): fix long standing bug
To:
tech <tech@openbsd.org>
Date:
Mon, 26 Aug 2024 17:47:22 +0200

Download raw body.

Thread
It occurred to me that inet_aton(3) does not conform to section 2.3 of
RFC 761. I believe this is the case since 4.3bsd.

Now, we have replaced most uses of inet_aton(3) in base, but I think we
should still fix it, after all, config parsers in ports might still use
inet_aton(3) and we don't want config files to fail to load.

OK?

diff --git lib/libc/net/inet_addr.c lib/libc/net/inet_addr.c
index 62d46ad664f..5dcecb43769 100644
--- lib/libc/net/inet_addr.c
+++ lib/libc/net/inet_addr.c
@@ -85,7 +85,9 @@ inet_aton(const char *cp, struct in_addr *addr)
 	char c;
 	u_int parts[4];
 	u_int *pp = parts;
+	char *op;
 
+	op = cp;
 	c = *cp;
 	for (;;) {
 		/*
@@ -94,7 +96,7 @@ inet_aton(const char *cp, struct in_addr *addr)
 		 * 0x=hex, 0=octal, isdigit=decimal.
 		 */
 		if (!isdigit((unsigned char)c))
-			return (0);
+			goto lasttry;
 		val = 0; base = 10;
 		if (c == '0') {
 			c = *++cp;
@@ -125,7 +127,7 @@ inet_aton(const char *cp, struct in_addr *addr)
 			 *	a.b	(with b treated as 24 bits)
 			 */
 			if (pp >= parts + 3)
-				return (0);
+				goto lasttry;
 			*pp++ = val;
 			c = *++cp;
 		} else
@@ -136,7 +138,7 @@ inet_aton(const char *cp, struct in_addr *addr)
 	 */
 	if (c != '\0' &&
 	    (!isascii((unsigned char)c) || !isspace((unsigned char)c)))
-		return (0);
+		goto lasttry;
 	/*
 	 * Concoct the address according to
 	 * the number of parts specified.
@@ -145,31 +147,40 @@ inet_aton(const char *cp, struct in_addr *addr)
 	switch (n) {
 
 	case 0:
-		return (0);		/* initial nondigit */
+		goto lasttry;		/* initial nondigit */
 
 	case 1:				/* a -- 32 bits */
 		break;
 
 	case 2:				/* a.b -- 8.24 bits */
 		if ((val > 0xffffff) || (parts[0] > 0xff))
-			return (0);
+			goto lasttry;
 		val |= parts[0] << 24;
 		break;
 
 	case 3:				/* a.b.c -- 8.8.16 bits */
 		if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
-			return (0);
+			goto lasttry;
 		val |= (parts[0] << 24) | (parts[1] << 16);
 		break;
 
 	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
 		if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
-			return (0);
+			goto lasttry;
 		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
 		break;
 	}
+
 	if (addr)
 		addr->s_addr = htonl(val);
 	return (1);
+
+lasttry:
+	val = (in_addr_t)op;
+
+	if (addr)
+		addr->s_addr = htonl(val);
+	return (1);
+
 }
 DEF_WEAK(inet_aton);

-- 
In my defence, I have been left unsupervised.