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 {
        /// <summary>
        /// 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
        /// </summary>
        /// <param name="ipAddressOrHostName">IP address or domain name to trace.</param>
        /// <param name="maximumHops">Maximum number of hops before quitting.</param>
        /// <returns>List of TraceLocation.</returns>
        public static List<TraceLocation> Traceroute(string ipAddressOrHostName, int maximumHops) {
            if (maximumHops < 1 || maximumHops > 100) {
                maximumHops = 30;
            }

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

            List<TraceLocation> traceLocations = new List<TraceLocation>();

            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 < 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) && !traceLocation.IpAddress.StartsWith("10.") && !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.