#include #include #include #include #include #include #include #include #include #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "iphlpapi.lib") struct LocalNet { uint32_t ip = 0; uint32_t mask = 0; bool found = false; }; static LocalNet find_local_net() { LocalNet net; ULONG size = 0; GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &size); std::vector buf(size); IP_ADAPTER_ADDRESSES* addrs = reinterpret_cast(buf.data()); if (GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, addrs, &size) != NO_ERROR) { return net; } for (IP_ADAPTER_ADDRESSES* a = addrs; a != nullptr; a = a->Next) { if (a->OperStatus != IfOperStatusUp) continue; if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue; for (IP_ADAPTER_UNICAST_ADDRESS* ua = a->FirstUnicastAddress; ua != nullptr; ua = ua->Next) { sockaddr_in* sin = reinterpret_cast(ua->Address.lpSockaddr); uint32_t ip = ntohl(sin->sin_addr.s_addr); if ((ip >> 24) == 127) continue; uint8_t prefix = ua->OnLinkPrefixLength; if (prefix == 0 || prefix > 32) continue; uint32_t mask = prefix == 32 ? 0xFFFFFFFFu : (~0u << (32 - prefix)); net.ip = ip; net.mask = mask; net.found = true; return net; } } return net; } static std::mutex out_mutex; static void probe(uint32_t ip_host_order) { uint32_t target = htonl(ip_host_order); uint8_t mac[6]; ULONG mac_len = 6; DWORD res = SendARP(target, 0, mac, &mac_len); if (res != NO_ERROR) return; in_addr addr{}; addr.s_addr = target; char ipstr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &addr, ipstr, sizeof(ipstr)); char macstr[32]; snprintf(macstr, sizeof(macstr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); std::lock_guard lock(out_mutex); std::cout << ipstr << "\t" << macstr << std::endl; } int main() { WSADATA wsa; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { std::cerr << "WSAStartup failed" << std::endl; return 1; } LocalNet net = find_local_net(); if (!net.found) { std::cerr << "no local ipv4 network found" << std::endl; WSACleanup(); return 1; } uint32_t network = net.ip & net.mask; uint32_t broadcast = network | ~net.mask; uint32_t host_count = broadcast - network; if (host_count == 0 || host_count > 65534) { std::cerr << "subnet too big or too small to scan (" << host_count << " hosts)" << std::endl; WSACleanup(); return 1; } in_addr netaddr{}; netaddr.s_addr = htonl(network); char netstr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &netaddr, netstr, sizeof(netstr)); std::cout << "scanning " << netstr << "/" << host_count << " hosts..." << std::endl; std::vector threads; for (uint32_t ip = network + 1; ip < broadcast; ++ip) { threads.emplace_back(probe, ip); if (threads.size() >= 64) { for (auto& t : threads) t.join(); threads.clear(); } } for (auto& t : threads) t.join(); WSACleanup(); return 0; }