diff --git a/src/network/stk_ipv6.cpp b/src/network/stk_ipv6.cpp index e6adf848c..2ce00aea9 100644 --- a/src/network/stk_ipv6.cpp +++ b/src/network/stk_ipv6.cpp @@ -24,13 +24,6 @@ # include # include -extern "C" -{ -#ifndef InetPtopN - WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, PCSTR pszAddrString, PVOID pAddrBuf); -#endif -} - #else # include # include @@ -52,6 +45,157 @@ extern "C" #include #include +// ============================================================================ +// For Windows XP support +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +static int +stk_inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + tp = tmp; + *tp = 0; + while((ch = *src++) != '\0') + { + const char *pch; + + pch = strchr(digits, ch); + if(pch) + { + unsigned int val = *tp * 10 + (unsigned int)(pch - digits); + + if(saw_digit && *tp == 0) + return (0); + if(val > 255) + return (0); + *tp = (unsigned char)val; + 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, INADDRSZ); + return (1); +} + +static int +stk_inet_pton6(const char *src, void *dest) +{ + unsigned char *dst = (unsigned char*)dest; + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *curtok; + int ch, saw_xdigit; + size_t 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 *xdigits; + const char *pch; + + pch = strchr((xdigits = xdigits_l), ch); + if(!pch) + pch = strchr((xdigits = xdigits_u), ch); + if(pch != NULL) + { + val <<= 4; + val |= (pch - xdigits); + if(++saw_xdigit > 4) + return (0); + continue; + } + if(ch == ':') + { + curtok = src; + if(!saw_xdigit) + { + if(colonp) + return (0); + colonp = tp; + continue; + } + if(tp + INT16SZ > 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) && + stk_inet_pton4(curtok, tp) > 0) + { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by stk_inet_pton4(). */ + } + return (0); + } + if(saw_xdigit) + { + if(tp + 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 ssize_t n = tp - colonp; + ssize_t 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); +} + // ============================================================================ // Android STK seems to crash when using inet_ntop so we copy it from linux static const char * @@ -283,7 +427,7 @@ void andIPv6(struct in6_addr* ipv6, const struct in6_addr* mask) extern "C" int64_t upperIPv6(const char* ipv6) { struct in6_addr v6_in; - if (inet_pton(AF_INET6, ipv6, &v6_in) != 1) + if (stk_inet_pton6(ipv6, &v6_in) != 1) return 0; uint64_t result = 0; unsigned shift = 56; @@ -303,13 +447,13 @@ extern "C" int insideIPv6CIDR(const char* ipv6_cidr, const char* ipv6_in) if (mask_location == NULL) return 0; struct in6_addr v6_in; - if (inet_pton(AF_INET6, ipv6_in, &v6_in) != 1) + if (stk_inet_pton6(ipv6_in, &v6_in) != 1) return 0; char ipv6[INET6_ADDRSTRLEN] = {}; memcpy(ipv6, ipv6_cidr, mask_location - ipv6_cidr); struct in6_addr cidr; - if (inet_pton(AF_INET6, ipv6, &cidr) != 1) + if (stk_inet_pton6(ipv6, &cidr) != 1) return 0; int mask_length = atoi(mask_location + 1);