From 3773443fc8bd5eb5fc0235b8235e77fd6f5f7ba5 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sat, 19 Mar 2016 15:44:55 -0700 Subject: [PATCH] Allow masking IPv4/6 and HW addresses --- include/tins/address_range.h | 2 +- include/tins/hw_address.h | 23 +++++++++++++ include/tins/internals.h | 12 ------- include/tins/ip_address.h | 10 +++++- include/tins/ipv6_address.h | 7 ++++ src/internals.cpp | 14 -------- src/ip_address.cpp | 4 +++ src/ipv6_address.cpp | 9 ++++++ tests/src/CMakeLists.txt | 10 +++--- tests/src/address_range.cpp | 32 +++++++++++++++++++ tests/src/{hwaddress.cpp => hw_address.cpp} | 8 +++++ tests/src/{ipaddress.cpp => ip_address.cpp} | 11 +++++++ .../src/{ipv6address.cpp => ipv6_address.cpp} | 18 +++++++++++ 13 files changed, 127 insertions(+), 33 deletions(-) rename tests/src/{hwaddress.cpp => hw_address.cpp} (93%) rename tests/src/{ipaddress.cpp => ip_address.cpp} (92%) rename tests/src/{ipv6address.cpp => ipv6_address.cpp} (86%) diff --git a/include/tins/address_range.h b/include/tins/address_range.h index 9880151..070f296 100644 --- a/include/tins/address_range.h +++ b/include/tins/address_range.h @@ -211,7 +211,7 @@ public: */ static AddressRange from_mask(const address_type& first, const address_type& mask) { return AddressRange( - Internals::first_address_from_mask(first, mask), + first & mask, Internals::last_address_from_mask(first, mask), true ); diff --git a/include/tins/hw_address.h b/include/tins/hw_address.h index f13fed9..91cbf01 100644 --- a/include/tins/hw_address.h +++ b/include/tins/hw_address.h @@ -249,6 +249,20 @@ public: bool operator<(const HWAddress& rhs) const { return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); } + + /** + * \brief Apply a mask to this address + * + * \param mask The mask to be applied + * \return The result of applying the mask to this address + */ + HWAddress operator&(const HWAddress& mask) const { + HWAddress output = *this; + for (size_t i = 0; i < n; ++i) { + output[i] = output[i] & mask[i]; + } + return output; + } /** * \brief Retrieves the size of this address. @@ -299,6 +313,15 @@ public: storage_type operator[](size_t i) const { return begin()[i]; } + + /** + * \brief Retrieves the i-th storage_type in this address. + * + * \param i The element to retrieve. + */ + storage_type& operator[](size_t i) { + return begin()[i]; + } /** * \brief Writes this HWAddress in hex-notation to a std::ostream. diff --git a/include/tins/internals.h b/include/tins/internals.h index 47df50d..4f0d10c 100644 --- a/include/tins/internals.h +++ b/include/tins/internals.h @@ -183,18 +183,6 @@ bool decrement(HWAddress& addr) { // Compares sequence numbers as defined by RFC 1982. int seq_compare(uint32_t seq1, uint32_t seq2); - -IPv4Address first_address_from_mask(IPv4Address addr, IPv4Address mask); -IPv6Address first_address_from_mask(IPv6Address addr, const IPv6Address& mask); -template -HWAddress first_address_from_mask(HWAddress addr, const HWAddress& mask) { - typename HWAddress::iterator addr_iter = addr.begin(); - for (typename HWAddress::const_iterator it = mask.begin(); it != mask.end(); ++it, ++addr_iter) { - *addr_iter = *addr_iter & *it; - } - return addr; -} - IPv4Address last_address_from_mask(IPv4Address addr, IPv4Address mask); IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address& mask); template diff --git a/include/tins/ip_address.h b/include/tins/ip_address.h index ddcce30..1fdf636 100644 --- a/include/tins/ip_address.h +++ b/include/tins/ip_address.h @@ -123,9 +123,17 @@ public: * \param rhs The address to be compared. * \return bool indicating whether this address is less-than rhs. */ - bool operator< (const IPv4Address& rhs) const { + bool operator<(const IPv4Address& rhs) const { return ip_addr_ < rhs.ip_addr_; } + + /** + * \brief Apply a mask to this address + * + * \param mask The mask to be applied + * \return The result of applying the mask to this address + */ + IPv4Address operator&(const IPv4Address& mask) const; /** * \brief Returns true if this is a private IPv4 address. diff --git a/include/tins/ipv6_address.h b/include/tins/ipv6_address.h index fb11600..992727a 100644 --- a/include/tins/ipv6_address.h +++ b/include/tins/ipv6_address.h @@ -206,6 +206,13 @@ public: friend std::ostream& operator<<(std::ostream& os, const IPv6Address& addr) { return os << addr.to_string(); } + + + /** + * Applies a mask to an address + */ + TINS_API friend IPv6Address operator&(const IPv6Address& lhs, const IPv6Address& rhs); + private: void init(const char* addr); diff --git a/src/internals.cpp b/src/internals.cpp index 2449db6..da41033 100644 --- a/src/internals.cpp +++ b/src/internals.cpp @@ -443,19 +443,5 @@ IPv6Address last_address_from_mask(IPv6Address addr, const IPv6Address& mask) { return addr; } -IPv4Address first_address_from_mask(IPv4Address addr, IPv4Address mask) { - uint32_t addr_int = Endian::be_to_host(addr), - mask_int = Endian::be_to_host(mask); - return IPv4Address(Endian::host_to_be(addr_int & mask_int)); -} - -IPv6Address first_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; -} - } // namespace Internals } // namespace Tins diff --git a/src/ip_address.cpp b/src/ip_address.cpp index d876914..7b8e898 100644 --- a/src/ip_address.cpp +++ b/src/ip_address.cpp @@ -139,4 +139,8 @@ bool IPv4Address::is_broadcast() const { return* this == broadcast; } +IPv4Address IPv4Address::operator&(const IPv4Address& mask) const { + return IPv4Address(Endian::be_to_host(ip_addr_ & mask.ip_addr_)); +} + } // Tins diff --git a/src/ipv6_address.cpp b/src/ipv6_address.cpp index f6a90e7..9954777 100644 --- a/src/ipv6_address.cpp +++ b/src/ipv6_address.cpp @@ -132,4 +132,13 @@ bool IPv6Address::is_multicast() const { return multicast_range.contains(*this); } +IPv6Address operator&(const IPv6Address& lhs, const IPv6Address& rhs) { + IPv6Address output = lhs; + IPv6Address::iterator addr_iter = output.begin(); + for (IPv6Address::const_iterator it = rhs.begin(); it != rhs.end(); ++it, ++addr_iter) { + *addr_iter = *addr_iter & *it; + } + return output; +} + } // Tins diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt index 09779a4..7518e51 100644 --- a/tests/src/CMakeLists.txt +++ b/tests/src/CMakeLists.txt @@ -63,7 +63,7 @@ ADD_CUSTOM_TARGET( ICMPv6Test IPTest IPReassemblerTest - IPAddressTest + IPv4AddressTest IPSecTest IPv6Test IPv6AddressTest @@ -102,16 +102,16 @@ ADD_EXECUTABLE(DHCPv6Test EXCLUDE_FROM_ALL dhcpv6.cpp) ADD_EXECUTABLE(DNSTest EXCLUDE_FROM_ALL dns.cpp) ADD_EXECUTABLE(Dot1QTest EXCLUDE_FROM_ALL dot1q.cpp) ADD_EXECUTABLE(EthernetTest EXCLUDE_FROM_ALL ethernetII.cpp) -ADD_EXECUTABLE(HWAddressTest EXCLUDE_FROM_ALL hwaddress.cpp) +ADD_EXECUTABLE(HWAddressTest EXCLUDE_FROM_ALL hw_address.cpp) ADD_EXECUTABLE(ICMPExtensionTest EXCLUDE_FROM_ALL icmp_extension.cpp) ADD_EXECUTABLE(ICMPTest EXCLUDE_FROM_ALL icmp.cpp) ADD_EXECUTABLE(ICMPv6Test EXCLUDE_FROM_ALL icmpv6.cpp) ADD_EXECUTABLE(IPTest EXCLUDE_FROM_ALL ip.cpp) ADD_EXECUTABLE(IPReassemblerTest EXCLUDE_FROM_ALL ip_reassembler.cpp) -ADD_EXECUTABLE(IPAddressTest EXCLUDE_FROM_ALL ipaddress.cpp) +ADD_EXECUTABLE(IPv4AddressTest EXCLUDE_FROM_ALL ip_address.cpp) ADD_EXECUTABLE(IPSecTest EXCLUDE_FROM_ALL ipsec.cpp) ADD_EXECUTABLE(IPv6Test EXCLUDE_FROM_ALL ipv6.cpp) -ADD_EXECUTABLE(IPv6AddressTest EXCLUDE_FROM_ALL ipv6address.cpp) +ADD_EXECUTABLE(IPv6AddressTest EXCLUDE_FROM_ALL ipv6_address.cpp) ADD_EXECUTABLE(LLCTest EXCLUDE_FROM_ALL llc.cpp) ADD_EXECUTABLE(LoopbackTest EXCLUDE_FROM_ALL loopback.cpp) ADD_EXECUTABLE(MPLSTest EXCLUDE_FROM_ALL mpls.cpp) @@ -190,7 +190,7 @@ ADD_TEST(ICMP ICMPTest) ADD_TEST(ICMPv6 ICMPv6Test) ADD_TEST(IP IPTest) ADD_TEST(IPReassembler IPReassemblerTest) -ADD_TEST(IPAddress IPAddressTest) +ADD_TEST(IPv4Address IPv4AddressTest) ADD_TEST(IPSec IPSecTest) ADD_TEST(IPv6 IPv6Test) ADD_TEST(IPv6Address IPv6AddressTest) diff --git a/tests/src/address_range.cpp b/tests/src/address_range.cpp index 2b8baaa..195d1dd 100644 --- a/tests/src/address_range.cpp +++ b/tests/src/address_range.cpp @@ -159,3 +159,35 @@ TEST_F(AddressRangeTest, Slash) { EXPECT_TRUE(range2.is_iterable()); } } + +TEST_F(AddressRangeTest, SlashUsingAddressGreaterThanMask) { + // v4 + { + IPv4Range range1 = IPv4Range::from_mask("192.168.0.128", "255.255.255.0"); + IPv4Range range2 = IPv4Address("192.168.0.0") / 24; + EXPECT_TRUE(std::equal(range1.begin(), range1.end(), range2.begin())); + EXPECT_TRUE(std::equal(range2.begin(), range2.end(), range1.begin())); + EXPECT_TRUE(range1.is_iterable()); + EXPECT_TRUE(range2.is_iterable()); + } + // v6 + { + IPv6Range range1 = IPv6Range::from_mask("dead:beef::1200", + "ffff:ffff:ffff:ffff:ffff:ffff:ffff::"); + IPv6Range range2 = IPv6Address("dead:beef::") / 112; + EXPECT_TRUE(std::equal(range1.begin(), range1.end(), range2.begin())); + EXPECT_TRUE(std::equal(range2.begin(), range2.end(), range1.begin())); + EXPECT_TRUE(range1.is_iterable()); + EXPECT_TRUE(range2.is_iterable()); + } + { + typedef AddressRange > HWAddressRange; + HWAddressRange range1 = HWAddressRange::from_mask("de:ad:be:ef:fe:00", + "ff:ff:ff:ef:00:00"); + HWAddressRange range2 = HWAddress<6>("de:ad:be:ef:00:00") / 32; + EXPECT_TRUE(std::equal(range1.begin(), range1.end(), range2.begin())); + EXPECT_TRUE(std::equal(range2.begin(), range2.end(), range1.begin())); + EXPECT_TRUE(range1.is_iterable()); + EXPECT_TRUE(range2.is_iterable()); + } +} diff --git a/tests/src/hwaddress.cpp b/tests/src/hw_address.cpp similarity index 93% rename from tests/src/hwaddress.cpp rename to tests/src/hw_address.cpp index a7f300f..9f356b0 100644 --- a/tests/src/hwaddress.cpp +++ b/tests/src/hw_address.cpp @@ -107,3 +107,11 @@ TEST_F(HWAddressTest, OutputOperator) { oss << addr; EXPECT_EQ(oss.str(), address); } + +TEST_F(HWAddressTest, Mask) { + typedef HWAddress<6> address_type; + EXPECT_EQ( + address_type("de:ad:be:e0:00:00"), + address_type("de:ad:be:ef:00:00") & address_type("ff:ff:ff:f0:00:00") + ); +} diff --git a/tests/src/ipaddress.cpp b/tests/src/ip_address.cpp similarity index 92% rename from tests/src/ipaddress.cpp rename to tests/src/ip_address.cpp index cfae398..f61208d 100644 --- a/tests/src/ipaddress.cpp +++ b/tests/src/ip_address.cpp @@ -101,3 +101,14 @@ TEST(IPAddressTest, IsUnicast) { EXPECT_TRUE(IPv4Address("240.0.0.0").is_unicast()); EXPECT_TRUE(IPv4Address("127.0.0.1").is_unicast()); } + +TEST(IPAddressTest, Mask) { + EXPECT_EQ( + IPv4Address("192.168.100.0"), + IPv4Address("192.168.100.1") & IPv4Address("255.255.255.0") + ); + EXPECT_EQ( + IPv4Address("192.128.0.0"), + IPv4Address("192.255.1.2") & IPv4Address("255.128.0.0") + ); +} diff --git a/tests/src/ipv6address.cpp b/tests/src/ipv6_address.cpp similarity index 86% rename from tests/src/ipv6address.cpp rename to tests/src/ipv6_address.cpp index a4919e2..c355abe 100644 --- a/tests/src/ipv6address.cpp +++ b/tests/src/ipv6_address.cpp @@ -106,3 +106,21 @@ TEST(IPv6AddressTest, FromPrefixLength) { EXPECT_EQ(IPv6Address("ffff:ffff::"), IPv6Address::from_prefix_length(32)); } +TEST(IPv6AddressTest, MaskAddress) { + EXPECT_EQ( + IPv6Address("deaf:beef::"), + IPv6Address("deaf:beef:adad:beef::") & IPv6Address("ffff:ffff::") + ); + EXPECT_EQ( + IPv6Address("deaf:be00::"), + IPv6Address("deaf:beef:adad:beef::") & IPv6Address("ffff:ff00::") + ); + EXPECT_EQ( + IPv6Address("deaf:b000::"), + IPv6Address("deaf:beef:adad:beef::") & IPv6Address("ffff:f000::") + ); + EXPECT_EQ( + IPv6Address("deaf:a000::"), + IPv6Address("deaf:beef:adad:beef::") & IPv6Address("ffff:e000::") + ); +}