blob: b2cb649f5f902564deb7e31d2f71557b4bdcb1f5 [file] [log] [blame]
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "quic/platform/api/quic_ip_address.h"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <string>
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_logging.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;
}
QUIC_BUG(quic_bug_10126_1)
<< "Invalid IpAddressFamily " << static_cast<int32_t>(family);
return AF_UNSPEC;
}
QuicIpAddress QuicIpAddress::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() {
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() {
in_addr address;
memset(&address, 0, sizeof(address));
return QuicIpAddress(address);
}
QuicIpAddress QuicIpAddress::Any6() {
in6_addr address;
memset(&address, 0, sizeof(address));
return QuicIpAddress(address);
}
QuicIpAddress::QuicIpAddress() : family_(IpAddressFamily::IP_UNSPEC) {}
QuicIpAddress::QuicIpAddress(const in_addr& ipv4_address)
: family_(IpAddressFamily::IP_V4) {
address_.v4 = ipv4_address;
}
QuicIpAddress::QuicIpAddress(const in6_addr& ipv6_address)
: family_(IpAddressFamily::IP_V6) {
address_.v6 = ipv6_address;
}
bool operator==(QuicIpAddress lhs, QuicIpAddress rhs) {
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;
}
QUIC_BUG(quic_bug_10126_2)
<< "Invalid IpAddressFamily " << static_cast<int32_t>(lhs.family_);
return false;
}
bool operator!=(QuicIpAddress lhs, QuicIpAddress rhs) {
return !(lhs == rhs);
}
bool QuicIpAddress::IsInitialized() const {
return family_ != IpAddressFamily::IP_UNSPEC;
}
IpAddressFamily QuicIpAddress::address_family() const {
return family_;
}
int QuicIpAddress::AddressFamilyToInt() const {
return ToPlatformAddressFamily(family_);
}
std::string QuicIpAddress::ToPackedString() const {
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 "";
}
QUIC_BUG(quic_bug_10126_3)
<< "Invalid IpAddressFamily " << static_cast<int32_t>(family_);
return "";
}
std::string QuicIpAddress::ToString() const {
if (!IsInitialized()) {
return "";
}
char buffer[INET6_ADDRSTRLEN] = {0};
const char* result =
inet_ntop(AddressFamilyToInt(), address_.bytes, buffer, sizeof(buffer));
QUIC_BUG_IF(quic_bug_10126_4, 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 {
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 {
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) {
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) {
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 family_ == IpAddressFamily::IP_V4;
}
bool QuicIpAddress::IsIPv6() const {
return family_ == IpAddressFamily::IP_V6;
}
bool QuicIpAddress::InSameSubnet(const QuicIpAddress& other,
int subnet_length) {
if (!IsInitialized()) {
QUIC_BUG(quic_bug_10126_5)
<< "Attempting to do subnet matching on undefined address";
return false;
}
if ((IsIPv4() && subnet_length > 32) || (IsIPv6() && subnet_length > 128)) {
QUIC_BUG(quic_bug_10126_6) << "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;
}
QUICHE_DCHECK_LT(static_cast<size_t>(bytes_to_check), sizeof(address_.bytes));
int mask = (~0u) << (8u - bits_to_check);
return (lhs[bytes_to_check] & mask) == (rhs[bytes_to_check] & mask);
}
in_addr QuicIpAddress::GetIPv4() const {
QUICHE_DCHECK(IsIPv4());
return address_.v4;
}
in6_addr QuicIpAddress::GetIPv6() const {
QUICHE_DCHECK(IsIPv6());
return address_.v6;
}
} // namespace quic