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.

901 lines
28 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. pathping.c
  5. Abstract:
  6. PathPing utility
  7. Author:
  8. Dave Thaler
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. rajeshsu Aug 10, 1999 Added QoS support (802.1p and RSVP)
  13. dthaler Mar 31, 2001 Added IPv6 support
  14. mjourd Feb 20, 2002 Removed QoS support.
  15. Notes:
  16. --*/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #define NOGDI
  21. #define NOMINMAX
  22. #include <windows.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <ctype.h>
  26. #include <io.h>
  27. #include <nls.h>
  28. #include <winsock2.h>
  29. #include <ws2tcpip.h>
  30. #include <ntddip6.h>
  31. #include "ipexport.h"
  32. #include "icmpapi.h"
  33. #include "nlstxt.h"
  34. #include "pathping.h"
  35. ULONG g_ulTimeout = DEFAULT_TIMEOUT;
  36. ULONG g_ulInterval = MIN_INTERVAL;
  37. ULONG g_ulNumQueries = DEFAULT_NUM_QUERIES;
  38. HANDLE g_hIcmp = NULL;
  39. ULONG g_ulRcvBufSize = 0x2000;
  40. BOOLEAN g_bDoReverseLookup = TRUE;
  41. SOCKADDR_STORAGE g_ssMyAddr = {0};
  42. socklen_t g_slMyAddrLen = 0;
  43. BOOLEAN g_bSetAddr = FALSE;
  44. HOP hop[MAX_HOPS];
  45. #ifdef VXD
  46. # define FAR _far
  47. #endif // VXD
  48. char SendBuffer[DEFAULT_SEND_SIZE];
  49. char RcvBuffer[DEFAULT_RECEIVE_SIZE];
  50. WSADATA WsaData;
  51. struct IPErrorTable {
  52. IP_STATUS Error; // The IP Error
  53. DWORD ErrorNlsID; // The corresponding NLS string ID.
  54. } ErrorTable[] =
  55. {
  56. { IP_BUF_TOO_SMALL, PATHPING_BUF_TOO_SMALL },
  57. { IP_DEST_NET_UNREACHABLE, PATHPING_DEST_NET_UNREACHABLE },
  58. { IP_DEST_HOST_UNREACHABLE, PATHPING_DEST_HOST_UNREACHABLE },
  59. { IP_DEST_PROT_UNREACHABLE, PATHPING_DEST_PROT_UNREACHABLE },
  60. { IP_DEST_PORT_UNREACHABLE, PATHPING_DEST_PORT_UNREACHABLE },
  61. { IP_NO_RESOURCES, PATHPING_NO_RESOURCES },
  62. { IP_BAD_OPTION, PATHPING_BAD_OPTION },
  63. { IP_HW_ERROR, PATHPING_HW_ERROR },
  64. { IP_PACKET_TOO_BIG, PATHPING_PACKET_TOO_BIG },
  65. { IP_REQ_TIMED_OUT, PATHPING_REQ_TIMED_OUT },
  66. { IP_BAD_REQ, PATHPING_BAD_REQ },
  67. { IP_BAD_ROUTE, PATHPING_BAD_ROUTE },
  68. { IP_TTL_EXPIRED_TRANSIT, PATHPING_TTL_EXPIRED_TRANSIT },
  69. { IP_TTL_EXPIRED_REASSEM, PATHPING_TTL_EXPIRED_REASSEM },
  70. { IP_PARAM_PROBLEM, PATHPING_PARAM_PROBLEM },
  71. { IP_SOURCE_QUENCH, PATHPING_SOURCE_QUENCH },
  72. { IP_OPTION_TOO_BIG, PATHPING_OPTION_TOO_BIG },
  73. { IP_BAD_DESTINATION, PATHPING_BAD_DESTINATION },
  74. { IP_NEGOTIATING_IPSEC, PATHPING_NEGOTIATING_IPSEC },
  75. { IP_GENERAL_FAILURE, PATHPING_GENERAL_FAILURE }
  76. };
  77. void
  78. print_addr(SOCKADDR *sa, socklen_t salen, BOOLEAN DoReverseLookup)
  79. {
  80. char hostname[NI_MAXHOST];
  81. int i;
  82. BOOLEAN didReverse = FALSE;
  83. if (DoReverseLookup) {
  84. i = getnameinfo(sa, salen, hostname, sizeof(hostname),
  85. NULL, 0, NI_NAMEREQD);
  86. if (i == NO_ERROR) {
  87. didReverse = TRUE;
  88. NlsPutMsg(STDOUT, PATHPING_TARGET_NAME, hostname);
  89. }
  90. }
  91. i = getnameinfo(sa, salen, hostname, sizeof(hostname),
  92. NULL, 0, NI_NUMERICHOST);
  93. if (i != NO_ERROR) {
  94. // This should never happen unless there is a memory problem,
  95. // in which case the message associated with PATHPING_NO_RESOURCES
  96. // is reasonable.
  97. NlsPutMsg(STDOUT, PATHPING_NO_RESOURCES);
  98. exit (1);
  99. }
  100. if (didReverse) {
  101. NlsPutMsg( STDOUT, PATHPING_BRKT_IP_ADDRESS, hostname );
  102. } else {
  103. NlsPutMsg( STDOUT, PATHPING_IP_ADDRESS, hostname );
  104. }
  105. }
  106. void
  107. print_ip_addr(IPAddr ipv4Addr, BOOLEAN DoReverseLookup)
  108. {
  109. SOCKADDR_IN sin;
  110. memset(&sin, 0, sizeof(sin));
  111. sin.sin_family = AF_INET;
  112. sin.sin_addr.s_addr = ipv4Addr;
  113. print_addr((LPSOCKADDR)&sin, sizeof(sin), DoReverseLookup);
  114. }
  115. void
  116. print_ipv6_addr(USHORT ipv6Addr[8], BOOLEAN DoReverseLookup)
  117. {
  118. SOCKADDR_IN6 sin;
  119. memset(&sin, 0, sizeof(sin));
  120. sin.sin6_family = AF_INET6;
  121. memcpy(&sin.sin6_addr, ipv6Addr, sizeof(sin.sin6_addr));
  122. print_addr((LPSOCKADDR)&sin, sizeof(sin), DoReverseLookup);
  123. }
  124. void
  125. print_time(ULONG Time)
  126. {
  127. if (Time) {
  128. NlsPutMsg( STDOUT, PATHPING_TIME, Time );
  129. // printf(" %3lu ms\n", Time);
  130. }
  131. else {
  132. NlsPutMsg( STDOUT, PATHPING_TIME_10MS );
  133. // printf(" <10 ms\n");
  134. }
  135. }
  136. BOOLEAN
  137. param(
  138. ULONG *parameter,
  139. char **argv,
  140. int argc,
  141. int current,
  142. ULONG min,
  143. ULONG max
  144. )
  145. {
  146. ULONG temp;
  147. char *dummy;
  148. if (current == (argc - 1) ) {
  149. NlsPutMsg( STDOUT, PATHPING_NO_OPTION_VALUE, argv[current] );
  150. // printf( "Value must be supplied for option %s.\n", argv[current]);
  151. return(FALSE);
  152. }
  153. temp = strtoul(argv[current+1], &dummy, 0);
  154. if (temp < min || temp > max) {
  155. NlsPutMsg( STDOUT, PATHPING_BAD_OPTION_VALUE, argv[current] );
  156. // printf( "Bad value for option %s.\n", argv[current]);
  157. return(FALSE);
  158. }
  159. *parameter = temp;
  160. return(TRUE);
  161. }
  162. BOOLEAN
  163. ResolveTarget(
  164. IN DWORD Family,
  165. IN char *TargetString,
  166. OUT SOCKADDR_STORAGE *TargetAddress,
  167. OUT socklen_t *TargetAddressLen,
  168. OUT char *TargetName,
  169. IN DWORD TargetNameLen,
  170. IN BOOLEAN DoReverseLookup
  171. )
  172. {
  173. int i;
  174. struct addrinfo hints, *ai;
  175. TargetName[0] = '\0';
  176. memset(&hints, 0, sizeof(hints));
  177. hints.ai_family = Family;
  178. hints.ai_flags = AI_NUMERICHOST;
  179. i = getaddrinfo(TargetString, NULL, &hints, &ai);
  180. if (i == NO_ERROR) {
  181. *TargetAddressLen = (socklen_t)ai->ai_addrlen;
  182. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  183. if (DoReverseLookup) {
  184. getnameinfo(ai->ai_addr, (socklen_t)ai->ai_addrlen,
  185. TargetName, TargetNameLen,
  186. NULL, 0, NI_NAMEREQD);
  187. }
  188. freeaddrinfo(ai);
  189. return(TRUE);
  190. } else {
  191. hints.ai_flags = AI_CANONNAME;
  192. if (getaddrinfo(TargetString, NULL, &hints, &ai) == 0) {
  193. *TargetAddressLen = (socklen_t)ai->ai_addrlen;
  194. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  195. strcpy(TargetName,
  196. (ai->ai_canonname)? ai->ai_canonname : TargetString);
  197. freeaddrinfo(ai);
  198. return(TRUE);
  199. }
  200. }
  201. return(FALSE);
  202. } // ResolveTarget
  203. ULONG g_ulSendsDone = 0;
  204. void
  205. SleepForTotal(
  206. DWORD dwTotal
  207. )
  208. {
  209. DWORD dwStopAt = GetTickCount() + dwTotal;
  210. int iLeft = (int)dwTotal;
  211. while (iLeft > 0) {
  212. SleepEx(iLeft, TRUE);
  213. iLeft = dwStopAt - GetTickCount();
  214. }
  215. }
  216. VOID
  217. EchoDone(
  218. IN PVOID pContext,
  219. IN PIO_STATUS_BLOCK Ignored1,
  220. IN ULONG Ignored2
  221. )
  222. {
  223. PAPC_CONTEXT pApc = (PAPC_CONTEXT)pContext;
  224. ULONG ulNumReplies;
  225. ULONG i;
  226. UNREFERENCED_PARAMETER(Ignored1);
  227. UNREFERENCED_PARAMETER(Ignored2);
  228. g_ulSendsDone++;
  229. if (g_ssMyAddr.ss_family == AF_INET) {
  230. ulNumReplies = IcmpParseReplies(pApc->pReply4, g_ulRcvBufSize);
  231. for (i=0; i<ulNumReplies; i++) {
  232. if (pApc->sinAddr.sin_addr.s_addr is pApc->pReply4[i].Address) {
  233. pApc->ulNumRcvd++;
  234. pApc->ulRTTtotal += pApc->pReply4[i].RoundTripTime;
  235. return;
  236. }
  237. }
  238. } else {
  239. ulNumReplies = Icmp6ParseReplies(pApc->pReply6, g_ulRcvBufSize);
  240. for (i=0; i<ulNumReplies; i++) {
  241. if (!memcmp(&pApc->sin6Addr.sin6_addr,
  242. &pApc->pReply6[i].Address.sin6_addr,
  243. sizeof(struct in6_addr))) {
  244. pApc->ulNumRcvd++;
  245. pApc->ulRTTtotal += pApc->pReply6[i].RoundTripTime;
  246. return;
  247. }
  248. }
  249. }
  250. }
  251. // now that the hop[] array is filled in, ping each one every g_ulInterval
  252. // seconds
  253. void
  254. ComputeStatistics(
  255. PIP_OPTION_INFORMATION pOptions
  256. )
  257. {
  258. ULONG h, q;
  259. ULONG ulHopCount = (ULONG)pOptions->Ttl;
  260. // Allocate memory for replies
  261. for (h=1; h<=ulHopCount; h++)
  262. hop[h].pReply = LocalAlloc(LMEM_FIXED, g_ulRcvBufSize);
  263. for (q=0; q<g_ulNumQueries; q++) {
  264. for (h=1; h<=ulHopCount; h++) {
  265. if (hop[h].saAddr.sa_family == AF_INET) {
  266. // Send ping to h
  267. IcmpSendEcho2(g_hIcmp, // handle to icmp
  268. NULL, // no event
  269. EchoDone, // callback function
  270. (LPVOID)&hop[h], // parameter to pass to callback fcn
  271. hop[h].sinAddr.sin_addr.s_addr, // destination
  272. SendBuffer,
  273. DEFAULT_SEND_SIZE,
  274. pOptions,
  275. hop[h].pReply,
  276. g_ulRcvBufSize,
  277. g_ulTimeout );
  278. } else {
  279. Icmp6SendEcho2(g_hIcmp, // handle to icmp
  280. NULL, // no event
  281. EchoDone, // callback function
  282. (LPVOID)&hop[h], // parameter to pass to callback fcn
  283. (LPSOCKADDR_IN6)&g_ssMyAddr,
  284. &hop[h].sin6Addr,// destination
  285. SendBuffer,
  286. DEFAULT_SEND_SIZE,
  287. pOptions,
  288. hop[h].pReply,
  289. g_ulRcvBufSize,
  290. g_ulTimeout );
  291. }
  292. // Wait alertably for 'delay' ms
  293. SleepForTotal(g_ulInterval);
  294. }
  295. }
  296. // Wait alertably until Done count hits max
  297. while (g_ulSendsDone < ulHopCount * g_ulNumQueries)
  298. SleepEx(INFINITE, TRUE);
  299. // Compute per-hop info
  300. // hoprcvd is max rcvd of all hops >= h
  301. hop[ulHopCount].ulHopRcvd = hop[ulHopCount].ulNumRcvd;
  302. for (h=ulHopCount-1; h>0; h--)
  303. hop[h].ulHopRcvd = MAX(hop[h].ulNumRcvd, hop[h+1].ulHopRcvd);
  304. hop[0].ulHopRcvd = g_ulNumQueries;
  305. }
  306. VOID
  307. PrintResults(
  308. ULONG ulHopCount
  309. )
  310. {
  311. ULONG h;
  312. int sent, rcvd, lost, linklost, nodelost;
  313. // Now output results
  314. NlsPutMsg(STDOUT, PATHPING_STAT_HEADER, GetLastError());
  315. // printf(" Source to Here This Node/Link\n");
  316. // printf("Hop RTT Lost/Sent = Pct Lost/Sent = Pct Address\n");
  317. // printf(" 0 ");
  318. print_addr((LPSOCKADDR)&g_ssMyAddr, g_slMyAddrLen, g_bDoReverseLookup);
  319. NlsPutMsg(STDOUT, PATHPING_CR);
  320. // printf("\n");
  321. for (h=1; h<=ulHopCount; h++) {
  322. sent = g_ulNumQueries;
  323. rcvd = hop[h].ulNumRcvd;
  324. lost = sent - rcvd;
  325. linklost = hop[h-1].ulHopRcvd - hop[h].ulHopRcvd;
  326. nodelost = hop[h].ulHopRcvd - hop[h].ulNumRcvd;
  327. // Display previous link stats
  328. // printf( " %4d/%4d =%3.0f%% |\n",
  329. // linklost, sent, 100.0*linklost/sent);
  330. NlsPutMsg(STDOUT, PATHPING_STAT_LINK,
  331. linklost, sent, 100*linklost/sent);
  332. if (rcvd)
  333. NlsPutMsg(STDOUT, PATHPING_HOP_RTT, h, hop[h].ulRTTtotal/rcvd);
  334. else
  335. NlsPutMsg(STDOUT, PATHPING_HOP_NO_RTT, h);
  336. // printf("%3d ", h);
  337. // if (!rcvd)
  338. // printf(" --- ");
  339. #if 0
  340. // else if (hop[h].ulRTTtotal/rcvd == 0)
  341. // printf(" <10ms ");
  342. #endif
  343. // else
  344. // printf("%4dms ", hop[h].ulRTTtotal/rcvd);
  345. // printf("%4d/%4d =%3.0f%% ", lost, sent, 100.0*lost/sent);
  346. // printf("%4d/%4d =%3.0f%% ", nodelost, sent, 100.0*nodelost/sent);
  347. NlsPutMsg(STDOUT, PATHPING_STAT_LOSS,
  348. lost, sent, 100*lost/sent);
  349. NlsPutMsg(STDOUT, PATHPING_STAT_LOSS,
  350. nodelost, sent, 100*nodelost/sent);
  351. if (!hop[h].saAddr.sa_family) {
  352. hop[h].saAddr.sa_family = g_ssMyAddr.ss_family;
  353. }
  354. print_addr(&hop[h].saAddr, g_slMyAddrLen, g_bDoReverseLookup);
  355. NlsPutMsg(STDOUT, PATHPING_CR);
  356. // printf("\n");
  357. }
  358. }
  359. BOOLEAN
  360. SetFamily(DWORD *Family, DWORD Value, char *arg)
  361. {
  362. if ((*Family != AF_UNSPEC) && (*Family != Value)) {
  363. NlsPutMsg(STDOUT, PATHPING_FAMILY, arg,
  364. (Value==AF_INET)? "IPv4" : "IPv6");
  365. return FALSE;
  366. }
  367. *Family = Value;
  368. return TRUE;
  369. }
  370. int __cdecl
  371. main(int argc, char **argv)
  372. {
  373. SOCKADDR_STORAGE address;
  374. socklen_t addressLen;
  375. DWORD numberOfReplies;
  376. DWORD status;
  377. PICMP_ECHO_REPLY reply4;
  378. PICMPV6_ECHO_REPLY reply6;
  379. char hostname[NI_MAXHOST], literal[INET6_ADDRSTRLEN];
  380. char *arg;
  381. int i;
  382. ULONG maximumHops = DEFAULT_MAXIMUM_HOPS;
  383. IP_OPTION_INFORMATION options;
  384. unsigned char optionsData[MAX_OPT_SIZE];
  385. unsigned char *optionPtr;
  386. BYTE currentIndex;
  387. IPAddr tempAddr;
  388. BYTE j;
  389. BYTE SRIndex = 0;
  390. BOOLEAN foundAddress = FALSE;
  391. BOOLEAN haveReply;
  392. int numRetries = DEFAULT_MAX_RETRIES;
  393. DWORD Family = AF_UNSPEC;
  394. if (WSAStartup( 0x0101, &WsaData)) {
  395. NlsPutMsg(STDOUT, PATHPING_WSASTARTUP_FAILED, GetLastError());
  396. return(1);
  397. }
  398. ZeroMemory(&address, sizeof(address));
  399. addressLen = sizeof(address);
  400. options.Ttl = 1;
  401. options.Tos = DEFAULT_TOS;
  402. options.Flags = DEFAULT_FLAGS;
  403. options.OptionsSize = 0;
  404. options.OptionsData = optionsData;
  405. if (argc < 2) {
  406. NlsPutMsg( STDOUT, PATHPING_USAGE, argv[0] );
  407. goto error_exit;
  408. }
  409. //
  410. // process command line
  411. //
  412. for (i=1; i < argc; i++) {
  413. arg = argv[i];
  414. if ((arg[0] == '-') || (arg[0] == '/')) {
  415. switch(arg[1]) {
  416. case '?':
  417. NlsPutMsg(STDOUT, PATHPING_USAGE, argv[0]);
  418. goto error_exit;
  419. case '4':
  420. if (!SetFamily(&Family, AF_INET, arg)) {
  421. goto error_exit;
  422. }
  423. break;
  424. case '6':
  425. if (!SetFamily(&Family, AF_INET6, arg)) {
  426. goto error_exit;
  427. }
  428. break;
  429. case 'g': // Loose source routing
  430. // Only implemented for IPv4 so far
  431. if (!SetFamily(&Family, AF_INET, arg)) {
  432. goto error_exit;
  433. }
  434. currentIndex = options.OptionsSize;
  435. if ((currentIndex + 7) > MAX_OPT_SIZE) {
  436. NlsPutMsg(STDOUT, PATHPING_TOO_MANY_OPTIONS);
  437. goto error_exit;
  438. }
  439. optionPtr = options.OptionsData;
  440. optionPtr[currentIndex] = (unsigned char) IP_OPT_LSRR;
  441. optionPtr[currentIndex+1] = 3;
  442. optionPtr[currentIndex + 2] = 4; // Set initial pointer value
  443. options.OptionsSize += 3;
  444. while ( (i < (argc - 2)) && (*argv[i+1] != '-')) {
  445. if ((currentIndex + 7) > MAX_OPT_SIZE) {
  446. NlsPutMsg(STDOUT, PATHPING_TOO_MANY_OPTIONS);
  447. goto error_exit;
  448. }
  449. arg = argv[++i];
  450. tempAddr = inet_addr(arg);
  451. if (tempAddr == INADDR_NONE) {
  452. NlsPutMsg(
  453. STDOUT,
  454. PATHPING_BAD_ROUTE_ADDRESS,
  455. arg
  456. );
  457. // printf("Bad route specified for loose source route");
  458. goto error_exit;
  459. }
  460. j = optionPtr[currentIndex+1];
  461. *(ULONG UNALIGNED *)&optionPtr[j+currentIndex] = tempAddr;
  462. optionPtr[currentIndex+1] += 4;
  463. options.OptionsSize += 4;
  464. }
  465. SRIndex = optionPtr[currentIndex+1] + currentIndex;
  466. optionPtr[currentIndex+1] += 4; // Save space for dest. addr
  467. options.OptionsSize += 4;
  468. break;
  469. case 'h':
  470. if (!param(&maximumHops, argv, argc, i, 1, 255)) {
  471. goto error_exit;
  472. }
  473. i++;
  474. break;
  475. case 'i':
  476. {
  477. char tmphostname[NI_MAXHOST];
  478. arg = argv[++i];
  479. if (ResolveTarget(Family,
  480. arg,
  481. &g_ssMyAddr,
  482. &g_slMyAddrLen,
  483. tmphostname,
  484. sizeof(tmphostname),
  485. FALSE)) {
  486. g_bSetAddr = TRUE;
  487. }
  488. }
  489. break;
  490. case 'n':
  491. g_bDoReverseLookup = FALSE;
  492. break;
  493. case 'p':
  494. if (!param(&g_ulInterval, argv, argc, i, 1, 0xffffffff)) {
  495. goto error_exit;
  496. }
  497. i++;
  498. break;
  499. case 'q':
  500. if (!param(&g_ulNumQueries, argv, argc, i, 1, 255)) {
  501. goto error_exit;
  502. }
  503. i++;
  504. break;
  505. case 'w':
  506. if (!param(&g_ulTimeout, argv, argc, i, 1, 0xffffffff)) {
  507. goto error_exit;
  508. }
  509. i++;
  510. break;
  511. default:
  512. NlsPutMsg(STDOUT, PATHPING_INVALID_SWITCH, argv[i]);
  513. NlsPutMsg(STDOUT, PATHPING_USAGE);
  514. goto error_exit;
  515. break;
  516. }
  517. } else {
  518. foundAddress = TRUE;
  519. if ( !ResolveTarget(Family,
  520. argv[i],
  521. &address,
  522. &addressLen,
  523. hostname,
  524. sizeof(hostname),
  525. g_bDoReverseLookup) )
  526. {
  527. NlsPutMsg( STDOUT, PATHPING_MESSAGE_1, argv[i] );
  528. // printf( "Unable to resolve target name %s.\n", argv[i]);
  529. goto error_exit;
  530. }
  531. }
  532. }
  533. if (!foundAddress) {
  534. NlsPutMsg(STDOUT, PATHPING_NO_ADDRESS);
  535. NlsPutMsg(STDOUT, PATHPING_USAGE);
  536. goto error_exit;
  537. }
  538. if (SRIndex != 0) {
  539. *(ULONG UNALIGNED *)&options.OptionsData[SRIndex] = ((LPSOCKADDR_IN)&address)->sin_addr.s_addr;
  540. }
  541. Family = address.ss_family;
  542. if (Family == AF_INET) {
  543. g_hIcmp = IcmpCreateFile();
  544. } else {
  545. g_hIcmp = Icmp6CreateFile();
  546. }
  547. if (g_hIcmp == INVALID_HANDLE_VALUE) {
  548. status = GetLastError();
  549. NlsPutMsg( STDOUT, PATHPING_MESSAGE_2, status );
  550. // printf( "Unable to contact IP driver. Error code %d.\n", status);
  551. goto error_exit;
  552. }
  553. getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
  554. NULL, 0, NI_NUMERICHOST);
  555. if (hostname[0]) {
  556. NlsPutMsg(
  557. STDOUT,
  558. PATHPING_HEADER1,
  559. hostname,
  560. literal,
  561. maximumHops
  562. );
  563. }
  564. else {
  565. NlsPutMsg(
  566. STDOUT,
  567. PATHPING_HEADER2,
  568. literal,
  569. maximumHops
  570. );
  571. }
  572. // Get local IP address
  573. if (!g_bSetAddr)
  574. {
  575. SOCKET s = socket(address.ss_family, SOCK_RAW, 0);
  576. DWORD BytesReturned;
  577. WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY,
  578. &address, sizeof address,
  579. &g_ssMyAddr, sizeof g_ssMyAddr,
  580. &BytesReturned, NULL, NULL);
  581. g_slMyAddrLen = BytesReturned;
  582. closesocket(s);
  583. NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, 0);
  584. print_addr((LPSOCKADDR)&g_ssMyAddr, g_slMyAddrLen,
  585. g_bDoReverseLookup);
  586. NlsPutMsg(STDOUT, PATHPING_CR);
  587. }
  588. // First we need to find out the path, so we
  589. //
  590. while((options.Ttl <= maximumHops) && (options.Ttl != 0)) {
  591. NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, (UINT)options.Ttl );
  592. // printf("[%3lu] ", (UINT)SendOpts.Ttl);
  593. haveReply = FALSE;
  594. for (i=0; i<numRetries; i++) {
  595. if (Family == AF_INET) {
  596. numberOfReplies = IcmpSendEcho2( g_hIcmp,
  597. 0,
  598. NULL,
  599. NULL,
  600. ((LPSOCKADDR_IN)&address)->sin_addr.s_addr,
  601. SendBuffer,
  602. DEFAULT_SEND_SIZE,
  603. &options,
  604. RcvBuffer,
  605. DEFAULT_RECEIVE_SIZE,
  606. g_ulTimeout );
  607. if (numberOfReplies == 0) {
  608. status = GetLastError();
  609. reply4 = NULL;
  610. } else {
  611. reply4 = (PICMP_ECHO_REPLY) RcvBuffer;
  612. status = reply4->Status;
  613. }
  614. if (status == IP_SUCCESS) {
  615. print_ip_addr(
  616. reply4->Address,
  617. g_bDoReverseLookup
  618. );
  619. NlsPutMsg(STDOUT, PATHPING_CR);
  620. ZeroMemory(&hop[options.Ttl], sizeof(HOP));
  621. hop[options.Ttl].sinAddr.sin_family = AF_INET;
  622. hop[options.Ttl].sinAddr.sin_addr.s_addr = reply4->Address;
  623. goto loop_end;
  624. }
  625. if (status == IP_TTL_EXPIRED_TRANSIT) {
  626. ZeroMemory(&hop[options.Ttl], sizeof(HOP));
  627. hop[options.Ttl].sinAddr.sin_family = AF_INET;
  628. hop[options.Ttl].sinAddr.sin_addr.s_addr = reply4->Address;
  629. break;
  630. }
  631. if (status == IP_REQ_TIMED_OUT) {
  632. NlsPutMsg(STDOUT, PATHPING_NO_REPLY_TIME);
  633. // printf(".");
  634. continue;
  635. }
  636. if (status < IP_STATUS_BASE) {
  637. NlsPutMsg( STDOUT, PATHPING_MESSAGE_7, status );
  638. // printf("Transmit error: code %lu\n", status);
  639. continue;
  640. }
  641. //
  642. // Fatal error.
  643. //
  644. if (reply4 != NULL) {
  645. print_ip_addr(
  646. reply4->Address,
  647. g_bDoReverseLookup
  648. );
  649. NlsPutMsg( STDOUT, PATHPING_MESSAGE_6 );
  650. // printf(" reports: ");
  651. }
  652. } else {
  653. numberOfReplies = Icmp6SendEcho2(g_hIcmp,
  654. 0,
  655. NULL,
  656. NULL,
  657. (LPSOCKADDR_IN6)&g_ssMyAddr,
  658. (LPSOCKADDR_IN6)&address,
  659. SendBuffer,
  660. DEFAULT_SEND_SIZE,
  661. &options,
  662. RcvBuffer,
  663. DEFAULT_RECEIVE_SIZE,
  664. g_ulTimeout );
  665. if (numberOfReplies == 0) {
  666. status = GetLastError();
  667. reply6 = NULL;
  668. } else {
  669. reply6 = (PICMPV6_ECHO_REPLY) RcvBuffer;
  670. status = reply6->Status;
  671. }
  672. if (status == IP_SUCCESS) {
  673. print_ipv6_addr(
  674. (USHORT*)reply6->Address.sin6_addr,
  675. g_bDoReverseLookup
  676. );
  677. NlsPutMsg(STDOUT, PATHPING_CR);
  678. ZeroMemory(&hop[options.Ttl], sizeof(HOP));
  679. hop[options.Ttl].sin6Addr.sin6_family = AF_INET6;
  680. memcpy(&hop[options.Ttl].sin6Addr.sin6_addr.s6_words,
  681. reply6->Address.sin6_addr,
  682. sizeof(reply6->Address.sin6_addr));
  683. hop[options.Ttl].sin6Addr.sin6_scope_id = reply6->Address.sin6_scope_id;
  684. goto loop_end;
  685. }
  686. if (status == IP_TTL_EXPIRED_TRANSIT) {
  687. ZeroMemory(&hop[options.Ttl], sizeof(HOP));
  688. hop[options.Ttl].sin6Addr.sin6_family = AF_INET6;
  689. memcpy(&hop[options.Ttl].sin6Addr.sin6_addr.s6_words,
  690. reply6->Address.sin6_addr,
  691. sizeof(reply6->Address.sin6_addr));
  692. hop[options.Ttl].sin6Addr.sin6_scope_id = reply6->Address.sin6_scope_id;
  693. break;
  694. }
  695. if (status == IP_REQ_TIMED_OUT) {
  696. NlsPutMsg(STDOUT, PATHPING_NO_REPLY_TIME);
  697. // printf(".");
  698. continue;
  699. }
  700. if (status < IP_STATUS_BASE) {
  701. NlsPutMsg( STDOUT, PATHPING_MESSAGE_7, status );
  702. // printf("Transmit error: code %lu\n", status);
  703. continue;
  704. }
  705. //
  706. // Fatal error.
  707. //
  708. if (reply6 != NULL) {
  709. print_ipv6_addr(
  710. (USHORT*)reply6->Address.sin6_addr,
  711. g_bDoReverseLookup
  712. );
  713. NlsPutMsg( STDOUT, PATHPING_MESSAGE_6 );
  714. // printf(" reports: ");
  715. }
  716. }
  717. for (i = 0;
  718. ( ErrorTable[i].Error != status &&
  719. ErrorTable[i].Error != IP_GENERAL_FAILURE
  720. );
  721. i++
  722. );
  723. NlsPutMsg( STDOUT, ErrorTable[i].ErrorNlsID );
  724. // printf("%s.\n", ErrorTable[i].ErrorString);
  725. goto loop_end;
  726. }
  727. if (i==numRetries)
  728. break;
  729. print_addr(&hop[options.Ttl].saAddr,
  730. g_slMyAddrLen,
  731. g_bDoReverseLookup );
  732. NlsPutMsg(STDOUT, PATHPING_CR);
  733. options.Ttl++;
  734. }
  735. loop_end:
  736. NlsPutMsg(STDOUT, PATHPING_COMPUTING, options.Ttl * g_ulInterval * g_ulNumQueries / 1000);
  737. // Okay, now that we have the path, we want to go back and
  738. // compute statistics over numQueries queries sent every intvl
  739. // seconds.
  740. ComputeStatistics(&options);
  741. PrintResults((ULONG)options.Ttl);
  742. NlsPutMsg( STDOUT, PATHPING_MESSAGE_8 );
  743. // printf("\nTrace complete.\n");
  744. IcmpCloseHandle(g_hIcmp);
  745. WSACleanup();
  746. return(0);
  747. error_exit:
  748. WSACleanup();
  749. return(1);
  750. }