用C#实现IP的路由跟踪- -

来源:互联网 发布:加尔默罗修女知乎 编辑:程序博客网 时间:2024/05/21 01:44
ICMP协议可以被用来跟踪显示一个从主机发送出去的IP包从发送源到达目标主机所经过的路由IP,下面就利用C#语言,在.Net环境中,使用ICMP协议来实现一个具有IP路由跟踪功能的应用.ICMP(Internet Control Message Protocal)协议为了编写本实例,了解ICMP协议是非常必要的。在互联网络系统中,主机与主机之间的寻址使用IP协议。源地址通过IP地址来同目标进行通信,但有的时候,目标主机也会同源地址进行通信,比如,向源主机报告寻址处理的错误等。对于主机探测、路由维护、路由选择以及流量控制等网络功能来说,通常会用到ICMP协议。ICMP建立在IP协议的基础上,好像它是更高级的协议,而实际上ICMP是IP的一个主要部分,在每一个IP模块它都必须被执行。当出现下面的某个情况时(仅仅是部分情况),ICMP会有信息被反馈:寻址无法到达目标网关对于到来的寻址数据包没有了缓冲能力网关遇到生存周期为0的报文事实上,IP协议本身并没有被设计成绝对的可靠,上面的一些控制信息被用来反馈通信环境中出现的问题,但这并不能保证IP包的可靠传输。更高级的协议为了保证绝对可靠传输,通常都加入了新的传输机制。ICMP设计的目的是使网络用户可以检测网络连接的状况以及保证连接的准确性。实现原理利用ICMP协议实现路由跟踪的原理如下。对于ICMP的超时报文,如果网关发现报文的生存周期(TTL)为0,则该数据报必须被抛弃,且网关会向源主机发送超时通知。通过构造ICMP包的IP包头中的TTL字段可以实现这样的发送包。具体过程是这样:假设IP将要到达的目标地址需要经过K个路由器(K > 1),则进行下面工作。1) 构造一个ICMP包,TTL = 1,发送后得到第一个数据路由器的超时报文。2) 构造第S(S < K)个ICMP包,TTL = S,则可以得到第S个数据路由器的超时报文。具体实现添加名称空间为了使用C#的某些网络函数,需要添加下面的名称空间。using System.Net;using System.Net.Sockets;定义ICMP结构在构造ICMP包时,需要首先定义几个ICMP包用到的结构。 struct ICMPConstants { public const int ICMP_ECHOREPLY= 0; public const int ICMP_TIMEEXCEEDED= 11; public const int ICMP_ECHOREQ= 8; public const int MAX_TTL= 256; } //ICMP 包头 struct ICMP { public byte type; public byte code; public ushort checksum; public ushort id; public ushort seq; // 次序 } // ICMP 应答请求 struct REQUEST { public ICMP m_icmp; public byte []m_data;}函数CreatePacket函数CreatePacket用来构造一个符合要求的ICMP数据包,具体实现如下:public static byte[] CreatePacket( REQUEST req ){ Byte[] ByteSend= new Byte[PACKET_SIZE+ 8]; ByteSend[0]= req.m_icmp.type; ByteSend[1]= req.m_icmp.code; Array.Copy(BitConverter.GetBytes(req.m_icmp.checksum), 0, ByteSend, 2, 2); Array.Copy(BitConverter.GetBytes(req.m_icmp.id), 0, ByteSend, 4, 2); Array.Copy(BitConverter.GetBytes(req.m_icmp.seq), 0, ByteSend, 6, 2); for(int i=0; i< req.m_data.Length; i++) ByteSend[i+8]= req.m_data[i]; //计算校验和 int iCheckSum = 0; for (int i= 0; i < ByteSend.Length; i+= 2) iCheckSum += Convert.ToInt32( BitConverter.ToUInt16(ByteSend,i)); iCheckSum = (iCheckSum >> 16) + (iCheckSum & 0xffff); iCheckSum += (iCheckSum >> 16); Array.Copy(BitConverter.GetBytes((ushort)~iCheckSum), 0, ByteSend, 2, 2); return ByteSend; }主函数以下是主函数Main()的具体实现。static void Main(string[] args){ try { if(args.Length== 0) { Console.WriteLine("使用方法: tracedemo "); return; } Socket s= new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);//目标 IPEndPoint ipdest= new IPEndPoint(Dns.Resolve(args[0]).AddressList[0],80); //源 IPEndPoint ipsrc= new IPEndPoint(Dns.GetHostByName(Dns.GetHostName()).AddressList[0],80); EndPoint epsrc= (EndPoint)ipsrc; ICMP ip= new ICMP(); ip.type = ICMPConstants.ICMP_ECHOREQ; ip.code = 0; ip.checksum = 0; ip.id = (ushort)DateTime.Now.Millisecond; ip.seq = 0; REQUEST req= new REQUEST(); req.m_icmp= ip; req.m_data = new Byte[PACKET_SIZE]; //初始化数据 for (int i = 0; i < req.m_data.Length; i++) { req.m_data[i] = (byte)'S'; } Byte[] ByteSend= CreatePacket(req); //发送请求 for(int ittl=1; ittl<= ICMPConstants.MAX_TTL; ittl++) { Byte[] ByteRecv = new Byte[256]; //Socket options to set TTL and Timeouts s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, ittl); s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout,10000); s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout,10000); //取得当前时间 DateTime dt= DateTime.Now; int iRet= s.SendTo(ByteSend, ByteSend.Length, SocketFlags.None, ipdest); //check for Win32 SOCKET_ERROR if(iRet== -1) Console.WriteLine("error sending data"); //接收 iRet= s.ReceiveFrom(ByteRecv, ByteRecv.Length, SocketFlags.None, ref epsrc); TimeSpan ts= DateTime.Now - dt; //检验申请返回的数据 if(iRet== -1) Console.WriteLine("error getting data"); Console.WriteLine("TTL= {0,-5} IP= {1,-20} Time= {2,3}ms",ittl,((IPEndPoint)epsrc).Address,ts.Milliseconds); if((iRet == PACKET_SIZE+ 8 +20)&& (BitConverter.ToInt16(ByteRecv,24) == BitConverter.ToInt16(ByteSend,4))&& (ByteRecv[20] == ICMPConstants.ICMP_ECHOREPLY)) break; //超时 if(ByteRecv[20] != ICMPConstants.ICMP_TIMEEXCEEDED) { Console.WriteLine("unexpected reply, quitting..."); break; } } } catch(SocketException e) { Console.WriteLine(e.Message); } catch(Exception e) { Console.WriteLine(e.Message); }}以上就是本例的完整代码实现,代码在Visual Stuido.Net 2002 C#编译环境中,Windows2000 Profession操作系统下调试通过。
原创粉丝点击