summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/qbone/platform/ip_range.cc
blob: 97df5cff0523ba615b0a401975422d4de2e8a19b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// 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