diff options
Diffstat (limited to 'compat/inet_pton.c')
-rw-r--r-- | compat/inet_pton.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/compat/inet_pton.c b/compat/inet_pton.c new file mode 100644 index 0000000..32ee887 --- /dev/null +++ b/compat/inet_pton.c @@ -0,0 +1,209 @@ +#include "inet_aton.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Copyright (C) 1996-2001 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. +*/ + +#ifndef HAVE_INET_PTON +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 + +/* int + * isc_net_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) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton(int af, + const char *src, + void *dst) { + switch ( af ) { + case AF_INET: + return(inet_pton4(src, dst)); +#if HAVE_IPV6 + case AF_INET6: + return(inet_pton6(src, dst)); +#endif + default: + return 0; + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +int +inet_pton4(src, dst) +const char *src; +unsigned char *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ( (ch = *src++) != '\0' ) { + const char *pch; + + if ( (pch = strchr(digits, ch)) != NULL ) { + unsigned int new = *tp * 10 + (pch - digits); + + if ( new > 255 ) + return(0); + *tp = new; + if ( ! saw_digit ) { + if ( ++octets > 4 ) + return(0); + saw_digit = 1; + } + } else if ( ch == '.' && saw_digit ) { + if ( octets == 4 ) + return(0); + *++tp = 0; + saw_digit = 0; + } else + return(0); + } + if ( octets < 4 ) + return(0); + memcpy(dst, tmp, NS_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. + */ +#if HAVE_IPV6 +int +inet_pton6(src, dst) +const char *src; +unsigned char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_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; + } + if ( tp + NS_INT16SZ > endp ) + return(0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if ( ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0 ) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return(0); + } + if ( saw_xdigit ) { + if ( tp + NS_INT16SZ > 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; + + 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, NS_IN6ADDRSZ); + return(1); +} +#endif + +#endif /* HAVE_INET_PTON */ + +#ifdef __cplusplus +} /* end extern "C" */ +#endif |