Ping Part II: Adventures in Socket programming using System.Net


If you see the ping utility that comes with your OS, you will notice that it has many options. However, the one we are going to develop will just take one argument:


 



C:\ping>ping <hostname> | <ipaddress>


        Example: ping www.contoso.com


        Example: ping 127.0.0.1


 


 Let us start out by looking at requirements of the Ping client. Basically, the task of the tool is to find out if a specified server is alive, and on the network. The way it achieves this is by sending an “echo” packet to the server. The server responds with an “echo” response. If the server responds within a certain time interval, then we can assume that there is network connectivity from the client to the server. If it doesn’t respond, then it could indicate a variety of things that could be wrong, for eg:


 



  • The destination server is not up.
  • The destination server is up but does not have networking enabled.
  • The destination server is up and on the network, but is configured to drop Ping requests
  • Etc.

 


We will not concern ourselves with “why” a server is not responding to the Ping request, as it could be another topic in itself.


 


Where was I? Oh yeah, the Ping client. It so happens that we have a protocol (ICMP) that has the echo request and reply operations that we need to implement the Ping client. Read the ICMP RFC to get information about all the features offered by the ICMP protocol. As we know, the ICMP protocol is at the same layer as the IP protocol in the OSI layering scheme.


 


For the ping utility, we will be using the ICMP Echo Request and response messages. The client will send the ICMP echo request message, and the server will reply with an Echo response message. If you look at the Rfc, it describes how an RFC message looks like:


 







































Offset


Field Name


Size (octets)


Description


0


Type


1


Specified type of the operation. It should be set to 8 for request message and 0 for reply messages


8


Code


1


This field is Zero.


16


Checksum


2


One’s complement checksum of the ICMP message


32


Identifier


2


Used to correlate request and reply


48


Sequence Number


2


Used to correlate request and reply


64


Data


Variable


Optional data to be sent with the request. This must be sent back by the server.


 


 


Looking at the table above, we can come up with a C# class that corresponds to what the packet will look like:


 


public class ICMP_PACKET


{


      public Byte i_type;    // type of message


      public Byte i_code;    // sub code


      public UInt16 i_cksum;   // ones complement checksum of header


      public UInt16 i_id;      // identifier


      public UInt16 i_seq;     // sequence number 


      public Byte[] data;


}


 


 


I used Ethereal to sniff the network while doing a Ping, to see what a Ping request/response looks like on the wire. The request packet looks like this:


 


0020  59 99 08 00 b5 58 02 00  96 03 61 62 63 64 65 66   Y….X.. ..abcdef


0030  67 68 69 6a 6b 6c 6d 6e  6f 70 71 72 73 74 75 76    ghijklmn opqrstuv


0040  77 61 62 63 64 65 66 67  68 69                                 wabcdefghi     


 


 


Let us dissect the packet:


 


i_type = 0x08 ( Echo Request)


i_code = 0x00


i_cksum = 0xb558


i_id  = 0x0200


i_seq = 0x9603


data = 32 bytes ( abcedf…. )


 


The ICMP echo reply looks as follows:


 


0020  59 9a 00 00 bd 58 02 00  96 03 61 62 63 64 65 66   Y….X.. ..abcdef


0030  67 68 69 6a 6b 6c 6d 6e  6f 70 71 72 73 74 75 76    ghijklmn opqrstuv


0040  77 61 62 63 64 65 66 67  68 69                                 wabcdefghi     


 


Let us dissect the packet:


 


i_type = 0x00 ( Echo Reply)


i_code = 0x00


i_cksum = 0xbd58


i_id  = 0x0200


i_seq = 0x9603


data = 32 bytes ( abcedf…. )


 


 


Given what we have learned so far, we can now come up with a skeleton for the program that we will develop:


 


using System;


using System.Text;


using System.Globalization;


 


namespace ping


{


public class ICMP_PACKET


      {


            Byte i_type;    // type of message


            Byte i_code;    // sub code


            UInt16 i_cksum;   // ones complement checksum of header


            UInt16 i_id;      // identifier


            UInt16 i_seq;     // sequence number 


            Byte[] data;


 


            private const int headerLength = 8;


 


            // Total size of the packet (header + payload)


            public int Length


            {


                  get { return HeaderLength + PayloadLength; }


            }


 


            // Size of the packet header (excluding data)


            public int HeaderLength


            {


                  get { return headerLength; }


            }


 


            // Size of the payload


            public int PayloadLength


            {


                  get { return (data == null) ? 0 : data.Length; }


            }


 


            public byte PacketType


            {


                  get { return i_type; }


            }


 


            public byte Code


            {


                  get { return i_code; }


            }


 


            public UInt16 Identifier


            {


                  get { return i_id; }


            }


 


            public UInt16 SequenceNumber


            {


                  get { return i_seq; }


            }


 


            public ICMP_PACKET(Byte kind, Byte code, UInt16 id, UInt16 seq, byte[] data)


            {


                  this.i_type = kind;


                  this.i_code = code;


                  this.i_id = id;


                  this.i_seq = seq;


                  this.data = data;


                  this.i_cksum = 0;


            }


 


            public static ICMP_PACKET CreateRequestPacket(UInt16 id, UInt16 seq, byte[] data)


            {


                  return new ICMP_PACKET(8, 0, id, seq, data);


            }


      };


 


      class Program


      {


            static void Main(string[] args)


            {


                  if (args.Length != 1)


                  {


                        Usage();


                  }


 


                  if (0 == String.Compare(args[0], “/?”, true, CultureInfo.InvariantCulture)


                  || 0 == String.Compare(args[0], “-h”, true, CultureInfo.InvariantCulture)


                  || 0 == String.Compare(args[0], “-?”, true, CultureInfo.InvariantCulture))


                  {


                        Usage();


                  }


 


            }


 


            static void Usage()


            {


                  Console.WriteLine(“ping <hostname> | <ipaddress>”);


                  Console.WriteLine(“\tExample: ping www.contoso.com”);


                  Console.WriteLine(“\tExample: ping 127.0.0.1”);


                  Environment.Exit(0);


            }


 


      }


}


Comments (3)

  1. Feroze Daushas posted about socket programmingusing System.Net.Sockets and implemented a ping client

Skip to main content