/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#include "IPAddressTest.h"
-
-#include <gtest/gtest.h>
+#include <folly/test/IPAddressTest.h>
#include <folly/Bits.h>
#include <folly/Format.h>
-#include <folly/String.h>
#include <folly/MacAddress.h>
+#include <folly/String.h>
+#include <folly/detail/IPAddressSource.h>
+#include <folly/portability/GTest.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));
+ EXPECT_EQ(20, sizeof(IPAddressV6));
+ EXPECT_EQ(24, sizeof(IPAddress));
+ IPAddress uninitaddr;
IPAddress v4addr("192.0.2.129");
IPAddress v6map("::ffff:192.0.2.129");
+ ASSERT_TRUE(uninitaddr.empty());
+ ASSERT_FALSE(v4addr.empty());
+ ASSERT_FALSE(v6map.empty());
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_FALSE(uninitaddr.isV4());
+ ASSERT_FALSE(uninitaddr.isV6());
ASSERT_TRUE(v4addr.isV4());
ASSERT_TRUE(v6map.isV6());
EXPECT_TRUE(v4addr == v6map);
EXPECT_TRUE(IPAddress::createIPv6(v4addr) == v6map.asV6());
}
+TEST(IPAddress, Scope) {
+ // Test that link-local scope is saved
+ auto str = "fe80::62eb:69ff:fe9b:ba60%eth0";
+ IPAddressV6 a2(str);
+ EXPECT_EQ(str, a2.str());
+
+ sockaddr_in6 sock = a2.toSockAddr();
+ EXPECT_NE(0, sock.sin6_scope_id);
+
+ IPAddress a1(str);
+ EXPECT_EQ(str, a1.str());
+
+ a2.setScopeId(0);
+ EXPECT_NE(a1, a2);
+
+ EXPECT_TRUE(a2 < a1);
+}
+
TEST(IPAddress, Ordering) {
IPAddress a1("0.1.1.1");
IPAddress a2("1.1.1.0");
EXPECT_EQ(IPAddressV6("::0"), v6);
}
+TEST(IPAddressV4, validate) {
+ EXPECT_TRUE(IPAddressV4::validate("0.0.0.0"));
+ EXPECT_FALSE(IPAddressV4::validate("0.0.0."));
+ EXPECT_TRUE(IPAddressV4::validate("127.127.127.127"));
+}
+
+TEST(IPAddressV6, validate) {
+ EXPECT_TRUE(IPAddressV6::validate("2620:0:1cfe:face:b00c::3"));
+ EXPECT_FALSE(IPAddressV6::validate("0.0.0.0"));
+ EXPECT_TRUE(IPAddressV6::validate("[2620:0:1cfe:face:b00c::3]"));
+ EXPECT_TRUE(IPAddressV6::validate("::ffff:0.1.1.1"));
+ EXPECT_TRUE(IPAddressV6::validate("2620:0000:1cfe:face:b00c:0000:0000:0003"));
+ EXPECT_TRUE(
+ IPAddressV6::validate("2620:0000:1cfe:face:b00c:0000:127.127.127.127"));
+}
+
+TEST(IPAddress, validate) {
+ EXPECT_TRUE(IPAddress::validate("0.0.0.0"));
+ EXPECT_TRUE(IPAddress::validate("::"));
+ EXPECT_FALSE(IPAddress::validate("asdf"));
+}
+
// Test addresses constructed using a in[6]_addr value
TEST_P(IPAddressTest, CtorAddress) {
AddressData param = GetParam();
{
// setup
sockaddr_in6 addr;
+ memset(&addr, 0, sizeof(addr));
in6_addr sin_addr;
ByteArray16 sec{{
// 2620:0:1cfe:face:b00c::3
" - ", addr_1, " - ", addr_10_1_2_3));
}
+TEST(IPaddress, toInverseArpaName) {
+ IPAddressV4 addr_ipv4("10.0.0.1");
+ EXPECT_EQ("1.0.0.10.in-addr.arpa", addr_ipv4.toInverseArpaName());
+ IPAddressV6 addr_ipv6("2620:0000:1cfe:face:b00c:0000:0000:0003");
+ EXPECT_EQ(
+ sformat(
+ "{}.ip6.arpa",
+ "3.0.0.0.0.0.0.0.0.0.0.0.c.0.0.b.e.c.a.f.e.f.c.1.0.0.0.0.0.2.6.2"),
+ addr_ipv6.toInverseArpaName());
+}
+
// Test that invalid string values are killed
TEST_P(IPAddressCtorTest, InvalidCreation) {
string addr = GetParam();
IPAddressFormatException);
}
+TEST(IPAddressSource, ToHex) {
+ vector<std::uint8_t> data = {{0xff, 0x20, 0x45}};
+ EXPECT_EQ(detail::Bytes::toHex(data.data(), 0), "");
+ EXPECT_EQ(detail::Bytes::toHex(data.data(), 1), "ff");
+ EXPECT_EQ(detail::Bytes::toHex(data.data(), 2), "ff20");
+ EXPECT_EQ(detail::Bytes::toHex(data.data(), 3), "ff2045");
+}
+
// Test toFullyQualified()
TEST(IPAddress, ToFullyQualifiedFb) {
IPAddress ip("2620:0:1cfe:face:b00c::3");
EXPECT_EQ("0000:0000:0000:0000:0000:0000:0000:0001", ip.toFullyQualified())
<< ip;
}
+TEST(IPAddress, ToFullyQualifiedSize) {
+ auto actual = IPAddressV6::kToFullyQualifiedSize;
+ auto expected = IPAddress("::").toFullyQualified().size();
+ EXPECT_EQ(expected, actual);
+}
// test v4-v6 mapped addresses
TEST_P(IPAddressMappedTest, MappedEqual) {
IPAddress ip(param.address);
IPAddress masked = ip.mask(param.mask);
EXPECT_EQ(param.subnet, masked.str())
- << param.address << "/" << to_string(param.mask)
- << " -> " << param.subnet;
+ << param.address << "/" << folly::to<std::string>(param.mask) << " -> "
+ << param.subnet;
}
// Test inSubnet calculations
EXPECT_EQ(param.inSubnet, ip.inSubnet(subnet, param.mask));
}
+TEST(IPAddress, UnitializedEqual) {
+ IPAddress addrEmpty;
+ IPAddress ip4("127.0.0.1");
+ EXPECT_FALSE(addrEmpty == ip4);
+ EXPECT_FALSE(ip4 == addrEmpty);
+ IPAddress ip6("::1");
+ EXPECT_FALSE(addrEmpty == ip6);
+ EXPECT_FALSE(ip6 == addrEmpty);
+ IPAddress ip6Map("::ffff:192.0.2.129");
+ EXPECT_FALSE(addrEmpty == ip6Map);
+ EXPECT_FALSE(ip6Map == addrEmpty);
+ IPAddress ip4Zero("0.0.0.0");
+ EXPECT_FALSE(addrEmpty == ip4Zero);
+ EXPECT_FALSE(ip4Zero == addrEmpty);
+ IPAddress ip6Zero("::");
+ EXPECT_FALSE(addrEmpty == ip6Zero);
+ EXPECT_FALSE(ip6Zero == addrEmpty);
+ EXPECT_EQ(addrEmpty, addrEmpty);
+}
+
// Test subnet calcs with 6to4 addresses
TEST(IPAddress, InSubnetWith6to4) {
auto ip = IPAddress("2002:c000:022a::"); // 192.0.2.42
EXPECT_TRUE(ip3.inSubnet(subnet3, 16));
}
-static vector<pair<string, uint8_t> > invalidMasks = {
+static const vector<string> ipv4Strs = {
+ "127.0.0.1",
+ "198.168.0.1",
+ "8.8.0.0",
+};
+TEST(IPAddress, getIPv6For6To4) {
+ for (auto ipv4Str : ipv4Strs) {
+ auto ip = IPAddress(ipv4Str);
+ EXPECT_TRUE(ip.isV4());
+ IPAddressV4 ipv4 = ip.asV4();
+ auto ipv6 = ipv4.getIPv6For6To4();
+ EXPECT_EQ(ipv6.type(), IPAddressV6::Type::T6TO4);
+ auto ipv4New = ipv6.getIPv4For6To4();
+ EXPECT_TRUE(ipv4Str.compare(ipv4New.str()) == 0);
+ }
+}
+
+static const 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 = {
+static const 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},
break;
default:
throw std::range_error("Invalid expected type: " +
- to_string(tc.second));
+ folly::to<std::string>(tc.second));
}
}
}
-static vector<pair<string, uint32_t> > provideToLong = {
+static const vector<pair<string, uint32_t> > provideToLong = {
{"0.0.0.0", 0},
{"10.0.0.0", 167772160},
{"126.131.128.23", 2122547223},
IPAddressFormatException);
}
-static vector<pair<string, vector<uint8_t> > > provideBinary16Bytes = {
+TEST(IPAddress, toBinaryV4) {
+ 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);
+ auto toBin = fromBin.toBinary();
+ EXPECT_EQ(bytes, toBin);
+ }
+}
+
+static const vector<pair<string, vector<uint8_t> > > provideBinary16Bytes = {
{"::0",
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
IPAddressFormatException);
}
+TEST(IPAddress, toBinaryV6) {
+ for (auto& tc : provideBinary16Bytes) {
+ SCOPED_TRACE(tc.first);
+ ByteRange bytes(&tc.second.front(), tc.second.size());
+
+ auto fromBin = IPAddressV6::fromBinary(bytes);
+ auto toBin = fromBin.toBinary();
+ EXPECT_EQ(bytes, toBin);
+ }
+}
+
TEST_P(IPAddressFlagTest, IsLoopback) {
AddressFlags param = GetParam();
IPAddress addr(param.address);
TEST_P(IPAddressFlagTest, IsLinkLocal) {
AddressFlags param = GetParam();
- if (param.version != 6) {
- return;
- }
- IPAddressV6 addr(param.address);
+ IPAddress addr(param.address);
EXPECT_EQ(param.isLinkLocal(), addr.isLinkLocal()) << addr;
}
TEST_P(IPAddressByteAccessorTest, CheckBytes) {
auto addrData = GetParam();
IPAddress ip(addrData.address);
- auto i = 0;
+ size_t i = 0;
for (auto byitr = addrData.bytes.begin(); i < ip.byteCount(); ++i, ++byitr) {
EXPECT_EQ(*byitr, ip.getNthMSByte(i));
EXPECT_EQ(*byitr, ip.isV4() ?
//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) {
+ for (size_t 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) :
EXPECT_THROW(asV6.getNthLSBit(-1), std::invalid_argument);
}
+TEST(IPAddress, StringFormat) {
+ in6_addr a6;
+ for (int i = 0; i < 8; ++i) {
+ auto t = htons(0x0123 + ((i % 4) * 0x4444));
+#ifdef _WIN32
+ a6.u.Word[i] = t;
+#else
+ a6.s6_addr16[i] = t;
+#endif
+ }
+ EXPECT_EQ("0123:4567:89ab:cdef:0123:4567:89ab:cdef",
+ detail::fastIpv6ToString(a6));
+
+ in_addr a4;
+ a4.s_addr = htonl(0x01020304);
+ EXPECT_EQ("1.2.3.4", detail::fastIpv4ToString(a4));
+}
+
+TEST(IPAddress, getMacAddressFromLinkLocal) {
+ IPAddressV6 ip6("fe80::f652:14ff:fec5:74d8");
+ EXPECT_TRUE(ip6.getMacAddressFromLinkLocal().hasValue());
+ EXPECT_EQ("f4:52:14:c5:74:d8", ip6.getMacAddressFromLinkLocal()->toString());
+}
+
+TEST(IPAddress, getMacAddressFromLinkLocal_Negative) {
+ IPAddressV6 no_link_local_ip6("2803:6082:a2:4447::1");
+ EXPECT_FALSE(no_link_local_ip6.getMacAddressFromLinkLocal().hasValue());
+ no_link_local_ip6 = IPAddressV6("fe80::f652:14ff:ccc5:74d8");
+ EXPECT_FALSE(no_link_local_ip6.getMacAddressFromLinkLocal().hasValue());
+ no_link_local_ip6 = IPAddressV6("fe80::f652:14ff:ffc5:74d8");
+ EXPECT_FALSE(no_link_local_ip6.getMacAddressFromLinkLocal().hasValue());
+ no_link_local_ip6 = IPAddressV6("fe81::f652:14ff:ffc5:74d8");
+ EXPECT_FALSE(no_link_local_ip6.getMacAddressFromLinkLocal().hasValue());
+}
+
TEST(IPAddress, LongestCommonPrefix) {
IPAddress ip10("10.0.0.0");
IPAddress ip11("11.0.0.0");
}
-static vector<AddressData> validAddressProvider = {
+static const 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),
{38,32,0,0,28,254,250,206,176,12,0,0,0,0,0,3}, 6),
};
-static vector<string> invalidAddressProvider = {
+static const vector<string> invalidAddressProvider = {
"",
"foo",
"1.1.1.256",
"[1234]",
};
-static vector<ByteVector> invalidBinaryProvider = {
+static const vector<ByteVector> invalidBinaryProvider = {
{0x31, 0x32, 0x37, 0x2e, 0x30, 0x30, 0x2e, 0x30, 0x2e, 0x31},
// foo
{0x66, 0x6f, 0x6f},
AddressFlags("127.0.0.1", 4, IS_LOCAL | IS_PVT_NONROUTE),
AddressFlags("::1", 6, IS_LOCAL | IS_PVT_NONROUTE),
+ // link-local v4
+ AddressFlags("169.254.0.1", 4, IS_LINK_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("127.128.129.200", 4, IS_LOCAL | IS_PVT_NONROUTE),
+ AddressFlags("127.255.255.255", 4, IS_LOCAL | IS_PVT_NONROUTE),
+ AddressFlags("169.254.0.0", 4, IS_LINK_LOCAL | 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),
AddressFlags("ff02::1", 6, IS_NONROUTABLE | IS_LINK_LOCAL_BROADCAST),
};
-static vector<pair<string, string> > mapProvider = {
+static const 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"},
{"::FFFF:222.1.41.90", "222.1.41.90"},
};
-static vector<MaskData> masksProvider = {
+static const 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("2620:0:1cfe:face:b00c::3", 0, "::")
};
-static vector<MaskBoundaryData> maskBoundaryProvider = {
+static const 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),