Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(308)

Side by Side Diff: net/base/ip_address.cc

Issue 1408803010: Add IPAddress class as a replacement for the IPAddressNumber typedef. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/base/ip_address.h"
6
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/sys_byteorder.h"
12 #include "url/gurl.h"
13 #include "url/url_canon_ip.h"
14
15 namespace net {
16
17 const unsigned char IPAddress::kIPv4MappedPrefix[] = {0, 0, 0, 0, 0, 0,
18 0, 0, 0, 0, 0xFF, 0xFF};
19
20 IPAddress::IPAddress() {}
21
22 IPAddress::~IPAddress() {}
23
24 IPAddress::IPAddress(std::vector<unsigned char>& ip_address)
25 : ip_address_(ip_address) {}
26
27 // Don't compare IPv4 and IPv6 addresses (they have different range
28 // reservations). Keep separate reservation arrays for each IP type, and
29 // consolidate adjacent reserved ranges within a reservation array when
30 // possible.
31 // Sources for info:
32 // www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml
33 // www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
34 // They're formatted here with the prefix as the last element. For example:
35 // 10.0.0.0/8 becomes 10,0,0,0,8 and fec0::/10 becomes 0xfe,0xc0,0,0,0...,10.
36 bool IPAddress::IsIPAddressReserved() const {
37 static const unsigned char kReservedIPv4[][5] = {
38 {0, 0, 0, 0, 8}, {10, 0, 0, 0, 8}, {100, 64, 0, 0, 10},
39 {127, 0, 0, 0, 8}, {169, 254, 0, 0, 16}, {172, 16, 0, 0, 12},
40 {192, 0, 2, 0, 24}, {192, 88, 99, 0, 24}, {192, 168, 0, 0, 16},
41 {198, 18, 0, 0, 15}, {198, 51, 100, 0, 24}, {203, 0, 113, 0, 24},
42 {224, 0, 0, 0, 3}};
43 static const unsigned char kReservedIPv6[][17] = {
44 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8},
45 {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2},
46 {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2},
47 {0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3},
48 {0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
49 {0xf0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5},
50 {0xf8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6},
51 {0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7},
52 {0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9},
53 {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
54 {0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
55 };
56 size_t array_size = 0;
57 const unsigned char* array = NULL;
58 switch (ip_address_.size()) {
59 case kIPv4AddressSize:
60 array_size = arraysize(kReservedIPv4);
61 array = kReservedIPv4[0];
62 break;
63 case kIPv6AddressSize:
64 array_size = arraysize(kReservedIPv6);
65 array = kReservedIPv6[0];
66 break;
67 }
68 if (!array)
69 return false;
70 size_t width = ip_address_.size() + 1;
71 for (size_t i = 0; i < array_size; ++i, array += width) {
72 if (IPAddressPrefixCheck(array, array[width - 1]))
73 return true;
74 }
75 return false;
76 }
77
78 std::string IPAddress::ToString() const {
79 std::string str;
80 url::StdStringCanonOutput output(&str);
81
82 if (IsIPv4()) {
83 url::AppendIPv4Address(&ip_address_.front(), &output);
84 } else if (IsIPv6()) {
85 url::AppendIPv6Address(&ip_address_.front(), &output);
86 } else {
87 size_t address_len = ip_address_.size();
88 CHECK(false) << "Invalid IP address with length: " << address_len;
89 }
90
91 output.Complete();
92 return str;
93 }
94
95 std::string IPAddress::ToStringWithPort(uint16_t port) const {
96 std::string address_str = ToString();
97
98 if (IsIPv6()) {
99 // Need to bracket IPv6 addresses since they contain colons.
100 return base::StringPrintf("[%s]:%d", address_str.c_str(), port);
101 }
102 return base::StringPrintf("%s:%d", address_str.c_str(), port);
103 }
104
105 std::string IPAddress::ToPackedString() const {
106 return std::string(reinterpret_cast<const char*>(&ip_address_.front()),
107 ip_address_.size());
108 }
109
110 // Returns number of matching initial bits between the addresses and |other|.
111 unsigned IPAddress::CommonPrefixLength(const IPAddress& other) const {
112 DCHECK_EQ(ip_address_.size(), other.ip_address_.size());
113 for (size_t i = 0; i < ip_address_.size(); ++i) {
114 unsigned diff = ip_address_[i] ^ other.ip_address_[i];
115 if (!diff)
116 continue;
117 for (unsigned j = 0; j < CHAR_BIT; ++j) {
118 if (diff & (1 << (CHAR_BIT - 1)))
119 return i * CHAR_BIT + j;
120 diff <<= 1;
121 }
122 NOTREACHED();
123 }
124 return ip_address_.size() * CHAR_BIT;
125 }
126
127 // Computes the number of leading 1-bits in |ip_address_|.
128 unsigned IPAddress::MaskPrefixLength() const {
129 std::vector<unsigned char> all_ones_mask(ip_address_.size(), 0xFF);
130 IPAddress all_ones(all_ones_mask);
131 return all_ones.CommonPrefixLength(all_ones);
132 }
133
134 bool IPAddress::IsIPv4Mapped() const {
135 if (!IsIPv6())
136 return false;
137 return std::equal(ip_address_.begin(),
138 ip_address_.begin() + arraysize(kIPv4MappedPrefix),
139 kIPv4MappedPrefix);
140 }
141
142 AddressFamily IPAddress::GetAddressFamily() const {
143 switch (ip_address_.size()) {
144 case kIPv4AddressSize:
145 return ADDRESS_FAMILY_IPV4;
146 case kIPv6AddressSize:
147 return ADDRESS_FAMILY_IPV6;
148 default:
149 return ADDRESS_FAMILY_UNSPECIFIED;
150 }
151 }
152
153 bool IPAddress::MatchesPrefix(const IPAddress& ip_prefix,
154 size_t prefix_length_in_bits) {
155 // Both the input IP address and the prefix IP address should be
156 // either IPv4 or IPv6.
157 DCHECK(IsIPv4() || IsIPv6());
158 DCHECK(ip_prefix.IsIPv4() || ip_prefix.IsIPv6());
159
160 DCHECK_LE(prefix_length_in_bits, ip_prefix.ip_address_.size() * 8);
161
162 // In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to
163 // IPv6 addresses in order to do the comparison.
164 if (ip_address_.size() != ip_prefix.ip_address_.size()) {
165 if (IsIPv4()) {
166 IPAddress temp = IPAddress::ConvertIPv4ToIPv6(*this);
167 return temp.MatchesPrefix(ip_prefix, prefix_length_in_bits);
168 }
169 IPAddress temp = IPAddress::ConvertIPv4ToIPv6(ip_prefix);
170 return MatchesPrefix(temp, 96 + prefix_length_in_bits);
171 }
172
173 return IPAddressPrefixCheck(&ip_prefix, prefix_length_in_bits);
174 }
175
176 bool IPAddress::ToSockAddrWithPort(struct sockaddr* address,
177 socklen_t* address_length,
178 int port) const {
179 DCHECK(address);
180 DCHECK(address_length);
181 switch (ip_address_.size()) {
182 case kIPv4AddressSize: {
183 socklen_t kSockaddrInSize = sizeof(struct sockaddr_in);
184 if (*address_length < kSockaddrInSize)
185 return false;
186 *address_length = kSockaddrInSize;
187 struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(address);
188 memset(addr, 0, sizeof(struct sockaddr_in));
189 addr->sin_family = AF_INET;
190 addr->sin_port = base::HostToNet16(port);
191 memcpy(&addr->sin_addr, &ip_address_[0], kIPv4AddressSize);
192 break;
193 }
194 case kIPv6AddressSize: {
195 socklen_t kSockaddrInSize = sizeof(struct sockaddr_in6);
196 if (*address_length < kSockaddrInSize)
197 return false;
198 *address_length = kSockaddrInSize;
199 struct sockaddr_in6* addr6 =
200 reinterpret_cast<struct sockaddr_in6*>(address);
201 memset(addr6, 0, sizeof(struct sockaddr_in6));
202 addr6->sin6_family = AF_INET6;
203 addr6->sin6_port = base::HostToNet16(port);
204 memcpy(&addr6->sin6_addr, &ip_address_[0], kIPv6AddressSize);
205 break;
206 }
207 default:
208 return false;
209 }
210 return true;
211 }
212
213 // static
214 bool IPAddress::FromURLHostname(const std::string& hostname,
215 IPAddress* ip_address) {
216 // |hostname| is an already canoncalized hostname, conforming to RFC 3986.
217 // For an IP address, this is defined in Section 3.2.2 of RFC 3986, with
218 // the canonical form for IPv6 addresses defined in Section 4 of RFC 5952.
219 url::Component host_comp(0, hostname.size());
220
221 std::vector<unsigned char> ip;
222
223 // If it has a bracket, try parsing it as an IPv6 address.
224 if (hostname[0] == '[') {
225 ip.resize(16); // 128 bits.
226 bool result =
227 url::IPv6AddressToNumber(hostname.data(), host_comp, &(ip)[0]);
228 ip_address->ip_address_ = ip;
229 return result;
230 }
231
232 // Otherwise, try IPv4.
233 ip.resize(4); // 32 bits.
234 int num_components;
235 url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
236 hostname.data(), host_comp, &(ip)[0], &num_components);
237 ip_address->ip_address_ = ip;
238 return family == url::CanonHostInfo::IPV4;
239 }
240
241 // static
242 bool IPAddress::FromIPLiteral(const base::StringPiece& ip_literal,
243 IPAddress* ip_address) {
244 std::vector<unsigned char> ip;
245
246 // |ip_literal| could be either a IPv4 or an IPv6 literal. If it contains
247 // a colon however, it must be an IPv6 address.
248 if (ip_literal.find(':') != base::StringPiece::npos) {
249 // GURL expects IPv6 hostnames to be surrounded with brackets.
250 std::string host_brackets = "[";
251 ip_literal.AppendToString(&host_brackets);
252 host_brackets.push_back(']');
253 url::Component host_comp(0, host_brackets.size());
254
255 // Try parsing the hostname as an IPv6 literal.
256 ip.resize(16); // 128 bits.
257 bool result =
258 url::IPv6AddressToNumber(host_brackets.data(), host_comp, &(ip)[0]);
259 ip_address->ip_address_ = ip;
260 return result;
261 }
262
263 // Otherwise the string is an IPv4 address.
264 ip.resize(4); // 32 bits.
265 url::Component host_comp(0, ip_literal.size());
266 int num_components;
267 url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
268 ip_literal.data(), host_comp, &(ip)[0], &num_components);
269
270 ip_address->ip_address_ = ip;
271 return family == url::CanonHostInfo::IPV4;
272 }
273
274 // static
275 bool IPAddress::FromCIDRBlock(const std::string& cidr_literal,
276 IPAddress* ip_address,
277 size_t* prefix_length_in_bits) {
278 // We expect CIDR notation to match one of these two templates:
279 // <IPv4-literal> "/" <number of bits>
280 // <IPv6-literal> "/" <number of bits>
281
282 std::vector<base::StringPiece> parts = base::SplitStringPiece(
283 cidr_literal, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
284 if (parts.size() != 2)
285 return false;
286
287 // Parse the IP address.
288 if (!IPAddress::FromIPLiteral(parts[0], ip_address))
289 return false;
290
291 // Parse the prefix length.
292 int number_of_bits = -1;
293 if (!base::StringToInt(parts[1], &number_of_bits))
294 return false;
295
296 // Make sure the prefix length is in a valid range.
297 if (number_of_bits < 0 ||
298 number_of_bits > static_cast<int>(ip_address->ip_address_.size() * 8))
299 return false;
300
301 *prefix_length_in_bits = static_cast<size_t>(number_of_bits);
302 return true;
303 }
304
305 // static
306 IPAddress IPAddress::FromLegacy(const IPAddressNumber& ip_address) {
307 std::vector<unsigned char> address_copy(ip_address);
308 IPAddress new_address(address_copy);
309 return new_address;
310 }
311
312 // static
313 IPAddress IPAddress::ConvertIPv4ToIPv6(const IPAddress& ipv4_address) {
314 DCHECK(ipv4_address.IsIPv4());
315
316 // IPv4-mapped addresses are formed by:
317 // <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
318 std::vector<unsigned char> ipv6_address;
319 ipv6_address.reserve(16);
320 ipv6_address.insert(ipv6_address.end(), kIPv4MappedPrefix,
321 kIPv4MappedPrefix + arraysize(kIPv4MappedPrefix));
322 ipv6_address.insert(ipv6_address.end(), ipv4_address.ip_address_.begin(),
323 ipv4_address.ip_address_.end());
324 return IPAddress(ipv6_address);
325 }
326
327 // static
328 IPAddress IPAddress::ConvertIPv4MappedToIPv4(const IPAddress& address) {
329 DCHECK(address.IsIPv4Mapped());
330 std::vector<unsigned char> without_prefix(
331 address.ip_address_.begin() + arraysize(kIPv4MappedPrefix),
332 address.ip_address_.end());
333 IPAddress ip_address(without_prefix);
334 return ip_address;
335 }
336
337 bool IPAddress::operator==(const IPAddress& that) const {
338 return ip_address_ == that.ip_address_;
339 }
340
341 bool IPAddress::operator!=(const IPAddress& that) const {
342 return ip_address_ != that.ip_address_;
343 }
344
345 bool IPAddress::operator<(const IPAddress& that) const {
346 // Sort IPv4 before IPv6.
347 if (ip_address_.size() != that.ip_address_.size()) {
348 return ip_address_.size() < that.ip_address_.size();
349 }
350
351 return ip_address_ < that.ip_address_;
352 }
353
354 bool IPAddress::operator>(const IPAddress& that) const {
355 // Sort IPv4 after IPv6.
356 if (ip_address_.size() != that.ip_address_.size()) {
357 return ip_address_.size() > that.ip_address_.size();
358 }
359
360 return ip_address_ > that.ip_address_;
361 }
362
363 bool IPAddress::IPAddressPrefixCheck(const IPAddress* ip_prefix,
364 size_t prefix_length_in_bits) const {
365 return IPAddressPrefixCheck(&(ip_prefix->ip_address_)[0],
366 prefix_length_in_bits);
367 }
368
369 bool IPAddress::IPAddressPrefixCheck(const unsigned char* ip_prefix,
370 size_t prefix_length_in_bits) const {
371 // Compare all the bytes that fall entirely within the prefix.
372 int num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
373 for (int i = 0; i < num_entire_bytes_in_prefix; ++i) {
374 if (ip_address_[i] != ip_prefix[i])
375 return false;
376 }
377
378 // In case the prefix was not a multiple of 8, there will be 1 byte
379 // which is only partially masked.
380 int remaining_bits = prefix_length_in_bits % 8;
381 if (remaining_bits != 0) {
382 unsigned char mask = 0xFF << (8 - remaining_bits);
383 int i = num_entire_bytes_in_prefix;
384 if ((ip_address_[i] & mask) != (ip_prefix[i] & mask))
385 return false;
386 }
387 return true;
388 }
389
390 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698