diff --git a/include/ipv6_address.h b/include/ipv6_address.h new file mode 100644 index 0000000..0f6db36 --- /dev/null +++ b/include/ipv6_address.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2012, Nasel + * 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_IPV6_ADDRESS +#define TINS_IPV6_ADDRESS + +#include +#include +#include + +namespace Tins { +class IPv6Address { +public: + /** + * The exception thrown when a malformed address is parsed. + */ + class malformed_address : public std::exception { + public: + const char *what() const throw() { + return "Malformed address"; + } + }; + + static const size_t address_size = 16; + + /** + * The iterator type. + */ + typedef uint8_t* iterator; + + /** + * The const iterator type. + */ + typedef const uint8_t* const_iterator; + + /** + * \brief Default constructor. + * Initializes this IPv6 address to "::" + */ + IPv6Address(); + + /** + * \brief Constructor from a text representation. + * \param addr The text representation from which to construct this + * object. + */ + IPv6Address(const std::string &addr); + + /** + * \brief Retrieve the string representation of this address. + * + * \return std::string containing the representation of this address. + */ + std::string to_string() const; + + /** + * Returns an iterator to the beginning of this address. + */ + iterator begin() { + return address; + } + + /** + * Returns a const iterator to the beginning of this address. + */ + const_iterator begin() const { + return address; + } + + /** + * Returns an iterator to the one-past-the-end element of this address. + */ + iterator end() { + return address + address_size; + } + + /** + * Returns a const iterator to the one-past-the-end element of this + * address. + */ + const_iterator end() const { + return address + address_size; + } + + /** + * \brief Compares this address for equality. + * + * \param rhs The address to be compared to. + * + * \return bool indicating whether addresses are equal. + */ + bool operator==(const IPv6Address &rhs) const { + return std::equal(begin(), end(), rhs.begin()); + } + + /** + * \brief Compares this address for inequality. + * + * \param rhs The address to be compared to. + * + * \return bool indicating whether addresses are distinct. + */ + bool operator!=(const IPv6Address &rhs) const { + return !(*this == rhs); + } + + /** + * \brief Compares this address for less-than inequality. + * + * \param rhs The address to be compared to. + * + * \return bool indicating whether this address is less-than rhs. + */ + bool operator<(const IPv6Address &rhs) const { + return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); + } + + /** + * \brief Helper function which copies the address into an output + * iterator. + * + * This is the same as: + * + * std::copy(begin(), end(), iter); + * + * But since some PDUs return a IPv6Address by value, this function + * can be used to avoid temporaries. + * + * \param iter The output iterator in which to store this address. + * \return OutputIterator pointing to one-past the last position + * written. + */ + template + OutputIterator copy(OutputIterator iter) const { + return std::copy(begin(), end(), iter); + } + + /** + * \brief Writes this address in hex-notation to a std::ostream. + * + * \param os The stream in which to write the address. + * \param addr The parameter to be written. + * \return std::ostream& pointing to the os parameter. + */ + friend std::ostream &operator<<(std::ostream &os, const IPv6Address &addr) { + return os << addr.to_string(); + } +private: + uint8_t address[address_size]; +}; +} + +#endif // TINS_IPV6_ADDRESS diff --git a/src/ipv6_address.cpp b/src/ipv6_address.cpp new file mode 100644 index 0000000..0da8a54 --- /dev/null +++ b/src/ipv6_address.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, Nasel + * 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. + * + */ + +#include +#ifndef WIN32 + #include +#endif +#include +#include // borrame +#include +#include "ipv6_address.h" + +namespace Tins { + IPv6Address::IPv6Address() { + std::fill(address, address + address_size, 0); + } + + IPv6Address::IPv6Address(const std::string &addr) { + if(inet_pton(AF_INET6, addr.c_str(), address) == 0) + throw malformed_address(); + } + + std::string IPv6Address::to_string() const { + char buffer[INET6_ADDRSTRLEN]; + if(inet_ntop(AF_INET6, address, buffer, sizeof(buffer)) == 0) + throw malformed_address(); + return buffer; + } + +} + diff --git a/tests/src/ipv6address.cpp b/tests/src/ipv6address.cpp new file mode 100644 index 0000000..675634c --- /dev/null +++ b/tests/src/ipv6address.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include "ipv6_address.h" +#include "utils.h" + +using namespace Tins; + + +const uint8_t empty_addr[IPv6Address::address_size] = { 0 }; + +void test_to_string(const std::string &str) { + EXPECT_EQ(str, IPv6Address(str).to_string()); +} + +TEST(IPv6AddressTest, DefaultConstructor) { + IPv6Address addr; + EXPECT_TRUE(std::equal(addr.begin(), addr.end(), empty_addr)); +} + +TEST(IPv6AddressTest, ConstructorFromString1) { + IPv6Address addr("2001:db8:85a3:8d3:1319:8a2e:370:7348"); + const uint8_t some_addr[IPv6Address::address_size] = { + 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x08, 0xd3, 0x13, 0x19, + 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x48 + }; + EXPECT_TRUE(std::equal(addr.begin(), addr.end(), some_addr)); +} + +TEST(IPv6AddressTest, ConstructorFromString2) { + IPv6Address addr("2001:db8:85a3::1319:8a2e:370:7348"); + const uint16_t some_addr[IPv6Address::address_size] = { + 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x13, 0x19, + 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x48 + }; + EXPECT_TRUE(std::equal(addr.begin(), addr.end(), some_addr)); +} + +TEST(IPv6AddressTest, ConstructorFromString3) { + IPv6Address addr("::1"); + const uint16_t some_addr[IPv6Address::address_size] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; + EXPECT_TRUE(std::equal(addr.begin(), addr.end(), some_addr)); +} + +TEST(IPv6AddressTest, ToString) { + test_to_string("2001:db8:85a3:8d3:1319:8a2e:370:7348"); + test_to_string("2001:db8:85a3:8d3:1319:8a2e::"); + test_to_string("1:db8:85a3:8d3:1319:8a2e:370:7348"); + test_to_string("::85a3:8d3:1319:8a2e:370:7348"); + test_to_string("::1:2:3"); +} + +TEST(IPv6AddressTest, EqualOperator) { + EXPECT_EQ(IPv6Address("17f8::1"), IPv6Address("17f8:0::0:1")); + EXPECT_EQ(IPv6Address("::1"), IPv6Address("::1")); + EXPECT_EQ(IPv6Address("1::"), IPv6Address("1::")); +} + +TEST(IPv6AddressTest, DistinctOperator) { + EXPECT_NE(IPv6Address("17f8::12"), IPv6Address("17f8:0::1:12")); + EXPECT_NE(IPv6Address("::1"), IPv6Address("::2")); + EXPECT_NE(IPv6Address("4::"), IPv6Address("5::")); +} + +TEST(IPv6AddressTest, LessThanOperator) { + EXPECT_LT(IPv6Address("17f8::1"), IPv6Address("17f8:0::0:5")); + EXPECT_LT(IPv6Address("::1"), IPv6Address("::5")); + EXPECT_LT(IPv6Address("1::"), IPv6Address("2::")); +} + +TEST(IPv6AddressTest, OutputOperator) { + std::ostringstream oss; + oss << IPv6Address("17f8::1"); + EXPECT_EQ("17f8::1", oss.str()); +} + +TEST(IPv6AddressTest, Copy) { + IPv6Address addr1("17f8::1"); + IPv6Address addr2; + addr1.copy(addr2.begin()); + EXPECT_EQ(addr1, addr2); +}