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

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

Issue 2881673002: Avoid heap allocations in IPAddress (Closed)
Patch Set: DCHECK Created 3 years, 7 months 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
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 <limits.h> 7 #include <limits.h>
8 8
9 #include "base/strings/string_piece.h" 9 #include "base/strings/string_piece.h"
10 #include "base/strings/string_split.h" 10 #include "base/strings/string_split.h"
11 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
12 #include "net/base/parse_number.h" 12 #include "net/base/parse_number.h"
13 #include "url/gurl.h" 13 #include "url/gurl.h"
14 #include "url/url_canon_ip.h" 14 #include "url/url_canon_ip.h"
15 15
16 namespace { 16 namespace {
17 17
18 // The prefix for IPv6 mapped IPv4 addresses. 18 // The prefix for IPv6 mapped IPv4 addresses.
19 // https://tools.ietf.org/html/rfc4291#section-2.5.5.2 19 // https://tools.ietf.org/html/rfc4291#section-2.5.5.2
20 const uint8_t kIPv4MappedPrefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF}; 20 const uint8_t kIPv4MappedPrefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF};
21 21
22 // Note that this function assumes: 22 // Note that this function assumes:
23 // * |ip_address| is at least |prefix_length_in_bits| (bits) long; 23 // * |ip_address| is at least |prefix_length_in_bits| (bits) long;
24 // * |ip_prefix| is at least |prefix_length_in_bits| (bits) long. 24 // * |ip_prefix| is at least |prefix_length_in_bits| (bits) long.
25 bool IPAddressPrefixCheck(const std::vector<uint8_t>& ip_address, 25 bool IPAddressPrefixCheck(const net::IPAddress::IPAddressBytes& ip_address,
26 const uint8_t* ip_prefix, 26 const uint8_t* ip_prefix,
27 size_t prefix_length_in_bits) { 27 size_t prefix_length_in_bits) {
28 // Compare all the bytes that fall entirely within the prefix. 28 // Compare all the bytes that fall entirely within the prefix.
29 size_t num_entire_bytes_in_prefix = prefix_length_in_bits / 8; 29 size_t num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
30 for (size_t i = 0; i < num_entire_bytes_in_prefix; ++i) { 30 for (size_t i = 0; i < num_entire_bytes_in_prefix; ++i) {
31 if (ip_address[i] != ip_prefix[i]) 31 if (ip_address[i] != ip_prefix[i])
32 return false; 32 return false;
33 } 33 }
34 34
35 // In case the prefix was not a multiple of 8, there will be 1 byte 35 // In case the prefix was not a multiple of 8, there will be 1 byte
36 // which is only partially masked. 36 // which is only partially masked.
37 size_t remaining_bits = prefix_length_in_bits % 8; 37 size_t remaining_bits = prefix_length_in_bits % 8;
38 if (remaining_bits != 0) { 38 if (remaining_bits != 0) {
39 uint8_t mask = 0xFF << (8 - remaining_bits); 39 uint8_t mask = 0xFF << (8 - remaining_bits);
40 size_t i = num_entire_bytes_in_prefix; 40 size_t i = num_entire_bytes_in_prefix;
41 if ((ip_address[i] & mask) != (ip_prefix[i] & mask)) 41 if ((ip_address[i] & mask) != (ip_prefix[i] & mask))
42 return false; 42 return false;
43 } 43 }
44 return true; 44 return true;
45 } 45 }
46 46
47 // Returns true if |ip_address| matches any of the reserved IPv4 ranges. This 47 // Returns true if |ip_address| matches any of the reserved IPv4 ranges. This
48 // method operates on a blacklist of reserved IPv4 ranges. Some ranges are 48 // method operates on a blacklist of reserved IPv4 ranges. Some ranges are
49 // consolidated. 49 // consolidated.
50 // Sources for info: 50 // Sources for info:
51 // www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml 51 // www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml
52 // www.iana.org/assignments/iana-ipv4-special-registry/ 52 // www.iana.org/assignments/iana-ipv4-special-registry/
53 // iana-ipv4-special-registry.xhtml 53 // iana-ipv4-special-registry.xhtml
54 bool IsReservedIPv4(const std::vector<uint8_t>& ip_address) { 54 bool IsReservedIPv4(const net::IPAddress::IPAddressBytes& ip_address) {
55 // Different IP versions have different range reservations. 55 // Different IP versions have different range reservations.
56 DCHECK_EQ(net::IPAddress::kIPv4AddressSize, ip_address.size()); 56 DCHECK_EQ(net::IPAddress::kIPv4AddressSize, ip_address.size());
57 struct { 57 struct {
58 const uint8_t address[4]; 58 const uint8_t address[4];
59 size_t prefix_length_in_bits; 59 size_t prefix_length_in_bits;
60 } static const kReservedIPv4Ranges[] = { 60 } static const kReservedIPv4Ranges[] = {
61 {{0, 0, 0, 0}, 8}, {{10, 0, 0, 0}, 8}, {{100, 64, 0, 0}, 10}, 61 {{0, 0, 0, 0}, 8}, {{10, 0, 0, 0}, 8}, {{100, 64, 0, 0}, 10},
62 {{127, 0, 0, 0}, 8}, {{169, 254, 0, 0}, 16}, {{172, 16, 0, 0}, 12}, 62 {{127, 0, 0, 0}, 8}, {{169, 254, 0, 0}, 16}, {{172, 16, 0, 0}, 12},
63 {{192, 0, 2, 0}, 24}, {{192, 88, 99, 0}, 24}, {{192, 168, 0, 0}, 16}, 63 {{192, 0, 2, 0}, 24}, {{192, 88, 99, 0}, 24}, {{192, 168, 0, 0}, 16},
64 {{198, 18, 0, 0}, 15}, {{198, 51, 100, 0}, 24}, {{203, 0, 113, 0}, 24}, 64 {{198, 18, 0, 0}, 15}, {{198, 51, 100, 0}, 24}, {{203, 0, 113, 0}, 24},
65 {{224, 0, 0, 0}, 3}}; 65 {{224, 0, 0, 0}, 3}};
66 66
67 for (const auto& range : kReservedIPv4Ranges) { 67 for (const auto& range : kReservedIPv4Ranges) {
68 if (IPAddressPrefixCheck(ip_address, range.address, 68 if (IPAddressPrefixCheck(ip_address, range.address,
69 range.prefix_length_in_bits)) { 69 range.prefix_length_in_bits)) {
70 return true; 70 return true;
71 } 71 }
72 } 72 }
73 73
74 return false; 74 return false;
75 } 75 }
76 76
77 // Returns true if |ip_address| matches any of the reserved IPv6 ranges. This 77 // Returns true if |ip_address| matches any of the reserved IPv6 ranges. This
78 // method operates on a whitelist of non-reserved IPv6 ranges. All IPv6 78 // method operates on a whitelist of non-reserved IPv6 ranges. All IPv6
79 // addresses outside these ranges are reserved. 79 // addresses outside these ranges are reserved.
80 // Sources for info: 80 // Sources for info:
81 // www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml 81 // www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
82 bool IsReservedIPv6(const std::vector<uint8_t>& ip_address) { 82 bool IsReservedIPv6(const net::IPAddress::IPAddressBytes& ip_address) {
83 // Different IP versions have different range reservations. 83 // Different IP versions have different range reservations.
84 DCHECK_EQ(net::IPAddress::kIPv6AddressSize, ip_address.size()); 84 DCHECK_EQ(net::IPAddress::kIPv6AddressSize, ip_address.size());
85 struct { 85 struct {
86 const uint8_t address_prefix[2]; 86 const uint8_t address_prefix[2];
87 size_t prefix_length_in_bits; 87 size_t prefix_length_in_bits;
88 } static const kPublicIPv6Ranges[] = { 88 } static const kPublicIPv6Ranges[] = {
89 // 2000::/3 -- Global Unicast 89 // 2000::/3 -- Global Unicast
90 {{0x20, 0}, 3}, 90 {{0x20, 0}, 3},
91 // ff00::/8 -- Multicast 91 // ff00::/8 -- Multicast
92 {{0xff, 0}, 8}, 92 {{0xff, 0}, 8},
93 }; 93 };
94 94
95 for (const auto& range : kPublicIPv6Ranges) { 95 for (const auto& range : kPublicIPv6Ranges) {
96 if (IPAddressPrefixCheck(ip_address, range.address_prefix, 96 if (IPAddressPrefixCheck(ip_address, range.address_prefix,
97 range.prefix_length_in_bits)) { 97 range.prefix_length_in_bits)) {
98 return false; 98 return false;
99 } 99 }
100 } 100 }
101 101
102 return true; 102 return true;
103 } 103 }
104 104
105 bool ParseIPLiteralToBytes(const base::StringPiece& ip_literal, 105 bool ParseIPLiteralToBytes(const base::StringPiece& ip_literal,
106 std::vector<uint8_t>* bytes) { 106 net::IPAddress::IPAddressBytes* bytes) {
107 // |ip_literal| could be either an IPv4 or an IPv6 literal. If it contains 107 // |ip_literal| could be either an IPv4 or an IPv6 literal. If it contains
108 // a colon however, it must be an IPv6 address. 108 // a colon however, it must be an IPv6 address.
109 if (ip_literal.find(':') != base::StringPiece::npos) { 109 if (ip_literal.find(':') != base::StringPiece::npos) {
110 // GURL expects IPv6 hostnames to be surrounded with brackets. 110 // GURL expects IPv6 hostnames to be surrounded with brackets.
111 std::string host_brackets = "["; 111 std::string host_brackets = "[";
112 ip_literal.AppendToString(&host_brackets); 112 ip_literal.AppendToString(&host_brackets);
113 host_brackets.push_back(']'); 113 host_brackets.push_back(']');
114 url::Component host_comp(0, host_brackets.size()); 114 url::Component host_comp(0, host_brackets.size());
115 115
116 // Try parsing the hostname as an IPv6 literal. 116 // Try parsing the hostname as an IPv6 literal.
117 bytes->resize(16); // 128 bits. 117 bytes->resize(16); // 128 bits.
118 return url::IPv6AddressToNumber(host_brackets.data(), host_comp, 118 return url::IPv6AddressToNumber(host_brackets.data(), host_comp,
119 bytes->data()); 119 bytes->data());
120 } 120 }
121 121
122 // Otherwise the string is an IPv4 address. 122 // Otherwise the string is an IPv4 address.
123 bytes->resize(4); // 32 bits. 123 bytes->resize(4); // 32 bits.
124 url::Component host_comp(0, ip_literal.size()); 124 url::Component host_comp(0, ip_literal.size());
125 int num_components; 125 int num_components;
126 url::CanonHostInfo::Family family = url::IPv4AddressToNumber( 126 url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
127 ip_literal.data(), host_comp, bytes->data(), &num_components); 127 ip_literal.data(), host_comp, bytes->data(), &num_components);
128 return family == url::CanonHostInfo::IPV4; 128 return family == url::CanonHostInfo::IPV4;
129 } 129 }
130 130
131 } // namespace 131 } // namespace
132 132
133 namespace net { 133 namespace net {
134 134
135 IPAddress::IPAddressBytes::IPAddressBytes() : size_(0) {}
136
137 IPAddress::IPAddressBytes::IPAddressBytes(const uint8_t* data, size_t data_len)
138 : size_(data_len) {
139 CHECK_GE(16u, data_len);
140 if (data_len > 0)
141 memcpy(bytes_.data(), data, data_len);
142 }
143
144 net::IPAddress::IPAddressBytes::~IPAddressBytes() {}
145 net::IPAddress::IPAddressBytes::IPAddressBytes(
146 net::IPAddress::IPAddressBytes const& other) = default;
147
148 bool operator<(const IPAddress::IPAddressBytes& lhs,
149 const IPAddress::IPAddressBytes& rhs) {
150 if (lhs.size_ < rhs.size_)
151 return true;
152 if (lhs.size_ > rhs.size_)
153 return false;
154 for (size_t i = 0; i < lhs.size_; ++i) {
155 if (lhs.bytes_[i] < rhs.bytes_[i])
156 return true;
157 }
158 return false;
159 }
160
161 bool operator>(const IPAddress::IPAddressBytes& lhs,
162 const IPAddress::IPAddressBytes& rhs) {
163 if (lhs.size_ > rhs.size_)
164 return true;
165 if (lhs.size_ < rhs.size_)
166 return false;
167 for (size_t i = 0; i < lhs.size_; ++i) {
168 if (lhs.bytes_[i] > rhs.bytes_[i])
169 return true;
170 }
171 return false;
172 }
173
174 bool operator==(const IPAddress::IPAddressBytes& lhs,
175 const IPAddress::IPAddressBytes& rhs) {
176 if (lhs.size_ != rhs.size_)
177 return false;
178 for (size_t i = 0; i < lhs.size_; ++i) {
179 if (lhs.bytes_[i] != rhs.bytes_[i])
180 return false;
181 }
182 return true;
183 }
184
185 bool operator!=(const IPAddress::IPAddressBytes& lhs,
186 const IPAddress::IPAddressBytes& rhs) {
187 return !(lhs == rhs);
188 }
189
135 IPAddress::IPAddress() {} 190 IPAddress::IPAddress() {}
136 191
137 IPAddress::IPAddress(const std::vector<uint8_t>& address) 192 IPAddress::IPAddress(const std::vector<uint8_t>& address)
138 : ip_address_(address) {} 193 : ip_address_(address.data(), address.size()) {}
139 194
140 IPAddress::IPAddress(const IPAddress& other) = default; 195 IPAddress::IPAddress(const IPAddress& other) = default;
141 196
142 IPAddress::IPAddress(const uint8_t* address, size_t address_len) 197 IPAddress::IPAddress(const uint8_t* address, size_t address_len)
143 : ip_address_(address, address + address_len) {} 198 : ip_address_(address, address_len) {}
144 199
145 IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) { 200 IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
146 ip_address_.reserve(4);
147 ip_address_.push_back(b0); 201 ip_address_.push_back(b0);
148 ip_address_.push_back(b1); 202 ip_address_.push_back(b1);
149 ip_address_.push_back(b2); 203 ip_address_.push_back(b2);
150 ip_address_.push_back(b3); 204 ip_address_.push_back(b3);
151 } 205 }
152 206
153 IPAddress::IPAddress(uint8_t b0, 207 IPAddress::IPAddress(uint8_t b0,
154 uint8_t b1, 208 uint8_t b1,
155 uint8_t b2, 209 uint8_t b2,
156 uint8_t b3, 210 uint8_t b3,
157 uint8_t b4, 211 uint8_t b4,
158 uint8_t b5, 212 uint8_t b5,
159 uint8_t b6, 213 uint8_t b6,
160 uint8_t b7, 214 uint8_t b7,
161 uint8_t b8, 215 uint8_t b8,
162 uint8_t b9, 216 uint8_t b9,
163 uint8_t b10, 217 uint8_t b10,
164 uint8_t b11, 218 uint8_t b11,
165 uint8_t b12, 219 uint8_t b12,
166 uint8_t b13, 220 uint8_t b13,
167 uint8_t b14, 221 uint8_t b14,
168 uint8_t b15) { 222 uint8_t b15) {
169 const uint8_t address[] = {b0, b1, b2, b3, b4, b5, b6, b7, 223 ip_address_.push_back(b0);
170 b8, b9, b10, b11, b12, b13, b14, b15}; 224 ip_address_.push_back(b1);
171 ip_address_ = std::vector<uint8_t>(std::begin(address), std::end(address)); 225 ip_address_.push_back(b2);
226 ip_address_.push_back(b3);
227 ip_address_.push_back(b4);
228 ip_address_.push_back(b5);
229 ip_address_.push_back(b6);
230 ip_address_.push_back(b7);
231 ip_address_.push_back(b8);
232 ip_address_.push_back(b9);
233 ip_address_.push_back(b10);
234 ip_address_.push_back(b11);
235 ip_address_.push_back(b12);
236 ip_address_.push_back(b13);
237 ip_address_.push_back(b14);
238 ip_address_.push_back(b15);
172 } 239 }
173 240
174 IPAddress::~IPAddress() {} 241 IPAddress::~IPAddress() {}
175 242
176 bool IPAddress::IsIPv4() const { 243 bool IPAddress::IsIPv4() const {
177 return ip_address_.size() == kIPv4AddressSize; 244 return ip_address_.size() == kIPv4AddressSize;
178 } 245 }
179 246
180 bool IPAddress::IsIPv6() const { 247 bool IPAddress::IsIPv6() const {
181 return ip_address_.size() == kIPv6AddressSize; 248 return ip_address_.size() == kIPv6AddressSize;
(...skipping 19 matching lines...) Expand all
201 } 268 }
202 269
203 return !empty(); 270 return !empty();
204 } 271 }
205 272
206 bool IPAddress::IsIPv4MappedIPv6() const { 273 bool IPAddress::IsIPv4MappedIPv6() const {
207 return IsIPv6() && IPAddressStartsWith(*this, kIPv4MappedPrefix); 274 return IsIPv6() && IPAddressStartsWith(*this, kIPv4MappedPrefix);
208 } 275 }
209 276
210 bool IPAddress::AssignFromIPLiteral(const base::StringPiece& ip_literal) { 277 bool IPAddress::AssignFromIPLiteral(const base::StringPiece& ip_literal) {
211 std::vector<uint8_t> number; 278 IPAddressBytes number;
212 279
280 // TODO(rch): change the contract so ip_address_ is cleared on failure,
281 // to avoid needing this temporary at all.
213 if (!ParseIPLiteralToBytes(ip_literal, &number)) 282 if (!ParseIPLiteralToBytes(ip_literal, &number))
214 return false; 283 return false;
215 284
216 std::swap(number, ip_address_); 285 ip_address_ = number;
217 return true; 286 return true;
218 } 287 }
219 288
289 std::vector<uint8_t> IPAddress::BytesAsVector() const {
290 return std::vector<uint8_t>(ip_address_.begin(), ip_address_.end());
291 }
292
220 // static 293 // static
221 IPAddress IPAddress::IPv4Localhost() { 294 IPAddress IPAddress::IPv4Localhost() {
222 static const uint8_t kLocalhostIPv4[] = {127, 0, 0, 1}; 295 static const uint8_t kLocalhostIPv4[] = {127, 0, 0, 1};
223 return IPAddress(kLocalhostIPv4); 296 return IPAddress(kLocalhostIPv4);
224 } 297 }
225 298
226 // static 299 // static
227 IPAddress IPAddress::IPv6Localhost() { 300 IPAddress IPAddress::IPv6Localhost() {
228 static const uint8_t kLocalhostIPv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 301 static const uint8_t kLocalhostIPv6[] = {0, 0, 0, 0, 0, 0, 0, 0,
229 0, 0, 0, 0, 0, 0, 0, 1}; 302 0, 0, 0, 0, 0, 0, 0, 1};
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 } 469 }
397 return a1.size() * CHAR_BIT; 470 return a1.size() * CHAR_BIT;
398 } 471 }
399 472
400 unsigned MaskPrefixLength(const IPAddress& mask) { 473 unsigned MaskPrefixLength(const IPAddress& mask) {
401 std::vector<uint8_t> all_ones(mask.size(), 0xFF); 474 std::vector<uint8_t> all_ones(mask.size(), 0xFF);
402 return CommonPrefixLength(mask, IPAddress(all_ones)); 475 return CommonPrefixLength(mask, IPAddress(all_ones));
403 } 476 }
404 477
405 } // namespace net 478 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698