From simon@comsys.ntu-kpi.kiev.ua  Mon Feb  6 06:50:02 2006
Return-Path: <simon@comsys.ntu-kpi.kiev.ua>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 3775716A422
	for <FreeBSD-gnats-submit@freebsd.org>; Mon,  6 Feb 2006 06:50:02 +0000 (GMT)
	(envelope-from simon@comsys.ntu-kpi.kiev.ua)
Received: from comsys.ntu-kpi.kiev.ua (comsys.ntu-kpi.kiev.ua [195.245.194.142])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 9EE0B43D5C
	for <FreeBSD-gnats-submit@freebsd.org>; Mon,  6 Feb 2006 06:49:29 +0000 (GMT)
	(envelope-from simon@comsys.ntu-kpi.kiev.ua)
Received: from pm513-1.comsys.ntu-kpi.kiev.ua (pm513-1.comsys.ntu-kpi.kiev.ua [10.18.52.101])
	(authenticated bits=0)
	by comsys.ntu-kpi.kiev.ua (8.12.10/8.12.10) with ESMTP id k1671IVO041886
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL)
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 6 Feb 2006 09:01:19 +0200 (EET)
Received: by pm513-1.comsys.ntu-kpi.kiev.ua (Postfix, from userid 1001)
	id C71535C021; Mon,  6 Feb 2006 08:49:09 +0200 (EET)
Message-Id: <20060206064909.GA762@pm513-1.comsys.ntu-kpi.kiev.ua>
Date: Mon, 6 Feb 2006 08:49:09 +0200
From: Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To: FreeBSD-gnats-submit@freebsd.org
Subject: [patch] almost rewritten inet_network(3) function

>Number:         92880
>Category:       kern
>Synopsis:       [libc] [patch] almost rewritten inet_network(3) function
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-net
>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:  Tue Oct 23 08:40:00 UTC 2012
>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:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: brucec 
Responsible-Changed-When: Mon Mar 23 21:35:59 UTC 2009 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=92880 

From: Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/92880: [libc] [patch] almost rewritten inet_network(3)
 function
Date: Fri, 21 Jan 2011 16:12:49 +0200

 My previous modification had one typo and did not work correctly
 for IPv4 addresses given in `.' donation in hexadecimal form.
 
 Here another one update:
 
 1. Test program that shows difference between implementation of
    inet_network(3) from 9-CURRENT and my implementation.
 
 2. Diff for the src/lib/libc/inet/inet_network.c file.
 
 Look on output from the test program ("<---" shows different values):
 
 STRING			INET_NETWORK	INET_NETWORK_NEW
 "0x12"			0x00000012	0x00000012
 "127.1"			0x00007f01	0x00007f01
 "127.1.2.3"		0x7f010203	0x7f010203
 "0x123456"		INADDR_NONE	INADDR_NONE
 "0x12.0x34"		0x00001234	0x00001234
 "0x12.0x345"		INADDR_NONE	INADDR_NONE
 "1.2.3.4.5"		INADDR_NONE	INADDR_NONE
 "1..3.4"		INADDR_NONE	INADDR_NONE
 "."			INADDR_NONE	INADDR_NONE
 "1."			INADDR_NONE	INADDR_NONE
 ".1"			INADDR_NONE	INADDR_NONE
 "0x"			0x00000000	INADDR_NONE	<---
 "0"			0x00000000	0x00000000
 "01.02.07.077"		0x0102073f	0x0102073f
 "0x1.23.045.0"		0x01172500	0x01172500
 ""			INADDR_NONE	INADDR_NONE
 " "			INADDR_NONE	INADDR_NONE
 " f"			INADDR_NONE	INADDR_NONE
 "bar"			INADDR_NONE	INADDR_NONE
 "1.2bar"		INADDR_NONE	INADDR_NONE
 "1."			INADDR_NONE	INADDR_NONE
 "=CA=C3=D5=CB=C5=CE"		INADDR_NONE	INADDR_NONE
 "255.255.255.255"	INADDR_NONE	INADDR_NONE
 "x"			INADDR_NONE	INADDR_NONE
 "0X12"			0x00000012	0x00000012
 "078"			INADDR_NONE	INADDR_NONE
 "1 bar"			0x00000001	INADDR_NONE	<---
 "127.0xabcd"		INADDR_NONE	INADDR_NONE
 "128"			0x00000080	0x00000080
 "0.1.2"			0x00000102	0x00000102
 "0xff.010.23.0xa0"	0xff0817a0	0xff0817a0
 "x10"			0x00000010	INADDR_NONE	<---
 "X20"			0x00000020	INADDR_NONE	<---
 "x10.x20"		0x00001020	INADDR_NONE	<---
 "4294967297"		0x00000001	INADDR_NONE	<---
 "0x10000000f"		0x0000000f	INADDR_NONE	<---
 "040000000003"		0x00000003	INADDR_NONE	<---
 
 Test program:
 
 diff -ruNp inet_network_test.orig/Makefile inet_network_test/Makefile
 --- inet_network_test.orig/Makefile	1970-01-01 03:00:00.000000000 +0300
 +++ inet_network_test/Makefile	2011-01-21 12:48:48.000000000 +0200
 @@ -0,0 +1,9 @@
 +PROG=3Dinet_network
 +
 +NO_MAN=3Dtrue
 +
 +WARNS=3D6
 +
 +DEBUG_FLAGS=3D-g
 +
 +.include <bsd.prog.mk>
 diff -ruNp inet_network_test.orig/inet_network.c inet_network_test/inet_n=
 etwork.c
 --- inet_network_test.orig/inet_network.c	1970-01-01 03:00:00.000000000 +=
 0300
 +++ inet_network_test/inet_network.c	2011-01-21 15:29:47.000000000 +0200
 @@ -0,0 +1,105 @@
 +#include <sys/types.h>
 +#include <sys/socket.h>
 +
 +#include <netinet/in.h>
 +#include <arpa/inet.h>
 +
 +#include <ctype.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +
 +static in_addr_t
 +inet_network_new(const char *s)
 +{
 +	u_int base, dots;
 +	in_addr_t res, val;
 +	u_char c;
 +	char got_data;
 +
 +	res =3D 0;
 +	dots =3D 0;
 +	for (;;) {
 +		val =3D 0;
 +		got_data =3D 0;
 +		if (*s =3D=3D '0') {
 +			s++;
 +			if (*s =3D=3D 'x' || *s =3D=3D 'X') {
 +				s++;
 +				base =3D 16;
 +			} else {
 +				base =3D 8;
 +				got_data =3D 1;
 +			}
 +		} else
 +			base =3D 10;
 +		while ((c =3D *s) !=3D '\0') {
 +			if (isdigit(c)) {
 +				if (base =3D=3D 8 && c > '7')
 +					return (INADDR_NONE);
 +				val =3D val * base + c - '0';
 +			} else if (base =3D=3D 16 && isxdigit(c))
 +				val =3D (val << 4) + c + 10 -
 +				    (islower(c) ? 'a' : 'A');
 +			else
 +				break;
 +			if (val > 0xff)
 +				return (INADDR_NONE);
 +			s++;
 +			got_data =3D 1;
 +		}
 +		if (!got_data)
 +			return (INADDR_NONE);
 +		if (dots !=3D 0)
 +			res <<=3D 8;
 +		res |=3D val;
 +		if (c !=3D '.')
 +			break;
 +		if (++dots =3D=3D 4)
 +			return (INADDR_NONE);
 +		s++;
 +	}
 +	return (c =3D=3D '\0' ? res : INADDR_NONE);
 +}
 +
 +int
 +main(void)
 +{
 +	const char *const addr_str_tbl[] =3D {
 +	    "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", "", " ", " f", "bar",
 +	    "1.2bar", "1.", "=CA=C3=D5=CB=C5=CE", "255.255.255.255", "x", "0X12=
 ", "078",
 +	    "1 bar", "127.0xabcd", "128", "0.1.2", "0xff.010.23.0xa0",
 +	    "x10", "X20", "x10.x20", "4294967297", "0x10000000f",
 +	    "040000000003", NULL };
 +	const char *const *addr_str;
 +	size_t len;
 +	in_addr_t addr1, addr2;
 +
 +	printf("STRING\t\t\tINET_NETWORK\tINET_NETWORK_NEW\n");
 +	for (addr_str =3D addr_str_tbl; *addr_str !=3D NULL; ++addr_str) {
 +		printf("\"%s\"", *addr_str);
 +		len =3D strlen(*addr_str) + 2;
 +		if (len < 8)
 +			printf("\t\t\t");
 +		else if (len < 16)
 +			printf("\t\t");
 +		else
 +			printf("\t");
 +		addr1 =3D inet_network(*addr_str);
 +		if (addr1 =3D=3D INADDR_NONE)
 +			printf("INADDR_NONE\t");
 +		else
 +			printf("0x%08x\t", addr1);
 +		addr2 =3D inet_network_new(*addr_str);
 +		if (addr2 =3D=3D INADDR_NONE)
 +			printf("INADDR_NONE");
 +		else
 +			printf("0x%08x", addr2);
 +		if (addr1 !=3D addr2)
 +			printf("\t<---");
 +		printf("\n");
 +	}
 +	return (0);
 +}
 
 Diff for src/lib/libc/inet/inet_network.c:
 
 --- inet_network.c.orig	2008-01-15 00:55:20.000000000 +0200
 +++ inet_network.c	2011-01-21 15:58:17.000000000 +0200
 @@ -48,57 +48,56 @@ __FBSDID("$FreeBSD: src/lib/libc/inet/in
   * network numbers.
   */
  in_addr_t
 -inet_network(cp)
 -	const char *cp;
 +inet_network(const char *s)
  {
 -	in_addr_t val, base, n;
 -	char c;
 -	in_addr_t parts[4], *pp =3D parts;
 -	int i, digit;
 +	u_int base, dots;
 +	in_addr_t res, val;
 +	u_char c;
 +	char got_data;
 =20
 -again:
 -	val =3D 0; base =3D 10; digit =3D 0;
 -	if (*cp =3D=3D '0')
 -		digit =3D 1, base =3D 8, cp++;
 -	if (*cp =3D=3D 'x' || *cp =3D=3D 'X')
 -		base =3D 16, cp++;
 -	while ((c =3D *cp) !=3D 0) {
 -		if (isdigit((unsigned char)c)) {
 -			if (base =3D=3D 8U && (c =3D=3D '8' || c =3D=3D '9'))
 +	res =3D 0;
 +	dots =3D 0;
 +	for (;;) {
 +		val =3D 0;
 +		got_data =3D 0;
 +		if (*s =3D=3D '0') {
 +			s++;
 +			if (*s =3D=3D 'x' || *s =3D=3D 'X') {
 +				s++;
 +				base =3D 16;
 +			} else {
 +				base =3D 8;
 +				got_data =3D 1;
 +			}
 +		} else
 +			base =3D 10;
 +		while ((c =3D *s) !=3D '\0') {
 +			if (isdigit(c)) {
 +				if (base =3D=3D 8 && c > '7')
 +					return (INADDR_NONE);
 +				val =3D val * base + c - '0';
 +			} else if (base =3D=3D 16 && isxdigit(c))
 +				val =3D (val << 4) + c + 10 -
 +				    (islower(c) ? 'a' : 'A');
 +			else
 +				break;
 +			if (val > 0xff)
  				return (INADDR_NONE);
 -			val =3D (val * base) + (c - '0');
 -			cp++;
 -			digit =3D 1;
 -			continue;
 +			s++;
 +			got_data =3D 1;
  		}
 -		if (base =3D=3D 16U && isxdigit((unsigned char)c)) {
 -			val =3D (val << 4) +
 -			      (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
 -			cp++;
 -			digit =3D 1;
 -			continue;
 -		}
 -		break;
 -	}
 -	if (!digit)
 -		return (INADDR_NONE);
 -	if (pp >=3D parts + 4 || val > 0xffU)
 -		return (INADDR_NONE);
 -	if (*cp =3D=3D '.') {
 -		*pp++ =3D val, cp++;
 -		goto again;
 -	}
 -	if (*cp && !isspace(*cp&0xff))
 -		return (INADDR_NONE);
 -	*pp++ =3D val;
 -	n =3D pp - parts;
 -	if (n > 4U)
 -		return (INADDR_NONE);
 -	for (val =3D 0, i =3D 0; i < n; i++) {
 -		val <<=3D 8;
 -		val |=3D parts[i] & 0xff;
 +		if (!got_data)
 +			return (INADDR_NONE);
 +		if (dots !=3D 0)
 +			res <<=3D 8;
 +		res |=3D val;
 +		if (c !=3D '.')
 +			break;
 +		if (++dots =3D=3D 4)
 +			return (INADDR_NONE);
 +		s++;
  	}
 -	return (val);
 +	return (c =3D=3D '\0' ? res : INADDR_NONE);
  }
 =20
  /*

From: Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/92880: [libc] [patch] almost rewritten inet_network(3)
 function
Date: Mon, 24 Jan 2011 14:56:25 +0200

 Since all '=' were changed to '=3D' in previous email, here is the copy
 of diff for the inet_network.c file.
 
 --- inet_network.c.orig	2008-01-15 00:55:20.000000000 +0200
 +++ inet_network.c	2011-01-21 15:58:17.000000000 +0200
 @@ -48,57 +48,56 @@ __FBSDID("$FreeBSD: src/lib/libc/inet/in
   * network numbers.
   */
  in_addr_t
 -inet_network(cp)
 -	const char *cp;
 +inet_network(const char *s)
  {
 -	in_addr_t val, base, n;
 -	char c;
 -	in_addr_t parts[4], *pp = parts;
 -	int i, digit;
 +	u_int base, dots;
 +	in_addr_t res, val;
 +	u_char c;
 +	char got_data;
  
 -again:
 -	val = 0; base = 10; digit = 0;
 -	if (*cp == '0')
 -		digit = 1, base = 8, cp++;
 -	if (*cp == 'x' || *cp == 'X')
 -		base = 16, cp++;
 -	while ((c = *cp) != 0) {
 -		if (isdigit((unsigned char)c)) {
 -			if (base == 8U && (c == '8' || c == '9'))
 +	res = 0;
 +	dots = 0;
 +	for (;;) {
 +		val = 0;
 +		got_data = 0;
 +		if (*s == '0') {
 +			s++;
 +			if (*s == 'x' || *s == 'X') {
 +				s++;
 +				base = 16;
 +			} else {
 +				base = 8;
 +				got_data = 1;
 +			}
 +		} else
 +			base = 10;
 +		while ((c = *s) != '\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) + c + 10 -
 +				    (islower(c) ? 'a' : 'A');
 +			else
 +				break;
 +			if (val > 0xff)
  				return (INADDR_NONE);
 -			val = (val * base) + (c - '0');
 -			cp++;
 -			digit = 1;
 -			continue;
 +			s++;
 +			got_data = 1;
  		}
 -		if (base == 16U && isxdigit((unsigned char)c)) {
 -			val = (val << 4) +
 -			      (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
 -			cp++;
 -			digit = 1;
 -			continue;
 -		}
 -		break;
 -	}
 -	if (!digit)
 -		return (INADDR_NONE);
 -	if (pp >= parts + 4 || val > 0xffU)
 -		return (INADDR_NONE);
 -	if (*cp == '.') {
 -		*pp++ = val, cp++;
 -		goto again;
 -	}
 -	if (*cp && !isspace(*cp&0xff))
 -		return (INADDR_NONE);
 -	*pp++ = val;
 -	n = pp - parts;
 -	if (n > 4U)
 -		return (INADDR_NONE);
 -	for (val = 0, i = 0; i < n; i++) {
 -		val <<= 8;
 -		val |= parts[i] & 0xff;
 +		if (!got_data)
 +			return (INADDR_NONE);
 +		if (dots != 0)
 +			res <<= 8;
 +		res |= val;
 +		if (c != '.')
 +			break;
 +		if (++dots == 4)
 +			return (INADDR_NONE);
 +		s++;
  	}
 -	return (val);
 +	return (c == '\0' ? res : INADDR_NONE);
  }
  
  /*

From: Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To: bug-followup@FreeBSD.org
Cc:  
Subject: kern/92880: [libc] [patch] almost rewritten inet_network(3) function
Date: Tue, 23 Oct 2012 11:36:04 +0300

 I optimized inet_network() again.
 
 Difference between implementation of inet_network(3) from 9.1-PRERELEASE
 and my implementation.
 
 STRING			INET_NETWORK	INET_NETWORK_NEW
 "0x12"			0x00000012	0x00000012
 "127.1"			0x00007f01	0x00007f01
 "127.1.2.3"		0x7f010203	0x7f010203
 "0x123456"		INADDR_NONE	INADDR_NONE
 "0x12.0x34"		0x00001234	0x00001234
 "0x12.0x345"		INADDR_NONE	INADDR_NONE
 "1.2.3.4.5"		INADDR_NONE	INADDR_NONE
 "1..3.4"		INADDR_NONE	INADDR_NONE
 "."			INADDR_NONE	INADDR_NONE
 "1."			INADDR_NONE	INADDR_NONE
 ".1"			INADDR_NONE	INADDR_NONE
 "0x"			0x00000000	INADDR_NONE	<---
 "0"			0x00000000	0x00000000
 "01.02.07.077"		0x0102073f	0x0102073f
 "0x1.23.045.0"		0x01172500	0x01172500
 ""			INADDR_NONE	INADDR_NONE
 " "			INADDR_NONE	INADDR_NONE
 " f"			INADDR_NONE	INADDR_NONE
 "bar"			INADDR_NONE	INADDR_NONE
 "1.2bar"		INADDR_NONE	INADDR_NONE
 "1."			INADDR_NONE	INADDR_NONE
 "=CA=C3=D5=CB=C5=CE"		INADDR_NONE	INADDR_NONE
 "255.255.255.255"	INADDR_NONE	INADDR_NONE
 "x"			INADDR_NONE	INADDR_NONE
 "0X12"			0x00000012	0x00000012
 "078"			INADDR_NONE	INADDR_NONE
 "1 bar"			0x00000001	INADDR_NONE	<---
 "127.0xabcd"		INADDR_NONE	INADDR_NONE
 "128"			0x00000080	0x00000080
 "0.1.2"			0x00000102	0x00000102
 "0xff.010.23.0xa0"	0xff0817a0	0xff0817a0
 "x10"			0x00000010	INADDR_NONE	<---
 "X20"			0x00000020	INADDR_NONE	<---
 "x10.x20"		0x00001020	INADDR_NONE	<---
 "4294967297"		0x00000001	INADDR_NONE	<---
 "0x10000000f"		0x0000000f	INADDR_NONE	<---
 "040000000003"		0x00000003	INADDR_NONE	<---
 
 #include <sys/types.h>
 #include <sys/socket.h>
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
 #include <ctype.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 static in_addr_t
 inet_network_new(const char *s)
 {
 	u_int d, base, dots;
 	in_addr_t addr, byte;
 	u_char c;
 	bool flag;
 
 	addr =3D 0;
 	dots =3D 0;
 	for (;; ++s) {
 		byte =3D 0;
 		flag =3D false;
 		if (*s =3D=3D '0') {
 			++s;
 			if (*s =3D=3D 'x' || *s =3D=3D 'X') {
 				++s;
 				base =3D 16;
 			} else {
 				base =3D 8;
 				flag =3D true;
 			}
 		} else
 			base =3D 10;
 		for (; (c =3D *s) !=3D '\0'; ++s) {
 			d =3D digittoint(c);
 			if (c !=3D '0' && (d =3D=3D 0 || d >=3D base))
 				break;
 			byte =3D byte * base + d;
 			if (byte > UINT8_MAX)
 				return (INADDR_NONE);
 			flag =3D true;
 		}
 		if (!flag)
 			return (INADDR_NONE);
 		addr =3D (addr << 8) | byte;
 		if (c !=3D '.')
 			break;
 		if (++dots =3D=3D 4)
 			return (INADDR_NONE);
 	}
 	return (c =3D=3D '\0' ? addr : INADDR_NONE);
 }
 
 int
 main(void)
 {
 	const char *const addr_str_tbl[] =3D {
 	    "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", "", " ", " f", "bar",
 	    "1.2bar", "1.", "=CA=C3=D5=CB=C5=CE", "255.255.255.255", "x", "0X12"=
 , "078",
 	    "1 bar", "127.0xabcd", "128", "0.1.2", "0xff.010.23.0xa0",
 	    "x10", "X20", "x10.x20", "4294967297", "0x10000000f",
 	    "040000000003", NULL };
 	const char *const *addr_str;
 	size_t len;
 	in_addr_t addr1, addr2;
 
 	printf("STRING\t\t\tINET_NETWORK\tINET_NETWORK_NEW\n");
 	for (addr_str =3D addr_str_tbl; *addr_str !=3D NULL; ++addr_str) {
 		printf("\"%s\"", *addr_str);
 		len =3D strlen(*addr_str) + 2;
 		if (len < 8)
 			printf("\t\t\t");
 		else if (len < 16)
 			printf("\t\t");
 		else
 			printf("\t");
 		addr1 =3D inet_network(*addr_str);
 		if (addr1 =3D=3D INADDR_NONE)
 			printf("INADDR_NONE\t");
 		else
 			printf("0x%08x\t", addr1);
 		addr2 =3D inet_network_new(*addr_str);
 		if (addr2 =3D=3D INADDR_NONE)
 			printf("INADDR_NONE");
 		else
 			printf("0x%08x", addr2);
 		if (addr1 !=3D addr2)
 			printf("\t<---");
 		printf("\n");
 	}
 	return (0);
 }
>Unformatted:
