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

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

Issue 2881673002: Avoid heap allocations in IPAddress (Closed)
Patch Set: Address comments 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 memcpy(bytes_.data(), data, data_len);
eroman 2017/05/15 22:15:23 If you want to avoid relying on undefined behavior
Ryan Hamilton 2017/05/17 18:26:41 Done.
141 }
142
143 net::IPAddress::IPAddressBytes::~IPAddressBytes() {}
144 net::IPAddress::IPAddressBytes::IPAddressBytes(
145 net::IPAddress::IPAddressBytes const& other) = default;
146
147 bool operator<(const IPAddress::IPAddressBytes& lhs,
148 const IPAddress::IPAddressBytes& rhs) {
149 if (lhs.size_ < rhs.size_)
150 return true;
151 if (lhs.size_ > rhs.size_)
152 return false;
153 for (size_t i = 0; i < lhs.size_; ++i) {
154 if (lhs.bytes_[i] < rhs.bytes_[i])
155 return true;
156 }
157 return false;
158 }
159
160 bool operator>(const IPAddress::IPAddressBytes& lhs,
161 const IPAddress::IPAddressBytes& rhs) {
162 if (lhs.size_ > rhs.size_)
163 return true;
164 if (lhs.size_ < rhs.size_)
165 return false;
166 for (size_t i = 0; i < lhs.size_; ++i) {
167 if (lhs.bytes_[i] > rhs.bytes_[i])
168 return true;
169 }
170 return false;
171 }
172
173 bool operator==(const IPAddress::IPAddressBytes& lhs,
174 const IPAddress::IPAddressBytes& rhs) {
175 if (lhs.size_ != rhs.size_)
176 return false;
177 for (size_t i = 0; i < lhs.size_; ++i) {
178 if (lhs.bytes_[i] != rhs.bytes_[i])
179 return false;
180 }
181 return true;
182 }
183
184 bool operator!=(const IPAddress::IPAddressBytes& lhs,
185 const IPAddress::IPAddressBytes& rhs) {
186 return !(lhs == rhs);
187 }
188
135 IPAddress::IPAddress() {} 189 IPAddress::IPAddress() {}
136 190
137 IPAddress::IPAddress(const std::vector<uint8_t>& address) 191 IPAddress::IPAddress(const std::vector<uint8_t>& address)
138 : ip_address_(address) {} 192 : ip_address_(address.data(), address.size()) {}
139 193
140 IPAddress::IPAddress(const IPAddress& other) = default; 194 IPAddress::IPAddress(const IPAddress& other) = default;
141 195
142 IPAddress::IPAddress(const uint8_t* address, size_t address_len) 196 IPAddress::IPAddress(const uint8_t* address, size_t address_len)
143 : ip_address_(address, address + address_len) {} 197 : ip_address_(address, address_len) {}
144 198
145 IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) { 199 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); 200 ip_address_.push_back(b0);
148 ip_address_.push_back(b1); 201 ip_address_.push_back(b1);
149 ip_address_.push_back(b2); 202 ip_address_.push_back(b2);
150 ip_address_.push_back(b3); 203 ip_address_.push_back(b3);
151 } 204 }
152 205
153 IPAddress::IPAddress(uint8_t b0, 206 IPAddress::IPAddress(uint8_t b0,
154 uint8_t b1, 207 uint8_t b1,
155 uint8_t b2, 208 uint8_t b2,
156 uint8_t b3, 209 uint8_t b3,
157 uint8_t b4, 210 uint8_t b4,
158 uint8_t b5, 211 uint8_t b5,
159 uint8_t b6, 212 uint8_t b6,
160 uint8_t b7, 213 uint8_t b7,
161 uint8_t b8, 214 uint8_t b8,
162 uint8_t b9, 215 uint8_t b9,
163 uint8_t b10, 216 uint8_t b10,
164 uint8_t b11, 217 uint8_t b11,
165 uint8_t b12, 218 uint8_t b12,
166 uint8_t b13, 219 uint8_t b13,
167 uint8_t b14, 220 uint8_t b14,
168 uint8_t b15) { 221 uint8_t b15) {
169 const uint8_t address[] = {b0, b1, b2, b3, b4, b5, b6, b7, 222 ip_address_.push_back(b0);
170 b8, b9, b10, b11, b12, b13, b14, b15}; 223 ip_address_.push_back(b1);
171 ip_address_ = std::vector<uint8_t>(std::begin(address), std::end(address)); 224 ip_address_.push_back(b2);
225 ip_address_.push_back(b3);
226 ip_address_.push_back(b4);
227 ip_address_.push_back(b5);
228 ip_address_.push_back(b6);
229 ip_address_.push_back(b7);
230 ip_address_.push_back(b8);
231 ip_address_.push_back(b9);
232 ip_address_.push_back(b10);
233 ip_address_.push_back(b11);
234 ip_address_.push_back(b12);
235 ip_address_.push_back(b13);
236 ip_address_.push_back(b14);
237 ip_address_.push_back(b15);
172 } 238 }
173 239
174 IPAddress::~IPAddress() {} 240 IPAddress::~IPAddress() {}
175 241
176 bool IPAddress::IsIPv4() const { 242 bool IPAddress::IsIPv4() const {
177 return ip_address_.size() == kIPv4AddressSize; 243 return ip_address_.size() == kIPv4AddressSize;
178 } 244 }
179 245
180 bool IPAddress::IsIPv6() const { 246 bool IPAddress::IsIPv6() const {
181 return ip_address_.size() == kIPv6AddressSize; 247 return ip_address_.size() == kIPv6AddressSize;
(...skipping 19 matching lines...) Expand all
201 } 267 }
202 268
203 return !empty(); 269 return !empty();
204 } 270 }
205 271
206 bool IPAddress::IsIPv4MappedIPv6() const { 272 bool IPAddress::IsIPv4MappedIPv6() const {
207 return IsIPv6() && IPAddressStartsWith(*this, kIPv4MappedPrefix); 273 return IsIPv6() && IPAddressStartsWith(*this, kIPv4MappedPrefix);
208 } 274 }
209 275
210 bool IPAddress::AssignFromIPLiteral(const base::StringPiece& ip_literal) { 276 bool IPAddress::AssignFromIPLiteral(const base::StringPiece& ip_literal) {
211 std::vector<uint8_t> number; 277 IPAddressBytes number;
212 278
279 // TODO(rch): change the contract so ip_address_ is cleared on failure,
280 // to avoid needing this temporary at all.
213 if (!ParseIPLiteralToBytes(ip_literal, &number)) 281 if (!ParseIPLiteralToBytes(ip_literal, &number))
214 return false; 282 return false;
215 283
216 std::swap(number, ip_address_); 284 ip_address_ = number;
217 return true; 285 return true;
218 } 286 }
219 287
288 std::vector<uint8_t> IPAddress::BytesAsVector() const {
289 return std::vector<uint8_t>(ip_address_.begin(), ip_address_.end());
290 }
291
220 // static 292 // static
221 IPAddress IPAddress::IPv4Localhost() { 293 IPAddress IPAddress::IPv4Localhost() {
222 static const uint8_t kLocalhostIPv4[] = {127, 0, 0, 1}; 294 static const uint8_t kLocalhostIPv4[] = {127, 0, 0, 1};
223 return IPAddress(kLocalhostIPv4); 295 return IPAddress(kLocalhostIPv4);
224 } 296 }
225 297
226 // static 298 // static
227 IPAddress IPAddress::IPv6Localhost() { 299 IPAddress IPAddress::IPv6Localhost() {
228 static const uint8_t kLocalhostIPv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 300 static const uint8_t kLocalhostIPv6[] = {0, 0, 0, 0, 0, 0, 0, 0,
229 0, 0, 0, 0, 0, 0, 0, 1}; 301 0, 0, 0, 0, 0, 0, 0, 1};
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 } 468 }
397 return a1.size() * CHAR_BIT; 469 return a1.size() * CHAR_BIT;
398 } 470 }
399 471
400 unsigned MaskPrefixLength(const IPAddress& mask) { 472 unsigned MaskPrefixLength(const IPAddress& mask) {
401 std::vector<uint8_t> all_ones(mask.size(), 0xFF); 473 std::vector<uint8_t> all_ones(mask.size(), 0xFF);
402 return CommonPrefixLength(mask, IPAddress(all_ones)); 474 return CommonPrefixLength(mask, IPAddress(all_ones));
403 } 475 }
404 476
405 } // namespace net 477 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698