您的位置:首页 > 编程语言 > C#

[C#]路由跟踪tracert

2013-11-07 16:55 246 查看
using System;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Net;
using System.Net.NetworkInformation;

namespace tracert
{
class Program
{
static byte[] PING_BUFFER = new byte[] { 0 };

static int g_nHops = 30;
static int g_nTimeout = 3000;
static bool g_bCanceled = false;

public struct ICMP_PARAM
{
internal long m_nSendTicks;
internal IPAddress m_IPAddress;
internal PingOptions m_PingOptions;
}

static void icmp_PingCompleted(object sender, PingCompletedEventArgs e)
{
ICMP_PARAM param = (ICMP_PARAM)e.UserState;
long nDeltaMS = (DateTime.Now.Ticks - param.m_nSendTicks) / TimeSpan.TicksPerMillisecond;
Console.WriteLine("{0}:\t{1} ms\t{2}",
param.m_PingOptions.Ttl,
(e.Reply.Status == IPStatus.TimedOut) ? "*" : nDeltaMS.ToString(),
e.Reply.Address.ToString());

if (param.m_IPAddress.Equals(e.Reply.Address))
{
Console.WriteLine("已到达目标地址!");
g_bCanceled = true;
return;
}

if (param.m_PingOptions.Ttl >= g_nHops)
{
Console.WriteLine("已达到最大跃点计数!");
g_bCanceled = true;
return;
}

Ping icmp = (Ping)sender;
param.m_PingOptions.Ttl++;
param.m_nSendTicks = DateTime.Now.Ticks;
icmp.SendAsync(param.m_IPAddress, g_nTimeout, PING_BUFFER, param.m_PingOptions, param);
}

static void Usage()
{
Console.WriteLine("Usage: {0} [-h max_hops] [-w timeout] ip/domain", Process.GetCurrentProcess().ProcessName);
}

static void Main(string[] args)
{
string szDomain = "";
if (args.Length == 0)
{
Usage();
return;
}
else
{
string szTmp = "";
for (int i = 0; i < args.Length; i++)
{
if (args[i].StartsWith("-"))
{
if (args[i].Length == 2)
{
if (i + 1 < args.Length)
{
szTmp = args[i + 1];
}
else
{
Usage();
return;
}
}
else
{
szTmp = args[i].Substring(2);
}

switch (args[i][1])
{
case 'h':
case 'H':
if (!int.TryParse(szTmp, out g_nHops))
{
Usage();
return;
}
break;

case 'w':
case 'W':
if (!int.TryParse(szTmp, out g_nTimeout))
{
Usage();
return;
}
break;

default:
Usage();
return;
}
}
else
{
szDomain = args[i];
}
}
}

Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

ICMP_PARAM param = new ICMP_PARAM();
param.m_PingOptions = new PingOptions(1, false);
if (!IPAddress.TryParse(szDomain, out param.m_IPAddress))
{
// 解析域名
try
{
Regex regEx = new Regex("\\d+\\.\\d+\\.\\d+\\.\\d+");
IPHostEntry hostEntry = Dns.GetHostEntry(szDomain);
foreach (IPAddress ipAddr in hostEntry.AddressList)
{
if (regEx.IsMatch(ipAddr.ToString()))
{
param.m_IPAddress = ipAddr;
break;
}
}

if (param.m_IPAddress == null)
{
Usage();
return;
}

Console.WriteLine("正在跟踪到 {0}[{1}] 间的路由:", szDomain, param.m_IPAddress.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return;
}
}
else
{
Console.WriteLine("正在跟踪到 {0} 间的路由:", param.m_IPAddress.ToString());
}

Ping icmp = new Ping();
icmp.PingCompleted += new PingCompletedEventHandler(icmp_PingCompleted);

param.m_nSendTicks = DateTime.Now.Ticks;
icmp.SendAsync(param.m_IPAddress, g_nTimeout, PING_BUFFER, param.m_PingOptions, param);

while (!g_bCanceled)
{
Thread.Sleep(1);
}
}

static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("程序被终止!");
}
}
}


tracert的原理比较简单,每个路由器收到ICMP报文都会将TTL减一再发送到下一个路由,当TTL减少到0时将值返回源IP地址,可以利用这个原理从1开始逐步增加TTL的值来获取到指定IP路径上经过的路由IP。附上的代码是C#控制台代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: