Basic .NET (C#) Traceroute library

Spending the day researching all things DNS, I eventually came upon Jim Scott's post on C# Traceroute using .net framework. After a bit of tweaking, I've got something that I like a bit more, because I really want to know what the IP address means.

The code for the assembly and console application are included below. Written against .NET Framework 4 (in Visual Studio 2010), but if you change the String.IsNullOrWhiteSpace() reference, you should be able to compile this in 3.5.

Trace.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.NetworkInformation;
using System.Diagnostics;

namespace JamesRSkemp.Traceroute { public class TraceLocation { /// <summary> /// Hop number in a particular trace. /// </summary> public int Hop { get; set; } /// <summary> /// Time in milliseconds. /// </summary> public long Time { get; set; } /// <summary> /// IP address returned. /// </summary> public String IpAddress { get; set; } }

public class Trace {
	/// &lt;summary&gt;
	/// Given an ip address or domain name, follow the trace path.
	/// 
	/// Idea and majority of the code from Jim Scott - http://coding.infoconex.com/post/C-Traceroute-using-net-framework.aspx
	/// &lt;/summary&gt;
	/// &lt;param name="ipAddressOrHostName"&gt;IP address or domain name to trace.&lt;/param&gt;
	/// &lt;param name="maximumHops"&gt;Maximum number of hops before quitting.&lt;/param&gt;
	/// &lt;returns&gt;List of TraceLocation.&lt;/returns&gt;
	public static List&lt;TraceLocation&gt; Traceroute(string ipAddressOrHostName, int maximumHops) {
		if (maximumHops &lt; 1 || maximumHops &gt; 100) {
			maximumHops = 30;
		}

		IPAddress ipAddress = Dns.GetHostEntry(ipAddressOrHostName).AddressList[0];

		List&lt;TraceLocation&gt; traceLocations = new List&lt;TraceLocation&gt;();

		using (Ping pingSender = new Ping()) {
			PingOptions pingOptions = new PingOptions();
			Stopwatch stopWatch = new Stopwatch();
			byte[] bytes = new byte[32];
			pingOptions.DontFragment = true;
			pingOptions.Ttl = 1;

			for (int i = 1; i &lt; maximumHops + 1; i++) {
				TraceLocation traceLocation = new TraceLocation();

				stopWatch.Reset();
				stopWatch.Start();
				PingReply pingReply = pingSender.Send(
					ipAddress,
					5000,
					new byte[32], pingOptions);
				stopWatch.Stop();

				traceLocation.Hop = i;
				traceLocation.Time = stopWatch.ElapsedMilliseconds;
				if (pingReply.Address != null) {
					traceLocation.IpAddress = pingReply.Address.ToString();
				}

				traceLocations.Add(traceLocation);
				traceLocation = null;

				if (pingReply.Status == IPStatus.Success) {
					break;
				}
				pingOptions.Ttl++;
			}
		}
		return traceLocations;
	}
}

}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.NetworkInformation;
using System.Diagnostics;

namespace DnsConsoleApp { class Program { static void Main(string[] args) { List domainNames = new List(); domainNames.Add(“strivinglife.com”);

		foreach (String domainName in domainNames) {
			Console.WriteLine("***" + domainName + "***");

			foreach (JamesRSkemp.Traceroute.TraceLocation traceLocation in JamesRSkemp.Traceroute.Trace.Traceroute(domainName)) {
				Console.Write(traceLocation.Hop + "	");
				Console.Write(traceLocation.Time + "ms	");
				Console.Write(traceLocation.IpAddress + "	");
				if (!String.IsNullOrWhiteSpace(traceLocation.IpAddress) &amp;&amp; !traceLocation.IpAddress.StartsWith("10.") &amp;&amp; !traceLocation.IpAddress.StartsWith("192.")) {
					try {
						Console.WriteLine(Dns.GetHostEntry(traceLocation.IpAddress).HostName.ToString());
					} catch (Exception ex) {
						Console.WriteLine(ex.Message);
					}
				} else {
					Console.WriteLine();
				}
			}
			Console.ReadKey();
		}
	}
}

}

Next steps

It would probably make sense to allow the application to accept domain names/IPs on the fly, and what an IP resolves to could be cached.

Comments and etcetera welcome.