| Index: net/base/ip_address.cc
|
| diff --git a/net/base/ip_address.cc b/net/base/ip_address.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9b76f2e34319f48fd0e4f80a9b843fc5e57eb59b
|
| --- /dev/null
|
| +++ b/net/base/ip_address.cc
|
| @@ -0,0 +1,390 @@
|
| +// Copyright (c) 2015 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 "net/base/ip_address.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/sys_byteorder.h"
|
| +#include "url/gurl.h"
|
| +#include "url/url_canon_ip.h"
|
| +
|
| +namespace net {
|
| +
|
| +const unsigned char IPAddress::kIPv4MappedPrefix[] = {0, 0, 0, 0, 0, 0,
|
| + 0, 0, 0, 0, 0xFF, 0xFF};
|
| +
|
| +IPAddress::IPAddress() {}
|
| +
|
| +IPAddress::~IPAddress() {}
|
| +
|
| +IPAddress::IPAddress(std::vector<unsigned char>& ip_address)
|
| + : ip_address_(ip_address) {}
|
| +
|
| +// Don't compare IPv4 and IPv6 addresses (they have different range
|
| +// reservations). Keep separate reservation arrays for each IP type, and
|
| +// consolidate adjacent reserved ranges within a reservation array when
|
| +// possible.
|
| +// Sources for info:
|
| +// www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml
|
| +// www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
|
| +// They're formatted here with the prefix as the last element. For example:
|
| +// 10.0.0.0/8 becomes 10,0,0,0,8 and fec0::/10 becomes 0xfe,0xc0,0,0,0...,10.
|
| +bool IPAddress::IsIPAddressReserved() const {
|
| + static const unsigned char kReservedIPv4[][5] = {
|
| + {0, 0, 0, 0, 8}, {10, 0, 0, 0, 8}, {100, 64, 0, 0, 10},
|
| + {127, 0, 0, 0, 8}, {169, 254, 0, 0, 16}, {172, 16, 0, 0, 12},
|
| + {192, 0, 2, 0, 24}, {192, 88, 99, 0, 24}, {192, 168, 0, 0, 16},
|
| + {198, 18, 0, 0, 15}, {198, 51, 100, 0, 24}, {203, 0, 113, 0, 24},
|
| + {224, 0, 0, 0, 3}};
|
| + static const unsigned char kReservedIPv6[][17] = {
|
| + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8},
|
| + {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2},
|
| + {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2},
|
| + {0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3},
|
| + {0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
|
| + {0xf0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5},
|
| + {0xf8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6},
|
| + {0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7},
|
| + {0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9},
|
| + {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
|
| + {0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
|
| + };
|
| + size_t array_size = 0;
|
| + const unsigned char* array = NULL;
|
| + switch (ip_address_.size()) {
|
| + case kIPv4AddressSize:
|
| + array_size = arraysize(kReservedIPv4);
|
| + array = kReservedIPv4[0];
|
| + break;
|
| + case kIPv6AddressSize:
|
| + array_size = arraysize(kReservedIPv6);
|
| + array = kReservedIPv6[0];
|
| + break;
|
| + }
|
| + if (!array)
|
| + return false;
|
| + size_t width = ip_address_.size() + 1;
|
| + for (size_t i = 0; i < array_size; ++i, array += width) {
|
| + if (IPAddressPrefixCheck(array, array[width - 1]))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +std::string IPAddress::ToString() const {
|
| + std::string str;
|
| + url::StdStringCanonOutput output(&str);
|
| +
|
| + if (IsIPv4()) {
|
| + url::AppendIPv4Address(&ip_address_.front(), &output);
|
| + } else if (IsIPv6()) {
|
| + url::AppendIPv6Address(&ip_address_.front(), &output);
|
| + } else {
|
| + size_t address_len = ip_address_.size();
|
| + CHECK(false) << "Invalid IP address with length: " << address_len;
|
| + }
|
| +
|
| + output.Complete();
|
| + return str;
|
| +}
|
| +
|
| +std::string IPAddress::ToStringWithPort(uint16_t port) const {
|
| + std::string address_str = ToString();
|
| +
|
| + if (IsIPv6()) {
|
| + // Need to bracket IPv6 addresses since they contain colons.
|
| + return base::StringPrintf("[%s]:%d", address_str.c_str(), port);
|
| + }
|
| + return base::StringPrintf("%s:%d", address_str.c_str(), port);
|
| +}
|
| +
|
| +std::string IPAddress::ToPackedString() const {
|
| + return std::string(reinterpret_cast<const char*>(&ip_address_.front()),
|
| + ip_address_.size());
|
| +}
|
| +
|
| +// Returns number of matching initial bits between the addresses and |other|.
|
| +unsigned IPAddress::CommonPrefixLength(const IPAddress& other) const {
|
| + DCHECK_EQ(ip_address_.size(), other.ip_address_.size());
|
| + for (size_t i = 0; i < ip_address_.size(); ++i) {
|
| + unsigned diff = ip_address_[i] ^ other.ip_address_[i];
|
| + if (!diff)
|
| + continue;
|
| + for (unsigned j = 0; j < CHAR_BIT; ++j) {
|
| + if (diff & (1 << (CHAR_BIT - 1)))
|
| + return i * CHAR_BIT + j;
|
| + diff <<= 1;
|
| + }
|
| + NOTREACHED();
|
| + }
|
| + return ip_address_.size() * CHAR_BIT;
|
| +}
|
| +
|
| +// Computes the number of leading 1-bits in |ip_address_|.
|
| +unsigned IPAddress::MaskPrefixLength() const {
|
| + std::vector<unsigned char> all_ones_mask(ip_address_.size(), 0xFF);
|
| + IPAddress all_ones(all_ones_mask);
|
| + return all_ones.CommonPrefixLength(all_ones);
|
| +}
|
| +
|
| +bool IPAddress::IsIPv4Mapped() const {
|
| + if (!IsIPv6())
|
| + return false;
|
| + return std::equal(ip_address_.begin(),
|
| + ip_address_.begin() + arraysize(kIPv4MappedPrefix),
|
| + kIPv4MappedPrefix);
|
| +}
|
| +
|
| +AddressFamily IPAddress::GetAddressFamily() const {
|
| + switch (ip_address_.size()) {
|
| + case kIPv4AddressSize:
|
| + return ADDRESS_FAMILY_IPV4;
|
| + case kIPv6AddressSize:
|
| + return ADDRESS_FAMILY_IPV6;
|
| + default:
|
| + return ADDRESS_FAMILY_UNSPECIFIED;
|
| + }
|
| +}
|
| +
|
| +bool IPAddress::MatchesPrefix(const IPAddress& ip_prefix,
|
| + size_t prefix_length_in_bits) {
|
| + // Both the input IP address and the prefix IP address should be
|
| + // either IPv4 or IPv6.
|
| + DCHECK(IsIPv4() || IsIPv6());
|
| + DCHECK(ip_prefix.IsIPv4() || ip_prefix.IsIPv6());
|
| +
|
| + DCHECK_LE(prefix_length_in_bits, ip_prefix.ip_address_.size() * 8);
|
| +
|
| + // In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to
|
| + // IPv6 addresses in order to do the comparison.
|
| + if (ip_address_.size() != ip_prefix.ip_address_.size()) {
|
| + if (IsIPv4()) {
|
| + IPAddress temp = IPAddress::ConvertIPv4ToIPv6(*this);
|
| + return temp.MatchesPrefix(ip_prefix, prefix_length_in_bits);
|
| + }
|
| + IPAddress temp = IPAddress::ConvertIPv4ToIPv6(ip_prefix);
|
| + return MatchesPrefix(temp, 96 + prefix_length_in_bits);
|
| + }
|
| +
|
| + return IPAddressPrefixCheck(&ip_prefix, prefix_length_in_bits);
|
| +}
|
| +
|
| +bool IPAddress::ToSockAddrWithPort(struct sockaddr* address,
|
| + socklen_t* address_length,
|
| + int port) const {
|
| + DCHECK(address);
|
| + DCHECK(address_length);
|
| + switch (ip_address_.size()) {
|
| + case kIPv4AddressSize: {
|
| + socklen_t kSockaddrInSize = sizeof(struct sockaddr_in);
|
| + if (*address_length < kSockaddrInSize)
|
| + return false;
|
| + *address_length = kSockaddrInSize;
|
| + struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(address);
|
| + memset(addr, 0, sizeof(struct sockaddr_in));
|
| + addr->sin_family = AF_INET;
|
| + addr->sin_port = base::HostToNet16(port);
|
| + memcpy(&addr->sin_addr, &ip_address_[0], kIPv4AddressSize);
|
| + break;
|
| + }
|
| + case kIPv6AddressSize: {
|
| + socklen_t kSockaddrInSize = sizeof(struct sockaddr_in6);
|
| + if (*address_length < kSockaddrInSize)
|
| + return false;
|
| + *address_length = kSockaddrInSize;
|
| + struct sockaddr_in6* addr6 =
|
| + reinterpret_cast<struct sockaddr_in6*>(address);
|
| + memset(addr6, 0, sizeof(struct sockaddr_in6));
|
| + addr6->sin6_family = AF_INET6;
|
| + addr6->sin6_port = base::HostToNet16(port);
|
| + memcpy(&addr6->sin6_addr, &ip_address_[0], kIPv6AddressSize);
|
| + break;
|
| + }
|
| + default:
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +bool IPAddress::FromURLHostname(const std::string& hostname,
|
| + IPAddress* ip_address) {
|
| + // |hostname| is an already canoncalized hostname, conforming to RFC 3986.
|
| + // For an IP address, this is defined in Section 3.2.2 of RFC 3986, with
|
| + // the canonical form for IPv6 addresses defined in Section 4 of RFC 5952.
|
| + url::Component host_comp(0, hostname.size());
|
| +
|
| + std::vector<unsigned char> ip;
|
| +
|
| + // If it has a bracket, try parsing it as an IPv6 address.
|
| + if (hostname[0] == '[') {
|
| + ip.resize(16); // 128 bits.
|
| + bool result =
|
| + url::IPv6AddressToNumber(hostname.data(), host_comp, &(ip)[0]);
|
| + ip_address->ip_address_ = ip;
|
| + return result;
|
| + }
|
| +
|
| + // Otherwise, try IPv4.
|
| + ip.resize(4); // 32 bits.
|
| + int num_components;
|
| + url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
|
| + hostname.data(), host_comp, &(ip)[0], &num_components);
|
| + ip_address->ip_address_ = ip;
|
| + return family == url::CanonHostInfo::IPV4;
|
| +}
|
| +
|
| +// static
|
| +bool IPAddress::FromIPLiteral(const base::StringPiece& ip_literal,
|
| + IPAddress* ip_address) {
|
| + std::vector<unsigned char> ip;
|
| +
|
| + // |ip_literal| could be either a IPv4 or an IPv6 literal. If it contains
|
| + // a colon however, it must be an IPv6 address.
|
| + if (ip_literal.find(':') != base::StringPiece::npos) {
|
| + // GURL expects IPv6 hostnames to be surrounded with brackets.
|
| + std::string host_brackets = "[";
|
| + ip_literal.AppendToString(&host_brackets);
|
| + host_brackets.push_back(']');
|
| + url::Component host_comp(0, host_brackets.size());
|
| +
|
| + // Try parsing the hostname as an IPv6 literal.
|
| + ip.resize(16); // 128 bits.
|
| + bool result =
|
| + url::IPv6AddressToNumber(host_brackets.data(), host_comp, &(ip)[0]);
|
| + ip_address->ip_address_ = ip;
|
| + return result;
|
| + }
|
| +
|
| + // Otherwise the string is an IPv4 address.
|
| + ip.resize(4); // 32 bits.
|
| + url::Component host_comp(0, ip_literal.size());
|
| + int num_components;
|
| + url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
|
| + ip_literal.data(), host_comp, &(ip)[0], &num_components);
|
| +
|
| + ip_address->ip_address_ = ip;
|
| + return family == url::CanonHostInfo::IPV4;
|
| +}
|
| +
|
| +// static
|
| +bool IPAddress::FromCIDRBlock(const std::string& cidr_literal,
|
| + IPAddress* ip_address,
|
| + size_t* prefix_length_in_bits) {
|
| + // We expect CIDR notation to match one of these two templates:
|
| + // <IPv4-literal> "/" <number of bits>
|
| + // <IPv6-literal> "/" <number of bits>
|
| +
|
| + std::vector<base::StringPiece> parts = base::SplitStringPiece(
|
| + cidr_literal, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
|
| + if (parts.size() != 2)
|
| + return false;
|
| +
|
| + // Parse the IP address.
|
| + if (!IPAddress::FromIPLiteral(parts[0], ip_address))
|
| + return false;
|
| +
|
| + // Parse the prefix length.
|
| + int number_of_bits = -1;
|
| + if (!base::StringToInt(parts[1], &number_of_bits))
|
| + return false;
|
| +
|
| + // Make sure the prefix length is in a valid range.
|
| + if (number_of_bits < 0 ||
|
| + number_of_bits > static_cast<int>(ip_address->ip_address_.size() * 8))
|
| + return false;
|
| +
|
| + *prefix_length_in_bits = static_cast<size_t>(number_of_bits);
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +IPAddress IPAddress::FromLegacy(const IPAddressNumber& ip_address) {
|
| + std::vector<unsigned char> address_copy(ip_address);
|
| + IPAddress new_address(address_copy);
|
| + return new_address;
|
| +}
|
| +
|
| +// static
|
| +IPAddress IPAddress::ConvertIPv4ToIPv6(const IPAddress& ipv4_address) {
|
| + DCHECK(ipv4_address.IsIPv4());
|
| +
|
| + // IPv4-mapped addresses are formed by:
|
| + // <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
|
| + std::vector<unsigned char> ipv6_address;
|
| + ipv6_address.reserve(16);
|
| + ipv6_address.insert(ipv6_address.end(), kIPv4MappedPrefix,
|
| + kIPv4MappedPrefix + arraysize(kIPv4MappedPrefix));
|
| + ipv6_address.insert(ipv6_address.end(), ipv4_address.ip_address_.begin(),
|
| + ipv4_address.ip_address_.end());
|
| + return IPAddress(ipv6_address);
|
| +}
|
| +
|
| +// static
|
| +IPAddress IPAddress::ConvertIPv4MappedToIPv4(const IPAddress& address) {
|
| + DCHECK(address.IsIPv4Mapped());
|
| + std::vector<unsigned char> without_prefix(
|
| + address.ip_address_.begin() + arraysize(kIPv4MappedPrefix),
|
| + address.ip_address_.end());
|
| + IPAddress ip_address(without_prefix);
|
| + return ip_address;
|
| +}
|
| +
|
| +bool IPAddress::operator==(const IPAddress& that) const {
|
| + return ip_address_ == that.ip_address_;
|
| +}
|
| +
|
| +bool IPAddress::operator!=(const IPAddress& that) const {
|
| + return ip_address_ != that.ip_address_;
|
| +}
|
| +
|
| +bool IPAddress::operator<(const IPAddress& that) const {
|
| + // Sort IPv4 before IPv6.
|
| + if (ip_address_.size() != that.ip_address_.size()) {
|
| + return ip_address_.size() < that.ip_address_.size();
|
| + }
|
| +
|
| + return ip_address_ < that.ip_address_;
|
| +}
|
| +
|
| +bool IPAddress::operator>(const IPAddress& that) const {
|
| + // Sort IPv4 after IPv6.
|
| + if (ip_address_.size() != that.ip_address_.size()) {
|
| + return ip_address_.size() > that.ip_address_.size();
|
| + }
|
| +
|
| + return ip_address_ > that.ip_address_;
|
| +}
|
| +
|
| +bool IPAddress::IPAddressPrefixCheck(const IPAddress* ip_prefix,
|
| + size_t prefix_length_in_bits) const {
|
| + return IPAddressPrefixCheck(&(ip_prefix->ip_address_)[0],
|
| + prefix_length_in_bits);
|
| +}
|
| +
|
| +bool IPAddress::IPAddressPrefixCheck(const unsigned char* ip_prefix,
|
| + size_t prefix_length_in_bits) const {
|
| + // Compare all the bytes that fall entirely within the prefix.
|
| + int num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
|
| + for (int i = 0; i < num_entire_bytes_in_prefix; ++i) {
|
| + if (ip_address_[i] != ip_prefix[i])
|
| + return false;
|
| + }
|
| +
|
| + // In case the prefix was not a multiple of 8, there will be 1 byte
|
| + // which is only partially masked.
|
| + int remaining_bits = prefix_length_in_bits % 8;
|
| + if (remaining_bits != 0) {
|
| + unsigned char mask = 0xFF << (8 - remaining_bits);
|
| + int i = num_entire_bytes_in_prefix;
|
| + if ((ip_address_[i] & mask) != (ip_prefix[i] & mask))
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +} // namespace net
|
|
|