📄 ping.cpp
字号:
//
// Description:
// This routine posts an overlapped WSARecvFrom on the raw socket.
//
int PostRecvfrom(SOCKET s, char *buf, int buflen, SOCKADDR *from, int *fromlen, WSAOVERLAPPED *ol)
{
WSABUF wbuf;
DWORD flags,
bytes;
int rc;
wbuf.buf = buf;
wbuf.len = buflen;
flags = 0;
rc = WSARecvFrom(
s,
&wbuf,
1,
&bytes,
&flags,
from,
fromlen,
ol,
NULL
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "WSARecvFrom failed: %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
}
return NO_ERROR;
}
//
// Function: PrintPayload
//
// Description:
// This routine is for IPv4 only. It determines if there are any IP options
// present (by seeing if the IP header length is greater than 20 bytes) and
// if so it prints the IP record route options.
//
void PrintPayload(char *buf, int bytes)
{
int hdrlen=0,
routes=0,
i;
if (gAddressFamily == AF_INET)
{
SOCKADDR_IN hop;
IPV4_OPTION_HDR *v4opt=NULL;
IPV4_HDR *v4hdr=NULL;
hop.sin_family = (USHORT)gAddressFamily;
hop.sin_port = 0;
v4hdr = (IPV4_HDR *)buf;
hdrlen = (v4hdr->ip_verlen & 0x0F) * 4;
// If the header length is greater than the size of the basic IPv4
// header then there are options present. Find them and print them.
if (hdrlen > sizeof(IPV4_HDR))
{
v4opt = (IPV4_OPTION_HDR *)(buf + sizeof(IPV4_HDR));
routes = (v4opt->opt_ptr / sizeof(ULONG)) - 1;
for(i=0; i < routes ;i++)
{
hop.sin_addr.s_addr = v4opt->opt_addr[i];
// Print the route
if (i == 0)
printf(" Route: ");
else
printf(" ");
PrintAddress((SOCKADDR *)&hop, sizeof(hop));
if (i < routes-1)
printf(" ->\n");
else
printf("\n");
}
}
}
return;
}
//
// 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: 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];
struct addrinfo *dest=NULL,
*local=NULL;
IPV4_OPTION_HDR ipopt;
SOCKADDR_STORAGE from;
DWORD bytes,
flags;
int packetlen=0,
recvbuflen=0xFFFF,
fromlen,
time=0,
rc,
i;
// 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;
}
SetTtl(s, gTtl);
// 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 += gDataSize;
// 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)
{
if (bRecordRoute)
{
// Setup the IP option header to go out on every ICMP packet
ZeroMemory(&ipopt, sizeof(ipopt));
ipopt.opt_code = IP_RECORD_ROUTE; // record route option
ipopt.opt_ptr = 4; // point to the first addr offset
ipopt.opt_len = 39; // length of option header
rc = setsockopt(s, IPPROTO_IP, IP_OPTIONS,
(char *)&ipopt, sizeof(ipopt));
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "setsockopt(IP_OPTIONS) failed: %d\n", WSAGetLastError());
return -1;
}
}
InitIcmpHeader(icmpbuf, gDataSize);
}
else if (gAddressFamily == AF_INET6)
{
InitIcmp6Header(icmpbuf, gDataSize);
}
// 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("\nPinging ");
PrintAddress(dest->ai_addr, dest->ai_addrlen);
printf(" with %d bytes of data\n\n", gDataSize);
// Start sending the ICMP requests
for(i=0; i < DEFAULT_SEND_COUNT ;i++)
{
// Set the sequence number and compute the checksum
SetIcmpSequence(icmpbuf);
ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);
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;
}
// Waite for a response
rc = WaitForSingleObject((HANDLE)recvol.hEvent, DEFAULT_RECV_TIMEOUT);
if (rc == WAIT_FAILED)
{
fprintf(stderr, "WaitForSingleObject failed: %d\n", GetLastError());
return -1;
}
else if (rc == WAIT_TIMEOUT)
{
printf("Request timed out.\n");
}
else
{
rc = WSAGetOverlappedResult(
s,
&recvol,
&bytes,
FALSE,
&flags
);
if (rc == FALSE)
{
fprintf(stderr, "WSAGetOverlappedResult failed: %d\n", WSAGetLastError());
}
time = time - GetTickCount();
WSAResetEvent(recvol.hEvent);
printf("Reply from ");
PrintAddress((SOCKADDR *)&from, fromlen);
if (time == 0)
printf(": bytes=%d time<1ms TTL=%d\n", gDataSize, gTtl);
else
printf(": bytes=%d time=%dms TTL=%d\n", gDataSize, time, gTtl);
PrintPayload(recvbuf, bytes);
if (i < DEFAULT_SEND_COUNT)
{
fromlen = sizeof(from);
PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);
}
}
Sleep(1000);
}
//
// 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 + -