diff options
Diffstat (limited to 'src/lib/asiolink/tests/io_address_unittest.cc')
-rw-r--r-- | src/lib/asiolink/tests/io_address_unittest.cc | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc new file mode 100644 index 0000000..b113940 --- /dev/null +++ b/src/lib/asiolink/tests/io_address_unittest.cc @@ -0,0 +1,370 @@ +// Copyright (C) 2011-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <gtest/gtest.h> + +#include <asiolink/io_error.h> +#include <asiolink/io_address.h> +#include <exceptions/exceptions.h> + +#include <algorithm> +#include <cstring> +#include <vector> +#include <sstream> +#include <unordered_set> + +using namespace isc::asiolink; + +TEST(IOAddressHashTest, hashIPv4) { + IOAddress::Hash hash; + std::unordered_set<size_t> results; + for (uint32_t i = 0; i < 10; i++) { + IOAddress address(i); + auto result = hash(address); + results.insert(result); + } + // Make sure that the hashing function generated a unique hash for + // each address. + EXPECT_EQ(10, results.size()); +} + +TEST(IOAddressHashTest, hashIPv6) { + IOAddress::Hash hash; + std::unordered_set<size_t> results; + for (auto i = 0; i < 10; i++) { + std::ostringstream s; + s << "2001:db8:" << i << "::ffff"; + IOAddress address(s.str()); + auto result = hash(address); + results.insert(result); + } + // Make sure that the hashing function generated a unique hash for + // each address. + EXPECT_EQ(10, results.size()); +} + +TEST(IOAddressTest, fromText) { + IOAddress io_address_v4("192.0.2.1"); + EXPECT_EQ("192.0.2.1", io_address_v4.toText()); + + IOAddress io_address_v6("2001:db8::1234"); + EXPECT_EQ("2001:db8::1234", io_address_v6.toText()); + + // bogus IPv4 address-like input + EXPECT_THROW(IOAddress("192.0.2.2.1"), IOError); + + // bogus IPv4 address-like input: out-of-range octet + EXPECT_THROW(IOAddress("192.0.2.300"), IOError); + + // bogus IPv6 address-like input + EXPECT_THROW(IOAddress("2001:db8:::1234"), IOError); + + // bogus IPv6 address-like input + EXPECT_THROW(IOAddress("2001:db8::efgh"), IOError); +} + +TEST(IOAddressTest, Equality) { + EXPECT_TRUE(IOAddress("192.0.2.1") == IOAddress("192.0.2.1")); + EXPECT_FALSE(IOAddress("192.0.2.1") != IOAddress("192.0.2.1")); + + EXPECT_TRUE(IOAddress("192.0.2.1") != IOAddress("192.0.2.2")); + EXPECT_FALSE(IOAddress("192.0.2.1") == IOAddress("192.0.2.2")); + + EXPECT_TRUE(IOAddress("2001:db8::12") == IOAddress("2001:0DB8:0:0::0012")); + EXPECT_FALSE(IOAddress("2001:db8::12") != IOAddress("2001:0DB8:0:0::0012")); + + EXPECT_TRUE(IOAddress("2001:db8::1234") != IOAddress("2001:db8::1235")); + EXPECT_FALSE(IOAddress("2001:db8::1234") == IOAddress("2001:db8::1235")); + + EXPECT_TRUE(IOAddress("2001:db8::1234") != IOAddress("192.0.2.3")); + EXPECT_FALSE(IOAddress("2001:db8::1234") == IOAddress("192.0.2.3")); +} + +TEST(IOAddressTest, Family) { + EXPECT_EQ(AF_INET, IOAddress("192.0.2.1").getFamily()); + EXPECT_EQ(AF_INET6, IOAddress("2001:0DB8:0:0::0012").getFamily()); +} + +TEST(IOAddressTest, fromBytes) { + // 2001:db8:1::dead:beef + uint8_t v6[] = { + 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0, + 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef }; + + uint8_t v4[] = { 192, 0 , 2, 3 }; + + IOAddress addr("::"); + EXPECT_NO_THROW({ + addr = IOAddress::fromBytes(AF_INET6, v6); + }); + EXPECT_EQ("2001:db8:1::dead:beef", addr.toText()); + + EXPECT_NO_THROW({ + addr = IOAddress::fromBytes(AF_INET, v4); + }); + EXPECT_EQ(addr, IOAddress("192.0.2.3")); +} + +TEST(IOAddressTest, toBytesV4) { + // Address and network byte-order representation of the address. + const char* V4STRING = "192.0.2.1"; + uint8_t V4[] = {0xc0, 0x00, 0x02, 0x01}; + + std::vector<uint8_t> actual = IOAddress(V4STRING).toBytes(); + ASSERT_EQ(sizeof(V4), actual.size()); + EXPECT_TRUE(std::equal(actual.begin(), actual.end(), V4)); +} + +TEST(IOAddressTest, toBytesV6) { + // Address and network byte-order representation of the address. + const char* V6STRING = "2001:db8:1::dead:beef"; + uint8_t V6[] = { + 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef + }; + + std::vector<uint8_t> actual = IOAddress(V6STRING).toBytes(); + ASSERT_EQ(sizeof(V6), actual.size()); + EXPECT_TRUE(std::equal(actual.begin(), actual.end(), V6)); +} + +TEST(IOAddressTest, isV4) { + const IOAddress address4("192.0.2.1"); + const IOAddress address6("2001:db8:1::dead:beef"); + + EXPECT_TRUE(address4.isV4()); + EXPECT_FALSE(address6.isV4()); +} + +TEST(IOAddressTest, isV4Zero) { + // 0.0.0.0 + const IOAddress address_zero("0.0.0.0"); + EXPECT_TRUE(address_zero.isV4Zero()); + // :: (v6 zero address) + const IOAddress address_zero_v6("::"); + EXPECT_FALSE(address_zero_v6.isV4Zero()); + // 192.0.2.3 + const IOAddress address_non_zero("192.0.2.3"); + EXPECT_FALSE(address_non_zero.isV4Zero()); + // 0.0.0.100 + const IOAddress address_non_zero1("0.0.0.100"); + EXPECT_FALSE(address_non_zero1.isV4Zero()); + // 64.0.0.0 + const IOAddress address_non_zero2("64.0.0.0"); + EXPECT_FALSE(address_non_zero2.isV4Zero()); +} + +TEST(IOAddressTest, isV4Bcast) { + // 255.255.255.255 + const IOAddress address_bcast("255.255.255.255"); + EXPECT_TRUE(address_bcast.isV4Bcast()); + // 10.2.3.4 + const IOAddress address_non_bcast("10.2.3.4"); + EXPECT_FALSE(address_non_bcast.isV4Bcast()); + // 255.255.255.23 + const IOAddress address_non_bcast1("255.255.255.23"); + EXPECT_FALSE(address_non_bcast1.isV4Bcast()); + // 123.255.255.255 + const IOAddress address_non_bcast2("123.255.255.255"); + EXPECT_FALSE(address_non_bcast2.isV4Bcast()); + +} + +TEST(IOAddressTest, isV6) { + const IOAddress address4("192.0.2.1"); + const IOAddress address6("2001:db8:1::dead:beef"); + + EXPECT_FALSE(address4.isV6()); + EXPECT_TRUE(address6.isV6()); +} + +TEST(IOAddressTest, isV6Zero) { + // :: + const IOAddress address_zero("::"); + EXPECT_TRUE(address_zero.isV6Zero()); + // 0.0.0.0 + const IOAddress address_non_zero("0.0.0.0"); + EXPECT_FALSE(address_non_zero.isV6Zero()); + // ::ff + const IOAddress address_non_zero1("::ff"); + EXPECT_FALSE(address_non_zero1.isV6Zero()); + // ff:: + const IOAddress address_non_zero2("ff::"); + EXPECT_FALSE(address_non_zero2.isV6Zero()); +} + +TEST(IOAddressTest, uint32) { + IOAddress addr1("192.0.2.5"); + + // operator uint_32() is used here + uint32_t tmp = addr1.toUint32(); + + uint32_t expected = (192U << 24) + (0U << 16) + (2U << 8) + 5U; + + EXPECT_EQ(expected, tmp); + + // now let's try opposite conversion + IOAddress addr3 = IOAddress(expected); + + EXPECT_EQ(addr3.toText(), "192.0.2.5"); +} + +TEST(IOAddressTest, lessThanEqual) { + IOAddress addr1("192.0.2.5"); + IOAddress addr2("192.0.2.6"); + IOAddress addr3("0.0.0.0"); + + IOAddress addr4("::"); + IOAddress addr5("2001:db8::1"); + IOAddress addr6("2001:db8::1:0"); + IOAddress addr7("2001:db8::1:0"); // the same as 6 + + // v4 comparisons + EXPECT_TRUE(addr1 < addr2); + EXPECT_FALSE(addr2 < addr1); + EXPECT_FALSE(addr2 <= addr1); + EXPECT_TRUE(addr3 < addr1); + EXPECT_TRUE(addr3 < addr2); + EXPECT_TRUE(addr3 <= addr2); + + // v6 comparisons + EXPECT_TRUE(addr4 < addr5); + EXPECT_TRUE(addr5 < addr6); + EXPECT_FALSE(addr6 < addr5); + EXPECT_FALSE(addr6 <= addr5); + + // v4 to v6 - v4 should always be smaller + EXPECT_TRUE(addr1 < addr4); + EXPECT_TRUE(addr3 < addr4); + EXPECT_TRUE(addr2 < addr5); + + EXPECT_TRUE(addr6 <= addr7); +} + +// test operator<<. We simply confirm it appends the result of toText(). +TEST(IOAddressTest, LeftShiftOperator) { + const IOAddress addr("192.0.2.5"); + + std::ostringstream oss; + oss << addr; + EXPECT_EQ(addr.toText(), oss.str()); +} + +// Tests address classification methods (which were previously used by accessing +// underlying asio objects directly) +TEST(IOAddressTest, accessClassificationMethods) { + IOAddress addr1("192.0.2.5"); // IPv4 + IOAddress addr2("::"); // IPv6 + IOAddress addr3("2001:db8::1"); // global IPv6 + IOAddress addr4("fe80::1234"); // link-local + IOAddress addr5("ff02::1:2"); // multicast + + EXPECT_TRUE (addr1.isV4()); + EXPECT_FALSE(addr1.isV6()); + EXPECT_FALSE(addr1.isV6LinkLocal()); + EXPECT_FALSE(addr1.isV6Multicast()); + + EXPECT_FALSE(addr2.isV4()); + EXPECT_TRUE (addr2.isV6()); + EXPECT_FALSE(addr2.isV6LinkLocal()); + EXPECT_FALSE(addr2.isV6Multicast()); + + EXPECT_FALSE(addr3.isV4()); + EXPECT_TRUE (addr3.isV6()); + EXPECT_FALSE(addr3.isV6LinkLocal()); + EXPECT_FALSE(addr3.isV6Multicast()); + + EXPECT_FALSE(addr4.isV4()); + EXPECT_TRUE (addr4.isV6()); + EXPECT_TRUE (addr4.isV6LinkLocal()); + EXPECT_FALSE(addr4.isV6Multicast()); + + EXPECT_FALSE(addr5.isV4()); + EXPECT_TRUE (addr5.isV6()); + EXPECT_FALSE(addr5.isV6LinkLocal()); + EXPECT_TRUE (addr5.isV6Multicast()); +} + +TEST(IOAddressTest, staticAddresses) { + EXPECT_EQ(IOAddress("0.0.0.0"), IOAddress::IPV4_ZERO_ADDRESS()); + EXPECT_EQ(IOAddress("255.255.255.255"), IOAddress::IPV4_BCAST_ADDRESS()); + EXPECT_EQ(IOAddress("::"), IOAddress::IPV6_ZERO_ADDRESS()); +} + +// Tests whether address subtraction works correctly. +TEST(IOAddressTest, subtract) { + IOAddress addr1("192.0.2.12"); + IOAddress addr2("192.0.2.5"); + IOAddress addr3("192.0.2.0"); + IOAddress addr4("0.0.2.1"); + IOAddress any4("0.0.0.0"); + IOAddress bcast("255.255.255.255"); + + EXPECT_EQ("0.0.0.7", IOAddress::subtract(addr1, addr2).toText()); + EXPECT_EQ("0.0.0.12", IOAddress::subtract(addr1, addr3).toText()); + + // Subtracting 0.0.0.0 is like subtracting 0. + EXPECT_EQ("192.0.2.12", IOAddress::subtract(addr1, any4).toText()); + EXPECT_EQ("192.0.2.13", IOAddress::subtract(addr1, bcast).toText()); + EXPECT_EQ("191.255.255.255", IOAddress::subtract(addr3, addr4).toText()); + + // Let's check if we can subtract greater address from smaller. + // This will check if we can "loop" + EXPECT_EQ("255.255.255.251", IOAddress::subtract(addr3, addr2).toText()); + + IOAddress addr6("fe80::abcd"); + IOAddress addr7("fe80::"); + IOAddress addr8("fe80::1234"); + IOAddress addr9("2001:db8::face"); + IOAddress addr10("2001:db8::ffff:ffff:ffff:ffff"); + IOAddress addr11("::1"); + IOAddress any6("::"); + + EXPECT_EQ(IOAddress("::abcd"), IOAddress::subtract(addr6, addr7)); + EXPECT_EQ(IOAddress("::9999"), IOAddress::subtract(addr6, addr8)); + EXPECT_EQ("::ffff:ffff:ffff:531", IOAddress::subtract(addr10, addr9).toText()); + + // Subtract with borrow, extreme edition. Need to borrow one bit + // 112 times. + EXPECT_EQ("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + IOAddress::subtract(addr7, addr11).toText()); + + // Now check if we can loop beyond :: (:: - ::1 is a lot of F's) + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + IOAddress::subtract(any6, addr11).toText()); + + // Subtracting :: is like subtracting 0. + EXPECT_EQ("2001:db8::face", IOAddress::subtract(addr9, any6).toText()); + + // Let's check if we can subtract greater address from smaller. + // This will check if we can "loop" + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:edcc", + IOAddress::subtract(addr7, addr8).toText()); + + // Inter-family relations are not allowed. + EXPECT_THROW(IOAddress::subtract(addr1, addr6), isc::BadValue); + EXPECT_THROW(IOAddress::subtract(addr6, addr1), isc::BadValue); +} + +// Test checks whether an address can be increased. +TEST(IOAddressTest, increaseAddr) { + IOAddress addr1("192.0.2.12"); + IOAddress any4("0.0.0.0"); + IOAddress bcast("255.255.255.255"); + IOAddress addr6("2001:db8::ffff:ffff:ffff:ffff"); + IOAddress addr11("::1"); + IOAddress any6("::"); + IOAddress the_last_one("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + + EXPECT_EQ("192.0.2.13", IOAddress::increase(addr1).toText()); + EXPECT_EQ("0.0.0.1", IOAddress::increase(any4).toText()); + EXPECT_EQ("0.0.0.0", IOAddress::increase(bcast).toText()); + EXPECT_EQ("2001:db8:0:1::", IOAddress::increase(addr6).toText()); + EXPECT_EQ(IOAddress("::2"), IOAddress::increase(addr11)); + EXPECT_EQ(IOAddress("::1"), IOAddress::increase(any6)); + EXPECT_EQ(IOAddress("::"), IOAddress::increase(the_last_one)); +} |