Read ICMP packets in C# using raw sockets


Raw sockets are useful when you want to read all details of a network packet such as the IP header, protocol header, and payload. They can also be used to communicate using protocols that don’t have a higher level API, which means most protocols that are not UDP or TCP based. Reading ICMP protocol packets is one useful example.

The following source code is a console application. It receives any kind of IP version 4 ICMP protocol packet, from any host, and prints the entire packet to console.

    static class Program
    {
        private static Socket icmpSocket;
        private static byte[] receiveBuffer = new byte[256];
        private static EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            CreateIcmpSocket();
            while (true) { Thread.Sleep(10); }
        }

        private static void CreateIcmpSocket()
        {
            icmpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
            icmpSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
            // Uncomment to receive all ICMP message (including destination unreachable).
            // Requires that the socket is bound to a particular interface. With mono,
            // fails on any OS but Windows.
            //if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            //{
            //    icmpSocket.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });
            //}
            BeginReceiveFrom();
        }

        private static void BeginReceiveFrom()
        {
            icmpSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None,
                ref remoteEndPoint, ReceiveCallback, null);
        }

        private static void ReceiveCallback(IAsyncResult ar)
        {
            int len = icmpSocket.EndReceiveFrom(ar, ref remoteEndPoint);
            Console.WriteLine(string.Format("{0} Received {1} bytes from {2}",
                DateTime.Now, len, remoteEndPoint));
            LogIcmp(receiveBuffer, len);
            BeginReceiveFrom();
        }

        private static void LogIcmp(byte[] buffer, int length)
        {
            for (int i = 0; i < length; i++)
            {
                Console.Write(String.Format("{0:X2} ", buffer[i]));
            }
            Console.WriteLine("");
        }
    }

Here’s an example of the kind of output the program spits.

26/11/2013 16:42:40 Received 56 bytes from 192.168.61.61:0
45 00 00 38 01 36 00 00 40 01 7D C3 C0 A8 3D 3D C0 A8 3D 3E 04 00 A7 61 00 00 00
 00 45 00 00 27 31 4F 00 00 80 11 FF 22 C0 A8 3D 3E 0C 00 00 6E E8 9E 0F E5 00 1
3 5C 07
26/11/2013 16:58:02 Received 60 bytes from 192.168.61.61:0
45 00 00 3C 01 A6 00 00 40 01 7D 4F C0 A8 3D 3D C0 A8 3D 3E 03 06 9B CF 00 00 00
 00 46 00 00 28 68 6F 00 00 01 02 DE 63 C0 A8 3D 3E E0 00 00 16 94 04 00 00 22 0
0 F9 01 46 00 00 28

The first 20 bytes are the IP v4 header, followed by the ICMP payload. The first byte of ICMP payload identifies the type of the ICMP packet. For instance, a value of 3 indicates that the host is unreachable, and 4 indicates source quench. If you want the packets nicely dissected for you, capture them from the network interface using Wireshark.

Advertisements

iPad Mini with Retina display


iPad Mini with Retina display, at Apple Store in Woodfield Mall, Schaumburg, IL. Retina display is the best thing to have happened to the iPad Mini. Is the smaller screen an issue? My myopic eyes don’t think so, but my presbyopic eyes think bigger is better.

20131121-174059.jpg

iPad Air


20131105-102229.jpg

At Apple Store, Kurfürstendamm, holding iPad Air. Impressive how much lighter it is when compared to the original iPad.

20131105-103843.jpg

Nice store. Yes! The one featured in WWDC 2013.

20131106-043417.jpg

It’s huge too.