• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
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 <stddef.h>
8 
9 #include <algorithm>
10 #include <array>
11 #include <climits>
12 #include <optional>
13 #include <string_view>
14 
15 #include "base/check_op.h"
16 #include "base/debug/alias.h"
17 #include "base/debug/crash_logging.h"
18 #include "base/logging.h"
19 #include "base/notreached.h"
20 #include "base/ranges/algorithm.h"
21 #include "base/strings/strcat.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/trace_event/memory_usage_estimator.h"
25 #include "base/values.h"
26 #include "net/base/parse_number.h"
27 #include "url/gurl.h"
28 #include "url/url_canon_ip.h"
29 
30 namespace net {
31 namespace {
32 
33 // The prefix for IPv6 mapped IPv4 addresses.
34 // https://tools.ietf.org/html/rfc4291#section-2.5.5.2
35 constexpr uint8_t kIPv4MappedPrefix[] = {0, 0, 0, 0, 0,    0,
36                                          0, 0, 0, 0, 0xFF, 0xFF};
37 
38 // Note that this function assumes:
39 // * |ip_address| is at least |prefix_length_in_bits| (bits) long;
40 // * |ip_prefix| is at least |prefix_length_in_bits| (bits) long.
IPAddressPrefixCheck(const IPAddressBytes & ip_address,const uint8_t * ip_prefix,size_t prefix_length_in_bits)41 bool IPAddressPrefixCheck(const IPAddressBytes& ip_address,
42                           const uint8_t* ip_prefix,
43                           size_t prefix_length_in_bits) {
44   // Compare all the bytes that fall entirely within the prefix.
45   size_t num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
46   for (size_t i = 0; i < num_entire_bytes_in_prefix; ++i) {
47     if (ip_address[i] != ip_prefix[i])
48       return false;
49   }
50 
51   // In case the prefix was not a multiple of 8, there will be 1 byte
52   // which is only partially masked.
53   size_t remaining_bits = prefix_length_in_bits % 8;
54   if (remaining_bits != 0) {
55     uint8_t mask = 0xFF << (8 - remaining_bits);
56     size_t i = num_entire_bytes_in_prefix;
57     if ((ip_address[i] & mask) != (ip_prefix[i] & mask))
58       return false;
59   }
60   return true;
61 }
62 
63 // Returns false if |ip_address| matches any of the reserved IPv4 ranges. This
64 // method operates on a list of reserved IPv4 ranges. Some ranges are
65 // consolidated.
66 // Sources for info:
67 // www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml
68 // www.iana.org/assignments/iana-ipv4-special-registry/
69 // iana-ipv4-special-registry.xhtml
IsPubliclyRoutableIPv4(const IPAddressBytes & ip_address)70 bool IsPubliclyRoutableIPv4(const IPAddressBytes& ip_address) {
71   // Different IP versions have different range reservations.
72   DCHECK_EQ(IPAddress::kIPv4AddressSize, ip_address.size());
73   struct {
74     const uint8_t address[4];
75     size_t prefix_length_in_bits;
76   } static const kReservedIPv4Ranges[] = {
77       {{0, 0, 0, 0}, 8},      {{10, 0, 0, 0}, 8},     {{100, 64, 0, 0}, 10},
78       {{127, 0, 0, 0}, 8},    {{169, 254, 0, 0}, 16}, {{172, 16, 0, 0}, 12},
79       {{192, 0, 0, 0}, 24},   {{192, 0, 2, 0}, 24},   {{192, 88, 99, 0}, 24},
80       {{192, 168, 0, 0}, 16}, {{198, 18, 0, 0}, 15},  {{198, 51, 100, 0}, 24},
81       {{203, 0, 113, 0}, 24}, {{224, 0, 0, 0}, 3}};
82 
83   for (const auto& range : kReservedIPv4Ranges) {
84     if (IPAddressPrefixCheck(ip_address, range.address,
85                              range.prefix_length_in_bits)) {
86       return false;
87     }
88   }
89 
90   return true;
91 }
92 
93 // Returns false if |ip_address| matches any of the IPv6 ranges IANA reserved
94 // for local networks. This method operates on an allowlist of non-reserved
95 // IPv6 ranges, plus the list of reserved IPv4 ranges mapped to IPv6.
96 // Sources for info:
97 // www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
IsPubliclyRoutableIPv6(const IPAddressBytes & ip_address)98 bool IsPubliclyRoutableIPv6(const IPAddressBytes& ip_address) {
99   DCHECK_EQ(IPAddress::kIPv6AddressSize, ip_address.size());
100   struct {
101     const uint8_t address_prefix[2];
102     size_t prefix_length_in_bits;
103   } static const kPublicIPv6Ranges[] = {// 2000::/3  -- Global Unicast
104                                         {{0x20, 0}, 3},
105                                         // ff00::/8  -- Multicast
106                                         {{0xff, 0}, 8}};
107 
108   for (const auto& range : kPublicIPv6Ranges) {
109     if (IPAddressPrefixCheck(ip_address, range.address_prefix,
110                              range.prefix_length_in_bits)) {
111       return true;
112     }
113   }
114 
115   IPAddress addr(ip_address);
116   if (addr.IsIPv4MappedIPv6()) {
117     IPAddress ipv4 = ConvertIPv4MappedIPv6ToIPv4(addr);
118     return IsPubliclyRoutableIPv4(ipv4.bytes());
119   }
120 
121   return false;
122 }
123 
ParseIPLiteralToBytes(std::string_view ip_literal,IPAddressBytes * bytes)124 bool ParseIPLiteralToBytes(std::string_view ip_literal, IPAddressBytes* bytes) {
125   // |ip_literal| could be either an IPv4 or an IPv6 literal. If it contains
126   // a colon however, it must be an IPv6 address.
127   if (ip_literal.find(':') != std::string_view::npos) {
128     // GURL expects IPv6 hostnames to be surrounded with brackets.
129     std::string host_brackets = base::StrCat({"[", ip_literal, "]"});
130     url::Component host_comp(0, host_brackets.size());
131 
132     // Try parsing the hostname as an IPv6 literal.
133     bytes->Resize(16);  // 128 bits.
134     return url::IPv6AddressToNumber(host_brackets.data(), host_comp,
135                                     bytes->data());
136   }
137 
138   // Otherwise the string is an IPv4 address.
139   bytes->Resize(4);  // 32 bits.
140   url::Component host_comp(0, ip_literal.size());
141   int num_components;
142   url::CanonHostInfo::Family family = url::IPv4AddressToNumber(
143       ip_literal.data(), host_comp, bytes->data(), &num_components);
144   return family == url::CanonHostInfo::IPV4;
145 }
146 
147 }  // namespace
148 
IPAddressBytes()149 IPAddressBytes::IPAddressBytes() : size_(0) {}
150 
IPAddressBytes(const uint8_t * data,size_t data_len)151 IPAddressBytes::IPAddressBytes(const uint8_t* data, size_t data_len) {
152   Assign(data, data_len);
153 }
154 
155 IPAddressBytes::~IPAddressBytes() = default;
156 IPAddressBytes::IPAddressBytes(IPAddressBytes const& other) = default;
157 
Assign(const uint8_t * data,size_t data_len)158 void IPAddressBytes::Assign(const uint8_t* data, size_t data_len) {
159   size_ = data_len;
160   CHECK_GE(16u, data_len);
161   std::copy_n(data, data_len, bytes_.data());
162 }
163 
operator <(const IPAddressBytes & other) const164 bool IPAddressBytes::operator<(const IPAddressBytes& other) const {
165   if (size_ == other.size_)
166     return std::lexicographical_compare(begin(), end(), other.begin(),
167                                         other.end());
168   return size_ < other.size_;
169 }
170 
operator ==(const IPAddressBytes & other) const171 bool IPAddressBytes::operator==(const IPAddressBytes& other) const {
172   return base::ranges::equal(*this, other);
173 }
174 
operator !=(const IPAddressBytes & other) const175 bool IPAddressBytes::operator!=(const IPAddressBytes& other) const {
176   return !(*this == other);
177 }
178 
Append(const uint8_t * first,const uint8_t * last)179 void IPAddressBytes::Append(const uint8_t* first, const uint8_t* last) {
180   CHECK_LE(first, last);
181   const ptrdiff_t bytes_to_append = last - first;
182   CHECK_LE(bytes_to_append, 16);
183   // Now we know `bytes_to_append` is between 0 and 16 and `size_` is between 0
184   // and 255 so their sum must fit inside a ptrdiff_t type.
185   CHECK_LE(ptrdiff_t{size_} + bytes_to_append, 16);
186   std::copy(first, last, bytes_.data() + size_);
187   size_ += bytes_to_append;
188 }
189 
EstimateMemoryUsage() const190 size_t IPAddressBytes::EstimateMemoryUsage() const {
191   return base::trace_event::EstimateMemoryUsage(bytes_);
192 }
193 
194 // static
FromValue(const base::Value & value)195 std::optional<IPAddress> IPAddress::FromValue(const base::Value& value) {
196   if (!value.is_string()) {
197     return std::nullopt;
198   }
199 
200   return IPAddress::FromIPLiteral(value.GetString());
201 }
202 
203 // static
FromIPLiteral(std::string_view ip_literal)204 std::optional<IPAddress> IPAddress::FromIPLiteral(std::string_view ip_literal) {
205   IPAddress address;
206   if (!address.AssignFromIPLiteral(ip_literal)) {
207     return std::nullopt;
208   }
209   DCHECK(address.IsValid());
210   return address;
211 }
212 
213 IPAddress::IPAddress() = default;
214 
215 IPAddress::IPAddress(const IPAddress& other) = default;
216 
IPAddress(const IPAddressBytes & address)217 IPAddress::IPAddress(const IPAddressBytes& address) : ip_address_(address) {}
218 
IPAddress(const uint8_t * address,size_t address_len)219 IPAddress::IPAddress(const uint8_t* address, size_t address_len)
220     : ip_address_(address, address_len) {}
221 
IPAddress(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3)222 IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
223   const uint8_t bytes[] = {b0, b1, b2, b3};
224   ip_address_.Assign(bytes, std::size(bytes));
225 }
226 
IPAddress(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint8_t b5,uint8_t b6,uint8_t b7,uint8_t b8,uint8_t b9,uint8_t b10,uint8_t b11,uint8_t b12,uint8_t b13,uint8_t b14,uint8_t b15)227 IPAddress::IPAddress(uint8_t b0,
228                      uint8_t b1,
229                      uint8_t b2,
230                      uint8_t b3,
231                      uint8_t b4,
232                      uint8_t b5,
233                      uint8_t b6,
234                      uint8_t b7,
235                      uint8_t b8,
236                      uint8_t b9,
237                      uint8_t b10,
238                      uint8_t b11,
239                      uint8_t b12,
240                      uint8_t b13,
241                      uint8_t b14,
242                      uint8_t b15) {
243   const uint8_t bytes[] = {b0, b1, b2,  b3,  b4,  b5,  b6,  b7,
244                            b8, b9, b10, b11, b12, b13, b14, b15};
245   ip_address_.Assign(bytes, std::size(bytes));
246 }
247 
248 IPAddress::~IPAddress() = default;
249 
IsIPv4() const250 bool IPAddress::IsIPv4() const {
251   return ip_address_.size() == kIPv4AddressSize;
252 }
253 
IsIPv6() const254 bool IPAddress::IsIPv6() const {
255   return ip_address_.size() == kIPv6AddressSize;
256 }
257 
IsValid() const258 bool IPAddress::IsValid() const {
259   return IsIPv4() || IsIPv6();
260 }
261 
IsPubliclyRoutable() const262 bool IPAddress::IsPubliclyRoutable() const {
263   if (IsIPv4()) {
264     return IsPubliclyRoutableIPv4(ip_address_);
265   } else if (IsIPv6()) {
266     return IsPubliclyRoutableIPv6(ip_address_);
267   }
268   return true;
269 }
270 
IsZero() const271 bool IPAddress::IsZero() const {
272   for (auto x : ip_address_) {
273     if (x != 0)
274       return false;
275   }
276 
277   return !empty();
278 }
279 
IsIPv4MappedIPv6() const280 bool IPAddress::IsIPv4MappedIPv6() const {
281   return IsIPv6() && IPAddressStartsWith(*this, kIPv4MappedPrefix);
282 }
283 
IsLoopback() const284 bool IPAddress::IsLoopback() const {
285   // 127.0.0.1/8
286   if (IsIPv4())
287     return ip_address_[0] == 127;
288 
289   // ::1
290   if (IsIPv6()) {
291     for (size_t i = 0; i + 1 < ip_address_.size(); ++i) {
292       if (ip_address_[i] != 0)
293         return false;
294     }
295     return ip_address_.back() == 1;
296   }
297 
298   return false;
299 }
300 
IsLinkLocal() const301 bool IPAddress::IsLinkLocal() const {
302   // 169.254.0.0/16
303   if (IsIPv4())
304     return (ip_address_[0] == 169) && (ip_address_[1] == 254);
305 
306   // [::ffff:169.254.0.0]/112
307   if (IsIPv4MappedIPv6())
308     return (ip_address_[12] == 169) && (ip_address_[13] == 254);
309 
310   // [fe80::]/10
311   if (IsIPv6())
312     return (ip_address_[0] == 0xFE) && ((ip_address_[1] & 0xC0) == 0x80);
313 
314   return false;
315 }
316 
IsUniqueLocalIPv6() const317 bool IPAddress::IsUniqueLocalIPv6() const {
318   // [fc00::]/7
319   return IsIPv6() && ((ip_address_[0] & 0xFE) == 0xFC);
320 }
321 
AssignFromIPLiteral(std::string_view ip_literal)322 bool IPAddress::AssignFromIPLiteral(std::string_view ip_literal) {
323   bool success = ParseIPLiteralToBytes(ip_literal, &ip_address_);
324   if (!success)
325     ip_address_.Resize(0);
326   return success;
327 }
328 
CopyBytesToVector() const329 std::vector<uint8_t> IPAddress::CopyBytesToVector() const {
330   return std::vector<uint8_t>(ip_address_.begin(), ip_address_.end());
331 }
332 
333 // static
IPv4Localhost()334 IPAddress IPAddress::IPv4Localhost() {
335   static const uint8_t kLocalhostIPv4[] = {127, 0, 0, 1};
336   return IPAddress(kLocalhostIPv4);
337 }
338 
339 // static
IPv6Localhost()340 IPAddress IPAddress::IPv6Localhost() {
341   static const uint8_t kLocalhostIPv6[] = {0, 0, 0, 0, 0, 0, 0, 0,
342                                            0, 0, 0, 0, 0, 0, 0, 1};
343   return IPAddress(kLocalhostIPv6);
344 }
345 
346 // static
AllZeros(size_t num_zero_bytes)347 IPAddress IPAddress::AllZeros(size_t num_zero_bytes) {
348   CHECK_LE(num_zero_bytes, 16u);
349   IPAddress result;
350   for (size_t i = 0; i < num_zero_bytes; ++i)
351     result.ip_address_.push_back(0u);
352   return result;
353 }
354 
355 // static
IPv4AllZeros()356 IPAddress IPAddress::IPv4AllZeros() {
357   return AllZeros(kIPv4AddressSize);
358 }
359 
360 // static
IPv6AllZeros()361 IPAddress IPAddress::IPv6AllZeros() {
362   return AllZeros(kIPv6AddressSize);
363 }
364 
operator ==(const IPAddress & that) const365 bool IPAddress::operator==(const IPAddress& that) const {
366   return ip_address_ == that.ip_address_;
367 }
368 
operator !=(const IPAddress & that) const369 bool IPAddress::operator!=(const IPAddress& that) const {
370   return ip_address_ != that.ip_address_;
371 }
372 
operator <(const IPAddress & that) const373 bool IPAddress::operator<(const IPAddress& that) const {
374   // Sort IPv4 before IPv6.
375   if (ip_address_.size() != that.ip_address_.size()) {
376     return ip_address_.size() < that.ip_address_.size();
377   }
378 
379   return ip_address_ < that.ip_address_;
380 }
381 
ToString() const382 std::string IPAddress::ToString() const {
383   std::string str;
384   url::StdStringCanonOutput output(&str);
385 
386   if (IsIPv4()) {
387     url::AppendIPv4Address(ip_address_.data(), &output);
388   } else if (IsIPv6()) {
389     url::AppendIPv6Address(ip_address_.data(), &output);
390   }
391 
392   output.Complete();
393   return str;
394 }
395 
ToValue() const396 base::Value IPAddress::ToValue() const {
397   DCHECK(IsValid());
398   return base::Value(ToString());
399 }
400 
EstimateMemoryUsage() const401 size_t IPAddress::EstimateMemoryUsage() const {
402   return base::trace_event::EstimateMemoryUsage(ip_address_);
403 }
404 
IPAddressToStringWithPort(const IPAddress & address,uint16_t port)405 std::string IPAddressToStringWithPort(const IPAddress& address, uint16_t port) {
406   std::string address_str = address.ToString();
407   if (address_str.empty())
408     return address_str;
409 
410   if (address.IsIPv6()) {
411     // Need to bracket IPv6 addresses since they contain colons.
412     return base::StringPrintf("[%s]:%d", address_str.c_str(), port);
413   }
414   return base::StringPrintf("%s:%d", address_str.c_str(), port);
415 }
416 
IPAddressToPackedString(const IPAddress & address)417 std::string IPAddressToPackedString(const IPAddress& address) {
418   return std::string(reinterpret_cast<const char*>(address.bytes().data()),
419                      address.size());
420 }
421 
ConvertIPv4ToIPv4MappedIPv6(const IPAddress & address)422 IPAddress ConvertIPv4ToIPv4MappedIPv6(const IPAddress& address) {
423   CHECK(address.IsIPv4());
424   // IPv4-mapped addresses are formed by:
425   // <80 bits of zeros>  + <16 bits of ones> + <32-bit IPv4 address>.
426   IPAddressBytes bytes;
427   bytes.Append(std::begin(kIPv4MappedPrefix), std::end(kIPv4MappedPrefix));
428   bytes.Append(address.bytes().begin(), address.bytes().end());
429   return IPAddress(bytes);
430 }
431 
ConvertIPv4MappedIPv6ToIPv4(const IPAddress & address)432 IPAddress ConvertIPv4MappedIPv6ToIPv4(const IPAddress& address) {
433   DCHECK(address.IsIPv4MappedIPv6());
434 
435   IPAddressBytes bytes;
436   bytes.Append(address.bytes().begin() + std::size(kIPv4MappedPrefix),
437                address.bytes().end());
438   return IPAddress(bytes);
439 }
440 
IPAddressMatchesPrefix(const IPAddress & ip_address,const IPAddress & ip_prefix,size_t prefix_length_in_bits)441 bool IPAddressMatchesPrefix(const IPAddress& ip_address,
442                             const IPAddress& ip_prefix,
443                             size_t prefix_length_in_bits) {
444   // Both the input IP address and the prefix IP address should be either IPv4
445   // or IPv6.
446   CHECK(ip_address.IsValid());
447   CHECK(ip_prefix.IsValid());
448 
449   CHECK_LE(prefix_length_in_bits, ip_prefix.size() * 8);
450 
451   // In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to
452   // IPv6 addresses in order to do the comparison.
453   if (ip_address.size() != ip_prefix.size()) {
454     if (ip_address.IsIPv4()) {
455       return IPAddressMatchesPrefix(ConvertIPv4ToIPv4MappedIPv6(ip_address),
456                                     ip_prefix, prefix_length_in_bits);
457     }
458     return IPAddressMatchesPrefix(ip_address,
459                                   ConvertIPv4ToIPv4MappedIPv6(ip_prefix),
460                                   96 + prefix_length_in_bits);
461   }
462 
463   return IPAddressPrefixCheck(ip_address.bytes(), ip_prefix.bytes().data(),
464                               prefix_length_in_bits);
465 }
466 
ParseCIDRBlock(std::string_view cidr_literal,IPAddress * ip_address,size_t * prefix_length_in_bits)467 bool ParseCIDRBlock(std::string_view cidr_literal,
468                     IPAddress* ip_address,
469                     size_t* prefix_length_in_bits) {
470   // We expect CIDR notation to match one of these two templates:
471   //   <IPv4-literal> "/" <number of bits>
472   //   <IPv6-literal> "/" <number of bits>
473 
474   std::vector<std::string_view> parts = base::SplitStringPiece(
475       cidr_literal, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
476   if (parts.size() != 2)
477     return false;
478 
479   // Parse the IP address.
480   if (!ip_address->AssignFromIPLiteral(parts[0]))
481     return false;
482 
483   // Parse the prefix length.
484   uint32_t number_of_bits;
485   if (!ParseUint32(parts[1], ParseIntFormat::NON_NEGATIVE, &number_of_bits)) {
486     return false;
487   }
488 
489   // Make sure the prefix length is in a valid range.
490   if (number_of_bits > ip_address->size() * 8)
491     return false;
492 
493   *prefix_length_in_bits = number_of_bits;
494   return true;
495 }
496 
ParseURLHostnameToAddress(std::string_view hostname,IPAddress * ip_address)497 bool ParseURLHostnameToAddress(std::string_view hostname,
498                                IPAddress* ip_address) {
499   if (hostname.size() >= 2 && hostname.front() == '[' &&
500       hostname.back() == ']') {
501     // Strip the square brackets that surround IPv6 literals.
502     auto ip_literal = std::string_view(hostname).substr(1, hostname.size() - 2);
503     return ip_address->AssignFromIPLiteral(ip_literal) && ip_address->IsIPv6();
504   }
505 
506   return ip_address->AssignFromIPLiteral(hostname) && ip_address->IsIPv4();
507 }
508 
CommonPrefixLength(const IPAddress & a1,const IPAddress & a2)509 size_t CommonPrefixLength(const IPAddress& a1, const IPAddress& a2) {
510   DCHECK_EQ(a1.size(), a2.size());
511   for (size_t i = 0; i < a1.size(); ++i) {
512     unsigned diff = a1.bytes()[i] ^ a2.bytes()[i];
513     if (!diff)
514       continue;
515     for (unsigned j = 0; j < CHAR_BIT; ++j) {
516       if (diff & (1 << (CHAR_BIT - 1)))
517         return i * CHAR_BIT + j;
518       diff <<= 1;
519     }
520     NOTREACHED();
521   }
522   return a1.size() * CHAR_BIT;
523 }
524 
MaskPrefixLength(const IPAddress & mask)525 size_t MaskPrefixLength(const IPAddress& mask) {
526   IPAddressBytes all_ones;
527   all_ones.Resize(mask.size());
528   std::fill(all_ones.begin(), all_ones.end(), 0xFF);
529   return CommonPrefixLength(mask, IPAddress(all_ones));
530 }
531 
ExtractPref64FromIpv4onlyArpaAAAA(const IPAddress & address)532 Dns64PrefixLength ExtractPref64FromIpv4onlyArpaAAAA(const IPAddress& address) {
533   DCHECK(address.IsIPv6());
534   IPAddress ipv4onlyarpa0(192, 0, 0, 170);
535   IPAddress ipv4onlyarpa1(192, 0, 0, 171);
536   if (std::equal(ipv4onlyarpa0.bytes().begin(), ipv4onlyarpa0.bytes().end(),
537                  address.bytes().begin() + 12u) ||
538       std::equal(ipv4onlyarpa1.bytes().begin(), ipv4onlyarpa1.bytes().end(),
539                  address.bytes().begin() + 12u)) {
540     return Dns64PrefixLength::k96bit;
541   } else if (std::equal(ipv4onlyarpa0.bytes().begin(),
542                         ipv4onlyarpa0.bytes().end(),
543                         address.bytes().begin() + 9u) ||
544              std::equal(ipv4onlyarpa1.bytes().begin(),
545                         ipv4onlyarpa1.bytes().end(),
546                         address.bytes().begin() + 9u)) {
547     return Dns64PrefixLength::k64bit;
548   } else if ((std::equal(ipv4onlyarpa0.bytes().begin(),
549                          ipv4onlyarpa0.bytes().begin() + 1u,
550                          address.bytes().begin() + 7u) &&
551               std::equal(ipv4onlyarpa0.bytes().begin() + 1u,
552                          ipv4onlyarpa0.bytes().end(),
553                          address.bytes().begin() + 9u)) ||
554              (std::equal(ipv4onlyarpa1.bytes().begin(),
555                          ipv4onlyarpa1.bytes().begin() + 1u,
556                          address.bytes().begin() + 7u) &&
557               std::equal(ipv4onlyarpa1.bytes().begin() + 1u,
558                          ipv4onlyarpa1.bytes().end(),
559                          address.bytes().begin() + 9u))) {
560     return Dns64PrefixLength::k56bit;
561   } else if ((std::equal(ipv4onlyarpa0.bytes().begin(),
562                          ipv4onlyarpa0.bytes().begin() + 2u,
563                          address.bytes().begin() + 6u) &&
564               std::equal(ipv4onlyarpa0.bytes().begin() + 2u,
565                          ipv4onlyarpa0.bytes().end(),
566                          address.bytes().begin() + 9u)) ||
567              ((std::equal(ipv4onlyarpa1.bytes().begin(),
568                           ipv4onlyarpa1.bytes().begin() + 2u,
569                           address.bytes().begin() + 6u) &&
570                std::equal(ipv4onlyarpa1.bytes().begin() + 2u,
571                           ipv4onlyarpa1.bytes().end(),
572                           address.bytes().begin() + 9u)))) {
573     return Dns64PrefixLength::k48bit;
574   } else if ((std::equal(ipv4onlyarpa0.bytes().begin(),
575                          ipv4onlyarpa0.bytes().begin() + 3u,
576                          address.bytes().begin() + 5u) &&
577               std::equal(ipv4onlyarpa0.bytes().begin() + 3u,
578                          ipv4onlyarpa0.bytes().end(),
579                          address.bytes().begin() + 9u)) ||
580              (std::equal(ipv4onlyarpa1.bytes().begin(),
581                          ipv4onlyarpa1.bytes().begin() + 3u,
582                          address.bytes().begin() + 5u) &&
583               std::equal(ipv4onlyarpa1.bytes().begin() + 3u,
584                          ipv4onlyarpa1.bytes().end(),
585                          address.bytes().begin() + 9u))) {
586     return Dns64PrefixLength::k40bit;
587   } else if (std::equal(ipv4onlyarpa0.bytes().begin(),
588                         ipv4onlyarpa0.bytes().end(),
589                         address.bytes().begin() + 4u) ||
590              std::equal(ipv4onlyarpa1.bytes().begin(),
591                         ipv4onlyarpa1.bytes().end(),
592                         address.bytes().begin() + 4u)) {
593     return Dns64PrefixLength::k32bit;
594   } else {
595     // if ipv4onlyarpa address is not found return 0
596     return Dns64PrefixLength::kInvalid;
597   }
598 }
599 
ConvertIPv4ToIPv4EmbeddedIPv6(const IPAddress & ipv4_address,const IPAddress & ipv6_address,Dns64PrefixLength prefix_length)600 IPAddress ConvertIPv4ToIPv4EmbeddedIPv6(const IPAddress& ipv4_address,
601                                         const IPAddress& ipv6_address,
602                                         Dns64PrefixLength prefix_length) {
603   DCHECK(ipv4_address.IsIPv4());
604   DCHECK(ipv6_address.IsIPv6());
605 
606   IPAddressBytes bytes;
607 
608   constexpr uint8_t kZeroBits[8] = {0x00, 0x00, 0x00, 0x00,
609                                     0x00, 0x00, 0x00, 0x00};
610 
611   switch (prefix_length) {
612     case Dns64PrefixLength::k96bit:
613       bytes.Append(ipv6_address.bytes().begin(),
614                    ipv6_address.bytes().begin() + 12u);
615       bytes.Append(ipv4_address.bytes().begin(), ipv4_address.bytes().end());
616       return IPAddress(bytes);
617     case Dns64PrefixLength::k64bit:
618       bytes.Append(ipv6_address.bytes().begin(),
619                    ipv6_address.bytes().begin() + 8u);
620       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 1u);
621       bytes.Append(ipv4_address.bytes().begin(), ipv4_address.bytes().end());
622       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 3u);
623       return IPAddress(bytes);
624     case Dns64PrefixLength::k56bit:
625       bytes.Append(ipv6_address.bytes().begin(),
626                    ipv6_address.bytes().begin() + 7u);
627       bytes.Append(ipv4_address.bytes().begin(),
628                    ipv4_address.bytes().begin() + 1u);
629       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 1u);
630       bytes.Append(ipv4_address.bytes().begin() + 1u,
631                    ipv4_address.bytes().end());
632       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 4u);
633       return IPAddress(bytes);
634     case Dns64PrefixLength::k48bit:
635       bytes.Append(ipv6_address.bytes().begin(),
636                    ipv6_address.bytes().begin() + 6u);
637       bytes.Append(ipv4_address.bytes().begin(),
638                    ipv4_address.bytes().begin() + 2u);
639       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 1u);
640       bytes.Append(ipv4_address.bytes().begin() + 2u,
641                    ipv4_address.bytes().end());
642       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 5u);
643       return IPAddress(bytes);
644     case Dns64PrefixLength::k40bit:
645       bytes.Append(ipv6_address.bytes().begin(),
646                    ipv6_address.bytes().begin() + 5u);
647       bytes.Append(ipv4_address.bytes().begin(),
648                    ipv4_address.bytes().begin() + 3u);
649       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 1u);
650       bytes.Append(ipv4_address.bytes().begin() + 3u,
651                    ipv4_address.bytes().end());
652       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 6u);
653       return IPAddress(bytes);
654     case Dns64PrefixLength::k32bit:
655       bytes.Append(ipv6_address.bytes().begin(),
656                    ipv6_address.bytes().begin() + 4u);
657       bytes.Append(ipv4_address.bytes().begin(), ipv4_address.bytes().end());
658       bytes.Append(std::begin(kZeroBits), std::begin(kZeroBits) + 8u);
659       return IPAddress(bytes);
660     case Dns64PrefixLength::kInvalid:
661       return ipv4_address;
662   }
663 }
664 
665 }  // namespace net
666