Inet_pton is the official NetBSD address conversion, from the ASCII representation of the dot.quad IPv4 address or the colon-separated version of the IPv6 address to a binary internal value. I suspect it loses the ability to grasp 127.1 as the localhost address, but I'm not entirely sure. It does work considerably more reliably than the equivalent code in inet_addr.c which it replaces. It provides inet_aton() which is a bit more fragile and seemingly deprecated. Essential to the implementation of the OpenLDAP client tools. Notes: Sun Sep 2 01:38:02 EDT 2007 geoff seems redundant with ip(2) and the like. Reference: /n/sources/patch/sorry/ape_libbsd_inet_addr Date: Sat Mar 3 21:54:00 CET 2007 Signed-off-by: lucio@proxima.alt.za Reviewed-by: geoff --- /sys/src/ape/lib/bsd/inet_pton.c Thu Jan 1 00:00:00 1970 +++ /sys/src/ape/lib/bsd/inet_pton.c Sat Mar 3 21:47:28 2007 @@ -0,0 +1,320 @@ +/* $NetBSD: inet_pton.c,v 1.16 2000/02/07 18:51:02 itojun Exp $ */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 (const char *src, unsigned char *dst, int pton); +static int inet_pton6 (const char *src, unsigned char *dst); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(af, src, dst) + int af; + const char *src; + void *dst; +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst, 1)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst, pton) + * when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. + * when last arg is 1: inet_pton(). decimal dotted-quad only. + * return: + * 1 if `src' is a valid input, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +#define INADDRSZ (4) +static int +inet_pton4(src, dst, pton) + const char *src; + unsigned char *dst; + int pton; +{ + unsigned int val; + unsigned int digit; + int base, n; + unsigned char c; + unsigned int parts[4]; + unsigned int *pp = parts; + + c = *src; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++src; + if (c == 'x' || c == 'X') + base = 16, c = *++src; + else if (isdigit(c) && c != '9') + base = 8; + } + /* inet_pton() takes decimal only */ + if (pton && base != 10) + return (0); + for (;;) { + if (isdigit(c)) { + digit = c - '0'; + if (digit >= base) + break; + val = (val * base) + digit; + c = *++src; + } else if (base == 16 && isxdigit(c)) { + digit = c + 10 - (islower(c) ? 'a' : 'A'); + if (digit >= 16) + break; + val = (val << 4) | digit; + c = *++src; + } 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) + * a (with a treated as 32 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++src; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + /* inet_pton() takes dotted-quad only. it does not take shorthand. */ + if (pton && n != 4) + return (0); + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (parts[0] > 0xff || val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if ((parts[0] | parts[1]) > 0xff || val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if ((parts[0] | parts[1] | parts[2] | val) > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (dst) { + val = htonl(val); + memcpy(dst, &val, INADDRSZ); + } + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +#define IN6ADDRSZ (16) +static int +inet_pton6(src, dst) + const char *src; + unsigned char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } else if (*src == '\0') + return (0); + if (tp + 2 > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp, 1) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + 2 > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} + +/* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +unsigned long +inet_addr(cp) + register const char *cp; +{ + struct in_addr val; + + if (inet_pton4(cp, (unsigned char *)(void *)&val.s_addr, 0)) + return (val.s_addr); + return (INADDR_NONE); +} + +/* + * 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 + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) + register const char *cp; + struct in_addr *addr; +{ + return inet_pton4(cp, (unsigned char *)(void *)&addr->s_addr, 0); +}