1、1Traceroute 程序设计与实现学生姓名: 樊冠宇 指导老师:姜文超摘 要 本文主要讲述了路由追踪的基本程序设计与实现,并给出了一种基于IP网络的路由追踪命令Tracert,详细分析了实现路由追踪的基本原理,归纳了路由追踪的基本流程。Tracert通过ICMP协议和 header中(存活时间)利用路由器对数据报存活时间的处理方式来实现路由探测的。首先根据任务书设计好流程图,然后编写程序代码,运行得到Traceroute的命令窗口。提取tracert的输出,再结合现有IP数据库及自建地名- 坐标数据库对路由中各节点IP进行定位,最终实现了动态显示追踪的详细信息和路径。关键词: IP 地址,
2、ICMP 协议,TTL,Tracert 路由追踪121 引 言Internet,是目前世界上最大的计算机网络,更确切的说是网络中的网络,它由遍布全球的几万局域网和数百万台计算机组成,并通过用于异构网络的TCP/IP 协议进行网间通信。互联网中,信息的传送是通过网中许多段的传输介质和设备从一端到达另一端。每一个连接在 Internet 上的设备,如主机、路由器、接入服务器等一般情况下都会有一个独立的 IP 地址。通过 Traceroute 我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路劲。当然每次数据包由某一同样的出发点到达某一同样的目的地走的路劲可能会不同,但基本上来说大部分时候
3、所走的路由是相同的。随着 Internet(国际互联网)的发展,越来越多的服务通过网络提供给大众,与此同时,针对互联网的攻击事件也越来越频繁。所谓路由追踪实际上就是在 IP 网络上判断从源到达目的所经过的路由器的 IP 地址,其基本的实现手段都是向目的地发送数据包以获取经过的路由器的 IP。由于 Internet 上的路由协议是动态的,所以每次形成的数据包从同一个出发点到达目的地的路由可能会不一样,但由于路由算法有一定的稳定性,在大部分时侯所走的路由会是相同的。1.1 课程设计目的1.这次课程设计,主要为了加深同学们对计算机网络网络的理解和认识2.了解信息在计算机网络与网络之间的传送和接收3.
4、进一步加深了解网络与网络之间的协议4.理解网络中的 IP 地址以及路由之间的相关命令。1.2 课程设计内容1.已知参数:输入:目的节点 IP 地址或主机名;输出:从控制台屏幕输出 IP报文由本机出发到达目的主机所经过的路由信息。2.设计要求:通过原始套接字编程,实现 Tracert 的基本功能132.1 初始化 Windows Sockets 网络环境;2.2 解析命令行参数,构造目的端 socket 地址;2.3 定义 IP、ICMP 报文;2.4 接收 ICMP 差错报文并进行解析。1.3 课程设计要求(1)按要求编写课程设计报告书,能正确阐述设计结果。(2)通过课程设计培养学生严谨的科学
5、态度,认真的工作作风和团队协作精神。(3)学会文献检索的基本方法和综合运用文献的能力。(4)在老师的指导下,要求每个学生独立完成课程设计的全部内容。2 设计原理raceroute 是一个路由跟踪命令,它通过 ICMP 协议和 header 中(存活时间)来实现的。 具体而言就是:发送方发出一个是的IP Datagram (事实上每个数据包发送三次,大小为 40 字节,包括本机的 IP 地址,目的主机的 IP 地址以及时间戳) ,当经由第一个路由器时,路由器将该数据包的 TTL 减 1,发现此时的 TTL 为 0,将数据包丢失,同时向源主机发送一个 ICMP Time-to-Exceed 报文(
6、包括源主机的 IP 地址、路由地址以及路由的相关消息) ,源主机收到这个数据包后就知道了这个路由器在这条路径上。同理发送第二个、第三个第 n 个。源主机将每次数据报的,直到某个数据报到达了目的地址,此时不知发回一个 ,而是发送一个数据报的响应报文。当源主机收到这样一个报文后便知道数据包已经到达了目的地。Traceroute 提取发 ICMP TTL 到期消息设备的 IP 地址并作域名解析。每次 ,Traceroute 都打印出一系列数据,包括所经过的路由设备的域名及 IP 地址 ,三个包每次来回所花时间。Traceroute 有一个固定的时间等待响应(ICMP TTL 到期消息)。如果这个时间
7、过14了,它将打印出一系列的*号表明:在这个路径上,这个设备不能在给定的时间内发出 ICMP TTL 到期消息的响应。然后,Traceroute 给 TTL 记数器加 1,继续进行。2.1ICMP 简介和基本原理ICMP(Internet Control Message Protocol),即 Internet 控制报文协议, 它是TCP/IP 协 议 族的一个子协议 ,属于网络层面向无连接的协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。当遇到IP 数据无法访问目标、IP 路由器无法按当前的传输速率转发数 据 包 等情况时,会自动发送 ICMP 消息。
8、ICMP 报文被包装成 IP 数据包传到数据链路层进行传输。通过 ICMP 协议,主机和路由器可以报告错误并交换相关的状态信息。ICMP 对于 TCP/IP 协议的可靠运行是至关重要的。 ICMP 报文结构如图 1 所示:2.2traceRoute 程序的基本原理路由追踪的主要原理是根据路径上各路由器对数据报的存活时(Time to Live,TTL)做不同的处理,使其产生超时 ICMP 消息响应,反馈至源主机,从而获得此跳路由器或主机的 IP。照此再发送下一个 TTL 经过自增的数据报,直至获得整个路由中各节点的 IP 或者接收到错误的消息。详细过程描述如下:1) 置 n = 1。假设该过程
9、中共经过 M 个路由器。2) 源主机 S 向目标主机 D 发送一个 TTL 为 n 的 UDP 数据报。并设定端口号(一般大于 30 000) 。3) 路由器(或者网关、主机) Rn 对接收到的数据报的 TTL 值 n 做减 1 处理。4) 若 n = 0,则丢弃 UDP 数据报,向源主机 S 发送 ICMP 超时报文。155) 若 n 1,继续向目标主机 D 发送经过处理的数据报。6) 源主机 S 分析返回的 ICMP 报文, 从中提取出发送者 Rn 的地址 IPn 并做记录。7) 若收到“端口不可达”的 ICMP 报文,则发送方即目标主机 D,记录其地址 IPn,追踪完成。8) 置 n =
10、 n +1,继续向目标主机 D 发送 TTL 为 n 的数据报。注意,这里使 UDP 数据报的端口号大于 30000,是因为一般的应用程序不可能使用如此高的端口号。当然这并非绝对,若出现例外,则源主机会发现等待超时,于是随机改变此 UDP 数据报的端口号,再次发送。这样最终可以在目标主机上找到一个空闲的端口号。另外,这里假设路由器和目标主机没有被配置为“过滤 ICMP”或者做了其他的非常规处理,如果被做了类似的配置,则上面的追踪机制就无能为力了。2.3traceRoute 实现的功能IP 数据报的首部由两部分构成:固定部分和可变部分。固定部分的长度是20 个字段,可变部分由许多选项构成,最长可
11、达 40 个字节。虽然选项并不是IP 数据报的必需部分,但选项的处理却是 IP 软件的必需部分。在现在的 TCP/IP 协议中,只定义了六种选项,对于我们进行路由追踪技术有用的是记录路由选项,一个记录路由选项是用来记录处理 IP 数据报的互联网路由器的 IP 地址。因为首部的最大长度是 60 个字节,它包括 20 个字节的基本首部。这就意味着只剩下 40 个字节留下给选项部分,所以通过选项字段最多能够记录 9 个路由器的 IP 地址。源站在选项中创建一个位标置(placeholder),用来填入所经过的各路由器,图 2 给出了记录路由选项的格式。图 2 记录路由选项16向目的主机发送一个 IC
12、MP 报文,这种方法只要求使用一个套接字。ICMP 即Internet 控制报文协议,是一种用于特殊用途的报文机制,可以使互联网中的路由器或主机报告差错或提供有关意外情况的信息。尽管 UDP 和 ICMP 工作在TCP/IP 的不同层次上,但他们的封装是类似的。ICMP 报文为两级封装 ICMP 报文放在 IP 数据报的数据部分,数据报则放在帧的数据中进行网络传输(如图 3 所示)ICMP 报文与其他普通报文一样,具有相同的路由选择,并没有特殊的优先权和增加可靠性。通过路由选项的方法记录路由的实现同 UDP 数据报是相似的,这里主要说明通过 TTL 方法的实现。图 3 ICMP 报文的两级封装
13、3 设计步骤分析本次课程设计的任务书,整个课程设计的过程大致可以分为三个步骤:第一步主要是设计好流程图;第二步是根据流程图编写程序代码;第三步是在程序编译通过后,运行程序结果,在对话框中输入要追踪的 IP 地址,观察路由追踪命令追踪 IP 地址在网络中的运行。其中第一步跟第二步是关键,只有完整的流程图和根据要求编写好正确的程序,才能运行得到正确的结果。下面是整个设计过程中各个步骤的详细分析。173.1traceroute 流程图根据要求设计好的流程图如图 4 所示:图 4 流程图3.2traceroute 的核心程序整个设计过程的核心程序代码:#include “stdafx.h“#inclu
14、de “MyPing.h“#include “Ping.h“#include “MyPingDlg.h“#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE=_FILE_;#define new DEBUG_NEW#endifvoid CPing:Ping(int timeout) m_hSocket = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, 18NULL, 0,WSA_FLAG_OVERLAPPED);if (m_hSocket = INVALID_SOCKET) AfxMessageBox(“
15、socket 创建失败!“);return ;Start sending/receiving ICMP packets 开始发送/接收 ICMP 的数据包/static int nCount = 0;静态的 nCount = 0。int nCount=0;while(1) int bwrote;if (nCount+ = 4) break;(IcmpHeader*)icmp_data)-i_cksum = 0;(IcmpHeader*)icmp_data)-timestamp = GetTickCount();(IcmpHeader*)icmp_data)-i_seq = seq_no+;(I
16、cmpHeader*)icmp_data)-i_cksum = checksum(USHORT*)icmp_data, datasize);bwrote = sendto(m_hSocket, icmp_data, datasize, 0, (struct sockaddr*)if (bwrote = SOCKET_ERROR) if (WSAGetLastError() = WSAETIMEDOUT) m_dlg-m_result+=“Timed out ! rn“;m_dlg-SetDlgItemText(IDC_EDIT2,m_dlg-m_result);continue; AfxMes
17、sageBox(“发送数据函数调用错误 !“);return ;3.3traceroute 程序运行结果在运行程序后得到的 对话框中输入 ,再单击路由跟踪,就可以详细的观察到路由整个的跟踪过程,如图 5 所示:19图 5 路由跟踪示意图4 总结在整个课程设计过程中,首先得仔细分析课程设计任务书,根据要求编写好程序代码,然后运行程序,分析得到的结果。在编写代码过程中,遇到许多问题。开始看到题目不知道该如何下手去做。编写好的代码,在 VC+平台上运行时,总是出现错误,最终在老师的帮助下,成功的解决了该问题。还有在宿舍运行 tracert 后一闪就没了, 也不知道是什么原因,上网查找了解到,必须得
18、先运行 CMD,然后在 CMD 里运行其他命令。成功的运行 tracert 后,出现的一连串数字,不知道是什么意思,结合老师上课所讲的东西并仔细分析才知道,192.168.20.45 是 IP 地址,0ms 是跳到下个 IP 地址所用的时间。从整体来说这次课程设计是成功的。但中间存在一些细节问题,程序代码过于复杂,没有很好的用语句解释出程序中的代码。每次课程设计都让我们学到了很多书本上学不到的东西,如严谨的做事风格,认真学习的态度,不懂要问的道理。因此,我们应该要认认真真的做好每一次的课程设计。1105 结束语通过这次课程设计,加强了我们动手、思考和解决问题的能力,让我们对网络和网络之间的信息
19、和数据的传送以及相关的协议有了更深刻的理解。在这次课程设计中,tracerroute 通过 ICMP 协议和 header 中(存活时间)利用路由器对数据报存活时间的处理方式成功的实现路由探测。跟踪到网络中数据 IP 地址的移动,但在跟踪过程中经常发生数据的丢失和网络超时。我认为做课程设计同时也是对课本知识的巩固和加强,由于课本的知识太多,平时课间的学习并不能很好的理解和运用,而且考试内容有限,所以在这次课程设计过程中,我们了解了很多网络之间的协议和路由跟踪的命令,并对抽象的网络有了更多的认识。然而,认识来源于实践,实践是认识的动力和最终目的,实践是检验真理的唯一标准,所以这次课程设计对我们来
20、说是受益匪浅。对我们而言,知识上的收获重要,精神上的丰收更是可喜。挫折是一份财富,经历是一份拥有,通过这次课程设计让我懂得了理论与实践相结合的重要性。只有理论知识是远远不够的,必须把平时所学的理论知识与实践结合起来,从理论中得出结论,才能真正的利用所学的东西为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到这样那样的难题,但是,在老师和同学们的帮助下,都顺利的解决了,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解的不够深刻,掌握的不够牢固。这次课程设计,让我学到了很多课内学不到的东西,比如团体合作,出现差错的随机应变等,那都是受益匪浅。在此,感谢我们指导
21、老师的细心指导,今后,我会加倍的努力学习。111参考文献1W Richard Stevens. TCP/ IP Illust rated ,Volum 1 :The ProtocolsM1 北京:机械工业出版社,2002.85296.2W Richard Stevens. UNIX Network ProgrammingVolum1Networking APIs :Socket s and XTI ( SecondEdition) (影印版) M . 北京: 清华大学出版社,2002.3日井口信和. TCP/ IP 网络工具篇M . 吴松芝,董江洪译. 北京:科学出版社,2003. 15821
22、62.4余青霓,王晓程,周钢,等. 网络入侵检测分析员手册Z.北京:人民邮电出版社,2000. 1012109.5JAMES F.KUROSE, KEITH W.Ross Computer Networking A Top2Down Approach Featuring the Internet (影印版) M.北京: 高等教育出版社,2001.6李为民,赵迎新,梁济仁,等. 网络连通性测试与故障定位J .计算机应用,2004 ,24(增刊):47249.7张保通.基于路由器的防火墙设计J .华北航天工业学院学报,2002,(2):11216219.附加程序清单:莫小锋 通信 0802 班 学
23、号:200885250224源程序:#include “stdafx.h“#include “TraceRoute.h“#include “Tracer.h“#include “TraceRouteDlg.h“#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE=_FILE_;#define new DEBUG_NEW#endif/ Construction/Destruction/IPstruct IPHEADER unsigned int h_len:4; / 首部长度unsigned int version:4; / 版本unsigned
24、char tos; / 服务类型unsigned short total_len; / 报文总长度unsigned short ident; / 标识unsigned short frag_and_flags; / 偏移量113unsigned char ttl; / 寿命unsigned char proto; / 协议unsigned short checksum; / 首部校验和unsigned int sourceIP; / 源站 IPunsigned int destIP; / 目的站 IP;/ICMP 首部数据结构struct ICMPHEADERBYTE i_type; / 类型
25、BYTE i_code; / 代码USHORT i_cksum; / 首部校验和USHORT i_id; / 标识USHORT i_seq; / 序列号ULONG timestamp; / 时间戳( 选用);CTracer:CTracer()m_nSeq=1;icmpData=NULL;icmpRcvBuf=NULL;m_hSocket=INVALID_SOCKET;/初始化 socketWSADATA wsaData;if(WSAStartup(MAKEWORD(2,2),CTracer:CTracer()/关闭 Socketif (m_hSocket!=NULL)closesocket(m
26、_hSocket); WSACleanup();/CheckSumUSHORT CTracer:CheckSum(char* pBuffer,int size) USHORT* buffer=(USHORT*)pBuffer;114unsigned long cksum=0;while(size 1) cksum += *buffer+;size -= sizeof(USHORT);if(size )cksum += *(UCHAR*)buffer;cksum = (cksum 16) + (cksum cksum += (cksum 16);return (USHORT)(cksum);/F
27、illAddressBOOL CTracer:FillAddress(char *addrDest)memset(m_addrDest.sin_family =AF_INET;if(inet_addr(addrDest)=INADDR_NONE)/输入的地址为计算机名字HOSTENT* hp=NULL;hp=gethostbyname(addrDest);if(hp)memcpy(m_addrDest.sin_family =hp-h_addrtype ;elseAfxMessageBox(“获取地址失败!“);return FALSE;elsem_addrDest.sin_addr.s_ad
28、dr=inet_addr(addrDest);return TRUE;/FillICMPDatavoid CTracer:FillICMPData(char* icmpData,int size)115memset(icmpData,0,size);ICMPHEADER* icmpHeader=NULL;icmpHeader=(ICMPHEADER*)icmpData;icmpHeader-i_type =ICMP_ECHO;icmpHeader-i_code =0;icmpHeader-i_id =(USHORT)GetCurrentProcessId();icmpHeader-i_seq
29、=m_nSeq+; /GetTickCount 返回从 0 点到现在的毫秒数,作时间戳icmpHeader-timestamp=GetTickCount();char* datapart=icmpData+sizeof(ICMPHEADER);memset(datapart,*,size-sizeof(ICMPHEADER);/填充校验和icmpHeader-i_cksum =CheckSum(icmpData,size);/设置数据报的寿命BOOL CTracer:SetTTL(SOCKET hSocket, int ttl)int result;result=setsockopt(hSoc
30、ket,IPPROTO_IP,IP_TTL,(LPSTR)if(result=SOCKET_ERROR)AfxMessageBox(“设置数据报寿命失败!“);TerminateProcess(GetCurrentProcess(),-1);return TRUE;/发送数据报BOOL CTracer:SendData(char* icmpData,int size)/填充 ICMP 报头FillICMPData(icmpData,size);/发送数据报int result;time1=GetTickCount();result=sendto(m_hSocket,icmpData,size,
31、0,(SOCKADDR*)if(result=SOCKET_ERROR)if(WSAGetLastError()=WSAETIMEDOUT)116(CTraceRouteDlg*)m_pWnd)-InfoAdd(“发送超时“);return TRUE;AfxMessageBox(“发送报文失败!“);TerminateProcess(GetCurrentProcess(),-1);return FALSE;/接收数据报BOOL CTracer:RecvData(char* icmpRcvBuf,int* presult)static int count=0;/总共 6 次出现接收超时,判断存在
32、连接问题。if(count5) AfxMessageBox(“连接存在问题!“);TerminateProcess(GetCurrentProcess(),-1);int fromlen=sizeof(SOCKADDR);*presult=SOCKET_ERROR;*presult=recvfrom(m_hSocket,icmpRcvBuf,MAX_PACKET,0,(SOCKADDR*)time2=GetTickCount(); if(*presult=SOCKET_ERROR)if(WSAGetLastError()=WSAETIMEDOUT)(CTraceRouteDlg*)m_pWnd
33、)-InfoAdd (“接收超时!“);count+;return TRUE;AfxMessageBox(“接收数据报失败!“);TerminateProcess(GetCurrentProcess(),-1);return FALSE;/处理接收到的数据报BOOL CTracer:DecodeICMP(char* pBuffer,int bytes,int ttl)IPHEADER *ipHeader=NULL;ICMPHEADER *icmpHeader=NULL;117unsigned short ipHeaderLen;HOSTENT *ph=NULL;in_addr inaddr=m
34、_addrFrom.sin_addr;ipHeader=(IPHEADER*)pBuffer;ipHeaderLen=20;if (bytesi_type)/目的站点的返回case ICMP_ECHOREPLY: ph=gethostbyaddr(const char *)if (ph != NULL)CString report;report.Format(“%2d %s (%s)“,ttl,ph-h_name,inet_ntoa(inaddr);(CTraceRouteDlg*)m_pWnd)-InfoAdd(report);return TRUE;break;/中途路由器的返回case
35、ICMP_TIMEOUT: CString report;report.Format(“%2d %s %2d ms“,ttl, inet_ntoa(inaddr),(time2-time1);(CTraceRouteDlg*)m_pWnd)-InfoAdd(report);return FALSE;break;/错误:主机不可达case ICMP_DESTUNREACH: CString report;report.Format(“%2d %s 主机不可达“,ttl,inet_ntoa(inaddr);(CTraceRouteDlg*)m_pWnd)-InfoAdd(report);retur
36、n TRUE;break;118/收到一个不是回应的报文default:CString report;report.Format(“非回应报文“);(CTraceRouteDlg*)m_pWnd)-InfoAdd(report);return TRUE;return FALSE;void CTracer:SetWnd(CDialog *pWnd)/设置窗口指针m_pWnd=pWnd;void CTracer:Trace(char *destAddress)int size=DEF_PACKET_SIZE+sizeof(ICMPHEADER);/转换地址if (!FillAddress(dest
37、Address) return ;/分配必要的内存空间icmpData=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);icmpRcvBuf=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);if(!icmpData|!icmpRcvBuf)AfxMessageBox(“分配内存空间失败!“);TerminateProcess(GetCurrentProcess(),-1);memset(icmpData,0,MAX_PACKET);mems
38、et(icmpRcvBuf,0,MAX_PACKET);/初始化套接字119m_hSocket=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);if(m_hSocket=INVALID_SOCKET) AfxMessageBox(“套接字初始化失败!“);TerminateProcess(GetCurrentProcess(),-1);/设置超时选项int nTimeOut=1000;int result;result=setsockopt(m_hSocket,SOL_SOCKET,SO_RCVTIMEO,
39、(char*)if(result=SOCKET_ERROR) AfxMessageBox(“设置接收超时选项失败!“);TerminateProcess(GetCurrentProcess(),-1);result=setsockopt(m_hSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)if(result=SOCKET_ERROR)AfxMessageBox(“设置发送超时选项失败!“);TerminateProcess(GetCurrentProcess(),-1);/设置路由不查询路由表选项BOOL bDontRoute=TRUE;result=setsock
40、opt(m_hSocket,SOL_SOCKET,SO_DONTROUTE,(char*)if(result=SOCKET_ERROR)AfxMessageBox(“设置不查询路由表选项失败!“);TerminateProcess(GetCurrentProcess(),-1);for(int ttl=1;ttlMAX_NOTES;ttl+)/设定数据报的寿命SetTTL(m_hSocket,ttl);/发送数据报120if(SendData(icmpData,size) continue; /接收数据报if(RecvData(icmpRcvBuf, /处理接收到的数据报if (DecodeICMP(icmpRcvBuf,result,ttl) break;HeapFree(GetProcessHeap(), 0, icmpData);HeapFree(GetProcessHeap(), 0, icmpRcvBuf);