From 7525450fb6d79d7371375d7f710ba4fe484494b3 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 30 Nov 2014 19:59:24 +0300 Subject: Add inet_ntop() and inet_pton() replacements for Windows. These are implemented only on Vista and later. For XP sake, import replacement functions from liblwres included in ISC BIND distribution. --- src/common/net/inet_ntop.h | 179 ++++++++++++++++++++++++++++++++++++++++ src/common/net/inet_pton.h | 200 +++++++++++++++++++++++++++++++++++++++++++++ src/common/net/net.c | 19 ++++- 3 files changed, 394 insertions(+), 4 deletions(-) create mode 100644 src/common/net/inet_ntop.h create mode 100644 src/common/net/inet_pton.h diff --git a/src/common/net/inet_ntop.h b/src/common/net/inet_ntop.h new file mode 100644 index 0000000..922d1ec --- /dev/null +++ b/src/common/net/inet_ntop.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1996-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/*! \file lwinetntop.c + */ + +/* + * 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 const char *inet_ntop4(const unsigned char *src, char *dst, + size_t size); +static const char *inet_ntop6(const unsigned char *src, char *dst, + size_t size); + +/*! char * + * lwres_net_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +static const char * +os_inet_ntop(int af, const void *src, char *dst, size_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + /* errno = EAFNOSUPPORT; */ + return (NULL); + } + /* NOTREACHED */ +} + +/*! const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a unsigned char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const unsigned char *src, char *dst, size_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof("255.255.255.255")]; + size_t len; + + len = Q_snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + if (len >= size) { + /* errno = ENOSPC; */ + return (NULL); + } + strcpy(dst, tmp); + + return (dst); +} + +/*! const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(const unsigned char *src, char *dst, size_t size) +{ + /*! + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp; + struct { + int base, len; + } best, cur; + unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof(words)); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src + 12, tp, + sizeof(tmp) - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += sprintf(tp, "%x", words[i]); /* XXX */ + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + /* errno = ENOSPC; */ + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} diff --git a/src/common/net/inet_pton.h b/src/common/net/inet_pton.h new file mode 100644 index 0000000..a3c9aaf --- /dev/null +++ b/src/common/net/inet_pton.h @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011-2014 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/*! \file lwinetpton.c + */ + +/* + * 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); +static int inet_pton6(const char *src, unsigned char *dst); + +/*! + * int + * lwres_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) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +static int os_inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + /* errno = EAFNOSUPPORT */; + return (-1); + } + /* 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. + */ +static int inet_pton4(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; + + new += (unsigned int)(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); + /* + * "clang --analyse" generates warnings using: + * *++tp = 0; + */ + tp++; + *tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memmove(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. + */ +static int inet_pton6(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, seen_xdigits; + 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; + seen_xdigits = 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 (++seen_xdigits > 4) + return (0); + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + 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; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + seen_xdigits = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (seen_xdigits) { + 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 = (int)(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); + memmove(dst, tmp, NS_IN6ADDRSZ); + return (1); +} diff --git a/src/common/net/net.c b/src/common/net/net.c index 19fe13f..8b65d72 100644 --- a/src/common/net/net.c +++ b/src/common/net/net.c @@ -202,6 +202,17 @@ static void NET_SockadrToNetadr(const struct sockaddr_storage *s, netadr_t *a) } } +#ifdef _WIN32 +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#include "inet_ntop.h" +#include "inet_pton.h" +#else +#define os_inet_ntop inet_ntop +#define os_inet_pton inet_pton +#endif + char *NET_BaseAdrToString(const netadr_t *a) { static char s[MAX_QPATH]; @@ -213,7 +224,7 @@ char *NET_BaseAdrToString(const netadr_t *a) return strcpy(s, "loopback"); case NA_IP: case NA_BROADCAST: - if (inet_ntop(AF_INET, &a->ip, s, sizeof(s))) + if (os_inet_ntop(AF_INET, &a->ip, s, sizeof(s))) return s; else return strcpy(s, ""); @@ -227,7 +238,7 @@ char *NET_BaseAdrToString(const netadr_t *a) s, sizeof(s), NULL, 0, NI_NUMERICHOST) == 0) return s; } - if (inet_ntop(AF_INET6, &a->ip, s, sizeof(s))) + if (os_inet_ntop(AF_INET6, &a->ip, s, sizeof(s))) return s; else return strcpy(s, ""); @@ -281,8 +292,8 @@ qboolean NET_StringPairToAdr(const char *host, const char *port, netadr_t *a) if (net_enable_ipv6->integer < 1) hints.ai_family = AF_INET; - if (inet_pton(AF_INET, host, buf) == 1 || - inet_pton(AF_INET6, host, buf) == 1) + if (os_inet_pton(AF_INET, host, buf) == 1 || + os_inet_pton(AF_INET6, host, buf) == 1) hints.ai_flags |= AI_NUMERICHOST; #ifdef AI_NUMERICSERV -- cgit v1.2.3