diff --git a/include/address_range.h b/include/address_range.h index d7f7039..a749fca 100644 --- a/include/address_range.h +++ b/include/address_range.h @@ -294,6 +294,16 @@ private: address_type first, last; bool only_hosts; }; + +/** + * An IPv4 address range. + */ +typedef AddressRange IPv4Range; + +/** + * An IPv6 address range. + */ +typedef AddressRange IPv6Range; } // namespace Tins #endif // TINS_ADDRESS_RANGE \ No newline at end of file diff --git a/include/hw_address.h b/include/hw_address.h index 12a8d11..55bf5c8 100644 --- a/include/hw_address.h +++ b/include/hw_address.h @@ -234,6 +234,13 @@ public: return *std::min_element(begin(), end()) == 0xff; } + /** + * \brief Indicates whether this is a multicast address + */ + bool is_multicast() const { + return (buffer[0] & 0x01); + } + /** * \brief Convert this address to a hex-notation std::string address. * diff --git a/include/internals.h b/include/internals.h index 304508a..5666643 100644 --- a/include/internals.h +++ b/include/internals.h @@ -35,6 +35,7 @@ #include #include "constants.h" #include "pdu.h" +#include "hw_address.h" /** * \cond @@ -42,6 +43,7 @@ namespace Tins { class IPv4Address; class IPv6Address; + namespace Internals { template class byte_array { @@ -114,10 +116,46 @@ 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); +template +bool increment_buffer(T &addr) { + typename T::iterator it = addr.end() - 1; + while(it >= addr.begin() && *it == 0xff) { + *it = 0; + --it; + } + // reached end + if(it < addr.begin()) + return true; + (*it)++; + return false; +} + +template +bool decrement_buffer(T &addr) { + typename T::iterator it = addr.end() - 1; + while(it >= addr.begin() && *it == 0) { + *it = 0xff; + --it; + } + // reached end + if(it < addr.begin()) + return true; + (*it)--; + return false; +} + bool increment(IPv4Address &addr); bool increment(IPv6Address &addr); bool decrement(IPv4Address &addr); bool decrement(IPv6Address &addr); +template +bool increment(HWAddress &addr) { + return increment_buffer(addr); +} +template +bool decrement(HWAddress &addr) { + return decrement_buffer(addr); +} inline bool is_dot3(const uint8_t *ptr, size_t sz) { return (sz >= 13 && ptr[12] < 8); diff --git a/include/ip_address.h b/include/ip_address.h index decd51e..db108bb 100644 --- a/include/ip_address.h +++ b/include/ip_address.h @@ -144,6 +144,14 @@ public: * 127.0.0.0/8, false otherwise. */ bool is_loopback() const; + + /** + * \brief Returns true if this is a multicast IPv4 address. + * + * This method returns true if this address is in the address range + * 224.0.0.0/4, false otherwise. + */ + bool is_multicast() const; /** * \brief Writes this address to a std::ostream. diff --git a/include/ipv6_address.h b/include/ipv6_address.h index 904e436..8b812ae 100644 --- a/include/ipv6_address.h +++ b/include/ipv6_address.h @@ -191,6 +191,14 @@ public: * false otherwise. */ bool is_loopback() const; + + /** + * \brief Returns true if this is a multicast IPv6 address. + * + * This method returns true if this address is in the address range + * ff00::/8, false otherwise. + */ + bool is_multicast() const; /** * \brief Writes this address in hex-notation to a std::ostream. diff --git a/src/internals.cpp b/src/internals.cpp index 1b60cd1..31652ed 100644 --- a/src/internals.cpp +++ b/src/internals.cpp @@ -174,16 +174,7 @@ bool increment(IPv4Address &addr) { } bool increment(IPv6Address &addr) { - IPv6Address::iterator it = addr.end() - 1; - while(it >= addr.begin() && *it == 0xff) { - *it = 0; - --it; - } - // reached end - if(it < addr.begin()) - return true; - (*it)++; - return false; + return increment_buffer(addr); } bool decrement(IPv4Address &addr) { @@ -194,16 +185,7 @@ bool decrement(IPv4Address &addr) { } bool decrement(IPv6Address &addr) { - IPv6Address::iterator it = addr.end() - 1; - while(it >= addr.begin() && *it == 0) { - *it = 0xff; - --it; - } - // reached end - if(it < addr.begin()) - return true; - (*it)--; - return false; + return decrement_buffer(addr); } } // namespace Internals } // namespace Tins diff --git a/src/ip_address.cpp b/src/ip_address.cpp index fd8b99a..f051005 100644 --- a/src/ip_address.cpp +++ b/src/ip_address.cpp @@ -43,6 +43,7 @@ const AddressRange private_ranges[] = { }; const AddressRange loopback_range = IPv4Address("127.0.0.0") / 8; +const AddressRange multicast_range = IPv4Address("224.0.0.0") / 4; IPv4Address::IPv4Address(uint32_t ip) : ip_addr(Endian::be_to_host(ip)) { @@ -118,6 +119,10 @@ bool IPv4Address::is_loopback() const { return loopback_range.contains(*this); } +bool IPv4Address::is_multicast() const { + return multicast_range.contains(*this); +} + AddressRange operator/(const IPv4Address &addr, int mask) { if(mask > 32) throw std::logic_error("Prefix length cannot exceed 32"); diff --git a/src/ipv6_address.cpp b/src/ipv6_address.cpp index c099011..fc6e6e2 100644 --- a/src/ipv6_address.cpp +++ b/src/ipv6_address.cpp @@ -45,6 +45,7 @@ namespace Tins { const IPv6Address loopback_address = "::1"; +const AddressRange multicast_range = IPv6Address("ff00::") / 8; IPv6Address::IPv6Address() { std::fill(address, address + address_size, 0); @@ -104,6 +105,10 @@ bool IPv6Address::is_loopback() const { return loopback_address == *this; } +bool IPv6Address::is_multicast() const { + return multicast_range.contains(*this); +} + AddressRange operator/(const IPv6Address &addr, int mask) { if(mask > 128) throw std::logic_error("Prefix length cannot exceed 128"); diff --git a/tests/src/address_range.cpp b/tests/src/address_range.cpp index 0331bb2..bdbbd61 100644 --- a/tests/src/address_range.cpp +++ b/tests/src/address_range.cpp @@ -12,12 +12,12 @@ using namespace Tins; class AddressRangeTest : public testing::Test { public: - void contain_tests24(const AddressRange &range); - void contain_tests24(const AddressRange &range); - void contain_tests26(const AddressRange &range); + void contain_tests24(const IPv4Range &range); + void contain_tests24(const IPv6Range &range); + void contain_tests26(const IPv4Range &range); }; -void AddressRangeTest::contain_tests24(const AddressRange &range) { +void AddressRangeTest::contain_tests24(const IPv4Range &range) { EXPECT_TRUE(range.contains("192.168.0.0")); EXPECT_TRUE(range.contains("192.168.0.1")); EXPECT_TRUE(range.contains("192.168.0.254")); @@ -26,14 +26,14 @@ void AddressRangeTest::contain_tests24(const AddressRange &range) { EXPECT_FALSE(range.contains("192.168.1.1")); } -void AddressRangeTest::contain_tests26(const AddressRange &range) { +void AddressRangeTest::contain_tests26(const IPv4Range &range) { EXPECT_TRUE(range.contains("192.168.254.192")); EXPECT_TRUE(range.contains("192.168.254.255")); EXPECT_FALSE(range.contains("192.168.254.0")); EXPECT_FALSE(range.contains("192.168.254.191")); } -void AddressRangeTest::contain_tests24(const AddressRange &range) { +void AddressRangeTest::contain_tests24(const IPv6Range &range) { EXPECT_TRUE(range.contains("dead::1")); EXPECT_TRUE(range.contains("dead::1fee")); EXPECT_TRUE(range.contains("dead::ffee")); @@ -42,19 +42,25 @@ void AddressRangeTest::contain_tests24(const AddressRange &range) { } TEST_F(AddressRangeTest, Contains) { - contain_tests24(AddressRange("192.168.0.0", "192.168.0.255")); - contain_tests24(AddressRange::from_mask("192.168.0.0", "255.255.255.0")); - contain_tests26(AddressRange("192.168.254.192", "192.168.254.255")); - contain_tests26(AddressRange::from_mask("192.168.254.192", "255.255.255.192")); + contain_tests24(IPv4Range("192.168.0.0", "192.168.0.255")); + contain_tests24(IPv4Range::from_mask("192.168.0.0", "255.255.255.0")); + contain_tests26(IPv4Range("192.168.254.192", "192.168.254.255")); + contain_tests26(IPv4Range::from_mask("192.168.254.192", "255.255.255.192")); - contain_tests24(AddressRange("dead::0", "dead::ffff")); - contain_tests24(AddressRange::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0")); + contain_tests24(IPv6Range("dead::0", "dead::ffff")); + contain_tests24(IPv6Range::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0")); + + AddressRange > range("00:00:00:00:00:00", "00:00:00:00:00:ff"); + EXPECT_TRUE(range.contains("00:00:00:00:00:00")); + EXPECT_TRUE(range.contains("00:00:00:00:00:10")); + EXPECT_TRUE(range.contains("00:00:00:00:00:ff")); + EXPECT_FALSE(range.contains("00:00:00:00:01:00")); } TEST_F(AddressRangeTest, Iterators) { // v4 { - AddressRange addr = AddressRange::from_mask("192.168.0.0", "255.255.255.252"); + IPv4Range addr = IPv4Range::from_mask("192.168.0.0", "255.255.255.252"); std::vector addresses; addresses.push_back("192.168.0.1"); addresses.push_back("192.168.0.2"); @@ -62,7 +68,7 @@ TEST_F(AddressRangeTest, Iterators) { EXPECT_TRUE(addr.is_iterable()); } { - AddressRange addr = AddressRange::from_mask("255.255.255.252", "255.255.255.252"); + IPv4Range addr = IPv4Range::from_mask("255.255.255.252", "255.255.255.252"); std::vector addresses; addresses.push_back("255.255.255.253"); addresses.push_back("255.255.255.254"); @@ -72,7 +78,7 @@ TEST_F(AddressRangeTest, Iterators) { // v6 { - AddressRange addr = AddressRange::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"); + IPv6Range addr = IPv6Range::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"); std::vector addresses; addresses.push_back("dead::1"); addresses.push_back("dead::2"); @@ -81,8 +87,8 @@ TEST_F(AddressRangeTest, Iterators) { } { - AddressRange addr = - AddressRange::from_mask( + IPv6Range addr = + IPv6Range::from_mask( "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc" ); @@ -97,16 +103,16 @@ TEST_F(AddressRangeTest, Iterators) { TEST_F(AddressRangeTest, Slash) { // v4 { - AddressRange range1 = AddressRange::from_mask("192.168.0.0", "255.255.255.252"); - AddressRange range2 = IPv4Address("192.168.0.0") / 30; + IPv4Range range1 = IPv4Range::from_mask("192.168.0.0", "255.255.255.252"); + IPv4Range range2 = IPv4Address("192.168.0.0") / 30; 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()); } { - AddressRange range1 = AddressRange::from_mask("255.255.255.252", "255.255.255.252"); - AddressRange range2 = IPv4Address("255.255.255.252") / 30; + IPv4Range range1 = IPv4Range::from_mask("255.255.255.252", "255.255.255.252"); + IPv4Range range2 = IPv4Address("255.255.255.252") / 30; 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()); @@ -115,20 +121,20 @@ TEST_F(AddressRangeTest, Slash) { // v6 { - AddressRange range1 = AddressRange::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"); - AddressRange range2 = IPv6Address("dead::0") / 126; + IPv6Range range1 = IPv6Range::from_mask("dead::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"); + IPv6Range range2 = IPv6Address("dead::0") / 126; 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()); } { - AddressRange range1 = - AddressRange::from_mask( + IPv6Range range1 = + IPv6Range::from_mask( "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc" ); - AddressRange range2 = IPv6Address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc") / 126; + IPv6Range range2 = IPv6Address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc") / 126; 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()); diff --git a/tests/src/hwaddress.cpp b/tests/src/hwaddress.cpp index 3e6f529..abac310 100644 --- a/tests/src/hwaddress.cpp +++ b/tests/src/hwaddress.cpp @@ -66,6 +66,13 @@ TEST_F(HWAddressTest, IsBroadcast) { EXPECT_TRUE(HWAddress<6>("ff:ff:ff:ff:ff:ff").is_broadcast()); } +TEST_F(HWAddressTest, IsMulticast) { + EXPECT_TRUE(HWAddress<6>("01:02:03:04:05:06").is_multicast()); + EXPECT_TRUE(HWAddress<6>("09:02:03:04:05:06").is_multicast()); + EXPECT_TRUE(HWAddress<6>("03:02:03:04:05:06").is_multicast()); + EXPECT_FALSE(HWAddress<6>("00:02:03:04:05:06").is_multicast()); + EXPECT_FALSE(HWAddress<6>("02:02:03:04:05:06").is_multicast()); +} TEST_F(HWAddressTest, CopyAssignmentOperator) { HWAddress<6> addr1(byte_address), addr2; diff --git a/tests/src/ipaddress.cpp b/tests/src/ipaddress.cpp index 7befdbd..54f21ba 100644 --- a/tests/src/ipaddress.cpp +++ b/tests/src/ipaddress.cpp @@ -80,3 +80,11 @@ TEST(IPAddressTest, IsLoopback) { EXPECT_FALSE(IPv4Address("126.255.255.254").is_loopback()); EXPECT_FALSE(IPv4Address("128.0.0.0").is_loopback()); } + +TEST(IPAddressTest, IsMulticast) { + EXPECT_TRUE(IPv4Address("224.0.0.1").is_multicast()); + EXPECT_TRUE(IPv4Address("226.3.54.132").is_multicast()); + EXPECT_TRUE(IPv4Address("239.255.255.255").is_multicast()); + EXPECT_FALSE(IPv4Address("223.255.255.255").is_multicast()); + EXPECT_FALSE(IPv4Address("240.0.0.0").is_multicast()); +} diff --git a/tests/src/ipv6address.cpp b/tests/src/ipv6address.cpp index 9957365..725992b 100644 --- a/tests/src/ipv6address.cpp +++ b/tests/src/ipv6address.cpp @@ -91,3 +91,12 @@ TEST(IPv6AddressTest, IsLoopback) { EXPECT_FALSE(IPv6Address("::2").is_loopback()); EXPECT_FALSE(IPv6Address("ffff::2").is_loopback()); } + +TEST(IPv6AddressTest, IsMulticast) { + EXPECT_TRUE(IPv6Address("ff00::1").is_multicast()); + EXPECT_TRUE(IPv6Address("ff02::1").is_multicast()); + EXPECT_TRUE(IPv6Address("ffff::ffff").is_multicast()); + EXPECT_FALSE(IPv6Address("f000::").is_multicast()); + EXPECT_FALSE(IPv6Address("feaa::dead").is_multicast()); +} +