Sept. 24, 2007, 1:15 a.m.
posted by vendetta
The TraceRoute.cs Program
A close cousin to ping is traceroute. The traceroute program sends an ICMP Echo Request to a remote host, but with a twist. To determine what routers the ICMP packet travels through to reach its destination, traceroute exploits another ICMP message packet.
By setting the IP packet TTL (time to live) to increasing values, the traceroute program can force the ICMP packet to die at different points along its path to the destination host. Each time the TTL value expires, the last receiving network router sends an ICMP Time Exceeded (Type 11) packet back to the sending host. By starting off with a TTL of 1 and increasing it by 1 after each attempt, the traceroute program forces each router along the network path to return an ICMP Time Exceeded packet. By displaying the sending address of each packet, you can watch each router along the path of the ping packet.
The traceroute operation can be implemented by using the SetSocketOption() method call and the IPTimeToLive socket option to manipulate the TTL value in the IP packet. Again, the newly created ICMP class will be used, creating an Echo Request packet to send to the remote host. Because only the IP TTL value is changed, the ICMP packet can be created once and used for all of the attempts.
The TraceRoute.cs program, Listing 11.5, implements these features.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class TraceRoute
{
public static void Main (string[] argv)
{
byte[] data = new byte[1024];
int recv, timestart, timestop;
Socket host = new Socket(AddressFamily.InterNetwork,
SocketType.Raw, ProtocolType.Icmp);
IPHostEntry iphe = Dns.Resolve(argv[0]);
IPEndPoint iep = new IPEndPoint(iphe.AddressList[0], 0);
EndPoint ep = (EndPoint)iep;
ICMP packet = new ICMP();
packet.Type = 0x08;
packet.Code = 0x00;
packet.Checksum = 0;
Buffer.BlockCopy(BitConverter.GetBytes(1), 0, packet.Message, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(1), 0, packet.Message, 2, 2);
data = Encoding.ASCII.GetBytes("test packet");
Buffer.BlockCopy(data, 0, packet.Message, 4, data.Length);
packet.MessageSize = data.Length + 4;
int packetsize = packet.MessageSize + 4;
UInt16 chcksum = packet.getCchecksum();
packet.Checksum = chcksum;
host.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, 3000);
int badcount = 0;
for (int i = 1; i < 50; i++)
{
host.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.IpTimeToLive, i);
timestart = Environment.TickCount;
host.SendTo(packet.getBytes(), packetsize, SocketFlags.None, iep);
try
{
data = new byte[1024];
recv = host.ReceiveFrom(data, ref ep);
timestop = Environment.TickCount;
ICMP response = new ICMP(data, recv);
if (response.Type == 11)
Console.WriteLine("hop {0}: response from {1}, {2}ms",
i, ep.ToString(), timestop-timestart);
if (response.Type == 0)
{
Console.WriteLine("{0} reached in {1} hops, {2}ms.",
ep.ToString(), i, timestop-timestart);
break;
}
badcount = 0;
} catch (SocketException)
{
Console.WriteLine("hop {0}: No response from remote host", i);
badcount++;
if (badcount == 5)
{
Console.WriteLine("Unable to contact remote host");
break;
}
}
}
host.Close();
}
}
The TraceRoute.cs program creates a normal ICMP Echo Request packet and then enters a loop, setting the IP TTL value to increasing values until the destination host is reached:
for (int i = 1; i < 50; i++)
{
host.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.IpTimeToLive, i);
timestart = Environment.TickCount;
host.SendTo(packet.getBytes(), packetsize, SocketFlags.None, iep);
Each time an Echo Request packet is sent out, the program waits for a response. The Type element of the return packet is examined to determine if the packet made it to the destination. Two types of ICMP packets will be returned:
-
Time Exceeded (Type 11) packets sent from routers when the TTL value expires
-
Echo Reply (Type 0) packets sent from the destination host when the Echo Request packet is received
By examining the source of the Time Exceeded packets, you can see what routers are in the network path to the destination device. It is possible that some routers in the network path are configured to ignore ICMP packets. They will produce the “no response from host” error message, but the TTL value will be increased and the next router will be queried. Typically, you’ll run across several routers in a network path that ignore ICMP packets. However, it is also possible that the destination host either won’t respond to the ICMP packet or won’t even be active. In that case, to prevent an endless loop of packets, after five no responses, the program assumes that the remote host cannot be reached.
Also, similar to the AdvPing program, the Environment.TickCount property value measures the time it takes for the response to the Echo Request packet for each router.
Here, too, you must compile the TraceRoute.cs program with the ICMP.cs file included on the compiler command line:
csc TraceRoute.cs ICMP.cs
Testing TraceRoute.cs
You can test the TraceRoute.cs program by running it from a command-prompt window, using a known host that responds to pings:
C:\>TraceRoute www.cisco.com hop 1: No response from remote host hop 2: response from 206.148.207.106:0, 220ms hop 3: response from 65.123.106.113:0, 140ms hop 4: response from 205.171.20.125:0, 141ms hop 5: response from 205.171.20.142:0, 140ms hop 6: response from 205.171.1.162:0, 130ms hop 7: response from 144.232.26.54:0, 130ms hop 8: response from 144.232.8.117:0, 191ms hop 9: response from 144.232.3.138:0, 190ms hop 10: response from 144.228.44.14:0, 190ms hop 11: response from 128.107.239.89:0, 190ms hop 12: response from 128.107.239.102:0, 191ms 198.133.219.25:0 reached in 13 hops, 180ms. C:\>
As you can see, it took 13 hops to get from my workstation connected to an ISP, to the www.cisco.com host. From the hops, you can see the IP addresses of the individual routers that pass the packet on to the destination address. The first router in the path did not send an ICMP packet back when the TTL value expired.
Notice the different response times for each router along the path. The response times do not necessarily get longer as the hops get larger because some networks and equipment are faster than others.
Sometimes it is interesting to watch the routes for several remote network addresses. Often networks out on the Internet route traffic to various sites through vastly different paths. You can often see how your ISP connects to the Internet by tracing the routes to remote sites.