TraceRouteC++实现
使用cmd自带的TraceRoute
使用C++实现tracert
traceroute
关掉公用网络防火墙:
再关掉域防火墙:
TraceRoute.h
#pragma once
#ifndef TRACEROUTE_H_INCLUDED
#define TRACEROUTE_H_INCLUDED
#pragma pack(1)
typedef struct
{
unsigned char hdr_len : 4;
unsigned char version : 4;
unsigned char tos;
unsigned short total_len;
unsigned short identifier;
unsigned short frag_and_flags;
unsigned char ttl;
unsigned char protocol;
unsigned short checksum;
unsigned long sourceIP;
unsigned long destIP;
} IP_HEADER;
typedef struct
{
BYTE type;
BYTE code;
USHORT cksum;
USHORT id;
USHORT seq;
} ICMP_HEADER;
typedef struct
{
USHORT usSeqNo;
DWORD dwRoundTripTime;
in_addr dwIPaddr;
} DECODE_RESULT;
#pragma pack()
const BYTE ICMP_ECHO_REPLY = 0;
const BYTE ICMP_ECHO_REQUEST = 8;
const BYTE ICMP_TIMEOUT = 11;
const DWORD DEF_ICMP_TIMEOUT = 3000;
const int DEF_ICMP_DATA_SIZE = 32;
const int MAX_ICMP_PACKET_SIZE = 1024;
const int DEF_MAX_HOP = 30;
USHORT GenerateChecksum(USHORT* pBuf, int iSize);
BOOL DecodeIcmpResponse(char* pBuf, int iPacketSize, DECODE_RESULT& stDecodeResult);
#endif
TraceRoute.cpp
#include <iostream>
#include <iomanip>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#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));
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
cerr << "\nFailed to initialize the WinSock2 DLL\n" << "error code: " << WSAGetLastError() << endl;
return -1;
}
u_long ulDestIP = inet_addr(ipString);
if (ulDestIP == INADDR_NONE)
{
hostent* pHostent = gethostbyname(ipString);
if (pHostent)
{
ulDestIP = (*(in_addr*)pHostent->h_addr).s_addr;
cout << "\nTracing route to " << ipString
<< " [" << inet_ntoa(*(in_addr*)(&ulDestIP)) << "]"
<< " with a maximum of " << DEF_MAX_HOP << " hops.\n" << endl;
}
else
{
cerr << "\nCould not resolve the host name " << ipString << '\n'
<< "error code: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
}
else
{
cout << "Tracing route to " << ipString
<< " with a maximum of " << DEF_MAX_HOP << " hops." << endl;
}
sockaddr_in destSockAddr;
ZeroMemory(&destSockAddr, sizeof(sockaddr_in));
destSockAddr.sin_family = AF_INET;
destSockAddr.sin_addr.s_addr = ulDestIP;
SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sockRaw == INVALID_SOCKET)
{
cerr << "\nFailed to create a raw socket\n"
<< "error code: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
int iTimeout = DEF_ICMP_TIMEOUT;
if (setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeout, sizeof(iTimeout)) == SOCKET_ERROR)
{
cerr << "\nFailed to set recv timeout\n"
<< "error code: " << WSAGetLastError() << endl;
closesocket(sockRaw);
WSACleanup();
return -1;
}
char IcmpSendBuf[sizeof(ICMP_HEADER) + DEF_ICMP_DATA_SIZE];
memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf));
char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE];
memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf));
ICMP_HEADER* pIcmpHeader = (ICMP_HEADER*)IcmpSendBuf;
pIcmpHeader->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--)
{
setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char*)&iTTL, sizeof(iTTL));
cout << setw(3) << iTTL << flush;
((ICMP_HEADER*)IcmpSendBuf)->cksum = 0;
((ICMP_HEADER*)IcmpSendBuf)->seq = htons(usSeqNo++);
((ICMP_HEADER*)IcmpSendBuf)->cksum = GenerateChecksum((USHORT*)IcmpSendBuf, sizeof(ICMP_HEADER) + DEF_ICMP_DATA_SIZE);
stDecodeResult.usSeqNo = ((ICMP_HEADER*)IcmpSendBuf)->seq;
stDecodeResult.dwRoundTripTime = GetTickCount();
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;
}
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)
{
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 recvfrom\n"
<< "error code: " << WSAGetLastError() << endl;
closesocket(sockRaw);
WSACleanup();
return -1;
}
}
iTTL++;
}
cout << "\nTrace complete.\n" << endl;
closesocket(sockRaw);
WSACleanup();
}
return 0;
}
USHORT GenerateChecksum(USHORT* pBuf, int iSize)
{
unsigned long cksum = 0;
while (iSize > 1)
{
cksum += *pBuf++;
iSize -= sizeof(USHORT);
}
if (iSize)
cksum += *(UCHAR*)pBuf;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (USHORT)(~cksum);
}
BOOL DecodeIcmpResponse(char* pBuf, int iPacketSize, DECODE_RESULT& stDecodeResult)
{
IP_HEADER* pIpHdr = (IP_HEADER*)pBuf;
int iIpHdrLen = pIpHdr->hdr_len * 4;
if (iPacketSize < (int)(iIpHdrLen + sizeof(ICMP_HEADER)))
return FALSE;
ICMP_HEADER* pIcmpHdr = (ICMP_HEADER*)(pBuf + iIpHdrLen);
USHORT usID, usSquNo;
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);
int iInnerIPHdrLen = ((IP_HEADER*)pInnerIpHdr)->hdr_len * 4;
ICMP_HEADER* pInnerIcmpHdr = (ICMP_HEADER*)(pInnerIpHdr + iInnerIPHdrLen);
usID = pInnerIcmpHdr->id;
usSquNo = pInnerIcmpHdr->seq;
}
else
return FALSE;
if (usID != (USHORT)GetCurrentProcessId() || usSquNo != stDecodeResult.usSeqNo)
return FALSE;
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
|