X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FIPAddressV6.cpp;h=5607a4bfcb37e61eef7d7f7b2e177a9594a4426a;hb=1d11ad7a0af6277ca6ed2ad147ac16a2e7ac3760;hp=915767b493d9a620b21e89780ee203150eac3c9a;hpb=ac31e5f5e80027418cb06a7718b6ade3cacad8bc;p=folly.git diff --git a/folly/IPAddressV6.cpp b/folly/IPAddressV6.cpp index 915767b4..5607a4bf 100644 --- a/folly/IPAddressV6.cpp +++ b/folly/IPAddressV6.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 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. @@ -23,6 +23,7 @@ #include #include #include +#include using std::ostream; using std::string; @@ -48,6 +49,20 @@ void toAppend(IPAddressV6 addr, fbstring* result) { result->append(addr.str()); } +bool IPAddressV6::validate(StringPiece ip) { + if (ip.size() > 0 && ip.front() == '[' && ip.back() == ']') { + ip = ip.subpiece(1, ip.size() - 2); + } + + constexpr size_t kStrMaxLen = INET6_ADDRSTRLEN; + std::array ip_cstr; + const size_t len = std::min(ip.size(), kStrMaxLen); + std::memcpy(ip_cstr.data(), ip.data(), len); + ip_cstr[len] = 0; + struct in6_addr addr; + return 1 == inet_pton(AF_INET6, ip_cstr.data(), &addr); +} + // public default constructor IPAddressV6::IPAddressV6() { } @@ -58,8 +73,8 @@ IPAddressV6::IPAddressV6(StringPiece addr) { // Allow addresses surrounded in brackets if (ip.size() < 2) { - throw IPAddressFormatException("Invalid IPv6 address '", ip, - "': address too short"); + throw IPAddressFormatException( + to("Invalid IPv6 address '", ip, "': address too short")); } if (ip.front() == '[' && ip.back() == ']') { ip = ip.substr(1, ip.size() - 2); @@ -74,10 +89,11 @@ IPAddressV6::IPAddressV6(StringPiece addr) { if (!getaddrinfo(ip.c_str(), nullptr, &hints, &result)) { struct sockaddr_in6* ipAddr = (struct sockaddr_in6*)result->ai_addr; addr_.in6Addr_ = ipAddr->sin6_addr; - scope_ = ipAddr->sin6_scope_id; + scope_ = uint16_t(ipAddr->sin6_scope_id); freeaddrinfo(result); } else { - throw IPAddressFormatException("Invalid IPv6 address '", ip, "'"); + throw IPAddressFormatException( + to("Invalid IPv6 address '", ip, "'")); } } @@ -90,7 +106,7 @@ IPAddressV6::IPAddressV6(const in6_addr& src) // sockaddr_in6 constructor IPAddressV6::IPAddressV6(const sockaddr_in6& src) : addr_(src.sin6_addr) - , scope_(src.sin6_scope_id) + , scope_(uint16_t(src.sin6_scope_id)) { } @@ -110,7 +126,7 @@ IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) { // See RFC 4291 sections 2.5.1, 2.5.6, and Appendix A const auto* macBytes = mac.bytes(); memcpy(&bytes_.front(), "\xfe\x80\x00\x00\x00\x00\x00\x00", 8); - bytes_[8] = macBytes[0] ^ 0x02; + bytes_[8] = uint8_t(macBytes[0] ^ 0x02); bytes_[9] = macBytes[1]; bytes_[10] = macBytes[2]; bytes_[11] = 0xff; @@ -120,10 +136,38 @@ IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) { bytes_[15] = macBytes[5]; } +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)) { + return folly::none; + } + // The link-local 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 2: invert the universal/local (U/L) flag (bit 7) + bytes[0] = addr_.bytes_[8] ^ 0x02; + // Step 3: copy thhese bytes are they are + bytes[1] = addr_.bytes_[9]; + bytes[2] = addr_.bytes_[10]; + // Step 4: strip bytes (0xfffe), which are bytes_[11] and bytes_[12] + // Step 5: copy the rest. + bytes[3] = addr_.bytes_[13]; + bytes[4] = addr_.bytes_[14]; + bytes[5] = addr_.bytes_[15]; + return Optional(MacAddress::fromBinary(range(bytes))); +} + void IPAddressV6::setFromBinary(ByteRange bytes) { if (bytes.size() != 16) { - throw IPAddressFormatException("Invalid IPv6 binary data: length must " - "be 16 bytes, got ", bytes.size()); + throw IPAddressFormatException(to( + "Invalid IPv6 binary data: length must ", + "be 16 bytes, got ", + bytes.size())); } memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr)); scope_ = 0; @@ -140,7 +184,7 @@ IPAddressV4 IPAddressV6::createIPv4() const { // convert two uint8_t bytes into a uint16_t as hibyte.lobyte static inline uint16_t unpack(uint8_t lobyte, uint8_t hibyte) { - return ((uint16_t)hibyte << 8) | (uint16_t)lobyte; + return uint16_t((uint16_t(hibyte) << 8) | lobyte); } // given a src string, unpack count*2 bytes into dest @@ -238,8 +282,8 @@ bool IPAddressV6::inSubnet(StringPiece cidrNetwork) const { auto subnetInfo = IPAddress::createNetwork(cidrNetwork); auto addr = subnetInfo.first; if (!addr.isV6()) { - throw IPAddressFormatException("Address '", addr.toJson(), "' ", - "is not a V6 address"); + throw IPAddressFormatException(to( + "Address '", addr.toJson(), "' ", "is not a V6 address")); } return inSubnetWithMask(addr.asV6(), fetchMask(subnetInfo.second)); } @@ -297,12 +341,12 @@ bool IPAddressV6::isMulticast() const { uint8_t IPAddressV6::getMulticastFlags() const { DCHECK(isMulticast()); - return ((addr_.bytes_[1] >> 4) & 0xf); + return uint8_t((addr_.bytes_[1] >> 4) & 0xf); } uint8_t IPAddressV6::getMulticastScope() const { DCHECK(isMulticast()); - return (addr_.bytes_[1] & 0xf); + return uint8_t(addr_.bytes_[1] & 0xf); } IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const { @@ -322,8 +366,8 @@ IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const { IPAddressV6 IPAddressV6::mask(size_t numBits) const { static const auto bits = bitCount(); if (numBits > bits) { - throw IPAddressFormatException("numBits(", numBits, ") > bitCount(", - bits, ")"); + throw IPAddressFormatException( + to("numBits(", numBits, ") > bitCount(", bits, ")")); } ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_); return IPAddressV6(ba); @@ -340,8 +384,11 @@ string IPAddressV6::str() const { string ip(buffer); return ip; } else { - throw IPAddressFormatException("Invalid address with hex ", - "'", detail::Bytes::toHex(bytes(), 16), "'"); + throw IPAddressFormatException(to( + "Invalid address with hex ", + "'", + detail::Bytes::toHex(bytes(), 16), + "'")); } } @@ -363,7 +410,7 @@ uint8_t IPAddressV6::getNthMSByte(size_t byteIndex) const { // protected const ByteArray16 IPAddressV6::fetchMask(size_t numBits) { - static const uint8_t bits = bitCount(); + static const size_t bits = bitCount(); if (numBits > bits) { throw IPAddressFormatException("IPv6 addresses are 128 bits."); } @@ -371,6 +418,15 @@ const ByteArray16 IPAddressV6::fetchMask(size_t numBits) { return masks_[numBits]; } +// public static +CIDRNetworkV6 IPAddressV6::longestCommonPrefix( + const CIDRNetworkV6& one, + const CIDRNetworkV6& two) { + auto prefix = detail::Bytes::longestCommonPrefix( + one.first.addr_.bytes_, one.second, two.first.addr_.bytes_, two.second); + return {IPAddressV6(prefix.first), prefix.second}; +} + // protected bool IPAddressV6::inBinarySubnet(const std::array addr, size_t numBits) const {