Tracert, a command line utility in Windows, displays the IP addresses of the nodes that a network packet encounters while it travels to a destination host from a source. There are some articles, here on CP, that show how to implement tracert functionality:
- CTraceRoute v1.0 by P. J. Naughter.
- Trace route using raw sockets by Babar Qaisrani
The above articles use C++ code, and I needed something in C# for .NET framework 2.0. Luckily, the .NET framework 2.0 has a
Ping component which is used by the code presented in this article to implement a tracert component.
Using the Tracert Component?
The simplest way to use the component in your project is to add the component to the VS.NET toolbox and drag and drop to the appropriate designer surface. If you add the tracert project as a reference to another project, then the
Tracert component is automatically available in the VS.NET toolbox as shown in the screenshot below. Also shown is how the component appears when it is dropped on the design surface.
Once you have added the component to the design surface, you need to set the properties of the component. The most important property you need to set is the
HostNameOrAddress property, which can either be set to a host name or an IP address.
tracert.HostNameOrAddress = "www.codeproject.com";
tracert.HostNameOrAddress = "22.214.171.124";
Next, you need to assign event handlers to the events exposed by the component. This is because the component does its work asynchronously. There are two events you can use:
Done. You can handle the
RouteNodeFound event to find out intermediate nodes as they are found.
In the code snippet below, the IP address of the nodes are added to a list view as they are found.
private void tracert_RouteNodeFound(object sender, RouteNodeFoundEventArgs e)
ListViewItem item = routeList.Items.Add(e.Node.Address.ToString());
Finally, you need to handle the
Done event to find whether the trace process has finished.
tracert.Done += new System.EventHandler(this.tracert_Done);
private void tracert_Done(object sender, EventArgs e)
IPAddress address = tracert.Nodes[i].Address;
Finally, the actual tracing itself can be started by calling the
This is the simplest and the most common way to use the component. You can further control the behavior of the component by setting some additional properties as described in the next section.
Tracert Component Reference
This component has public properties as described below.
|Maximum number of network hops to take to reach the destination. The tracert process aborts after the maximum number of hops even if the destination is not reached. The default value is 30.|
|Array of |
|This returns all the nodes in the path.|
|The name of the host like www.codeproject.com/, or the IP address in string form like 126.96.36.199.|
|The is the time, in milliseconds, to wait for a particular node to respond before moving to the next node in the path. The default value is 5000.|
true, then it indicates that the destination has been reached, or the maximum number of hops have been taken.
The methods of this control are as follows:
|Method Name||Return Value||Description|
|This method starts the actual route tracing. You must set the |
HostNameOrAddress property before calling this method. This method works asynchronously.
The events are as follows:
|This event is fired when the route tracing is finished. This can happen either when the destination host is reached, or when the maximum hops have been taken.|
|This event is fired when an intermediate node has been found on a path. The RouteNodeFoundEventArgs argument supplied to the event handler contains additional information about the node.|
An argument of type
RouteNodeFoundEventArgs is passed to the event handler for the
RouteNodeFound event. The properties of this class are the following:
|Indicates the node found in the iteration.|
TracertNode class is used to encapsulate a node in the path; it has the following properties.
|Indicates the IP Address of the node. The address is equal to |
IPAddress.Any (0.0.0.0 ) if an error or timeout occurs.
|The interval in milliseconds from the moment the packet was sent to the node and an acknowledgement received by the sender.|
|The status of the ping request sent to the node. This can be either |
How Tracert Works?
When you send a Ping request to a destination, you have an option to specify the TTL (time-to-live) value. As a network packet travels from one intermediate host to another, its TTL value is reduced by one. When the TTL value becomes zero, the sender gets an error acknowledgement - TTL exceeded. The sender can find out the IP address of the host from which this acknowledgement was received. So, if you set the TTL value to 1 and send a packet to the destination, the packet will be returned by the first node in the path. If you then set the TTL value to 2 and send the packet again, then it will be returned by the second host in the path, and so on. You can continue this process of incrementing the TTL values till the destination has arrived or the maximum number of hops has been reached. The figure below shows a sample network path and the behavior of a network packet:
The arrows in the diagram show the direction of the packet. The bold line shows the path traversed by the packet. The dotted line indicates that the network packet may have traversed the path had the TTL not expired. Now that we have a brief understanding of the way
Tracert works, let's look at how it can be implemented in code.
Implementing Tracert in Code
We will be using the .NET framework's
Ping class to implement the tracert functionality. Let's start directly with a code snippet.
_ping = new Ping();
_ping.PingCompleted += new PingCompletedEventHandler(OnPingCompleted);
_options = new PingOptions(1, true);
_ping.SendAsync(_destination, _timeout, Tracert.Buffer, _options, null);
Ping class can send the ping request either synchronously using the
Send method, or asynchronously using the
SendAsync method. When the
SendAsync method is used, the event
PingCompleted is fired to notify the completion of the request. The
SendAsync method has many different overloads. In the overload used in the above code, the parameters are as follows:
|This is the IP address of the final destination.|
|The time, in milliseconds, to wait for the network request to complete.|
|The byte buffer to send as request. This is taken from a static variable. In our sample, the buffer is a 32 byte array filled with the ASCII code of character A.|
An object of type
PingOptions which indicates the TTL values and also a boolean value that indicates whether the buffer should be fragemented or not. For the initial call, we choose a TTL value of 1. We also choose not to fragment the buffer (in my tests, I have not seen this value impacting the results in any way).
null (the last parameter)
The last parameter is a user defined object that is provided in the
PingCompleted event handler. We will not be using this, so we pass a
Once the request completes, either successfully or unsucessfully, the event handler for the
PingCompleted event is called. In our case, this is the
void OnPingCompleted(object sender, PingCompletedEventArgs e)
if (_ping == null)
_options.Ttl += 1;
Tracert.Buffer, _options, null);
OnPingCompleted function is called with two arguments. The first argument is the
sender object which will be the original
Ping object on which we invoked the
SendAsync method. The argument
e is of type
PingCompletedEventArgs, and provides more information about the event. The important member of the
PingCompletedEventArgs is the
Reply member. This member provides the
IPAddress of the nodes where the packet expired, and a status value. The status value is set to
IPStatus.TtlExpired when the destination is not reached by the packet; otherwise, it will be set to
IPStatus.Success. We process the intermediate node in the
protected void ProcessNode(IPAddress address,
long roundTripTime = 0;
if (status == IPStatus.TtlExpired ||
status == IPStatus.Success)
Ping pingIntermediate = new Ping();
PingReply reply = pingIntermediate.Send(
roundTripTime = reply.RoundtripTime;
status = reply.Status;
catch (PingException e)
TracertNode node = new TracertNode(address, roundTripTime,
if (RouteNodeFound != null)
new RouteNodeFoundEventArgs(node, this.IsDone));
this.IsDone = address.Equals(_destination);
if (!this.IsDone && _nodes.Count >= _maxHops - 1)
ProcessNode method, we ping the node again. This is because we want to obtain the round trip time to the destination. The
PingReply class does return the round trip time, but it does only when the packet has successfully reached the destination. Once we obtain the round trip time, we fire the
RouteNodeFound event. Next, we add the destination node to the list of nodes. Finally, we check whether we have reached the final destination. If it is true, we set the
IsDone property to
true. This is, in brief, how the component works.
- June 25, 2006: Initial submission.