X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FIPAddress.cpp;h=75c2ff3d50e6cd7563abdca611ff583da4a53114;hb=refs%2Ftags%2Fv2017.07.31.00;hp=016421043b338cda7de166263cbd7b761e098b1b;hpb=ce64f0f685111ac24c7a321ea56d0c3524621df1;p=folly.git diff --git a/folly/IPAddress.cpp b/folly/IPAddress.cpp index 01642104..75c2ff3d 100644 --- a/folly/IPAddress.cpp +++ b/folly/IPAddress.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,16 @@ * limitations under the License. */ -#include "IPAddress.h" +#include #include #include #include #include +#include #include +#include using std::ostream; using std::string; @@ -44,6 +46,10 @@ void toAppend(IPAddress addr, fbstring* result) { result->append(addr.str()); } +bool IPAddress::validate(StringPiece ip) { + return IPAddressV4::validate(ip) || IPAddressV6::validate(ip); +} + // public static IPAddressV4 IPAddress::createIPv4(const IPAddress& addr) { if (addr.isV4()) { @@ -75,29 +81,43 @@ CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr, if (elemCount == 0 || // weird invalid string elemCount > 2) { // invalid string (IP/CIDR/extras) - throw IPAddressFormatException("Invalid ipSlashCidr specified. ", - "Expected IP/CIDR format, got ", - "'", ipSlashCidr, "'"); + throw IPAddressFormatException(to( + "Invalid ipSlashCidr specified. ", + "Expected IP/CIDR format, got ", + "'", + ipSlashCidr, + "'")); } IPAddress subnet(vec.at(0)); - uint8_t cidr = (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128); + auto cidr = + uint8_t((defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128)); if (elemCount == 2) { try { cidr = to(vec.at(1)); } catch (...) { - throw IPAddressFormatException("Mask value ", - "'", vec.at(1), "' not a valid mask"); + throw IPAddressFormatException( + to("Mask value ", "'", vec.at(1), "' not a valid mask")); } } if (cidr > subnet.bitCount()) { - throw IPAddressFormatException("CIDR value '", cidr, "' ", - "is > network bit count ", - "'", subnet.bitCount(), "'"); + throw IPAddressFormatException(to( + "CIDR value '", + cidr, + "' ", + "is > network bit count ", + "'", + subnet.bitCount(), + "'")); } return std::make_pair(applyMask ? subnet.mask(cidr) : subnet, cidr); } +// public static +std::string IPAddress::networkToString(const CIDRNetwork& network) { + return network.first.str() + "/" + folly::to(network.second); +} + // public static IPAddress IPAddress::fromBinary(ByteRange bytes) { if (bytes.size() == 4) { @@ -106,8 +126,8 @@ IPAddress IPAddress::fromBinary(ByteRange bytes) { return IPAddress(IPAddressV6::fromBinary(bytes)); } else { string hexval = detail::Bytes::toHex(bytes.data(), bytes.size()); - throw IPAddressFormatException("Invalid address with hex value ", - "'", hexval, "'"); + throw IPAddressFormatException( + to("Invalid address with hex value ", "'", hexval, "'")); } } @@ -133,7 +153,8 @@ IPAddress::IPAddress(StringPiece addr) { string ip = addr.str(); // inet_pton() needs NUL-terminated string auto throwFormatException = [&](const string& msg) { - throw IPAddressFormatException("Invalid IP '", ip, "': ", msg); + throw IPAddressFormatException( + to("Invalid IP '", ip, "': ", msg)); }; if (ip.size() < 2) { @@ -146,12 +167,20 @@ IPAddress::IPAddress(StringPiece addr) // need to check for V4 address second, since IPv4-mapped IPv6 addresses may // contain a period if (ip.find(':') != string::npos) { - in6_addr ipAddr; - if (inet_pton(AF_INET6, ip.c_str(), &ipAddr) != 1) { - throwFormatException("inet_pton failed for V6 address"); + struct addrinfo* result; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + if (!getaddrinfo(ip.c_str(), nullptr, &hints, &result)) { + struct sockaddr_in6* ipAddr = (struct sockaddr_in6*)result->ai_addr; + addr_ = IPAddressV46(IPAddressV6(*ipAddr)); + family_ = AF_INET6; + freeaddrinfo(result); + } else { + throwFormatException("getsockaddr failed for V6 address"); } - addr_ = IPAddressV46(IPAddressV6(ipAddr)); - family_ = AF_INET6; } else if (ip.find('.') != string::npos) { in_addr ipAddr; if (inet_pton(AF_INET, ip.c_str(), &ipAddr) != 1) { @@ -181,7 +210,7 @@ IPAddress::IPAddress(const sockaddr* addr) } case AF_INET6: { const sockaddr_in6 *v6addr = reinterpret_cast(addr); - addr_.ipV6Addr = IPAddressV6(v6addr->sin6_addr); + addr_.ipV6Addr = IPAddressV6(*v6addr); break; } default: @@ -330,13 +359,13 @@ bool operator==(const IPAddress& addr1, const IPAddress& addr2) { } } // addr1 is v4 mapped v6 address, addr2 is v4 - if (addr1.isIPv4Mapped()) { + if (addr1.isIPv4Mapped() && addr2.isV4()) { if (IPAddress::createIPv4(addr1) == addr2.asV4()) { return true; } } // addr2 is v4 mapped v6 address, addr1 is v4 - if (addr2.isIPv4Mapped()) { + if (addr2.isIPv4Mapped() && addr1.isV4()) { if (IPAddress::createIPv4(addr2) == addr1.asV4()) { return true; } @@ -391,7 +420,18 @@ IPAddress::longestCommonPrefix(const CIDRNetwork& one, const CIDRNetwork& two) { } else { throw std::invalid_argument("Unknown address family"); } - return {IPAddress(0), 0}; } -} // folly +[[noreturn]] void IPAddress::asV4Throw() const { + auto fam = detail::familyNameStr(family()); + throw InvalidAddressFamilyException(to( + "Can't convert address with family ", fam, " to AF_INET address")); +} + +[[noreturn]] void IPAddress::asV6Throw() const { + auto fam = detail::familyNameStr(family()); + throw InvalidAddressFamilyException(to( + "Can't convert address with family ", fam, " to AF_INET6 address")); +} + +} // namespace folly