// TestRouteInstance.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #include #include #pragma comment(lib, "Ws2_32.lib") #define LOCAL_IP "192.168.100.94" #define ICMP_PORT 0 #define DEST_HOST_IP "119.75.213.61" #define DEST_HOST_PORT 22 #define RECV_BUF 1024 #define MAX_HOPS 30 #define MAX_RECVTIMEOUT 500 BOOL InitWinSock() //初始化WinSock 库 { WSADATA wsaData = {0}; int iRet(0); iRet = WSAStartup(MAKEWORD(2,2), &wsaData); if(iRet != 0) { return FALSE; } if(LOBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) { return FALSE; } return TRUE; } //卸载套接字库 void CleanWinSock() { WSACleanup(); } #pragma pack(1) typedef struct icmp_hdr { UCHAR icmp_type; //消息类型 UCHAR icmp_code; //消息代码 USHORT icmp_checksum; //检验和 //回显头 USHORT icmp_id; //请求ID USHORT icmp_sequence; //序列号 //每次发送至此//8byte //自定义数据部分 ULONG icmp_timestamp; //时间戳 }ICMP_HDR; #pragma pack() //求检验和 USHORT CheckSum(USHORT *uBuffer, int iSize) { ULONG uCheckSum(0); //将数据以字累加到uCheckSum中 while(iSize > 1) { //uCheckSum = uCheckSum + *uBuffer; //uBuffer++; uCheckSum += *uBuffer++; iSize -= sizeof(iSize); } //如果为奇数将最后一个字节扩展到双字在累加到uCheckSum中 if(iSize) { uCheckSum += *(UCHAR*)uBuffer; } uCheckSum = (uCheckSum >> 16) + (uCheckSum & 0xffff); uCheckSum += (uCheckSum >> 16); return (USHORT)(~uCheckSum); } BOOL DecodeICMPPacket(char *szBuffer, int iSize, SOCKADDR_IN* pRecvAddr, int iTTL) { ICMP_HDR* pICMPHdr = NULL, *pICMPOther = NULL; assert(szBuffer != NULL); assert(iSize > 0); pICMPHdr = (ICMP_HDR*)&(szBuffer[20]); pICMPOther = (ICMP_HDR*)&(szBuffer[48]); //static int iFirstRouter = iTTL; static int iFirst = 1; if(pICMPHdr->icmp_type != 11 && pICMPHdr->icmp_code != 0 && pICMPHdr->icmp_type != 0 ) { printf_s(" 未知ICMP包: type :%d , code: %d!/r/n", pICMPHdr->icmp_type, pICMPHdr->icmp_code); return FALSE; } if(pICMPOther->icmp_id == GetCurrentThreadId()) { printf_s("第: %d 个路由器 :%s /r/n", iFirst, inet_ntoa(pRecvAddr->sin_addr)); } if(pICMPHdr->icmp_code == 0 && pICMPHdr->icmp_type == 0) { printf_s("到达目的地: %s ", inet_ntoa(pRecvAddr->sin_addr)); printf_s("总共经过%d 个路由器 ", iFirst - 1); printf_s("超时: %d ms/r/n", (GetTickCount() - pICMPHdr->icmp_timestamp)); return TRUE; } iFirst++; return FALSE; } TCHAR * ParseDestIp(TCHAR **szString) { if(_tcscmp(szString[1], _T("-ip")) == 0) { return szString[2]; } return NULL; } int _tmain(int argc, _TCHAR* argv[]) { char *pszDestIp; USES_CONVERSION; if(argc > 1) { pszDestIp = W2A(ParseDestIp(argv)); } InitWinSock(); //创建ICMP套接字 SOCKET RawICMPSock(INVALID_SOCKET); int iRet(0); RawICMPSock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(RawICMPSock == INVALID_SOCKET) { printf_s("create icmp socket failed!"); return 1; } SOCKADDR_IN addrIn; addrIn.sin_family = AF_INET; addrIn.sin_addr.S_un.S_addr = INADDR_ANY;//inet_addr(LOCAL_IP); addrIn.sin_port = htons(ICMP_PORT); iRet = bind(RawICMPSock, (SOCKADDR*)&addrIn, sizeof(SOCKADDR)); if(iRet == SOCKET_ERROR) { printf_s("bind ICMP socket failed!"); return 1; } //设置超时值 int iTimeOut = MAX_RECVTIMEOUT; //设置TTL int iTTL = 1; iRet = setsockopt(RawICMPSock, IPPROTO_IP, IP_TTL, (char*)&iTTL, sizeof(int)); if(iRet == SOCKET_ERROR) { printf_s("set TTL failed!/r/n"); return 1; } //设置超时 iRet = setsockopt(RawICMPSock, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeOut, sizeof(int)); if(iRet == SOCKET_ERROR) { printf_s("setsockopt failed!"); return 1; } iRet = setsockopt(RawICMPSock, SOL_SOCKET, SO_SNDTIMEO, (char*)&iTimeOut, sizeof(int)); if(iRet == SOCKET_ERROR) { printf_s("setsockopt failed!"); return 1; } SOCKADDR_IN DestAddr; SOCKADDR_IN addrFrom = {0}; DestAddr.sin_family = AF_INET; if(pszDestIp != NULL) { #define DEST_HOST_IP pszDestIp } DestAddr.sin_addr.S_un.S_addr = inet_addr(DEST_HOST_IP); DestAddr.sin_port = htons(DEST_HOST_PORT); int iAddrFromLen = sizeof(addrFrom); BOOL bRet(FALSE); char szRecvBuffer[RECV_BUF] = {0}; char szSendBuffer[sizeof(ICMP_HDR) + 32] = {0}; ICMP_HDR *pIcmpHdr = NULL; //int iBeforeSendTime(0), iRecvTime(0); while(iTTL <= MAX_HOPS) { ZeroMemory(&szSendBuffer, sizeof(szSendBuffer)); pIcmpHdr = (ICMP_HDR*)szSendBuffer; pIcmpHdr->icmp_code = 0; pIcmpHdr->icmp_type = 8; pIcmpHdr->icmp_sequence = iTTL; pIcmpHdr->icmp_id = GetCurrentThreadId(); pIcmpHdr->icmp_timestamp = GetTickCount(); //自定义数据 pIcmpHdr->icmp_checksum = CheckSum((USHORT*)szSendBuffer, sizeof(szSendBuffer)); //memset(&szSendBuffer[sizeof(ICMP_HDR)], 'E', 32); iRet = sendto(RawICMPSock, szSendBuffer, sizeof(szSendBuffer), 0, (SOCKADDR*)&DestAddr, sizeof(SOCKADDR)); //iBeforeSendTime = GetTickCount(); if(iRet == SOCKET_ERROR) { printf_s("sendto failed!"); break; } //接收ICMP报文 iRet = recvfrom(RawICMPSock, szRecvBuffer, RECV_BUF, 0, (SOCKADDR*)&addrFrom, &iAddrFromLen); //iRecvTime = GetTickCount(); if(iRet == SOCKET_ERROR) { if(WSAGetLastError() == WSAETIMEDOUT) { printf_s("time out!/r/n"); //continue; } else { printf_s("recvfrom failed!"); break; } } if(iRet > 0) { //printf_s("超时: %d ms /r/n", iRecvTime - iBeforeSendTime); bRet = DecodeICMPPacket(szRecvBuffer, iRet, &addrFrom, iTTL); } if(bRet) { break; } //增加TTL iTTL ++; iRet = setsockopt(RawICMPSock, IPPROTO_IP, IP_TTL, (char*)&iTTL, sizeof(int)); if(iRet == SOCKET_ERROR) { printf_s("setsockopt failed!"); return 1; } } if(iTTL > 30) { printf_s("达到最大跳! %d /r/n", iTTL - 1); } closesocket(RawICMPSock); CleanWinSock(); return 0; }