339 lines
9.8 KiB
C++
339 lines
9.8 KiB
C++
/*
|
|
* Copyright (c) 2017, Matias Fontanini
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#ifndef TINS_ADDRESS_RANGE
|
|
#define TINS_ADDRESS_RANGE
|
|
|
|
#include <iterator>
|
|
#include <tins/endianness.h>
|
|
#include <tins/exceptions.h>
|
|
#include <tins/detail/address_helpers.h>
|
|
|
|
namespace Tins {
|
|
/**
|
|
* \brief AddressRange iterator class.
|
|
*/
|
|
template<typename Address>
|
|
class AddressRangeIterator {
|
|
public:
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef const Address value_type;
|
|
typedef std::ptrdiff_t difference_type;
|
|
typedef const Address* pointer;
|
|
typedef const Address& reference;
|
|
|
|
struct end_iterator {
|
|
|
|
};
|
|
|
|
/**
|
|
* Constructs an iterator.
|
|
*
|
|
* \param first The address held by this iterator.
|
|
*/
|
|
AddressRangeIterator(const value_type& address)
|
|
: address_(address), reached_end_(false) {
|
|
|
|
}
|
|
|
|
/**
|
|
* Constructs an iterator.
|
|
*
|
|
* \param first The address held by this iterator.
|
|
*/
|
|
AddressRangeIterator(const value_type& address, end_iterator)
|
|
: address_(address) {
|
|
reached_end_ = Internals::increment(address_);
|
|
}
|
|
|
|
/**
|
|
* Retrieves the current address pointed by this iterator.
|
|
*/
|
|
const value_type& operator*() const {
|
|
return address_;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a pointer to the current address pointed by this iterator.
|
|
*/
|
|
const value_type* operator->() const {
|
|
return& address_;
|
|
}
|
|
|
|
/**
|
|
* Compares two iterators for equality.
|
|
*
|
|
* \param rhs The iterator with which to compare.
|
|
*/
|
|
bool operator==(const AddressRangeIterator& rhs) const {
|
|
return reached_end_ == rhs.reached_end_ && address_ == rhs.address_;
|
|
}
|
|
|
|
/**
|
|
* Compares two iterators for inequality.
|
|
*
|
|
* \param rhs The iterator with which to compare.
|
|
*/
|
|
bool operator!=(const AddressRangeIterator& rhs) const {
|
|
return !(*this == rhs);
|
|
}
|
|
|
|
/**
|
|
* Increments this iterator.
|
|
*/
|
|
AddressRangeIterator& operator++() {
|
|
reached_end_ = Internals::increment(address_);
|
|
return* this;
|
|
}
|
|
|
|
/**
|
|
* Increments this iterator.
|
|
*/
|
|
AddressRangeIterator operator++(int) {
|
|
AddressRangeIterator copy(*this);
|
|
(*this)++;
|
|
return copy;
|
|
}
|
|
private:
|
|
Address address_;
|
|
bool reached_end_;
|
|
};
|
|
|
|
/**
|
|
* \brief Represents a range of addresses.
|
|
*
|
|
* This class provides a begin()/end() interface which allows
|
|
* iterating through every address stored in it.
|
|
*
|
|
* Note that when iterating a range that was created using
|
|
* operator/(IPv4Address, int) and the analog for IPv6, the
|
|
* network and broadcast addresses are discarded:
|
|
*
|
|
* \code
|
|
* auto range = IPv4Address("192.168.5.0") / 24;
|
|
* for(const auto& addr : range) {
|
|
* // process 192.168.5.1-254, .0 and .255 are discarded
|
|
* process(addr);
|
|
* }
|
|
*
|
|
* // That's only valid for iteration, not for AddressRange<>::contains
|
|
*
|
|
* assert(range.contains("192.168.5.0")); // works
|
|
* assert(range.contains("192.168.5.255")); // works
|
|
* \endcode
|
|
*
|
|
* Ranges created using AddressRange(address_type, address_type)
|
|
* will allow the iteration over the entire range:
|
|
*
|
|
* \code
|
|
* AddressRange<IPv4Address> range("192.168.5.0", "192.168.5.255");
|
|
* for(const auto& addr : range) {
|
|
* // process 192.168.5.0-255, no addresses are discarded
|
|
* process(addr);
|
|
* }
|
|
*
|
|
* assert(range.contains("192.168.5.0")); // still valid
|
|
* assert(range.contains("192.168.5.255")); // still valid
|
|
* \endcode
|
|
*
|
|
*/
|
|
template<typename Address>
|
|
class AddressRange {
|
|
public:
|
|
/**
|
|
* The type of addresses stored in the range.
|
|
*/
|
|
typedef Address address_type;
|
|
|
|
/**
|
|
* The iterator type.
|
|
*/
|
|
typedef AddressRangeIterator<address_type> const_iterator;
|
|
|
|
/**
|
|
* \brief The iterator type.
|
|
*
|
|
* This is the same type as const_iterator, since the
|
|
* addresses stored in this range are read only.
|
|
*/
|
|
typedef const_iterator iterator;
|
|
|
|
/**
|
|
* \brief Constructs an address range from two addresses.
|
|
*
|
|
* The range will consist of the addresses [first, last].
|
|
*
|
|
* If only_hosts is true, then the network and broadcast addresses
|
|
* will not be available when iterating the range.
|
|
*
|
|
* If last < first, an std::runtime_error exception is thrown.
|
|
*
|
|
* \param first The first address in the range.
|
|
* \param last The last address(inclusive) in the range.
|
|
* \param only_hosts Indicates whether only host addresses
|
|
* should be accessed when using iterators.
|
|
*/
|
|
AddressRange(const address_type& first, const address_type& last, bool only_hosts = false)
|
|
: first_(first), last_(last), only_hosts_(only_hosts){
|
|
if (last_ < first_) {
|
|
throw exception_base("Invalid address range");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Creates an address range from a base address
|
|
* and a network mask.
|
|
*
|
|
* \param first The base address.
|
|
* \param mask The network mask to be used.
|
|
*/
|
|
static AddressRange from_mask(const address_type& first, const address_type& mask) {
|
|
return AddressRange<address_type>(
|
|
first & mask,
|
|
Internals::last_address_from_mask(first, mask),
|
|
true
|
|
);
|
|
}
|
|
|
|
/**
|
|
* \brief Indicates whether an address is included in this range.
|
|
* \param addr The address to test.
|
|
* \return a bool indicating whether the address is in the range.
|
|
*/
|
|
bool contains(const address_type& addr) const {
|
|
return (first_ < addr && addr < last_) || addr == first_ || addr == last_;
|
|
}
|
|
|
|
/**
|
|
* \brief Returns an interator to the beginning of this range.
|
|
* \brief const_iterator pointing to the beginning of this range.
|
|
*/
|
|
const_iterator begin() const {
|
|
address_type addr = first_;
|
|
if (only_hosts_) {
|
|
Internals::increment(addr);
|
|
}
|
|
return const_iterator(addr);
|
|
}
|
|
|
|
/**
|
|
* \brief Returns an interator to the end of this range.
|
|
* \brief const_iterator pointing to the end of this range.
|
|
*/
|
|
const_iterator end() const {
|
|
address_type addr = last_;
|
|
if (only_hosts_) {
|
|
Internals::decrement(addr);
|
|
}
|
|
return const_iterator(addr, typename const_iterator::end_iterator());
|
|
}
|
|
|
|
/**
|
|
* \brief Indicates whether this range is iterable.
|
|
*
|
|
* Iterable ranges are those for which there is at least one
|
|
* address that could represent a host. For IPv4 ranges, a /31 or
|
|
* /32 ranges does not contain any, therefore it's not iterable.
|
|
* The same is true for /127 and /128 IPv6 ranges.
|
|
*
|
|
* If is_iterable returns false for a range, then iterating it
|
|
* through the iterators returned by begin() and end() is
|
|
* undefined.
|
|
*
|
|
* \return bool indicating whether this range is iterable.
|
|
*/
|
|
bool is_iterable() const {
|
|
// Since first < last, it's iterable
|
|
if (!only_hosts_) {
|
|
return true;
|
|
}
|
|
// We need that distance(first, last) >= 4
|
|
address_type addr(first_);
|
|
for (int i = 0; i < 3; ++i) {
|
|
// If there's overflow before the last iteration, we're done
|
|
if (Internals::increment(addr) && i != 2) {
|
|
return false;
|
|
}
|
|
}
|
|
// If addr <= last, it's OK.
|
|
return addr < last_ || addr == last_;
|
|
}
|
|
private:
|
|
address_type first_, last_;
|
|
bool only_hosts_;
|
|
};
|
|
|
|
/**
|
|
* An IPv4 address range.
|
|
*/
|
|
typedef AddressRange<IPv4Address> IPv4Range;
|
|
|
|
/**
|
|
* An IPv6 address range.
|
|
*/
|
|
typedef AddressRange<IPv6Address> IPv6Range;
|
|
|
|
/**
|
|
* \brief Constructs an AddressRange from a base address and a mask.
|
|
* \param addr The range's first address.
|
|
* \param mask The bit-length of the prefix.
|
|
*/
|
|
template<size_t n>
|
|
AddressRange<HWAddress<n> > operator/(const HWAddress<n>& addr, int mask) {
|
|
if (mask > 48) {
|
|
throw std::logic_error("Prefix length cannot exceed 48");
|
|
}
|
|
HWAddress<n> last_addr;
|
|
typename HWAddress<n>::iterator it = last_addr.begin();
|
|
while (mask > 8) {
|
|
*it = 0xff;
|
|
++it;
|
|
mask -= 8;
|
|
}
|
|
*it = 0xff << (8 - mask);
|
|
return AddressRange<HWAddress<6> >::from_mask(addr, last_addr);
|
|
}
|
|
|
|
/**
|
|
* \brief Constructs an IPv6Range from a base IPv6Address and a mask.
|
|
* \param addr The range's first address.
|
|
* \param mask The bit-length of the prefix.
|
|
*/
|
|
IPv6Range operator/(const IPv6Address& addr, int mask);
|
|
|
|
/**
|
|
* \brief Constructs an IPv4Range from a base IPv4Address and a mask.
|
|
* \param addr The range's first address.
|
|
* \param mask The bit-length of the prefix.
|
|
*/
|
|
IPv4Range operator/(const IPv4Address& addr, int mask);
|
|
} // namespace Tins
|
|
|
|
#endif // TINS_ADDRESS_RANGE
|