gfe-relnote: Replace QuicIpAddress with a standalone implementation. No functional change, not flag protected. This historically used platform representation out of convenience; making it platform-agnostic would make porting QUIC easier to new applications. The file itself needs to be moved to quic/core, and the impl can be deleted; that wil; be done in a separate CL. PiperOrigin-RevId: 251779401 Change-Id: Idc75704b8785d9b7b6b7870bf006c7f8dda83473
diff --git a/quic/platform/api/quic_ip_address.cc b/quic/platform/api/quic_ip_address.cc index 3b48c47..ebc71e1 100644 --- a/quic/platform/api/quic_ip_address.cc +++ b/quic/platform/api/quic_ip_address.cc
@@ -4,35 +4,83 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include <algorithm> +#include <cstring> #include <string> +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" + namespace quic { +static int ToPlatformAddressFamily(IpAddressFamily family) { + switch (family) { + case IpAddressFamily::IP_V4: + return AF_INET; + case IpAddressFamily::IP_V6: + return AF_INET6; + case IpAddressFamily::IP_UNSPEC: + return AF_UNSPEC; + } +} + QuicIpAddress QuicIpAddress::Loopback4() { - return QuicIpAddress(QuicIpAddressImpl::Loopback4()); + QuicIpAddress result; + result.family_ = IpAddressFamily::IP_V4; + result.address_.bytes[0] = 127; + result.address_.bytes[1] = 0; + result.address_.bytes[2] = 0; + result.address_.bytes[3] = 1; + return result; } QuicIpAddress QuicIpAddress::Loopback6() { - return QuicIpAddress(QuicIpAddressImpl::Loopback6()); + QuicIpAddress result; + result.family_ = IpAddressFamily::IP_V6; + uint8_t* bytes = result.address_.bytes; + memset(bytes, 0, 15); + bytes[15] = 1; + return result; } QuicIpAddress QuicIpAddress::Any4() { - return QuicIpAddress(QuicIpAddressImpl::Any4()); + in_addr address; + memset(&address, 0, sizeof(address)); + return QuicIpAddress(address); } QuicIpAddress QuicIpAddress::Any6() { - return QuicIpAddress(QuicIpAddressImpl::Any6()); + in6_addr address; + memset(&address, 0, sizeof(address)); + return QuicIpAddress(address); } -QuicIpAddress::QuicIpAddress(const QuicIpAddressImpl& impl) : impl_(impl) {} +QuicIpAddress::QuicIpAddress() : family_(IpAddressFamily::IP_UNSPEC) {} QuicIpAddress::QuicIpAddress(const in_addr& ipv4_address) - : impl_(ipv4_address) {} + : family_(IpAddressFamily::IP_V4) { + address_.v4 = ipv4_address; +} QuicIpAddress::QuicIpAddress(const in6_addr& ipv6_address) - : impl_(ipv6_address) {} + : family_(IpAddressFamily::IP_V6) { + address_.v6 = ipv6_address; +} bool operator==(QuicIpAddress lhs, QuicIpAddress rhs) { - return lhs.impl_ == rhs.impl_; + if (lhs.family_ != rhs.family_) { + return false; + } + switch (lhs.family_) { + case IpAddressFamily::IP_V4: + return std::equal(lhs.address_.bytes, + lhs.address_.bytes + QuicIpAddress::kIPv4AddressSize, + rhs.address_.bytes); + case IpAddressFamily::IP_V6: + return std::equal(lhs.address_.bytes, + lhs.address_.bytes + QuicIpAddress::kIPv6AddressSize, + rhs.address_.bytes); + case IpAddressFamily::IP_UNSPEC: + return true; + } } bool operator!=(QuicIpAddress lhs, QuicIpAddress rhs) { @@ -40,60 +88,141 @@ } bool QuicIpAddress::IsInitialized() const { - return impl_.IsInitialized(); + return family_ != IpAddressFamily::IP_UNSPEC; } IpAddressFamily QuicIpAddress::address_family() const { - return impl_.address_family(); + return family_; } int QuicIpAddress::AddressFamilyToInt() const { - return impl_.AddressFamilyToInt(); + return ToPlatformAddressFamily(family_); } std::string QuicIpAddress::ToPackedString() const { - return impl_.ToPackedString(); + switch (family_) { + case IpAddressFamily::IP_V4: + return std::string(address_.chars, sizeof(address_.v4)); + case IpAddressFamily::IP_V6: + return std::string(address_.chars, sizeof(address_.v6)); + case IpAddressFamily::IP_UNSPEC: + return ""; + } } std::string QuicIpAddress::ToString() const { - return impl_.ToString(); + if (!IsInitialized()) { + return ""; + } + + char buffer[INET6_ADDRSTRLEN] = {0}; + const char* result = + inet_ntop(AddressFamilyToInt(), address_.bytes, buffer, sizeof(buffer)); + QUIC_BUG_IF(result == nullptr) << "Failed to convert an IP address to string"; + return buffer; } +static const uint8_t kMappedAddressPrefix[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +}; + QuicIpAddress QuicIpAddress::Normalized() const { - return QuicIpAddress(impl_.Normalized()); + if (!IsIPv6()) { + return *this; + } + if (!std::equal(std::begin(kMappedAddressPrefix), + std::end(kMappedAddressPrefix), address_.bytes)) { + return *this; + } + + in_addr result; + memcpy(&result, &address_.bytes[12], sizeof(result)); + return QuicIpAddress(result); } QuicIpAddress QuicIpAddress::DualStacked() const { - return QuicIpAddress(impl_.DualStacked()); + if (!IsIPv4()) { + return *this; + } + + QuicIpAddress result; + result.family_ = IpAddressFamily::IP_V6; + memcpy(result.address_.bytes, kMappedAddressPrefix, + sizeof(kMappedAddressPrefix)); + memcpy(result.address_.bytes + 12, address_.bytes, kIPv4AddressSize); + return result; } bool QuicIpAddress::FromPackedString(const char* data, size_t length) { - return impl_.FromPackedString(data, length); + switch (length) { + case kIPv4AddressSize: + family_ = IpAddressFamily::IP_V4; + break; + case kIPv6AddressSize: + family_ = IpAddressFamily::IP_V6; + break; + default: + return false; + } + memcpy(address_.chars, data, length); + return true; } bool QuicIpAddress::FromString(std::string str) { - return impl_.FromString(str); + for (IpAddressFamily family : + {IpAddressFamily::IP_V6, IpAddressFamily::IP_V4}) { + int result = + inet_pton(ToPlatformAddressFamily(family), str.c_str(), address_.bytes); + if (result > 0) { + family_ = family; + return true; + } + } + return false; } bool QuicIpAddress::IsIPv4() const { - return impl_.IsIPv4(); + return family_ == IpAddressFamily::IP_V4; } bool QuicIpAddress::IsIPv6() const { - return impl_.IsIPv6(); + return family_ == IpAddressFamily::IP_V6; } bool QuicIpAddress::InSameSubnet(const QuicIpAddress& other, int subnet_length) { - return impl_.InSameSubnet(other.impl_, subnet_length); + if (!IsInitialized()) { + QUIC_BUG << "Attempting to do subnet matching on undefined address"; + return false; + } + if ((IsIPv4() && subnet_length > 32) || (IsIPv6() && subnet_length > 128)) { + QUIC_BUG << "Subnet mask is out of bounds"; + return false; + } + + int bytes_to_check = subnet_length / 8; + int bits_to_check = subnet_length % 8; + const uint8_t* const lhs = address_.bytes; + const uint8_t* const rhs = other.address_.bytes; + if (!std::equal(lhs, lhs + bytes_to_check, rhs)) { + return false; + } + if (bits_to_check == 0) { + return true; + } + DCHECK_LT(static_cast<size_t>(bytes_to_check), sizeof(address_.bytes)); + int mask = (~0) << (8 - bits_to_check); + return (lhs[bytes_to_check] & mask) == (rhs[bytes_to_check] & mask); } in_addr QuicIpAddress::GetIPv4() const { - return impl_.GetIPv4(); + DCHECK(IsIPv4()); + return address_.v4; } in6_addr QuicIpAddress::GetIPv6() const { - return impl_.GetIPv6(); + DCHECK(IsIPv6()); + return address_.v6; } } // namespace quic
diff --git a/quic/platform/api/quic_ip_address.h b/quic/platform/api/quic_ip_address.h index 6d507b4..e1a1076 100644 --- a/quic/platform/api/quic_ip_address.h +++ b/quic/platform/api/quic_ip_address.h
@@ -9,6 +9,7 @@ #include <winsock2.h> #include <ws2tcpip.h> #else +#include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> @@ -17,18 +18,18 @@ #include <string> #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" -#include "net/quic/platform/impl/quic_ip_address_impl.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address_family.h" namespace quic { +// Represents an IP address. class QUIC_EXPORT_PRIVATE QuicIpAddress { - // A class representing an IPv4 or IPv6 address in QUIC. The actual - // implementation (platform dependent) of an IP address is in - // QuicIpAddressImpl. public: + // Sizes of IP addresses of different types, in bytes. enum : size_t { - kIPv4AddressSize = QuicIpAddressImpl::kIPv4AddressSize, - kIPv6AddressSize = QuicIpAddressImpl::kIPv6AddressSize + kIPv4AddressSize = 32 / 8, + kIPv6AddressSize = 128 / 8, + kMaxAddressSize = kIPv6AddressSize, }; // TODO(fayang): Remove Loopback*() and use TestLoopback*() in tests. @@ -37,9 +38,8 @@ static QuicIpAddress Any4(); static QuicIpAddress Any6(); - QuicIpAddress() = default; + QuicIpAddress(); QuicIpAddress(const QuicIpAddress& other) = default; - explicit QuicIpAddress(const QuicIpAddressImpl& impl); explicit QuicIpAddress(const in_addr& ipv4_address); explicit QuicIpAddress(const in6_addr& ipv6_address); QuicIpAddress& operator=(const QuicIpAddress& other) = default; @@ -77,9 +77,20 @@ in6_addr GetIPv6() const; private: - QuicIpAddressImpl impl_; + union { + in_addr v4; + in6_addr v6; + uint8_t bytes[kMaxAddressSize]; + char chars[kMaxAddressSize]; + } address_; + IpAddressFamily family_; }; +inline std::ostream& operator<<(std::ostream& os, const QuicIpAddress address) { + os << address.ToString(); + return os; +} + } // namespace quic #endif // QUICHE_QUIC_PLATFORM_API_QUIC_IP_ADDRESS_H_
diff --git a/quic/platform/api/quic_ip_address_test.cc b/quic/platform/api/quic_ip_address_test.cc index 6942427..7dfe243 100644 --- a/quic/platform/api/quic_ip_address_test.cc +++ b/quic/platform/api/quic_ip_address_test.cc
@@ -56,6 +56,84 @@ EXPECT_EQ(0xff01u, *(v6_address_ptr + 5)); EXPECT_EQ(0x23feu, *(v6_address_ptr + 6)); EXPECT_EQ(0x6745u, *(v6_address_ptr + 7)); + + EXPECT_EQ(ip_address, ip_address.Normalized()); + EXPECT_EQ(ip_address, ip_address.DualStacked()); +} + +TEST(QuicIpAddressTest, FromPackedString) { + QuicIpAddress loopback4, loopback6; + const char loopback4_packed[] = "\x7f\0\0\x01"; + const char loopback6_packed[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"; + EXPECT_TRUE(loopback4.FromPackedString(loopback4_packed, 4)); + EXPECT_TRUE(loopback6.FromPackedString(loopback6_packed, 16)); + EXPECT_EQ(loopback4, QuicIpAddress::Loopback4()); + EXPECT_EQ(loopback6, QuicIpAddress::Loopback6()); +} + +TEST(QuicIpAddressTest, MappedAddress) { + QuicIpAddress ipv4_address; + QuicIpAddress mapped_address; + + EXPECT_TRUE(ipv4_address.FromString("127.0.0.1")); + EXPECT_TRUE(mapped_address.FromString("::ffff:7f00:1")); + + EXPECT_EQ(mapped_address, ipv4_address.DualStacked()); + EXPECT_EQ(ipv4_address, mapped_address.Normalized()); +} + +TEST(QuicIpAddressTest, Subnets) { + struct { + const char* address1; + const char* address2; + int subnet_size; + bool same_subnet; + } test_cases[] = { + {"127.0.0.1", "127.0.0.2", 24, true}, + {"8.8.8.8", "127.0.0.1", 24, false}, + {"8.8.8.8", "127.0.0.1", 16, false}, + {"8.8.8.8", "127.0.0.1", 8, false}, + {"8.8.8.8", "127.0.0.1", 2, false}, + {"8.8.8.8", "127.0.0.1", 1, true}, + + {"127.0.0.1", "127.0.0.128", 24, true}, + {"127.0.0.1", "127.0.0.128", 25, false}, + {"127.0.0.1", "127.0.0.127", 25, true}, + + {"127.0.0.1", "127.0.0.0", 30, true}, + {"127.0.0.1", "127.0.0.1", 30, true}, + {"127.0.0.1", "127.0.0.2", 30, true}, + {"127.0.0.1", "127.0.0.3", 30, true}, + {"127.0.0.1", "127.0.0.4", 30, false}, + + {"127.0.0.1", "127.0.0.2", 31, false}, + {"127.0.0.1", "127.0.0.0", 31, true}, + + {"::1", "fe80::1", 8, false}, + {"::1", "fe80::1", 1, false}, + {"::1", "fe80::1", 0, true}, + {"fe80::1", "fe80::2", 126, true}, + {"fe80::1", "fe80::2", 127, false}, + }; + + for (const auto& test_case : test_cases) { + QuicIpAddress address1, address2; + ASSERT_TRUE(address1.FromString(test_case.address1)); + ASSERT_TRUE(address2.FromString(test_case.address2)); + EXPECT_EQ(test_case.same_subnet, + address1.InSameSubnet(address2, test_case.subnet_size)) + << "Addresses: " << test_case.address1 << ", " << test_case.address2 + << "; subnet: /" << test_case.subnet_size; + } +} + +TEST(QuicIpAddress, LoopbackAddresses) { + QuicIpAddress loopback4; + QuicIpAddress loopback6; + ASSERT_TRUE(loopback4.FromString("127.0.0.1")); + ASSERT_TRUE(loopback6.FromString("::1")); + EXPECT_EQ(loopback4, QuicIpAddress::Loopback4()); + EXPECT_EQ(loopback6, QuicIpAddress::Loopback6()); } } // namespace