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