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
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>