X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FIPAddressV6.cpp;h=be909315f147b2c35ecb970062f4d4bfd179e25e;hb=79869083465aabfcb9d9abd7f31ecfe812e3464b;hp=29450f4b08ac6c35c5a7ee398343ac1195a75381;hpb=9b6eade1f3afa32adc9f7d56739b119f53168ccb;p=folly.git diff --git a/folly/IPAddressV6.cpp b/folly/IPAddressV6.cpp index 29450f4b..be909315 100644 --- a/folly/IPAddressV6.cpp +++ b/folly/IPAddressV6.cpp @@ -25,6 +25,19 @@ #include #include +#if !_WIN32 +#include +#else +// Because of the massive pain that is libnl, this can't go into the socket +// portability header as you can't include and in +// the same translation unit without getting errors -_-... +#include // @manual +#include // @manual + +// Alias the max size of an interface name to what posix expects. +#define IFNAMSIZ IF_NAMESIZE +#endif + using std::ostream; using std::string; @@ -64,8 +77,7 @@ bool IPAddressV6::validate(StringPiece ip) { } // public default constructor -IPAddressV6::IPAddressV6() { -} +IPAddressV6::IPAddressV6() {} // public string constructor IPAddressV6::IPAddressV6(StringPiece addr) { @@ -74,7 +86,7 @@ IPAddressV6::IPAddressV6(StringPiece addr) { // Allow addresses surrounded in brackets if (ip.size() < 2) { throw IPAddressFormatException( - to("Invalid IPv6 address '", ip, "': address too short")); + sformat("Invalid IPv6 address '{}': address too short", ip)); } if (ip.front() == '[' && ip.back() == ']') { ip = ip.substr(1, ip.size() - 2); @@ -92,34 +104,22 @@ IPAddressV6::IPAddressV6(StringPiece addr) { scope_ = uint16_t(ipAddr->sin6_scope_id); freeaddrinfo(result); } else { - throw IPAddressFormatException( - to("Invalid IPv6 address '", ip, "'")); + throw IPAddressFormatException(sformat("Invalid IPv6 address '{}'", ip)); } } // in6_addr constructor -IPAddressV6::IPAddressV6(const in6_addr& src) - : addr_(src) -{ -} +IPAddressV6::IPAddressV6(const in6_addr& src) : addr_(src) {} // sockaddr_in6 constructor IPAddressV6::IPAddressV6(const sockaddr_in6& src) - : addr_(src.sin6_addr) - , scope_(uint16_t(src.sin6_scope_id)) -{ -} + : addr_(src.sin6_addr), scope_(uint16_t(src.sin6_scope_id)) {} // ByteArray16 constructor -IPAddressV6::IPAddressV6(const ByteArray16& src) - : addr_(src) -{ -} +IPAddressV6::IPAddressV6(const ByteArray16& src) : addr_(src) {} // link-local constructor -IPAddressV6::IPAddressV6(LinkLocalTag, MacAddress mac) - : addr_(mac) { -} +IPAddressV6::IPAddressV6(LinkLocalTag, MacAddress mac) : addr_(mac) {} IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) { // The link-local address uses modified EUI-64 format, @@ -138,20 +138,23 @@ IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) { Optional IPAddressV6::getMacAddressFromLinkLocal() const { // Returned MacAddress must be constructed from a link-local IPv6 address. - if (!(addr_.bytes_[0] == 0xfe && addr_.bytes_[1] == 0x80 && - addr_.bytes_[2] == 0x00 && addr_.bytes_[3] == 0x00 && - addr_.bytes_[4] == 0x00 && addr_.bytes_[5] == 0x00 && - addr_.bytes_[6] == 0x00 && addr_.bytes_[7] == 0x00 && - addr_.bytes_[11] == 0xff && addr_.bytes_[12] == 0xfe)) { + if (!isLinkLocal()) { return folly::none; } - // The link-local address uses modified EUI-64 format, + return getMacAddressFromEUI64(); +} + +Optional IPAddressV6::getMacAddressFromEUI64() const { + if (!(addr_.bytes_[11] == 0xff && addr_.bytes_[12] == 0xfe)) { + return folly::none; + } + // The auto configured address uses modified EUI-64 format, // See RFC 4291 sections 2.5.1, 2.5.6, and Appendix A std::array bytes; - // Step 1: first 8 bytes are fe:80:00:00:00:00:00:00, and can be stripped + // Step 1: first 8 bytes are network prefix, and can be stripped // Step 2: invert the universal/local (U/L) flag (bit 7) bytes[0] = addr_.bytes_[8] ^ 0x02; - // Step 3: copy thhese bytes are they are + // Step 3: copy these bytes as they are bytes[1] = addr_.bytes_[9]; bytes[2] = addr_.bytes_[10]; // Step 4: strip bytes (0xfffe), which are bytes_[11] and bytes_[12] @@ -164,9 +167,8 @@ Optional IPAddressV6::getMacAddressFromLinkLocal() const { void IPAddressV6::setFromBinary(ByteRange bytes) { if (bytes.size() != 16) { - throw IPAddressFormatException(to( - "Invalid IPv6 binary data: length must ", - "be 16 bytes, got ", + throw IPAddressFormatException(sformat( + "Invalid IPv6 binary data: length must be 16 bytes, got {}", bytes.size())); } memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr)); @@ -217,9 +219,8 @@ static inline uint16_t unpack(uint8_t lobyte, uint8_t hibyte) { // given a src string, unpack count*2 bytes into dest // dest must have as much storage as count -static inline void unpackInto(const unsigned char* src, - uint16_t* dest, - size_t count) { +static inline void +unpackInto(const unsigned char* src, uint16_t* dest, size_t count) { for (size_t i = 0, hi = 1, lo = 0; i < count; i++) { dest[i] = unpack(src[hi], src[lo]); hi += 2; @@ -230,11 +231,11 @@ static inline void unpackInto(const unsigned char* src, // public IPAddressV4 IPAddressV6::getIPv4For6To4() const { if (!is6To4()) { - throw IPAddressV6::TypeError(format( - "Invalid IP '{}': not a 6to4 address", str()).str()); + throw IPAddressV6::TypeError( + sformat("Invalid IP '{}': not a 6to4 address", str())); } // convert 16x8 bytes into first 4x16 bytes - uint16_t ints[4] = {0,0,0,0}; + uint16_t ints[4] = {0, 0, 0, 0}; unpackInto(bytes(), ints, 4); // repack into 4x8 union { @@ -270,7 +271,7 @@ bool IPAddressV6::isIPv4Mapped() const { // public IPAddressV6::Type IPAddressV6::type() const { // convert 16x8 bytes into first 2x16 bytes - uint16_t ints[2] = {0,0}; + uint16_t ints[2] = {0, 0}; unpackInto(bytes(), ints, 2); if ((((uint32_t)ints[0] << 16) | ints[1]) == IPAddressV6::PREFIX_TEREDO) { @@ -286,8 +287,7 @@ IPAddressV6::Type IPAddressV6::type() const { // public string IPAddressV6::toJson() const { - return format( - "{{family:'AF_INET6', addr:'{}', hash:{}}}", str(), hash()).str(); + return sformat("{{family:'AF_INET6', addr:'{}', hash:{}}}", str(), hash()); } // public @@ -310,18 +310,18 @@ bool IPAddressV6::inSubnet(StringPiece cidrNetwork) const { auto subnetInfo = IPAddress::createNetwork(cidrNetwork); auto addr = subnetInfo.first; if (!addr.isV6()) { - throw IPAddressFormatException(to( - "Address '", addr.toJson(), "' ", "is not a V6 address")); + throw IPAddressFormatException( + sformat("Address '{}' is not a V6 address", addr.toJson())); } return inSubnetWithMask(addr.asV6(), fetchMask(subnetInfo.second)); } // public -bool IPAddressV6::inSubnetWithMask(const IPAddressV6& subnet, - const ByteArray16& cidrMask) const { - const ByteArray16 mask = detail::Bytes::mask(toByteArray(), cidrMask); - const ByteArray16 subMask = detail::Bytes::mask(subnet.toByteArray(), - cidrMask); +bool IPAddressV6::inSubnetWithMask( + const IPAddressV6& subnet, + const ByteArray16& cidrMask) const { + const auto mask = detail::Bytes::mask(toByteArray(), cidrMask); + const auto subMask = detail::Bytes::mask(subnet.toByteArray(), cidrMask); return (mask == subMask); } @@ -337,11 +337,11 @@ bool IPAddressV6::isLoopback() const { bool IPAddressV6::isRoutable() const { return - // 2000::/3 is the only assigned global unicast block - inBinarySubnet({{0x20, 0x00}}, 3) || - // ffxe::/16 are global scope multicast addresses, - // which are eligible to be routed over the internet - (isMulticast() && getMulticastScope() == 0xe); + // 2000::/3 is the only assigned global unicast block + inBinarySubnet({{0x20, 0x00}}, 3) || + // ffxe::/16 are global scope multicast addresses, + // which are eligible to be routed over the internet + (isMulticast() && getMulticastScope() == 0xe); } bool IPAddressV6::isLinkLocalBroadcast() const { @@ -382,11 +382,24 @@ IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const { // addresses DCHECK(!isMulticast()); - uint8_t bytes[16] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }; - bytes[13] = addr_.bytes_[13]; - bytes[14] = addr_.bytes_[14]; - bytes[15] = addr_.bytes_[15]; + uint8_t bytes[16] = { + 0xff, + 0x02, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0xff, + addr_.bytes_[13], + addr_.bytes_[14], + addr_.bytes_[15], + }; return IPAddressV6::fromBinary(ByteRange(bytes, 16)); } @@ -395,7 +408,7 @@ IPAddressV6 IPAddressV6::mask(size_t numBits) const { static const auto bits = bitCount(); if (numBits > bits) { throw IPAddressFormatException( - to("numBits(", numBits, ") > bitCount(", bits, ")")); + sformat("numBits({}) > bitCount({})", numBits, bits)); } ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_); return IPAddressV6(ba); @@ -403,30 +416,30 @@ IPAddressV6 IPAddressV6::mask(size_t numBits) const { // public string IPAddressV6::str() const { - char buffer[INET6_ADDRSTRLEN] = {0}; - sockaddr_in6 sock = toSockAddr(); - int error = getnameinfo( - (sockaddr*)&sock, - sizeof(sock), - buffer, - INET6_ADDRSTRLEN, - nullptr, - 0, - NI_NUMERICHOST); - if (!error) { - string ip(buffer); - return ip; - } else { - throw IPAddressFormatException(to( - "Invalid address with hex ", - "'", + char buffer[INET6_ADDRSTRLEN + IFNAMSIZ + 1]; + + if (!inet_ntop(AF_INET6, toAddr().s6_addr, buffer, INET6_ADDRSTRLEN)) { + throw IPAddressFormatException(sformat( + "Invalid address with hex '{}' with error {}", detail::Bytes::toHex(bytes(), 16), - "%", - sock.sin6_scope_id, - "'", - " , with error ", - gai_strerror(error))); + strerror(errno))); } + + auto scopeId = getScopeId(); + if (scopeId != 0) { + auto len = strlen(buffer); + buffer[len] = '%'; + + auto errsv = errno; + if (!if_indextoname(scopeId, buffer + len + 1)) { + // if we can't map the if because eg. it no longer exists, + // append the if index instead + snprintf(buffer + len + 1, IFNAMSIZ, "%u", scopeId); + } + errno = errsv; + } + + return string(buffer); } // public @@ -456,8 +469,9 @@ string IPAddressV6::toInverseArpaName() const { uint8_t IPAddressV6::getNthMSByte(size_t byteIndex) const { const auto highestIndex = byteCount() - 1; if (byteIndex > highestIndex) { - throw std::invalid_argument(to("Byte index must be <= ", - to(highestIndex), " for addresses of type :", + throw std::invalid_argument(sformat( + "Byte index must be <= {} for addresses of type: {}", + highestIndex, detail::familyNameStr(AF_INET6))); } return bytes()[byteIndex]; @@ -493,9 +507,10 @@ CIDRNetworkV6 IPAddressV6::longestCommonPrefix( } // protected -bool IPAddressV6::inBinarySubnet(const std::array addr, - size_t numBits) const { +bool IPAddressV6::inBinarySubnet( + const std::array addr, + size_t numBits) const { auto masked = mask(numBits); return (std::memcmp(addr.data(), masked.bytes(), 2) == 0); } -} // folly +} // namespace folly