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