From 42b6c404339c5ff76897c38df4c246ad6e1aa8c8 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Mon, 7 Mar 2016 19:40:38 -0800 Subject: [PATCH] Add Utils::route6_entries on OSX/BSD --- examples/route_table.cpp | 31 +++++++--- include/tins/utils.h | 2 +- src/utils.cpp | 123 ++++++++++++++++++++++++++++++--------- 3 files changed, 121 insertions(+), 35 deletions(-) diff --git a/examples/route_table.cpp b/examples/route_table.cpp index 49f22be..f6c58ce 100644 --- a/examples/route_table.cpp +++ b/examples/route_table.cpp @@ -40,13 +40,30 @@ using std::vector; using namespace Tins; int main() { - vector entries = Utils::route_entries(); - for (size_t i = 0; i < entries.size(); ++i) { + vector v4_entries = Utils::route_entries(); + cout << "IPv4 route table entries: " << endl + << "========================= " << endl; + for (size_t i = 0; i < v4_entries.size(); ++i) { cout << "Entry " << setw(2) << i << ": " << endl - << "Interface: " << entries[i].interface << endl - << "Destination: " << entries[i].destination << endl - << "Gateway: " << entries[i].gateway << endl - << "Genmask: " << entries[i].mask << endl - << "Metric: " << entries[i].metric << endl << endl; + << "Interface: " << v4_entries[i].interface << endl + << "Destination: " << v4_entries[i].destination << endl + << "Gateway: " << v4_entries[i].gateway << endl + << "Genmask: " << v4_entries[i].mask << endl + << "Metric: " << v4_entries[i].metric << endl << endl; + } + + vector v6_entries = Utils::route6_entries(); + if (!v6_entries.empty()) { + cout << endl + << "IPv6 route table entries: " << endl + << "========================= " << endl; + for (size_t i = 0; i < v6_entries.size(); ++i) { + cout << "Entry " << setw(2) << i << ": " << endl + << "Interface: " << v6_entries[i].interface << endl + << "Destination: " << v6_entries[i].destination << endl + << "Gateway: " << v6_entries[i].gateway << endl + << "Genmask: " << v6_entries[i].mask << endl + << "Metric: " << v6_entries[i].metric << endl << endl; + } } } \ No newline at end of file diff --git a/include/tins/utils.h b/include/tins/utils.h index 3e46abf..2d5b709 100644 --- a/include/tins/utils.h +++ b/include/tins/utils.h @@ -112,7 +112,7 @@ struct Route6Entry { /** * This route entry's next hop. */ - IPv6Address next_hop; + IPv6Address gateway; /** * This route entry's metric. diff --git a/src/utils.cpp b/src/utils.cpp index 86e0a56..3be76ed 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -110,7 +110,7 @@ addrinfo* resolve_domain(const string& to_resolve, int family) { } #if defined(BSD) || defined(__FreeBSD_kernel__) -vector query_route_table() { +vector query_route_table(int family) { int mib[6]; vector buf; size_t len; @@ -118,7 +118,7 @@ vector query_route_table() { mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; - mib[3] = AF_INET; + mib[3] = family; mib[4] = NET_RT_DUMP; mib[5] = 0; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { @@ -133,20 +133,19 @@ vector query_route_table() { return buf; } -template -void parse_header(struct rt_msghdr* rtm, ForwardIterator iter) { +void parse_header(struct rt_msghdr* rtm, vector& addrs) { char* ptr = (char *)(rtm + 1); - sockaddr* sa = 0; - - for (int i = 0; i < RTAX_MAX; i++) { - if (rtm->rtm_addrs & (1 << i)) { + // Iterate from RTA_DST (0) to RTA_NETMASK (2) + for (int i = 0; i < 3; ++i) { + sockaddr* sa = 0; + if ((rtm->rtm_addrs & (1 << i)) != 0) { sa = (struct sockaddr *)ptr; ptr += sa->sa_len; if (sa->sa_family == 0) { sa = 0; } } - *iter++ = sa; + addrs[i] = sa; } } #endif @@ -194,27 +193,94 @@ HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender) { vector route_entries() { vector output; - vector buffer = query_route_table(); + vector buffer = query_route_table(AF_INET); char* next = &buffer[0], *end = &buffer[buffer.size()]; rt_msghdr* rtm; - vector sa(RTAX_MAX); + vector sa(32); char iface_name[IF_NAMESIZE]; while (next < end) { rtm = (rt_msghdr*)next; - parse_header(rtm, sa.begin()); - if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) { - RouteEntry entry; - entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr); - entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr); - if (sa[RTAX_GENMASK]) { - entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_GENMASK])->sin_addr.s_addr); + // Filter: + // * RTF_STATIC (only manually added routes) + if ((rtm->rtm_flags & (RTF_STATIC)) != 0) { + parse_header(rtm, sa); + if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) { + RouteEntry entry; + entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr); + entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr); + if (sa[RTAX_NETMASK]) { + entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr.s_addr); + } + entry.interface = iface_name; + entry.metric = 0; + output.push_back(entry); } - else { - entry.mask = IPv4Address(uint32_t()); + } + next += rtm->rtm_msglen; + } + return output; +} + +vector route6_entries() { + vector output; + vector buffer = query_route_table(AF_INET6); + char* next = &buffer[0], *end = &buffer[buffer.size()]; + rt_msghdr* rtm; + vector sa(9); + char iface_name[IF_NAMESIZE]; + while (next < end) { + rtm = (rt_msghdr*)next; + // Filter protocol-cloned entries + if ((rtm->rtm_flags & RTF_WASCLONED) == 0 || (rtm->rtm_flags & RTF_PRCLONING) == 0) { + parse_header(rtm, sa); + if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) { + Route6Entry entry; + entry.destination = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_DST])->sin6_addr.s6_addr); + entry.gateway = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_GATEWAY])->sin6_addr.s6_addr); + int prefix_length = 0; + if (sa[RTAX_NETMASK]) { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa[RTAX_NETMASK]; + for (size_t i = 0; i < 16; ++i) { + uint8_t this_byte = sin->sin6_addr.s6_addr[i]; + // Stop when we find a zero byte + if (this_byte == 0) { + break; + } + switch (this_byte) { + case 0xff: + prefix_length += 8; + break; + case 0xfe: + prefix_length += 7; + break; + case 0xfc: + prefix_length += 6; + break; + case 0xf8: + prefix_length += 5; + break; + case 0xf0: + prefix_length += 4; + break; + case 0xe0: + prefix_length += 3; + break; + case 0xc0: + prefix_length += 2; + break; + case 0x80: + prefix_length += 1; + break; + default: + break; + } + } + } + entry.mask = IPv6Address::from_prefix_length(prefix_length); + entry.interface = iface_name; + entry.metric = 0; + output.push_back(entry); } - entry.interface = iface_name; - entry.metric = 0; - output.push_back(entry); } next += rtm->rtm_msglen; } @@ -225,9 +291,12 @@ vector route_entries() { vector route_entries() { vector output; - MIB_IPFORWARDTABLE table; + MIB_IPFORWARDTABLE* table; ULONG size = 0; - GetIpForwardTable(AF_INET6, &table); + GetIpForwardTable(0, &size, 0); + vector buffer(size); + table = (MIB_IPFORWARDTABLE*)&buffer[0]; + GetIpForwardTable(table, &size, 0); for (DWORD i = 0; i < table->dwNumEntries; i++) { MIB_IPFORWARDROW* row = &table->table[i]; @@ -257,7 +326,7 @@ vector route6_entries() { 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.gateway = IPv6Address(row->NextHop.Ipv6.sin6_addr.s6_addr); entry.metric = row->Metric; output.push_back(entry); } @@ -322,7 +391,7 @@ vector route6_entries() { 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]); + entry.gateway = IPv6Address((const uint8_t*)&temporary[0]); from_hex(metric, temporary_int); entry.metric = temporary_int; // Process flags