bin/92880: [patch] almost rewritten inet_network(3) function

Andrey Simonenko simon at comsys.ntu-kpi.kiev.ua
Sun Feb 5 23:00:15 PST 2006


>Number:         92880
>Category:       bin
>Synopsis:       [patch] almost rewritten inet_network(3) function
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 06 07:00:14 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Andrey Simonenko
>Release:        FreeBSD 6.0-STABLE i386
>Organization:
>Environment:
>Description:

inet_network(3) function is not very safe, since it does not
make all checks before converting string to network address.

Rewritten version of inet_network() performs all checks (at least
which I expect to see) and according to Assembler code it takes
less space and should be a bit faster.

Rewritten version also does not allow white space character
at the end of parsed string.

>How-To-Repeat:

Here I insert a test program and output from this program (rewritten
version of inet_network() is called inet_network_new() here):

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


static in_addr_t
inet_network_new(const char *cp)
{
	u_char c;
	int got_data;
	u_int base, dots;
	in_addr_t res, val;

	res = 0;
	dots = 0;

again:
	val = 0;
	got_data = 0;
	if (*cp == '0') {
		cp++;
		if (*cp == 'x' || *cp == 'X') {
			cp++;
			base = 16;
		} else {
			base = 8;
			got_data = 1;
		}
	} else
		base = 10;
	while ((c = *cp) != '\0') {
		if (isdigit(c)) {
			if (base == 8 && c > '7')
				return (INADDR_NONE);
			val = val * base + c - '0';
		} else if (base == 16 && isxdigit(c))
			val = (val << 4) + 10 - (islower(c) ? 'a' : 'A');
		else
			break;
		if (val > 0xff)
			return (INADDR_NONE);
		cp++;
		got_data = 1;
	}
	if (!got_data)
		return (INADDR_NONE);
	if (dots != 0)
		res <<= 8;
	res |= val;
	if (c == '.') {
		if (++dots == 4)
			return (INADDR_NONE);
		cp++;
		goto again;
	}
	if (c != '\0')
		return (INADDR_NONE);
	return (res);
}

int
main(void)
{
	size_t	len;
	in_addr_t addr;
	const char **addr_ptr;
	const char *addr_tbl[] = {
	    "0x12", "127.1", "127.1.2.3", "0x123456", "0x12.0x34",
	    "0x12.0x345", "1.2.3.4.5", "1..3.4", ".", "1.", ".1", "0x",
	    "0", "01.02.07.077", "0x1.23.045.0", "", " ", "bar", "1.2bar",
	    "1.", "ÊÃÕËÅÎ", "255.255.255.255", "x", "0X12", "078",
	    "1 bar", "127.0xfff", NULL };

	printf("STRING\t\t\tINET_NETWORK\tINET_NETWORK_NEW\n");
	for (addr_ptr = addr_tbl; *addr_ptr != NULL; ++addr_ptr) {
		printf("\"%s\"", *addr_ptr);
		len = strlen(*addr_ptr) + 2;
		if (len < 8)
			printf("\t\t\t");
		else if (len < 16)
			printf("\t\t");
		else
			printf("\t");
		addr = inet_network(*addr_ptr);
		if (addr == INADDR_NONE)
			printf("INADDR_NONE\t");
		else
			printf("0x%08x\t", addr);
		addr = inet_network_new(*addr_ptr);
		if (addr == INADDR_NONE)
			printf("INADDR_NONE\n");
		else
			printf("0x%08x\n", addr);
	}

	return 0;
}

STRING			INET_NETWORK	INET_NETWORK_NEW
"0x12"			0x00000012	0x00000012
"127.1"			0x00007f01	0x00007f01
"127.1.2.3"		0x7f010203	0x7f010203
"0x123456"		0x00000056	INADDR_NONE
"0x12.0x34"		0x00001234	0x00001234
"0x12.0x345"		0x00001245	INADDR_NONE
"1.2.3.4.5"		INADDR_NONE	INADDR_NONE
"1..3.4"		0x01000304	INADDR_NONE
"."			0x00000000	INADDR_NONE
"1."			0x00000100	INADDR_NONE
".1"			0x00000001	INADDR_NONE
"0x"			0x00000000	INADDR_NONE
"0"			0x00000000	0x00000000
"01.02.07.077"		0x0102073f	0x0102073f
"0x1.23.045.0"		0x01172500	0x01172500
""			0x00000000	INADDR_NONE
" "			0x00000000	INADDR_NONE
"bar"			INADDR_NONE	INADDR_NONE
"1.2bar"		INADDR_NONE	INADDR_NONE
"1."			0x00000100	INADDR_NONE
"ÊÃÕËÅÎ"		INADDR_NONE	INADDR_NONE
"255.255.255.255"	INADDR_NONE	INADDR_NONE
"x"			0x00000000	INADDR_NONE
"0X12"			0x00000012	0x00000012
"078"			0x00000040	INADDR_NONE
"1 bar"			0x00000001	INADDR_NONE
"127.0xfff"		0x00007fff	INADDR_NONE


>Fix:

--- inet_network.c.orig	Fri Mar 22 23:52:29 2002
+++ inet_network.c	Sun Feb  5 22:21:14 2006
@@ -48,48 +48,58 @@
  * network numbers.
  */
 in_addr_t
-inet_network(cp)
-	const char *cp;
+inet_network(const char *cp)
 {
-	in_addr_t val, base, n;
-	char c;
-	in_addr_t parts[4], *pp = parts;
-	int i;
+	u_char c;
+	int got_data;
+	u_int base, dots;
+	in_addr_t res, val;
+
+	res = 0;
+	dots = 0;
 
 again:
-	val = 0; base = 10;
-	if (*cp == '0')
-		base = 8, cp++;
-	if (*cp == 'x' || *cp == 'X')
-		base = 16, cp++;
-	while ((c = *cp) != 0) {
-		if (isdigit((unsigned char)c)) {
-			val = (val * base) + (c - '0');
-			cp++;
-			continue;
-		}
-		if (base == 16 && isxdigit((unsigned char)c)) {
-			val = (val << 4) + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
+	val = 0;
+	got_data = 0;
+	if (*cp == '0') {
+		cp++;
+		if (*cp == 'x' || *cp == 'X') {
 			cp++;
-			continue;
+			base = 16;
+		} else {
+			base = 8;
+			got_data = 1;
 		}
-		break;
+	} else
+		base = 10;
+	while ((c = *cp) != '\0') {
+		if (isdigit(c)) {
+			if (base == 8 && c > '7')
+				return (INADDR_NONE);
+			val = val * base + c - '0';
+		} else if (base == 16 && isxdigit(c))
+			val = (val << 4) + 10 - (islower(c) ? 'a' : 'A');
+		else
+			break;
+		if (val > 0xff)
+			return (INADDR_NONE);
+		cp++;
+		got_data = 1;
 	}
-	if (*cp == '.') {
-		if (pp >= parts + 3)
+	if (!got_data)
+		return (INADDR_NONE);
+	if (dots != 0)
+		res <<= 8;
+	res |= val;
+	if (c == '.') {
+		if (++dots == 4)
 			return (INADDR_NONE);
-		*pp++ = val, cp++;
+		cp++;
 		goto again;
 	}
-	if (*cp && !isspace((unsigned char)*cp))
+	if (c != '\0')
 		return (INADDR_NONE);
-	*pp++ = val;
-	n = pp - parts;
-	for (val = 0, i = 0; i < n; i++) {
-		val <<= 8;
-		val |= parts[i] & 0xff;
-	}
-	return (val);
+	return (res);
 }
 
 /*
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list