Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1373 lines
43 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. ping.c
  5. Abstract:
  6. Packet INternet Groper utility for TCP/IP.
  7. Author:
  8. Numerous TCP/IP folks.
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. MohsinA, 21-Oct-96. INADDR_NONE check to avoid broadcast.
  13. MohsinA, 13-Nov-96. Max packet size < 64K.
  14. Notes:
  15. --*/
  16. //:ts=4
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <ctype.h>
  20. #include <time.h>
  21. #include <nt.h>
  22. #include <ntrtl.h>
  23. #include <nturtl.h>
  24. #include <snmp.h>
  25. #include <winsock2.h>
  26. #include <ws2tcpip.h>
  27. #include <ntddip6.h>
  28. #include <winnlsp.h>
  29. #include <iphlpapi.h>
  30. #include "llinfo.h"
  31. #include "tcpcmd.h"
  32. #include "ipexport.h"
  33. #include "icmpapi.h"
  34. #include "nlstxt.h"
  35. #define MAX_BUFFER_SIZE (sizeof(ICMP_ECHO_REPLY) + 0xfff7 + MAX_OPT_SIZE)
  36. #define DEFAULT_BUFFER_SIZE (0x2000 - 8)
  37. #define DEFAULT_SEND_SIZE 32
  38. #define DEFAULT_COUNT 4
  39. #define DEFAULT_TTL 128
  40. #define DEFAULT_TOS 0
  41. #define DEFAULT_TIMEOUT 4000L
  42. #define MIN_INTERVAL 1000L
  43. #define STDOUT 1
  44. uchar SendOptions[MAX_OPT_SIZE];
  45. WSADATA WsaData;
  46. struct IPErrorTable {
  47. IP_STATUS Error; // The IP Error
  48. DWORD ErrorNlsID; // NLS string ID
  49. } ErrorTable[] =
  50. {
  51. { IP_BUF_TOO_SMALL, PING_BUF_TOO_SMALL},
  52. { IP_DEST_NET_UNREACHABLE, PING_DEST_NET_UNREACHABLE},
  53. { IP_DEST_HOST_UNREACHABLE, PING_DEST_HOST_UNREACHABLE},
  54. { IP_DEST_PROT_UNREACHABLE, PING_DEST_PROT_UNREACHABLE},
  55. { IP_DEST_PORT_UNREACHABLE, PING_DEST_PORT_UNREACHABLE},
  56. { IP_NO_RESOURCES, PING_NO_RESOURCES},
  57. { IP_BAD_OPTION, PING_BAD_OPTION},
  58. { IP_HW_ERROR, PING_HW_ERROR},
  59. { IP_PACKET_TOO_BIG, PING_PACKET_TOO_BIG},
  60. { IP_REQ_TIMED_OUT, PING_REQ_TIMED_OUT},
  61. { IP_BAD_REQ, PING_BAD_REQ},
  62. { IP_BAD_ROUTE, PING_BAD_ROUTE},
  63. { IP_TTL_EXPIRED_TRANSIT, PING_TTL_EXPIRED_TRANSIT},
  64. { IP_TTL_EXPIRED_REASSEM, PING_TTL_EXPIRED_REASSEM},
  65. { IP_PARAM_PROBLEM, PING_PARAM_PROBLEM},
  66. { IP_SOURCE_QUENCH, PING_SOURCE_QUENCH},
  67. { IP_OPTION_TOO_BIG, PING_OPTION_TOO_BIG},
  68. { IP_BAD_DESTINATION, PING_BAD_DESTINATION},
  69. { IP_NEGOTIATING_IPSEC, PING_NEGOTIATING_IPSEC},
  70. { IP_GENERAL_FAILURE, PING_GENERAL_FAILURE}
  71. };
  72. PWCHAR
  73. GetErrorString(int ErrorCode)
  74. {
  75. DWORD Status;
  76. DWORD Length;
  77. static WCHAR ErrorString[2048]; // a 2K static buffer should suffice
  78. Length = 2048;
  79. Status = GetIpErrorString(ErrorCode, ErrorString, &Length);
  80. if (Status == NO_ERROR) {
  81. return ErrorString; // success
  82. }
  83. return L""; // return a null string
  84. }
  85. unsigned
  86. NlsPutMsg(unsigned Handle, unsigned usMsgNum, ...)
  87. {
  88. unsigned msglen;
  89. VOID * vp;
  90. va_list arglist;
  91. DWORD StrLen;
  92. va_start(arglist, usMsgNum);
  93. if (!(msglen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  94. FORMAT_MESSAGE_FROM_HMODULE,
  95. NULL,
  96. usMsgNum,
  97. 0L, // Default country ID.
  98. (LPTSTR)&vp,
  99. 0,
  100. &arglist)))
  101. return(0);
  102. // Convert vp to oem
  103. StrLen=strlen(vp);
  104. CharToOemBuff((LPCTSTR)vp,(LPSTR)vp,StrLen);
  105. msglen = _write(Handle, vp, StrLen);
  106. LocalFree(vp);
  107. return(msglen);
  108. }
  109. void
  110. PrintUsage(void)
  111. {
  112. NlsPutMsg( STDOUT, PING_USAGE );
  113. // printf(
  114. // "Usage: ping [-s size] [-c count] [-d] [-l TTL] [-o options] [-t TOS]\n"
  115. // " [-w timeout] address.\n"
  116. // "Options:\n"
  117. // " -t Ping the specifed host until interrupted.\n"
  118. // " -l size Send buffer size.\n"
  119. // " -n count Send count.\n"
  120. // " -f Don't fragment.\n"
  121. // " -i TTL Time to live.\n"
  122. // " -v TOS Type of service\n"
  123. // " -w timeout Timeout (in milliseconds)\n"
  124. // " -r routes Record route.\n"
  125. // " -s routes Timestamp route.\n"
  126. // " -j ipaddress Loose source route.\n"
  127. // " -k ipaddress Strict source route.\n"
  128. // " -o IP options:\n"
  129. // " -ol hop list Loose source route.\n"
  130. // " -ot Timestamp.\n"
  131. // " -or Record route\n"
  132. // );
  133. }
  134. // ========================================================================
  135. // Note: old code would reject "255.255.255.255" string, but not
  136. // other aliases. However, the caller checks for that address returned,
  137. // so this function doesn't need to check for it. On the other hand,
  138. // no other broadcast addresses were disallowed (224.0.0.1, subnet
  139. // broadcast, etc). Why?
  140. BOOLEAN
  141. ResolveTarget(
  142. int Family,
  143. char *TargetString,
  144. SOCKADDR *TargetAddress,
  145. socklen_t *TargetAddressLen,
  146. char *TargetName,
  147. int TargetNameLen,
  148. BOOLEAN DoReverseLookup
  149. )
  150. {
  151. int i;
  152. struct addrinfo hints, *ai;
  153. TargetName[0] = '\0';
  154. memset(&hints, 0, sizeof(hints));
  155. hints.ai_family = Family;
  156. hints.ai_flags = AI_NUMERICHOST;
  157. i = getaddrinfo(TargetString, NULL, &hints, &ai);
  158. if (i == NO_ERROR) {
  159. *TargetAddressLen = ai->ai_addrlen;
  160. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  161. if (DoReverseLookup) {
  162. getnameinfo(ai->ai_addr, ai->ai_addrlen,
  163. TargetName, TargetNameLen,
  164. NULL, 0, NI_NAMEREQD);
  165. }
  166. freeaddrinfo(ai);
  167. return(TRUE);
  168. } else {
  169. hints.ai_flags = AI_CANONNAME;
  170. if (getaddrinfo(TargetString, NULL, &hints, &ai) == 0) {
  171. *TargetAddressLen = ai->ai_addrlen;
  172. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  173. strcpy(TargetName,
  174. (ai->ai_canonname)? ai->ai_canonname : TargetString);
  175. freeaddrinfo(ai);
  176. return(TRUE);
  177. }
  178. }
  179. return(FALSE);
  180. } // ResolveTarget
  181. unsigned long
  182. str2ip(char *addr, int *EndOffset)
  183. {
  184. char *endptr;
  185. char *start = addr;
  186. int i; // Counter variable.
  187. unsigned long curaddr = 0;
  188. unsigned long temp;
  189. for (i = 0; i < 4; i++) {
  190. temp = strtoul(addr, &endptr, 10);
  191. if (temp > 255)
  192. return 0L;
  193. if (endptr[0] != '.')
  194. if (i != 3)
  195. return 0L;
  196. else
  197. if (endptr[0] != '\0' && endptr[0] != ' ')
  198. return 0L;
  199. addr = endptr+1;
  200. curaddr = (curaddr << 8) + temp;
  201. }
  202. *EndOffset += (int)(endptr - start);
  203. return net_long(curaddr);
  204. }
  205. ulong
  206. param(char **argv, int argc, int current, ulong min, ulong max)
  207. {
  208. ulong temp;
  209. char *dummy;
  210. if (current == (argc - 1) ) {
  211. NlsPutMsg( STDOUT, PING_MESSAGE_1, argv[current] );
  212. // printf( "Value must be supplied for option %s.\n", argv[current]);
  213. exit(1);
  214. }
  215. temp = strtoul(argv[current+1], &dummy, 0);
  216. if (temp < min || temp > max) {
  217. NlsPutMsg( STDOUT, PING_MESSAGE_2, argv[current], min, max );
  218. // printf( "Bad value for option %s. range min..max\n",
  219. // argv[current], min, max );
  220. exit(1);
  221. }
  222. return temp;
  223. }
  224. void
  225. ProcessOptions(
  226. ICMP_ECHO_REPLY *reply,
  227. BOOLEAN DoReverseLookup)
  228. {
  229. UCHAR *optionPtr;
  230. UCHAR *endPtr;
  231. BOOLEAN done = FALSE;
  232. UCHAR optionLength;
  233. UCHAR entryEndPtr;
  234. UCHAR entryPtr;
  235. UCHAR addressMode;
  236. int entryCount = 0;
  237. optionPtr = reply->Options.OptionsData;
  238. endPtr = optionPtr + reply->Options.OptionsSize;
  239. while ((optionPtr < endPtr) && !done) {
  240. switch (*optionPtr) {
  241. case IP_OPT_EOL:
  242. done = TRUE;
  243. break;
  244. case IP_OPT_NOP:
  245. optionPtr++;
  246. break;
  247. case IP_OPT_SECURITY:
  248. optionPtr += 11;
  249. break;
  250. case IP_OPT_SID:
  251. optionPtr += 4;
  252. break;
  253. case IP_OPT_RR:
  254. case IP_OPT_LSRR:
  255. case IP_OPT_SSRR:
  256. if ((optionPtr + 3) > endPtr) {
  257. NlsPutMsg(STDOUT, PING_INVALID_RR_OPTION);
  258. done = TRUE;
  259. break;
  260. }
  261. optionLength = optionPtr[1];
  262. if (((optionPtr + optionLength) > endPtr) ||
  263. (optionLength < 3)
  264. ) {
  265. NlsPutMsg(STDOUT, PING_INVALID_RR_OPTION);
  266. done = TRUE;
  267. break;
  268. }
  269. entryEndPtr = optionPtr[2];
  270. if (entryEndPtr < 4) {
  271. NlsPutMsg(STDOUT, PING_INVALID_RR_OPTION);
  272. optionPtr += optionLength;
  273. break;
  274. }
  275. if (entryEndPtr > (optionLength + 1)) {
  276. entryEndPtr = optionLength + 1;
  277. }
  278. entryPtr = 4;
  279. entryCount = 0;
  280. NlsPutMsg(STDOUT, PING_ROUTE_HEADER1);
  281. while ((entryPtr + 3) < entryEndPtr) {
  282. struct in_addr routeAddress;
  283. if (entryCount) {
  284. NlsPutMsg(
  285. STDOUT,
  286. PING_ROUTE_SEPARATOR
  287. );
  288. if (entryCount == 1) {
  289. NlsPutMsg(STDOUT, PING_CR);
  290. NlsPutMsg(
  291. STDOUT,
  292. PING_ROUTE_HEADER2
  293. );
  294. entryCount = 0;
  295. }
  296. }
  297. entryCount++;
  298. routeAddress.S_un.S_addr =
  299. *( (IPAddr UNALIGNED *)
  300. (optionPtr + entryPtr - 1)
  301. );
  302. if (DoReverseLookup) {
  303. struct hostent *hostEntry;
  304. hostEntry = gethostbyaddr(
  305. (char *) &routeAddress,
  306. sizeof(routeAddress),
  307. AF_INET
  308. );
  309. if (hostEntry != NULL) {
  310. NlsPutMsg(
  311. STDOUT,
  312. PING_FULL_ROUTE_ENTRY,
  313. hostEntry->h_name,
  314. inet_ntoa(routeAddress)
  315. );
  316. } else {
  317. NlsPutMsg(
  318. STDOUT,
  319. PING_ROUTE_ENTRY,
  320. inet_ntoa(routeAddress)
  321. );
  322. }
  323. } else {
  324. NlsPutMsg(
  325. STDOUT,
  326. PING_ROUTE_ENTRY,
  327. inet_ntoa(routeAddress)
  328. );
  329. }
  330. entryPtr += 4;
  331. }
  332. NlsPutMsg(STDOUT, PING_CR);
  333. optionPtr += optionLength;
  334. break;
  335. case IP_OPT_TS:
  336. if ((optionPtr + 4) > endPtr) {
  337. NlsPutMsg(STDOUT, PING_INVALID_TS_OPTION);
  338. done = TRUE;
  339. break;
  340. }
  341. optionLength = optionPtr[1];
  342. entryEndPtr = optionPtr[2];
  343. if (entryEndPtr < 5) {
  344. NlsPutMsg(STDOUT, PING_INVALID_TS_OPTION);
  345. optionPtr += optionLength;
  346. break;
  347. }
  348. addressMode = optionPtr[3] & 1;
  349. if (entryEndPtr > (optionLength + 1)) {
  350. entryEndPtr = optionLength + 1;
  351. }
  352. entryPtr = 5;
  353. entryCount = 0;
  354. NlsPutMsg(STDOUT, PING_TS_HEADER1);
  355. while ((entryPtr + 3) < entryEndPtr) {
  356. struct in_addr routeAddress;
  357. ULONG timeStamp;
  358. if (entryCount) {
  359. NlsPutMsg(
  360. STDOUT,
  361. PING_ROUTE_SEPARATOR
  362. );
  363. if (entryCount == 1) {
  364. NlsPutMsg(STDOUT, PING_CR);
  365. NlsPutMsg(STDOUT, PING_TS_HEADER2);
  366. entryCount = 0;
  367. }
  368. }
  369. entryCount++;
  370. if (addressMode) {
  371. if ((entryPtr + 8) > entryEndPtr) {
  372. break;
  373. }
  374. routeAddress.S_un.S_addr =
  375. *( (IPAddr UNALIGNED *)
  376. (optionPtr + entryPtr - 1)
  377. );
  378. if (DoReverseLookup) {
  379. struct hostent *hostEntry;
  380. hostEntry = gethostbyaddr(
  381. (char *) &routeAddress,
  382. sizeof(routeAddress),
  383. AF_INET
  384. );
  385. if (hostEntry != NULL) {
  386. NlsPutMsg(
  387. STDOUT,
  388. PING_FULL_TS_ADDRESS,
  389. hostEntry->h_name,
  390. inet_ntoa(routeAddress)
  391. );
  392. } else {
  393. NlsPutMsg(
  394. STDOUT,
  395. PING_TS_ADDRESS,
  396. inet_ntoa(routeAddress)
  397. );
  398. }
  399. } else {
  400. NlsPutMsg(
  401. STDOUT,
  402. PING_TS_ADDRESS,
  403. inet_ntoa(routeAddress)
  404. );
  405. }
  406. entryPtr += 4;
  407. }
  408. timeStamp = *( (ULONG UNALIGNED *)
  409. (optionPtr + entryPtr - 1)
  410. );
  411. timeStamp = net_long(timeStamp);
  412. NlsPutMsg(
  413. STDOUT,
  414. PING_TS_TIMESTAMP,
  415. timeStamp
  416. );
  417. entryPtr += 4;
  418. }
  419. NlsPutMsg(STDOUT, PING_CR);
  420. optionPtr += optionLength;
  421. break;
  422. default:
  423. if ((optionPtr + 2) > endPtr) {
  424. done = TRUE;
  425. break;
  426. }
  427. optionPtr += optionPtr[1];
  428. break;
  429. }
  430. }
  431. }
  432. // ========================================================================
  433. // MohsinA, 05-Dec-96.
  434. SOCKADDR_STORAGE address; // was local to main earlier.
  435. socklen_t addressLen;
  436. uint num_send=0, num_recv=0,
  437. time_min=(uint)-1, time_max=0, time_total=0;
  438. void
  439. print_statistics( )
  440. {
  441. if (num_send > 0) {
  442. char literal[INET6_ADDRSTRLEN];
  443. if (time_min == (uint) -1) { // all times were off.
  444. time_min = 0;
  445. }
  446. getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
  447. NULL, 0, NI_NUMERICHOST);
  448. // printf
  449. // "Ping statistics for %s:\n"
  450. // "Packets: Sent=%ul, received=%ul, lost=%d (%u%% loss),\n"
  451. // "Round trip times in milli-seconds: "
  452. // "minimum=%dms, maximum=%dms, average=%dms\n" ....
  453. NlsPutMsg(STDOUT, PING_STATISTICS,
  454. literal,
  455. num_send, num_recv, num_send - num_recv,
  456. (uint) ( 100 * (num_send - num_recv) / num_send ));
  457. if (num_recv > 0) {
  458. NlsPutMsg(STDOUT, PING_STATISTICS2,
  459. time_min, time_max, time_total / num_recv );
  460. }
  461. }
  462. }
  463. // ========================================================================
  464. // MohsinA, 05-Dec-96.
  465. // Press C-c to print and abort.
  466. // Press C-break to print and continue.
  467. BOOL
  468. ConsoleControlHandler(DWORD dwCtrlType)
  469. {
  470. print_statistics();
  471. switch ( dwCtrlType ) {
  472. case CTRL_BREAK_EVENT:
  473. NlsPutMsg( STDOUT, PING_BREAK );
  474. return TRUE;
  475. break;
  476. case CTRL_C_EVENT:
  477. NlsPutMsg( STDOUT, PING_INTERRUPT );
  478. default: break;
  479. }
  480. return FALSE;
  481. }
  482. uchar
  483. GetDefaultTTL(void)
  484. {
  485. HKEY registry=0;
  486. DWORD DefaultTTL=0;
  487. DWORD key_type;
  488. DWORD key_size = sizeof(DWORD);
  489. uchar TTL;
  490. DWORD Stat;
  491. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  492. "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
  493. 0,
  494. KEY_QUERY_VALUE,
  495. &registry) == ERROR_SUCCESS) {
  496. Stat=RegQueryValueEx(registry,
  497. "DefaultTTL",
  498. 0,
  499. &key_type,
  500. (unsigned char *)&DefaultTTL,
  501. &key_size);
  502. }
  503. if (DefaultTTL) {
  504. TTL = (unsigned char)DefaultTTL;
  505. } else {
  506. TTL = DEFAULT_TTL;
  507. }
  508. if (registry) {
  509. RegCloseKey(registry);
  510. }
  511. return TTL;
  512. }
  513. int
  514. GetSource(int family, char *astr, struct sockaddr *address)
  515. {
  516. struct addrinfo hints;
  517. struct addrinfo *result;
  518. memset(&hints, 0, sizeof hints);
  519. hints.ai_flags = AI_PASSIVE;
  520. hints.ai_family = family;
  521. if (getaddrinfo(astr, NULL, &hints, &result) != 0)
  522. return FALSE;
  523. RtlCopyMemory(address, result->ai_addr, result->ai_addrlen);
  524. return TRUE;
  525. }
  526. BOOLEAN
  527. SetFamily(DWORD *Family, DWORD Value, char *arg)
  528. {
  529. if ((*Family != AF_UNSPEC) && (*Family != Value)) {
  530. NlsPutMsg(STDOUT, PING_MESSAGE_11, arg);
  531. // NlsPutMsg(STDOUT, PING_FAMILY, arg,
  532. // (Value==AF_INET)? "IPv4" : "IPv6");
  533. return FALSE;
  534. }
  535. *Family = Value;
  536. return TRUE;
  537. }
  538. // ========================================================================
  539. void
  540. __cdecl
  541. main(int argc, char **argv)
  542. {
  543. SOCKADDR_STORAGE sourceAddress;
  544. char *arg;
  545. uint i;
  546. uint j;
  547. int found_addr = 0;
  548. BOOLEAN dnsreq = FALSE;
  549. char hostname[NI_MAXHOST], literal[INET6_ADDRSTRLEN];
  550. DWORD numberOfReplies;
  551. uint Count = DEFAULT_COUNT;
  552. uchar TTL = 0;
  553. uchar *Opt = NULL; // Pointer to send options
  554. uint OptLength = 0;
  555. int OptIndex = 0; // Current index into SendOptions
  556. int SRIndex = -1; // Where to put address, if source routing
  557. uchar TOS = DEFAULT_TOS;
  558. uchar Flags = 0;
  559. ulong Timeout = DEFAULT_TIMEOUT;
  560. IP_OPTION_INFORMATION SendOpts;
  561. int EndOffset;
  562. ulong TempAddr;
  563. uchar TempCount;
  564. DWORD errorCode;
  565. HANDLE IcmpHandle;
  566. int err;
  567. // struct in_addr addr;
  568. BOOL result;
  569. PICMP_ECHO_REPLY reply4;
  570. PICMPV6_ECHO_REPLY reply6;
  571. BOOL sourceRouting = FALSE;
  572. char *SendBuffer, *RcvBuffer;
  573. uint RcvSize;
  574. uint SendSize = DEFAULT_SEND_SIZE;
  575. int Family = AF_UNSPEC;
  576. //
  577. // This will ensure the correct language message is displayed when
  578. // NlsPutMsg is called.
  579. //
  580. SetThreadUILanguage(0);
  581. err = WSAStartup(MAKEWORD(2, 0), &WsaData);
  582. if (err) {
  583. NlsPutMsg(STDOUT, PING_WSASTARTUP_FAILED, GetLastError());
  584. exit(1);
  585. }
  586. memset(&sourceAddress, 0, sizeof sourceAddress);
  587. TTL = GetDefaultTTL();
  588. if (argc < 2) {
  589. PrintUsage();
  590. goto error_exit;
  591. } else {
  592. i = 1;
  593. while (i < (uint) argc) {
  594. arg = argv[i];
  595. if ( (arg[0] == '-') || (arg[0] == '/') ) { // Have an option
  596. switch (arg[1]) {
  597. case '?':
  598. PrintUsage();
  599. exit(0);
  600. case 'l':
  601. // SendSize = (uint)param(argv, argc, i++, 0, 0xfff7);
  602. // A ping with packet size >= 64K can crash
  603. // some tcpip stacks during re-assembly,
  604. // So changed 'max' from 0xfff7 to 65500
  605. // - MohsinA, 13-Nov-96.
  606. SendSize = (uint)param(argv, argc, i++, 0, 65500 );
  607. break;
  608. case 't':
  609. Count = (uint)-1;
  610. break;
  611. case 'n':
  612. Count = (uint)param(argv, argc, i++, 1, 0xffffffff);
  613. break;
  614. case 'f':
  615. // Only implemented for IPv4.
  616. if (!SetFamily(&Family, AF_INET, arg)) {
  617. goto error_exit;
  618. }
  619. Flags = IP_FLAG_DF;
  620. break;
  621. case 'i':
  622. // TTL of zero is invalid, MohsinA, 13-Mar-97.
  623. TTL = (uchar)param(argv, argc, i++, 1, 0xff);
  624. break;
  625. case 'v':
  626. // Only implemented for IPv4.
  627. if (!SetFamily(&Family, AF_INET, arg)) {
  628. goto error_exit;
  629. }
  630. TOS = (uchar)param(argv, argc, i++, 0, 0xff);
  631. break;
  632. case 'w':
  633. Timeout = param(argv, argc, i++, 0, 0xffffffff);
  634. break;
  635. case 'a':
  636. dnsreq = TRUE;
  637. break;
  638. case 'r': // Record Route
  639. // Only implemented for IPv4.
  640. if (!SetFamily(&Family, AF_INET, arg)) {
  641. goto error_exit;
  642. }
  643. if ((OptIndex + 3) > MAX_OPT_SIZE) {
  644. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  645. goto error_exit;
  646. }
  647. Opt = SendOptions;
  648. Opt[OptIndex] = IP_OPT_RR;
  649. Opt[OptIndex + 2] = 4; // Set initial pointer value
  650. // min is 1 not zero, MohsinA, 16-4-97.
  651. TempCount = (uchar)param(argv, argc, i++, 1, 9);
  652. TempCount = (TempCount * sizeof(ulong)) + 3;
  653. if ((TempCount + OptIndex) > MAX_OPT_SIZE) {
  654. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  655. goto error_exit;
  656. }
  657. Opt[OptIndex+1] = TempCount;
  658. OptLength += TempCount;
  659. OptIndex += TempCount;
  660. break;
  661. case 's': // Timestamp
  662. // Only implemented for IPv4.
  663. if (!SetFamily(&Family, AF_INET, arg)) {
  664. goto error_exit;
  665. }
  666. if ((OptIndex + 4) > MAX_OPT_SIZE) {
  667. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  668. goto error_exit;
  669. }
  670. Opt = SendOptions;
  671. Opt[OptIndex] = IP_OPT_TS;
  672. Opt[OptIndex + 2] = 5; // Set initial pointer value
  673. TempCount = (uchar)param(argv, argc, i++, 1, 4);
  674. TempCount = (TempCount * (sizeof(ulong) * 2)) + 4;
  675. if ((TempCount + OptIndex) > MAX_OPT_SIZE) {
  676. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  677. goto error_exit;
  678. }
  679. Opt[OptIndex+1] = TempCount;
  680. Opt[OptIndex+3] = 1;
  681. OptLength += TempCount;
  682. OptIndex += TempCount;
  683. break;
  684. case 'j': // Loose source routing
  685. // Only implemented for IPv4.
  686. if (!SetFamily(&Family, AF_INET, arg)) {
  687. goto error_exit;
  688. }
  689. if (sourceRouting) {
  690. NlsPutMsg(STDOUT, PING_BAD_OPTION_COMBO);
  691. goto error_exit;
  692. }
  693. if ((OptIndex + 3) > MAX_OPT_SIZE) {
  694. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  695. goto error_exit;
  696. }
  697. Opt = SendOptions;
  698. Opt[OptIndex] = IP_OPT_LSRR;
  699. Opt[OptIndex+1] = 3;
  700. Opt[OptIndex + 2] = 4; // Set initial pointer value
  701. OptLength += 3;
  702. while ( (i < (uint)(argc - 2)) && (*argv[i+1] != '-')) {
  703. if ((OptIndex + 3) > (MAX_OPT_SIZE - 4)) {
  704. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  705. goto error_exit;
  706. }
  707. arg = argv[++i];
  708. EndOffset = 0;
  709. do {
  710. TempAddr = str2ip(arg + EndOffset, &EndOffset);
  711. if (!TempAddr) {
  712. NlsPutMsg( STDOUT, PING_MESSAGE_4 );
  713. // printf("Bad route specified for loose source route");
  714. goto error_exit;
  715. }
  716. j = Opt[OptIndex+1];
  717. *(ulong UNALIGNED *)&Opt[j+OptIndex] = TempAddr;
  718. Opt[OptIndex+1] += 4;
  719. OptLength += 4;
  720. while (arg[EndOffset] != '\0' && isspace((unsigned char)arg[EndOffset]))
  721. EndOffset++;
  722. } while (arg[EndOffset] != '\0');
  723. }
  724. SRIndex = Opt[OptIndex+1] + OptIndex;
  725. Opt[OptIndex+1] += 4; // Save space for dest. addr
  726. OptIndex += Opt[OptIndex+1];
  727. OptLength += 4;
  728. sourceRouting = TRUE;
  729. break;
  730. case 'k': // Strict source routing
  731. // Only implemented for IPv4.
  732. if (!SetFamily(&Family, AF_INET, arg)) {
  733. goto error_exit;
  734. }
  735. if (sourceRouting) {
  736. NlsPutMsg(STDOUT, PING_BAD_OPTION_COMBO);
  737. goto error_exit;
  738. }
  739. if ((OptIndex + 3) > MAX_OPT_SIZE) {
  740. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  741. goto error_exit;
  742. }
  743. Opt = SendOptions;
  744. Opt[OptIndex] = IP_OPT_SSRR;
  745. Opt[OptIndex+1] = 3;
  746. Opt[OptIndex + 2] = 4; // Set initial pointer value
  747. OptLength += 3;
  748. while ( (i < (uint)(argc - 2)) && (*argv[i+1] != '-')) {
  749. if ((OptIndex + 3) > (MAX_OPT_SIZE - 4)) {
  750. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  751. goto error_exit;
  752. }
  753. arg = argv[++i];
  754. EndOffset = 0;
  755. do {
  756. TempAddr = str2ip(arg + EndOffset, &EndOffset);
  757. if (!TempAddr) {
  758. NlsPutMsg( STDOUT, PING_MESSAGE_4 );
  759. // printf("Bad route specified for loose source route");
  760. goto error_exit;
  761. }
  762. j = Opt[OptIndex+1];
  763. *(ulong UNALIGNED *)&Opt[j+OptIndex] = TempAddr;
  764. Opt[OptIndex+1] += 4;
  765. OptLength += 4;
  766. while (arg[EndOffset] != '\0' && isspace((unsigned char)arg[EndOffset]))
  767. EndOffset++;
  768. } while (arg[EndOffset] != '\0');
  769. }
  770. SRIndex = Opt[OptIndex+1] + OptIndex;
  771. Opt[OptIndex+1] += 4; // Save space for dest. addr
  772. OptIndex += Opt[OptIndex+1];
  773. OptLength += 4;
  774. sourceRouting = TRUE;
  775. break;
  776. case 'R':
  777. // Only implemented for IPv6 so far
  778. if (!SetFamily(&Family, AF_INET6, arg)) {
  779. goto error_exit;
  780. }
  781. SendOpts.Flags |= ICMPV6_ECHO_REQUEST_FLAG_REVERSE;
  782. break;
  783. case 'S':
  784. // Only implemented for IPv6 so far
  785. if (!SetFamily(&Family, AF_INET6, arg)) {
  786. goto error_exit;
  787. }
  788. if (!GetSource(Family, argv[++i], (LPSOCKADDR)&sourceAddress)) {
  789. NlsPutMsg(STDOUT, PING_MESSAGE_13, argv[i]);
  790. // NlsPutMsg(STDOUT, PING_BAD_ADDRESS, argv[i]);
  791. goto error_exit;
  792. }
  793. break;
  794. case '4':
  795. if (!SetFamily(&Family, AF_INET, arg)) {
  796. goto error_exit;
  797. }
  798. break;
  799. case '6':
  800. if (!SetFamily(&Family, AF_INET6, arg)) {
  801. goto error_exit;
  802. }
  803. break;
  804. default:
  805. NlsPutMsg( STDOUT, PING_MESSAGE_11, arg );
  806. // printf( "Bad option %s.\n\n", arg);
  807. PrintUsage();
  808. goto error_exit;
  809. break;
  810. }
  811. i++;
  812. } else { // Not an option, must be an IP address.
  813. if (found_addr) {
  814. NlsPutMsg( STDOUT, PING_MESSAGE_12, arg );
  815. // printf( "Bad parameter %s.\n", arg);
  816. goto error_exit;
  817. }
  818. // Added check for INADDR_NONE, MohsinA, 21-Oct-96.
  819. if (ResolveTarget(Family, arg, (LPSOCKADDR)&address,
  820. &addressLen, hostname, sizeof(hostname),
  821. dnsreq) &&
  822. ((address.ss_family != AF_INET) || (((LPSOCKADDR_IN)&address)->sin_addr.s_addr != INADDR_NONE))) {
  823. found_addr = 1;
  824. i++;
  825. } else {
  826. NlsPutMsg( STDOUT, PING_MESSAGE_13, arg );
  827. // printf( "Bad IP address %s.\n", arg);
  828. // "Unknown host %s.", was Bug 1368.
  829. goto error_exit;
  830. }
  831. }
  832. }
  833. }
  834. if (!found_addr) {
  835. NlsPutMsg( STDOUT, PING_MESSAGE_14 );
  836. // printf("IP address must be specified.\n");
  837. goto error_exit;
  838. }
  839. Family = address.ss_family;
  840. if (Family == AF_INET) {
  841. if (SRIndex != -1) {
  842. *(ulong UNALIGNED *)&SendOptions[SRIndex] = ((LPSOCKADDR_IN)&address)->sin_addr.s_addr;
  843. }
  844. IcmpHandle = IcmpCreateFile();
  845. } else {
  846. if (sourceAddress.ss_family == AF_UNSPEC) {
  847. SOCKET s;
  848. DWORD BytesReturned;
  849. //
  850. // A source address was not specified.
  851. // Get the preferred source address for this destination.
  852. //
  853. // If you want each individual echo request
  854. // to select a source address, use "-S ::".
  855. //
  856. s = socket(address.ss_family, 0, 0);
  857. if (s == INVALID_SOCKET) {
  858. NlsPutMsg(STDOUT, PING_WSASTARTUP_FAILED, WSAGetLastError());
  859. // NlsPutMsg(STDOUT, PING_SOCKET_FAILED, WSAGetLastError());
  860. exit(1);
  861. }
  862. (void) WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY,
  863. &address, sizeof address,
  864. &sourceAddress, sizeof sourceAddress,
  865. &BytesReturned, NULL, NULL);
  866. closesocket(s);
  867. }
  868. IcmpHandle = Icmp6CreateFile();
  869. }
  870. if (IcmpHandle == INVALID_HANDLE_VALUE) {
  871. NlsPutMsg( STDOUT, PING_MESSAGE_15, GetLastError() );
  872. // printf( "Unable to contact IP driver, error code %d.\n",
  873. // GetLastError() );
  874. goto error_exit;
  875. }
  876. SendBuffer = LocalAlloc(LMEM_FIXED, SendSize);
  877. if (SendBuffer == NULL) {
  878. NlsPutMsg(STDOUT, PING_NO_MEMORY);
  879. goto error_exit;
  880. }
  881. //
  882. // Calculate receive buffer size and try to allocate it.
  883. //
  884. if (SendSize <= DEFAULT_SEND_SIZE) {
  885. RcvSize = DEFAULT_BUFFER_SIZE;
  886. } else {
  887. RcvSize = MAX_BUFFER_SIZE;
  888. }
  889. RcvBuffer = LocalAlloc(LMEM_FIXED, RcvSize);
  890. if (RcvBuffer == NULL) {
  891. NlsPutMsg(STDOUT, PING_NO_MEMORY);
  892. LocalFree(SendBuffer);
  893. goto error_exit;
  894. }
  895. //
  896. // Initialize the send buffer pattern.
  897. //
  898. for (i = 0; i < SendSize; i++) {
  899. SendBuffer[i] = 'a' + (i % 23);
  900. }
  901. //
  902. // Initialize the send options
  903. //
  904. SendOpts.OptionsData = Opt;
  905. SendOpts.OptionsSize = (uchar)OptLength;
  906. SendOpts.Ttl = TTL;
  907. SendOpts.Tos = TOS;
  908. SendOpts.Flags = Flags;
  909. getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
  910. NULL, 0, NI_NUMERICHOST);
  911. if (hostname[0]) {
  912. NlsPutMsg(
  913. STDOUT,
  914. PING_HEADER1,
  915. hostname,
  916. literal,
  917. SendSize
  918. );
  919. // printf("Pinging Host %s [%s]\n", hostname, literal);
  920. } else {
  921. NlsPutMsg(
  922. STDOUT,
  923. PING_HEADER2,
  924. literal,
  925. SendSize
  926. );
  927. // printf("Pinging Host [%s]\n", literal);
  928. }
  929. if (sourceAddress.ss_family == AF_INET6) {
  930. getnameinfo((LPSOCKADDR)&sourceAddress, sizeof(SOCKADDR_IN6), literal,
  931. sizeof(literal), NULL, 0, NI_NUMERICHOST);
  932. // NlsPutMsg(STDOUT, PING_SOURCE_ADDRESS, literal);
  933. }
  934. // NlsPutMsg(STDOUT, PING_WITH_DATA, SendSize);
  935. SetConsoleCtrlHandler( &ConsoleControlHandler, TRUE );
  936. for (i = 0; i < Count; i++) {
  937. if (Family == AF_INET) {
  938. numberOfReplies = IcmpSendEcho2(IcmpHandle,
  939. 0,
  940. NULL,
  941. NULL,
  942. ((LPSOCKADDR_IN)&address)->sin_addr.s_addr,
  943. SendBuffer,
  944. (unsigned short) SendSize,
  945. &SendOpts,
  946. RcvBuffer,
  947. RcvSize,
  948. Timeout);
  949. num_send++;
  950. if (numberOfReplies == 0) {
  951. errorCode = GetLastError();
  952. if (errorCode < IP_STATUS_BASE) {
  953. NlsPutMsg( STDOUT, PING_MESSAGE_18, errorCode );
  954. // printf("PING: transmit failed, error code %lu\n", errorCode);
  955. } else {
  956. for (j = 0; ErrorTable[j].Error != errorCode &&
  957. ErrorTable[j].Error != IP_GENERAL_FAILURE;j++)
  958. ;
  959. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID );
  960. // printf("PING: %s.\n", ErrorTable[j].ErrorString);
  961. }
  962. if (i < (Count - 1)) {
  963. Sleep(MIN_INTERVAL);
  964. }
  965. } else {
  966. reply4 = (PICMP_ECHO_REPLY) RcvBuffer;
  967. while (numberOfReplies--) {
  968. struct in_addr addr;
  969. addr.S_un.S_addr = reply4->Address;
  970. NlsPutMsg(STDOUT, PING_MESSAGE_19, inet_ntoa(addr));
  971. // printf(
  972. // "Reply from %s:",
  973. // inet_ntoa(addr),
  974. // );
  975. if (reply4->Status == IP_SUCCESS) {
  976. NlsPutMsg( STDOUT, PING_MESSAGE_25, (int) reply4->DataSize);
  977. // printf(
  978. // "Echo size=%d ",
  979. // reply4->DataSize
  980. // );
  981. if (reply4->DataSize != SendSize) {
  982. NlsPutMsg( STDOUT, PING_MESSAGE_20, SendSize );
  983. // printf("(sent %d) ", SendSize);
  984. } else {
  985. char *sendptr, *recvptr;
  986. sendptr = &(SendBuffer[0]);
  987. recvptr = (char *) reply4->Data;
  988. for (j = 0; j < SendSize; j++)
  989. if (*sendptr++ != *recvptr++) {
  990. NlsPutMsg( STDOUT, PING_MESSAGE_21, j );
  991. // printf("- MISCOMPARE at offset %d - ", j);
  992. break;
  993. }
  994. }
  995. if (reply4->RoundTripTime) {
  996. NlsPutMsg( STDOUT, PING_MESSAGE_22, reply4->RoundTripTime );
  997. // Collect stats.
  998. time_total += reply4->RoundTripTime;
  999. if ( reply4->RoundTripTime < time_min ) {
  1000. time_min = reply4->RoundTripTime;
  1001. }
  1002. if ( reply4->RoundTripTime > time_max ) {
  1003. time_max = reply4->RoundTripTime;
  1004. }
  1005. }
  1006. else {
  1007. NlsPutMsg( STDOUT, PING_MESSAGE_23 );
  1008. // printf("time<1ms ");
  1009. time_min = 0;
  1010. }
  1011. // printf("\n time rt=%dms min %d, max %d, total %d\n",
  1012. // reply4->RoundTripTime,
  1013. // time_min, time_max, time_total );
  1014. NlsPutMsg( STDOUT, PING_MESSAGE_24, (uint)reply4->Options.Ttl );
  1015. // printf("TTL=%u\n", (uint)reply4->Options.Ttl);
  1016. if (reply4->Options.OptionsSize) {
  1017. ProcessOptions(reply4, dnsreq);
  1018. }
  1019. } else {
  1020. for (j=0; ErrorTable[j].Error != IP_GENERAL_FAILURE; j++) {
  1021. if (ErrorTable[j].Error == reply4->Status) {
  1022. break;
  1023. }
  1024. }
  1025. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID);
  1026. }
  1027. num_recv++;
  1028. reply4++;
  1029. }
  1030. if (i < (Count - 1)) {
  1031. reply4--;
  1032. if (reply4->RoundTripTime < MIN_INTERVAL) {
  1033. Sleep(MIN_INTERVAL - reply4->RoundTripTime);
  1034. }
  1035. }
  1036. }
  1037. } else {
  1038. // AF_INET6
  1039. numberOfReplies = Icmp6SendEcho2(IcmpHandle,
  1040. 0,
  1041. NULL,
  1042. NULL,
  1043. (LPSOCKADDR_IN6)&sourceAddress,
  1044. (LPSOCKADDR_IN6)&address,
  1045. SendBuffer,
  1046. (unsigned short) SendSize,
  1047. &SendOpts,
  1048. RcvBuffer,
  1049. RcvSize,
  1050. Timeout);
  1051. num_send++;
  1052. if (numberOfReplies == 0) {
  1053. errorCode = GetLastError();
  1054. if (errorCode < IP_STATUS_BASE) {
  1055. NlsPutMsg( STDOUT, PING_MESSAGE_18, errorCode );
  1056. // printf("PING: transmit failed, error code %lu\n", errorCode);
  1057. } else {
  1058. for (j = 0; ErrorTable[j].Error != errorCode &&
  1059. ErrorTable[j].Error != IP_GENERAL_FAILURE;j++)
  1060. ;
  1061. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID );
  1062. // printf("PING: %s.\n", ErrorTable[j].ErrorString);
  1063. }
  1064. if (i < (Count - 1)) {
  1065. Sleep(MIN_INTERVAL);
  1066. }
  1067. } else {
  1068. reply6 = (PICMPV6_ECHO_REPLY) RcvBuffer;
  1069. while (numberOfReplies--) {
  1070. getnameinfo((LPSOCKADDR)&address, addressLen, literal,
  1071. sizeof(literal), NULL, 0, NI_NUMERICHOST);
  1072. NlsPutMsg(STDOUT, PING_MESSAGE_19, literal);
  1073. // printf(
  1074. // "Reply from %s:",
  1075. // inet_ntoa(addr),
  1076. // );
  1077. if (reply6->Status == IP_SUCCESS) {
  1078. if (reply6->RoundTripTime) {
  1079. NlsPutMsg( STDOUT, PING_MESSAGE_22, reply6->RoundTripTime );
  1080. // Collect stats.
  1081. time_total += reply6->RoundTripTime;
  1082. if ( reply6->RoundTripTime < time_min ) {
  1083. time_min = reply6->RoundTripTime;
  1084. }
  1085. if ( reply6->RoundTripTime > time_max ) {
  1086. time_max = reply6->RoundTripTime;
  1087. }
  1088. }
  1089. else {
  1090. NlsPutMsg( STDOUT, PING_MESSAGE_23 );
  1091. // printf("time<1ms ");
  1092. time_min = 0;
  1093. }
  1094. // printf("\n time rt=%dms min %d, max %d, total %d\n",
  1095. // reply6->RoundTripTime,
  1096. // time_min, time_max, time_total );
  1097. NlsPutMsg(STDOUT, PING_CR);
  1098. } else {
  1099. for (j=0; ErrorTable[j].Error != IP_GENERAL_FAILURE; j++) {
  1100. if (ErrorTable[j].Error == reply6->Status) {
  1101. break;
  1102. }
  1103. }
  1104. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID);
  1105. }
  1106. num_recv++;
  1107. reply6++;
  1108. }
  1109. if (i < (Count - 1)) {
  1110. reply6--;
  1111. if (reply6->RoundTripTime < MIN_INTERVAL) {
  1112. Sleep(MIN_INTERVAL - reply6->RoundTripTime);
  1113. }
  1114. }
  1115. }
  1116. }
  1117. }
  1118. // MohsinA, 05-Dec-96. DCR # 65503.
  1119. print_statistics();
  1120. result = IcmpCloseHandle(IcmpHandle);
  1121. LocalFree(SendBuffer);
  1122. LocalFree(RcvBuffer);
  1123. WSACleanup();
  1124. exit(0 == num_recv);
  1125. error_exit:
  1126. WSACleanup();
  1127. exit(1);
  1128. }