117 lines
3.4 KiB
C++
117 lines
3.4 KiB
C++
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <windows.h>
|
|
#include <iphlpapi.h>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <thread>
|
|
#include <mutex>
|
|
#include <cstdio>
|
|
|
|
#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<uint8_t> buf(size);
|
|
IP_ADAPTER_ADDRESSES* addrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(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<sockaddr_in*>(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<std::mutex> 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<std::thread> 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;
|
|
}
|