traceroute
关掉公用网络防火墙:
再关掉域防火墙:
TraceRoute.h#pragma once
//TraceRoute.h
#ifndef TRACEROUTE_H_INCLUDED
#define TRACEROUTE_H_INCLUDED
#pragma pack(1)
//IP数据报头
typedef struct
{
unsigned char hdr_len : 4; // 4位首部长度
unsigned char version : 4; // 4位版本
unsigned char tos; // 8位服务类型
unsigned short total_len; // 16位总长度(字节数)
unsigned short identifier; // 16位标识
unsigned short frag_and_flags; // 3位标志 13位片偏移
unsigned char ttl; // 8位生存时间
unsigned char protocol; // 8位协议 (TCP, UDP etc)
unsigned short checksum; // 16位首部校验和
unsigned long sourceIP; // 32位原地址
unsigned long destIP; // 32位目的IP地址
} IP_HEADER;
//ICMP数据报头
typedef struct
{
BYTE type; //8位类型
BYTE code; //8位代码
USHORT cksum; //16位校验和
USHORT id; //16位标识符
USHORT seq; //16位序列号
} ICMP_HEADER;
//解码结果
typedef struct
{
USHORT usSeqNo; //包序列号
DWORD dwRoundTripTime; //往返时间
in_addr dwIPaddr; //对端IP地址
} DECODE_RESULT;
#pragma pack()
//ICMP类型字段
const BYTE ICMP_ECHO_REPLY = 0; //回显应答
const BYTE ICMP_ECHO_REQUEST = 8; //请求回显
const BYTE ICMP_TIMEOUT = 11; //传输超时
const DWORD DEF_ICMP_TIMEOUT = 3000; //默认超时时间,单位ms
const int DEF_ICMP_DATA_SIZE = 32; //默认ICMP数据部分长度
const int MAX_ICMP_PACKET_SIZE = 1024; //最大ICMP数据报的大小
const int DEF_MAX_HOP = 30; //最大跳站数
USHORT GenerateChecksum(USHORT* pBuf, int iSize);
BOOL DecodeIcmpResponse(char* pBuf, int iPacketSize, DECODE_RESULT& stDecodeResult);
#endif // TRACEROUTE_H_INCLUDED
TraceRoute.cpp
//TraceRoute.cpp #include参考文章#include #include #include #include #include "TraceRoute.h" #pragma comment(lib,"ws2_32") using namespace std; int main() { while (1) { char ipString[100]; cout << "TraceRoute:"; scanf_s("%s", ipString,sizeof(ipString)); //char *ipString = "www.baidu.com"; WSADATA wsa;//一种数据结构。这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据 if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)//进行相应的socket库绑定,MAKEWORd(2,2)表示使用WINSOCK2版本 { cerr << "nFailed to initialize the WinSock2 DLLn" << "error code: " << WSAGetLastError() << endl;//Cerr通常用于输出错误信息与其他不属于正常逻辑的输出内容 return -1; } u_long ulDestIP = inet_addr(ipString);//将一个点分十进制的IP转换成一个长整数型数(u_long类型) //cout<<"测试————"<<"长整型数"< h_addr).s_addr;//in_addr 用来表示一个32位的IPv4地址. /cout<<"测试————"<<"ip地址"< type = ICMP_ECHO_REQUEST; pIcmpHeader->code = 0; pIcmpHeader->id = (USHORT)GetCurrentProcessId(); memset(IcmpSendBuf + sizeof(ICMP_HEADER), 'E', DEF_ICMP_DATA_SIZE);//数据部分填充 //开始探测路由 DECODE_RESULT stDecodeResult; BOOL bReachDestHost = FALSE; USHORT usSeqNo = 0; int iTTL = 1; int iMaxHop = DEF_MAX_HOP; while (!bReachDestHost && iMaxHop--) { //设置IP数据报头的ttl字段 setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char*)&iTTL, sizeof(iTTL));//为0(IPPROTO_IP)的raw socket。用于接收任何的IP数据包。其中的校验和和协议分析由程序自己完成。 //输出当前跳站数作为路由信息序号 cout << setw(3) << iTTL << flush;//setw(3)设置域宽,cout< cksum = 0; ((ICMP_HEADER*)IcmpSendBuf)->seq = htons(usSeqNo++);//将无符号短整型主机字节序转换为网络字节序,将一个数的高低位互换, (如:12 34 --> 34 12) ((ICMP_HEADER*)IcmpSendBuf)->cksum = GenerateChecksum((USHORT*)IcmpSendBuf, sizeof(ICMP_HEADER) + DEF_ICMP_DATA_SIZE); //记录序列号和当前时间 stDecodeResult.usSeqNo = ((ICMP_HEADER*)IcmpSendBuf)->seq; stDecodeResult.dwRoundTripTime = GetTickCount();//返回从操作系统启动到当前所经过的毫秒数,常常用来判断某个方法执行的时间 //发送ICMP的EchoRequest数据报 if (sendto(sockRaw, IcmpSendBuf, sizeof(IcmpSendBuf), 0, (sockaddr*)&destSockAddr, sizeof(destSockAddr)) == SOCKET_ERROR) { //如果目的主机不可达则直接退出 if (WSAGetLastError() == WSAEHOSTUNREACH) cout << '/t' << "Destination host unreachable.n" << "nTrace complete.n" << endl; closesocket(sockRaw); WSACleanup(); return 0; } //接收ICMP的EchoReply数据报 //因为收到的可能并非程序所期待的数据报,所以需要循环接收直到收到所要数据或超时 sockaddr_in from; int iFromLen = sizeof(from); int iReadDataLen; while (1) { //等待数据到达 iReadDataLen = recvfrom(sockRaw, IcmpRecvBuf, MAX_ICMP_PACKET_SIZE, 0, (sockaddr*)&from, &iFromLen); if (iReadDataLen != SOCKET_ERROR) //有数据包到达 { //解码得到的数据包,如果解码正确则跳出接收循环发送下一个EchoRequest包 if (DecodeIcmpResponse(IcmpRecvBuf, iReadDataLen, stDecodeResult)) { if (stDecodeResult.dwIPaddr.s_addr == destSockAddr.sin_addr.s_addr) bReachDestHost = TRUE; cout << 't' << inet_ntoa(stDecodeResult.dwIPaddr) << endl;//将网络地址转换成“.”点隔的字符串格式 break; } } else if (WSAGetLastError() == WSAETIMEDOUT) //接收超时,打印星号 { cout << setw(9) << '*' << 't' << "Request timed out." << endl; break; } else { cerr << "nFailed to call recvfromn" << "error code: " << WSAGetLastError() << endl; closesocket(sockRaw); WSACleanup(); return -1; } } //TTL值加1 iTTL++; //cout<<"测试————"< 1)//40 { cksum += *pBuf++; iSize -= sizeof(USHORT); } if (iSize) cksum += *(UCHAR*)pBuf;//8 //printf("测试——cksum——测试:%xn",cksum); //printf("测试——cksum>>16——测试:%xn",cksum>>16); //printf("测试——cksum & 0xffff——测试:%xn",cksum & 0xffff); cksum = (cksum >> 16) + (cksum & 0xffff); //printf("测试——cksum——测试:%xn",cksum); //printf("测试——cksum>>16——测试:%xn",cksum>>16); cksum += (cksum >> 16); //printf("测试——cksum——测试:%xn",cksum); //printf("测试——(USHORT)(~cksum)——测试:%xn",(USHORT)(~cksum)); return (USHORT)(~cksum);//~ 按位取反 } BOOL DecodeIcmpResponse(char* pBuf, int iPacketSize, DECODE_RESULT& stDecodeResult) { //检查数据报大小的合法性 IP_HEADER* pIpHdr = (IP_HEADER*)pBuf; int iIpHdrLen = pIpHdr->hdr_len * 4;//单位4个字节 if (iPacketSize < (int)(iIpHdrLen + sizeof(ICMP_HEADER))) return FALSE; //按照ICMP包类型检查id字段和序列号以确定是否是程序应接收的Icmp包 ICMP_HEADER* pIcmpHdr = (ICMP_HEADER*)(pBuf + iIpHdrLen); USHORT usID, usSquNo;//ICMP头 标识符和序列号 if (pIcmpHdr->type == ICMP_ECHO_REPLY) { usID = pIcmpHdr->id; usSquNo = pIcmpHdr->seq; } else if (pIcmpHdr->type == ICMP_TIMEOUT) { char* pInnerIpHdr = pBuf + iIpHdrLen + sizeof(ICMP_HEADER); //载荷中的IP头 int iInnerIPHdrLen = ((IP_HEADER*)pInnerIpHdr)->hdr_len * 4;//载荷中的IP头长 ICMP_HEADER* pInnerIcmpHdr = (ICMP_HEADER*)(pInnerIpHdr + iInnerIPHdrLen);//载荷中的ICMP头 usID = pInnerIcmpHdr->id; usSquNo = pInnerIcmpHdr->seq; } else return FALSE; if (usID != (USHORT)GetCurrentProcessId() || usSquNo != stDecodeResult.usSeqNo) return FALSE; //处理正确收到的ICMP数据报 if (pIcmpHdr->type == ICMP_ECHO_REPLY || pIcmpHdr->type == ICMP_TIMEOUT) { //返回解码结果 stDecodeResult.dwIPaddr.s_addr = pIpHdr->sourceIP; stDecodeResult.dwRoundTripTime = GetTickCount() - stDecodeResult.dwRoundTripTime; //打印屏幕信息 if (stDecodeResult.dwRoundTripTime) cout << setw(6) << stDecodeResult.dwRoundTripTime << " ms" << flush; else cout << setw(6) << "<1" << " ms" << flush; return TRUE; } return FALSE; }
https://blog.csdn.net/qq_41577750/article/details/109196890



