Commit dced19f5 authored by Anton Likhtarov's avatar Anton Likhtarov Committed by Dave Watson

Move common/network/IPAddress.h and related to folly/

Summary:
Moving our internal IP/Mac address libraries to folly/

Facebook:
We want to get rid of common/ dependencies in Mcrouter since we're going to open source it. Also looking at the original commit, seems like it's been the intention all along, so I just did it.

I tried to keep dependencies intact as much as possible. Changing projects to use this directly should be in separate diffs.

Test Plan:
Run folly/network and common/network unit tests.

Generate the list of targets with:

```
fbgs /$FILE.h | cut -f1 -d: | xargs -L1 dirname | cut -f2- -d/ | sort | uniq
```

Then fbconfig + fbmake. Will fix contbuild failures.

Revert Plan:

Reviewed By: simpkins@fb.com

FB internal diff: D1261089
parent fbdb6012
......@@ -21,6 +21,10 @@
#include "folly/Exception.h"
#include "folly/Traits.h"
// Ignore -Wformat-nonliteral warnings within this file
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
namespace folly {
namespace detail {
......@@ -1167,3 +1171,5 @@ toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
}
} // namespace folly
#pragma GCC diagnostic pop
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IPAddress.h"
#include <limits>
#include <ostream>
#include <string>
#include <vector>
#include "folly/String.h"
using std::ostream;
using std::string;
using std::vector;
namespace folly {
// free functions
size_t hash_value(const IPAddress& addr) {
return addr.hash();
}
ostream& operator<<(ostream& os, const IPAddress& addr) {
os << addr.str();
return os;
}
void toAppend(IPAddress addr, string* result) {
result->append(addr.str());
}
void toAppend(IPAddress addr, fbstring* result) {
result->append(addr.str());
}
// public static
IPAddressV4 IPAddress::createIPv4(const IPAddress& addr) {
if (addr.isV4()) {
return addr.asV4();
} else {
return addr.asV6().createIPv4();
}
}
// public static
IPAddressV6 IPAddress::createIPv6(const IPAddress& addr) {
if (addr.isV6()) {
return addr.asV6();
} else {
return addr.asV4().createIPv6();
}
}
// public static
CIDRNetwork IPAddress::createNetwork(StringPiece ipSlashCidr,
int defaultCidr, /* = -1 */
bool applyMask /* = true */) {
if (defaultCidr > std::numeric_limits<uint8_t>::max()) {
throw std::range_error("defaultCidr must be <= UINT8_MAX");
}
vector<string> vec;
split("/", ipSlashCidr, vec);
vector<string>::size_type elemCount = vec.size();
if (elemCount == 0 || // weird invalid string
elemCount > 2) { // invalid string (IP/CIDR/extras)
throw IPAddressFormatException("Invalid ipSlashCidr specified. ",
"Expected IP/CIDR format, got ",
"'", ipSlashCidr, "'");
}
IPAddress subnet(vec.at(0));
uint8_t cidr = (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128);
if (elemCount == 2) {
try {
cidr = to<uint8_t>(vec.at(1));
} catch (...) {
throw IPAddressFormatException("Mask value ",
"'", vec.at(1), "' not a valid mask");
}
}
if (cidr > subnet.bitCount()) {
throw IPAddressFormatException("CIDR value '", cidr, "' ",
"is > network bit count ",
"'", subnet.bitCount(), "'");
}
return std::make_pair(applyMask ? subnet.mask(cidr) : subnet, cidr);
}
// public static
IPAddress IPAddress::fromBinary(ByteRange bytes) {
if (bytes.size() == 4) {
return IPAddress(IPAddressV4::fromBinary(bytes));
} else if (bytes.size() == 16) {
return IPAddress(IPAddressV6::fromBinary(bytes));
} else {
string hexval = detail::Bytes::toHex(bytes.data(), bytes.size());
throw IPAddressFormatException("Invalid address with hex value ",
"'", hexval, "'");
}
}
// public static
IPAddress IPAddress::fromLong(uint32_t src) {
return IPAddress(IPAddressV4::fromLong(src));
}
IPAddress IPAddress::fromLongHBO(uint32_t src) {
return IPAddress(IPAddressV4::fromLongHBO(src));
}
// default constructor
IPAddress::IPAddress()
: addr_()
, family_(AF_UNSPEC)
{
}
// public string constructor
IPAddress::IPAddress(StringPiece addr)
: addr_()
, family_(AF_UNSPEC)
{
string ip = addr.str(); // inet_pton() needs NUL-terminated string
auto throwFormatException = [&](const string& msg) {
throw IPAddressFormatException("Invalid IP '", ip, "': ", msg);
};
if (ip.size() < 2) {
throwFormatException("address too short");
}
if (ip.front() == '[' && ip.back() == ']') {
ip = ip.substr(1, ip.size() - 2);
}
// 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");
}
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) {
throwFormatException("inet_pton failed for V4 address");
}
addr_ = IPAddressV46(IPAddressV4(ipAddr));
family_ = AF_INET;
} else {
throwFormatException("invalid address format");
}
}
// public sockaddr constructor
IPAddress::IPAddress(const sockaddr* addr)
: addr_()
, family_(AF_UNSPEC)
{
if (addr == nullptr) {
throw IPAddressFormatException("sockaddr == nullptr");
}
family_ = addr->sa_family;
switch (addr->sa_family) {
case AF_INET: {
const sockaddr_in *v4addr = reinterpret_cast<const sockaddr_in*>(addr);
addr_.ipV4Addr = IPAddressV4(v4addr->sin_addr);
break;
}
case AF_INET6: {
const sockaddr_in6 *v6addr = reinterpret_cast<const sockaddr_in6*>(addr);
addr_.ipV6Addr = IPAddressV6(v6addr->sin6_addr);
break;
}
default:
throw InvalidAddressFamilyException(addr->sa_family);
}
}
// public ipv4 constructor
IPAddress::IPAddress(const IPAddressV4 ipV4Addr)
: addr_(ipV4Addr)
, family_(AF_INET)
{
}
// public ipv4 constructor
IPAddress::IPAddress(const in_addr ipV4Addr)
: addr_(IPAddressV4(ipV4Addr))
, family_(AF_INET)
{
}
// public ipv6 constructor
IPAddress::IPAddress(const IPAddressV6& ipV6Addr)
: addr_(ipV6Addr)
, family_(AF_INET6)
{
}
// public ipv6 constructor
IPAddress::IPAddress(const in6_addr& ipV6Addr)
: addr_(IPAddressV6(ipV6Addr))
, family_(AF_INET6)
{
}
// Assign from V4 address
IPAddress& IPAddress::operator=(const IPAddressV4& ipv4_addr) {
addr_ = IPAddressV46(ipv4_addr);
family_ = AF_INET;
return *this;
}
// Assign from V6 address
IPAddress& IPAddress::operator=(const IPAddressV6& ipv6_addr) {
addr_ = IPAddressV46(ipv6_addr);
family_ = AF_INET6;
return *this;
}
// public
bool IPAddress::inSubnet(StringPiece cidrNetwork) const {
auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
return inSubnet(subnetInfo.first, subnetInfo.second);
}
// public
bool IPAddress::inSubnet(const IPAddress& subnet, uint8_t cidr) const {
if (bitCount() == subnet.bitCount()) {
if (isV4()) {
return asV4().inSubnet(subnet.asV4(), cidr);
} else {
return asV6().inSubnet(subnet.asV6(), cidr);
}
}
// an IPv4 address can never belong in a IPv6 subnet unless the IPv6 is a 6to4
// address and vice-versa
if (isV6()) {
const IPAddressV6& v6addr = asV6();
const IPAddressV4& v4subnet = subnet.asV4();
if (v6addr.is6To4()) {
return v6addr.getIPv4For6To4().inSubnet(v4subnet, cidr);
}
} else if (subnet.isV6()) {
const IPAddressV6& v6subnet = subnet.asV6();
const IPAddressV4& v4addr = asV4();
if (v6subnet.is6To4()) {
return v4addr.inSubnet(v6subnet.getIPv4For6To4(), cidr);
}
}
return false;
}
// public
bool IPAddress::inSubnetWithMask(const IPAddress& subnet,
ByteRange mask) const {
auto mkByteArray4 = [&]() -> ByteArray4 {
ByteArray4 ba{{0}};
std::memcpy(ba.data(), mask.begin(), std::min<size_t>(mask.size(), 4));
return ba;
};
if (bitCount() == subnet.bitCount()) {
if (isV4()) {
return asV4().inSubnetWithMask(subnet.asV4(), mkByteArray4());
} else {
ByteArray16 ba{{0}};
std::memcpy(ba.data(), mask.begin(), std::min<size_t>(mask.size(), 16));
return asV6().inSubnetWithMask(subnet.asV6(), ba);
}
}
// an IPv4 address can never belong in a IPv6 subnet unless the IPv6 is a 6to4
// address and vice-versa
if (isV6()) {
const IPAddressV6& v6addr = asV6();
const IPAddressV4& v4subnet = subnet.asV4();
if (v6addr.is6To4()) {
return v6addr.getIPv4For6To4().inSubnetWithMask(v4subnet, mkByteArray4());
}
} else if (subnet.isV6()) {
const IPAddressV6& v6subnet = subnet.asV6();
const IPAddressV4& v4addr = asV4();
if (v6subnet.is6To4()) {
return v4addr.inSubnetWithMask(v6subnet.getIPv4For6To4(), mkByteArray4());
}
}
return false;
}
uint8_t IPAddress::getNthMSByte(size_t byteIndex) const {
const auto highestIndex = byteCount() - 1;
if (byteIndex > highestIndex) {
throw std::invalid_argument(to<string>("Byte index must be <= ",
to<string>(highestIndex), " for addresses of type :",
detail::familyNameStr(family())));
}
if (isV4()) {
return asV4().bytes()[byteIndex];
}
return asV6().bytes()[byteIndex];
}
// public
bool operator==(const IPAddress& addr1, const IPAddress& addr2) {
if (addr1.family() == addr2.family()) {
if (addr1.isV6()) {
return (addr1.asV6() == addr2.asV6());
} else if (addr1.isV4()) {
return (addr1.asV4() == addr2.asV4());
} else {
CHECK_EQ(addr1.family(), AF_UNSPEC);
// Two default initialized AF_UNSPEC addresses should be considered equal.
// AF_UNSPEC is the only other value for which an IPAddress can be
// created, in the default constructor case.
return true;
}
}
// addr1 is v4 mapped v6 address, addr2 is v4
if (addr1.isIPv4Mapped()) {
if (IPAddress::createIPv4(addr1) == addr2.asV4()) {
return true;
}
}
// addr2 is v4 mapped v6 address, addr1 is v4
if (addr2.isIPv4Mapped()) {
if (IPAddress::createIPv4(addr2) == addr1.asV4()) {
return true;
}
}
// we only compare IPv4 and IPv6 addresses
return false;
}
bool operator<(const IPAddress& addr1, const IPAddress& addr2) {
if (addr1.family() == addr2.family()) {
if (addr1.isV6()) {
return (addr1.asV6() < addr2.asV6());
} else if (addr1.isV4()) {
return (addr1.asV4() < addr2.asV4());
} else {
CHECK_EQ(addr1.family(), AF_UNSPEC);
// Two default initialized AF_UNSPEC addresses can not be less than each
// other. AF_UNSPEC is the only other value for which an IPAddress can be
// created, in the default constructor case.
return false;
}
}
if (addr1.isV6()) {
// means addr2 is v4, convert it to a mapped v6 address and compare
return addr1.asV6() < addr2.asV4().createIPv6();
}
if (addr2.isV6()) {
// means addr2 is v6, convert addr1 to v4 mapped and compare
return addr1.asV4().createIPv6() < addr2.asV6();
}
return false;
}
CIDRNetwork
IPAddress::longestCommonPrefix(const CIDRNetwork& one, const CIDRNetwork& two) {
if (one.first.family() != two.first.family()) {
throw std::invalid_argument(to<string>("Can't compute "
"longest common prefix between addresses of different families. "
"Passed: ", detail::familyNameStr(one.first.family()), " and ",
detail::familyNameStr(two.first.family())));
}
if (one.first.isV4()) {
auto prefix = IPAddressV4::longestCommonPrefix(
{one.first.asV4(), one.second},
{two.first.asV4(), two.second});
return {IPAddress(prefix.first), prefix.second};
} else if (one.first.isV6()) {
auto prefix = IPAddressV6::longestCommonPrefix(
{one.first.asV6(), one.second},
{two.first.asV6(), two.second});
return {IPAddress(prefix.first), prefix.second};
} else {
throw std::invalid_argument("Unknown address family");
}
return {IPAddress(0), 0};
}
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <utility> // std::pair
#include <boost/operators.hpp>
#include "folly/Format.h"
#include "folly/Range.h"
#include "folly/IPAddressException.h"
#include "folly/IPAddressV4.h"
#include "folly/IPAddressV6.h"
#include "folly/detail/IPAddress.h"
namespace folly {
class IPAddress;
/**
* Pair of IPAddress, netmask
*/
typedef std::pair<IPAddress, uint8_t> CIDRNetwork;
/**
* Provides a unified interface for IP addresses.
*
* @note If you compare 2 IPAddress instances, v4-to-v6-mapped addresses are
* compared as V4 addresses.
*
* @note toLong/fromLong deal in network byte order, use toLongHBO/fromLongHBO
* if working in host byte order.
*
* Example usage:
* @code
* IPAddress v4addr("192.0.2.129");
* IPAddress v6map("::ffff:192.0.2.129");
* CHECK(v4addr.inSubnet("192.0.2.0/24") ==
* v4addr.inSubnet(IPAddress("192.0.2.0"), 24));
* CHECK(v4addr.inSubnet("192.0.2.128/30"));
* CHECK(!v4addr.inSubnet("192.0.2.128/32"));
* CHECK(v4addr.asV4().toLong() == 2164392128);
* CHECK(v4addr.asV4().toLongHBO() == 3221226113);
* CHECK(v4addr.isV4());
* CHECK(v6addr.isV6());
* CHECK(v4addr == v6map);
* CHECK(v6map.isIPv4Mapped());
* CHECK(v4addr.asV4() == IPAddress::createIPv4(v6map));
* CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6());
* @encode
*/
class IPAddress : boost::totally_ordered<IPAddress> {
public:
// return the V4 representation of the address, converting it from V6 to V4 if
// needed. Note that this will throw an IPAddressFormatException if the V6
// address is not IPv4Mapped.
static IPAddressV4 createIPv4(const IPAddress& addr);
// return the V6 representation of the address, converting it from V4 to V6 if
// needed.
static IPAddressV6 createIPv6(const IPAddress& addr);
/**
* Create a network and mask from a CIDR formatted address string.
* @param [in] ipSlashCidr IP/CIDR formatted string to split
* @param [in] defaultCidr default value if no /N specified (if defaultCidr
* is -1, will use /32 for IPv4 and /128 for IPv6)
* @param [in] mask apply mask on the address or not,
* e.g. 192.168.13.46/24 => 192.168.13.0/24
* @throws IPAddressFormatException if invalid address
* @return pair with IPAddress network and uint8_t mask
*/
static CIDRNetwork createNetwork(
StringPiece ipSlashCidr, int defaultCidr = -1, bool mask = true);
/**
* Return a string representation of a CIDR block created with createNetwork.
* @param [in] network, pair of address and cidr
*
* @return string representing the netblock
*/
static std::string networkToString(const CIDRNetwork& network) {
return network.first.str() + "/" + std::to_string(network.second);
}
/**
* Create a new IPAddress instance from the provided binary data
* in network byte order.
* @throws IPAddressFormatException if len is not 4 or 16
*/
static IPAddress fromBinary(ByteRange bytes);
/**
* Create an IPAddress from a 32bit long (network byte order).
* @throws IPAddressFormatException
*/
static IPAddress fromLong(uint32_t src);
// Same as above, but host byte order
static IPAddress fromLongHBO(uint32_t src);
// Given 2 IPAddress,mask pairs extract the longest common IPAddress,
// mask pair
static CIDRNetwork longestCommonPrefix(const CIDRNetwork& one,
const CIDRNetwork& two);
/**
* Constructs an uninitialized IPAddress.
*/
IPAddress();
/**
* Parse an IPAddress from a string representation.
*
* Formats accepted are exactly the same as the ones accepted by inet_pton(),
* using AF_INET6 if the string contains colons, and AF_INET otherwise;
* with the exception that the whole address can optionally be enclosed
* in square brackets.
*
* @throws IPAddressFormatException
*/
explicit IPAddress(StringPiece ip);
/**
* Create an IPAddress from a sockaddr.
* @throws IPAddressFormatException if nullptr or not AF_INET or AF_INET6
*/
explicit IPAddress(const sockaddr* addr);
// Create an IPAddress from a V4 address
/* implicit */ IPAddress(const IPAddressV4 ipV4Addr);
/* implicit */ IPAddress(const in_addr addr);
// Create an IPAddress from a V6 address
/* implicit */ IPAddress(const IPAddressV6& ipV6Addr);
/* implicit */ IPAddress(const in6_addr& addr);
// Assign from V4 address
IPAddress& operator=(const IPAddressV4& ipV4Addr);
// Assign from V6 address
IPAddress& operator=(const IPAddressV6& ipV6Addr);
/**
* Converts an IPAddress to an IPAddressV4 instance.
* @note This is not some handy convenience wrapper to convert an IPv4 address
* to a mapped IPv6 address. If you want that use
* IPAddress::createIPv6(addr)
* @throws IPAddressFormatException is not a V4 instance
*/
const IPAddressV4& asV4() const {
if (!isV4()) {
auto familyName = detail::familyNameStr(family());
throw InvalidAddressFamilyException("Can't convert address with family ",
familyName, " to AF_INET address");
}
return addr_.ipV4Addr;
}
/**
* Converts an IPAddress to an IPAddressV6 instance.
* @throws InvalidAddressFamilyException is not a V6 instance
*/
const IPAddressV6& asV6() const {
if (!isV6()) {
auto familyName = detail::familyNameStr(family());
throw InvalidAddressFamilyException("Can't convert address with family ",
familyName, " to AF_INET6 address");
}
return addr_.ipV6Addr;
}
// Return sa_family_t of IPAddress
sa_family_t family() const { return family_; }
// Populate sockaddr_storage with an appropriate value
int toSockaddrStorage(sockaddr_storage *dest, uint16_t port = 0) const {
if (dest == nullptr) {
throw IPAddressFormatException("dest must not be null");
}
memset(dest, 0, sizeof(sockaddr_storage));
dest->ss_family = family();
if (isV4()) {
sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(dest);
sin->sin_addr = asV4().toAddr();
sin->sin_port = port;
return sizeof(*sin);
} else if (isV6()) {
sockaddr_in6 *sin = reinterpret_cast<sockaddr_in6*>(dest);
sin->sin6_addr = asV6().toAddr();
sin->sin6_port = port;
return sizeof(*sin);
} else {
throw InvalidAddressFamilyException(family());
}
}
/**
* Check if the address is found in the specified CIDR netblock.
*
* This will return false if the specified cidrNet is V4, but the address is
* V6. It will also return false if the specified cidrNet is V6 but the
* address is V4. This method will do the right thing in the case of a v6
* mapped v4 address.
*
* @note This is slower than the below counterparts. If perf is important use
* one of the two argument variations below.
* @param [in] ipSlashCidr address in "192.168.1.0/24" format
* @throws IPAddressFormatException if no /mask
* @return true if address is part of specified subnet with cidr
*/
bool inSubnet(StringPiece ipSlashCidr) const;
/**
* Check if an IPAddress belongs to a subnet.
* @param [in] subnet Subnet to check against (e.g. 192.168.1.0)
* @param [in] cidr CIDR for subnet (e.g. 24 for /24)
* @return true if address is part of specified subnet with cidr
*/
bool inSubnet(const IPAddress& subnet, uint8_t cidr) const;
/**
* Check if an IPAddress belongs to the subnet with the given mask.
* This is the same as inSubnet but the mask is provided instead of looked up
* from the cidr.
* @param [in] subnet Subnet to check against
* @param [in] mask The netmask for the subnet
* @return true if address is part of the specified subnet with mask
*/
bool inSubnetWithMask(const IPAddress& subnet, ByteRange mask) const;
// @return true if address is a v4 mapped address
bool isIPv4Mapped() const {
return isV6() && asV6().isIPv4Mapped();
}
// @return true if this is an IPAddressV4 instance
bool isV4() const { return (family_ == AF_INET); }
// @return true if this is an IPAddressV6 instance
bool isV6() const { return (family_ == AF_INET6); }
// @return true if this address is all zeros
bool isZero() const {
return isV4() ? asV4().isZero()
: asV6().isZero();
}
// Number of bits in the address representation.
size_t bitCount() const {
return isV4() ? IPAddressV4::bitCount()
: IPAddressV6::bitCount();
}
// Number of bytes in the address representation.
size_t byteCount() const {
return bitCount() / 8;
}
//get nth most significant bit - 0 indexed
bool getNthMSBit(size_t bitIndex) const {
return detail::getNthMSBitImpl(*this, bitIndex, family());
}
//get nth most significant byte - 0 indexed
uint8_t getNthMSByte(size_t byteIndex) const;
//get nth bit - 0 indexed
bool getNthLSBit(size_t bitIndex) const {
return getNthMSBit(bitCount() - bitIndex - 1);
}
//get nth byte - 0 indexed
uint8_t getNthLSByte(size_t byteIndex) const {
return getNthMSByte(byteCount() - byteIndex - 1);
}
/**
* Get human-readable string representation of the address.
*
* This prints a string representation of the address, for human consumption
* or logging. The string will take the form of a JSON object that looks like:
* {family:'AF_INET|AF_INET6', addr:'address', hash:long}.
*/
std::string toJson() const {
return isV4() ? asV4().toJson()
: asV6().toJson();
}
// Hash of address
std::size_t hash() const {
return isV4() ? asV4().hash()
: asV6().hash();
}
// Return true if the address qualifies as localhost.
bool isLoopback() const {
return isV4() ? asV4().isLoopback()
: asV6().isLoopback();
}
// Return true if the address qualifies as broadcast.
bool isLinkLocalBroadcast() const {
return isV4() ? asV4().isLinkLocalBroadcast()
: asV6().isLinkLocalBroadcast();
}
/**
* Return true if the address is a special purpose address, as per rfc6890
* (i.e. 0.0.0.0).
* For V6, true if the address is not in one of global scope blocks:
* 2000::/3, ffxe::/16.
*/
bool isNonroutable() const {
return isV4() ? asV4().isNonroutable()
: asV6().isNonroutable();
}
/**
* Return true if the address is private, as per rfc1918 and rfc4193
* (for example, 192.168.xxx.xxx or fc00::/7 addresses)
*/
bool isPrivate() const {
return isV4() ? asV4().isPrivate()
: asV6().isPrivate();
}
// Return true if the address is a multicast address.
bool isMulticast() const {
return isV4() ? asV4().isMulticast()
: asV6().isMulticast();
}
/**
* Creates IPAddress instance with all but most significant numBits set to 0.
* @param [in] numBits number of bits to mask
* @throws abort if numBits > bitCount()
* @return IPAddress instance with bits set to 0
*/
IPAddress mask(uint8_t numBits) const {
return isV4() ? IPAddress(std::move(asV4().mask(numBits)))
: IPAddress(std::move(asV6().mask(numBits)));
}
/**
* Provides a string representation of address.
* @note The string representation is calculated on demand.
* @throws IPAddressFormatException on inet_ntop error
*/
std::string str() const {
return isV4() ? asV4().str()
: asV6().str();
}
/**
* Return the fully qualified string representation of the address.
* For V4 addresses this is the same as calling str(). For V6 addresses
* this is the hex representation with : characters inserted every 4 digits.
*/
std::string toFullyQualified() const {
return isV4() ? asV4().toFullyQualified()
: asV6().toFullyQualified();
}
// Address version (4 or 6)
uint8_t version() const {
return isV4() ? asV4().version()
: asV6().version();
}
/**
* Access to address bytes, in network byte order.
*/
const unsigned char* bytes() const {
return isV4() ? asV4().bytes() : asV6().bytes();
}
private:
typedef union IPAddressV46 {
IPAddressV4 ipV4Addr;
IPAddressV6 ipV6Addr;
// default constructor
IPAddressV46() {
std::memset(this, 0, sizeof(IPAddressV46));
}
explicit IPAddressV46(const IPAddressV4& addr): ipV4Addr(addr) {}
explicit IPAddressV46(const IPAddressV6& addr): ipV6Addr(addr) {}
} IPAddressV46;
IPAddressV46 addr_;
sa_family_t family_;
};
// boost::hash uses hash_value() so this allows boost::hash to work
// automatically for IPAddress
std::size_t hash_value(const IPAddress& addr);
std::ostream& operator<<(std::ostream& os, const IPAddress& addr);
// Define toAppend() to allow IPAddress to be used with folly::to<string>
void toAppend(IPAddress addr, std::string* result);
void toAppend(IPAddress addr, fbstring* result);
/**
* Return true if two addresses are equal.
*
* @note This takes into consideration V4 mapped addresses as well. If one
* address is v4 mapped we compare the v4 addresses.
*
* @return true if the two addresses are equal.
*/
bool operator==(const IPAddress& addr1, const IPAddress& addr2);
// Return true if addr1 < addr2
bool operator<(const IPAddress& addr1, const IPAddress& addr2);
} // folly
namespace std {
template<>
struct hash<folly::IPAddress> {
size_t operator()(const folly::IPAddress& addr) const {
return addr.hash();
}
};
} // std
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <exception>
#include <string>
#include "folly/Conv.h"
#include "folly/detail/IPAddress.h"
namespace folly {
/**
* Exception for invalid IP addresses.
*/
class IPAddressFormatException : public std::exception {
public:
explicit IPAddressFormatException(const std::string& msg)
: msg_(msg) {}
IPAddressFormatException(
const IPAddressFormatException& exception_) = default;
template<typename... Args>
explicit IPAddressFormatException(Args&&... args)
: msg_(to<std::string>(std::forward<Args>(args)...)) {}
virtual ~IPAddressFormatException() noexcept {}
virtual const char *what(void) const noexcept {
return msg_.c_str();
}
private:
const std::string msg_;
};
class InvalidAddressFamilyException : public IPAddressFormatException {
public:
explicit InvalidAddressFamilyException(const std::string& msg)
: IPAddressFormatException(msg) {}
InvalidAddressFamilyException(
const InvalidAddressFamilyException& ex) = default;
explicit InvalidAddressFamilyException(sa_family_t family)
: IPAddressFormatException("Address family " +
detail::familyNameStr(family) +
" is not AF_INET or AF_INET6") {}
template<typename... Args>
explicit InvalidAddressFamilyException(Args&&... args)
: IPAddressFormatException(std::forward<Args>(args)...) {}
};
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IPAddressV4.h"
#include <ostream>
#include <string>
#include "folly/Format.h"
#include "folly/IPAddress.h"
#include "folly/IPAddressV6.h"
using std::ostream;
using std::string;
namespace folly {
// free functions
size_t hash_value(const IPAddressV4& addr) {
return addr.hash();
}
ostream& operator<<(ostream& os, const IPAddressV4& addr) {
os << addr.str();
return os;
}
void toAppend(IPAddressV4 addr, string* result) {
result->append(addr.str());
}
void toAppend(IPAddressV4 addr, fbstring* result) {
result->append(addr.str());
}
// public static
IPAddressV4 IPAddressV4::fromLong(uint32_t src) {
in_addr addr;
addr.s_addr = src;
return IPAddressV4(addr);
}
IPAddressV4 IPAddressV4::fromLongHBO(uint32_t src) {
in_addr addr;
addr.s_addr = htonl(src);
return IPAddressV4(addr);
}
// static public
uint32_t IPAddressV4::toLong(StringPiece ip) {
auto str = ip.str();
in_addr addr;
if (inet_pton(AF_INET, str.c_str(), &addr) != 1) {
throw IPAddressFormatException("Can't convert invalid IP '", ip, "' ",
"to long");
}
return addr.s_addr;
}
// static public
uint32_t IPAddressV4::toLongHBO(StringPiece ip) {
return ntohl(IPAddressV4::toLong(ip));
}
// public default constructor
IPAddressV4::IPAddressV4() {
}
// ByteArray4 constructor
IPAddressV4::IPAddressV4(const ByteArray4& src)
: addr_(src)
{
}
// public string constructor
IPAddressV4::IPAddressV4(StringPiece addr)
: addr_()
{
auto ip = addr.str();
if (inet_pton(AF_INET, ip.c_str(), &addr_.inAddr_) != 1) {
throw IPAddressFormatException("Invalid IPv4 address '", addr, "'");
}
}
// in_addr constructor
IPAddressV4::IPAddressV4(const in_addr src)
: addr_(src)
{
}
// public
void IPAddressV4::setFromBinary(ByteRange bytes) {
if (bytes.size() != 4) {
throw IPAddressFormatException("Invalid IPv4 binary data: length must "
"be 4 bytes, got ", bytes.size());
}
memcpy(&addr_.inAddr_.s_addr, bytes.data(), sizeof(in_addr));
}
// public
IPAddressV6 IPAddressV4::createIPv6() const {
ByteArray16 ba{{0}};
ba[10] = 0xff;
ba[11] = 0xff;
std::memcpy(&ba[12], bytes(), 4);
return IPAddressV6(ba);
}
// public
string IPAddressV4::toJson() const {
return format(
"{{family:'AF_INET', addr:'{}', hash:{}}}", str(), hash()).str();
}
// public
bool IPAddressV4::inSubnet(StringPiece cidrNetwork) const {
auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
auto addr = subnetInfo.first;
if (!addr.isV4()) {
throw IPAddressFormatException("Address '", addr.toJson(), "' ",
"is not a V4 address");
}
return inSubnetWithMask(addr.asV4(), fetchMask(subnetInfo.second));
}
// public
bool IPAddressV4::inSubnetWithMask(const IPAddressV4& subnet,
const ByteArray4 cidrMask) const {
const ByteArray4 mask = detail::Bytes::mask(toByteArray(), cidrMask);
const ByteArray4 subMask = detail::Bytes::mask(subnet.toByteArray(),
cidrMask);
return (mask == subMask);
}
// public
bool IPAddressV4::isNonroutable() const {
auto ip = toLongHBO();
return isPrivate() ||
(ip <= 0x00FFFFFF) || // 0.0.0.0-0.255.255.255
(ip >= 0xC0000000 && ip <= 0xC00000FF) || // 192.0.0.0-192.0.0.255
(ip >= 0xC0000200 && ip <= 0xC00002FF) || // 192.0.2.0-192.0.2.255
(ip >= 0xC6120000 && ip <= 0xC613FFFF) || // 198.18.0.0-198.19.255.255
(ip >= 0xC6336400 && ip <= 0xC63364FF) || // 198.51.100.0-198.51.100.255
(ip >= 0xCB007100 && ip <= 0xCB0071FF) || // 203.0.113.0-203.0.113.255
(ip >= 0xE0000000 && ip <= 0xFFFFFFFF); // 224.0.0.0-255.255.255.255
}
// public
bool IPAddressV4::isPrivate() const {
auto ip = toLongHBO();
return
(ip >= 0x0A000000 && ip <= 0x0AFFFFFF) || // 10.0.0.0-10.255.255.255
(ip >= 0x7F000000 && ip <= 0x7FFFFFFF) || // 127.0.0.0-127.255.255.255
(ip >= 0xA9FE0000 && ip <= 0xA9FEFFFF) || // 169.254.0.0-169.254.255.255
(ip >= 0xAC100000 && ip <= 0xAC1FFFFF) || // 172.16.0.0-172.31.255.255
(ip >= 0xC0A80000 && ip <= 0xC0A8FFFF); // 192.168.0.0-192.168.255.255
}
// public
bool IPAddressV4::isMulticast() const {
return (toLongHBO() & 0xf0000000) == 0xe0000000;
}
// public
IPAddressV4 IPAddressV4::mask(size_t numBits) const {
static const auto bits = bitCount();
if (numBits > bits) {
throw IPAddressFormatException("numBits(", numBits,
") > bitsCount(", bits, ")");
}
ByteArray4 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_);
return IPAddressV4(ba);
}
// public
// Taken from TSocketAddress::getAddressStrIPv4Fast
string IPAddressV4::str() const {
char buf[INET_ADDRSTRLEN] = {0};
const uint8_t* ip = addr_.bytes_.data();
int pos = 0;
for (int k = 0; k < 4; ++k) {
uint8_t num = ip[k];
if (num >= 200) {
buf[pos++] = '2';
num -= 200;
} else if (num >= 100) {
buf[pos++] = '1';
num -= 100;
}
// num < 100
if (ip[k] >= 10) {
buf[pos++] = '0' + num / 10;
buf[pos++] = '0' + num % 10;
} else {
buf[pos++] = '0' + num;
}
buf[pos++] = '.';
}
buf[pos-1] = '\0';
string ipAddr(buf);
return std::move(ipAddr);
}
// public
uint8_t IPAddressV4::getNthMSByte(size_t byteIndex) const {
const auto highestIndex = byteCount() - 1;
if (byteIndex > highestIndex) {
throw std::invalid_argument(to<string>("Byte index must be <= ",
to<string>(highestIndex), " for addresses of type :",
detail::familyNameStr(AF_INET)));
}
return bytes()[byteIndex];
}
// protected
const ByteArray4 IPAddressV4::fetchMask(size_t numBits) {
static const uint8_t bits = bitCount();
if (numBits > bits) {
throw IPAddressFormatException("IPv4 addresses are 32 bits");
}
// masks_ is backed by an array so is zero indexed
return masks_[numBits];
}
// static private
const std::array<ByteArray4, 33> IPAddressV4::masks_ = {{
{{0x00, 0x00, 0x00, 0x00}},
{{0x80, 0x00, 0x00, 0x00}},
{{0xc0, 0x00, 0x00, 0x00}},
{{0xe0, 0x00, 0x00, 0x00}},
{{0xf0, 0x00, 0x00, 0x00}},
{{0xf8, 0x00, 0x00, 0x00}},
{{0xfc, 0x00, 0x00, 0x00}},
{{0xfe, 0x00, 0x00, 0x00}},
{{0xff, 0x00, 0x00, 0x00}},
{{0xff, 0x80, 0x00, 0x00}},
{{0xff, 0xc0, 0x00, 0x00}},
{{0xff, 0xe0, 0x00, 0x00}},
{{0xff, 0xf0, 0x00, 0x00}},
{{0xff, 0xf8, 0x00, 0x00}},
{{0xff, 0xfc, 0x00, 0x00}},
{{0xff, 0xfe, 0x00, 0x00}},
{{0xff, 0xff, 0x00, 0x00}},
{{0xff, 0xff, 0x80, 0x00}},
{{0xff, 0xff, 0xc0, 0x00}},
{{0xff, 0xff, 0xe0, 0x00}},
{{0xff, 0xff, 0xf0, 0x00}},
{{0xff, 0xff, 0xf8, 0x00}},
{{0xff, 0xff, 0xfc, 0x00}},
{{0xff, 0xff, 0xfe, 0x00}},
{{0xff, 0xff, 0xff, 0x00}},
{{0xff, 0xff, 0xff, 0x80}},
{{0xff, 0xff, 0xff, 0xc0}},
{{0xff, 0xff, 0xff, 0xe0}},
{{0xff, 0xff, 0xff, 0xf0}},
{{0xff, 0xff, 0xff, 0xf8}},
{{0xff, 0xff, 0xff, 0xfc}},
{{0xff, 0xff, 0xff, 0xfe}},
{{0xff, 0xff, 0xff, 0xff}}
}};
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <iostream>
#include <boost/operators.hpp>
#include "folly/Hash.h"
#include "folly/Range.h"
#include "folly/detail/IPAddress.h"
namespace folly {
class IPAddress;
class IPAddressV4;
class IPAddressV6;
/**
* Pair of IPAddressV4, netmask
*/
typedef std::pair<IPAddressV4, uint8_t> CIDRNetworkV4;
/**
* Specialization for IPv4 addresses
*/
typedef std::array<uint8_t, 4> ByteArray4;
/**
* IPv4 variation of IPAddress.
*
* Added methods: toLong, toLongHBO and createIPv6
*
* @note toLong/fromLong deal in network byte order, use toLongHBO/fromLongHBO
* if working in host byte order.
*
* @see IPAddress
*/
class IPAddressV4 : boost::totally_ordered<IPAddressV4> {
public:
// create an IPAddressV4 instance from a uint32_t (network byte order)
static IPAddressV4 fromLong(uint32_t src);
// same as above but host byte order
static IPAddressV4 fromLongHBO(uint32_t src);
/**
* Create a new IPAddress instance from the provided binary data.
* @throws IPAddressFormatException if the input length is not 4 bytes.
*/
static IPAddressV4 fromBinary(ByteRange bytes) {
IPAddressV4 addr;
addr.setFromBinary(bytes);
return addr;
}
/**
* Convert a IPv4 address string to a long in network byte order.
* @param [in] ip the address to convert
* @return the long representation of the address
*/
static uint32_t toLong(StringPiece ip);
// Same as above, but in host byte order.
// This is slightly slower than toLong.
static uint32_t toLongHBO(StringPiece ip);
/**
* Default constructor for IPAddressV4.
*
* The address value will be 0.0.0.0
*/
IPAddressV4();
// Create an IPAddressV4 from a string
// @throws IPAddressFormatException
explicit IPAddressV4(StringPiece ip);
// ByteArray4 constructor
explicit IPAddressV4(const ByteArray4& src);
// in_addr constructor
explicit IPAddressV4(const in_addr src);
// Return the V6 mapped representation of the address.
IPAddressV6 createIPv6() const;
// Return the long (network byte order) representation of the address.
uint32_t toLong() const {
return toAddr().s_addr;
}
// Return the long (host byte order) representation of the address.
// This is slightly slower than toLong.
uint32_t toLongHBO() const {
return ntohl(toLong());
}
/**
* @see IPAddress#bitCount
* @returns 32
*/
static size_t bitCount() { return 32; }
/**
* @See IPAddress#toJson
*/
std::string toJson() const;
size_t hash() const {
static const uint32_t seed = AF_INET;
uint32_t hashed = hash::fnv32_buf(&addr_, 4);
return hash::hash_combine(seed, hashed);
}
// @see IPAddress#inSubnet
// @throws IPAddressFormatException if string doesn't contain a V4 address
bool inSubnet(StringPiece cidrNetwork) const;
// return true if address is in subnet
bool inSubnet(const IPAddressV4& subnet, uint8_t cidr) const {
return inSubnetWithMask(subnet, fetchMask(cidr));
}
bool inSubnetWithMask(const IPAddressV4& subnet, const ByteArray4 mask) const;
// @see IPAddress#isLoopback
bool isLoopback() const {
return (INADDR_LOOPBACK == toLongHBO());
}
// @see IPAddress#isNonroutable
bool isNonroutable() const;
// @see IPAddress#isPrivate
bool isPrivate() const;
// @see IPAddress#isMulticast
bool isMulticast() const;
// @see IPAddress#isZero
bool isZero() const {
return detail::Bytes::isZero(bytes(), 4);
}
bool isLinkLocalBroadcast() const {
return (INADDR_BROADCAST == toLongHBO());
}
// @see IPAddress#mask
IPAddressV4 mask(size_t numBits) const;
// @see IPAddress#str
std::string str() const;
// return underlying in_addr structure
in_addr toAddr() const { return addr_.inAddr_; }
sockaddr_in toSockAddr() const {
sockaddr_in addr;
memset(&addr, 0, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
memcpy(&addr.sin_addr, &addr_.inAddr_, sizeof(in_addr));
return addr;
}
ByteArray4 toByteArray() const {
ByteArray4 ba{{0}};
std::memcpy(ba.data(), bytes(), 4);
return std::move(ba);
}
// @see IPAddress#toFullyQualified
std::string toFullyQualified() const { return str(); }
// @see IPAddress#version
size_t version() const { return 4; }
/**
* Return the mask associated with the given number of bits.
* If for instance numBits was 24 (e.g. /24) then the V4 mask returned should
* be {0xff, 0xff, 0xff, 0x00}.
* @param [in] numBits bitmask to retrieve
* @throws abort if numBits == 0 or numBits > bitCount()
* @return mask associated with numBits
*/
static const ByteArray4 fetchMask(size_t numBits);
// Given 2 IPAddressV4,mask pairs extract the longest common IPAddress,
// mask pair
static CIDRNetworkV4 longestCommonPrefix(
const CIDRNetworkV4& one, const CIDRNetworkV4& two) {
auto prefix =
detail::Bytes::longestCommonPrefix(one.first.addr_.bytes_, one.second,
two.first.addr_.bytes_, two.second);
return {IPAddressV4(prefix.first), prefix.second};
}
// Number of bytes in the address representation.
static size_t byteCount() { return 4; }
//get nth most significant bit - 0 indexed
bool getNthMSBit(size_t bitIndex) const {
return detail::getNthMSBitImpl(*this, bitIndex, AF_INET);
}
//get nth most significant byte - 0 indexed
uint8_t getNthMSByte(size_t byteIndex) const;
//get nth bit - 0 indexed
bool getNthLSBit(size_t bitIndex) const {
return getNthMSBit(bitCount() - bitIndex - 1);
}
//get nth byte - 0 indexed
uint8_t getNthLSByte(size_t byteIndex) const {
return getNthMSByte(byteCount() - byteIndex - 1);
}
const unsigned char* bytes() const { return addr_.bytes_.data(); }
private:
union AddressStorage {
in_addr inAddr_;
ByteArray4 bytes_;
AddressStorage() {
std::memset(this, 0, sizeof(AddressStorage));
}
explicit AddressStorage(const ByteArray4 bytes): bytes_(bytes) {}
explicit AddressStorage(const in_addr addr): inAddr_(addr) {}
} addr_;
static const std::array<ByteArray4, 33> masks_;
/**
* Set the current IPAddressV4 object to have the address specified by bytes.
* @throws IPAddressFormatException if bytes.size() is not 4.
*/
void setFromBinary(ByteRange bytes);
};
// boost::hash uses hash_value() so this allows boost::hash to work
// automatically for IPAddressV4
size_t hash_value(const IPAddressV4& addr);
std::ostream& operator<<(std::ostream& os, const IPAddressV4& addr);
// Define toAppend() to allow IPAddressV4 to be used with to<string>
void toAppend(IPAddressV4 addr, std::string* result);
void toAppend(IPAddressV4 addr, fbstring* result);
/**
* Return true if two addresses are equal.
*/
inline bool operator==(const IPAddressV4& addr1, const IPAddressV4& addr2) {
return (addr1.toLong() == addr2.toLong());
}
// Return true if addr1 < addr2
inline bool operator<(const IPAddressV4& addr1, const IPAddressV4& addr2) {
return (addr1.toLongHBO() < addr2.toLongHBO());
}
} // folly
namespace std {
template<>
struct hash<folly::IPAddressV4> {
size_t operator()(const folly::IPAddressV4 addr) const {
return addr.hash();
}
};
} // std
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IPAddressV6.h"
#include <ostream>
#include <string>
#include "folly/Format.h"
#include "folly/IPAddress.h"
#include "folly/IPAddressV4.h"
#include "folly/MacAddress.h"
using std::ostream;
using std::string;
namespace folly {
// public static const
const uint32_t IPAddressV6::PREFIX_TEREDO = 0x20010000;
const uint32_t IPAddressV6::PREFIX_6TO4 = 0x2002;
// free functions
size_t hash_value(const IPAddressV6& addr) {
return addr.hash();
}
ostream& operator<<(ostream& os, const IPAddressV6& addr) {
os << addr.str();
return os;
}
void toAppend(IPAddressV6 addr, string* result) {
result->append(addr.str());
}
void toAppend(IPAddressV6 addr, fbstring* result) {
result->append(addr.str());
}
// public default constructor
IPAddressV6::IPAddressV6() {
}
// public string constructor
IPAddressV6::IPAddressV6(StringPiece addr) {
auto ip = addr.str();
// Allow addresses surrounded in brackets
if (ip.size() < 2) {
throw IPAddressFormatException("Invalid IPv6 address '", ip,
"': address too short");
}
if (ip.front() == '[' && ip.back() == ']') {
ip = ip.substr(1, ip.size() - 2);
}
if (inet_pton(AF_INET6, ip.c_str(), &addr_.in6Addr_) != 1) {
throw IPAddressFormatException("Invalid IPv6 address '", ip, "'");
}
}
// in6_addr constructor
IPAddressV6::IPAddressV6(const in6_addr& src)
: addr_(src)
{
}
// ByteArray16 constructor
IPAddressV6::IPAddressV6(const ByteArray16& src)
: addr_(src)
{
}
// link-local constructor
IPAddressV6::IPAddressV6(LinkLocalTag, MacAddress mac)
: addr_(mac) {
}
IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) {
// The link-local address uses modified EUI-64 format,
// 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_[9] = macBytes[1];
bytes_[10] = macBytes[2];
bytes_[11] = 0xff;
bytes_[12] = 0xfe;
bytes_[13] = macBytes[3];
bytes_[14] = macBytes[4];
bytes_[15] = macBytes[5];
}
void IPAddressV6::setFromBinary(ByteRange bytes) {
if (bytes.size() != 16) {
throw IPAddressFormatException("Invalid IPv6 binary data: length must "
"be 16 bytes, got ", bytes.size());
}
memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr));
}
// public
IPAddressV4 IPAddressV6::createIPv4() const {
if (!isIPv4Mapped()) {
throw IPAddressFormatException("addr is not v4-to-v6-mapped");
}
const unsigned char* by = bytes();
return IPAddressV4(detail::Bytes::mkAddress4(&by[12]));
}
// 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;
}
// 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) {
for (int i = 0, hi = 1, lo = 0; i < count; i++) {
dest[i] = unpack(src[hi], src[lo]);
hi += 2;
lo += 2;
}
}
// public
IPAddressV4 IPAddressV6::getIPv4For6To4() const {
if (!is6To4()) {
throw IPAddressV6::TypeError(format(
"Invalid IP '{}': not a 6to4 address", str()).str());
}
// convert 16x8 bytes into first 4x16 bytes
uint16_t ints[4] = {0,0,0,0};
unpackInto(bytes(), ints, 4);
// repack into 4x8
union {
unsigned char bytes[4];
in_addr addr;
} ipv4;
ipv4.bytes[0] = (uint8_t)((ints[1] & 0xFF00) >> 8);
ipv4.bytes[1] = (uint8_t)(ints[1] & 0x00FF);
ipv4.bytes[2] = (uint8_t)((ints[2] & 0xFF00) >> 8);
ipv4.bytes[3] = (uint8_t)(ints[2] & 0x00FF);
return IPAddressV4(ipv4.addr);
}
// public
bool IPAddressV6::isIPv4Mapped() const {
// v4 mapped addresses have their first 10 bytes set to 0, the next 2 bytes
// set to 255 (0xff);
const unsigned char* by = bytes();
// check if first 10 bytes are 0
for (int i = 0; i < 10; i++) {
if (by[i] != 0x00) {
return false;
}
}
// check if bytes 11 and 12 are 255
if (by[10] == 0xff && by[11] == 0xff) {
return true;
}
return false;
}
// public
IPAddressV6::Type IPAddressV6::type() const {
// convert 16x8 bytes into first 2x16 bytes
uint16_t ints[2] = {0,0};
unpackInto(bytes(), ints, 2);
if ((((uint32_t)ints[0] << 16) | ints[1]) == IPAddressV6::PREFIX_TEREDO) {
return Type::TEREDO;
}
if ((uint32_t)ints[0] == IPAddressV6::PREFIX_6TO4) {
return Type::T6TO4;
}
return Type::NORMAL;
}
// public
string IPAddressV6::toJson() const {
return format(
"{{family:'AF_INET6', addr:'{}', hash:{}}}", str(), hash()).str();
}
// public
size_t IPAddressV6::hash() const {
if (isIPv4Mapped()) {
/* An IPAddress containing this object would be equal (i.e. operator==)
to an IPAddress containing the corresponding IPv4.
So we must make sure that the hash values are the same as well */
return IPAddress::createIPv4(*this).hash();
}
static const uint64_t seed = AF_INET6;
uint64_t hash1 = 0, hash2 = 0;
hash::SpookyHashV2::Hash128(&addr_, 16, &hash1, &hash2);
return hash::hash_combine(seed, hash1, hash2);
}
// public
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");
}
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);
return (mask == subMask);
}
// public
bool IPAddressV6::isLoopback() const {
const unsigned char* by = bytes();
for (int i = 0; i < 15; i++) {
if (by[i] != 0x00) {
return false;
}
}
return (by[15] == 0x01);
}
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);
}
bool IPAddressV6::isLinkLocalBroadcast() const {
static const IPAddressV6 kLinkLocalBroadcast("ff02::1");
return *this == kLinkLocalBroadcast;
}
// public
bool IPAddressV6::isPrivate() const {
return isLoopback() || inBinarySubnet({{0xfc, 0x00}}, 7);
}
bool IPAddressV6::isLinkLocal() const {
return inBinarySubnet({{0xfe, 0x80}}, 10);
}
bool IPAddressV6::isMulticast() const {
return addr_.bytes_[0] == 0xff;
}
uint8_t IPAddressV6::getMulticastFlags() const {
DCHECK(isMulticast());
return ((addr_.bytes_[1] >> 4) & 0xf);
}
uint8_t IPAddressV6::getMulticastScope() const {
DCHECK(isMulticast());
return (addr_.bytes_[1] & 0xf);
}
IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const {
// Solicted node addresses must be constructed from unicast (or anycast)
// 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];
return IPAddressV6::fromBinary(ByteRange(bytes, 16));
}
// public
IPAddressV6 IPAddressV6::mask(size_t numBits) const {
static const auto bits = bitCount();
if (numBits > bits) {
throw IPAddressFormatException("numBits(", numBits, ") > bitCount(",
bits, ")");
}
ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_);
return IPAddressV6(ba);
}
// public
string IPAddressV6::str() const {
char buffer[INET6_ADDRSTRLEN] = {0};
if (!inet_ntop(AF_INET6, &addr_.in6Addr_, buffer, INET6_ADDRSTRLEN)) {
throw IPAddressFormatException("Invalid address with hex ",
"'", detail::Bytes::toHex(bytes(), 16), "'");
}
string ip(buffer);
return std::move(ip);
}
// public
string IPAddressV6::toFullyQualified() const {
auto asHex = detail::Bytes::toHex(bytes(), 16);
uint8_t chunks = asHex.size() / 4;
for (int chunk = 1; chunk < chunks; chunk++) {
// position changes as new characters are inserted
int pos = (chunk*4) + (chunk - 1);
asHex.insert(pos, ":");
}
return asHex;
}
// public
uint8_t IPAddressV6::getNthMSByte(size_t byteIndex) const {
const auto highestIndex = byteCount() - 1;
if (byteIndex > highestIndex) {
throw std::invalid_argument(to<string>("Byte index must be <= ",
to<string>(highestIndex), " for addresses of type :",
detail::familyNameStr(AF_INET6)));
}
return bytes()[byteIndex];
}
// protected
const ByteArray16 IPAddressV6::fetchMask(size_t numBits) {
static const uint8_t bits = bitCount();
if (numBits > bits) {
throw IPAddressFormatException("IPv6 addresses are 128 bits.");
}
// masks_ is backed by an array so is zero indexed
return masks_[numBits];
}
// protected
bool IPAddressV6::inBinarySubnet(const std::array<uint8_t, 2> addr,
size_t numBits) const {
const unsigned char* subbytes = mask(numBits).bytes();
return (std::memcmp(addr.data(), subbytes, 2) == 0);
}
// static private
const std::array<ByteArray16, 129> IPAddressV6::masks_ = {{
/* /0 */ {{ 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /1 */ {{ 0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /2 */ {{ 0xc0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /3 */ {{ 0xe0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /4 */ {{ 0xf0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /5 */ {{ 0xf8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /6 */ {{ 0xfc,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /7 */ {{ 0xfe,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /8 */ {{ 0xff,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /9 */ {{ 0xff,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /10 */ {{ 0xff,0xc0,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /11 */ {{ 0xff,0xe0,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /12 */ {{ 0xff,0xf0,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /13 */ {{ 0xff,0xf8,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /14 */ {{ 0xff,0xfc,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /15 */ {{ 0xff,0xfe,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /16 */ {{ 0xff,0xff,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /17 */ {{ 0xff,0xff,0x80,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /18 */ {{ 0xff,0xff,0xc0,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /19 */ {{ 0xff,0xff,0xe0,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /20 */ {{ 0xff,0xff,0xf0,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /21 */ {{ 0xff,0xff,0xf8,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /22 */ {{ 0xff,0xff,0xfc,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /23 */ {{ 0xff,0xff,0xfe,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /24 */ {{ 0xff,0xff,0xff,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /25 */ {{ 0xff,0xff,0xff,0x80,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /26 */ {{ 0xff,0xff,0xff,0xc0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /27 */ {{ 0xff,0xff,0xff,0xe0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /28 */ {{ 0xff,0xff,0xff,0xf0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /29 */ {{ 0xff,0xff,0xff,0xf8,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /30 */ {{ 0xff,0xff,0xff,0xfc,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /31 */ {{ 0xff,0xff,0xff,0xfe,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /32 */ {{ 0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /33 */ {{ 0xff,0xff,0xff,0xff,
0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /34 */ {{ 0xff,0xff,0xff,0xff,
0xc0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /35 */ {{ 0xff,0xff,0xff,0xff,
0xe0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /36 */ {{ 0xff,0xff,0xff,0xff,
0xf0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /37 */ {{ 0xff,0xff,0xff,0xff,
0xf8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /38 */ {{ 0xff,0xff,0xff,0xff,
0xfc,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /39 */ {{ 0xff,0xff,0xff,0xff,
0xfe,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /40 */ {{ 0xff,0xff,0xff,0xff,
0xff,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /41 */ {{ 0xff,0xff,0xff,0xff,
0xff,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /42 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xc0,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /43 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xe0,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /44 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xf0,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /45 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xf8,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /46 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xfc,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /47 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xfe,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /48 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /49 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0x80,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /50 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xc0,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /51 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xe0,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /52 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xf0,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /53 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xf8,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /54 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xfc,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /55 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xfe,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /56 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /57 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x80,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /58 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xc0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /59 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xe0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /60 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xf0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /61 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xf8,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /62 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfc,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /63 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfe,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /64 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /65 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /66 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xc0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /67 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xe0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /68 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xf0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /69 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xf8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /70 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xfc,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /71 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xfe,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /72 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0x00,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /73 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0x80,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /74 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xc0,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /75 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xe0,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /76 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xf0,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /77 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xf8,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /78 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xfc,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /79 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xfe,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /80 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0x00,0x00,
0x00,0x00,0x00,0x00 }},
/* /81 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0x80,0x00,
0x00,0x00,0x00,0x00 }},
/* /82 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xc0,0x00,
0x00,0x00,0x00,0x00 }},
/* /83 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xe0,0x00,
0x00,0x00,0x00,0x00 }},
/* /84 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xf0,0x00,
0x00,0x00,0x00,0x00 }},
/* /85 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xf8,0x00,
0x00,0x00,0x00,0x00 }},
/* /86 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xfc,0x00,
0x00,0x00,0x00,0x00 }},
/* /87 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xfe,0x00,
0x00,0x00,0x00,0x00 }},
/* /88 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x00,
0x00,0x00,0x00,0x00 }},
/* /89 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x80,
0x00,0x00,0x00,0x00 }},
/* /90 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xc0,
0x00,0x00,0x00,0x00 }},
/* /91 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xe0,
0x00,0x00,0x00,0x00 }},
/* /92 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xf0,
0x00,0x00,0x00,0x00 }},
/* /93 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xf8,
0x00,0x00,0x00,0x00 }},
/* /94 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfc,
0x00,0x00,0x00,0x00 }},
/* /95 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfe,
0x00,0x00,0x00,0x00 }},
/* /96 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0x00,0x00,0x00,0x00 }},
/* /97 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0x80,0x00,0x00,0x00 }},
/* /98 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xc0,0x00,0x00,0x00 }},
/* /99 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xe0,0x00,0x00,0x00 }},
/* /100 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xf0,0x00,0x00,0x00 }},
/* /101 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xf8,0x00,0x00,0x00 }},
/* /102 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xfc,0x00,0x00,0x00 }},
/* /103 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xfe,0x00,0x00,0x00 }},
/* /104 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0x00,0x00,0x00 }},
/* /105 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0x80,0x00,0x00 }},
/* /106 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xc0,0x00,0x00 }},
/* /107 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xe0,0x00,0x00 }},
/* /108 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xf0,0x00,0x00 }},
/* /109 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xf8,0x00,0x00 }},
/* /110 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xfc,0x00,0x00 }},
/* /111 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xfe,0x00,0x00 }},
/* /112 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0x00,0x00 }},
/* /113 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0x80,0x00 }},
/* /114 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xc0,0x00 }},
/* /115 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xe0,0x00 }},
/* /116 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xf0,0x00 }},
/* /117 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xf8,0x00 }},
/* /118 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xfc,0x00 }},
/* /119 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xfe,0x00 }},
/* /120 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x00 }},
/* /121 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0x80 }},
/* /122 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xc0 }},
/* /123 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xe0 }},
/* /124 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xf0 }},
/* /125 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xf8 }},
/* /126 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfc }},
/* /127 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xfe }},
/* /128 */ {{ 0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff }},
}};
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <iostream>
#include <map>
#include <stdexcept>
#include <boost/operators.hpp>
#include "folly/Hash.h"
#include "folly/Range.h"
#include "folly/detail/IPAddress.h"
namespace folly {
class IPAddress;
class IPAddressV4;
class IPAddressV6;
class MacAddress;
/**
* Pair of IPAddressV6, netmask
*/
typedef std::pair<IPAddressV6, uint8_t> CIDRNetworkV6;
/**
* Specialization for IPv6 addresses
*/
typedef std::array<uint8_t, 16> ByteArray16;
/**
* IPv6 variation of IPAddress.
*
* Added methods: createIPv4, getIPv4For6To4, is6To4,
* isTeredo, isIPv4Mapped, tryCreateIPv4, type
*
* @see IPAddress
*/
class IPAddressV6 : boost::totally_ordered<IPAddressV6> {
public:
// V6 Address Type
enum Type {
TEREDO, T6TO4, NORMAL,
};
// A constructor parameter to indicate that we should create a link-local
// IPAddressV6.
enum LinkLocalTag {
LINK_LOCAL,
};
// Thrown when a type assertion fails
typedef std::runtime_error TypeError;
// Binary prefix for teredo networks
static const uint32_t PREFIX_TEREDO;
// Binary prefix for 6to4 networks
static const uint32_t PREFIX_6TO4;
/**
* Create a new IPAddress instance from the provided binary data.
* @throws IPAddressFormatException if the input length is not 16 bytes.
*/
static IPAddressV6 fromBinary(ByteRange bytes) {
IPAddressV6 addr;
addr.setFromBinary(bytes);
return addr;
}
/**
* Default constructor for IPAddressV6.
*
* The address value will be ::0
*/
IPAddressV6();
// Create an IPAddressV6 from a string
// @throws IPAddressFormatException
explicit IPAddressV6(StringPiece ip);
// ByteArray16 constructor
explicit IPAddressV6(const ByteArray16& src);
// in6_addr constructor
explicit IPAddressV6(const in6_addr& src);
/**
* Create a link-local IPAddressV6 from the specified ethernet MAC address.
*/
IPAddressV6(LinkLocalTag tag, MacAddress mac);
// return the mapped V4 address
// @throws IPAddressFormatException if !isIPv4Mapped
IPAddressV4 createIPv4() const;
/**
* Return a V4 address if this is a 6To4 address.
* @throws TypeError if not a 6To4 address
*/
IPAddressV4 getIPv4For6To4() const;
// Return true if a 6TO4 address
bool is6To4() const {
return type() == IPAddressV6::Type::T6TO4;
}
// Return true if a TEREDO address
bool isTeredo() const {
return type() == IPAddressV6::Type::TEREDO;
}
// return true if this is v4-to-v6-mapped
bool isIPv4Mapped() const;
// Return the V6 address type
Type type() const;
/**
* @see IPAddress#bitCount
* @returns 128
*/
static size_t bitCount() { return 128; }
/**
* @see IPAddress#toJson
*/
std::string toJson() const;
size_t hash() const;
// @see IPAddress#inSubnet
// @throws IPAddressFormatException if string doesn't contain a V6 address
bool inSubnet(StringPiece cidrNetwork) const;
// return true if address is in subnet
bool inSubnet(const IPAddressV6& subnet, uint8_t cidr) const {
return inSubnetWithMask(subnet, fetchMask(cidr));
}
bool inSubnetWithMask(const IPAddressV6& subnet,
const ByteArray16& mask) const;
// @see IPAddress#isLoopback
bool isLoopback() const;
// @see IPAddress#isNonroutable
bool isNonroutable() const {
return !isRoutable();
}
/**
* Return true if this address is routable.
*/
bool isRoutable() const;
// @see IPAddress#isPrivate
bool isPrivate() const;
/**
* Return true if this is a link-local IPv6 address.
*
* Note that this only returns true for addresses in the fe80::/10 range.
* It returns false for the loopback address (::1), even though this address
* is also effectively has link-local scope. It also returns false for
* link-scope and interface-scope multicast addresses.
*/
bool isLinkLocal() const;
/**
* Return true if this is a multicast address.
*/
bool isMulticast() const;
/**
* Return the flags for a multicast address.
* This method may only be called on multicast addresses.
*/
uint8_t getMulticastFlags() const;
/**
* Return the scope for a multicast address.
* This method may only be called on multicast addresses.
*/
uint8_t getMulticastScope() const;
// @see IPAddress#isZero
bool isZero() const {
return detail::Bytes::isZero(bytes(), 16);
}
bool isLinkLocalBroadcast() const;
// @see IPAddress#mask
IPAddressV6 mask(size_t numBits) const;
// return underlying in6_addr structure
in6_addr toAddr() const { return addr_.in6Addr_; }
sockaddr_in6 toSockAddr() const {
sockaddr_in6 addr;
memset(&addr, 0, sizeof(sockaddr_in6));
addr.sin6_family = AF_INET6;
memcpy(&addr.sin6_addr, &addr_.in6Addr_, sizeof(in6_addr));
return addr;
}
ByteArray16 toByteArray() const {
ByteArray16 ba{{0}};
std::memcpy(ba.data(), bytes(), 16);
return ba;
}
// @see IPAddress#toFullyQualified
std::string toFullyQualified() const;
// @see IPAddress#str
std::string str() const;
// @see IPAddress#version
size_t version() const { return 6; }
/**
* Return the solicited-node multicast address for this address.
*/
IPAddressV6 getSolicitedNodeAddress() const;
/**
* Return the mask associated with the given number of bits.
* If for instance numBits was 24 (e.g. /24) then the V4 mask returned should
* be {0xff, 0xff, 0xff, 0x00}.
* @param [in] numBits bitmask to retrieve
* @throws abort if numBits == 0 or numBits > bitCount()
* @return mask associated with numBits
*/
static const ByteArray16 fetchMask(size_t numBits);
// Given 2 IPAddressV6,mask pairs extract the longest common IPAddress,
// mask pair
static CIDRNetworkV6 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};
}
// Number of bytes in the address representation.
static constexpr size_t byteCount() { return 16; }
//get nth most significant bit - 0 indexed
bool getNthMSBit(size_t bitIndex) const {
return detail::getNthMSBitImpl(*this, bitIndex, AF_INET6);
}
//get nth most significant byte - 0 indexed
uint8_t getNthMSByte(size_t byteIndex) const;
//get nth bit - 0 indexed
bool getNthLSBit(size_t bitIndex) const {
return getNthMSBit(bitCount() - bitIndex - 1);
}
//get nth byte - 0 indexed
uint8_t getNthLSByte(size_t byteIndex) const {
return getNthMSByte(byteCount() - byteIndex - 1);
}
const unsigned char* bytes() const { return addr_.in6Addr_.s6_addr; }
protected:
/**
* Helper that returns true if the address is in the binary subnet specified
* by addr.
*/
bool inBinarySubnet(const std::array<uint8_t, 2> addr,
size_t numBits) const;
private:
union AddressStorage {
in6_addr in6Addr_;
ByteArray16 bytes_;
AddressStorage() {
std::memset(this, 0, sizeof(AddressStorage));
}
explicit AddressStorage(const ByteArray16& bytes): bytes_(bytes) {}
explicit AddressStorage(const in6_addr& addr): in6Addr_(addr) {}
explicit AddressStorage(MacAddress mac);
} addr_;
static const std::array<ByteArray16, 129> masks_;
/**
* Set the current IPAddressV6 object to have the address specified by bytes.
* @throws IPAddressFormatException if bytes.size() is not 16.
*/
void setFromBinary(ByteRange bytes);
};
// boost::hash uses hash_value() so this allows boost::hash to work
// automatically for IPAddressV6
std::size_t hash_value(const IPAddressV6& addr);
std::ostream& operator<<(std::ostream& os, const IPAddressV6& addr);
// Define toAppend() to allow IPAddressV6 to be used with to<string>
void toAppend(IPAddressV6 addr, std::string* result);
void toAppend(IPAddressV6 addr, fbstring* result);
/**
* Return true if two addresses are equal.
*/
inline bool operator==(const IPAddressV6& addr1, const IPAddressV6& addr2) {
return (std::memcmp(addr1.toAddr().s6_addr, addr2.toAddr().s6_addr, 16) == 0);
}
// Return true if addr1 < addr2
inline bool operator<(const IPAddressV6& addr1, const IPAddressV6& addr2) {
return (std::memcmp(addr1.toAddr().s6_addr, addr2.toAddr().s6_addr, 16) < 0);
}
} // folly
namespace std {
template<>
struct hash<folly::IPAddressV6> {
size_t operator()(const folly::IPAddressV6& addr) const {
return addr.hash();
}
};
} // std
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MacAddress.h"
#include "folly/Exception.h"
#include "folly/IPAddressV6.h"
using std::invalid_argument;
using std::string;
namespace folly {
const MacAddress MacAddress::BROADCAST{Endian::big(0xffffffffffffU)};
const MacAddress MacAddress::ZERO;
MacAddress::MacAddress(StringPiece str) {
memset(&bytes_, 0, 8);
parse(str);
}
MacAddress MacAddress::createMulticast(IPAddressV6 v6addr) {
// This method should only be used for multicast addresses.
DCHECK(v6addr.isMulticast());
uint8_t bytes[SIZE];
bytes[0] = 0x33;
bytes[1] = 0x33;
memcpy(bytes + 2, v6addr.bytes() + 12, 4);
return fromBinary(ByteRange(bytes, SIZE));
}
string MacAddress::toString() const {
static const char hexValues[] = "0123456789abcdef";
string result;
result.resize(17);
result[0] = hexValues[getByte(0) >> 4];
result[1] = hexValues[getByte(0) & 0xf];
result[2] = ':';
result[3] = hexValues[getByte(1) >> 4];
result[4] = hexValues[getByte(1) & 0xf];
result[5] = ':';
result[6] = hexValues[getByte(2) >> 4];
result[7] = hexValues[getByte(2) & 0xf];
result[8] = ':';
result[9] = hexValues[getByte(3) >> 4];
result[10] = hexValues[getByte(3) & 0xf];
result[11] = ':';
result[12] = hexValues[getByte(4) >> 4];
result[13] = hexValues[getByte(4) & 0xf];
result[14] = ':';
result[15] = hexValues[getByte(5) >> 4];
result[16] = hexValues[getByte(5) & 0xf];
return result;
}
void MacAddress::parse(StringPiece str) {
// Helper function to convert a single hex char into an integer
auto unhex = [](char c) -> int {
return c >= '0' && c <= '9' ? c - '0' :
c >= 'A' && c <= 'F' ? c - 'A' + 10 :
c >= 'a' && c <= 'f' ? c - 'a' + 10 :
-1;
};
auto isSeparatorChar = [](char c) {
return c == ':' || c == '-';
};
uint8_t parsed[SIZE];
auto p = str.begin();
for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) {
if (p == str.end()) {
throw invalid_argument(to<string>("invalid MAC address \"", str,
"\": not enough digits"));
}
// Skip over ':' or '-' separators between bytes
if (byteIndex != 0 && isSeparatorChar(*p)) {
++p;
if (p == str.end()) {
throw invalid_argument(to<string>("invalid MAC address \"", str,
"\": not enough digits"));
}
}
// Parse the upper nibble
int upper = unhex(*p);
if (upper < 0) {
throw invalid_argument(to<string>("invalid MAC address \"", str,
"\": contains non-hex digit"));
}
++p;
// Parse the lower nibble
int lower;
if (p == str.end()) {
lower = upper;
upper = 0;
} else {
lower = unhex(*p);
if (lower < 0) {
// Also accept ':', '-', or '\0', to handle the case where one
// of the bytes was represented by just a single digit.
if (isSeparatorChar(*p)) {
lower = upper;
upper = 0;
} else {
throw invalid_argument(to<string>("invalid MAC address \"", str,
"\": contains non-hex digit"));
}
}
++p;
}
// Update parsed with the newly parsed byte
parsed[byteIndex] = ((upper << 4) | lower);
}
if (p != str.end()) {
// String is too long to be a MAC address
throw invalid_argument(to<string>("invalid MAC address \"", str,
"\": found trailing characters"));
}
// Only update now that we have successfully parsed the entire
// string. This way we remain unchanged on error.
setFromBinary(ByteRange(parsed, SIZE));
}
void MacAddress::setFromBinary(ByteRange value) {
if (value.size() != SIZE) {
throw invalid_argument(to<string>("MAC address must be 6 bytes "
"long, got ", value.size()));
}
memcpy(bytes_ + 2, value.begin(), SIZE);
}
std::ostream& operator<<(std::ostream& os, MacAddress address) {
os << address.toString();
return os;
}
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <iostream>
#include <boost/operators.hpp>
#include "folly/Bits.h"
#include "folly/Conv.h"
namespace folly {
class IPAddressV6;
/*
* MacAddress represents an IEEE 802 MAC address.
*/
class MacAddress : private boost::totally_ordered<MacAddress> {
public:
static constexpr size_t SIZE = 6;
static const MacAddress BROADCAST;
static const MacAddress ZERO;
/*
* Construct a zero-initialized MacAddress.
*/
MacAddress() {
memset(&bytes_, 0, 8);
}
/*
* Parse a MacAddress from a human-readable string.
* The string must contain 6 one- or two-digit hexadecimal
* numbers, separated by dashes or colons.
* Examples: 00:02:C9:C8:F9:68 or 0-2-c9-c8-f9-68
*/
explicit MacAddress(StringPiece str);
/*
* Construct a MAC address from its 6-byte binary value
*/
static MacAddress fromBinary(ByteRange value) {
MacAddress ret;
ret.setFromBinary(value);
return ret;
}
/*
* Construct a MacAddress from a uint64_t in network byte order.
*
* The first two bytes are ignored, and the MAC address is taken from the
* latter 6 bytes.
*
* This is a static method rather than a constructor to avoid confusion
* between host and network byte order constructors.
*/
static MacAddress fromNBO(uint64_t value) {
return MacAddress(value);
}
/*
* Construct a MacAddress from a uint64_t in host byte order.
*
* The most significant two bytes are ignored, and the MAC address is taken
* from the least significant 6 bytes.
*
* This is a static method rather than a constructor to avoid confusion
* between host and network byte order constructors.
*/
static MacAddress fromHBO(uint64_t value) {
return MacAddress(Endian::big(value));
}
/*
* Construct the multicast MacAddress for the specified multicast IPv6
* address.
*/
static MacAddress createMulticast(IPAddressV6 addr);
/*
* Get a pointer to the MAC address' binary value.
*
* The returned value points to internal storage inside the MacAddress
* object. It is only valid as long as the MacAddress, and its contents may
* change if the MacAddress is updated.
*/
const uint8_t* bytes() const {
return bytes_ + 2;
}
/*
* Return the address as a uint64_t, in network byte order.
*
* The first two bytes will be 0, and the subsequent 6 bytes will contain
* the address in network byte order.
*/
uint64_t u64NBO() const {
return packedBytes();
}
/*
* Return the address as a uint64_t, in host byte order.
*
* The two most significant bytes will be 0, and the remaining 6 bytes will
* contain the address. The most significant of these 6 bytes will contain
* the first byte that appear on the wire, and the least significant byte
* will contain the last byte.
*/
uint64_t u64HBO() const {
// Endian::big() does what we want here, even though we are converting
// from big-endian to host byte order. This swaps if and only if
// the host byte order is little endian.
return Endian::big(packedBytes());
}
/*
* Return a human-readable representation of the MAC address.
*/
std::string toString() const;
/*
* Update the current MacAddress object from a human-readable string.
*/
void parse(StringPiece str);
/*
* Update the current MacAddress object from a 6-byte binary representation.
*/
void setFromBinary(ByteRange value);
bool isBroadcast() const {
return *this == BROADCAST;
}
bool isMulticast() const {
return getByte(0) & 0x1;
}
bool isUnicast() const {
return !isMulticast();
}
/*
* Return true if this MAC address is locally administered.
*
* Locally administered addresses are assigned by the local network
* administrator, and are not guaranteed to be globally unique. (It is
* similar to IPv4's private address space.)
*
* Note that isLocallyAdministered() will return true for the broadcast
* address, since it has the locally administered bit set.
*/
bool isLocallyAdministered() const {
return getByte(0) & 0x2;
}
// Equality and less-than operators.
// boost::totally_ordered provides the other comparison operators.
bool operator==(const MacAddress& other) const {
// All constructors and modifying methods make sure padding is 0,
// so we don't need to mask these bytes out when comparing here.
return packedBytes() == other.packedBytes();
}
bool operator<(const MacAddress& other) const {
return u64HBO() < other.u64HBO();
}
private:
explicit MacAddress(uint64_t valueNBO) {
memcpy(&bytes_, &valueNBO, 8);
// Set the pad bytes to 0.
// This allows us to easily compare two MacAddresses,
// without having to worry about differences in the padding.
bytes_[0] = 0;
bytes_[1] = 0;
}
/* We store the 6 bytes starting at bytes_[2] (most significant)
through bytes_[7] (least).
bytes_[0] and bytes_[1] are always equal to 0 to simplify comparisons.
*/
unsigned char bytes_[8];
inline uint64_t getByte(size_t index) const {
return bytes_[index + 2];
}
uint64_t packedBytes() const {
uint64_t u64;
memcpy(&u64, bytes_, 8);
return u64;
}
};
/* Define toAppend() so to<string> will work */
template <class Tgt>
typename std::enable_if<IsSomeString<Tgt>::value>::type
toAppend(MacAddress address, Tgt* result) {
toAppend(address.toString(), result);
}
std::ostream& operator<<(std::ostream& os, MacAddress address);
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <boost/noncopyable.hpp>
#include <glog/logging.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <string>
#include <sstream>
#include <type_traits>
#include <vector>
extern "C" {
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
}
#include "folly/Conv.h"
#include "folly/Format.h"
namespace folly { namespace detail {
inline std::string familyNameStr(sa_family_t family) {
switch (family) {
case AF_INET:
return "AF_INET";
case AF_INET6:
return "AF_INET6";
case AF_UNSPEC:
return "AF_UNSPEC";
case AF_UNIX:
return "AF_UNIX";
default:
return folly::format("sa_family_t({})",
folly::to<std::string>(family)).str();
}
}
template<typename IPAddrType>
inline bool getNthMSBitImpl(const IPAddrType& ip, uint8_t bitIndex,
sa_family_t family) {
if (bitIndex >= ip.bitCount()) {
throw std::invalid_argument(folly::to<std::string>("Bit index must be < ",
ip.bitCount(), " for addresses of type :", familyNameStr(family)));
}
//Underlying bytes are in n/w byte order
return (ip.getNthMSByte(bitIndex / 8) & (0x80 >> (bitIndex % 8))) != 0;
}
/**
* Helper for working with unsigned char* or uint8_t* ByteArray values
*/
struct Bytes : private boost::noncopyable {
// return true if all values of src are zero
static bool isZero(const uint8_t* src, std::size_t len) {
for (auto i = 0; i < len; i++) {
if (src[i] != 0x00) {
return false;
}
}
return true;
}
// mask the values from two byte arrays, returning a new byte array
template<std::size_t N>
static std::array<uint8_t, N> mask(const std::array<uint8_t, N>& a,
const std::array<uint8_t, N>& b) {
static_assert(N > 0, "Can't mask an empty ByteArray");
std::size_t asize = a.size();
std::array<uint8_t, N> ba{{0}};
for (int i = 0; i < asize; i++) {
ba[i] = a[i] & b[i];
}
return ba;
}
template<std::size_t N>
static std::pair<std::array<uint8_t, N>, uint8_t>
longestCommonPrefix(
const std::array<uint8_t, N>& one, uint8_t oneMask,
const std::array<uint8_t, N>& two, uint8_t twoMask) {
static constexpr auto kBitCount = N * 8;
static constexpr std::array<uint8_t, 8> kMasks {{
0x80, // /1
0xc0, // /2
0xe0, // /3
0xf0, // /4
0xf8, // /5
0xfc, // /6
0xfe, // /7
0xff // /8
}};
if (oneMask > kBitCount || twoMask > kBitCount) {
throw std::invalid_argument(folly::to<std::string>("Invalid mask "
"length: ", oneMask > twoMask ? oneMask : twoMask,
". Mask length must be <= ", kBitCount));
}
auto mask = std::min(oneMask, twoMask);
uint8_t byteIndex = 0;
std::array<uint8_t, N> ba{{0}};
// Compare a byte at a time. Note - I measured compared this with
// going multiple bytes at a time (8, 4, 2 and 1). It turns out
// to be 20 - 25% slower for 4 and 16 byte arrays.
while (byteIndex * 8 <= mask && one[byteIndex] == two[byteIndex]) {
ba[byteIndex] = one[byteIndex];
++byteIndex;
}
auto bitIndex = std::min(mask, (uint8_t)(byteIndex * 8));
// Compute the bit up to which the two byte arrays match in the
// unmatched byte.
// Here the check is bitIndex < mask since the 0th mask entry in
// kMasks array holds the mask for masking the MSb in this byte.
// We could instead make it hold so that no 0th entry masks no
// bits but thats a useless iteration.
while (bitIndex < mask && ((one[bitIndex / 8] & kMasks[bitIndex % 8]) ==
(two[bitIndex / 8] & kMasks[bitIndex % 8]))) {
ba[bitIndex / 8] = one[bitIndex / 8] & kMasks[bitIndex % 8];
++bitIndex;
}
return {ba, bitIndex};
}
// create an in_addr from an uint8_t*
static inline in_addr mkAddress4(const uint8_t* src) {
union {
in_addr addr;
uint8_t bytes[4];
} addr;
std::memset(&addr, 0, 4);
std::memcpy(addr.bytes, src, 4);
return addr.addr;
}
// create an in6_addr from an uint8_t*
static inline in6_addr mkAddress6(const uint8_t* src) {
in6_addr addr;
std::memset(&addr, 0, 16);
std::memcpy(addr.s6_addr, src, 16);
return addr;
}
// convert an uint8_t* to its hex value
static std::string toHex(const uint8_t* src, std::size_t len) {
static const char* const lut = "0123456789abcdef";
std::stringstream ss;
for (int i = 0; i < len; i++) {
const unsigned char c = src[i];
ss << lut[c >> 4] << lut[c & 15];
}
return ss.str();
}
private:
Bytes() = delete;
~Bytes() = delete;
};
}} // folly::detail
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IPAddressTest.h"
#include <gtest/gtest.h>
#include "folly/Bits.h"
#include "folly/Format.h"
#include "folly/String.h"
#include "folly/MacAddress.h"
using namespace folly;
using namespace std;
// tests code example
TEST(IPAddress, CodeExample) {
EXPECT_EQ(4, sizeof(IPAddressV4));
EXPECT_EQ(16, sizeof(IPAddressV6));
EXPECT_EQ(20, sizeof(IPAddress));
IPAddress v4addr("192.0.2.129");
IPAddress v6map("::ffff:192.0.2.129");
EXPECT_TRUE(v4addr.inSubnet("192.0.2.0/24"));
EXPECT_TRUE(v4addr.inSubnet(IPAddress("192.0.2.0"), 24));
EXPECT_TRUE(v4addr.inSubnet("192.0.2.128/30"));
EXPECT_FALSE(v4addr.inSubnet("192.0.2.128/32"));
EXPECT_EQ(2164392128, v4addr.asV4().toLong());
EXPECT_EQ(3221226113, v4addr.asV4().toLongHBO());
ASSERT_TRUE(v4addr.isV4());
ASSERT_TRUE(v6map.isV6());
EXPECT_TRUE(v4addr == v6map);
ASSERT_TRUE(v6map.isIPv4Mapped());
EXPECT_TRUE(v4addr.asV4() == IPAddress::createIPv4(v6map));
EXPECT_TRUE(IPAddress::createIPv6(v4addr) == v6map.asV6());
}
TEST(IPAddress, Ordering) {
IPAddress a1("0.1.1.1");
IPAddress a2("1.1.1.0");
EXPECT_TRUE(a1 < a2);
IPAddress b1("::ffff:0.1.1.1");
IPAddress b2("::ffff:1.1.1.0");
EXPECT_TRUE(b1 < b2);
}
TEST(IPAddress, InvalidAddressFamilyExceptions) {
// asV4
{
IPAddress addr;
EXPECT_THROW(addr.asV4(), InvalidAddressFamilyException);
}
// asV6
{
IPAddress addr;
EXPECT_THROW(addr.asV6(), InvalidAddressFamilyException);
}
// sockaddr ctor
{
// setup
sockaddr_in addr;
addr.sin_family = AF_UNSPEC;
EXPECT_THROW(IPAddress((sockaddr *)&addr), InvalidAddressFamilyException);
}
}
TEST(IPAddress, CreateNetwork) {
// test valid IPv4 network
{
auto net = IPAddress::createNetwork("192.168.0.1/24");
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.0", net.first.str());
EXPECT_EQ(24, net.second);
EXPECT_EQ("192.168.0.0/24", IPAddress::networkToString(net));
}
// test valid IPv4 network without applying mask
{
auto net = IPAddress::createNetwork("192.168.0.1/24", -1, false);
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.1", net.first.str());
EXPECT_EQ(24, net.second);
EXPECT_EQ("192.168.0.1/24", IPAddress::networkToString(net));
}
// test valid IPv6 network
{
auto net = IPAddress::createNetwork("1999::1/24");
ASSERT_TRUE(net.first.isV6());
EXPECT_EQ("1999::", net.first.str());
EXPECT_EQ(24, net.second);
EXPECT_EQ("1999::/24", IPAddress::networkToString(net));
}
// test valid IPv6 network without applying mask
{
auto net = IPAddress::createNetwork("1999::1/24", -1, false);
ASSERT_TRUE(net.first.isV6());
EXPECT_EQ("1999::1", net.first.str());
EXPECT_EQ(24, net.second);
EXPECT_EQ("1999::1/24", IPAddress::networkToString(net));
}
// test empty string
EXPECT_THROW(IPAddress::createNetwork(""), IPAddressFormatException);
// test multi slash string
EXPECT_THROW(IPAddress::createNetwork("192.168.0.1/24/36"),
IPAddressFormatException);
// test no slash string with default IPv4
{
auto net = IPAddress::createNetwork("192.168.0.1");
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.1", net.first.str());
EXPECT_EQ(32, net.second); // auto-detected
net = IPAddress::createNetwork("192.168.0.1", -1, false);
ASSERT_TRUE(net.first.isV4());
EXPECT_EQ("192.168.0.1", net.first.str());
EXPECT_EQ(32, net.second);
}
// test no slash string with default IPv6
{
auto net = IPAddress::createNetwork("1999::1");
ASSERT_TRUE(net.first.isV6());
EXPECT_EQ("1999::1", net.first.str());
EXPECT_EQ(128, net.second);
}
// test no slash string with invalid default
EXPECT_THROW(IPAddress::createNetwork("192.168.0.1", 33),
IPAddressFormatException);
}
// test assignment operators
TEST(IPAddress, Assignment) {
static const string kIPv4Addr = "69.63.189.16";
static const string kIPv6Addr = "2620:0:1cfe:face:b00c::3";
// Test assigning IPAddressV6 addr to IPAddress (was V4)
{
IPAddress addr(kIPv4Addr);
IPAddressV6 addrV6 = IPAddress(kIPv6Addr).asV6();
EXPECT_TRUE(addr.isV4());
EXPECT_EQ(kIPv4Addr, addr.str());
addr = addrV6;
EXPECT_TRUE(addr.isV6());
EXPECT_EQ(kIPv6Addr, addr.str());
}
// Test assigning IPAddressV4 addr to IPAddress (was V6)
{
IPAddress addr(kIPv6Addr);
IPAddressV4 addrV4 = IPAddress(kIPv4Addr).asV4();
EXPECT_TRUE(addr.isV6());
EXPECT_EQ(kIPv6Addr, addr.str());
addr = addrV4;
EXPECT_TRUE(addr.isV4());
EXPECT_EQ(kIPv4Addr, addr.str());
}
// Test assigning IPAddress(v6) to IPAddress (was v4)
{
IPAddress addr(kIPv4Addr);
IPAddress addrV6 = IPAddress(kIPv6Addr);
EXPECT_TRUE(addr.isV4());
EXPECT_EQ(kIPv4Addr, addr.str());
addr = addrV6;
EXPECT_TRUE(addr.isV6());
EXPECT_EQ(kIPv6Addr, addr.str());
}
// Test assigning IPAddress(v4) to IPAddress (was v6)
{
IPAddress addr(kIPv6Addr);
IPAddress addrV4 = IPAddress(kIPv4Addr);
EXPECT_TRUE(addr.isV6());
EXPECT_EQ(kIPv6Addr, addr.str());
addr = addrV4;
EXPECT_TRUE(addr.isV4());
EXPECT_EQ(kIPv4Addr, addr.str());
}
}
// Test the default constructors
TEST(IPAddress, CtorDefault) {
IPAddressV4 v4;
EXPECT_EQ(IPAddressV4("0.0.0.0"), v4);
IPAddressV6 v6;
EXPECT_EQ(IPAddressV6("::0"), v6);
}
// Test addresses constructed using a in[6]_addr value
TEST_P(IPAddressTest, CtorAddress) {
AddressData param = GetParam();
IPAddress strAddr(param.address);
IPAddress address;
if (param.version == 4) {
in_addr v4addr = detail::Bytes::mkAddress4(&param.bytes[0]);
address = IPAddress(v4addr);
} else {
in6_addr v6addr = detail::Bytes::mkAddress6(&param.bytes[0]);
address = IPAddress(v6addr);
}
ExpectIsValid(address);
EXPECT_EQ(strAddr, address);
}
// Test addresses constructed using a binary address
TEST_P(IPAddressTest, CtorBinary) {
AddressData param = GetParam();
IPAddress address;
if (param.version == 4) {
in_addr v4addr = AddressData::parseAddress4(param.address);
address = IPAddress::fromBinary(ByteRange((unsigned char*)&v4addr, 4));
} else {
in6_addr v6addr = AddressData::parseAddress6(param.address);
address = IPAddress::fromBinary(ByteRange((unsigned char*)&v6addr, 16));
}
ExpectIsValid(address);
EXPECT_EQ(IPAddress(param.address), address);
}
// Test addresses constructed using a string
TEST_P(IPAddressTest, CtorString) {
AddressData param = GetParam();
IPAddress address(param.address);
ExpectIsValid(address);
// Test the direct version-specific constructor
if (param.version == 4) {
IPAddressV4 v4(param.address);
ExpectIsValid(IPAddress(v4));
EXPECT_THROW(IPAddressV6 v6(param.address), IPAddressFormatException);
} else if (param.version == 6) {
IPAddressV6 v6(param.address);
ExpectIsValid(IPAddress(v6));
EXPECT_THROW(IPAddressV4 v4(param.address), IPAddressFormatException);
}
}
TEST(IPAddress, CtorSockaddr) {
// test v4 address
{
// setup
sockaddr_in addr;
in_addr sin_addr;
sin_addr.s_addr = htonl(2122547223);
addr.sin_family = AF_INET;
addr.sin_addr = sin_addr;
IPAddress ipAddr((sockaddr *)&addr);
EXPECT_TRUE(ipAddr.isV4());
EXPECT_EQ("126.131.128.23", ipAddr.str());
}
// test v6 address
{
// setup
sockaddr_in6 addr;
in6_addr sin_addr;
ByteArray16 sec{{
// 2620:0:1cfe:face:b00c::3
38,32,0,0,28,254,250,206,176,12,0,0,0,0,0,3
}};
std::memcpy(sin_addr.s6_addr, sec.data(), 16);
addr.sin6_family = AF_INET6;
addr.sin6_addr = sin_addr;
IPAddress ipAddr((sockaddr *)&addr);
EXPECT_TRUE(ipAddr.isV6());
EXPECT_EQ("2620:0:1cfe:face:b00c::3", ipAddr.str());
}
// test nullptr exception
{
sockaddr *addr = nullptr;
EXPECT_THROW(IPAddress((const sockaddr*)addr), IPAddressFormatException);
}
// test invalid family exception
{
// setup
sockaddr_in addr;
in_addr sin_addr;
sin_addr.s_addr = htonl(2122547223);
addr.sin_family = AF_UNSPEC;
addr.sin_addr = sin_addr;
EXPECT_THROW(IPAddress((sockaddr *)&addr), IPAddressFormatException);
}
}
TEST(IPAddress, ToSockaddrStorage) {
// test v4 address
{
string strAddr("126.131.128.23");
IPAddress addr(strAddr);
sockaddr_storage out;
ASSERT_TRUE(addr.isV4()); // test invariant
EXPECT_GT(addr.toSockaddrStorage(&out), 0);
IPAddress sockAddr((sockaddr*)&out);
ASSERT_TRUE(sockAddr.isV4());
EXPECT_EQ(strAddr, sockAddr.str());
}
// test v6 address
{
string strAddr("2620:0:1cfe:face:b00c::3");
IPAddress addr(strAddr);
sockaddr_storage out;
ASSERT_TRUE(addr.isV6()); // test invariant
EXPECT_GT(addr.toSockaddrStorage(&out), 0);
IPAddress sockAddr((sockaddr*)&out);
ASSERT_TRUE(sockAddr.isV6());
EXPECT_EQ(strAddr, sockAddr.str());
}
// test nullptr exception
{
sockaddr_storage *out = nullptr;
IPAddress addr("127.0.0.1");
EXPECT_THROW(addr.toSockaddrStorage(out), IPAddressFormatException);
}
// test invalid family exception
{
IPAddress addr;
sockaddr_storage out;
ASSERT_EQ(AF_UNSPEC, addr.family());
EXPECT_THROW(addr.toSockaddrStorage(&out), InvalidAddressFamilyException);
}
}
TEST(IPAddress, ToString) {
// Test with IPAddressV4
IPAddressV4 addr_10_0_0_1("10.0.0.1");
EXPECT_EQ("10.0.0.1", folly::to<string>(addr_10_0_0_1));
// Test with IPAddressV6
IPAddressV6 addr_1("::1");
EXPECT_EQ("::1", folly::to<string>(addr_1));
// Test with IPAddress, both V4 and V6
IPAddress addr_10_1_2_3("10.1.2.3");
EXPECT_EQ("10.1.2.3", folly::to<string>(addr_10_1_2_3));
IPAddress addr_1_2_3("1:2::3");
EXPECT_EQ("1:2::3", folly::to<string>(addr_1_2_3));
// Test a combination of all the above arguments
EXPECT_EQ("1:2::3 - 10.0.0.1 - ::1 - 10.1.2.3",
folly::to<string>(addr_1_2_3, " - ", addr_10_0_0_1,
" - ", addr_1, " - ", addr_10_1_2_3));
}
// Test that invalid string values are killed
TEST_P(IPAddressCtorTest, InvalidCreation) {
string addr = GetParam();
EXPECT_THROW(IPAddress((const string)addr), IPAddressFormatException)
<< "IPAddress(" << addr << ") "
<< "should have thrown an IPAddressFormatException";
}
// Test that invalid binary values throw an exception
TEST_P(IPAddressCtorBinaryTest, InvalidBinary) {
auto bin = GetParam();
EXPECT_THROW(IPAddress::fromBinary(ByteRange(&bin[0], bin.size())),
IPAddressFormatException);
}
// Test toFullyQualified()
TEST(IPAddress, ToFullyQualifiedFb) {
IPAddress ip("2620:0:1cfe:face:b00c::3");
EXPECT_EQ("2620:0000:1cfe:face:b00c:0000:0000:0003", ip.toFullyQualified())
<< ip;
}
TEST(IPAddress, ToFullyQualifiedLocal) {
IPAddress ip("::1");
EXPECT_EQ("0000:0000:0000:0000:0000:0000:0000:0001", ip.toFullyQualified())
<< ip;
}
// test v4-v6 mapped addresses
TEST_P(IPAddressMappedTest, MappedEqual) {
auto param = GetParam();
string mappedIp = param.first;
string otherIp = param.second;
auto mapped = IPAddress(mappedIp);
auto expected = IPAddress(otherIp);
EXPECT_EQ(expected, mapped);
IPAddress v6addr;
if (mapped.isV4()) {
v6addr = mapped.asV4().createIPv6();
} else if (expected.isV4()) {
v6addr = expected.asV4().createIPv6();
}
EXPECT_TRUE(v6addr.isV6());
EXPECT_TRUE(mapped == v6addr);
EXPECT_TRUE(expected == v6addr);
}
// Test subnet mask calculations
TEST_P(IPAddressMaskTest, Masks) {
auto param = GetParam();
IPAddress ip(param.address);
IPAddress masked = ip.mask(param.mask);
EXPECT_EQ(param.subnet, masked.str())
<< param.address << "/" << to_string(param.mask)
<< " -> " << param.subnet;
}
// Test inSubnet calculations
TEST_P(IPAddressMaskTest, InSubnet) {
auto param = GetParam();
IPAddress ip(param.address);
IPAddress subnet(param.subnet);
EXPECT_TRUE(ip.inSubnet(subnet, param.mask));
}
// Test boundary conditions for subnet calculations
TEST_P(IPAddressMaskBoundaryTest, NonMaskedSubnet) {
auto param = GetParam();
IPAddress ip(param.address);
IPAddress subnet(param.subnet);
EXPECT_EQ(param.inSubnet, ip.inSubnet(subnet, param.mask));
}
// Test subnet calcs with 6to4 addresses
TEST(IPAddress, InSubnetWith6to4) {
auto ip = IPAddress("2002:c000:022a::"); // 192.0.2.42
auto subnet = IPAddress("192.0.0.0");
EXPECT_TRUE(ip.inSubnet(subnet, 16));
auto ip2 = IPAddress("192.0.0.1");
auto subnet2 = IPAddress("2002:c000:0000::"); // 192.0.0.0
EXPECT_TRUE(ip2.inSubnet(subnet2, 14));
auto ip3 = IPAddress("2002:c000:022a::"); // 192.0.2.42
auto subnet3 = IPAddress("2002:c000:0000::"); // 192.0.0.0
EXPECT_TRUE(ip3.inSubnet(subnet3, 16));
}
static vector<pair<string, uint8_t> > invalidMasks = {
{"127.0.0.1", 33},
{"::1", 129},
};
TEST(IPAddress, InvalidMask) {
for (auto& tc : invalidMasks) {
uint8_t mask = tc.second;
auto ip = IPAddress(tc.first);
EXPECT_THROW(ip.mask(tc.second), IPAddressFormatException);
}
}
static vector<pair<string, IPAddressV6::Type> > v6types = {
{"::1", IPAddressV6::Type::NORMAL},
{"2620:0:1cfe:face:b00c::3", IPAddressV6::Type::NORMAL},
{"2001:0000:4136:e378:8000:63bf:3fff:fdd2", IPAddressV6::Type::TEREDO},
{"2002:c000:022a::", IPAddressV6::Type::T6TO4},
};
TEST(IPAddress, V6Types) {
auto mkName = [&](const IPAddressV6::Type t) -> string {
switch (t) {
case IPAddressV6::Type::TEREDO:
return "teredo";
case IPAddressV6::Type::T6TO4:
return "6to4";
default:
return "default";
}
};
for (auto& tc : v6types) {
auto ip = IPAddress(tc.first);
EXPECT_TRUE(ip.isV6());
IPAddressV6 ipv6 = ip.asV6();
EXPECT_EQ(tc.second, ipv6.type())
<< "expected " << mkName(tc.second) << ", got " << mkName(ipv6.type());
switch (tc.second) {
case IPAddressV6::Type::TEREDO:
EXPECT_TRUE(ipv6.isTeredo()) << "isTeredo was false";
EXPECT_FALSE(ipv6.is6To4()) << "is6To4 was true";
break;
case IPAddressV6::Type::T6TO4:
EXPECT_TRUE(ipv6.is6To4()) << "is6To4 was false";
EXPECT_FALSE(ipv6.isTeredo()) << "isTeredo was true";
break;
case IPAddressV6::Type::NORMAL:
EXPECT_FALSE(ipv6.is6To4()) << "is6To4 was true";
EXPECT_FALSE(ipv6.isTeredo()) << "isTeredo was true";
break;
default:
throw std::range_error("Invalid expected type: " +
to_string(tc.second));
}
}
}
static vector<pair<string, uint32_t> > provideToLong = {
{"0.0.0.0", 0},
{"10.0.0.0", 167772160},
{"126.131.128.23", 2122547223},
{"192.168.0.0", 3232235520},
};
TEST(IPAddress, ToLong) {
for (auto& tc : provideToLong) {
auto ip = IPAddress(tc.first);
EXPECT_TRUE(ip.isV4());
IPAddressV4 ipv4 = ip.asV4();
EXPECT_EQ(tc.second, ipv4.toLongHBO());
auto ip2 = IPAddress::fromLongHBO(tc.second);
EXPECT_TRUE(ip2.isV4());
EXPECT_TRUE(tc.first.compare(ip2.str()) == 0);
EXPECT_EQ(tc.second, ip2.asV4().toLongHBO());
auto nla = htonl(tc.second);
auto ip3 = IPAddress::fromLong(nla);
EXPECT_TRUE(ip3.isV4());
EXPECT_TRUE(tc.first.compare(ip3.str()) == 0);
EXPECT_EQ(nla, ip3.asV4().toLong());
}
}
TEST(IPAddress, fromBinaryV4) {
for (auto& tc : provideToLong) {
SCOPED_TRACE(tc.first);
union {
uint8_t u8[4];
uint32_t u32;
} data;
data.u32 = Endian::big(tc.second);
ByteRange bytes(data.u8, 4);
auto fromBin = IPAddressV4::fromBinary(bytes);
IPAddressV4 fromStr(tc.first);
EXPECT_EQ(fromStr, fromBin);
IPAddressV4 addr2("0.0.0.0");
addr2 = IPAddressV4::fromBinary(bytes);
EXPECT_EQ(fromStr, addr2);
IPAddress genericAddr = IPAddress::fromBinary(bytes);
ASSERT_TRUE(genericAddr.isV4());
EXPECT_EQ(fromStr, genericAddr.asV4());
EXPECT_EQ(ByteRange(genericAddr.bytes(), genericAddr.byteCount()), bytes);
}
uint8_t data[20];
EXPECT_THROW(IPAddressV4::fromBinary(ByteRange(data, 3)),
IPAddressFormatException);
EXPECT_THROW(IPAddressV4::fromBinary(ByteRange(data, 16)),
IPAddressFormatException);
EXPECT_THROW(IPAddressV4::fromBinary(ByteRange(data, 20)),
IPAddressFormatException);
}
static vector<pair<string, vector<uint8_t> > > provideBinary16Bytes = {
{"::0",
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{"1::2",
{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}},
{"fe80::0012:34ff:fe56:78ab",
{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x12, 0x34, 0xff, 0xfe, 0x56, 0x78, 0xab}},
{"2001:db8:1234:5678:90ab:cdef:8765:4321",
{0x20, 0x01, 0x0d, 0xb8, 0x12, 0x34, 0x56, 0x78,
0x90, 0xab, 0xcd, 0xef, 0x87, 0x65, 0x43, 0x21}},
{"::ffff:0:c0a8:1",
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xc0, 0xa8, 0x00, 0x01}},
};
TEST(IPAddress, fromBinaryV6) {
for (auto& tc : provideBinary16Bytes) {
SCOPED_TRACE(tc.first);
ByteRange bytes(&tc.second.front(), tc.second.size());
auto fromBin = IPAddressV6::fromBinary(bytes);
IPAddressV6 fromStr(tc.first);
EXPECT_EQ(fromStr, fromBin);
IPAddressV6 addr2("::0");
addr2 = IPAddressV6::fromBinary(bytes);
EXPECT_EQ(fromStr, addr2);
IPAddress genericAddr = IPAddress::fromBinary(bytes);
ASSERT_TRUE(genericAddr.isV6());
EXPECT_EQ(fromStr, genericAddr.asV6());
EXPECT_EQ(ByteRange(genericAddr.bytes(), genericAddr.byteCount()), bytes);
}
uint8_t data[20];
EXPECT_THROW(IPAddressV6::fromBinary(ByteRange(data, 3)),
IPAddressFormatException);
EXPECT_THROW(IPAddressV6::fromBinary(ByteRange(data, 4)),
IPAddressFormatException);
EXPECT_THROW(IPAddressV6::fromBinary(ByteRange(data, 20)),
IPAddressFormatException);
}
TEST_P(IPAddressFlagTest, IsLoopback) {
AddressFlags param = GetParam();
IPAddress addr(param.address);
EXPECT_EQ(param.version, addr.version());
EXPECT_EQ(param.isLoopback(), addr.isLoopback());
}
TEST_P(IPAddressFlagTest, IsPrivate) {
AddressFlags param = GetParam();
IPAddress addr(param.address);
EXPECT_EQ(param.version, addr.version());
EXPECT_EQ(param.isPrivate(), addr.isPrivate()) << addr;
}
TEST_P(IPAddressFlagTest, IsNonroutable) {
AddressFlags param = GetParam();
IPAddress addr(param.address);
EXPECT_EQ(param.version, addr.version());
EXPECT_EQ(param.isNonroutable(), addr.isNonroutable()) << addr;
}
TEST_P(IPAddressFlagTest, IsZero) {
AddressFlags param = GetParam();
IPAddress addr(param.address);
EXPECT_EQ(param.version, addr.version());
EXPECT_EQ(param.isZero(), addr.isZero()) << addr;
}
TEST_P(IPAddressFlagTest, IsLinkLocal) {
AddressFlags param = GetParam();
if (param.version != 6) {
return;
}
IPAddressV6 addr(param.address);
EXPECT_EQ(param.isLinkLocal(), addr.isLinkLocal()) << addr;
}
TEST(IPAddress, CreateLinkLocal) {
IPAddressV6 addr(IPAddressV6::LINK_LOCAL, MacAddress("00:05:73:f9:46:fc"));
EXPECT_EQ(IPAddressV6("fe80::0205:73ff:fef9:46fc"), addr);
addr = IPAddressV6(IPAddressV6::LINK_LOCAL, MacAddress("02:00:00:12:34:56"));
EXPECT_EQ(IPAddressV6("fe80::ff:fe12:3456"), addr);
}
TEST_P(IPAddressFlagTest, IsLinkLocalBroadcast) {
AddressFlags param = GetParam();
IPAddress addr(param.address);
EXPECT_EQ(param.version, addr.version());
EXPECT_EQ(param.isLinkLocalBroadcast(), addr.isLinkLocalBroadcast());
}
TEST(IPAddress, SolicitedNodeAddress) {
// An example from RFC 4291 section 2.7.1
EXPECT_EQ(IPAddressV6("ff02::1:ff0e:8c6c"),
IPAddressV6("4037::01:800:200e:8c6c").getSolicitedNodeAddress());
// An example from wikipedia
// (http://en.wikipedia.org/wiki/Solicited-node_multicast_address)
EXPECT_EQ(IPAddressV6("ff02::1:ff28:9c5a"),
IPAddressV6("fe80::2aa:ff:fe28:9c5a").getSolicitedNodeAddress());
}
TEST_P(IPAddressByteAccessorTest, CheckBytes) {
auto addrData = GetParam();
IPAddress ip(addrData.address);
auto i = 0;
for (auto byitr = addrData.bytes.begin(); i < ip.byteCount(); ++i, ++byitr) {
EXPECT_EQ(*byitr, ip.getNthMSByte(i));
EXPECT_EQ(*byitr, ip.isV4() ?
ip.asV4().getNthMSByte(i) : ip.asV6().getNthMSByte(i));
}
i = 0;
for (auto byritr = addrData.bytes.rbegin(); i < ip.byteCount(); ++i,
++byritr) {
EXPECT_EQ(*byritr, ip.getNthLSByte(i));
EXPECT_EQ(*byritr, ip.isV4() ?
ip.asV4().getNthLSByte(i) : ip.asV6().getNthLSByte(i));
}
}
TEST_P(IPAddressBitAccessorTest, CheckBits) {
auto addrData = GetParam();
auto littleEndianAddrData = addrData.bytes;
//IPAddress stores address data in n/w byte order.
reverse(littleEndianAddrData.begin(), littleEndianAddrData.end());
//Bit iterator goes from LSBit to MSBit
//We will traverse the IPAddress bits from 0 to bitCount -1
auto bitr = folly::makeBitIterator(littleEndianAddrData.begin());
IPAddress ip(addrData.address);
for (auto i = 0; i < ip.bitCount(); ++i) {
auto msbIndex = ip.bitCount() - i - 1;
EXPECT_EQ(*bitr, ip.getNthMSBit(msbIndex));
EXPECT_EQ(*bitr, ip.isV4() ? ip.asV4().getNthMSBit(msbIndex) :
ip.asV6().getNthMSBit(msbIndex));
EXPECT_EQ(*bitr, ip.getNthLSBit(i));
EXPECT_EQ(*bitr, ip.isV4() ? ip.asV4().getNthLSBit(i) :
ip.asV6().getNthLSBit(i));
++bitr;
}
}
TEST(IPAddress, InvalidByteAccess) {
IPAddress ip4("10.10.10.10");
//MSByte, LSByte accessors are 0 indexed
EXPECT_THROW(ip4.getNthMSByte(ip4.byteCount()), std::invalid_argument);
EXPECT_THROW(ip4.getNthLSByte(ip4.byteCount()), std::invalid_argument);
EXPECT_THROW(ip4.getNthMSByte(-1), std::invalid_argument);
EXPECT_THROW(ip4.getNthLSByte(-1), std::invalid_argument);
auto asV4 = ip4.asV4();
EXPECT_THROW(asV4.getNthMSByte(asV4.byteCount()), std::invalid_argument);
EXPECT_THROW(asV4.getNthLSByte(asV4.byteCount()), std::invalid_argument);
EXPECT_THROW(asV4.getNthMSByte(-1), std::invalid_argument);
EXPECT_THROW(asV4.getNthLSByte(-1), std::invalid_argument);
IPAddress ip6("2620:0:1cfe:face:b00c::3");
EXPECT_THROW(ip6.getNthMSByte(ip6.byteCount()), std::invalid_argument);
EXPECT_THROW(ip6.getNthLSByte(ip6.byteCount()), std::invalid_argument);
EXPECT_THROW(ip6.getNthMSByte(-1), std::invalid_argument);
EXPECT_THROW(ip6.getNthLSByte(-1), std::invalid_argument);
auto asV6 = ip6.asV6();
EXPECT_THROW(asV6.getNthMSByte(asV6.byteCount()), std::invalid_argument);
EXPECT_THROW(asV6.getNthLSByte(asV6.byteCount()), std::invalid_argument);
EXPECT_THROW(asV6.getNthMSByte(-1), std::invalid_argument);
EXPECT_THROW(asV6.getNthLSByte(-1), std::invalid_argument);
}
TEST(IPAddress, InvalidBBitAccess) {
IPAddress ip4("10.10.10.10");
//MSByte, LSByte accessors are 0 indexed
EXPECT_THROW(ip4.getNthMSBit(ip4.bitCount()), std::invalid_argument);
EXPECT_THROW(ip4.getNthLSBit(ip4.bitCount()), std::invalid_argument);
EXPECT_THROW(ip4.getNthMSBit(-1), std::invalid_argument);
EXPECT_THROW(ip4.getNthLSBit(-1), std::invalid_argument);
auto asV4 = ip4.asV4();
EXPECT_THROW(asV4.getNthMSBit(asV4.bitCount()), std::invalid_argument);
EXPECT_THROW(asV4.getNthLSBit(asV4.bitCount()), std::invalid_argument);
EXPECT_THROW(asV4.getNthMSBit(-1), std::invalid_argument);
EXPECT_THROW(asV4.getNthLSBit(-1), std::invalid_argument);
IPAddress ip6("2620:0:1cfe:face:b00c::3");
EXPECT_THROW(ip6.getNthMSBit(ip6.bitCount()), std::invalid_argument);
EXPECT_THROW(ip6.getNthLSBit(ip6.bitCount()), std::invalid_argument);
EXPECT_THROW(ip6.getNthMSBit(-1), std::invalid_argument);
EXPECT_THROW(ip6.getNthLSBit(-1), std::invalid_argument);
auto asV6 = ip6.asV6();
EXPECT_THROW(asV6.getNthMSBit(asV6.bitCount()), std::invalid_argument);
EXPECT_THROW(asV6.getNthLSBit(asV6.bitCount()), std::invalid_argument);
EXPECT_THROW(asV6.getNthMSBit(-1), std::invalid_argument);
EXPECT_THROW(asV6.getNthLSBit(-1), std::invalid_argument);
}
TEST(IPAddress, LongestCommonPrefix) {
IPAddress ip10("10.0.0.0");
IPAddress ip11("11.0.0.0");
IPAddress ip12("12.0.0.0");
IPAddress ip128("128.0.0.0");
IPAddress ip10dot10("10.10.0.0");
auto prefix = IPAddress::longestCommonPrefix({ip10, 8}, {ip128, 8});
auto prefix4 = IPAddressV4::longestCommonPrefix({ip10.asV4(), 8},
{ip128.asV4(), 8});
// No bits match b/w 128/8 and 10/8
EXPECT_EQ(IPAddress("0.0.0.0"), prefix.first);
EXPECT_EQ(0, prefix.second);
EXPECT_EQ(IPAddressV4("0.0.0.0"), prefix4.first);
EXPECT_EQ(0, prefix4.second);
prefix = IPAddress::longestCommonPrefix({ip10, 8}, {ip10dot10, 16});
prefix4 = IPAddressV4::longestCommonPrefix({ip10.asV4(), 8},
{ip10dot10.asV4(), 16});
// Between 10/8 and 10.10/16, 10/8 is the longest common match
EXPECT_EQ(ip10, prefix.first);
EXPECT_EQ(8, prefix.second);
EXPECT_EQ(ip10.asV4(), prefix4.first);
EXPECT_EQ(8, prefix4.second);
prefix = IPAddress::longestCommonPrefix({ip11, 8}, {ip12, 8});
prefix4 = IPAddressV4::longestCommonPrefix({ip11.asV4(), 8},
{ip12.asV4(), 8});
// 12 = 1100, 11 = 1011, longest match - 1000 = 8
EXPECT_EQ(IPAddress("8.0.0.0"), prefix.first);
EXPECT_EQ(5, prefix.second);
EXPECT_EQ(IPAddressV4("8.0.0.0"), prefix4.first);
EXPECT_EQ(5, prefix4.second);
// Between 128/1 and 128/2, longest match 128/1
prefix = IPAddress::longestCommonPrefix({ip128, 1}, {ip128, 2});
prefix4 = IPAddressV4::longestCommonPrefix({ip128.asV4(), 1},
{ip128.asV4(), 2});
EXPECT_EQ(ip128, prefix.first);
EXPECT_EQ(1, prefix.second);
EXPECT_EQ(ip128.asV4(), prefix4.first);
EXPECT_EQ(1, prefix4.second);
IPAddress ip6("2620:0:1cfe:face:b00c::3");
prefix = IPAddress::longestCommonPrefix({ip6, ip6.bitCount()},
{ip6, ip6.bitCount()});
auto prefix6 = IPAddressV6::longestCommonPrefix(
{ip6.asV6(), IPAddressV6::bitCount()},
{ip6.asV6(), IPAddressV6::bitCount()});
// Longest common b/w me and myself is myself
EXPECT_EQ(ip6, prefix.first);
EXPECT_EQ(ip6.bitCount(), prefix.second);
EXPECT_EQ(ip6.asV6(), prefix6.first);
EXPECT_EQ(ip6.asV6().bitCount(), prefix6.second);
IPAddress ip6Zero("::");
prefix = IPAddress::longestCommonPrefix({ip6, ip6.bitCount()}, {ip6Zero, 0});
prefix6 = IPAddressV6::longestCommonPrefix(
{ip6.asV6(), IPAddressV6::bitCount()},
{ip6Zero.asV6(), 0});
// Longest common b/w :: (ipv6 equivalent of 0/0) is ::
EXPECT_EQ(ip6Zero, prefix.first);
EXPECT_EQ(0, prefix.second);
// Exceptional cases
EXPECT_THROW(IPAddress::longestCommonPrefix({ip10, 8}, {ip6, 128}),
std::invalid_argument);
EXPECT_THROW(IPAddress::longestCommonPrefix({ip10, ip10.bitCount() + 1},
{ip10, 8}),
std::invalid_argument);
EXPECT_THROW(IPAddressV4::longestCommonPrefix(
{ip10.asV4(), IPAddressV4::bitCount() + 1},
{ip10.asV4(), 8}),
std::invalid_argument);
EXPECT_THROW(IPAddress::longestCommonPrefix({ip6, ip6.bitCount() + 1},
{ip6, ip6.bitCount()}),
std::invalid_argument);
EXPECT_THROW(IPAddressV6::longestCommonPrefix(
{ip6.asV6(), IPAddressV6::bitCount() + 1},
{ip6.asV6(), IPAddressV6::bitCount()}),
std::invalid_argument);
}
static vector<AddressData> validAddressProvider = {
AddressData("127.0.0.1", {127,0,0,1}, 4),
AddressData("69.63.189.16", {69,63,189,16}, 4),
AddressData("0.0.0.0", {0,0,0,0}, 4),
AddressData("::1",
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 6),
AddressData("2620:0:1cfe:face:b00c::3",
{38,32,0,0,28,254,250,206,176,12,0,0,0,0,0,3}, 6),
};
static vector<string> invalidAddressProvider = {
"",
"foo",
"1.1.1.256",
"1",
":1",
"127.0.0.1,127.0.0.1",
"[1234]",
};
static vector<ByteVector> invalidBinaryProvider = {
{0x31, 0x32, 0x37, 0x2e, 0x30, 0x30, 0x2e, 0x30, 0x2e, 0x31},
// foo
{0x66, 0x6f, 0x6f},
{0x00},
{0x00, 0x00},
{0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00},
{0xff},
};
static const uint8_t IS_LOCAL = AddressFlags::IS_LOCAL;
static const uint8_t IS_NONROUTABLE = AddressFlags::IS_NONROUTABLE;
static const uint8_t IS_PRIVATE = AddressFlags::IS_PRIVATE;
static const uint8_t IS_ZERO = AddressFlags::IS_ZERO;
static const uint8_t IS_LINK_LOCAL =
AddressFlags::IS_LINK_LOCAL | IS_NONROUTABLE;
static const uint8_t IS_PVT_NONROUTE = IS_NONROUTABLE | IS_PRIVATE;
static const uint8_t IS_MULTICAST = AddressFlags::IS_MULTICAST;
static const uint8_t IS_LINK_LOCAL_BROADCAST =
AddressFlags::IS_LINK_LOCAL_BROADCAST;
static vector<AddressFlags> flagProvider = {
// public v4
AddressFlags("69.63.176.1", 4, 0),
AddressFlags("128.12.65.3", 4, 0),
AddressFlags("192.0.1.0", 4, 0),
AddressFlags("198.51.101.0", 4, 0),
AddressFlags("203.0.114.0", 4, 0),
AddressFlags("128.12.64.115", 4, 0),
// public v6
AddressFlags("2620:0:1cfe:face:b00c::3", 6, 0),
// localhost
AddressFlags("127.0.0.1", 4, IS_LOCAL | IS_PVT_NONROUTE),
AddressFlags("::1", 6, IS_LOCAL | IS_PVT_NONROUTE),
// private v4
AddressFlags("10.0.0.0", 4, IS_PVT_NONROUTE),
AddressFlags("10.11.12.13", 4, IS_PVT_NONROUTE),
AddressFlags("10.255.255.255", 4, IS_PVT_NONROUTE),
AddressFlags("127.128.129.200", 4, IS_PVT_NONROUTE),
AddressFlags("127.255.255.255", 4, IS_PVT_NONROUTE),
AddressFlags("169.254.0.0", 4, IS_PVT_NONROUTE),
AddressFlags("192.168.0.0", 4, IS_PVT_NONROUTE),
AddressFlags("192.168.200.255", 4, IS_PVT_NONROUTE),
AddressFlags("192.168.255.255", 4, IS_PVT_NONROUTE),
// private v6
AddressFlags("fd01:1637:1c56:66af::", 6, IS_PVT_NONROUTE),
// non routable v4
AddressFlags("0.0.0.0", 4, IS_NONROUTABLE | IS_ZERO),
AddressFlags("0.255.255.255", 4, IS_NONROUTABLE),
AddressFlags("192.0.0.0", 4, IS_NONROUTABLE),
AddressFlags("192.0.2.0", 4, IS_NONROUTABLE),
AddressFlags("198.18.0.0", 4, IS_NONROUTABLE),
AddressFlags("198.19.255.255", 4, IS_NONROUTABLE),
AddressFlags("198.51.100.0", 4, IS_NONROUTABLE),
AddressFlags("198.51.100.255", 4, IS_NONROUTABLE),
AddressFlags("203.0.113.0", 4, IS_NONROUTABLE),
AddressFlags("203.0.113.255", 4, IS_NONROUTABLE),
AddressFlags("224.0.0.0", 4, IS_NONROUTABLE | IS_MULTICAST),
AddressFlags("240.0.0.0", 4, IS_NONROUTABLE),
AddressFlags("224.0.0.0", 4, IS_NONROUTABLE),
// v4 link local broadcast
AddressFlags("255.255.255.255", 4, IS_NONROUTABLE | IS_LINK_LOCAL_BROADCAST),
// non routable v6
AddressFlags("1999::1", 6, IS_NONROUTABLE),
AddressFlags("0::0", 6, IS_NONROUTABLE | IS_ZERO),
AddressFlags("0::0:0", 6, IS_NONROUTABLE | IS_ZERO),
AddressFlags("0:0:0::0", 6, IS_NONROUTABLE | IS_ZERO),
// link-local v6
AddressFlags("fe80::0205:73ff:fef9:46fc", 6, IS_LINK_LOCAL),
AddressFlags("fe80::0012:34ff:fe56:7890", 6, IS_LINK_LOCAL),
// multicast v4
AddressFlags("224.0.0.1", 4, IS_MULTICAST | IS_NONROUTABLE) ,
AddressFlags("224.0.0.251", 4, IS_MULTICAST | IS_NONROUTABLE),
AddressFlags("239.12.34.56", 4, IS_MULTICAST | IS_NONROUTABLE),
// multicast v6
AddressFlags("ff00::", 6, IS_MULTICAST | IS_NONROUTABLE),
AddressFlags("ff02:ffff::1", 6, IS_MULTICAST | IS_NONROUTABLE),
AddressFlags("ff02::101", 6, IS_MULTICAST | IS_NONROUTABLE),
AddressFlags("ff0e::101", 6, IS_MULTICAST),
// v6 link local broadcast
AddressFlags("ff02::1", 6, IS_NONROUTABLE | IS_LINK_LOCAL_BROADCAST),
};
static vector<pair<string, string> > mapProvider = {
{"::ffff:192.0.2.128", "192.0.2.128"},
{"192.0.2.128", "::ffff:192.0.2.128"},
{"::FFFF:129.144.52.38", "129.144.52.38"},
{"129.144.52.38", "::FFFF:129.144.52.38"},
{"0:0:0:0:0:FFFF:222.1.41.90", "222.1.41.90"},
{"::FFFF:222.1.41.90", "222.1.41.90"},
};
static vector<MaskData> masksProvider = {
MaskData("255.255.255.255", 1, "128.0.0.0"),
MaskData("255.255.255.255", 2, "192.0.0.0"),
MaskData("192.0.2.42", 16, "192.0.0.0"),
MaskData("255.255.255.255", 24, "255.255.255.0"),
MaskData("255.255.255.255", 32, "255.255.255.255"),
MaskData("10.10.10.10", 0, "0.0.0.0"),
MaskData("::1", 64, "::"),
MaskData("2620:0:1cfe:face:b00c::3", 1, "::"),
MaskData("2620:0:1cfe:face:b00c::3", 3, "2000::"),
MaskData("2620:0:1cfe:face:b00c::3", 6, "2400::"),
MaskData("2620:0:1cfe:face:b00c::3", 7, "2600::"),
MaskData("2620:0:1cfe:face:b00c::3", 11, "2620::"),
MaskData("2620:0:1cfe:face:b00c::3", 36, "2620:0:1000::"),
MaskData("2620:0:1cfe:face:b00c::3", 37, "2620:0:1800::"),
MaskData("2620:0:1cfe:face:b00c::3", 38, "2620:0:1c00::"),
MaskData("2620:0:1cfe:face:b00c::3", 41, "2620:0:1c80::"),
MaskData("2620:0:1cfe:face:b00c::3", 42, "2620:0:1cc0::"),
MaskData("2620:0:1cfe:face:b00c::3", 43, "2620:0:1ce0::"),
MaskData("2620:0:1cfe:face:b00c::3", 44, "2620:0:1cf0::"),
MaskData("2620:0:1cfe:face:b00c::3", 45, "2620:0:1cf8::"),
MaskData("2620:0:1cfe:face:b00c::3", 46, "2620:0:1cfc::"),
MaskData("2620:0:1cfe:face:b00c::3", 47, "2620:0:1cfe::"),
MaskData("2620:0:1cfe:face:b00c::3", 49, "2620:0:1cfe:8000::"),
MaskData("2620:0:1cfe:face:b00c::3", 50, "2620:0:1cfe:c000::"),
MaskData("2620:0:1cfe:face:b00c::3", 51, "2620:0:1cfe:e000::"),
MaskData("2620:0:1cfe:face:b00c::3", 52, "2620:0:1cfe:f000::"),
MaskData("2620:0:1cfe:face:b00c::3", 53, "2620:0:1cfe:f800::"),
MaskData("2620:0:1cfe:face:b00c::3", 55, "2620:0:1cfe:fa00::"),
MaskData("2620:0:1cfe:face:b00c::3", 57, "2620:0:1cfe:fa80::"),
MaskData("2620:0:1cfe:face:b00c::3", 58, "2620:0:1cfe:fac0::"),
MaskData("2620:0:1cfe:face:b00c::3", 61, "2620:0:1cfe:fac8::"),
MaskData("2620:0:1cfe:face:b00c::3", 62, "2620:0:1cfe:facc::"),
MaskData("2620:0:1cfe:face:b00c::3", 63, "2620:0:1cfe:face::"),
MaskData("2620:0:1cfe:face:b00c::3", 65, "2620:0:1cfe:face:8000::"),
MaskData("2620:0:1cfe:face:b00c::3", 67, "2620:0:1cfe:face:a000::"),
MaskData("2620:0:1cfe:face:b00c::3", 68, "2620:0:1cfe:face:b000::"),
MaskData("2620:0:1cfe:face:b00c::3", 77, "2620:0:1cfe:face:b008::"),
MaskData("2620:0:1cfe:face:b00c::3", 78, "2620:0:1cfe:face:b00c::"),
MaskData("2620:0:1cfe:face:b00c::3", 127, "2620:0:1cfe:face:b00c::2"),
MaskData("2620:0:1cfe:face:b00c::3", 128, "2620:0:1cfe:face:b00c::3"),
MaskData("2620:0:1cfe:face:b00c::3", 0, "::")
};
static vector<MaskBoundaryData> maskBoundaryProvider = {
MaskBoundaryData("10.1.1.1", 24, "10.1.1.1", true),
MaskBoundaryData("10.1.1.1", 8, "10.1.2.3", true),
MaskBoundaryData("2620:0:1cfe:face:b00c::1", 48, "2620:0:1cfe::", true),
// addresses that are NOT in the same subnet once mask is applied
MaskBoundaryData("10.1.1.1", 24, "10.1.2.1", false),
MaskBoundaryData("10.1.1.1", 16, "10.2.3.4", false),
MaskBoundaryData("2620:0:1cfe:face:b00c::1", 48, "2620:0:1cfc::", false),
};
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressTest,
::testing::ValuesIn(validAddressProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressFlagTest,
::testing::ValuesIn(flagProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressMappedTest,
::testing::ValuesIn(mapProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressCtorTest,
::testing::ValuesIn(invalidAddressProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressCtorBinaryTest,
::testing::ValuesIn(invalidBinaryProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressMaskTest,
::testing::ValuesIn(masksProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressMaskBoundaryTest,
::testing::ValuesIn(maskBoundaryProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressByteAccessorTest,
::testing::ValuesIn(validAddressProvider));
INSTANTIATE_TEST_CASE_P(IPAddress,
IPAddressBitAccessorTest,
::testing::ValuesIn(validAddressProvider));
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
#include <gtest/gtest.h>
extern "C" {
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
}
#include "folly/IPAddress.h"
namespace folly {
class IPAddress;
typedef std::vector<uint8_t> ByteVector;
struct AddressData {
std::string address;
ByteVector bytes;
uint8_t version;
AddressData(const std::string& address, const ByteVector& bytes,
uint8_t version)
: address(address), bytes(bytes), version(version) {}
AddressData(const std::string& address, uint8_t version)
: address(address), bytes(), version(version) {}
explicit AddressData(const std::string& address)
: address(address), bytes(), version(0) {}
AddressData(): address(""), bytes(), version(0) {}
static in_addr parseAddress4(const std::string& src) {
in_addr addr;
inet_pton(AF_INET, src.c_str(), &addr);
return addr;
}
static in6_addr parseAddress6(const std::string& src) {
in6_addr addr;
inet_pton(AF_INET6, src.c_str(), &addr);
return addr;
}
};
struct AddressFlags {
std::string address;
uint8_t flags;
uint8_t version;
static const uint8_t IS_LOCAL = 1 << 0;
static const uint8_t IS_NONROUTABLE = 1 << 1;
static const uint8_t IS_PRIVATE = 1 << 2;
static const uint8_t IS_ZERO = 1 << 3;
static const uint8_t IS_LINK_LOCAL = 1 << 4;
static const uint8_t IS_MULTICAST = 1 << 5;
static const uint8_t IS_LINK_LOCAL_BROADCAST = 1 << 6;
AddressFlags(const std::string& addr, uint8_t version, uint8_t flags)
: address(addr)
, flags(flags)
, version(version)
{}
bool isLoopback() const {
return (flags & IS_LOCAL);
}
bool isNonroutable() const {
return (flags & IS_NONROUTABLE);
}
bool isPrivate() const {
return (flags & IS_PRIVATE);
}
bool isZero() const {
return (flags & IS_ZERO);
}
bool isLinkLocal() const {
return (flags & IS_LINK_LOCAL);
}
bool isLinkLocalBroadcast() const {
return (flags & IS_LINK_LOCAL_BROADCAST);
}
};
struct MaskData {
std::string address;
uint8_t mask;
std::string subnet;
MaskData(const std::string& addr, uint8_t mask,
const std::string& subnet)
: address(addr)
, mask(mask)
, subnet(subnet)
{}
};
struct MaskBoundaryData : MaskData {
bool inSubnet;
MaskBoundaryData(const std::string& addr, uint8_t mask,
const std::string& subnet, bool inSubnet)
: MaskData(addr, mask, subnet)
, inSubnet(inSubnet)
{}
};
struct SerializeData {
std::string address;
ByteVector bytes;
SerializeData(const std::string& addr, const ByteVector& bytes)
: address(addr)
, bytes(bytes)
{}
};
struct IPAddressTest : public ::testing::TestWithParam<AddressData> {
void ExpectIsValid(const IPAddress& addr) {
AddressData param = GetParam();
EXPECT_EQ(param.version, addr.version());
EXPECT_EQ(param.address, addr.str());
if (param.version == 4) {
in_addr v4addr = AddressData::parseAddress4(param.address);
EXPECT_EQ(0, memcmp(&v4addr, addr.asV4().toByteArray().data(), 4));
EXPECT_TRUE(addr.isV4());
EXPECT_FALSE(addr.isV6());
} else {
in6_addr v6addr = AddressData::parseAddress6(param.address);
EXPECT_EQ(0, memcmp(&v6addr, addr.asV6().toByteArray().data(), 16));
EXPECT_TRUE(addr.isV6());
EXPECT_FALSE(addr.isV4());
}
}
};
struct IPAddressFlagTest : public ::testing::TestWithParam<AddressFlags> {};
struct IPAddressCtorTest : public ::testing::TestWithParam<std::string> {};
struct IPAddressCtorBinaryTest : public ::testing::TestWithParam<ByteVector> {};
struct IPAddressMappedTest :
public ::testing::TestWithParam<std::pair<std::string,std::string> > {};
struct IPAddressMaskTest : public ::testing::TestWithParam<MaskData> {};
struct IPAddressMaskBoundaryTest :
public ::testing::TestWithParam<MaskBoundaryData> {};
struct IPAddressSerializeTest :
public ::testing::TestWithParam<SerializeData> {};
struct IPAddressByteAccessorTest:
public ::testing::TestWithParam<AddressData> {};
struct IPAddressBitAccessorTest:
public ::testing::TestWithParam<AddressData> {};
} // folly
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include "folly/IPAddressV6.h"
#include "folly/MacAddress.h"
using folly::MacAddress;
using folly::IPAddressV6;
using folly::StringPiece;
void testMAC(const std::string& str, uint64_t expectedHBO) {
SCOPED_TRACE(str);
MacAddress addr(str);
// Make sure parsing returned the expected value.
EXPECT_EQ(expectedHBO, addr.u64HBO());
// Perform additional checks on the MacAddress
// Check using operator==()
EXPECT_EQ(MacAddress::fromHBO(expectedHBO), addr);
// Check using operator==() when passing in non-zero padding bytes
EXPECT_EQ(MacAddress::fromHBO(expectedHBO | 0xa5a5000000000000), addr);
// Similar checks after converting to network byte order
uint64_t expectedNBO = folly::Endian::big(expectedHBO);
EXPECT_EQ(expectedNBO, addr.u64NBO());
EXPECT_EQ(MacAddress::fromNBO(expectedNBO), addr);
uint64_t nboWithPad = folly::Endian::big(expectedHBO | 0xa5a5000000000000);
EXPECT_EQ(MacAddress::fromNBO(nboWithPad), addr);
// Check they value returned by bytes()
uint8_t expectedBytes[8];
memcpy(expectedBytes, &expectedNBO, 8);
for (int n = 0; n < 6; ++n) {
EXPECT_EQ(expectedBytes[n + 2], addr.bytes()[n]);
}
}
TEST(MacAddress, parse) {
testMAC("12:34:56:78:9a:bc", 0x123456789abc);
testMAC("00-11-22-33-44-55", 0x1122334455);
testMAC("abcdef123456", 0xabcdef123456);
testMAC("1:2:3:4:5:6", 0x010203040506);
testMAC("0:0:0:0:0:0", 0);
testMAC("0:0:5e:0:1:1", 0x00005e000101);
EXPECT_THROW(MacAddress(""), std::invalid_argument);
EXPECT_THROW(MacAddress("0"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:34"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:3"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:x4:56:78:9a:bc"), std::invalid_argument);
EXPECT_THROW(MacAddress("12x34:56:78:9a:bc"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:34:56:78:9a:bc:de"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:34:56:78:9a:bcde"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:34:56:78:9a:bc "), std::invalid_argument);
EXPECT_THROW(MacAddress(" 12:34:56:78:9a:bc"), std::invalid_argument);
EXPECT_THROW(MacAddress("12:34:56:78:-1:bc"), std::invalid_argument);
}
void testFromBinary(const char* str, uint64_t expectedHBO) {
StringPiece bin(str, 6);
auto mac = MacAddress::fromBinary(bin);
SCOPED_TRACE(mac.toString());
EXPECT_EQ(expectedHBO, mac.u64HBO());
}
TEST(MacAddress, fromBinary) {
testFromBinary("\0\0\0\0\0\0", 0);
testFromBinary("\x12\x34\x56\x78\x9a\xbc", 0x123456789abc);
testFromBinary("\x11\x22\x33\x44\x55\x66", 0x112233445566);
StringPiece empty("");
EXPECT_THROW(MacAddress::fromBinary(empty), std::invalid_argument);
StringPiece tooShort("\x11", 1);
EXPECT_THROW(MacAddress::fromBinary(tooShort), std::invalid_argument);
StringPiece tooLong("\x11\x22\x33\x44\x55\x66\x77", 7);
EXPECT_THROW(MacAddress::fromBinary(tooLong), std::invalid_argument);
}
TEST(MacAddress, toString) {
EXPECT_EQ("12:34:56:78:9a:bc",
MacAddress::fromHBO(0x123456789abc).toString());
EXPECT_EQ("12:34:56:78:9a:bc", MacAddress("12:34:56:78:9a:bc").toString());
EXPECT_EQ("01:23:45:67:89:ab", MacAddress("01-23-45-67-89-ab").toString());
EXPECT_EQ("01:23:45:67:89:ab", MacAddress("0123456789ab").toString());
}
TEST(MacAddress, attributes) {
EXPECT_TRUE(MacAddress("ff:ff:ff:ff:ff:ff").isBroadcast());
EXPECT_FALSE(MacAddress("7f:ff:ff:ff:ff:ff").isBroadcast());
EXPECT_FALSE(MacAddress("7f:ff:ff:ff:ff:fe").isBroadcast());
EXPECT_FALSE(MacAddress("00:00:00:00:00:00").isBroadcast());
EXPECT_TRUE(MacAddress::fromNBO(0xffffffffffffffffU).isBroadcast());
EXPECT_TRUE(MacAddress("ff:ff:ff:ff:ff:ff").isMulticast());
EXPECT_TRUE(MacAddress("01:00:00:00:00:00").isMulticast());
EXPECT_FALSE(MacAddress("00:00:00:00:00:00").isMulticast());
EXPECT_FALSE(MacAddress("fe:ff:ff:ff:ff:ff").isMulticast());
EXPECT_FALSE(MacAddress("00:00:5e:00:01:01").isMulticast());
EXPECT_FALSE(MacAddress("ff:ff:ff:ff:ff:ff").isUnicast());
EXPECT_FALSE(MacAddress("01:00:00:00:00:00").isUnicast());
EXPECT_TRUE(MacAddress("00:00:00:00:00:00").isUnicast());
EXPECT_TRUE(MacAddress("fe:ff:ff:ff:ff:ff").isUnicast());
EXPECT_TRUE(MacAddress("00:00:5e:00:01:01").isUnicast());
EXPECT_TRUE(MacAddress("ff:ff:ff:ff:ff:ff").isLocallyAdministered());
EXPECT_TRUE(MacAddress("02:00:00:00:00:00").isLocallyAdministered());
EXPECT_FALSE(MacAddress("01:00:00:00:00:00").isLocallyAdministered());
EXPECT_FALSE(MacAddress("00:00:00:00:00:00").isLocallyAdministered());
EXPECT_FALSE(MacAddress("fd:ff:ff:ff:ff:ff").isLocallyAdministered());
EXPECT_TRUE(MacAddress("fe:ff:ff:ff:ff:ff").isLocallyAdministered());
EXPECT_FALSE(MacAddress("00:00:5e:00:01:01").isLocallyAdministered());
EXPECT_TRUE(MacAddress("02:12:34:56:78:9a").isLocallyAdministered());
}
TEST(MacAddress, createMulticast) {
EXPECT_EQ(MacAddress("33:33:00:01:00:03"),
MacAddress::createMulticast(IPAddressV6("ff02:dead:beef::1:3")));
EXPECT_EQ(MacAddress("33:33:12:34:56:78"),
MacAddress::createMulticast(IPAddressV6("ff02::abcd:1234:5678")));
}
void testCmp(const char* str1, const char* str2) {
SCOPED_TRACE(folly::to<std::string>(str1, " < ", str2));
MacAddress m1(str1);
MacAddress m2(str2);
// Test the comparison operators
EXPECT_TRUE(m1 < m2);
EXPECT_FALSE(m1 < m1);
EXPECT_TRUE(m1 <= m2);
EXPECT_TRUE(m2 > m1);
EXPECT_TRUE(m2 >= m1);
EXPECT_TRUE(m1 != m2);
EXPECT_TRUE(m1 == m1);
EXPECT_FALSE(m1 == m2);
// Also test the copy constructor and assignment operator
MacAddress copy(m1);
EXPECT_EQ(copy, m1);
copy = m2;
EXPECT_EQ(copy, m2);
}
TEST(MacAddress, ordering) {
testCmp("00:00:00:00:00:00", "00:00:00:00:00:01");
testCmp("00:00:00:00:00:01", "00:00:00:00:00:02");
testCmp("01:00:00:00:00:00", "02:00:00:00:00:00");
testCmp("00:00:00:00:00:01", "00:00:00:00:01:00");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment