使用WinPcap(SharpPcap)實現ARP抓包以實現設備IP搜索功能


 

在監控攝像機安裝后,往往需要設置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 < 1)
                {
                    MessageBox.Show("不存在真實網卡");
                    return;
                }

                devices1 = LibPcapLiveDeviceList.Instance;
                if (devices1.Count < 1)
                {
                    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 > 0)
                            {
                                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, 1000);
                            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[70];
            bas[0] = 0;//硬件類型 - 以太網類型值0x1
            bas[1] = 1;

            bas[2] = 08;//上層協議類型 - IP協議(0x0800)
            bas[3] = 00;

            bas[4] = 6;//MAC地址長度
            bas[5] = 4;//IP地址長度

            bas[6] = 0;//操作碼 - 0x1表示ARP請求包,0x2表示應答包
            bas[7] = 1;

            string sendermac = localMAC.ToString().Trim();
            if (sendermac.Length == 12)
            {
                for (int i = 0; i < 6; i++)
                {
                    bas[i + 8] = Convert.ToByte(sendermac.Substring(i * 2, 2), 16);//發送方mac
                }
            }
            string[] senderip = localIP.ToString().Trim().Split('.');
            if (senderip.Length == 4)
            {
                for (int i = 0; i < senderip.Length; i++)
                {
                    bas[i + 14] = Convert.ToByte(senderip[i]);//發送方ip
                }
            }
            string receivermac = mac;
            if (receivermac.Length == 12)
            {
                for (int i = 0; i < 6; i++)
                {
                    bas[i + 18] = Convert.ToByte(receivermac.Substring(i * 2, 2), 16);//接收方mac
                }
            }
            string[] receiverip = destinationIP.ToString().Trim().Split('.');
            if (receiverip.Length == 4)
            {
                for (int i = 0; i < receiverip.Length; i++)
                {
                    bas[i + 24] = Convert.ToByte(receiverip[i]);//接收方ip
                }
            }

            string strpadding = "自定義頭," + Convert2Hex(localIP.ToString().Trim()) + "," + sendermac;
        
            byte[] padding = Encoding.UTF8.GetBytes(strpadding.PadRight(40, '\0'));//自定義數據
            for (int i = 0; i < 40; i++)
            {
                bas[i + 28] = 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 == 80)
                            {
                               
                            }
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                log.ErrorFormat("解析arp包失敗!錯誤信息:{0}", ex.Message);
            }
        }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM