diff --git a/include/tins/internals.h b/include/tins/internals.h index db51de9..09c09f4 100644 --- a/include/tins/internals.h +++ b/include/tins/internals.h @@ -108,6 +108,7 @@ private: void skip_line(std::istream& input); bool from_hex(const std::string& str, uint32_t& result); +bool from_hex(const std::string& str, std::string& result); template struct enable_if { diff --git a/include/tins/ipv6_address.h b/include/tins/ipv6_address.h index fd677f3..fb11600 100644 --- a/include/tins/ipv6_address.h +++ b/include/tins/ipv6_address.h @@ -55,6 +55,13 @@ public: */ typedef const uint8_t* const_iterator; + /** + * \brief Constructs an IPv6 address from a prefix length + * + * \param prefix_length The length of the prefix + */ + static IPv6Address from_prefix_length(uint32_t prefix_length); + /** * \brief Default constructor. * Initializes this IPv6 address to "::" diff --git a/include/tins/utils.h b/include/tins/utils.h index c647e19..3e46abf 100644 --- a/include/tins/utils.h +++ b/include/tins/utils.h @@ -36,6 +36,7 @@ #include #include #include "ip_address.h" +#include "ipv6_address.h" #include "internals.h" // Fix for Windows interface define on combaseapi.h @@ -89,6 +90,36 @@ struct RouteEntry { int metric; }; +/** + * Struct that represents an entry the IPv6 routing table + */ +struct Route6Entry { + /** + * This interface's name. + */ + std::string interface; + + /** + * This route entry's destination. + */ + IPv6Address destination; + + /** + * This route entry's subnet mask. + */ + IPv6Address mask; + + /** + * This route entry's next hop. + */ + IPv6Address next_hop; + + /** + * This route entry's metric. + */ + int metric; +}; + /** * \brief Resolves a domain name and returns its corresponding ip address. * @@ -176,6 +207,13 @@ void route_entries(ForwardIterator output); */ TINS_API std::vector route_entries(); +/** + * \brief Retrieves entries in the routing table. + * + * \return a vector which contains all of the route entries. + */ +TINS_API std::vector route6_entries(); + /** \brief Returns the 32 bit crc of the given buffer. * * \param data The input buffer. diff --git a/src/address_range.cpp b/src/address_range.cpp index bcbfb05..00291a9 100644 --- a/src/address_range.cpp +++ b/src/address_range.cpp @@ -49,15 +49,7 @@ IPv6Range operator/(const IPv6Address& addr, int mask) { if (mask > 128) { throw std::logic_error("Prefix length cannot exceed 128"); } - IPv6Address last_addr; - IPv6Address::iterator it = last_addr.begin(); - while (mask > 8) { - *it = 0xff; - ++it; - mask -= 8; - } - *it = 0xff << (8 - mask); - return IPv6Range::from_mask(addr, last_addr); + return IPv6Range::from_mask(addr, IPv6Address::from_prefix_length(mask)); } } // Tins diff --git a/src/internals.cpp b/src/internals.cpp index b15f017..748f9ae 100644 --- a/src/internals.cpp +++ b/src/internals.cpp @@ -63,7 +63,7 @@ namespace Tins { namespace Internals { bool from_hex(const string& str, uint32_t& result) { - unsigned i(0); + size_t i = 0; result = 0; while (i < str.size()) { uint8_t tmp; @@ -82,6 +82,29 @@ bool from_hex(const string& str, uint32_t& result) { return true; } +bool from_hex(const string& str, string& result) { + result = ""; + for (size_t i = 0; i < str.size(); i+= 2) { + uint8_t value = 0; + for (size_t j = i; j < i + 2 && j < str.size(); ++j) { + if (str[j] >= 'A' && str[j] <= 'F') { + value = (value << 4) | (str[j] - 'A' + 10); + } + else if (str[j] >= 'a' && str[j] <= 'f') { + value = (value << 4) | (str[j] - 'a' + 10); + } + else if (str[j] >= '0' && str[j] <= '9') { + value = (value << 4) | (str[j] - '0'); + } + else { + return false; + } + } + result.push_back(value); + } + return true; +} + void skip_line(std::istream& input) { int c = 0; while (c != '\n' && input) { diff --git a/src/ipv6_address.cpp b/src/ipv6_address.cpp index 2a94706..f6a90e7 100644 --- a/src/ipv6_address.cpp +++ b/src/ipv6_address.cpp @@ -52,6 +52,18 @@ namespace Tins { const IPv6Address loopback_address = "::1"; const AddressRange multicast_range = IPv6Address("ff00::") / 8; +IPv6Address IPv6Address::from_prefix_length(uint32_t prefix_length) { + IPv6Address address; + IPv6Address::iterator it = address.begin(); + while (prefix_length > 8) { + *it = 0xff; + ++it; + prefix_length -= 8; + } + *it = 0xff << (8 - prefix_length); + return address; +} + IPv6Address::IPv6Address() { fill(address_, address_ + address_size, 0); } diff --git a/src/utils.cpp b/src/utils.cpp index 14a05e3..86e0a56 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -54,8 +54,8 @@ #endif #else #include - #include #include + #include #undef interface #endif #include "utils.h" @@ -191,6 +191,7 @@ HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender) { } #if defined(BSD) || defined(__FreeBSD_kernel__) + vector route_entries() { vector output; vector buffer = query_route_table(); @@ -219,15 +220,14 @@ vector route_entries() { } return output; } + #elif defined(_WIN32) + vector route_entries() { vector output; - MIB_IPFORWARDTABLE* table; + MIB_IPFORWARDTABLE table; ULONG size = 0; - GetIpForwardTable(0, &size, 0); - vector buffer(size); - table = (MIB_IPFORWARDTABLE*)&buffer[0]; - GetIpForwardTable(table, &size, 0); + GetIpForwardTable(AF_INET6, &table); for (DWORD i = 0; i < table->dwNumEntries; i++) { MIB_IPFORWARDROW* row = &table->table[i]; @@ -244,7 +244,34 @@ vector route_entries() { } return output; } -#else + +vector route6_entries() { + vector output; + MIB_IPFORWARD_TABLE2* table; + GetIpForwardTable2(AF_INET6, &table); + for (ULONG i = 0; i < table->NumEntries; i++) { + MIB_IPFORWARD_ROW2* row = &table->Table[i]; + if (true) { + try { + Route6Entry entry; + entry.interface = NetworkInterface::from_index(row->InterfaceIndex).name(); + entry.destination = IPv6Address(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.s6_addr); + entry.mask = IPv6Address::from_prefix_length(row->DestinationPrefix.PrefixLength); + entry.next_hop = IPv6Address(row->NextHop.Ipv6.sin6_addr.s6_addr); + entry.metric = row->Metric; + output.push_back(entry); + } + catch (invalid_interface&) { + + } + } + } + FreeMibTable(table); + return output; +} + +#else // GNU/LINUX + vector route_entries() { using namespace Tins::Internals; vector output; @@ -271,6 +298,44 @@ vector route_entries() { } return output; } + +vector route6_entries() { + using namespace Tins::Internals; + vector output; + ifstream input("/proc/net/ipv6_route"); + string destination, mask_length, metric, next_hop, dummy, flags; + Route6Entry entry; + while (input >> destination >> mask_length) { + string temporary; + uint32_t temporary_int; + for (unsigned i(0); i < 2; ++i) { + input >> dummy; + } + input >> next_hop; + input >> metric; + for (unsigned i(0); i < 2; ++i) { + input >> dummy; + } + input >> flags >> entry.interface; + from_hex(destination, temporary); + entry.destination = IPv6Address((const uint8_t*)&temporary[0]); + from_hex(mask_length, temporary_int); + entry.mask = IPv6Address::from_prefix_length(temporary_int); + from_hex(next_hop, temporary); + entry.next_hop = IPv6Address((const uint8_t*)&temporary[0]); + from_hex(metric, temporary_int); + entry.metric = temporary_int; + // Process flags + from_hex(flags, temporary_int); + // Skip: + // * 0x01000000 -> cache entries + if ((temporary_int & 0x01000000) == 0) { + output.push_back(entry); + } + } + return output; +} + #endif bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) { diff --git a/tests/src/ipv6address.cpp b/tests/src/ipv6address.cpp index fad5019..a4919e2 100644 --- a/tests/src/ipv6address.cpp +++ b/tests/src/ipv6address.cpp @@ -100,3 +100,9 @@ TEST(IPv6AddressTest, IsMulticast) { EXPECT_FALSE(IPv6Address("feaa::dead").is_multicast()); } +TEST(IPv6AddressTest, FromPrefixLength) { + EXPECT_EQ(IPv6Address("ffff:fe00::"), IPv6Address::from_prefix_length(23)); + EXPECT_EQ(IPv6Address("ffff::"), IPv6Address::from_prefix_length(16)); + EXPECT_EQ(IPv6Address("ffff:ffff::"), IPv6Address::from_prefix_length(32)); +} +