| Summary: | [libc] [patch] almost rewritten inet_network(3) function | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | Andrey Simonenko <simon> | ||||
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> | ||||
| Status: | Open --- | ||||||
| Severity: | Affects Only Me | Keywords: | patch | ||||
| Priority: | Normal | ||||||
| Version: | 6.0-STABLE | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
Responsible Changed From-To: freebsd-bugs->freebsd-net Over to maintainer(s). 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
/*
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);
}
/*
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);
}
For bugs matching the following criteria: Status: In Progress Changed: (is less than) 2014-06-01 Reset to default assignee and clear in-progress tags. Mail being skipped Keyword:
patch
or patch-ready
– in lieu of summary line prefix:
[patch]
* bulk change for the keyword
* summary lines may be edited manually (not in bulk).
Keyword descriptions and search interface:
<https://bugs.freebsd.org/bugzilla/describekeywords.cgi>
|
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