blob: 97df5cff0523ba615b0a401975422d4de2e8a19b [file] [log] [blame]
// 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