diff --git a/include/tins/utils.h b/include/tins/utils.h index e3fcaf4..7c33c66 100644 --- a/include/tins/utils.h +++ b/include/tins/utils.h @@ -30,38 +30,22 @@ #ifndef TINS_UTILS_H #define TINS_UTILS_H -#ifndef _WIN32 - #include -#else - #include - #include - #undef interface - #include "network_interface.h" -#endif #include "macros.h" -#if defined(BSD) || defined(__FreeBSD_kernel__) - #include - #include - #include - - #include - #include - #include -#endif #include #include -#include #include #include #include "ip_address.h" -#include "ipv6_address.h" -#include "hw_address.h" #include "internals.h" namespace Tins { + class NetworkInterface; class PacketSender; class PDU; +class IPv6Address; +template +class HWAddress; /** * \brief Network utils namespace. @@ -71,8 +55,9 @@ class PDU; * interface listing, etc. */ namespace Utils { + /** - * Struct that represents an entry in /proc/net/route + * Struct that represents an entry the routing table */ struct RouteEntry { /** @@ -266,46 +251,6 @@ TINS_API uint32_t pseudoheader_checksum(IPv6Address source_ip, uint16_t len, uint16_t flag); -/** \brief Generic function to iterate through interface and collect - * data. - * - * The parameter is applied to every interface found, allowing - * the object to collect data from them. - * \param functor An instance of an class which implements operator(struct ifaddrs*). - */ -#ifndef _WIN32 -template -void generic_iface_loop(Functor& functor) { - struct ifaddrs* ifaddrs = 0; - struct ifaddrs* if_it = 0; - getifaddrs(&ifaddrs); - for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) { - if (functor(if_it)) { - break; - } - } - if (ifaddrs) { - freeifaddrs(ifaddrs); - } -} -#else // _WIN32 -template -void generic_iface_loop(Functor& functor) { - ULONG size; - ::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size); - std::vector buffer(size); - if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) { - PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0]; - while (iface) { - if (functor(iface)) { - break; - } - iface = iface->Next; - } - } -} -#endif // _WIN32 - template struct is_pdu { template @@ -338,130 +283,16 @@ dereference_until_pdu(T& value) { return dereference_until_pdu(*value); } -#if defined(BSD) || defined(__FreeBSD_kernel__) -inline std::vector query_route_table() { - int mib[6]; - std::vector buf; - size_t len; - - mib[0] = CTL_NET; - mib[1] = AF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { - throw std::runtime_error("sysctl failed"); - } - - buf.resize(len); - if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) { - throw std::runtime_error("sysctl failed"); - } - - return buf; -} - -template -void parse_header(struct rt_msghdr* rtm, ForwardIterator iter) { - char* ptr = (char *)(rtm + 1); - sockaddr* sa = 0; - - for (int i = 0; i < RTAX_MAX; i++) { - if (rtm->rtm_addrs & (1 << i)) { - sa = (struct sockaddr *)ptr; - ptr += sa->sa_len; - if (sa->sa_family == 0) { - sa = 0; - } - } - *iter++ = sa; - } -} -#endif - } // Utils } // Tins -#if defined(BSD) || defined(__FreeBSD_kernel__) template void Tins::Utils::route_entries(ForwardIterator output) { - std::vector buffer = query_route_table(); - char* next = &buffer[0], *end = &buffer[buffer.size()]; - rt_msghdr* rtm; - std::vector sa(RTAX_MAX); - 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); - } - else { - entry.mask = IPv4Address(uint32_t()); - } - entry.interface = iface_name; - entry.metric = 0; - *output++ = entry; - } - next += rtm->rtm_msglen; - } -} -#elif defined(_WIN32) -template -void Tins::Utils::route_entries(ForwardIterator output) { - MIB_IPFORWARDTABLE* table; - ULONG size = 0; - GetIpForwardTable(0, &size, 0); - std::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]; - if (row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT || - row->dwForwardType == MIB_IPROUTE_TYPE_DIRECT) { - RouteEntry entry; - entry.interface = NetworkInterface::from_index(row->dwForwardIfIndex).name(); - entry.destination = IPv4Address(row->dwForwardDest); - entry.mask = IPv4Address(row->dwForwardMask); - entry.gateway = IPv4Address(row->dwForwardNextHop); - entry.metric = row->dwForwardMetric1; - *output++ = entry; - } - } -} -#else -template -void Tins::Utils::route_entries(ForwardIterator output) { - using namespace Tins::Internals; - std::ifstream input("/proc/net/route"); - std::string destination, mask, metric, gw; - uint32_t dummy; - skip_line(input); - RouteEntry entry; - while (input >> entry.interface >> destination >> gw) { - for (unsigned i(0); i < 4; ++i) { - input >> metric; - } - input >> mask; - from_hex(destination, dummy); - entry.destination = IPv4Address(dummy); - from_hex(mask, dummy); - entry.mask = IPv4Address(dummy); - from_hex(gw, dummy); - entry.gateway = IPv4Address(dummy); - from_hex(metric, dummy); - entry.metric = dummy; - skip_line(input); - *output = entry; + std::vector entries = route_entries(); + for (size_t i = 0; i < entries.size(); ++i) { + *output = entries[i]; ++output; } } -#endif #endif // TINS_UTILS_H diff --git a/src/network_interface.cpp b/src/network_interface.cpp index a56c000..55d0b18 100644 --- a/src/network_interface.cpp +++ b/src/network_interface.cpp @@ -40,10 +40,11 @@ #else #include #endif + #include #include #else #include - #include + #include #endif #include "network_interface.h" #include "utils.h" @@ -76,7 +77,7 @@ struct InterfaceInfoCollector { const struct sockaddr_dl* addr_ptr = ((struct sockaddr_dl*)addr->ifa_addr); if (addr->ifa_addr->sa_family == AF_LINK && addr_ptr->sdl_index == iface_id) { - info->hw_addr = (const uint8_t*)LLADDR(addr_ptr); // mmmm + info->hw_addr = (const uint8_t*)LLADDR(addr_ptr); found_hw = true; } else if (addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) { @@ -253,7 +254,33 @@ NetworkInterface::Info NetworkInterface::info() const { Info info; InterfaceInfoCollector collector(&info, iface_id_, iface_name.c_str()); info.is_up = false; - Utils::generic_iface_loop(collector); + + #ifdef _WIN32 + + ULONG size; + ::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size); + std::vector buffer(size); + if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) { + PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0]; + while (iface) { + collector(iface); + iface = iface->Next; + } + } + + #else // _WIN32 + + struct ifaddrs* ifaddrs = 0; + struct ifaddrs* if_it = 0; + getifaddrs(&ifaddrs); + for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) { + collector(if_it); + } + if (ifaddrs) { + freeifaddrs(ifaddrs); + } + + #endif // _WIN32 // If we didn't even get the hw address or ip address, this went wrong if (!collector.found_hw && !collector.found_ip) { diff --git a/src/utils.cpp b/src/utils.cpp index 52fcdb8..b7bcc21 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -31,15 +31,21 @@ #include #include #include +#include #include "utils.h" #ifndef _WIN32 #if defined(BSD) || defined(__FreeBSD_kernel__) #include - #include + #include + #include + #include #include + #include + #include #else #include #endif + #include #include #include #ifdef __ANDROID_API__ @@ -47,7 +53,10 @@ #include #endif #else + #include + #include #include + #undef interface #endif #include "pdu.h" #include "arp.h" @@ -56,10 +65,12 @@ #include "network_interface.h" #include "packet_sender.h" #include "cxxstd.h" +#include "hw_address.h" #include "memory_helpers.h" using std::string; using std::set; +using std::ifstream; using std::vector; using std::back_inserter; using std::runtime_error; @@ -97,6 +108,48 @@ addrinfo* resolve_domain(const string& to_resolve, int family) { } } +#if defined(BSD) || defined(__FreeBSD_kernel__) +vector query_route_table() { + int mib[6]; + vector buf; + size_t len; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + throw runtime_error("sysctl failed"); + } + + buf.resize(len); + if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) { + throw runtime_error("sysctl failed"); + } + + return buf; +} + +template +void parse_header(struct rt_msghdr* rtm, ForwardIterator iter) { + char* ptr = (char *)(rtm + 1); + sockaddr* sa = 0; + + for (int i = 0; i < RTAX_MAX; i++) { + if (rtm->rtm_addrs & (1 << i)) { + sa = (struct sockaddr *)ptr; + ptr += sa->sa_len; + if (sa->sa_family == 0) { + sa = 0; + } + } + *iter++ = sa; + } +} +#endif + namespace Tins { /** \endcond */ @@ -136,11 +189,88 @@ HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender) { return resolve_hwaddr(sender.default_interface(), ip, sender); } +#if defined(BSD) || defined(__FreeBSD_kernel__) vector route_entries() { - vector entries; - route_entries(back_inserter(entries)); - return entries; + vector output; + vector buffer = query_route_table(); + char* next = &buffer[0], *end = &buffer[buffer.size()]; + rt_msghdr* rtm; + vector sa(RTAX_MAX); + 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); + } + else { + entry.mask = IPv4Address(uint32_t()); + } + entry.interface = iface_name; + entry.metric = 0; + output.push_back(entry); + } + next += rtm->rtm_msglen; + } + return output; } +#elif defined(_WIN32) +vector route_entries() { + vector output; + MIB_IPFORWARDTABLE* table; + ULONG size = 0; + 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]; + if (row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT || + row->dwForwardType == MIB_IPROUTE_TYPE_DIRECT) { + RouteEntry entry; + entry.interface = NetworkInterface::from_index(row->dwForwardIfIndex).name(); + entry.destination = IPv4Address(row->dwForwardDest); + entry.mask = IPv4Address(row->dwForwardMask); + entry.gateway = IPv4Address(row->dwForwardNextHop); + entry.metric = row->dwForwardMetric1; + output.push_back(entry); + } + } + return output; +} +#else +vector route_entries() { + using namespace Tins::Internals; + vector output; + ifstream input("/proc/net/route"); + string destination, mask, metric, gw; + uint32_t dummy; + skip_line(input); + RouteEntry entry; + while (input >> entry.interface >> destination >> gw) { + for (unsigned i(0); i < 4; ++i) { + input >> metric; + } + input >> mask; + from_hex(destination, dummy); + entry.destination = IPv4Address(dummy); + from_hex(mask, dummy); + entry.mask = IPv4Address(dummy); + from_hex(gw, dummy); + entry.gateway = IPv4Address(dummy); + from_hex(metric, dummy); + entry.metric = dummy; + skip_line(input); + output.push_back(entry); + } + return output; +} +#endif bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) { typedef vector entries_type; @@ -156,11 +286,36 @@ bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) { return false; } +#ifdef _WIN32 set network_interfaces() { - InterfaceCollector collector; - generic_iface_loop(collector); - return collector.ifaces; + set output; + ULONG size; + ::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size); + std::vector buffer(size); + if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) { + PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0]; + while (iface) { + output.insert(iface->AdapterName); + iface = iface->Next; + } + } + return output; } +#else +set network_interfaces() { + set output; + struct ifaddrs* ifaddrs = 0; + struct ifaddrs* if_it = 0; + getifaddrs(&ifaddrs); + for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) { + output.insert(if_it->ifa_name); + } + if (ifaddrs) { + freeifaddrs(ifaddrs); + } + return output; +} +#endif // _WIN32 uint16_t channel_to_mhz(uint16_t channel) { return 2407 + (channel * 5);