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.

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