/// <summary> /// This routine creates an instance of the Icmpv6EchoRequest class from a byte /// array that is a received IGMP packet. This is useful when a packet /// is received from the network and the header object needs to be /// constructed from those values. /// </summary> /// <param name="echoData">Byte array containing the binary ICMPv6 echo request header</param> /// <param name="bytesCopied">Number of bytes used in header</param> /// <returns>Returns the Icmpv6EchoRequest object created from the byte array</returns> public static Icmpv6EchoRequest Create(byte[] echoData, ref int bytesCopied) { Icmpv6EchoRequest icmpv6EchoRequestHeader = new Icmpv6EchoRequest(); // Verify buffer is large enough if (echoData.Length < Icmpv6EchoRequest.Icmpv6EchoRequestLength) return null; // Properties are stored in network byte order so just grab the bytes // from the buffer icmpv6EchoRequestHeader.echoId = BitConverter.ToUInt16(echoData, 0); icmpv6EchoRequestHeader.echoSequence = BitConverter.ToUInt16(echoData, 2); bytesCopied = Icmpv6EchoRequest.Icmpv6EchoRequestLength; return icmpv6EchoRequestHeader; }
/// <summary> /// This routine creates an instance of the Icmpv6EchoRequest class from a byte /// array that is a received IGMP packet. This is useful when a packet /// is received from the network and the header object needs to be /// constructed from those values. /// </summary> /// <param name="echoData">Byte array containing the binary ICMPv6 echo request header</param> /// <param name="bytesCopied">Number of bytes used in header</param> /// <returns>Returns the Icmpv6EchoRequest object created from the byte array</returns> static public Icmpv6EchoRequest Create(byte[] echoData, ref int bytesCopied) { Icmpv6EchoRequest icmpv6EchoRequestHeader = new Icmpv6EchoRequest(); // Verify buffer is large enough if (echoData.Length < Icmpv6EchoRequest.Icmpv6EchoRequestLength) { return(null); } // Properties are stored in network byte order so just grab the bytes // from the buffer icmpv6EchoRequestHeader.echoId = BitConverter.ToUInt16(echoData, 0); icmpv6EchoRequestHeader.echoSequence = BitConverter.ToUInt16(echoData, 2); bytesCopied = Icmpv6EchoRequest.Icmpv6EchoRequestLength; return(icmpv6EchoRequestHeader); }
public ManualResetEvent pingDoneEvent; // Event to indicate all outstanding receives are done // this ping class can be disposed /// <summary> /// Base constructor that initializes the member variables to default values. It also /// creates the events used and initializes the async callback function. /// </summary> public RawSocketPing() { pingSocket = null; pingFamily = AddressFamily.InterNetwork; pingTtl = 8; pingPayloadLength = 8; pingSequence = 0; pingReceiveTimeout = 4000; pingOutstandingReceives = 0; destEndPoint = new IPEndPoint(IPAddress.Loopback, 0); protocolHeaderList = new ArrayList(); pingReceiveEvent = new ManualResetEvent(false); pingDoneEvent = new ManualResetEvent(false); receiveCallback = new AsyncCallback(PingReceiveCallback); icmpHeader = null; icmpv6Header = null; icmpv6EchoRequestHeader = null; }
/// <summary> /// This is the asynchronous callback that is fired when an async ReceiveFrom. /// An asynchronous ReceiveFrom is posted by calling BeginReceiveFrom. When this /// function is invoked, it calculates the elapsed time between when the ping /// packet was sent and when it was completed. /// </summary> /// <param name="ar">Asynchronous context for operation that completed</param> static void PingReceiveCallback(IAsyncResult ar) { RawSocketPing rawSock = (RawSocketPing)ar.AsyncState; TimeSpan elapsedTime; int bytesReceived = 0; ushort receivedId = 0; try { // Keep a count of how many async operations are outstanding -- one just completed // so decrement the count. Interlocked.Decrement(ref rawSock.pingOutstandingReceives); // If we're done because ping is exiting and the socket has been closed, // set the done event if (rawSock.pingSocket == null) { if (rawSock.pingOutstandingReceives == 0) { rawSock.pingDoneEvent.Set(); } return; } // Complete the receive op by calling EndReceiveFrom. This will return the number // of bytes received as well as the source address of who sent this packet. bytesReceived = rawSock.pingSocket.EndReceiveFrom(ar, ref rawSock.castResponseEndPoint); // Calculate the elapsed time from when the ping request was sent and a response was // received. elapsedTime = DateTime.Now - rawSock.pingSentTime; rawSock.responseEndPoint = (IPEndPoint)rawSock.castResponseEndPoint; // Here we unwrap the data received back into the respective protocol headers such // that we can find the ICMP ID in the ICMP or ICMPv6 packet to verify that // the echo response we received was really a response to our request. if (rawSock.pingSocket.AddressFamily == AddressFamily.InterNetwork) { Ipv4Header v4Header; IcmpHeader icmpv4Header; byte[] pktIcmp; int offset = 0; // Remember, raw IPv4 sockets will return the IPv4 header along with all // subsequent protocol headers v4Header = Ipv4Header.Create(rawSock.receiveBuffer, ref offset); pktIcmp = new byte[bytesReceived - offset]; Array.Copy(rawSock.receiveBuffer, offset, pktIcmp, 0, pktIcmp.Length); icmpv4Header = IcmpHeader.Create(pktIcmp, ref offset); /*Console.WriteLine("Icmp.Id = {0}; Icmp.Sequence = {1}", * icmpv4Header.Id, * icmpv4Header.Sequence * );*/ receivedId = icmpv4Header.Id; } else if (rawSock.pingSocket.AddressFamily == AddressFamily.InterNetworkV6) { Icmpv6Header icmp6Header; Icmpv6EchoRequest echoHeader; byte[] pktEchoRequest; int offset = 0; // For IPv6 raw sockets, the IPv6 header is never returned along with the // data received -- the received data always starts with the header // following the IPv6 header. icmp6Header = Icmpv6Header.Create(rawSock.receiveBuffer, ref offset); pktEchoRequest = new byte[bytesReceived - offset]; Array.Copy(rawSock.receiveBuffer, offset, pktEchoRequest, 0, pktEchoRequest.Length); echoHeader = Icmpv6EchoRequest.Create(pktEchoRequest, ref offset); /*Console.WriteLine("Icmpv6.Id = {0}; Icmp.Sequence = {1}", * echoHeader.Id, * echoHeader.Sequence * );*/ receivedId = echoHeader.Id; } if (receivedId == rawSock.pingId) { string elapsedString; // Print out the usual statistics for ping if (elapsedTime.Milliseconds < 1) { elapsedString = "<1"; } else { elapsedString = "=" + elapsedTime.Milliseconds.ToString(); } Console.WriteLine("Reply from {0}: byte={1} time{2}ms TTL={3} ", rawSock.responseEndPoint.Address.ToString(), bytesReceived, elapsedString, rawSock.pingTtl ); } // Post another async receive if the count indicates for us to do so. if (rawSock.pingCount > 0) { rawSock.pingSocket.BeginReceiveFrom( rawSock.receiveBuffer, 0, rawSock.receiveBuffer.Length, SocketFlags.None, ref rawSock.castResponseEndPoint, rawSock.receiveCallback, rawSock ); // Keep track of outstanding async operations Interlocked.Increment(ref rawSock.pingOutstandingReceives); } else { // If we're done then set the done event if (rawSock.pingOutstandingReceives == 0) { rawSock.pingDoneEvent.Set(); } } // If this is indeed the response to our echo request then signal the main thread // that we received the response so it can send additional echo requests if // necessary. This is done after another async ReceiveFrom is already posted. if (receivedId == rawSock.pingId) { rawSock.pingReceiveEvent.Set(); } } catch (SocketException err) { Console.WriteLine("Socket error occurred in async callback: {0}", err.Message); } }
/// <summary> /// This routine builds the appropriate ICMP echo packet depending on the /// protocol family requested. /// </summary> public void BuildPingPacket() { // Initialize the socket if it hasn't already been done Console.WriteLine("Building the ping packet..."); Console.WriteLine("Initializing the socket if not done yet..."); if (pingSocket == null) { InitializeSocket(); } // Clear any existing headers in the list Console.WriteLine("Clearing any existing headers in the list using Clear()..."); protocolHeaderList.Clear(); if (destEndPoint.AddressFamily == AddressFamily.InterNetwork) { // Create the ICMP header and initialize the members Console.WriteLine("Creating the ICMP header and initialize the members..."); icmpHeader = new IcmpHeader(); icmpHeader.Id = pingId; icmpHeader.Sequence = pingSequence; icmpHeader.Type = IcmpHeader.EchoRequestType; icmpHeader.Code = IcmpHeader.EchoRequestCode; // Build the data payload of the ICMP echo request Console.WriteLine("Building the data payload of the ICMP echo request..."); pingPayload = new byte[pingPayloadLength]; for (int i = 0; i < pingPayload.Length; i++) { pingPayload[i] = (byte)'e'; } // Add ICMP header to the list of headers Console.WriteLine("Adding ICMP header to the list of headers using Add()..."); protocolHeaderList.Add(icmpHeader); } else if (destEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { Ipv6Header ipv6Header; // Required for pseudo header checksum IPEndPoint localInterface; byte[] localAddressBytes = new byte[28]; Console.WriteLine("This part is for IPv6..."); // An IPv6 header is required since the IPv6 protocol specifies that the // pseudo header checksum needs to be calculated on ICMPv6 packets which // requires the source and destination address that will appear in the // IPv6 packet. ipv6Header = new Ipv6Header(); // We definitely know the destination IPv6 address but the stack will // choose the "appropriate" local v6 interface depending on the // routing table which may be different than the address we bound // the socket to. Because of this we will call the Winsock ioctl // SIO_ROUTING_INTERFACE_QUERY which will return the local interface // for a given destination address by querying the routing table. Console.WriteLine("Implementing the IOControl()..."); pingSocket.IOControl( WinsockIoctl.SIO_ROUTING_INTERFACE_QUERY, SockaddrConvert.GetSockaddrBytes(destEndPoint), localAddressBytes ); localInterface = SockaddrConvert.GetEndPoint(localAddressBytes); // Fill out the fields of the IPv6 header used in the pseudo-header checksum calculation Console.WriteLine("Filling out the IPv6 header fields..."); ipv6Header.SourceAddress = localInterface.Address; ipv6Header.DestinationAddress = destEndPoint.Address; ipv6Header.NextHeader = 58; // IPPROTO_ICMP6 // Initialize the ICMPv6 header Console.WriteLine("Initializing the ICMPv6 header..."); icmpv6Header = new Icmpv6Header(ipv6Header); icmpv6Header.Type = Icmpv6Header.Icmpv6EchoRequestType; icmpv6Header.Code = Icmpv6Header.Icmpv6EchoRequestCode; // Initialize the payload Console.WriteLine("Initializing the payload..."); pingPayload = new byte[pingPayloadLength]; for (int i = 0; i < pingPayload.Length; i++) { pingPayload[i] = (byte)'e'; } // Create the ICMPv6 echo request header Console.WriteLine("Creating the ICMPv6 echo request header..."); icmpv6EchoRequestHeader = new Icmpv6EchoRequest(); icmpv6EchoRequestHeader.Id = pingId; // Add the headers to the protocol header list Console.WriteLine("Adding the headers to the protocol header list..."); protocolHeaderList.Add(icmpv6Header); protocolHeaderList.Add(icmpv6EchoRequestHeader); } }
/// <summary> /// Initializes a new instance of the <see cref="Icmpv6EchoReply"/> class. /// Simple constructor for the ICMPv6 echo request header /// </summary> /// public Icmpv6EchoReply(Icmpv6EchoRequest icmpv6EchoRequest) { Id = icmpv6EchoRequest.Id; Sequence = icmpv6EchoRequest.Sequence; Icmpv6EchoPayload = icmpv6EchoRequest.Icmpv6EchoPayload; }