diff options
author | green <green@FreeBSD.org> | 1999-10-31 04:07:56 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 1999-10-31 04:07:56 +0000 |
commit | 5e58dc63ee1fb4790892c28641e9c19e421705de (patch) | |
tree | aeeddd8b823863a86ab1fba7630e4972d0481f3e /lib/libc/net/inet_addr.c | |
parent | eaf14abb4fe809130e9575a14d2879ac56d87519 (diff) | |
download | FreeBSD-src-5e58dc63ee1fb4790892c28641e9c19e421705de.zip FreeBSD-src-5e58dc63ee1fb4790892c28641e9c19e421705de.tar.gz |
This is the new inet_addr/inet_aton with proper error checking. This
should close all outstanding PRs on incorrect inet_aton behavior, and
since it has a decent parsing routine, doesn't allow some hysterically
working behavior.
PR: 13628
Submitted by: Adrian Chadd <adrian@FreeBSD.org>
Diffstat (limited to 'lib/libc/net/inet_addr.c')
-rw-r--r-- | lib/libc/net/inet_addr.c | 134 |
1 files changed, 69 insertions, 65 deletions
diff --git a/lib/libc/net/inet_addr.c b/lib/libc/net/inet_addr.c index 3fac1ca..8998624 100644 --- a/lib/libc/net/inet_addr.c +++ b/lib/libc/net/inet_addr.c @@ -59,15 +59,19 @@ static char rcsid[] = "$FreeBSD$"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> + #include <netinet/in.h> #include <arpa/inet.h> + #include <ctype.h> +#include <errno.h> +#include <string.h> /* - * Ascii internet address interpretation routine. + * ASCII internet address interpretation routine. * The value returned is in network order. */ -u_long +u_long /* XXX should be struct in_addr :( */ inet_addr(cp) register const char *cp; { @@ -79,7 +83,7 @@ inet_addr(cp) } /* - * Check whether "cp" is a valid ascii representation + * Check whether "cp" is a valid ASCII representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * This replaces inet_addr, the return value from which @@ -90,91 +94,91 @@ inet_aton(cp, addr) register const char *cp; struct in_addr *addr; { - register u_long val; - register int base, n; - register char c; - u_int parts[4]; - register u_int *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. + u_long parts[4]; + u_long val; + char *c; + char *endptr; + int base, gotend, n; + + c = (char *)cp; + n = 0; + /* + * Run through the string, grabbing numbers until + * the end of the string, or some error + */ + gotend = 0; + while (!gotend) { + errno = 0; + val = strtoul(c, &endptr, 0); + + if (val == ERANGE) /* Fail completely if it overflowed. */ + return (0); + + /* + * If the whole string is invalid, endptr will equal + * c.. this way we can make sure someone hasn't + * gone '.12' or something which would get past + * the next check. */ - if (!isdigit(c)) + if (endptr == c) return (0); - val = 0; base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') - base = 16, c = *++cp; - else - base = 8; - } - for (;;) { - if (isascii(c) && isdigit(c)) { - val = (val * base) + (c - '0'); - c = *++cp; - } else if (base == 16 && isascii(c) && isxdigit(c)) { - val = (val << 4) | - (c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) + parts[n] = val; + c = endptr; + + /* Check the next character past the previous number's end */ + switch (*c) { + case '.' : + /* Make sure we only do 3 dots .. */ + if (n == 3) /* Whoops. Quit. */ return (0); - *pp++ = val; - c = *++cp; - } else + n++; + c++; break; + + case '\0' : + gotend = 1; + break; + + default: + /* Invalid character, so fail */ + return (0); + } + } - /* - * Check for trailing characters. - */ - if (c != '\0' && (!isascii(c) || !isspace(c))) - return (0); + /* * Concoct the address according to * the number of parts specified. */ - n = pp - parts + 1; - switch (n) { - case 0: - return (0); /* initial nondigit */ - - case 1: /* a -- 32 bits */ + switch (n) { + case 0: /* a -- 32 bits */ + /* + * Nothing is necessary here. Overflow checking was + * already done in strtoul(). + */ break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) + case 1: /* a.b -- 8.24 bits */ + if (val > 0xffffff || parts[0] > 0xff) return (0); val |= parts[0] << 24; break; - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) + case 2: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) + case 3: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || + parts[2] > 0xff) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } - if (addr) + + if (addr != NULL) addr->s_addr = htonl(val); return (1); } |