NetworkInterface::Map NetworkInterface::get_interfaces_map() { Map result{}; auto ifaces = get_ifaddrs(); for (auto* ifa = ifaces.get(); ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) { continue; } const auto family = ifa->ifa_addr->sa_family; if (AF_PACKET == family || AF_INET == family #ifdef NET_HAVE_IPv6 || AF_INET6 == family #endif ) { const auto index = ::if_nametoindex(ifa->ifa_name); auto it = result.find(index); if (it == result.end()) { it = result.emplace_hint(it, index, NetworkInterface(iface_from_ifaddrs(index, ifa))); } if (AF_PACKET == family) { continue; } if (it != result.end()) { it->second.m_impl->add_address(address_from_ifaddrs(ifa)); } } } return result; }
std::vector<ip_interface> enum_net_interfaces(io_service& ios, error_code& ec) { std::vector<ip_interface> ret; #if TORRENT_USE_IFADDRS int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { ec = error_code(errno, asio::error::system_category); return ret; } ifaddrs *ifaddr; if (getifaddrs(&ifaddr) == -1) { ec = error_code(errno, asio::error::system_category); close(s); return ret; } for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr == 0) continue; if ((ifa->ifa_flags & IFF_UP) == 0) continue; int family = ifa->ifa_addr->sa_family; if (family == AF_INET #if TORRENT_USE_IPV6 || family == AF_INET6 #endif ) { ip_interface iface; if (iface_from_ifaddrs(ifa, iface, ec)) { ifreq req; memset(&req, 0, sizeof(req)); // -1 to leave a null terminator strncpy(req.ifr_name, iface.name, IF_NAMESIZE - 1); if (ioctl(s, SIOCGIFMTU, &req) < 0) { continue; } iface.mtu = req.ifr_mtu; ret.push_back(iface); } } } close(s); freeifaddrs(ifaddr); // MacOS X, BSD and solaris #elif TORRENT_USE_IFCONF int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { ec = error_code(errno, asio::error::system_category); return ret; } ifconf ifc; // make sure the buffer is aligned to hold ifreq structs ifreq buf[40]; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = (char*)buf; if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { ec = error_code(errno, asio::error::system_category); close(s); return ret; } char *ifr = (char*)ifc.ifc_req; int remaining = ifc.ifc_len; while (remaining > 0) { ifreq const& item = *reinterpret_cast<ifreq*>(ifr); #ifdef _SIZEOF_ADDR_IFREQ int current_size = _SIZEOF_ADDR_IFREQ(item); #elif defined TORRENT_BSD int current_size = item.ifr_addr.sa_len + IFNAMSIZ; #else int current_size = sizeof(ifreq); #endif if (remaining < current_size) break; if (item.ifr_addr.sa_family == AF_INET #if TORRENT_USE_IPV6 || item.ifr_addr.sa_family == AF_INET6 #endif ) { ip_interface iface; iface.interface_address = sockaddr_to_address(&item.ifr_addr); strcpy(iface.name, item.ifr_name); ifreq req; memset(&req, 0, sizeof(req)); // -1 to leave a null terminator strncpy(req.ifr_name, item.ifr_name, IF_NAMESIZE - 1); if (ioctl(s, SIOCGIFMTU, &req) < 0) { ec = error_code(errno, asio::error::system_category); close(s); return ret; } #ifndef TORRENT_OS2 iface.mtu = req.ifr_mtu; #else iface.mtu = req.ifr_metric; // according to tcp/ip reference #endif memset(&req, 0, sizeof(req)); strncpy(req.ifr_name, item.ifr_name, IF_NAMESIZE - 1); if (ioctl(s, SIOCGIFNETMASK, &req) < 0) { #if TORRENT_USE_IPV6 if (iface.interface_address.is_v6()) { // this is expected to fail (at least on MacOS X) iface.netmask = address_v6::any(); } else #endif { ec = error_code(errno, asio::error::system_category); close(s); return ret; } } else { iface.netmask = sockaddr_to_address(&req.ifr_addr, item.ifr_addr.sa_family); } ret.push_back(iface); } ifr += current_size; remaining -= current_size; } close(s); #elif TORRENT_USE_GETADAPTERSADDRESSES #if _WIN32_WINNT >= 0x0501 // Load Iphlpapi library HMODULE iphlp = LoadLibraryA("Iphlpapi.dll"); if (iphlp) { // Get GetAdaptersAddresses() pointer typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG,ULONG,PVOID,PIP_ADAPTER_ADDRESSES,PULONG); GetAdaptersAddresses_t GetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress( iphlp, "GetAdaptersAddresses"); if (GetAdaptersAddresses) { PIP_ADAPTER_ADDRESSES adapter_addresses = 0; ULONG out_buf_size = 0; if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST, NULL, adapter_addresses, &out_buf_size) != ERROR_BUFFER_OVERFLOW) { FreeLibrary(iphlp); ec = asio::error::operation_not_supported; return std::vector<ip_interface>(); } adapter_addresses = (IP_ADAPTER_ADDRESSES*)malloc(out_buf_size); if (!adapter_addresses) { FreeLibrary(iphlp); ec = asio::error::no_memory; return std::vector<ip_interface>(); } if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST, NULL, adapter_addresses, &out_buf_size) == NO_ERROR) { for (PIP_ADAPTER_ADDRESSES adapter = adapter_addresses; adapter != 0; adapter = adapter->Next) { ip_interface r; strncpy(r.name, adapter->AdapterName, sizeof(r.name)); r.name[sizeof(r.name)-1] = 0; r.mtu = adapter->Mtu; IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; while (unicast) { r.interface_address = sockaddr_to_address(unicast->Address.lpSockaddr); ret.push_back(r); unicast = unicast->Next; } } } // Free memory free(adapter_addresses); FreeLibrary(iphlp); return ret; } FreeLibrary(iphlp); } #endif SOCKET s = socket(AF_INET, SOCK_DGRAM, 0); if (s == SOCKET_ERROR) { ec = error_code(WSAGetLastError(), asio::error::system_category); return ret; } INTERFACE_INFO buffer[30]; DWORD size; if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer, sizeof(buffer), &size, 0, 0) != 0) { ec = error_code(WSAGetLastError(), asio::error::system_category); closesocket(s); return ret; } closesocket(s); int n = size / sizeof(INTERFACE_INFO); ip_interface iface; for (int i = 0; i < n; ++i) { iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address); if (iface.interface_address == address_v4::any()) continue; iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address , iface.interface_address.is_v4() ? AF_INET : AF_INET6); iface.name[0] = 0; iface.mtu = 1500; // how to get the MTU? ret.push_back(iface); } #else #warning THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK // make a best guess of the interface we're using and its IP udp::resolver r(ios); udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"), ec); if (ec) return ret; ip_interface iface; for (;i != udp::resolver_iterator(); ++i) { iface.interface_address = i->endpoint().address(); iface.mtu = 1500; if (iface.interface_address.is_v4()) iface.netmask = address_v4::netmask(iface.interface_address.to_v4()); ret.push_back(iface); } #endif return ret; }