C# Traceroute using .net framework

If you have ever tried to create a traceroute program using one of the few available ICMP libraries freely available for C# you may have run into some issues mainly to do with the ICMP checksum not being correct. It seems that as of .NET 2.0 framework that microsoft included a Ping class that makes it really easy to then use it to create a traceroute utility. Here is some basic code to create a traceroute utility.

public string Traceroute(string ipAddressOrHostName)
{
    IPAddress ipAddress = Dns.GetHostEntry(ipAddressOrHostName).AddressList[0];
    StringBuilder traceResults = new StringBuilder();
 
    using(Ping pingSender = new Ping())
    {
        PingOptions pingOptions = new PingOptions();
        Stopwatch stopWatch = new Stopwatch();
        byte[] bytes = new byte[32];
 
        pingOptions.DontFragment = true;
        pingOptions.Ttl = 1;
        int maxHops = 30;
 
 
 
        traceResults.AppendLine(
            string.Format(
                "Tracing route to {0} over a maximum of {1} hops:", 
                ipAddress, 
                maxHops));
 
        traceResults.AppendLine();
 
        for(int i = 1; i < maxHops + 1; i++)
        {
            stopWatch.Reset();
            stopWatch.Start();
            PingReply pingReply = pingSender.Send(
                ipAddress, 
                5000, 
                new byte[32], pingOptions);
 
            stopWatch.Stop();
 
            traceResults.AppendLine(
                string.Format("{0}\t{1} ms\t{2}", 
                i, 
                stopWatch.ElapsedMilliseconds, 
                pingReply.Address));
 
            if(pingReply.Status == IPStatus.Success)
            {
                traceResults.AppendLine();
                traceResults.AppendLine("Trace complete."); break;
            }
 
            pingOptions.Ttl++;
        }
 
    }
 
    return traceResults.ToString();
}

 

 

Microsoft released free Chart Controls for ASP.NET and Winforms

I might be behind the times but I just found out that MS released free charting controls for Winform and ASP.NET. Requires you be running VS2008.

Charting Component Download : http://www.microsoft.com/downloads/details.aspx?FamilyId=130F7986-BF49-4FE5-9CA8-910AE6EA442C&displaylang=en

Language Pack if you are using other languages: http://www.microsoft.com/downloads/details.aspx?FamilyId=581FF4E3-749F-4454-A5E3-DE4C463143BD&displaylang=en

Visual Studio 2008 Add-On: http://www.microsoft.com/downloads/details.aspx?familyid=1D69CE13-E1E5-4315-825C-F14D33A303E9&displaylang=en

Documentation: http://www.microsoft.com/downloads/details.aspx?familyid=EE8F6F35-B087-4324-9DBA-6DD5E844FD9F&displaylang=en

Also here is a good resouce site that provides samples in asp.net and winforms for using the controls: http://code.msdn.microsoft.com/mschart/Release/ProjectReleases.aspx?ReleaseId=1591

I will be downloading later this evening and playing around with this but this is great to see MS finally release some nice looking chart controls.

c# and vb.net preserving or persisting user settings user.config after upgrades

If you store settings in your application using Settings.Settings and have ever upgraded your application you may have found all the user settings have vanished. It seems that the user.config file is stored in %UserProfile/LocalSettings/Application Data/CompanyName/ApplicationName/versionnumber/user.config

Every time you increment the version on your application a new version folder will be created that is of course empty and the process of populating those user specific settings starts over again.

Here is a way you can use to persist those settings after an upgrade.

C# Directions:

In your project open Settings.Settings and add a new user setting called ShouldUpgrade and set this to be a boolean value and set the value to true. Now click View Code icon at the top left side of the settings window. In the constructor add something like this.

public Settings()
{
    if(this.ShouldUpgrade)
    {
       
this.Upgrade();
       
this.ShouldUpgrade = false;
       
this.Save();
    }
}

So the first time that the settings class is instantiated it will check the ShouldUpgrade setting of the new user.config file which will be set to true. The this.Upgrade() then copies any user settings from the most recent version prior to this upgrade. Then set ShouldUpgrade to false and save the settings.

Also because we stored ShouldUpgrade as a user setting this upgrade will happen for each individual user on the same machine.

For VB.NET you do the same approach but use My.Settings.Upgrade()

 

C# Ping

I was recently tasked with putting together a ping and traceroute feature in an application and like I always do I googled to see if someone had already worked out how to do this.

I found a few people who had posted ICMP libraries and so I used one of them and tested and everything seemed to work properly. However I was getting reports that it was not working on Vista. However the person could use the built in ping and tracert utilities with no issue.

At first I thought it might be related to permissions or firewall but none of those ended up resolving the issue.

So I fired up wireshark and looked at what was different at the packet level between what I was doing and what the built in windows ping was doing.

The code I was using was returning an incorrect checksum on the ICMP reply. So I searched a bit to learn about the checksum and ended up finding somehow that as of .NET 2.0 framework there is a Ping class built into the framework!!

So I am posting this in hopes of saving someone a bunch of time with the same issue I had. Also the code I had to put together initially was much more complex. This I think you will see is very straight forward.

Download PingUtility.cs (3.14 kb)

Example Output:

Pinging 192.168.105.10 with 32 bytes of data:

Reply from 192.168.105.10: bytes=32 time=11ms TTL=128
Reply from 192.168.105.10: bytes=32 time=3ms TTL=128
Reply from 192.168.105.10: bytes=32 time=3ms TTL=128
Reply from 192.168.105.10: bytes=32 time=3ms TTL=128

Ping statistics for 192.168.105.10:
	Packets: Sent = 4, Received = 4, Lost = 0
Approximate round trip times in milli-seconds:
	Minimum = 3ms, Maximum = 11ms
Code:
public static string Ping()
{
    using (Ping pingSender = new Ping())
    {
        PingOptions pingOptions = null;
        StringBuilder pingResults = null;
        PingReply pingReply = null;
        IPAddress ipAddress = null;
        int numberOfPings = 4;
        int pingTimeout = 1000;
        int byteSize = 32;
        byte[] buffer = new byte[byteSize];
        int sentPings = 0;
        int receivedPings = 0;
        int lostPings = 0;
        long minPingResponse = 0;
        long maxPingResponse = 0;
        string ipAddressString = "192.168.105.10";
        pingOptions = new PingOptions();
        //pingOptions.DontFragment = true;
        //pingOptions.Ttl = 128;
        ipAddress = IPAddress.Parse(ipAddressString);
        pingResults = new StringBuilder();
        pingResults.AppendLine(string.Format("Pinging {0} with {1} bytes of data:", ipAddress, byteSize));
        pingResults.AppendLine();
        for (int i = 0; i < numberOfPings; i++)
        {
            sentPings++;
            pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions);
            if (pingReply.Status == IPStatus.Success)
            {
                pingResults.AppendLine(string.Format("Reply from {0}: bytes={1} time={2}ms TTL={3}", ipAddress, byteSize, pingReply.RoundtripTime, pingReply.Options.Ttl));
                if (minPingResponse == 0)
                {
                    minPingResponse = pingReply.RoundtripTime;
                    maxPingResponse = minPingResponse;
                }
                else if (pingReply.RoundtripTime < minPingResponse)
                {
                    minPingResponse = pingReply.RoundtripTime;
                }
                else if (pingReply.RoundtripTime > maxPingResponse)
                {
                    maxPingResponse = pingReply.RoundtripTime;
                }
                receivedPings++;
            }
            else
            {
                pingResults.AppendLine(pingReply.Status.ToString());
                lostPings++;
            }
        }
        pingResults.AppendLine();
        pingResults.AppendLine(string.Format("Ping statistics for {0}:", ipAddress));
        pingResults.AppendLine(string.Format("\tPackets: Sent = {0}, Received = {1}, Lost = {2}", sentPings, receivedPings, lostPings));
        pingResults.AppendLine("Approximate round trip times in milli-seconds:");
        pingResults.AppendLine(string.Format("\tMinimum = {0}ms, Maximum = {1}ms", minPingResponse, maxPingResponse));
        return pingResults.ToString();
    }
}