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.

876 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)))
  101. return(0);
  102. // Convert vp to oem
  103. StrLen=strlen(vp);
  104. CharToOemBuff((LPCTSTR)vp,(LPSTR)vp,StrLen);
  105. msglen = _write(Handle, vp, StrLen);
  106. LocalFree(vp);
  107. return(msglen);
  108. }
  109. 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 = ai->ai_addrlen;
  232. memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
  233. if (DoReverseLookup) {
  234. getnameinfo(ai->ai_addr, 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 = 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_INVALID_SWITCH, arg);
  271. // NlsPutMsg(STDOUT, TRACERT_FAMILY, arg,
  272. // (Value==AF_INET)? "IPv4" : "IPv6");
  273. return FALSE;
  274. }
  275. *Family = Value;
  276. return TRUE;
  277. }
  278. int __cdecl
  279. main(int argc, char **argv)
  280. {
  281. SOCKADDR_STORAGE address, sourceAddress;
  282. socklen_t addressLen;
  283. IPAddr reply4Address;
  284. IN6_ADDR reply6Address;
  285. DWORD numberOfReplies;
  286. HANDLE IcmpHandle;
  287. DWORD status;
  288. PICMP_ECHO_REPLY reply4;
  289. PICMPV6_ECHO_REPLY reply6;
  290. char hostname[NI_MAXHOST], literal[INET6_ADDRSTRLEN];
  291. char *arg;
  292. int i;
  293. ulong maximumHops = DEFAULT_MAXIMUM_HOPS;
  294. BOOLEAN doReverseLookup = TRUE;
  295. IP_OPTION_INFORMATION options;
  296. char optionsData[MAX_OPT_SIZE];
  297. char *optionPtr;
  298. uchar currentIndex;
  299. IPAddr tempAddr;
  300. uchar j;
  301. uchar SRIndex = 0;
  302. ulong timeout = DEFAULT_TIMEOUT;
  303. BOOLEAN foundAddress = FALSE;
  304. BOOLEAN haveReply;
  305. DWORD Family = AF_UNSPEC;
  306. //
  307. // This will ensure the correct language message is displayed when
  308. // NlsPutMsg is called.
  309. //
  310. SetThreadUILanguage(0);
  311. if (WSAStartup(MAKEWORD(2, 0), &WsaData)) {
  312. NlsPutMsg(STDOUT, TRACERT_WSASTARTUP_FAILED, GetLastError());
  313. return(1);
  314. }
  315. memset(&sourceAddress, 0, sizeof sourceAddress);
  316. options.Ttl = 1;
  317. options.Tos = DEFAULT_TOS;
  318. options.Flags = DEFAULT_FLAGS;
  319. options.OptionsSize = 0;
  320. options.OptionsData = optionsData;
  321. if (argc < 2) {
  322. NlsPutMsg( STDOUT, TRACERT_USAGE, argv[0] );
  323. goto error_exit;
  324. }
  325. //
  326. // process command line
  327. //
  328. for (i=1; i < argc; i++) {
  329. arg = argv[i];
  330. if ((arg[0] == '-') || (arg[0] == '/')) {
  331. switch(arg[1]) {
  332. case '?':
  333. NlsPutMsg(STDOUT, TRACERT_USAGE, argv[0]);
  334. goto error_exit;
  335. case 'd':
  336. doReverseLookup = FALSE;
  337. break;
  338. case 'h':
  339. if (!param(&maximumHops, argv, argc, i++, 1, 255)) {
  340. goto error_exit;
  341. }
  342. break;
  343. case 'j': // Loose source routing
  344. // Only implemented for IPv4 so far
  345. if (!SetFamily(&Family, AF_INET, arg)) {
  346. goto error_exit;
  347. }
  348. currentIndex = options.OptionsSize;
  349. if ((currentIndex + 7) > MAX_OPT_SIZE) {
  350. NlsPutMsg(STDOUT, TRACERT_TOO_MANY_OPTIONS);
  351. goto error_exit;
  352. }
  353. optionPtr = options.OptionsData;
  354. optionPtr[currentIndex] = (char) IP_OPT_LSRR;
  355. optionPtr[currentIndex+1] = 3;
  356. optionPtr[currentIndex+2] = 4; // Set initial pointer value
  357. options.OptionsSize += 3;
  358. while ( (i < (argc - 2)) && (*argv[i+1] != '-')) {
  359. if ((currentIndex + 7) > MAX_OPT_SIZE) {
  360. NlsPutMsg(STDOUT, TRACERT_TOO_MANY_OPTIONS);
  361. goto error_exit;
  362. }
  363. arg = argv[++i];
  364. tempAddr = inet_addr(arg);
  365. if (tempAddr == INADDR_NONE) {
  366. NlsPutMsg(
  367. STDOUT,
  368. TRACERT_BAD_ROUTE_ADDRESS,
  369. arg
  370. );
  371. goto error_exit;
  372. }
  373. j = optionPtr[currentIndex+1];
  374. *(ulong UNALIGNED *)&optionPtr[j+currentIndex] = tempAddr;
  375. optionPtr[currentIndex+1] += 4;
  376. options.OptionsSize += 4;
  377. }
  378. SRIndex = optionPtr[currentIndex+1] + currentIndex;
  379. optionPtr[currentIndex+1] += 4; // Save space for dest. addr
  380. options.OptionsSize += 4;
  381. break;
  382. case 'w':
  383. if (!param(&timeout, argv, argc, i++, 1, 0xffffffff)) {
  384. goto error_exit;
  385. }
  386. break;
  387. case 'R':
  388. // Only implemented for IPv6 so far
  389. if (!SetFamily(&Family, AF_INET6, arg)) {
  390. goto error_exit;
  391. }
  392. options.Flags |= ICMPV6_ECHO_REQUEST_FLAG_REVERSE;
  393. break;
  394. case 'S':
  395. // Only implemented for IPv6 so far
  396. if (!SetFamily(&Family, AF_INET6, arg)) {
  397. goto error_exit;
  398. }
  399. if (!GetSource(Family, argv[++i], (LPSOCKADDR)&sourceAddress)) {
  400. NlsPutMsg(STDOUT, TRACERT_BAD_OPTION_VALUE, arg[1]);
  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_WSASTARTUP_FAILED, WSAGetLastError());
  457. // NlsPutMsg(STDOUT, TRACERT_SOCKET_FAILED, WSAGetLastError());
  458. exit(1);
  459. }
  460. (void) WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY,
  461. &address, sizeof address,
  462. &sourceAddress, sizeof sourceAddress,
  463. &BytesReturned, NULL, NULL);
  464. closesocket(s);
  465. }
  466. IcmpHandle = Icmp6CreateFile();
  467. }
  468. if (IcmpHandle == INVALID_HANDLE_VALUE) {
  469. status = GetLastError();
  470. NlsPutMsg( STDOUT, TRACERT_MESSAGE_2, status );
  471. goto error_exit;
  472. }
  473. getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
  474. NULL, 0, NI_NUMERICHOST);
  475. if (hostname[0]) {
  476. NlsPutMsg(
  477. STDOUT,
  478. TRACERT_HEADER1,
  479. hostname,
  480. literal,
  481. maximumHops
  482. );
  483. }
  484. else {
  485. NlsPutMsg(
  486. STDOUT,
  487. TRACERT_HEADER2,
  488. literal,
  489. maximumHops
  490. );
  491. }
  492. while((options.Ttl <= maximumHops) && (options.Ttl != 0)) {
  493. NlsPutMsg( STDOUT, TRACERT_MESSAGE_4, (uint)options.Ttl );
  494. haveReply = FALSE;
  495. for (i=0; i<3; i++) {
  496. BOOLEAN ErrorNotHandled = FALSE;
  497. if (Family == AF_INET) {
  498. numberOfReplies = IcmpSendEcho2(
  499. IcmpHandle,
  500. 0,
  501. NULL,
  502. NULL,
  503. ((LPSOCKADDR_IN)&address)->sin_addr.s_addr,
  504. SendBuffer,
  505. DEFAULT_SEND_SIZE,
  506. &options,
  507. RcvBuffer,
  508. DEFAULT_RECEIVE_SIZE,
  509. timeout
  510. );
  511. if (numberOfReplies == 0) {
  512. // We did not get any replies. This is possibly a timeout,
  513. // or an internal error to IP.
  514. //
  515. status = GetLastError();
  516. reply4 = NULL;
  517. if (status == IP_REQ_TIMED_OUT) {
  518. NlsPutMsg(STDOUT, TRACERT_NO_REPLY_TIME);
  519. if (i == 2) {
  520. if (haveReply) {
  521. print_ip_addr(
  522. reply4Address,
  523. doReverseLookup
  524. );
  525. NlsPutMsg(STDOUT, TRACERT_CR);
  526. }
  527. else {
  528. NlsPutMsg( STDOUT, TRACERT_REQ_TIMED_OUT);
  529. }
  530. }
  531. }
  532. else {
  533. ErrorNotHandled = TRUE;
  534. }
  535. }
  536. else {
  537. // We got a reply. It's either for the final destination
  538. // (IP_SUCCESS), or because the TTL expired at a node along
  539. // the way, or we got an unexpected error response.
  540. //
  541. reply4 = (PICMP_ECHO_REPLY) RcvBuffer;
  542. status = reply4->Status;
  543. if (status == IP_SUCCESS) {
  544. print_time(reply4->RoundTripTime);
  545. if (i == 2) {
  546. print_ip_addr(
  547. reply4->Address,
  548. doReverseLookup
  549. );
  550. NlsPutMsg(STDOUT, TRACERT_CR);
  551. goto loop_end;
  552. }
  553. else {
  554. haveReply = TRUE;
  555. reply4Address = reply4->Address;
  556. }
  557. }
  558. else if (status == IP_TTL_EXPIRED_TRANSIT) {
  559. print_time(reply4->RoundTripTime);
  560. if (i == 2) {
  561. print_ip_addr(
  562. reply4->Address,
  563. doReverseLookup
  564. );
  565. NlsPutMsg(STDOUT, TRACERT_CR);
  566. if (reply4->RoundTripTime < MIN_INTERVAL) {
  567. Sleep(MIN_INTERVAL - reply4->RoundTripTime);
  568. }
  569. }
  570. else {
  571. haveReply = TRUE;
  572. reply4Address = reply4->Address;
  573. }
  574. }
  575. else {
  576. ErrorNotHandled = TRUE;
  577. }
  578. }
  579. // If we've not handled the status code by now, it represents
  580. // an unexpected fatal error and we'll now bail out.
  581. //
  582. if (ErrorNotHandled) {
  583. if (status < IP_STATUS_BASE) {
  584. NlsPutMsg( STDOUT, TRACERT_MESSAGE_7, status );
  585. }
  586. else {
  587. if (reply4 != NULL) {
  588. print_ip_addr(
  589. reply4->Address,
  590. doReverseLookup
  591. );
  592. NlsPutMsg( STDOUT, TRACERT_MESSAGE_6 );
  593. }
  594. for (i = 0;
  595. ( ErrorTable[i].Error != status &&
  596. ErrorTable[i].Error != IP_GENERAL_FAILURE
  597. );
  598. i++
  599. );
  600. NlsPutMsg( STDOUT, ErrorTable[i].ErrorNlsID );
  601. }
  602. goto loop_end;
  603. }
  604. }
  605. else { // AF_INET6
  606. numberOfReplies = Icmp6SendEcho2(
  607. IcmpHandle,
  608. 0,
  609. NULL,
  610. NULL,
  611. (LPSOCKADDR_IN6)&sourceAddress,
  612. (LPSOCKADDR_IN6)&address,
  613. SendBuffer,
  614. DEFAULT_SEND_SIZE,
  615. &options,
  616. RcvBuffer,
  617. DEFAULT_RECEIVE_SIZE,
  618. timeout
  619. );
  620. if (numberOfReplies == 0) {
  621. // We did not get any replies. This is possibly a timeout,
  622. // or an internal error to IP.
  623. //
  624. status = GetLastError();
  625. reply6 = NULL;
  626. if (status == IP_REQ_TIMED_OUT) {
  627. NlsPutMsg(STDOUT, TRACERT_NO_REPLY_TIME);
  628. if (i == 2) {
  629. if (haveReply) {
  630. print_ipv6_addr(
  631. &reply6Address,
  632. doReverseLookup
  633. );
  634. NlsPutMsg(STDOUT, TRACERT_CR);
  635. }
  636. else {
  637. NlsPutMsg( STDOUT, TRACERT_REQ_TIMED_OUT);
  638. }
  639. }
  640. }
  641. else {
  642. ErrorNotHandled = TRUE;
  643. }
  644. }
  645. else {
  646. // We got a reply. It's either for the final destination
  647. // (IP_SUCCESS), or because the TTL expired at a node along
  648. // the way, or we got an unexpected error response.
  649. //
  650. reply6 = (PICMPV6_ECHO_REPLY) RcvBuffer;
  651. status = reply6->Status;
  652. if (status == IP_SUCCESS) {
  653. print_time(reply6->RoundTripTime);
  654. if (i == 2) {
  655. print_ipv6_addr(
  656. (IN6_ADDR*)&reply6->Address.sin6_addr,
  657. doReverseLookup
  658. );
  659. NlsPutMsg(STDOUT, TRACERT_CR);
  660. goto loop_end;
  661. }
  662. else {
  663. haveReply = TRUE;
  664. RtlCopyMemory(&reply6Address,
  665. &reply6->Address.sin6_addr,
  666. sizeof(IN6_ADDR));
  667. }
  668. }
  669. else if (status == IP_HOP_LIMIT_EXCEEDED) {
  670. print_time(reply6->RoundTripTime);
  671. if (i == 2) {
  672. print_ipv6_addr(
  673. (IN6_ADDR*)&reply6->Address.sin6_addr,
  674. doReverseLookup
  675. );
  676. NlsPutMsg(STDOUT, TRACERT_CR);
  677. if (reply6->RoundTripTime < MIN_INTERVAL) {
  678. Sleep(MIN_INTERVAL - reply6->RoundTripTime);
  679. }
  680. }
  681. else {
  682. haveReply = TRUE;
  683. RtlCopyMemory(&reply6Address,
  684. &reply6->Address.sin6_addr,
  685. sizeof(IN6_ADDR));
  686. }
  687. }
  688. else {
  689. ErrorNotHandled = TRUE;
  690. }
  691. }
  692. // If we've not handled the status code by now, it represents
  693. // an unexpected fatal error and we'll now bail out.
  694. //
  695. if (ErrorNotHandled) {
  696. if (status < IP_STATUS_BASE) {
  697. NlsPutMsg( STDOUT, TRACERT_MESSAGE_7, status );
  698. }
  699. else {
  700. if (reply6 != NULL) {
  701. print_ipv6_addr(
  702. (IN6_ADDR*)&reply6->Address.sin6_addr,
  703. doReverseLookup
  704. );
  705. NlsPutMsg( STDOUT, TRACERT_MESSAGE_6 );
  706. }
  707. for (i = 0;
  708. ( ErrorTable[i].Error != status &&
  709. ErrorTable[i].Error != IP_GENERAL_FAILURE
  710. );
  711. i++
  712. );
  713. NlsPutMsg( STDOUT, ErrorTable[i].ErrorNlsID );
  714. }
  715. goto loop_end;
  716. }
  717. }
  718. }
  719. options.Ttl++;
  720. }
  721. loop_end:
  722. NlsPutMsg( STDOUT, TRACERT_MESSAGE_8 );
  723. IcmpCloseHandle(IcmpHandle);
  724. WSACleanup();
  725. return(0);
  726. error_exit:
  727. WSACleanup();
  728. return(1);
  729. }