From ad71158268f99dcded6dfedd85994fc17c45b8c5 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Wed, 2 Mar 2016 21:13:50 -0800 Subject: [PATCH] Add IPv6 addresses to NetworkInterface::Info --- examples/interfaces_info.cpp | 30 ++++++++--- include/tins/network_interface.h | 10 ++++ src/network_interface.cpp | 85 +++++++++++++++++++++----------- 3 files changed, 90 insertions(+), 35 deletions(-) diff --git a/examples/interfaces_info.cpp b/examples/interfaces_info.cpp index e2db82c..3bcc326 100644 --- a/examples/interfaces_info.cpp +++ b/examples/interfaces_info.cpp @@ -29,12 +29,14 @@ #include #include +#include #include using std::cout; using std::wcout; using std::endl; using std::string; +using std::ostringstream; using namespace Tins; @@ -59,11 +61,27 @@ int main() { #endif // _WIN32 cout << ": " << endl; - cout << " HW address: " << info.hw_addr << endl - << " IP address: " << info.ip_addr << endl - << " Netmask: " << info.netmask << endl - << " Broadcast: " << info.bcast_addr << endl - << " Iface index: " << iface.id() << endl - << " Status: " << "interface " << status << endl << endl; + string ipv6_string; + if (info.ipv6_addrs.empty()) { + ipv6_string = "(none)"; + } + else { + ostringstream oss; + for (size_t i = 0; i < info.ipv6_addrs.size(); ++i) { + const NetworkInterface::IPv6AddressPrefix& prefix = info.ipv6_addrs[i]; + if (i > 0) { + oss << ", "; + } + oss << prefix.address << "/" << prefix.prefix_length; + } + ipv6_string = oss.str(); + } + cout << " HW address: " << info.hw_addr << endl + << " IP address: " << info.ip_addr << endl + << " IPv6 addresses: " << ipv6_string << endl + << " Netmask: " << info.netmask << endl + << " Broadcast: " << info.bcast_addr << endl + << " Iface index: " << iface.id() << endl + << " Status: " << "interface " << status << endl << endl; } } \ No newline at end of file diff --git a/include/tins/network_interface.h b/include/tins/network_interface.h index 1cade50..606760f 100644 --- a/include/tins/network_interface.h +++ b/include/tins/network_interface.h @@ -36,6 +36,7 @@ #include "macros.h" #include "hw_address.h" #include "ip_address.h" +#include "ipv6_address.h" namespace Tins { @@ -55,11 +56,20 @@ public: */ typedef HWAddress<6> address_type; + /** + * + */ + struct IPv6AddressPrefix { + IPv6Address address; + uint32_t prefix_length; + }; + /** * \brief Struct that holds an interface's addresses. */ struct Info { IPv4Address ip_addr, netmask, bcast_addr; + std::vector ipv6_addrs; address_type hw_addr; bool is_up; }; diff --git a/src/network_interface.cpp b/src/network_interface.cpp index 04b1403..3ec8904 100644 --- a/src/network_interface.cpp +++ b/src/network_interface.cpp @@ -45,6 +45,7 @@ #include #else #include + #include #include #undef interface #endif @@ -75,37 +76,32 @@ struct InterfaceInfoCollector { using Tins::Endian::host_to_be; using Tins::IPv4Address; #if defined(BSD) || defined(__FreeBSD_kernel__) + #define TINS_BROADCAST_ADDR(addr) (addr->ifa_dstaddr) 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); found_hw = true; } - else if (addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) { - info->ip_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr); - info->netmask = IPv4Address(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr); - if ((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT))) { - info->bcast_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_dstaddr)->sin_addr.s_addr); - } - else { - info->bcast_addr = 0; - } - info->is_up = (addr->ifa_flags & IFF_UP); - found_ip = true; - } #else + #define TINS_BROADCAST_ADDR(addr) (addr->ifa_broadaddr) const struct sockaddr_ll* addr_ptr = ((struct sockaddr_ll*)addr->ifa_addr); - if (addr->ifa_addr) { - if (addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) { - info->hw_addr = addr_ptr->sll_addr; - found_hw = true; - } - else if (addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) { + if (!addr->ifa_addr) { + return false; + } + if (addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) { + info->hw_addr = addr_ptr->sll_addr; + found_hw = true; + } + #endif + else if (!std::strcmp(addr->ifa_name, iface_name)) { + if (addr->ifa_addr->sa_family == AF_INET) { info->ip_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr); info->netmask = IPv4Address(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr); if ((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT))) { - info->bcast_addr = IPv4Address(((struct sockaddr_in *)addr->ifa_broadaddr)->sin_addr.s_addr); + info->bcast_addr = IPv4Address( + ((struct sockaddr_in *)TINS_BROADCAST_ADDR(addr))->sin_addr.s_addr); } else { info->bcast_addr = 0; @@ -113,9 +109,29 @@ struct InterfaceInfoCollector { info->is_up = (addr->ifa_flags & IFF_UP); found_ip = true; } + else if (addr->ifa_addr->sa_family == AF_INET6) { + Tins::NetworkInterface::IPv6AddressPrefix prefix; + prefix.address = ((struct sockaddr_in6 *)addr->ifa_addr)->sin6_addr.s6_addr; + Tins::IPv6Address mask = ((struct sockaddr_in6 *)addr->ifa_netmask)->sin6_addr.s6_addr; + prefix.prefix_length = 0; + for (Tins::IPv6Address::iterator iter = mask.begin(); iter != mask.end(); ++iter) { + if (*iter == 255) { + prefix.prefix_length += 8; + } + else { + uint8_t current_value = 128; + while (*iter > 0) { + prefix.prefix_length += 1; + *iter &= ~current_value; + current_value /= 2; + } + break; + } + } + info->ipv6_addrs.push_back(prefix); + } } - #endif - + #undef TINS_BROADCAST_ADDR return found_ip && found_hw; } #else // _WIN32 @@ -124,14 +140,25 @@ struct InterfaceInfoCollector { using Tins::Endian::host_to_be; if (iface_id == uint32_t(iface->IfIndex)) { copy(iface->PhysicalAddress, iface->PhysicalAddress + 6, info->hw_addr.begin()); - const IP_ADAPTER_UNICAST_ADDRESS* unicast = iface->FirstUnicastAddress; - if (unicast) { - info->ip_addr = IPv4Address(((const struct sockaddr_in *)unicast->Address.lpSockaddr)->sin_addr.s_addr); - info->netmask = IPv4Address(host_to_be(0xffffffff << (32 - unicast->OnLinkPrefixLength))); - info->bcast_addr = IPv4Address((info->ip_addr & info->netmask) | ~info->netmask); - info->is_up = (iface->Flags & IP_ADAPTER_IPV4_ENABLED) != 0; - found_ip = true; - found_hw = true; + found_hw = true; + IP_ADAPTER_UNICAST_ADDRESS* unicast = iface->FirstUnicastAddress; + while (unicast) { + int family = ((const struct sockaddr*)unicast->Address.lpSockaddr)->sa_family; + if (family == AF_INET) { + info->ip_addr = IPv4Address(((const struct sockaddr_in *)unicast->Address.lpSockaddr)->sin_addr.s_addr); + info->netmask = IPv4Address(host_to_be(0xffffffff << (32 - unicast->OnLinkPrefixLength))); + info->bcast_addr = IPv4Address((info->ip_addr & info->netmask) | ~info->netmask); + info->is_up = (iface->Flags & IP_ADAPTER_IPV4_ENABLED) != 0; + found_ip = true; + } + else if (family == AF_INET6) { + Tins::NetworkInterface::IPv6AddressPrefix prefix; + prefix.address = ((const struct sockaddr_in6 *)unicast->Address.lpSockaddr)->sin6_addr.s6_addr; + prefix.prefix_length = unicast->OnLinkPrefixLength; + info->ipv6_addrs.push_back(prefix); + found_ip = true; + } + unicast = unicast->Next; } } return found_ip && found_hw;