private Kavprot.Packets.Packet BuildRequest(System.Net.IPAddress destinationIP, PhysicalAddress localMac, System.Net.IPAddress localIP) { // an arp packet is inside of an ethernet packet var ethernetPacket = new Kavprot.Packets.EthernetPacket(localMac, PhysicalAddress.Parse("FF-FF-FF-FF-FF-FF"), Kavprot.Packets.EthernetPacketType.Arp); var arpPacket = new Kavprot.Packets.ARPPacket(Kavprot.Packets.ARPOperation.Request, PhysicalAddress.Parse("00-00-00-00-00-00"), destinationIP, localMac, localIP); // the arp packet is the payload of the ethernet packet ethernetPacket.PayloadPacket = arpPacket; return(ethernetPacket); }
/// <summary> /// Resolves the MAC address of the specified IP address /// </summary> /// <param name="destIP">The IP address to resolve</param> /// <param name="deviceName">The local network device name on which to send the ARP request</param> /// <returns>The MAC address that matches to the given IP address or /// null if there was a timeout</returns> public PhysicalAddress Resolve(System.Net.IPAddress destIP, string deviceName) { PhysicalAddress localMAC = LocalMAC; System.Net.IPAddress localIP = LocalIP; var device = LibPcap.LibPcapLiveDeviceList.Instance[DeviceName]; // if no local ip address is specified attempt to find one from the adapter if (localIP == null) { if (device.Addresses.Count > 0) { foreach (var address in device.Addresses) { if (address.Addr.type == LibPcap.Sockaddr.Type.AF_INET_AF_INET6) { localIP = address.Addr.ipAddress; break; // break out of the foreach } } if (localIP == null) { localIP = System.Net.IPAddress.Parse("127.0.0.1"); } } } // if no local mac address is specified attempt to find one from the device if (localMAC == null) { foreach (var address in device.Addresses) { if (address.Addr.type == LibPcap.Sockaddr.Type.HARDWARE) { localMAC = address.Addr.hardwareAddress; } } } if (localIP == null) { throw new System.InvalidOperationException("Unable to find local ip address"); } if (localMAC == null) { throw new System.InvalidOperationException("Unable to find local mac address"); } //Build a new ARP request packet var request = BuildRequest(destIP, localMAC, localIP); //create a "tcpdump" filter for allowing only arp replies to be read String arpFilter = "arp and ether dst " + localMAC.ToString(); //open the device with 20ms timeout device.Open(DeviceMode.Promiscuous, 20); //set the filter device.Filter = arpFilter; // set a last request time that will trigger sending the // arp request immediately var lastRequestTime = DateTime.FromBinary(0); var requestInterval = new TimeSpan(0, 0, 1); Kavprot.Packets.ARPPacket arpPacket = null; // attempt to resolve the address with the current timeout var timeoutDateTime = DateTime.Now + Timeout; while (DateTime.Now < timeoutDateTime) { if (requestInterval < (DateTime.Now - lastRequestTime)) { // inject the packet to the wire device.SendPacket(request); lastRequestTime = DateTime.Now; } //read the next packet from the network var reply = device.GetNextPacket(); if (reply == null) { continue; } // parse the packet var packet = Kavprot.Packets.Packet.ParsePacket(reply); // is this an arp packet? arpPacket = Kavprot.Packets.ARPPacket.GetEncapsulated(packet); if (arpPacket == null) { continue; } //if this is the reply we're looking for, stop if (arpPacket.SenderProtocolAddress.Equals(destIP)) { break; } } // free the device device.Close(); // the timeout happened if (DateTime.Now >= timeoutDateTime) { return(null); } else { //return the resolved MAC address return(arpPacket.SenderHardwareAddress); } }