/* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-1999 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 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. */ #include #include #if defined(_MSC_VER) && _MSC_VER < 1600 # include "uv-private/stdint-msvc2008.h" #else # include #endif #include "uv.h" #include "uv-common.h" static const uv_err_t uv_eafnosupport_ = { UV_EAFNOSUPPORT, 0 }; static const uv_err_t uv_enospc_ = { UV_ENOSPC, 0 }; static const uv_err_t uv_einval_ = { UV_EINVAL, 0 }; static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size); static uv_err_t inet_ntop6(const unsigned char *src, char *dst, size_t size); static uv_err_t inet_pton4(const char *src, unsigned char *dst); static uv_err_t inet_pton6(const char *src, unsigned char *dst); uv_err_t uv_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: return uv_eafnosupport_; } /* NOTREACHED */ } static uv_err_t 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"]; int l; #ifndef _WIN32 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); #else l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); #endif if (l <= 0 || (size_t) l >= size) { return uv_enospc_; } strncpy(dst, tmp, size); dst[size - 1] = '\0'; return uv_ok_; } static uv_err_t 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[sizeof(struct in6_addr) / sizeof(uint16_t)]; 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 < (int) sizeof(struct in6_addr); 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 < (int) ARRAY_SIZE(words); 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 < (int) ARRAY_SIZE(words); 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 == 7 && words[7] != 0x0001) || (best.len == 5 && words[5] == 0xffff))) { uv_err_t err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)); if (err.code != UV_OK) return err; tp += strlen(tp); break; } tp += sprintf(tp, "%x", words[i]); } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) *tp++ = ':'; *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((size_t)(tp - tmp) > size) { return uv_enospc_; } strcpy(dst, tmp); return uv_ok_; } uv_err_t uv_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: return uv_eafnosupport_; } /* NOTREACHED */ } static uv_err_t inet_pton4(const char *src, unsigned char *dst) { static const char digits[] = "0123456789"; int saw_digit, octets, ch; unsigned char tmp[sizeof(struct in_addr)], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { unsigned int nw = *tp * 10 + (pch - digits); if (saw_digit && *tp == 0) return uv_einval_; if (nw > 255) return uv_einval_; *tp = nw; if (!saw_digit) { if (++octets > 4) return uv_einval_; saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return uv_einval_; *++tp = 0; saw_digit = 0; } else return uv_einval_; } if (octets < 4) return uv_einval_; memcpy(dst, tmp, sizeof(struct in_addr)); return uv_ok_; } static uv_err_t inet_pton6(const char *src, unsigned char *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, seen_xdigits; unsigned int val; memset((tp = tmp), '\0', sizeof tmp); endp = tp + sizeof tmp; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return uv_einval_; 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 uv_einval_; continue; } if (ch == ':') { curtok = src; if (!seen_xdigits) { if (colonp) return uv_einval_; colonp = tp; continue; } else if (*src == '\0') { return uv_einval_; } if (tp + sizeof(uint16_t) > endp) return uv_einval_; *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; seen_xdigits = 0; val = 0; continue; } if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) { uv_err_t err = inet_pton4(curtok, tp); if (err.code == 0) { tp += sizeof(struct in_addr); seen_xdigits = 0; break; /*%< '\\0' was seen by inet_pton4(). */ } } return uv_einval_; } if (seen_xdigits) { if (tp + sizeof(uint16_t) > endp) return uv_einval_; *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 uv_einval_; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return uv_einval_; memcpy(dst, tmp, sizeof tmp); return uv_ok_; }