Leaked source code of windows server 2003
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.

1368 lines
44 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)) == 0)
  101. return(0);
  102. // Convert vp to oem
  103. StrLen=(DWORD)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 = (int)ai->ai_addrlen;
  160. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  161. if (DoReverseLookup) {
  162. getnameinfo(ai->ai_addr, (socklen_t)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 = (socklen_t)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 = NULL;
  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_FAMILY, arg,
  531. (Value==AF_INET)? "IPv4" : "IPv6");
  532. return FALSE;
  533. }
  534. *Family = Value;
  535. return TRUE;
  536. }
  537. // ========================================================================
  538. void
  539. __cdecl
  540. main(int argc, char **argv)
  541. {
  542. SOCKADDR_STORAGE sourceAddress;
  543. char *arg;
  544. uint i;
  545. uint j;
  546. int found_addr = 0;
  547. BOOLEAN dnsreq = FALSE;
  548. char hostname[NI_MAXHOST], literal[INET6_ADDRSTRLEN];
  549. DWORD numberOfReplies;
  550. uint Count = DEFAULT_COUNT;
  551. uchar TTL = 0;
  552. uchar *Opt = NULL; // Pointer to send options
  553. uint OptLength = 0;
  554. int OptIndex = 0; // Current index into SendOptions
  555. int SRIndex = -1; // Where to put address, if source routing
  556. uchar TOS = DEFAULT_TOS;
  557. uchar Flags = 0; // For options specific to IPv4 or IPv6
  558. ulong Timeout = DEFAULT_TIMEOUT;
  559. IP_OPTION_INFORMATION SendOpts;
  560. int EndOffset;
  561. ulong TempAddr;
  562. uchar TempCount;
  563. DWORD errorCode;
  564. HANDLE IcmpHandle;
  565. int err;
  566. // struct in_addr addr;
  567. BOOL result;
  568. PICMP_ECHO_REPLY reply4;
  569. PICMPV6_ECHO_REPLY reply6;
  570. BOOL sourceRouting = FALSE;
  571. char *SendBuffer, *RcvBuffer;
  572. uint RcvSize;
  573. uint SendSize = DEFAULT_SEND_SIZE;
  574. DWORD Family = AF_UNSPEC;
  575. //
  576. // This will ensure the correct language message is displayed when
  577. // NlsPutMsg is called.
  578. //
  579. SetThreadUILanguage(0);
  580. err = WSAStartup(MAKEWORD(2, 0), &WsaData);
  581. if (err) {
  582. NlsPutMsg(STDOUT, PING_WSASTARTUP_FAILED, GetLastError());
  583. exit(1);
  584. }
  585. memset(&sourceAddress, 0, sizeof sourceAddress);
  586. TTL = GetDefaultTTL();
  587. if (argc < 2) {
  588. PrintUsage();
  589. goto error_exit;
  590. } else {
  591. i = 1;
  592. while (i < (uint) argc) {
  593. arg = argv[i];
  594. if ( (arg[0] == '-') || (arg[0] == '/') ) { // Have an option
  595. switch (arg[1]) {
  596. case '?':
  597. PrintUsage();
  598. exit(0);
  599. case 'l':
  600. // SendSize = (uint)param(argv, argc, i++, 0, 0xfff7);
  601. // A ping with packet size >= 64K can crash
  602. // some tcpip stacks during re-assembly,
  603. // So changed 'max' from 0xfff7 to 65500
  604. // - MohsinA, 13-Nov-96.
  605. SendSize = (uint)param(argv, argc, i++, 0, 65500 );
  606. break;
  607. case 't':
  608. Count = (uint)-1;
  609. break;
  610. case 'n':
  611. Count = (uint)param(argv, argc, i++, 1, 0xffffffff);
  612. break;
  613. case 'f':
  614. // Only implemented for IPv4.
  615. if (!SetFamily(&Family, AF_INET, arg)) {
  616. goto error_exit;
  617. }
  618. Flags |= IP_FLAG_DF;
  619. break;
  620. case 'i':
  621. // TTL of zero is invalid, MohsinA, 13-Mar-97.
  622. TTL = (uchar)param(argv, argc, i++, 1, 0xff);
  623. break;
  624. case 'v':
  625. // Only implemented for IPv4.
  626. if (!SetFamily(&Family, AF_INET, arg)) {
  627. goto error_exit;
  628. }
  629. TOS = (uchar)param(argv, argc, i++, 0, 0xff);
  630. break;
  631. case 'w':
  632. Timeout = param(argv, argc, i++, 0, 0xffffffff);
  633. break;
  634. case 'a':
  635. dnsreq = TRUE;
  636. break;
  637. case 'r': // Record Route
  638. // Only implemented for IPv4.
  639. if (!SetFamily(&Family, AF_INET, arg)) {
  640. goto error_exit;
  641. }
  642. if ((OptIndex + 3) > MAX_OPT_SIZE) {
  643. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  644. goto error_exit;
  645. }
  646. Opt = SendOptions;
  647. Opt[OptIndex] = IP_OPT_RR;
  648. Opt[OptIndex + 2] = 4; // Set initial pointer value
  649. // min is 1 not zero, MohsinA, 16-4-97.
  650. TempCount = (uchar)param(argv, argc, i++, 1, 9);
  651. TempCount = (TempCount * sizeof(ulong)) + 3;
  652. if ((TempCount + OptIndex) > MAX_OPT_SIZE) {
  653. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  654. goto error_exit;
  655. }
  656. Opt[OptIndex+1] = TempCount;
  657. OptLength += TempCount;
  658. OptIndex += TempCount;
  659. break;
  660. case 's': // Timestamp
  661. // Only implemented for IPv4.
  662. if (!SetFamily(&Family, AF_INET, arg)) {
  663. goto error_exit;
  664. }
  665. if ((OptIndex + 4) > MAX_OPT_SIZE) {
  666. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  667. goto error_exit;
  668. }
  669. Opt = SendOptions;
  670. Opt[OptIndex] = IP_OPT_TS;
  671. Opt[OptIndex + 2] = 5; // Set initial pointer value
  672. TempCount = (uchar)param(argv, argc, i++, 1, 4);
  673. TempCount = (TempCount * (sizeof(ulong) * 2)) + 4;
  674. if ((TempCount + OptIndex) > MAX_OPT_SIZE) {
  675. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  676. goto error_exit;
  677. }
  678. Opt[OptIndex+1] = TempCount;
  679. Opt[OptIndex+3] = 1;
  680. OptLength += TempCount;
  681. OptIndex += TempCount;
  682. break;
  683. case 'j': // Loose source routing
  684. // Only implemented for IPv4.
  685. if (!SetFamily(&Family, AF_INET, arg)) {
  686. goto error_exit;
  687. }
  688. if (sourceRouting) {
  689. NlsPutMsg(STDOUT, PING_BAD_OPTION_COMBO);
  690. goto error_exit;
  691. }
  692. if ((OptIndex + 3) > MAX_OPT_SIZE) {
  693. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  694. goto error_exit;
  695. }
  696. Opt = SendOptions;
  697. Opt[OptIndex] = IP_OPT_LSRR;
  698. Opt[OptIndex+1] = 3;
  699. Opt[OptIndex + 2] = 4; // Set initial pointer value
  700. OptLength += 3;
  701. while ( (i < (uint)(argc - 2)) && (*argv[i+1] != '-')) {
  702. if ((OptIndex + 3) > (MAX_OPT_SIZE - 4)) {
  703. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  704. goto error_exit;
  705. }
  706. arg = argv[++i];
  707. EndOffset = 0;
  708. do {
  709. TempAddr = str2ip(arg + EndOffset, &EndOffset);
  710. if (!TempAddr) {
  711. NlsPutMsg( STDOUT, PING_MESSAGE_4 );
  712. // printf("Bad route specified for loose source route");
  713. goto error_exit;
  714. }
  715. j = Opt[OptIndex+1];
  716. *(ulong UNALIGNED *)&Opt[j+OptIndex] = TempAddr;
  717. Opt[OptIndex+1] += 4;
  718. OptLength += 4;
  719. while (arg[EndOffset] != '\0' && isspace((unsigned char)arg[EndOffset]))
  720. EndOffset++;
  721. } while (arg[EndOffset] != '\0');
  722. }
  723. SRIndex = Opt[OptIndex+1] + OptIndex;
  724. Opt[OptIndex+1] += 4; // Save space for dest. addr
  725. OptIndex += Opt[OptIndex+1];
  726. OptLength += 4;
  727. sourceRouting = TRUE;
  728. break;
  729. case 'k': // Strict source routing
  730. // Only implemented for IPv4.
  731. if (!SetFamily(&Family, AF_INET, arg)) {
  732. goto error_exit;
  733. }
  734. if (sourceRouting) {
  735. NlsPutMsg(STDOUT, PING_BAD_OPTION_COMBO);
  736. goto error_exit;
  737. }
  738. if ((OptIndex + 3) > MAX_OPT_SIZE) {
  739. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  740. goto error_exit;
  741. }
  742. Opt = SendOptions;
  743. Opt[OptIndex] = IP_OPT_SSRR;
  744. Opt[OptIndex+1] = 3;
  745. Opt[OptIndex + 2] = 4; // Set initial pointer value
  746. OptLength += 3;
  747. while ( (i < (uint)(argc - 2)) && (*argv[i+1] != '-')) {
  748. if ((OptIndex + 3) > (MAX_OPT_SIZE - 4)) {
  749. NlsPutMsg(STDOUT, PING_TOO_MANY_OPTIONS);
  750. goto error_exit;
  751. }
  752. arg = argv[++i];
  753. EndOffset = 0;
  754. do {
  755. TempAddr = str2ip(arg + EndOffset, &EndOffset);
  756. if (!TempAddr) {
  757. NlsPutMsg( STDOUT, PING_MESSAGE_4 );
  758. // printf("Bad route specified for loose source route");
  759. goto error_exit;
  760. }
  761. j = Opt[OptIndex+1];
  762. *(ulong UNALIGNED *)&Opt[j+OptIndex] = TempAddr;
  763. Opt[OptIndex+1] += 4;
  764. OptLength += 4;
  765. while (arg[EndOffset] != '\0' && isspace((unsigned char)arg[EndOffset]))
  766. EndOffset++;
  767. } while (arg[EndOffset] != '\0');
  768. }
  769. SRIndex = Opt[OptIndex+1] + OptIndex;
  770. Opt[OptIndex+1] += 4; // Save space for dest. addr
  771. OptIndex += Opt[OptIndex+1];
  772. OptLength += 4;
  773. sourceRouting = TRUE;
  774. break;
  775. case 'R':
  776. // Only implemented for IPv6 so far
  777. if (!SetFamily(&Family, AF_INET6, arg)) {
  778. goto error_exit;
  779. }
  780. Flags |= ICMPV6_ECHO_REQUEST_FLAG_REVERSE;
  781. break;
  782. case 'S':
  783. // Only implemented for IPv6 so far
  784. if (!SetFamily(&Family, AF_INET6, arg)) {
  785. goto error_exit;
  786. }
  787. if (!GetSource(Family, argv[++i], (LPSOCKADDR)&sourceAddress)) {
  788. NlsPutMsg(STDOUT, PING_BAD_ADDRESS, argv[i]);
  789. goto error_exit;
  790. }
  791. break;
  792. case '4':
  793. if (!SetFamily(&Family, AF_INET, arg)) {
  794. goto error_exit;
  795. }
  796. break;
  797. case '6':
  798. if (!SetFamily(&Family, AF_INET6, arg)) {
  799. goto error_exit;
  800. }
  801. break;
  802. default:
  803. NlsPutMsg( STDOUT, PING_MESSAGE_11, arg );
  804. // printf( "Bad option %s.\n\n", arg);
  805. PrintUsage();
  806. goto error_exit;
  807. break;
  808. }
  809. i++;
  810. } else { // Not an option, must be an IP address.
  811. if (found_addr) {
  812. NlsPutMsg( STDOUT, PING_MESSAGE_12, arg );
  813. // printf( "Bad parameter %s.\n", arg);
  814. goto error_exit;
  815. }
  816. // Added check for INADDR_NONE, MohsinA, 21-Oct-96.
  817. if (ResolveTarget(Family, arg, (LPSOCKADDR)&address,
  818. &addressLen, hostname, sizeof(hostname),
  819. dnsreq) &&
  820. ((address.ss_family != AF_INET) || (((LPSOCKADDR_IN)&address)->sin_addr.s_addr != INADDR_NONE))) {
  821. found_addr = 1;
  822. i++;
  823. } else {
  824. NlsPutMsg( STDOUT, PING_MESSAGE_13, arg );
  825. // printf( "Bad IP address %s.\n", arg);
  826. // "Unknown host %s.", was Bug 1368.
  827. goto error_exit;
  828. }
  829. }
  830. }
  831. }
  832. if (!found_addr) {
  833. NlsPutMsg( STDOUT, PING_MESSAGE_14 );
  834. // printf("IP address must be specified.\n");
  835. goto error_exit;
  836. }
  837. Family = address.ss_family;
  838. if (Family == AF_INET) {
  839. if (SRIndex != -1) {
  840. *(ulong UNALIGNED *)&SendOptions[SRIndex] = ((LPSOCKADDR_IN)&address)->sin_addr.s_addr;
  841. }
  842. IcmpHandle = IcmpCreateFile();
  843. } else {
  844. if (sourceAddress.ss_family == AF_UNSPEC) {
  845. SOCKET s;
  846. DWORD BytesReturned;
  847. //
  848. // A source address was not specified.
  849. // Get the preferred source address for this destination.
  850. //
  851. // If you want each individual echo request
  852. // to select a source address, use "-S ::".
  853. //
  854. s = socket(address.ss_family, 0, 0);
  855. if (s == INVALID_SOCKET) {
  856. NlsPutMsg(STDOUT, PING_SOCKET_FAILED, WSAGetLastError());
  857. exit(1);
  858. }
  859. (void) WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY,
  860. &address, sizeof address,
  861. &sourceAddress, sizeof sourceAddress,
  862. &BytesReturned, NULL, NULL);
  863. closesocket(s);
  864. }
  865. IcmpHandle = Icmp6CreateFile();
  866. }
  867. if (IcmpHandle == INVALID_HANDLE_VALUE) {
  868. NlsPutMsg( STDOUT, PING_MESSAGE_15, GetLastError() );
  869. // printf( "Unable to contact IP driver, error code %d.\n",
  870. // GetLastError() );
  871. goto error_exit;
  872. }
  873. SendBuffer = LocalAlloc(LMEM_FIXED, SendSize);
  874. if (SendBuffer == NULL) {
  875. NlsPutMsg(STDOUT, PING_NO_MEMORY);
  876. goto error_exit;
  877. }
  878. //
  879. // Calculate receive buffer size and try to allocate it.
  880. //
  881. if (SendSize <= DEFAULT_SEND_SIZE) {
  882. RcvSize = DEFAULT_BUFFER_SIZE;
  883. } else {
  884. RcvSize = MAX_BUFFER_SIZE;
  885. }
  886. RcvBuffer = LocalAlloc(LMEM_FIXED, RcvSize);
  887. if (RcvBuffer == NULL) {
  888. NlsPutMsg(STDOUT, PING_NO_MEMORY);
  889. LocalFree(SendBuffer);
  890. goto error_exit;
  891. }
  892. //
  893. // Initialize the send buffer pattern.
  894. //
  895. for (i = 0; i < SendSize; i++) {
  896. SendBuffer[i] = (char)('a' + (i % 23));
  897. }
  898. //
  899. // Initialize the send options
  900. //
  901. SendOpts.OptionsData = Opt;
  902. SendOpts.OptionsSize = (uchar)OptLength;
  903. SendOpts.Ttl = TTL;
  904. SendOpts.Tos = TOS;
  905. SendOpts.Flags = Flags;
  906. getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
  907. NULL, 0, NI_NUMERICHOST);
  908. if (hostname[0]) {
  909. NlsPutMsg(
  910. STDOUT,
  911. PING_HEADER1,
  912. hostname,
  913. literal
  914. );
  915. // printf("Pinging Host %s [%s]\n", hostname, literal);
  916. } else {
  917. NlsPutMsg(
  918. STDOUT,
  919. PING_HEADER2,
  920. literal
  921. );
  922. // printf("Pinging Host [%s]\n", literal);
  923. }
  924. if (sourceAddress.ss_family == AF_INET6) {
  925. getnameinfo((LPSOCKADDR)&sourceAddress, sizeof(SOCKADDR_IN6), literal,
  926. sizeof(literal), NULL, 0, NI_NUMERICHOST);
  927. NlsPutMsg(STDOUT, PING_SOURCE_ADDRESS, literal);
  928. }
  929. NlsPutMsg(STDOUT, PING_WITH_DATA, SendSize);
  930. SetConsoleCtrlHandler( &ConsoleControlHandler, TRUE );
  931. for (i = 0; i < Count; i++) {
  932. if (Family == AF_INET) {
  933. numberOfReplies = IcmpSendEcho2(IcmpHandle,
  934. 0,
  935. NULL,
  936. NULL,
  937. ((LPSOCKADDR_IN)&address)->sin_addr.s_addr,
  938. SendBuffer,
  939. (unsigned short) SendSize,
  940. &SendOpts,
  941. RcvBuffer,
  942. RcvSize,
  943. Timeout);
  944. num_send++;
  945. if (numberOfReplies == 0) {
  946. errorCode = GetLastError();
  947. if (errorCode < IP_STATUS_BASE) {
  948. NlsPutMsg( STDOUT, PING_MESSAGE_18, errorCode );
  949. // printf("PING: transmit failed, error code %lu\n", errorCode);
  950. } else {
  951. for (j = 0; ErrorTable[j].Error != errorCode &&
  952. ErrorTable[j].Error != IP_GENERAL_FAILURE;j++)
  953. ;
  954. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID );
  955. // printf("PING: %s.\n", ErrorTable[j].ErrorString);
  956. }
  957. if (i < (Count - 1)) {
  958. Sleep(MIN_INTERVAL);
  959. }
  960. } else {
  961. reply4 = (PICMP_ECHO_REPLY) RcvBuffer;
  962. while (numberOfReplies--) {
  963. struct in_addr addr;
  964. addr.S_un.S_addr = reply4->Address;
  965. NlsPutMsg(STDOUT, PING_MESSAGE_19, inet_ntoa(addr));
  966. // printf(
  967. // "Reply from %s:",
  968. // inet_ntoa(addr),
  969. // );
  970. if (reply4->Status == IP_SUCCESS) {
  971. NlsPutMsg( STDOUT, PING_MESSAGE_25, (int) reply4->DataSize);
  972. // printf(
  973. // "Echo size=%d ",
  974. // reply4->DataSize
  975. // );
  976. if (reply4->DataSize != SendSize) {
  977. NlsPutMsg( STDOUT, PING_MESSAGE_20, SendSize );
  978. // printf("(sent %d) ", SendSize);
  979. } else {
  980. char *sendptr, *recvptr;
  981. sendptr = &(SendBuffer[0]);
  982. recvptr = (char *) reply4->Data;
  983. for (j = 0; j < SendSize; j++)
  984. if (*sendptr++ != *recvptr++) {
  985. NlsPutMsg( STDOUT, PING_MESSAGE_21, j );
  986. // printf("- MISCOMPARE at offset %d - ", j);
  987. break;
  988. }
  989. }
  990. if (reply4->RoundTripTime) {
  991. NlsPutMsg( STDOUT, PING_MESSAGE_22, reply4->RoundTripTime );
  992. // Collect stats.
  993. time_total += reply4->RoundTripTime;
  994. if ( reply4->RoundTripTime < time_min ) {
  995. time_min = reply4->RoundTripTime;
  996. }
  997. if ( reply4->RoundTripTime > time_max ) {
  998. time_max = reply4->RoundTripTime;
  999. }
  1000. }
  1001. else {
  1002. NlsPutMsg( STDOUT, PING_MESSAGE_23 );
  1003. // printf("time<1ms ");
  1004. time_min = 0;
  1005. }
  1006. // printf("\n time rt=%dms min %d, max %d, total %d\n",
  1007. // reply4->RoundTripTime,
  1008. // time_min, time_max, time_total );
  1009. NlsPutMsg( STDOUT, PING_MESSAGE_24, (uint)reply4->Options.Ttl );
  1010. // printf("TTL=%u\n", (uint)reply4->Options.Ttl);
  1011. if (reply4->Options.OptionsSize) {
  1012. ProcessOptions(reply4, dnsreq);
  1013. }
  1014. } else {
  1015. for (j=0; ErrorTable[j].Error != IP_GENERAL_FAILURE; j++) {
  1016. if (ErrorTable[j].Error == reply4->Status) {
  1017. break;
  1018. }
  1019. }
  1020. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID);
  1021. }
  1022. num_recv++;
  1023. reply4++;
  1024. }
  1025. if (i < (Count - 1)) {
  1026. reply4--;
  1027. if (reply4->RoundTripTime < MIN_INTERVAL) {
  1028. Sleep(MIN_INTERVAL - reply4->RoundTripTime);
  1029. }
  1030. }
  1031. }
  1032. } else {
  1033. // AF_INET6
  1034. numberOfReplies = Icmp6SendEcho2(IcmpHandle,
  1035. 0,
  1036. NULL,
  1037. NULL,
  1038. (LPSOCKADDR_IN6)&sourceAddress,
  1039. (LPSOCKADDR_IN6)&address,
  1040. SendBuffer,
  1041. (unsigned short) SendSize,
  1042. &SendOpts,
  1043. RcvBuffer,
  1044. RcvSize,
  1045. Timeout);
  1046. num_send++;
  1047. if (numberOfReplies == 0) {
  1048. errorCode = GetLastError();
  1049. if (errorCode < IP_STATUS_BASE) {
  1050. NlsPutMsg( STDOUT, PING_MESSAGE_18, errorCode );
  1051. // printf("PING: transmit failed, error code %lu\n", errorCode);
  1052. } else {
  1053. for (j = 0; ErrorTable[j].Error != errorCode &&
  1054. ErrorTable[j].Error != IP_GENERAL_FAILURE;j++)
  1055. ;
  1056. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID );
  1057. // printf("PING: %s.\n", ErrorTable[j].ErrorString);
  1058. }
  1059. if (i < (Count - 1)) {
  1060. Sleep(MIN_INTERVAL);
  1061. }
  1062. } else {
  1063. reply6 = (PICMPV6_ECHO_REPLY) RcvBuffer;
  1064. while (numberOfReplies--) {
  1065. getnameinfo((LPSOCKADDR)&address, addressLen, literal,
  1066. sizeof(literal), NULL, 0, NI_NUMERICHOST);
  1067. NlsPutMsg(STDOUT, PING_MESSAGE_19, literal);
  1068. // printf(
  1069. // "Reply from %s:",
  1070. // inet_ntoa(addr),
  1071. // );
  1072. if (reply6->Status == IP_SUCCESS) {
  1073. if (reply6->RoundTripTime) {
  1074. NlsPutMsg( STDOUT, PING_MESSAGE_22, reply6->RoundTripTime );
  1075. // Collect stats.
  1076. time_total += reply6->RoundTripTime;
  1077. if ( reply6->RoundTripTime < time_min ) {
  1078. time_min = reply6->RoundTripTime;
  1079. }
  1080. if ( reply6->RoundTripTime > time_max ) {
  1081. time_max = reply6->RoundTripTime;
  1082. }
  1083. }
  1084. else {
  1085. NlsPutMsg( STDOUT, PING_MESSAGE_23 );
  1086. // printf("time<1ms ");
  1087. time_min = 0;
  1088. }
  1089. // printf("\n time rt=%dms min %d, max %d, total %d\n",
  1090. // reply6->RoundTripTime,
  1091. // time_min, time_max, time_total );
  1092. NlsPutMsg(STDOUT, PING_CR);
  1093. } else {
  1094. for (j=0; ErrorTable[j].Error != IP_GENERAL_FAILURE; j++) {
  1095. if (ErrorTable[j].Error == reply6->Status) {
  1096. break;
  1097. }
  1098. }
  1099. NlsPutMsg( STDOUT, ErrorTable[j].ErrorNlsID);
  1100. }
  1101. num_recv++;
  1102. reply6++;
  1103. }
  1104. if (i < (Count - 1)) {
  1105. reply6--;
  1106. if (reply6->RoundTripTime < MIN_INTERVAL) {
  1107. Sleep(MIN_INTERVAL - reply6->RoundTripTime);
  1108. }
  1109. }
  1110. }
  1111. }
  1112. }
  1113. // MohsinA, 05-Dec-96. DCR # 65503.
  1114. print_statistics();
  1115. result = IcmpCloseHandle(IcmpHandle);
  1116. LocalFree(SendBuffer);
  1117. LocalFree(RcvBuffer);
  1118. WSACleanup();
  1119. exit(0 == num_recv);
  1120. error_exit:
  1121. WSACleanup();
  1122. exit(1);
  1123. }