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.

875 lines
27 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. tracert.c
  5. Abstract:
  6. TraceRoute utility for TCP/IP.
  7. Author:
  8. Numerous TCP/IP folks.
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. Notes:
  13. --*/
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <ctype.h>
  17. #include <time.h>
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <snmp.h>
  22. #include <winsock2.h>
  23. #include <ws2tcpip.h>
  24. #include <ntddip6.h>
  25. #include <winnlsp.h>
  26. #include <iphlpapi.h>
  27. #include "llinfo.h"
  28. #include "tcpcmd.h"
  29. #include "ipexport.h"
  30. #include "icmpapi.h"
  31. #include "nlstxt.h"
  32. #define DEFAULT_MAXIMUM_HOPS 30
  33. #define DEFAULT_TOS 0
  34. #define DEFAULT_FLAGS 0
  35. #define DEFAULT_SEND_SIZE 64
  36. #define DEFAULT_RECEIVE_SIZE ( (sizeof(ICMP_ECHO_REPLY) + \
  37. DEFAULT_SEND_SIZE + \
  38. MAX_OPT_SIZE))
  39. #define DEFAULT_TOS 0
  40. #define DEFAULT_TIMEOUT 4000L
  41. #define MIN_INTERVAL 1000L
  42. #define STDOUT 1
  43. char SendBuffer[DEFAULT_SEND_SIZE];
  44. char RcvBuffer[DEFAULT_RECEIVE_SIZE];
  45. WSADATA WsaData;
  46. struct IPErrorTable {
  47. IP_STATUS Error; // The IP Error
  48. DWORD ErrorNlsID; // The corresponding NLS string ID.
  49. } ErrorTable[] =
  50. {
  51. { IP_BUF_TOO_SMALL, TRACERT_BUF_TOO_SMALL },
  52. { IP_DEST_NET_UNREACHABLE, TRACERT_DEST_NET_UNREACHABLE },
  53. { IP_DEST_HOST_UNREACHABLE, TRACERT_DEST_HOST_UNREACHABLE },
  54. { IP_DEST_PROT_UNREACHABLE, TRACERT_DEST_PROT_UNREACHABLE },
  55. { IP_DEST_PORT_UNREACHABLE, TRACERT_DEST_PORT_UNREACHABLE },
  56. { IP_NO_RESOURCES, TRACERT_NO_RESOURCES },
  57. { IP_BAD_OPTION, TRACERT_BAD_OPTION },
  58. { IP_HW_ERROR, TRACERT_HW_ERROR },
  59. { IP_PACKET_TOO_BIG, TRACERT_PACKET_TOO_BIG },
  60. { IP_REQ_TIMED_OUT, TRACERT_REQ_TIMED_OUT },
  61. { IP_BAD_REQ, TRACERT_BAD_REQ },
  62. { IP_BAD_ROUTE, TRACERT_BAD_ROUTE },
  63. { IP_TTL_EXPIRED_TRANSIT, TRACERT_TTL_EXPIRED_TRANSIT },
  64. { IP_TTL_EXPIRED_REASSEM, TRACERT_TTL_EXPIRED_REASSEM },
  65. { IP_PARAM_PROBLEM, TRACERT_PARAM_PROBLEM },
  66. { IP_SOURCE_QUENCH, TRACERT_SOURCE_QUENCH },
  67. { IP_OPTION_TOO_BIG, TRACERT_OPTION_TOO_BIG },
  68. { IP_BAD_DESTINATION, TRACERT_BAD_DESTINATION },
  69. { IP_NEGOTIATING_IPSEC, TRACERT_NEGOTIATING_IPSEC },
  70. { IP_GENERAL_FAILURE, TRACERT_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. unsigned long
  110. str2ip(char *addr)
  111. {
  112. char *endptr;
  113. int i; // Counter variable.
  114. unsigned long curaddr = 0;
  115. unsigned long temp;
  116. for (i = 0; i < 4; i++) {
  117. temp = strtoul(addr, &endptr, 10);
  118. if (temp > 255)
  119. return 0L;
  120. if (endptr[0] != '.')
  121. if (i != 3)
  122. return 0L;
  123. else
  124. if (endptr[0] != '\0' && endptr[0] != ' ')
  125. return 0L;
  126. addr = endptr+1;
  127. curaddr = (curaddr << 8) + temp;
  128. }
  129. return net_long(curaddr);
  130. }
  131. void
  132. print_addr(SOCKADDR *sa, socklen_t salen, BOOLEAN DoReverseLookup)
  133. {
  134. char hostname[NI_MAXHOST];
  135. int i;
  136. BOOLEAN didReverse = FALSE;
  137. if (DoReverseLookup) {
  138. i = getnameinfo(sa, salen, hostname, sizeof(hostname),
  139. NULL, 0, NI_NAMEREQD);
  140. if (i == NO_ERROR) {
  141. didReverse = TRUE;
  142. NlsPutMsg(STDOUT, TRACERT_TARGET_NAME, hostname);
  143. }
  144. }
  145. i = getnameinfo(sa, salen, hostname, sizeof(hostname),
  146. NULL, 0, NI_NUMERICHOST);
  147. if (i != NO_ERROR) {
  148. // This should never happen unless there is a memory problem,
  149. // in which case the message associated with TRACERT_NO_RESOURCES
  150. // is reasonable.
  151. NlsPutMsg(STDOUT, TRACERT_NO_RESOURCES);
  152. exit (1);
  153. }
  154. if (didReverse) {
  155. NlsPutMsg( STDOUT, TRACERT_BRKT_IP_ADDRESS, hostname );
  156. } else {
  157. NlsPutMsg( STDOUT, TRACERT_IP_ADDRESS, hostname );
  158. }
  159. }
  160. void
  161. print_ip_addr(IPAddr ipv4Addr, BOOLEAN DoReverseLookup)
  162. {
  163. SOCKADDR_IN sin;
  164. memset(&sin, 0, sizeof(sin));
  165. sin.sin_family = AF_INET;
  166. sin.sin_addr.s_addr = ipv4Addr;
  167. print_addr((LPSOCKADDR)&sin, sizeof(sin), DoReverseLookup);
  168. }
  169. void
  170. print_ipv6_addr(IN6_ADDR *ipv6Addr, BOOLEAN DoReverseLookup)
  171. {
  172. SOCKADDR_IN6 sin;
  173. memset(&sin, 0, sizeof(sin));
  174. sin.sin6_family = AF_INET6;
  175. memcpy(&sin.sin6_addr, ipv6Addr, sizeof(sin.sin6_addr));
  176. print_addr((LPSOCKADDR)&sin, sizeof(sin), DoReverseLookup);
  177. }
  178. void
  179. print_time(ulong Time)
  180. {
  181. if (Time) {
  182. NlsPutMsg( STDOUT, TRACERT_TIME, Time );
  183. }
  184. else {
  185. NlsPutMsg( STDOUT, TRACERT_TIME_10MS );
  186. }
  187. }
  188. BOOLEAN
  189. param(
  190. ulong *parameter,
  191. char **argv,
  192. int argc,
  193. int current,
  194. ulong min,
  195. ulong max
  196. )
  197. {
  198. ulong temp;
  199. char *dummy;
  200. if (current == (argc - 1) ) {
  201. NlsPutMsg( STDOUT, TRACERT_NO_OPTION_VALUE, argv[current] );
  202. return(FALSE);
  203. }
  204. temp = strtoul(argv[current+1], &dummy, 0);
  205. if (temp < min || temp > max) {
  206. NlsPutMsg( STDOUT, TRACERT_BAD_OPTION_VALUE, argv[current] );
  207. return(FALSE);
  208. }
  209. *parameter = temp;
  210. return(TRUE);
  211. }
  212. BOOLEAN
  213. ResolveTarget(
  214. int Family,
  215. char *TargetString,
  216. SOCKADDR *TargetAddress,
  217. socklen_t *TargetAddressLen,
  218. char *TargetName,
  219. int TargetNameLen,
  220. BOOLEAN DoReverseLookup
  221. )
  222. {
  223. int i;
  224. struct addrinfo hints, *ai;
  225. TargetName[0] = '\0';
  226. memset(&hints, 0, sizeof(hints));
  227. hints.ai_family = Family;
  228. hints.ai_flags = AI_NUMERICHOST;
  229. i = getaddrinfo(TargetString, NULL, &hints, &ai);
  230. if (i == NO_ERROR) {
  231. *TargetAddressLen = (socklen_t)ai->ai_addrlen;
  232. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  233. if (DoReverseLookup) {
  234. getnameinfo(ai->ai_addr, (socklen_t)ai->ai_addrlen,
  235. TargetName, TargetNameLen,
  236. NULL, 0, NI_NAMEREQD);
  237. }
  238. freeaddrinfo(ai);
  239. return(TRUE);
  240. } else {
  241. hints.ai_flags = AI_CANONNAME;
  242. if (getaddrinfo(TargetString, NULL, &hints, &ai) == 0) {
  243. *TargetAddressLen = (socklen_t)ai->ai_addrlen;
  244. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  245. strcpy(TargetName,
  246. (ai->ai_canonname)? ai->ai_canonname : TargetString);
  247. freeaddrinfo(ai);
  248. return(TRUE);
  249. }
  250. }
  251. return(FALSE);
  252. } // ResolveTarget
  253. int
  254. GetSource(int family, char *astr, struct sockaddr *address)
  255. {
  256. struct addrinfo hints;
  257. struct addrinfo *result;
  258. memset(&hints, 0, sizeof hints);
  259. hints.ai_flags = AI_PASSIVE;
  260. hints.ai_family = family;
  261. if (getaddrinfo(astr, NULL, &hints, &result) != 0)
  262. return FALSE;
  263. RtlCopyMemory(address, result->ai_addr, result->ai_addrlen);
  264. return TRUE;
  265. }
  266. BOOLEAN
  267. SetFamily(DWORD *Family, DWORD Value, char *arg)
  268. {
  269. if ((*Family != AF_UNSPEC) && (*Family != Value)) {
  270. NlsPutMsg(STDOUT, TRACERT_FAMILY, arg,
  271. (Value==AF_INET)? "IPv4" : "IPv6");
  272. return FALSE;
  273. }
  274. *Family = Value;
  275. return TRUE;
  276. }
  277. int __cdecl
  278. main(int argc, char **argv)
  279. {
  280. SOCKADDR_STORAGE address, sourceAddress;
  281. socklen_t addressLen;
  282. IPAddr reply4Address = INADDR_ANY;
  283. IN6_ADDR reply6Address;
  284. DWORD numberOfReplies;
  285. HANDLE IcmpHandle;
  286. DWORD status;
  287. PICMP_ECHO_REPLY reply4;
  288. PICMPV6_ECHO_REPLY reply6;
  289. char hostname[NI_MAXHOST], literal[INET6_ADDRSTRLEN];
  290. char *arg;
  291. int i;
  292. ulong maximumHops = DEFAULT_MAXIMUM_HOPS;
  293. BOOLEAN doReverseLookup = TRUE;
  294. IP_OPTION_INFORMATION options;
  295. uchar optionsData[MAX_OPT_SIZE];
  296. uchar *optionPtr;
  297. uchar currentIndex;
  298. IPAddr tempAddr;
  299. uchar j;
  300. uchar SRIndex = 0;
  301. ulong timeout = DEFAULT_TIMEOUT;
  302. BOOLEAN foundAddress = FALSE;
  303. BOOLEAN haveReply;
  304. DWORD Family = AF_UNSPEC;
  305. //
  306. // This will ensure the correct language message is displayed when
  307. // NlsPutMsg is called.
  308. //
  309. SetThreadUILanguage(0);
  310. if (WSAStartup(MAKEWORD(2, 0), &WsaData)) {
  311. NlsPutMsg(STDOUT, TRACERT_WSASTARTUP_FAILED, GetLastError());
  312. return(1);
  313. }
  314. memset(&sourceAddress, 0, sizeof sourceAddress);
  315. memset(&address, 0, sizeof address);
  316. addressLen = sizeof(address);
  317. options.Ttl = 1;
  318. options.Tos = DEFAULT_TOS;
  319. options.Flags = DEFAULT_FLAGS;
  320. options.OptionsSize = 0;
  321. options.OptionsData = optionsData;
  322. if (argc < 2) {
  323. NlsPutMsg( STDOUT, TRACERT_USAGE, argv[0] );
  324. goto error_exit;
  325. }
  326. //
  327. // process command line
  328. //
  329. for (i=1; i < argc; i++) {
  330. arg = argv[i];
  331. if ((arg[0] == '-') || (arg[0] == '/')) {
  332. switch(arg[1]) {
  333. case '?':
  334. NlsPutMsg(STDOUT, TRACERT_USAGE, argv[0]);
  335. goto error_exit;
  336. case 'd':
  337. doReverseLookup = FALSE;
  338. break;
  339. case 'h':
  340. if (!param(&maximumHops, argv, argc, i++, 1, 255)) {
  341. goto error_exit;
  342. }
  343. break;
  344. case 'j': // Loose source routing
  345. // Only implemented for IPv4 so far
  346. if (!SetFamily(&Family, AF_INET, arg)) {
  347. goto error_exit;
  348. }
  349. currentIndex = options.OptionsSize;
  350. if ((currentIndex + 7) > MAX_OPT_SIZE) {
  351. NlsPutMsg(STDOUT, TRACERT_TOO_MANY_OPTIONS);
  352. goto error_exit;
  353. }
  354. optionPtr = options.OptionsData;
  355. optionPtr[currentIndex] = (uchar) IP_OPT_LSRR;
  356. optionPtr[currentIndex+1] = 3;
  357. optionPtr[currentIndex+2] = 4; // Set initial pointer value
  358. options.OptionsSize += 3;
  359. while ( (i < (argc - 2)) && (*argv[i+1] != '-')) {
  360. if ((currentIndex + 7) > MAX_OPT_SIZE) {
  361. NlsPutMsg(STDOUT, TRACERT_TOO_MANY_OPTIONS);
  362. goto error_exit;
  363. }
  364. arg = argv[++i];
  365. tempAddr = inet_addr(arg);
  366. if (tempAddr == INADDR_NONE) {
  367. NlsPutMsg(
  368. STDOUT,
  369. TRACERT_BAD_ROUTE_ADDRESS,
  370. arg
  371. );
  372. goto error_exit;
  373. }
  374. j = optionPtr[currentIndex+1];
  375. *(ulong UNALIGNED *)&optionPtr[j+currentIndex] = tempAddr;
  376. optionPtr[currentIndex+1] += 4;
  377. options.OptionsSize += 4;
  378. }
  379. SRIndex = optionPtr[currentIndex+1] + currentIndex;
  380. optionPtr[currentIndex+1] += 4; // Save space for dest. addr
  381. options.OptionsSize += 4;
  382. break;
  383. case 'w':
  384. if (!param(&timeout, argv, argc, i++, 1, 0xffffffff)) {
  385. goto error_exit;
  386. }
  387. break;
  388. case 'R':
  389. // Only implemented for IPv6 so far
  390. if (!SetFamily(&Family, AF_INET6, arg)) {
  391. goto error_exit;
  392. }
  393. options.Flags |= ICMPV6_ECHO_REQUEST_FLAG_REVERSE;
  394. break;
  395. case 'S':
  396. // Only implemented for IPv6 so far
  397. if (!SetFamily(&Family, AF_INET6, arg)) {
  398. goto error_exit;
  399. }
  400. if (!GetSource(Family, argv[++i], (LPSOCKADDR)&sourceAddress)) {
  401. NlsPutMsg(STDOUT, TRACERT_BAD_ADDRESS, argv[i]);
  402. goto error_exit;
  403. }
  404. break;
  405. case '4':
  406. if (!SetFamily(&Family, AF_INET, arg)) {
  407. goto error_exit;
  408. }
  409. break;
  410. case '6':
  411. if (!SetFamily(&Family, AF_INET6, arg)) {
  412. goto error_exit;
  413. }
  414. break;
  415. default:
  416. NlsPutMsg(STDOUT, TRACERT_INVALID_SWITCH, argv[i]);
  417. NlsPutMsg(STDOUT, TRACERT_USAGE);
  418. goto error_exit;
  419. break;
  420. }
  421. }
  422. else {
  423. foundAddress = TRUE;
  424. if (!ResolveTarget(Family, argv[i], (LPSOCKADDR)&address,
  425. &addressLen, hostname, sizeof(hostname),
  426. doReverseLookup)) {
  427. NlsPutMsg( STDOUT, TRACERT_MESSAGE_1, argv[i] );
  428. goto error_exit;
  429. }
  430. }
  431. }
  432. if (!foundAddress) {
  433. NlsPutMsg(STDOUT, TRACERT_NO_ADDRESS);
  434. NlsPutMsg(STDOUT, TRACERT_USAGE);
  435. goto error_exit;
  436. }
  437. Family = address.ss_family;
  438. if (Family == AF_INET) {
  439. if (SRIndex != 0) {
  440. *(ulong UNALIGNED *)&options.OptionsData[SRIndex] = ((LPSOCKADDR_IN)&address)->sin_addr.s_addr;
  441. }
  442. IcmpHandle = IcmpCreateFile();
  443. } else {
  444. if (sourceAddress.ss_family == AF_UNSPEC) {
  445. SOCKET s;
  446. DWORD BytesReturned;
  447. //
  448. // A source address was not specified.
  449. // Get the preferred source address for this destination.
  450. //
  451. // If you want each individual echo request
  452. // to select a source address, use "-S ::".
  453. //
  454. s = socket(address.ss_family, 0, 0);
  455. if (s == INVALID_SOCKET) {
  456. NlsPutMsg(STDOUT, TRACERT_SOCKET_FAILED, WSAGetLastError());
  457. exit(1);
  458. }
  459. (void) WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY,
  460. &address, sizeof address,
  461. &sourceAddress, sizeof sourceAddress,
  462. &BytesReturned, NULL, NULL);
  463. closesocket(s);
  464. }
  465. IcmpHandle = Icmp6CreateFile();
  466. }
  467. if (IcmpHandle == INVALID_HANDLE_VALUE) {
  468. status = GetLastError();
  469. NlsPutMsg( STDOUT, TRACERT_MESSAGE_2, status );
  470. goto error_exit;
  471. }
  472. getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
  473. NULL, 0, NI_NUMERICHOST);
  474. if (hostname[0]) {
  475. NlsPutMsg(
  476. STDOUT,
  477. TRACERT_HEADER1,
  478. hostname,
  479. literal,
  480. maximumHops
  481. );
  482. }
  483. else {
  484. NlsPutMsg(
  485. STDOUT,
  486. TRACERT_HEADER2,
  487. literal,
  488. maximumHops
  489. );
  490. }
  491. while((options.Ttl <= maximumHops) && (options.Ttl != 0)) {
  492. NlsPutMsg( STDOUT, TRACERT_MESSAGE_4, (uint)options.Ttl );
  493. haveReply = FALSE;
  494. for (i=0; i<3; i++) {
  495. BOOLEAN ErrorNotHandled = FALSE;
  496. if (Family == AF_INET) {
  497. numberOfReplies = IcmpSendEcho2(
  498. IcmpHandle,
  499. 0,
  500. NULL,
  501. NULL,
  502. ((LPSOCKADDR_IN)&address)->sin_addr.s_addr,
  503. SendBuffer,
  504. DEFAULT_SEND_SIZE,
  505. &options,
  506. RcvBuffer,
  507. DEFAULT_RECEIVE_SIZE,
  508. timeout
  509. );
  510. if (numberOfReplies == 0) {
  511. // We did not get any replies. This is possibly a timeout,
  512. // or an internal error to IP.
  513. //
  514. status = GetLastError();
  515. reply4 = NULL;
  516. if (status == IP_REQ_TIMED_OUT) {
  517. NlsPutMsg(STDOUT, TRACERT_NO_REPLY_TIME);
  518. if (i == 2) {
  519. if (haveReply) {
  520. print_ip_addr(
  521. reply4Address,
  522. doReverseLookup
  523. );
  524. NlsPutMsg(STDOUT, TRACERT_CR);
  525. }
  526. else {
  527. NlsPutMsg( STDOUT, TRACERT_REQ_TIMED_OUT);
  528. }
  529. }
  530. }
  531. else {
  532. ErrorNotHandled = TRUE;
  533. }
  534. }
  535. else {
  536. // We got a reply. It's either for the final destination
  537. // (IP_SUCCESS), or because the TTL expired at a node along
  538. // the way, or we got an unexpected error response.
  539. //
  540. reply4 = (PICMP_ECHO_REPLY) RcvBuffer;
  541. status = reply4->Status;
  542. if (status == IP_SUCCESS) {
  543. print_time(reply4->RoundTripTime);
  544. if (i == 2) {
  545. print_ip_addr(
  546. reply4->Address,
  547. doReverseLookup
  548. );
  549. NlsPutMsg(STDOUT, TRACERT_CR);
  550. goto loop_end;
  551. }
  552. else {
  553. haveReply = TRUE;
  554. reply4Address = reply4->Address;
  555. }
  556. }
  557. else if (status == IP_TTL_EXPIRED_TRANSIT) {
  558. print_time(reply4->RoundTripTime);
  559. if (i == 2) {
  560. print_ip_addr(
  561. reply4->Address,
  562. doReverseLookup
  563. );
  564. NlsPutMsg(STDOUT, TRACERT_CR);
  565. if (reply4->RoundTripTime < MIN_INTERVAL) {
  566. Sleep(MIN_INTERVAL - reply4->RoundTripTime);
  567. }
  568. }
  569. else {
  570. haveReply = TRUE;
  571. reply4Address = reply4->Address;
  572. }
  573. }
  574. else {
  575. ErrorNotHandled = TRUE;
  576. }
  577. }
  578. // If we've not handled the status code by now, it represents
  579. // an unexpected fatal error and we'll now bail out.
  580. //
  581. if (ErrorNotHandled) {
  582. if (status < IP_STATUS_BASE) {
  583. NlsPutMsg( STDOUT, TRACERT_MESSAGE_7, status );
  584. }
  585. else {
  586. if (reply4 != NULL) {
  587. print_ip_addr(
  588. reply4->Address,
  589. doReverseLookup
  590. );
  591. NlsPutMsg( STDOUT, TRACERT_MESSAGE_6 );
  592. }
  593. for (i = 0;
  594. ( ErrorTable[i].Error != status &&
  595. ErrorTable[i].Error != IP_GENERAL_FAILURE
  596. );
  597. i++
  598. );
  599. NlsPutMsg( STDOUT, ErrorTable[i].ErrorNlsID );
  600. }
  601. goto loop_end;
  602. }
  603. }
  604. else { // AF_INET6
  605. numberOfReplies = Icmp6SendEcho2(
  606. IcmpHandle,
  607. 0,
  608. NULL,
  609. NULL,
  610. (LPSOCKADDR_IN6)&sourceAddress,
  611. (LPSOCKADDR_IN6)&address,
  612. SendBuffer,
  613. DEFAULT_SEND_SIZE,
  614. &options,
  615. RcvBuffer,
  616. DEFAULT_RECEIVE_SIZE,
  617. timeout
  618. );
  619. if (numberOfReplies == 0) {
  620. // We did not get any replies. This is possibly a timeout,
  621. // or an internal error to IP.
  622. //
  623. status = GetLastError();
  624. reply6 = NULL;
  625. if (status == IP_REQ_TIMED_OUT) {
  626. NlsPutMsg(STDOUT, TRACERT_NO_REPLY_TIME);
  627. if (i == 2) {
  628. if (haveReply) {
  629. print_ipv6_addr(
  630. &reply6Address,
  631. doReverseLookup
  632. );
  633. NlsPutMsg(STDOUT, TRACERT_CR);
  634. }
  635. else {
  636. NlsPutMsg( STDOUT, TRACERT_REQ_TIMED_OUT);
  637. }
  638. }
  639. }
  640. else {
  641. ErrorNotHandled = TRUE;
  642. }
  643. }
  644. else {
  645. // We got a reply. It's either for the final destination
  646. // (IP_SUCCESS), or because the TTL expired at a node along
  647. // the way, or we got an unexpected error response.
  648. //
  649. reply6 = (PICMPV6_ECHO_REPLY) RcvBuffer;
  650. status = reply6->Status;
  651. if (status == IP_SUCCESS) {
  652. print_time(reply6->RoundTripTime);
  653. if (i == 2) {
  654. print_ipv6_addr(
  655. (IN6_ADDR*)&reply6->Address.sin6_addr,
  656. doReverseLookup
  657. );
  658. NlsPutMsg(STDOUT, TRACERT_CR);
  659. goto loop_end;
  660. }
  661. else {
  662. haveReply = TRUE;
  663. RtlCopyMemory(&reply6Address,
  664. &reply6->Address.sin6_addr,
  665. sizeof(IN6_ADDR));
  666. }
  667. }
  668. else if (status == IP_HOP_LIMIT_EXCEEDED) {
  669. print_time(reply6->RoundTripTime);
  670. if (i == 2) {
  671. print_ipv6_addr(
  672. (IN6_ADDR*)&reply6->Address.sin6_addr,
  673. doReverseLookup
  674. );
  675. NlsPutMsg(STDOUT, TRACERT_CR);
  676. if (reply6->RoundTripTime < MIN_INTERVAL) {
  677. Sleep(MIN_INTERVAL - reply6->RoundTripTime);
  678. }
  679. }
  680. else {
  681. haveReply = TRUE;
  682. RtlCopyMemory(&reply6Address,
  683. &reply6->Address.sin6_addr,
  684. sizeof(IN6_ADDR));
  685. }
  686. }
  687. else {
  688. ErrorNotHandled = TRUE;
  689. }
  690. }
  691. // If we've not handled the status code by now, it represents
  692. // an unexpected fatal error and we'll now bail out.
  693. //
  694. if (ErrorNotHandled) {
  695. if (status < IP_STATUS_BASE) {
  696. NlsPutMsg( STDOUT, TRACERT_MESSAGE_7, status );
  697. }
  698. else {
  699. if (reply6 != NULL) {
  700. print_ipv6_addr(
  701. (IN6_ADDR*)&reply6->Address.sin6_addr,
  702. doReverseLookup
  703. );
  704. NlsPutMsg( STDOUT, TRACERT_MESSAGE_6 );
  705. }
  706. for (i = 0;
  707. ( ErrorTable[i].Error != status &&
  708. ErrorTable[i].Error != IP_GENERAL_FAILURE
  709. );
  710. i++
  711. );
  712. NlsPutMsg( STDOUT, ErrorTable[i].ErrorNlsID );
  713. }
  714. goto loop_end;
  715. }
  716. }
  717. }
  718. options.Ttl++;
  719. }
  720. loop_end:
  721. NlsPutMsg( STDOUT, TRACERT_MESSAGE_8 );
  722. IcmpCloseHandle(IcmpHandle);
  723. WSACleanup();
  724. return(0);
  725. error_exit:
  726. WSACleanup();
  727. return(1);
  728. }