📄 tracert.cpp
字号:
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "WSARecvFrom failed: %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
}
return NO_ERROR;
}
//
// Function: AnalyzePacket
//
// Description:
// This routines finds the ICMP packet within the encapsulated header and
// verifies that the ICMP packet is a TTL expired or echo reply message.
// If not then an error is returned.
//
int AnalyzePacket(char *buf, int bytes)
{
int hdrlen=0,
routes=0,
rc;
rc = NO_ERROR;
if (gAddressFamily == AF_INET)
{
IPV4_HDR *v4hdr=NULL;
ICMP_HDR *icmphdr=NULL;
v4hdr = (IPV4_HDR *)buf;
hdrlen = (v4hdr->ip_verlen & 0x0F) * 4;
if (v4hdr->ip_protocol == IPPROTO_ICMP)
{
icmphdr = (ICMP_HDR *)&buf[hdrlen];
if ((icmphdr->icmp_type != ICMPV4_TIMEOUT) &&
(icmphdr->icmp_type != ICMPV4_ECHO_REPLY_TYPE) &&
(icmphdr->icmp_code != ICMPV4_ECHO_REPLY_CODE) )
{
printf("Received ICMP message type %d instead of TTL expired!\n", icmphdr->icmp_type);
rc = SOCKET_ERROR;
}
}
}
else if (gAddressFamily == AF_INET6)
{
IPV6_HDR *v6hdr=NULL;
ICMPV6_HDR *icmp6=NULL;
v6hdr = (IPV6_HDR *)buf;
if (v6hdr->ipv6_nexthdr == IPPROTO_ICMP6)
{
icmp6 = (ICMPV6_HDR *)&buf[sizeof(IPV6_HDR)];
if ((icmp6->icmp6_type != ICMPV6_TIME_EXCEEDED_TYPE) &&
(icmp6->icmp6_code != ICMPV6_TIME_EXCEEDED_CODE) &&
(icmp6->icmp6_type != ICMPV6_ECHO_REPLY_TYPE) &&
(icmp6->icmp6_code != ICMPV6_ECHO_REPLY_CODE) )
{
printf("Received ICMP6 message type %d instead of TTL expired!\n",
icmp6->icmp6_type);
rc = SOCKET_ERROR;
}
}
}
return rc;
}
//
// Function: SetTtl
//
// Description:
// Sets the TTL on the socket.
//
int SetTtl(SOCKET s, int ttl)
{
int optlevel,
option,
rc;
rc = NO_ERROR;
if (gAddressFamily == AF_INET)
{
optlevel = IPPROTO_IP;
option = IP_TTL;
}
else if (gAddressFamily == AF_INET6)
{
optlevel = IPPROTO_IPV6;
option = IPV6_UNICAST_HOPS;
}
else
{
rc = SOCKET_ERROR;
}
if (rc == NO_ERROR)
{
rc = setsockopt(
s,
optlevel,
option,
(char *)&ttl,
sizeof(ttl)
);
}
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "SetTtl: setsockopt failed: %d\n", WSAGetLastError());
}
return rc;
}
//
// Function: IsSockaddrEqual
//
// Description:
// This routines compares two SOCKADDR structure to determine
// whether the address portion of them are equal. Zero is returned
// for equal; non-zero for not equal.
//
int IsSockaddrEqual(SOCKADDR *sa1, SOCKADDR *sa2)
{
int rc;
rc = 1;
if (sa1->sa_family == sa2->sa_family)
{
if (sa1->sa_family == AF_INET)
{
rc = memcmp(
&((SOCKADDR_IN *)sa1)->sin_addr,
&((SOCKADDR_IN *)sa2)->sin_addr,
sizeof(struct in_addr)
);
rc = rc;
}
else if (sa1->sa_family == AF_INET6)
{
rc = memcmp(
&((SOCKADDR_IN6 *)sa1)->sin6_addr,
&((SOCKADDR_IN6 *)sa2)->sin6_addr,
sizeof(struct in6_addr)
);
rc = rc;
}
}
return rc;
}
//
// Function: main
//
// Description:
// Setup the ICMP raw socket and create the ICMP header. Add
// the appropriate IP option header and start sending ICMP
// echo requests to the endpoint. For each send and receive we
// set a timeout value so that we don't wait forever for a
// response in case the endpoint is not responding. When we
// receive a packet decode it.
//
int __cdecl main(int argc, char **argv)
{
WSADATA wsd;
WSAOVERLAPPED recvol;
SOCKET s=INVALID_SOCKET;
char *icmpbuf=NULL,
recvbuf[0xFFFF],
hopname[512];
struct addrinfo *dest=NULL,
*local=NULL;
SOCKADDR_STORAGE from;
DWORD bytes,
flags;
int packetlen=0,
recvbuflen=0xFFFF,
hopbuflen=512,
fromlen,
notdone,
time=0,
ttl,
rc;
// Load Winsock
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("WSAStartup() failed: %d\n", GetLastError());
return -1;
}
// Parse the command line
ValidateArgs(argc, argv);
// Resolve the destination address
dest = ResolveAddress(
gDestination,
"0",
gAddressFamily,
0,
0
);
if (dest == NULL)
{
printf("bad name %s\n", gDestination);
return -1;
}
gAddressFamily = dest->ai_family;
if (gAddressFamily == AF_INET)
gProtocol = IPPROTO_ICMP;
else if (gAddressFamily == AF_INET6)
gProtocol = IPPROTO_ICMP6;
// Get the bind address
local = ResolveAddress(
NULL,
"0",
gAddressFamily,
0,
0
);
if (local == NULL)
{
printf("Unable to obtain the bind address!\n");
return -1;
}
// Create the raw socket
s = socket(gAddressFamily, SOCK_RAW, gProtocol);
if (s == INVALID_SOCKET)
{
printf("socket failed: %d\n", WSAGetLastError());
return -1;
}
// Figure out the size of the ICMP header and payload
if (gAddressFamily == AF_INET)
packetlen += sizeof(ICMP_HDR);
else if (gAddressFamily == AF_INET6)
packetlen += sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST);
// Add in the data size
packetlen += DEFAULT_DATA_SIZE;
// Allocate the buffer that will contain the ICMP request
icmpbuf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen);
if (icmpbuf == NULL)
{
fprintf(stderr, "HeapAlloc failed: %d\n", GetLastError());
return -1;
}
// Initialize the ICMP headers
if (gAddressFamily == AF_INET)
{
InitIcmpHeader(icmpbuf, DEFAULT_DATA_SIZE);
}
else if (gAddressFamily == AF_INET6)
{
InitIcmp6Header(icmpbuf, DEFAULT_DATA_SIZE);
}
// Bind the socket -- need to do this since we post a receive first
rc = bind(s, local->ai_addr, local->ai_addrlen);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
return -1;
}
// Setup the receive operation
memset(&recvol, 0, sizeof(recvol));
recvol.hEvent = WSACreateEvent();
// Post the first overlapped receive
fromlen = sizeof(from);
PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);
printf("\nTraceroute to %s [", gDestination);
PrintAddress(dest->ai_addr, dest->ai_addrlen);
printf("]\nover a maximum of %d hops\n\n", gTtl);
ttl = 1;
// Start sending the ICMP requests
do
{
notdone = 1;
SetTtl(s, ttl);
// Set the sequence number and compute the checksum
SetIcmpSequence(icmpbuf);
ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);
// Send the ICMP echo request
time = GetTickCount();
rc = sendto(
s,
icmpbuf,
packetlen,
0,
dest->ai_addr,
dest->ai_addrlen
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "sendto failed: %d\n", WSAGetLastError());
return -1;
}
// Wait for a response
rc = WaitForSingleObject((HANDLE)recvol.hEvent, gTimeout);
if (rc == WAIT_FAILED)
{
fprintf(stderr, "WaitForSingleObject failed: %d\n", GetLastError());
return -1;
}
else if (rc == WAIT_TIMEOUT)
{
printf("Request timed out.\n");
}
else
{
// Check for an error
rc = WSAGetOverlappedResult(
s,
&recvol,
&bytes,
FALSE,
&flags
);
if (rc == FALSE)
{
fprintf(stderr, "WSAGetOverlappedResult failed: %d\n", WSAGetLastError());
}
time = time - GetTickCount();
WSAResetEvent(recvol.hEvent);
// See if we got an ICMP ttl expired or echo reply, if not ignore and
// receive again.
if (AnalyzePacket(recvbuf, bytes) == NO_ERROR)
{
if (bResolve)
{
ReverseLookup((SOCKADDR *)&from, fromlen, hopname, hopbuflen);
printf("%d %d ms %s [", ttl, time, hopname);
PrintAddress((SOCKADDR *)&from, fromlen);
printf("]\n");
}
else
{
printf("%d %d ms ", ttl, time);
PrintAddress((SOCKADDR *)&from, fromlen);
printf("\n");
}
// See if the response is from the desired destination
notdone = IsSockaddrEqual(dest->ai_addr, (SOCKADDR *)&from);
// Increment the TTL
ttl++;
}
// Post another receive
if (notdone)
{
fromlen = sizeof(from);
PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);
}
}
Sleep(1000);
} while ((notdone) && (ttl < gTtl));
//
// Cleanup
//
freeaddrinfo(dest);
freeaddrinfo(local);
if (s != INVALID_SOCKET)
closesocket(s);
HeapFree(GetProcessHeap(), 0, icmpbuf);
WSACleanup();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -