使用WinPcap(SharpPcap)实现ARP抓包以实现设备IP搜索功能

时间:2024-07-28 20:04:20

在监控摄像机安装后,往往需要设置IP等信息,在IP不知道的情况下,IP搜索是一个很常见也必须的功能。

考虑到设备IP和当前局域网可能不在同一个网段,ARP是一个不错的选择。

首先安装WinPcap软件

使用C#开发还需要以下dll

SharpPcap.dll

PacketDotNet.dll

请自己百度下载。

设计逻辑:

用户电脑开始搜索IP时,首先发送一个arp请求然后用户电脑开始监听,监控摄像机等设备监听到后发送一个arp包,包含ip等信息回复,用户电脑监听到后解析

首先要获取当前计算机的网卡及ip和mac物理地址

ManagementObjectSearcher ms = new ManagementObjectSearcher(@"SELECT DeviceID FROM Win32_NetworkAdapter WHERE ((MACAddress Is Not NULL) AND (Manufacturer <> 'Microsoft'))");//WHERE PNPDeviceID LIKE 'PCI%'
if (ms.Get().Count < )
{
MessageBox.Show("不存在真实网卡");
return;
} devices1 = LibPcapLiveDeviceList.Instance;
if (devices1.Count < )
{
MessageBox.Show("无法获取网卡");
return;
} PhysicalAddress pmac = PhysicalAddress.Parse("FF-FF-FF-FF-FF-FF");
destinationIP = IPAddress.Broadcast;
//遍历网卡
foreach (var device in devices1)
{
if (!device.Description.ToLower().Contains("vmware") && !device.Description.ToLower().Contains("virtual"))//排除虚拟机网卡
{
DeviceNoticeThread = new Thread(new ThreadStart(() =>
{
if (device.Addresses.Count > )
{
foreach (var address in device.Addresses)
{
if (address.Addr.type == SharpPcap.LibPcap.Sockaddr.AddressTypes.AF_INET_AF_INET6)
{
if (address.Addr.ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
localIP = address.Addr.ipAddress;
break;
}
}
}
} foreach (var address in device.Addresses)
{
if (address.Addr.type == SharpPcap.LibPcap.Sockaddr.AddressTypes.HARDWARE)
{
localMAC = address.Addr.hardwareAddress;
}
}
var ethernetPacket = new EthernetPacket(localMAC, pmac, EthernetPacketType.Arp);
var arpPacket = new ARPPacket(getBas("FFFFFFFFFFFF"));
ethernetPacket.PayloadPacket = arpPacket;
device.Open();
device.SendPacket(ethernetPacket);
})); DeviceCaptureThread = new Thread(new ThreadStart(() =>
{
device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);
device.Open(DeviceMode.Normal, );
string filter = "arp";
device.Filter = filter; device.StartCapture();
})); DeviceCaptureThread.IsBackground = true;
DeviceCaptureThread.Start(); DeviceNoticeThread.IsBackground = true;
DeviceNoticeThread.Start();
}
}
getBas函数是拼出arp包内容,这里暂定长度40,内容自己拼
private ByteArraySegment getBas(string mac)
{
byte[] bas = new byte[];
bas[] = ;//硬件类型 - 以太网类型值0x1
bas[] = ; bas[] = ;//上层协议类型 - IP协议(0x0800)
bas[] = ; bas[] = ;//MAC地址长度
bas[] = ;//IP地址长度 bas[] = ;//操作码 - 0x1表示ARP请求包,0x2表示应答包
bas[] = ; string sendermac = localMAC.ToString().Trim();
if (sendermac.Length == )
{
for (int i = ; i < ; i++)
{
bas[i + ] = Convert.ToByte(sendermac.Substring(i * , ), );//发送方mac
}
}
string[] senderip = localIP.ToString().Trim().Split('.');
if (senderip.Length == )
{
for (int i = ; i < senderip.Length; i++)
{
bas[i + ] = Convert.ToByte(senderip[i]);//发送方ip
}
}
string receivermac = mac;
if (receivermac.Length == )
{
for (int i = ; i < ; i++)
{
bas[i + ] = Convert.ToByte(receivermac.Substring(i * , ), );//接收方mac
}
}
string[] receiverip = destinationIP.ToString().Trim().Split('.');
if (receiverip.Length == )
{
for (int i = ; i < receiverip.Length; i++)
{
bas[i + ] = Convert.ToByte(receiverip[i]);//接收方ip
}
} string strpadding = "自定义头," + Convert2Hex(localIP.ToString().Trim()) + "," + sendermac; byte[] padding = Encoding.UTF8.GetBytes(strpadding.PadRight(, '\0'));//自定义数据
for (int i = ; i < ; i++)
{
bas[i + ] = padding[i];
}
return new ByteArraySegment(bas);
}

监听到arp包且长度一致暂定80,根据实际情况改,且头一致,就可以解析显示了

private void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
if (bStopOnPacketArrival) return;
try
{
Packet packet = Packet.ParsePacket(e.Device.LinkType, e.Packet.Data);
if (packet is EthernetPacket)
{
EthernetPacket ep = (EthernetPacket)packet;
if (ep.PayloadPacket is ARPPacket)
{
ARPPacket ap = (ARPPacket)ep.PayloadPacket;
if (ep.Type == EthernetPacketType.Arp && ap.Operation == ARPOperation.Response)
{
byte[] data = ep.Bytes;
if (data.Length == )
{ }
}
}
}
}
catch (System.Exception ex)
{
log.ErrorFormat("解析arp包失败!错误信息:{0}", ex.Message);
}
}