Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702/* * Copyright (c) 2015 Tim Crawford * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *//* * PROJECT: ReactOS Ping Command * LICENSE: MIT * FILE: base/applications/network/ping/ping.c * PURPOSE: Network test utility * PROGRAMMERS: Tim Crawford <crawfxrd@gmail.com> */
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#define WIN32_NO_STATUS#include <windef.h>#include <winbase.h>#include <winsock2.h>#include <ws2tcpip.h>#include <iphlpapi.h>#include <icmpapi.h>
#include <conutils.h>
#include "resource.h"
#define NDEBUG#include <debug.h>
#define SIZEOF_ICMP_ERROR 8#define SIZEOF_IO_STATUS_BLOCK 8#define DEFAULT_TIMEOUT 1000#define MAX_SEND_SIZE 65500
static BOOL ParseCmdLine(int argc, PWSTR argv[]);static BOOL ResolveTarget(PCWSTR target);static void Ping(void);static void PrintStats(void);static BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType);
static HANDLE hIcmpFile = INVALID_HANDLE_VALUE;static ULONG Timeout = 4000;static int Family = AF_UNSPEC;static ULONG RequestSize = 32;static ULONG PingCount = 4;static BOOL PingForever = FALSE;static PADDRINFOW Target = NULL;static PCWSTR TargetName = NULL;static WCHAR Address[46];static WCHAR CanonName[NI_MAXHOST];static BOOL ResolveAddress = FALSE;
static ULONG RTTMax = 0;static ULONG RTTMin = 0;static ULONG RTTTotal = 0;static ULONG EchosSent = 0;static ULONG EchosReceived = 0;static ULONG EchosSuccessful = 0;
static IP_OPTION_INFORMATION IpOptions;
intwmain(int argc, WCHAR *argv[]){ WSADATA wsaData; ULONG i; DWORD StrLen = 46; int Status;
/* Initialize the Console Standard Streams */ ConInitStdStreams();
IpOptions.Ttl = 128;
if (!ParseCmdLine(argc, argv)) return 1;
if (!SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE)) { DPRINT("Failed to set control handler: %lu\n", GetLastError()); return 1; }
Status = WSAStartup(MAKEWORD(2, 2), &wsaData); if (Status != 0) { ConResPrintf(StdErr, IDS_WINSOCK_FAIL, Status); return 1; }
if (!ResolveTarget(TargetName)) { WSACleanup(); return 1; }
if (WSAAddressToStringW(Target->ai_addr, (DWORD)Target->ai_addrlen, NULL, Address, &StrLen) != 0) { DPRINT("WSAAddressToStringW failed: %d\n", WSAGetLastError()); FreeAddrInfoW(Target); WSACleanup(); return 1; }
if (Family == AF_INET6) hIcmpFile = Icmp6CreateFile(); else hIcmpFile = IcmpCreateFile();
if (hIcmpFile == INVALID_HANDLE_VALUE) { DPRINT("IcmpCreateFile failed: %lu\n", GetLastError()); FreeAddrInfoW(Target); WSACleanup(); return 1; }
if (*CanonName) ConResPrintf(StdOut, IDS_PINGING_HOSTNAME, CanonName, Address); else ConResPrintf(StdOut, IDS_PINGING_ADDRESS, Address);
ConResPrintf(StdOut, IDS_PING_SIZE, RequestSize);
Ping();
i = 1; while (i < PingCount) { Sleep(1000); Ping();
if (!PingForever) i++; }
PrintStats();
IcmpCloseHandle(hIcmpFile); FreeAddrInfoW(Target); WSACleanup();
return 0;}
staticBOOLParseCmdLine(int argc, PWSTR argv[]){ int i;
if (argc < 2) { ConResPrintf(StdOut, IDS_USAGE); return FALSE; }
for (i = 1; i < argc; i++) { if (argv[i][0] == L'-' || argv[i][0] == L'/') { switch (argv[i][1]) { case L't': PingForever = TRUE; break;
case L'a': ResolveAddress = TRUE; break;
case L'n': { if (i + 1 < argc) { PingForever = FALSE; PingCount = wcstoul(argv[++i], NULL, 0); if (PingCount == 0) { ConResPrintf(StdErr, IDS_BAD_VALUE, argv[i - 1], 1, UINT_MAX); return FALSE; } } else { ConResPrintf(StdErr, IDS_MISSING_VALUE, argv[i]); return FALSE; } break; }
case L'l': { if (i + 1 < argc) { RequestSize = wcstoul(argv[++i], NULL, 0); if (RequestSize > MAX_SEND_SIZE) { ConResPrintf(StdErr, IDS_BAD_VALUE, argv[i - 1], 0, MAX_SEND_SIZE); return FALSE; } } else { ConResPrintf(StdErr, IDS_MISSING_VALUE, argv[i]); return FALSE; } break; }
case L'f': { if (Family == AF_INET6) { ConResPrintf(StdErr, IDS_WRONG_FAMILY, argv[i], L"IPv4"); return FALSE; }
Family = AF_INET; IpOptions.Flags |= IP_FLAG_DF; break; }
case L'i': { if (i + 1 < argc) { ULONG Ttl = wcstoul(argv[++i], NULL, 0);
if ((Ttl == 0) || (Ttl > UCHAR_MAX)) { ConResPrintf(StdErr, IDS_BAD_VALUE, argv[i - 1], 1, UCHAR_MAX); return FALSE; }
IpOptions.Ttl = (UCHAR)Ttl; } else { ConResPrintf(StdErr, IDS_MISSING_VALUE, argv[i]); return FALSE; } break; }
case L'v': { if (Family == AF_INET6) { ConResPrintf(StdErr, IDS_WRONG_FAMILY, argv[i], L"IPv4"); return FALSE; }
Family = AF_INET;
if (i + 1 < argc) { /* This option has been deprecated. Don't do anything. */ i++; } else { ConResPrintf(StdErr, IDS_MISSING_VALUE, argv[i]); return FALSE; }
break; }
case L'w': { if (i + 1 < argc) { Timeout = wcstoul(argv[++i], NULL, 0); if (Timeout < DEFAULT_TIMEOUT) Timeout = DEFAULT_TIMEOUT; } else { ConResPrintf(StdErr, IDS_MISSING_VALUE, argv[i]); return FALSE; } break; }
case L'R': { if (Family == AF_INET) { ConResPrintf(StdErr, IDS_WRONG_FAMILY, argv[i], L"IPv6"); return FALSE; }
Family = AF_INET6;
/* This option has been deprecated. Don't do anything. */ break; }
case L'4': { if (Family == AF_INET6) { ConResPrintf(StdErr, IDS_WRONG_FAMILY, argv[i], L"IPv4"); return FALSE; }
Family = AF_INET; break; }
case L'6': { if (Family == AF_INET) { ConResPrintf(StdErr, IDS_WRONG_FAMILY, argv[i], L"IPv6"); return FALSE; }
Family = AF_INET6; break; }
case L'?': ConResPrintf(StdOut, IDS_USAGE); return FALSE;
default: ConResPrintf(StdErr, IDS_BAD_OPTION, argv[i]); ConResPrintf(StdErr, IDS_USAGE); return FALSE; } } else { if (TargetName != NULL) { ConResPrintf(StdErr, IDS_BAD_PARAMETER, argv[i]); return FALSE; }
TargetName = argv[i]; } }
if (TargetName == NULL) { ConResPrintf(StdErr, IDS_MISSING_ADDRESS); return FALSE; }
return TRUE;}
staticBOOLResolveTarget(PCWSTR target){ ADDRINFOW hints; int Status;
ZeroMemory(&hints, sizeof(hints)); hints.ai_family = Family; hints.ai_flags = AI_NUMERICHOST;
Status = GetAddrInfoW(target, NULL, &hints, &Target); if (Status != 0) { hints.ai_flags = AI_CANONNAME;
Status = GetAddrInfoW(target, NULL, &hints, &Target); if (Status != 0) { ConResPrintf(StdOut, IDS_UNKNOWN_HOST, target); return FALSE; }
wcsncpy(CanonName, Target->ai_canonname, wcslen(Target->ai_canonname)); } else if (ResolveAddress) { Status = GetNameInfoW(Target->ai_addr, Target->ai_addrlen, CanonName, _countof(CanonName), NULL, 0, NI_NAMEREQD); if (Status != 0) { DPRINT("GetNameInfoW failed: %d\n", WSAGetLastError()); } }
Family = Target->ai_family;
return TRUE;}
staticvoidPing(void){ PVOID ReplyBuffer; PVOID SendBuffer = NULL; DWORD ReplySize = 0; DWORD Status;
if (RequestSize != 0) { SendBuffer = malloc(RequestSize); if (SendBuffer == NULL) { ConResPrintf(StdErr, IDS_NO_RESOURCES); exit(1); }
/* Windows ping utility fills the optional data field with * ASCII characters from 'a' to 'w', wrapping back around * until SendBuffer is full. */ for (ULONG i = 0; i < RequestSize; i++) ((PUCHAR)SendBuffer)[i] = (UCHAR)('a' + (i % ('w' - 'a' + 1))); }
if (Family == AF_INET6) { ReplySize += sizeof(ICMPV6_ECHO_REPLY); } else {#ifdef _WIN64 ReplySize += sizeof(ICMP_ECHO_REPLY32);#else ReplySize += sizeof(ICMP_ECHO_REPLY);#endif }
ReplySize += RequestSize + SIZEOF_ICMP_ERROR + SIZEOF_IO_STATUS_BLOCK;
ReplyBuffer = malloc(ReplySize); if (ReplyBuffer == NULL) { ConResPrintf(StdErr, IDS_NO_RESOURCES); free(SendBuffer); exit(1); }
ZeroMemory(ReplyBuffer, ReplySize);
EchosSent++;
if (Family == AF_INET6) { struct sockaddr_in6 Source;
ZeroMemory(&Source, sizeof(Source)); Source.sin6_family = AF_INET6;
Status = Icmp6SendEcho2(hIcmpFile, NULL, NULL, NULL, &Source, (struct sockaddr_in6 *)Target->ai_addr, SendBuffer, (USHORT)RequestSize, &IpOptions, ReplyBuffer, ReplySize, Timeout); } else { Status = IcmpSendEcho2(hIcmpFile, NULL, NULL, NULL, ((PSOCKADDR_IN)Target->ai_addr)->sin_addr.s_addr, SendBuffer, (USHORT)RequestSize, &IpOptions, ReplyBuffer, ReplySize, Timeout); }
/* TODO: Compare ReplyBuffer data to SendBuffer. */ free(SendBuffer);
if (Status == 0) { Status = GetLastError(); switch (Status) { case IP_REQ_TIMED_OUT: ConResPrintf(StdOut, IDS_REQUEST_TIMED_OUT); break;
default: ConResPrintf(StdOut, IDS_TRANSMIT_FAILED, Status); break; } } else { SOCKADDR_IN6 SockAddrIn6; SOCKADDR_IN SockAddrIn; PSOCKADDR SockAddr; socklen_t Size;
EchosReceived++;
ZeroMemory(&SockAddrIn, sizeof(SockAddrIn)); ZeroMemory(&SockAddrIn6, sizeof(SockAddrIn6));
if (Family == AF_INET6) { PICMPV6_ECHO_REPLY pEchoReply; PIPV6_ADDRESS_EX Ipv6Addr;
pEchoReply = (PICMPV6_ECHO_REPLY)ReplyBuffer;
Ipv6Addr = (PIPV6_ADDRESS_EX)&pEchoReply->Address; SockAddrIn6.sin6_family = AF_INET6; CopyMemory(SockAddrIn6.sin6_addr.u.Word, Ipv6Addr->sin6_addr, sizeof(SockAddrIn6.sin6_addr)); //SockAddrIn6.sin6_addr = Ipv6Addr->sin6_addr; SockAddr = (PSOCKADDR)&SockAddrIn6; Size = sizeof(SOCKADDR_IN6);
GetNameInfoW(SockAddr, Size, Address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
ConResPrintf(StdOut, IDS_REPLY_FROM, Address);
switch (pEchoReply->Status) { case IP_SUCCESS: { EchosSuccessful++;
if (pEchoReply->RoundTripTime == 0) ConResPrintf(StdOut, IDS_REPLY_TIME_0MS); else ConResPrintf(StdOut, IDS_REPLY_TIME_MS, pEchoReply->RoundTripTime);
if (pEchoReply->RoundTripTime < RTTMin || RTTMin == 0) RTTMin = pEchoReply->RoundTripTime;
if (pEchoReply->RoundTripTime > RTTMax || RTTMax == 0) RTTMax = pEchoReply->RoundTripTime;
ConPuts(StdOut, L"\n");
RTTTotal += pEchoReply->RoundTripTime; break; }
case IP_DEST_NET_UNREACHABLE: ConResPrintf(StdOut, IDS_DEST_NET_UNREACHABLE); break;
case IP_DEST_HOST_UNREACHABLE: ConResPrintf(StdOut, IDS_DEST_HOST_UNREACHABLE); break;
case IP_TTL_EXPIRED_TRANSIT: ConResPrintf(StdOut, IDS_TTL_EXPIRED); break;
default: ConResPrintf(StdOut, IDS_REPLY_STATUS, pEchoReply->Status); break; } } else {#ifdef _WIN64 PICMP_ECHO_REPLY32 pEchoReply;#else PICMP_ECHO_REPLY pEchoReply;#endif IPAddr *IP4Addr;
#ifdef _WIN64 pEchoReply = (PICMP_ECHO_REPLY32)ReplyBuffer;#else pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;#endif
IP4Addr = (IPAddr *)&pEchoReply->Address; SockAddrIn.sin_family = AF_INET; SockAddrIn.sin_addr.S_un.S_addr = *IP4Addr; SockAddr = (PSOCKADDR)&SockAddrIn; Size = sizeof(SOCKADDR_IN);
GetNameInfoW(SockAddr, Size, Address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
ConResPrintf(StdOut, IDS_REPLY_FROM, Address);
switch (pEchoReply->Status) { case IP_SUCCESS: { EchosSuccessful++;
ConResPrintf(StdOut, IDS_REPLY_BYTES, pEchoReply->DataSize);
if (pEchoReply->RoundTripTime == 0) ConResPrintf(StdOut, IDS_REPLY_TIME_0MS); else ConResPrintf(StdOut, IDS_REPLY_TIME_MS, pEchoReply->RoundTripTime);
ConResPrintf(StdOut, IDS_REPLY_TTL, pEchoReply->Options.Ttl);
if (pEchoReply->RoundTripTime < RTTMin || RTTMin == 0) RTTMin = pEchoReply->RoundTripTime;
if (pEchoReply->RoundTripTime > RTTMax || RTTMax == 0) RTTMax = pEchoReply->RoundTripTime;
RTTTotal += pEchoReply->RoundTripTime; break; }
case IP_DEST_NET_UNREACHABLE: ConResPrintf(StdOut, IDS_DEST_NET_UNREACHABLE); break;
case IP_DEST_HOST_UNREACHABLE: ConResPrintf(StdOut, IDS_DEST_HOST_UNREACHABLE); break;
case IP_TTL_EXPIRED_TRANSIT: ConResPrintf(StdOut, IDS_TTL_EXPIRED); break;
default: ConResPrintf(StdOut, IDS_REPLY_STATUS, pEchoReply->Status); break; } } }
free(ReplyBuffer);}
staticvoidPrintStats(void){ ULONG EchosLost = EchosSent - EchosReceived; ULONG PercentLost = (ULONG)((EchosLost / (double)EchosSent) * 100.0);
ConResPrintf(StdOut, IDS_STATISTICS, Address, EchosSent, EchosReceived, EchosLost, PercentLost);
if (EchosSuccessful > 0) { ULONG RTTAverage = RTTTotal / EchosSuccessful; ConResPrintf(StdOut, IDS_APPROXIMATE_RTT, RTTMin, RTTMax, RTTAverage); }}
staticBOOLWINAPIConsoleCtrlHandler(DWORD ControlType){ switch (ControlType) { case CTRL_C_EVENT: PrintStats(); ConResPrintf(StdOut, IDS_CTRL_C); return FALSE;
case CTRL_BREAK_EVENT: PrintStats(); ConResPrintf(StdOut, IDS_CTRL_BREAK); return TRUE;
case CTRL_CLOSE_EVENT: PrintStats(); return FALSE;
default: return FALSE; }}