windows下使用arp 协议

news2025/1/11 17:03:31

/
//自动扫描局域网存活主机

本程序是利用arp协议去获取局域网中的存活主机

arp协议概述

地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址

定义数据结构

这个数据结构位ip和mac对应
typedef struct s_ip_fname
{
	//一个网卡可能有多个IP地址
	std::vector<std::string> ips;
	std::string mac;
}s_ip_fname;
下面的数据结构是为了存储mac地址的
typedef struct list_nim
{
	atomic<uint32_t> v_n = 0;
	std::map<std::string,std::string> nim;
	std::mutex  mutex;
	void clear()
	{
		nim.clear();
	}
	void push(string &ip, string &mac)
	{
		mutex.lock();
		nim[mac] = ip;
		mutex.unlock();
	}
}list_nim;

获取IP地址

获取到本机的IP地址,本例子是可以获取网卡的多个IP地址

std::string main_ip()
{
	std::vector<s_ip_fname> ip_mac_vector;
	get_ipfname(ip_mac_vector);
	std::string ip;
	if (ip_mac_vector.size() == 0)
		return ip;
	auto it = ip_mac_vector.begin();
	if(it->ips.size()>0)
		ip = it->ips[0];
	return ip;
}

其中获取get_ipfname 获取ip地址列表,写成了一个静态函数,我们无论如何都要想到,一个主机不一定只有一个网卡,一个网卡不一定只有一个ip

static int get_ipfname(std::vector<s_ip_fname>& ff)
{
#define ADDR(x) pIpAdapterInfo->Address[x]
	PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
	unsigned long stSize = sizeof(IP_ADAPTER_INFO);
	int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
	DWORD netCardNum = 0;
	GetNumberOfInterfaces(&netCardNum);
	int IPnumPerNetCard = 0;
	if (ERROR_BUFFER_OVERFLOW == nRel)
	{
		delete pIpAdapterInfo;
		pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
		nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
		//return -1;
	}
	if (ERROR_SUCCESS == nRel)
	{
		//maybe we have >1 network card
		while (pIpAdapterInfo)
		{
			s_ip_fname ipf;
			switch (pIpAdapterInfo->Type)
			{
			case MIB_IF_TYPE_OTHER:
				//cout << "OTHER" << endl; 
				break;
			case MIB_IF_TYPE_ETHERNET:
				//cout << "ETHERNET" << endl; 
				break;
			case MIB_IF_TYPE_TOKENRING:
				//cout << "TOKENRING" << endl; 
				break;
			case MIB_IF_TYPE_FDDI:
				//cout << "FDDI" << endl; 
				break;
			case MIB_IF_TYPE_PPP:
				//cout << "PPP" << endl; 
				break;
			case MIB_IF_TYPE_LOOPBACK:
				//cout << "LOOPBACK" << endl; 
				break;
			case MIB_IF_TYPE_SLIP:
				//cout << "SLIP" << endl; 
				break;
			default:
				//cout << "" << endl; 
				break;
			}
			char buffer[128];
			sprintf(buffer, "%02X-%02X-%02X-%02X-%02X-%02X",
				//sprintf(buffer, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
				ADDR(0), ADDR(1), ADDR(2), ADDR(3), ADDR(4), ADDR(5));
			ipf.mac = buffer;
			IPnumPerNetCard = 0;
			//可能网卡有多IP
			IP_ADDR_STRING* pIpAddrString = &(pIpAdapterInfo->IpAddressList);
			do
			{
				ipf.ips.push_back(pIpAddrString->IpAddress.String);
				pIpAddrString = pIpAddrString->Next;

			} while (pIpAddrString);
			ff.push_back(ipf);
			pIpAdapterInfo = pIpAdapterInfo->Next;
		}
	}
	//释放内存空间
	if (pIpAdapterInfo)
	{
		delete pIpAdapterInfo;
	}
	return 0;
}

线程函数

改函数启动一个线程,去发送arp请求

	void start_thread(int tn,uint32_t ulNetName)
	{
		thread th[256];
		for (int i = 0; i < tn; i++)
		{
			th[i] = thread([this,ulNetName] {
				while (1)
				{
					uint32_t x = v_number--;
					uint32_t n = htonl(ulNetName + x + 1);
					this->send_arp(n);
					if (v_number < 0)
						break;
				}
			});
			//th.detach();
		}
		for (int i = 0; i < tn; i++)
			th[i].join();
	}

send arp 函数实际上就是调用windows的辅助函数SendARP

	void send_arp(uint32_t naddr_f)
	{
		//for (uint32_t t = naddr_f; t < naddr_t; t++)
		//{
			struct in_addr in;
			in.S_un.S_addr = naddr_f;
			string ip = inet_ntoa(in);
			std::cout << "scan:";
			std::cout << ip.c_str() << endl;
			HRESULT result;
			ULONG c[2] = { 0 }, len = 6;
			//unsigned int ipn = htonl(inet_addr(ip.c_str()));
			//发送ARP包
			result = SendARP(naddr_f, NULL, c, &len);

			if (result == NO_ERROR)
			{
				BYTE *g = (BYTE *)&c;
				if (len)
				{
					string strmac(32, 0);
					sprintf(const_cast<char*>(strmac.c_str()),
						"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
						g[0], g[1], g[2], g[3], g[4], g[5]);
					v_lnim.push(strmac, ip);

				}
			}
		//}
		//return 0;
	}

目标

//自动扫描局域网存活主机
程序清单,复制可用
/
//自动扫描局域网存活主机
//优点:不用输入ip
//缺点:如果遇到主机多IP只能扫描其中一个

#include <winsock2.h>
#include <stdio.h>
#include <iphlpapi.h>

#pragma comment (lib,"ws2_32.lib")  
#pragma comment (lib,"iphlpapi.lib")

#include <iostream>
#include <list>
#include <windows.h>
#include <thread>
#include <atomic>
#include <mutex>
#include <map>
#include <vector>
using namespace std;

typedef struct s_ip_fname
{
	//一个网卡可能有多个IP地址
	std::vector<std::string> ips;
	std::string mac;
}s_ip_fname;

typedef struct list_nim
{
	atomic<uint32_t> v_n = 0;
	std::map<std::string,std::string> nim;
	std::mutex  mutex;
	void clear()
	{
		nim.clear();
	}
	void push(string &ip, string &mac)
	{
		mutex.lock();
		nim[mac] = ip;
		mutex.unlock();
	}
}list_nim;



static int get_ipfname(std::vector<s_ip_fname>& ff)
{
#define ADDR(x) pIpAdapterInfo->Address[x]
	PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
	unsigned long stSize = sizeof(IP_ADAPTER_INFO);
	int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
	DWORD netCardNum = 0;
	GetNumberOfInterfaces(&netCardNum);
	int IPnumPerNetCard = 0;
	if (ERROR_BUFFER_OVERFLOW == nRel)
	{
		delete pIpAdapterInfo;
		pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
		nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
		//return -1;
	}
	if (ERROR_SUCCESS == nRel)
	{
		//maybe we have >1 network card
		while (pIpAdapterInfo)
		{
			s_ip_fname ipf;
			switch (pIpAdapterInfo->Type)
			{
			case MIB_IF_TYPE_OTHER:
				//cout << "OTHER" << endl; 
				break;
			case MIB_IF_TYPE_ETHERNET:
				//cout << "ETHERNET" << endl; 
				break;
			case MIB_IF_TYPE_TOKENRING:
				//cout << "TOKENRING" << endl; 
				break;
			case MIB_IF_TYPE_FDDI:
				//cout << "FDDI" << endl; 
				break;
			case MIB_IF_TYPE_PPP:
				//cout << "PPP" << endl; 
				break;
			case MIB_IF_TYPE_LOOPBACK:
				//cout << "LOOPBACK" << endl; 
				break;
			case MIB_IF_TYPE_SLIP:
				//cout << "SLIP" << endl; 
				break;
			default:
				//cout << "" << endl; 
				break;
			}
			char buffer[128];
			sprintf(buffer, "%02X-%02X-%02X-%02X-%02X-%02X",
				//sprintf(buffer, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
				ADDR(0), ADDR(1), ADDR(2), ADDR(3), ADDR(4), ADDR(5));
			ipf.mac = buffer;
			IPnumPerNetCard = 0;
			//可能网卡有多IP
			IP_ADDR_STRING* pIpAddrString = &(pIpAdapterInfo->IpAddressList);
			do
			{
				ipf.ips.push_back(pIpAddrString->IpAddress.String);
				pIpAddrString = pIpAddrString->Next;

			} while (pIpAddrString);
			ff.push_back(ipf);
			pIpAdapterInfo = pIpAdapterInfo->Next;
		}
	}
	//释放内存空间
	if (pIpAdapterInfo)
	{
		delete pIpAdapterInfo;
	}
	return 0;
}


class c_arp
{
	list_nim v_lnim;
	std::atomic<int> v_number = 0;
		
public:
	~c_arp()
	{
		v_lnim.clear();
	}
	size_t size()
	{
		return v_lnim.nim.size();
	}
	void set_max_ip(uint32_t number)
	{
		v_number = number;
	}
	void send_arp(uint32_t naddr_f)
	{
		//for (uint32_t t = naddr_f; t < naddr_t; t++)
		//{
			struct in_addr in;
			in.S_un.S_addr = naddr_f;
			string ip = inet_ntoa(in);
			std::cout << "scan:";
			std::cout << ip.c_str() << endl;
			HRESULT result;
			ULONG c[2] = { 0 }, len = 6;
			//unsigned int ipn = htonl(inet_addr(ip.c_str()));
			//发送ARP包
			result = SendARP(naddr_f, NULL, c, &len);

			if (result == NO_ERROR)
			{
				BYTE *g = (BYTE *)&c;
				if (len)
				{
					string strmac(32, 0);
					sprintf(const_cast<char*>(strmac.c_str()),
						"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
						g[0], g[1], g[2], g[3], g[4], g[5]);
					v_lnim.push(strmac, ip);

				}
			}
		//}
		//return 0;
	}


	void start_thread(int tn,uint32_t ulNetName)
	{
		thread th[256];
		for (int i = 0; i < tn; i++)
		{
			th[i] = thread([this,ulNetName] {
				while (1)
				{
					uint32_t x = v_number--;
					uint32_t n = htonl(ulNetName + x + 1);
					this->send_arp(n);
					if (v_number < 0)
						break;
				}
			});
			//th.detach();
		}
		for (int i = 0; i < tn; i++)
			th[i].join();
	}
	void print()
	{
		for (auto iter : v_lnim.nim)
		{
			std::cout << iter.first.c_str() << ":" << iter.second.c_str() << endl;
		}
	}
};



std::string main_ip()
{
	std::vector<s_ip_fname> ip_mac_vector;
	get_ipfname(ip_mac_vector);
	std::string ip;
	if (ip_mac_vector.size() == 0)
		return ip;
	auto it = ip_mac_vector.begin();
	if(it->ips.size()>0)
		ip = it->ips[0];
	return ip;
}
int main()
{
	// 初始化socket
	WSADATA data;
	WORD wVersion = MAKEWORD(2, 2);
	WSAStartup(wVersion, &data);


	hostent *pLocalHost;
//	HANDLE hEvent;

	// 获得本机IP结构
	pLocalHost = ::gethostbyname("");
	std::string ip = main_ip();

	

	// 这样获得是网络字节序
	//ULONG ulIpAddress = (*(struct in_addr *)*(pLocalHost->h_addr_list)).S_un.S_addr;
	ULONG ulIpAddress = inet_addr(ip.c_str());

	PIP_ADAPTER_INFO pAdapterInfo = NULL;
	ULONG ulLen = 0;

	// 为适配器结构申请内存
	::GetAdaptersInfo(pAdapterInfo, &ulLen);
	pAdapterInfo = (PIP_ADAPTER_INFO)::GlobalAlloc(GPTR, ulLen);


	c_arp arp;
	if (::GetAdaptersInfo(pAdapterInfo, &ulLen) == ERROR_SUCCESS)
	{
		while (pAdapterInfo != NULL)
		{
			if(ip.compare(pAdapterInfo->IpAddressList.IpAddress.String) == 0)
			//if (::inet_addr(pAdapterInfo->IpAddressList.IpAddress.String) == ulIpAddress)
			{
				// 这里要转换为主机字节序
				ULONG ulIpMask = ntohl(::inet_addr(pAdapterInfo->IpAddressList.IpMask.String));
				// 与获得网络号
				ULONG ulNetName = ntohl(ulIpAddress) & ulIpMask;
				//获得网段内的主机数
				UINT unNum = ~ulIpMask;
				UINT nNumofHost = unNum - 2;
				arp.set_max_ip(nNumofHost);
				//arp.start_thread(255,ulNetName);
				for (uint32_t i = 0; i < nNumofHost; i++)
				{
					uint32_t n = htonl(ulNetName + i + 1);
					thread th(std::bind(&c_arp::send_arp, &arp, n));
					th.detach();
				}
				break;
			}
			pAdapterInfo = pAdapterInfo->Next;
		}
	}

	cout<<arp.size()<<endl;
	arp.print();
	getchar();
	return 0;
}

编译运行,如下图所示:
在这里插入图片描述

windows其他函数

GetIpNetTable 函数检索本地计算机上的 ARP 表,该表将 IPv4 地址映射到物理地址。

CreateIpNetEntry 函数在本地计算机上的 ARP 表中创建 ARP 条目。

DeleteIpNetEntry 函数从本地计算机上的 ARP 表中删除 ARP 条目。

SetIpNetEntry 函数修改本地计算机上的 ARP 表中的现有 ARP 条目。

FlushIpNetTable 函数从本地计算机上的 ARP 表中删除指定接口的所有 ARP 条目。

感谢大家阅读

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/746506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「Paraverse平行云」入选IDC MarketScape中国实时云渲染解决方案

近日&#xff0c;全球领先的IT研究与咨询顾问机构IDC发布了《IDC MarketScape&#xff1a;中国实时云渲染解决方案2023年厂商评估》报告。作为在实时云渲染技术领域具有代表性的技术提供商&#xff0c;「Paraverse平行云」成功入选报告。 IDC报告通过综合考量厂商在产品、市场…

一文搞懂Goroutine之间的通信Channel

文章目录 Channel定义通道初始化通道通道的操作1、发送/接收2、关闭 多返回值模式for range获取通道值 单向通道selectgoroutine、channel案例 道阻且长&#xff0c;行则将至&#xff0c;行而不辍&#xff0c;未来可期&#x1f31f;。人生是一条且漫长且充满荆棘的道路&#xf…

C++函数cincout的基本用法

C的输入输出格式可比C语言的简单得多&#xff0c;输入函数是cin()&#xff0c;输出函数是cout。 首先是cin的基本用法如下 (假设n 5) #include <iostream> using namespace std; int main() {int n;cin>>n;return 0; } 而它的结果则是 cin不仅可以输入int类型…

从单目数据生成3D模型,Meta智能眼镜摄像头校正算法揭秘

众所周知&#xff0c;Meta下一个目标就是AR眼镜&#xff0c;尽管开发AR比VR面临更多复杂的难题&#xff0c;因此可能还要过一段时间才能看到Meta的AR眼镜。目前&#xff0c;该公司已推出了第一代Ray-Ban Stories智能眼镜&#xff0c;特点是搭载的双摄像头不仅可以拍照&#xff…

Verilog基础之十五、锁存器实现

目录 一、前言 二、工程设计 2.1 工程代码 2.2 综合结果 2.3 Latch实现 一、前言 在之前的文章中介绍过寄存器&#xff0c;本节介绍一个类似的逻辑单元&#xff1a;锁存器。在大部分的资料和文章介绍中&#xff0c;都是告诉读者设计中应尽量避免出现锁存器&#xff0c;这主…

从0到1,带你深入了解react fiber

react16之后&#xff0c;react引入了fiber架构&#xff0c;那么它究竟是什么&#xff0c;如何实现的呢&#xff1f;下面就让笔者带你掰扯掰扯&#xff0c;如有错误&#xff0c;欢迎指正 目录 渲染过程 react15 react16 为什么要引入fiber 不可中断原因 fiber详解 是什么…

百度墨斗鱼文库创作中心源码分析

前言 公司解散&#xff0c;待业中&#xff0c;耗时一天研究了一下百度墨斗鱼文库创作中心源码。实现了后台自动完成任务并通知。 下面主要分析一下实现思路和难点 一&#xff0c;实现思路 调用接口查询未回答的题目列表 合并多个tab下的题目 设置黑白名单&#xff0c;这里…

你知道为什么不用XFP光模块了吗?

在光纤通信应用领域中&#xff0c;10G光模块凭借着较低的成本和功耗被广泛应用于学校、企业等应用场景中。XFP和SFP是10G光模块常见的两种封装类型&#xff0c;那为什么现在市场上XFP光模块应用比较少了呢&#xff1f;下面我们来简单分析一下原因。 一、XFP与SFP光模块的概述 …

从小白到大神之路之学习运维第58天--------Firewalld防火墙

第三阶段基础 时 间&#xff1a;2023年7月12日 参加人&#xff1a;全班人员 内 容&#xff1a; Firewalld防火墙 目录 Firewalld防火墙 一、防火墙 1、netfilter和防火墙管理工具 2、防火墙配置模式 3、Firewalld数据流处理的方式 4、firewalld区域类型 1&#x…

【SVN wc.db 删除不掉的问题】

SVN wc.db 删除不掉的问题 方案1&#xff1a;任务管理器 >性能 >打开资源监视器 > CPU >搜索句柄&#xff0c;关闭相关线程&#xff0c;重试删除。若删除explorer.exe导致资源管理器不显示&#xff0c;在任务管理器新建该任务即可“explorer.exe” 方案2&#xff1…

2023-07-12:RocketMQ如何做到消息不丢失?

2023-07-12&#xff1a;RocketMQ如何做到消息不丢失&#xff1f; 答案2023-07-12&#xff1a; RocketMQ通过刷盘机制、消息拉取机制和ACK机制等多种方式来确保消息投递的可靠性&#xff0c;防止消息丢失。 1.刷盘机制 RocketMQ中的消息分为内存消息和磁盘消息&#xff0c;内…

Acwing.858 Prim算法求最小生成树(朴素Prims算法)

题目 给定一个n个点m条边的无向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。求最小生成树的树边权重之和&#xff0c;如果最小生成树不存在则输出impossible。 给定一张边带权的无向图G(V,E)&#xff0c;其中V表示图中点的集合&#xff0c;E表示图中边的…

赛效:如何用在线压缩GIF图片

1&#xff1a;在电脑网页上打开并登录快改图&#xff0c;点击左侧菜单栏里的“GIF压缩”。 2&#xff1a;点击页面中间的上传按钮&#xff0c;将电脑本地的GIF文件上传上去。 3&#xff1a;GIF文件上传成功后&#xff0c;设置下方压缩设置&#xff0c;点击右下角“开始压缩”。…

APP外包开发硬件通讯协议

开发APP时会遇到需要与硬件设备通讯的业务场景&#xff0c;常见的硬件设备有健康设备(手环、血压计、血糖仪等)、智能家居设备(冰箱、灯、电视等)、工业设备等等&#xff0c;这些设备的通讯要求各不相同&#xff0c;因此通讯协议也不相同。今天和大家分享这方面的知识&#xff…

buu-Reverse-[2019红帽杯]childRE

目录 [2019红帽杯]childRE 修饰函数名和函数签名是什么&#xff1f; 对于变换部分的具体分析&#xff1a; [2019红帽杯]childRE 下载附件&#xff0c;查壳&#xff0c;无壳 在IDA中打开&#xff0c;定位主函数 int __cdecl main(int argc, const char **argv, const char …

深度学习笔记之Transformer(八)Transformer模型架构基本介绍

机器学习笔记之Transformer——Transformer模型架构基本介绍 引言回顾&#xff1a;简单理解&#xff1a; Seq2seq \text{Seq2seq} Seq2seq模型架构与自编码器自注意力机制 Transformer \text{Transformer} Transformer架构关于架构的简单认识多头注意力机制包含掩码的多头注意力…

kubernetes 1.27.3 集群部署方案

一、准备环境 1.1 Kubernetes 1.27.3 版本集群部署环境准备 1.1.1 主机硬件配置说明 cpu内存硬盘角色主机名系统版本 8C 8G 1024GB master master01 centos 7.9 8C 16G 1024GB worker(node) worker01 centos 7.9 8C 16G 1024GB worker(node) worker…

EasyCVR平台Ehome协议接入,设备管理中出现新增通道按钮的问题优化

EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。 有用…

软件测试重要性

导言&#xff1a; 在现代软件开发中&#xff0c;软件测试扮演着确保质量的重要角色。通过对软件系统的验证和验证&#xff0c;软件测试有助于发现潜在的缺陷和问题&#xff0c;并确保软件在部署之前能够达到预期的质量标准。本文将深入探讨软件测试的重要性、测试的类型以及成功…

docker常用功能以及mysql实际使用【推荐】

docker常用功能以及mysql实际使用&#xff1a; 一、docker常用命令&#xff1a; 查看版本 docker -v [rootlocalhost ~]# docker -v Docker version 23.0.4, build f480fb1 [rootlocalhost ~]# 2. 查看 Docker 中已存在的镜像 docker images [rootlocalhost ~]# docker ima…