Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/ip_address.h" | 5 #include "net/base/ip_address.h" |
| 6 | 6 |
| 7 #include "base/strings/string_piece.h" | 7 #include "base/strings/string_piece.h" |
| 8 #include "base/strings/string_split.h" | 8 #include "base/strings/string_split.h" |
| 9 #include "net/base/ip_address_number.h" | 9 #include "net/base/ip_address_number.h" |
| 10 #include "net/base/parse_number.h" | 10 #include "net/base/parse_number.h" |
| 11 #include "url/gurl.h" | 11 #include "url/gurl.h" |
| 12 #include "url/url_canon_ip.h" | 12 #include "url/url_canon_ip.h" |
| 13 | 13 |
| 14 namespace { | |
| 15 | |
| 16 bool IPAddressPrefixCheck(const std::vector<uint8_t>& ip_address, | |
| 17 const unsigned char* ip_prefix, | |
| 18 size_t prefix_length_in_bits) { | |
| 19 // Compare all the bytes that fall entirely within the prefix. | |
| 20 int num_entire_bytes_in_prefix = prefix_length_in_bits / 8; | |
| 21 for (int i = 0; i < num_entire_bytes_in_prefix; ++i) { | |
| 22 if (ip_address[i] != ip_prefix[i]) | |
| 23 return false; | |
| 24 } | |
| 25 | |
| 26 // In case the prefix was not a multiple of 8, there will be 1 byte | |
| 27 // which is only partially masked. | |
| 28 int remaining_bits = prefix_length_in_bits % 8; | |
| 29 if (remaining_bits != 0) { | |
| 30 unsigned char mask = 0xFF << (8 - remaining_bits); | |
| 31 int i = num_entire_bytes_in_prefix; | |
| 32 if ((ip_address[i] & mask) != (ip_prefix[i] & mask)) | |
| 33 return false; | |
| 34 } | |
| 35 return true; | |
| 36 } | |
| 37 | |
| 38 } // namespace | |
| 39 | |
| 14 namespace net { | 40 namespace net { |
| 15 | 41 |
| 16 IPAddress::IPAddress() {} | 42 IPAddress::IPAddress() {} |
| 17 | 43 |
| 18 IPAddress::IPAddress(const IPAddressNumber& address) : ip_address_(address) {} | 44 IPAddress::IPAddress(const IPAddressNumber& address) : ip_address_(address) {} |
| 19 | 45 |
| 20 IPAddress::IPAddress(const IPAddress& other) = default; | 46 IPAddress::IPAddress(const IPAddress& other) = default; |
| 21 | 47 |
| 22 IPAddress::IPAddress(const uint8_t* address, size_t address_len) | 48 IPAddress::IPAddress(const uint8_t* address, size_t address_len) |
| 23 : ip_address_(address, address + address_len) {} | 49 : ip_address_(address, address + address_len) {} |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 58 } | 84 } |
| 59 | 85 |
| 60 bool IPAddress::IsIPv6() const { | 86 bool IPAddress::IsIPv6() const { |
| 61 return ip_address_.size() == kIPv6AddressSize; | 87 return ip_address_.size() == kIPv6AddressSize; |
| 62 } | 88 } |
| 63 | 89 |
| 64 bool IPAddress::IsValid() const { | 90 bool IPAddress::IsValid() const { |
| 65 return IsIPv4() || IsIPv6(); | 91 return IsIPv4() || IsIPv6(); |
| 66 } | 92 } |
| 67 | 93 |
| 94 // Don't compare IPv4 and IPv6 addresses (they have different range | |
| 95 // reservations). Keep separate reservation arrays for each IP type, and | |
| 96 // consolidate adjacent reserved ranges within a reservation array when | |
| 97 // possible. | |
| 98 // Sources for info: | |
| 99 // www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml | |
| 100 // www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml | |
| 101 // They're formatted here with the prefix as the last element. For example: | |
| 102 // 10.0.0.0/8 becomes 10,0,0,0,8 and fec0::/10 becomes 0xfe,0xc0,0,0,0...,10. | |
| 68 bool IPAddress::IsReserved() const { | 103 bool IPAddress::IsReserved() const { |
| 69 return IsIPAddressReserved(ip_address_); | 104 static const unsigned char kReservedIPv4[][5] = { |
| 105 {0, 0, 0, 0, 8}, {10, 0, 0, 0, 8}, {100, 64, 0, 0, 10}, | |
| 106 {127, 0, 0, 0, 8}, {169, 254, 0, 0, 16}, {172, 16, 0, 0, 12}, | |
| 107 {192, 0, 2, 0, 24}, {192, 88, 99, 0, 24}, {192, 168, 0, 0, 16}, | |
| 108 {198, 18, 0, 0, 15}, {198, 51, 100, 0, 24}, {203, 0, 113, 0, 24}, | |
| 109 {224, 0, 0, 0, 3}}; | |
| 110 static const unsigned char kReservedIPv6[][17] = { | |
|
martijnc
2016/04/11 22:02:08
I copied this list but while trying to write tests
eroman
2016/04/12 05:30:56
Thanks for raising this issue Martin!
Yeah, those
Ryan Sleevi
2016/04/12 21:15:59
When the review introducing this started, that's w
| |
| 111 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8}, | |
| 112 {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}, | |
| 113 {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}, | |
| 114 {0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}, | |
| 115 {0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}, | |
| 116 {0xf0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}, | |
| 117 {0xf8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6}, | |
| 118 {0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}, | |
| 119 {0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9}, | |
| 120 {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10}, | |
| 121 {0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10}, | |
| 122 }; | |
| 123 size_t array_size = 0; | |
| 124 const unsigned char* array = nullptr; | |
| 125 switch (ip_address_.size()) { | |
| 126 case kIPv4AddressSize: | |
| 127 array_size = arraysize(kReservedIPv4); | |
| 128 array = kReservedIPv4[0]; | |
| 129 break; | |
| 130 case kIPv6AddressSize: | |
| 131 array_size = arraysize(kReservedIPv6); | |
| 132 array = kReservedIPv6[0]; | |
| 133 break; | |
| 134 } | |
| 135 if (!array) | |
| 136 return false; | |
| 137 size_t width = ip_address_.size() + 1; | |
| 138 for (size_t i = 0; i < array_size; ++i, array += width) { | |
| 139 if (IPAddressPrefixCheck(ip_address_, array, array[width - 1])) | |
| 140 return true; | |
| 141 } | |
| 142 return false; | |
| 70 } | 143 } |
| 71 | 144 |
| 72 bool IPAddress::IsZero() const { | 145 bool IPAddress::IsZero() const { |
| 73 for (auto x : ip_address_) { | 146 for (auto x : ip_address_) { |
| 74 if (x != 0) | 147 if (x != 0) |
| 75 return false; | 148 return false; |
| 76 } | 149 } |
| 77 | 150 |
| 78 return !empty(); | 151 return !empty(); |
| 79 } | 152 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 return IPAddress(ConvertIPv4NumberToIPv6Number(address.bytes())); | 225 return IPAddress(ConvertIPv4NumberToIPv6Number(address.bytes())); |
| 153 } | 226 } |
| 154 | 227 |
| 155 IPAddress ConvertIPv4MappedIPv6ToIPv4(const IPAddress& address) { | 228 IPAddress ConvertIPv4MappedIPv6ToIPv4(const IPAddress& address) { |
| 156 return IPAddress(ConvertIPv4MappedToIPv4(address.bytes())); | 229 return IPAddress(ConvertIPv4MappedToIPv4(address.bytes())); |
| 157 } | 230 } |
| 158 | 231 |
| 159 bool IPAddressMatchesPrefix(const IPAddress& ip_address, | 232 bool IPAddressMatchesPrefix(const IPAddress& ip_address, |
| 160 const IPAddress& ip_prefix, | 233 const IPAddress& ip_prefix, |
| 161 size_t prefix_length_in_bits) { | 234 size_t prefix_length_in_bits) { |
| 162 return IPNumberMatchesPrefix(ip_address.bytes(), ip_prefix.bytes(), | 235 // Both the input IP address and the prefix IP address should be either IPv4 |
| 163 prefix_length_in_bits); | 236 // or IPv6. |
| 237 DCHECK(ip_address.IsValid()); | |
| 238 DCHECK(ip_prefix.IsValid()); | |
| 239 | |
| 240 DCHECK_LE(prefix_length_in_bits, ip_prefix.size() * 8); | |
| 241 | |
| 242 // In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to | |
| 243 // IPv6 addresses in order to do the comparison. | |
| 244 if (ip_address.size() != ip_prefix.size()) { | |
| 245 if (ip_address.IsIPv4()) { | |
| 246 return IPAddressMatchesPrefix(ConvertIPv4ToIPv4MappedIPv6(ip_address), | |
| 247 ip_prefix, prefix_length_in_bits); | |
| 248 } | |
| 249 return IPAddressMatchesPrefix(ip_address, | |
| 250 ConvertIPv4ToIPv4MappedIPv6(ip_prefix), | |
| 251 96 + prefix_length_in_bits); | |
| 252 } | |
| 253 | |
| 254 return IPAddressPrefixCheck(ip_address.bytes(), ip_prefix.bytes().data(), | |
| 255 prefix_length_in_bits); | |
| 164 } | 256 } |
| 165 | 257 |
| 166 bool ParseCIDRBlock(const std::string& cidr_literal, | 258 bool ParseCIDRBlock(const std::string& cidr_literal, |
| 167 IPAddress* ip_address, | 259 IPAddress* ip_address, |
| 168 size_t* prefix_length_in_bits) { | 260 size_t* prefix_length_in_bits) { |
| 169 // We expect CIDR notation to match one of these two templates: | 261 // We expect CIDR notation to match one of these two templates: |
| 170 // <IPv4-literal> "/" <number of bits> | 262 // <IPv4-literal> "/" <number of bits> |
| 171 // <IPv6-literal> "/" <number of bits> | 263 // <IPv6-literal> "/" <number of bits> |
| 172 | 264 |
| 173 std::vector<base::StringPiece> parts = base::SplitStringPiece( | 265 std::vector<base::StringPiece> parts = base::SplitStringPiece( |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 208 | 300 |
| 209 unsigned CommonPrefixLength(const IPAddress& a1, const IPAddress& a2) { | 301 unsigned CommonPrefixLength(const IPAddress& a1, const IPAddress& a2) { |
| 210 return CommonPrefixLength(a1.bytes(), a2.bytes()); | 302 return CommonPrefixLength(a1.bytes(), a2.bytes()); |
| 211 } | 303 } |
| 212 | 304 |
| 213 unsigned MaskPrefixLength(const IPAddress& mask) { | 305 unsigned MaskPrefixLength(const IPAddress& mask) { |
| 214 return MaskPrefixLength(mask.bytes()); | 306 return MaskPrefixLength(mask.bytes()); |
| 215 } | 307 } |
| 216 | 308 |
| 217 } // namespace net | 309 } // namespace net |
| OLD | NEW |