xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/platform/ip_range.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 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 "quiche/quic/qbone/platform/ip_range.h"
6 
7 #include "quiche/common/quiche_endian.h"
8 
9 namespace quic {
10 
11 namespace {
12 
13 constexpr size_t kIPv4Size = 32;
14 constexpr size_t kIPv6Size = 128;
15 
TruncateToLength(const QuicIpAddress & input,size_t * prefix_length)16 QuicIpAddress TruncateToLength(const QuicIpAddress& input,
17                                size_t* prefix_length) {
18   QuicIpAddress output;
19   if (input.IsIPv4()) {
20     if (*prefix_length > kIPv4Size) {
21       *prefix_length = kIPv4Size;
22       return input;
23     }
24     uint32_t raw_address =
25         *reinterpret_cast<const uint32_t*>(input.ToPackedString().data());
26     raw_address = quiche::QuicheEndian::NetToHost32(raw_address);
27     raw_address &= ~0U << (kIPv4Size - *prefix_length);
28     raw_address = quiche::QuicheEndian::HostToNet32(raw_address);
29     output.FromPackedString(reinterpret_cast<const char*>(&raw_address),
30                             sizeof(raw_address));
31     return output;
32   }
33   if (input.IsIPv6()) {
34     if (*prefix_length > kIPv6Size) {
35       *prefix_length = kIPv6Size;
36       return input;
37     }
38     uint64_t raw_address[2];
39     memcpy(raw_address, input.ToPackedString().data(), sizeof(raw_address));
40     // raw_address[0] holds higher 8 bytes in big endian and raw_address[1]
41     // holds lower 8 bytes. Converting each to little endian for us to mask bits
42     // out.
43     // The endianess between raw_address[0] and raw_address[1] is handled
44     // explicitly by handling lower and higher bytes separately.
45     raw_address[0] = quiche::QuicheEndian::NetToHost64(raw_address[0]);
46     raw_address[1] = quiche::QuicheEndian::NetToHost64(raw_address[1]);
47     if (*prefix_length <= kIPv6Size / 2) {
48       raw_address[0] &= ~uint64_t{0} << (kIPv6Size / 2 - *prefix_length);
49       raw_address[1] = 0;
50     } else {
51       raw_address[1] &= ~uint64_t{0} << (kIPv6Size - *prefix_length);
52     }
53     raw_address[0] = quiche::QuicheEndian::HostToNet64(raw_address[0]);
54     raw_address[1] = quiche::QuicheEndian::HostToNet64(raw_address[1]);
55     output.FromPackedString(reinterpret_cast<const char*>(raw_address),
56                             sizeof(raw_address));
57     return output;
58   }
59   return output;
60 }
61 
62 }  // namespace
63 
IpRange(const QuicIpAddress & prefix,size_t prefix_length)64 IpRange::IpRange(const QuicIpAddress& prefix, size_t prefix_length)
65     : prefix_(prefix), prefix_length_(prefix_length) {
66   prefix_ = TruncateToLength(prefix_, &prefix_length_);
67 }
68 
operator ==(IpRange other) const69 bool IpRange::operator==(IpRange other) const {
70   return prefix_ == other.prefix_ && prefix_length_ == other.prefix_length_;
71 }
72 
operator !=(IpRange other) const73 bool IpRange::operator!=(IpRange other) const { return !(*this == other); }
74 
FromString(const std::string & range)75 bool IpRange::FromString(const std::string& range) {
76   size_t slash_pos = range.find('/');
77   if (slash_pos == std::string::npos) {
78     return false;
79   }
80   QuicIpAddress prefix;
81   bool success = prefix.FromString(range.substr(0, slash_pos));
82   if (!success) {
83     return false;
84   }
85   uint64_t num_processed = 0;
86   size_t prefix_length = std::stoi(range.substr(slash_pos + 1), &num_processed);
87   if (num_processed + 1 + slash_pos != range.length()) {
88     return false;
89   }
90   prefix_ = TruncateToLength(prefix, &prefix_length);
91   prefix_length_ = prefix_length;
92   return true;
93 }
94 
FirstAddressInRange() const95 QuicIpAddress IpRange::FirstAddressInRange() const { return prefix(); }
96 
97 }  // namespace quic
98