| // Copyright (c) 2019 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "quic/qbone/platform/ip_range.h" | 
 |  | 
 | #include "common/quiche_endian.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr size_t kIPv4Size = 32; | 
 | constexpr size_t kIPv6Size = 128; | 
 |  | 
 | QuicIpAddress TruncateToLength(const QuicIpAddress& input, | 
 |                                size_t* prefix_length) { | 
 |   QuicIpAddress output; | 
 |   if (input.IsIPv4()) { | 
 |     if (*prefix_length > kIPv4Size) { | 
 |       *prefix_length = kIPv4Size; | 
 |       return input; | 
 |     } | 
 |     uint32_t raw_address = | 
 |         *reinterpret_cast<const uint32_t*>(input.ToPackedString().data()); | 
 |     raw_address = quiche::QuicheEndian::NetToHost32(raw_address); | 
 |     raw_address &= ~0U << (kIPv4Size - *prefix_length); | 
 |     raw_address = quiche::QuicheEndian::HostToNet32(raw_address); | 
 |     output.FromPackedString(reinterpret_cast<const char*>(&raw_address), | 
 |                             sizeof(raw_address)); | 
 |     return output; | 
 |   } | 
 |   if (input.IsIPv6()) { | 
 |     if (*prefix_length > kIPv6Size) { | 
 |       *prefix_length = kIPv6Size; | 
 |       return input; | 
 |     } | 
 |     uint64_t raw_address[2]; | 
 |     memcpy(raw_address, input.ToPackedString().data(), sizeof(raw_address)); | 
 |     // raw_address[0] holds higher 8 bytes in big endian and raw_address[1] | 
 |     // holds lower 8 bytes. Converting each to little endian for us to mask bits | 
 |     // out. | 
 |     // The endianess between raw_address[0] and raw_address[1] is handled | 
 |     // explicitly by handling lower and higher bytes separately. | 
 |     raw_address[0] = quiche::QuicheEndian::NetToHost64(raw_address[0]); | 
 |     raw_address[1] = quiche::QuicheEndian::NetToHost64(raw_address[1]); | 
 |     if (*prefix_length <= kIPv6Size / 2) { | 
 |       raw_address[0] &= ~uint64_t{0} << (kIPv6Size / 2 - *prefix_length); | 
 |       raw_address[1] = 0; | 
 |     } else { | 
 |       raw_address[1] &= ~uint64_t{0} << (kIPv6Size - *prefix_length); | 
 |     } | 
 |     raw_address[0] = quiche::QuicheEndian::HostToNet64(raw_address[0]); | 
 |     raw_address[1] = quiche::QuicheEndian::HostToNet64(raw_address[1]); | 
 |     output.FromPackedString(reinterpret_cast<const char*>(raw_address), | 
 |                             sizeof(raw_address)); | 
 |     return output; | 
 |   } | 
 |   return output; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | IpRange::IpRange(const QuicIpAddress& prefix, size_t prefix_length) | 
 |     : prefix_(prefix), prefix_length_(prefix_length) { | 
 |   prefix_ = TruncateToLength(prefix_, &prefix_length_); | 
 | } | 
 |  | 
 | bool IpRange::operator==(IpRange other) const { | 
 |   return prefix_ == other.prefix_ && prefix_length_ == other.prefix_length_; | 
 | } | 
 |  | 
 | bool IpRange::operator!=(IpRange other) const { | 
 |   return !(*this == other); | 
 | } | 
 |  | 
 | bool IpRange::FromString(const std::string& range) { | 
 |   size_t slash_pos = range.find('/'); | 
 |   if (slash_pos == std::string::npos) { | 
 |     return false; | 
 |   } | 
 |   QuicIpAddress prefix; | 
 |   bool success = prefix.FromString(range.substr(0, slash_pos)); | 
 |   if (!success) { | 
 |     return false; | 
 |   } | 
 |   uint64_t num_processed = 0; | 
 |   size_t prefix_length = std::stoi(range.substr(slash_pos + 1), &num_processed); | 
 |   if (num_processed + 1 + slash_pos != range.length()) { | 
 |     return false; | 
 |   } | 
 |   prefix_ = TruncateToLength(prefix, &prefix_length); | 
 |   prefix_length_ = prefix_length; | 
 |   return true; | 
 | } | 
 |  | 
 | QuicIpAddress IpRange::FirstAddressInRange() const { | 
 |   return prefix(); | 
 | } | 
 |  | 
 | }  // namespace quic |