Skip to content

Commit

Permalink
Added AddressRange class template.
Browse files Browse the repository at this point in the history
  • Loading branch information
mfontanini committed Jul 6, 2013
1 parent f385e4e commit 3b34947
Show file tree
Hide file tree
Showing 12 changed files with 598 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ libtins_HEADERS = include/internals.h \
include/cxxstd.h \
include/stp.h \
include/exceptions.h \
include/config.h
include/config.h \
include/address_range.h

libtins_dot11_HEADERS = include/dot11/dot11_base.h \
include/dot11/dot11_beacon.h \
Expand Down
3 changes: 2 additions & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ libtins_HEADERS = include/internals.h \
include/cxxstd.h \
include/stp.h \
include/exceptions.h \
include/config.h
include/config.h \
include/address_range.h

libtins_dot11_HEADERS = include/dot11/dot11_base.h \
include/dot11/dot11_beacon.h \
Expand Down
299 changes: 299 additions & 0 deletions include/address_range.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
/*
* Copyright (c) 2012, 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 <stdexcept>
#include <iterator>
#include "ip_address.h"
#include "ipv6_address.h"
#include "endianness.h"
#include "internals.h"

namespace Tins {
/**
* \brief AddressRange iterator class.
*/
template<typename Address>
class AddressRangeIterator : public std::iterator<std::forward_iterator_tag, const Address> {
public:
typedef typename std::iterator<std::forward_iterator_tag, const Address>::value_type value_type;

struct end_iterator {

};

/**
* Constructs an iterator.
*
* \param first The address held by this iterator.
*/
AddressRangeIterator(const value_type &addr)
: addr(addr), reached_end(false)
{

}

/**
* Constructs an iterator.
*
* \param first The address held by this iterator.
*/
AddressRangeIterator(const value_type &address, end_iterator)
: addr(address)
{
reached_end = Internals::increment(addr);
}

/**
* Retrieves the current address pointed by this iterator.
*/
const value_type& operator*() const {
return addr;
}

/**
* Retrieves a pointer to the current address pointed by this iterator.
*/
const value_type* operator->() const {
return &addr;
}

/**
* 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 && addr == rhs.addr;
}

/**
* 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(addr);
return *this;
}

/**
* Increments this iterator.
*/
AddressRangeIterator operator++(int) {
AddressRangeIterator copy(*this);
(*this)++;
return copy;
}
private:
Address addr;
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 std::runtime_error("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, 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:
static address_type last_address_from_mask(IPv4Address addr, IPv4Address mask) {
uint32_t addr_int = Endian::be_to_host<uint32_t>(addr),
mask_int = Endian::be_to_host<uint32_t>(mask);
return address_type(Endian::host_to_be(addr_int | ~mask_int));
}

static address_type last_address_from_mask(IPv6Address addr, const IPv6Address &mask) {
IPv6Address::iterator addr_iter = addr.begin();
for(IPv6Address::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) {
*addr_iter = *addr_iter | ~*it;
}
return addr;
}

address_type first, last;
bool only_hosts;
};
} // namespace Tins

#endif // TINS_ADDRESS_RANGE
7 changes: 7 additions & 0 deletions include/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
* \cond
*/
namespace Tins {
class IPv4Address;
class IPv6Address;
namespace Internals {
template<size_t n>
class byte_array {
Expand Down Expand Up @@ -111,6 +113,11 @@ PDU *pdu_from_flag(Constants::Ethernet::e flag, const uint8_t *buffer,
PDU *pdu_from_flag(PDU::PDUType type, const uint8_t *buffer, uint32_t size);

Constants::Ethernet::e pdu_flag_to_ether_type(PDU::PDUType flag);

bool increment(IPv4Address &addr);
bool increment(IPv6Address &addr);
bool decrement(IPv4Address &addr);
bool decrement(IPv6Address &addr);
} // namespace Internals
} // namespace Tins
/**
Expand Down
10 changes: 10 additions & 0 deletions include/ip_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
#include "cxxstd.h"

namespace Tins {
template<typename Address>
class AddressRange;

/**
* \class IPv4Address
* \brief Abstraction of an IPv4 address.
Expand Down Expand Up @@ -137,6 +140,13 @@ class IPv4Address {

uint32_t ip_addr;
};

/**
* \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.
*/
AddressRange<IPv4Address> operator/(const IPv4Address &addr, int mask);
} //namespace Tins

#if TINS_IS_CXX11
Expand Down
13 changes: 13 additions & 0 deletions include/ipv6_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
#include "cxxstd.h"

namespace Tins {
template<typename Address>
class AddressRange;

/**
* Represents an IPv6 address.
*/
class IPv6Address {
public:
/**
Expand Down Expand Up @@ -193,6 +199,13 @@ class IPv6Address {

uint8_t address[address_size];
};

/**
* \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.
*/
AddressRange<IPv6Address> operator/(const IPv6Address &addr, int mask);
} //namespace Tins

#if TINS_IS_CXX11
Expand Down
1 change: 1 addition & 0 deletions include/tins.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@
#include "pppoe.h"
#include "stp.h"
#include "handshake_capturer.h"
#include "address_range.h"

#endif // TINS_TINS_H
Loading

0 comments on commit 3b34947

Please sign in to comment.