bool ParseIPv4(char *str, uint32_t *out_addr, char **next /*NULL*/) { return ParseIPv4(const_cast<const char *>(str), out_addr, const_cast<const char **>(next) ); }
bool sockAddrBase::FromString(const char *str) { // This is called from the constructor, so it must work with an uninitialized // structure. init(Addr::Invalid); // First determine if it is IPv4 or IPv6 str = SkipWhite(str); const char *firstColon = strchr(str, ':'); const char *firstDot = strchr(str, '.'); const char *firstPercent = strchr(str, '%'); if (!firstDot && !firstColon) return false; if (!firstColon || (firstDot && firstDot < firstColon)) { // IPv4 uint16_t port; uint32_t addr; if (firstPercent) return false; if (!firstColon) { if (!ParseIPv4(str, &addr, &str)) return false; str = SkipWhite(str); if (*str != '\0') return false; init(Addr::IPv4); getIPv4Storage()->sin_addr.s_addr = addr; return true; } // Has dots and a colon, presumably its an IPv4 with port if (!m_allowPort) return false; if (!ParseIPv4Port(str, &addr, &port)) return false; init(Addr::IPv4); getIPv4Storage()->sin_addr.s_addr = addr; SetPort(port); return true; } // Not IPv4 if (!firstColon || (firstPercent && (firstPercent < firstColon))) return false; else { // IPv6 sockaddr_in6 tmp = sockaddr_in6(); if (firstPercent || *str == '[') { char addrStr[INET6_ADDRSTRLEN]; const char *last, *lastBrace = NULL; if (*str == '[') { ++str; last = lastBrace = strchr(str, ']'); if (!lastBrace) return false; } if (firstPercent) { if (lastBrace && lastBrace < firstPercent + 2) return false; last = firstPercent; } if (last == str || size_t(last - str) >= sizeof(addrStr)) return false; memcpy(addrStr, str, last - str); addrStr[last - str] = '\0'; if (1 != inet_pton(AF_INET6, addrStr, &tmp.sin6_addr)) return false; if (firstPercent) { // ONLY allow interface (scope) for link local addresses (for now) // Otherwise address comparison breaks for regular addresses, one of which has a // scope. if (!IN6_IS_ADDR_LINKLOCAL(&tmp.sin6_addr)) return false; if (lastBrace) { // already checked that (lastBrace-firstPercent >= 2) memcpy(addrStr, firstPercent + 1, lastBrace - (firstPercent + 1)); addrStr[lastBrace - (firstPercent + 1)] = '\0'; last = addrStr; } else last = firstPercent + 1; unsigned int index = if_nametoindex(last); if (index == 0 || index > UINT32_MAX) return false; tmp.sin6_scope_id = uint32_t(index); } if (lastBrace) { last = lastBrace + 1; if (*last != ':') { last = SkipWhite(last); if (*last != '\0') return false; } else { // We have a port uint64_t val; if (!m_allowPort) return false; ++last; if (!StringToInt(last, val)) return false; if (val > UINT16_MAX) return false; tmp.sin6_port = htons(uint16_t(val)); } } } else { // no [] and no % so the string can be parsed directly if (1 != inet_pton(AF_INET6, str, &tmp.sin6_addr)) return false; } // Set the actual value init(Addr::IPv6); sockaddr_in6 *storage = getIPv6Storage(); storage->sin6_addr = tmp.sin6_addr; storage->sin6_port = tmp.sin6_port; storage->sin6_scope_id = tmp.sin6_scope_id; return true; } }