2 * PROJECT: ReactOS trace route utility
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/network/tracert/tracert.cpp
5 * PURPOSE: Trace network paths through networks
6 * COPYRIGHT: Copyright 2018 Ged Murphy <gedmurphy@reactos.org>
11 #define WIN32_NO_STATUS
30 #define SIZEOF_ICMP_ERROR 8
31 #define SIZEOF_IO_STATUS_BLOCK 8
32 #define PACKET_SIZE 32
33 #define MAX_IPADDRESS 32
34 #define NUM_OF_PINGS 3
38 bool ResolveAddresses
;
41 WCHAR HostName
[NI_MAXHOST
];
42 WCHAR TargetIP
[MAX_IPADDRESS
];
64 if (hInst
== NULL
) return -1;
66 lpName
= (LPWSTR
)MAKEINTRESOURCE((uID
>> 4) + 1);
68 if ((hrSrc
= FindResourceW(hInst
, lpName
, (LPWSTR
)RT_STRING
)) &&
69 (hRes
= LoadResource(hInst
, hrSrc
)) &&
70 (lpStr
= (WCHAR
*)LockResource(hRes
)))
74 for (x
= 0; x
< uID
; x
++)
76 lpStr
+= (*lpStr
) + 1;
87 _Out_ LPWSTR
*lpTarget
93 hInst
= GetModuleHandleW(NULL
);
94 Length
= LengthOfStrResource(hInst
, uID
);
97 (*lpTarget
) = (LPWSTR
)LocalAlloc(LMEM_FIXED
,
98 Length
* sizeof(WCHAR
));
99 if ((*lpTarget
) != NULL
)
102 if (!(Ret
= LoadStringW(hInst
, uID
, *lpTarget
, Length
)))
104 LocalFree((HLOCAL
)(*lpTarget
));
122 if (AllocAndLoadString(uID
, &Format
) > 0)
124 va_start(lArgs
, uID
);
127 Ret
= FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_STRING
,
141 LocalFree((HLOCAL
)Format
);
147 #define OutputText(Id, ...) ConResPrintf(StdOut, Id, __VA_ARGS__)
148 #endif //USE_CONUTILS
154 OutputText(IDS_USAGE
);
163 Length
= wcslen(String
);
166 while ((i
< Length
) && ((String
[i
] < L
'0') || (String
[i
] > L
'9'))) i
++;
167 if ((i
>= Length
) || ((String
[i
] < L
'0') || (String
[i
] > L
'9')))
173 return wcstoul(&String
[i
], &StopString
, 10);
180 ZeroMemory(&Hints
, sizeof(Hints
));
181 Hints
.ai_family
= Info
.Family
;
182 Hints
.ai_flags
= AI_CANONNAME
;
185 Status
= GetAddrInfoW(Info
.HostName
,
194 Status
= GetNameInfoW(Info
.Target
->ai_addr
,
195 Info
.Target
->ai_addrlen
,
210 PrintHopInfo(_In_ PVOID Buffer
)
212 SOCKADDR_IN6 SockAddrIn6
= { 0 };
213 SOCKADDR_IN SockAddrIn
= { 0 };
217 if (Info
.Family
== AF_INET6
)
219 PIPV6_ADDRESS_EX Ipv6Addr
= (PIPV6_ADDRESS_EX
)Buffer
;
220 SockAddrIn6
.sin6_family
= AF_INET6
;
221 CopyMemory(SockAddrIn6
.sin6_addr
.u
.Word
, Ipv6Addr
->sin6_addr
, sizeof(SockAddrIn6
.sin6_addr
));
222 //SockAddrIn6.sin6_addr = Ipv6Addr->sin6_addr;
223 SockAddr
= (PSOCKADDR
)&SockAddrIn6
;
224 Size
= sizeof(SOCKADDR_IN6
);
229 IPAddr
*Address
= (IPAddr
*)Buffer
;
230 SockAddrIn
.sin_family
= AF_INET
;
231 SockAddrIn
.sin_addr
.S_un
.S_addr
= *Address
;
232 SockAddr
= (PSOCKADDR
)&SockAddrIn
;
233 Size
= sizeof(SOCKADDR_IN
);
237 bool Resolved
= false;
238 WCHAR HostName
[NI_MAXHOST
];
239 if (Info
.ResolveAddresses
)
241 Status
= GetNameInfoW(SockAddr
,
254 WCHAR IpAddress
[MAX_IPADDRESS
];
255 Status
= GetNameInfoW(SockAddr
,
266 OutputText(IDS_HOP_RES_INFO
, HostName
, IpAddress
);
270 OutputText(IDS_HOP_IP_INFO
, IpAddress
);
274 return (Status
== 0);
279 _In_ PVOID ReplyBuffer
,
280 _In_
bool OutputHopAddress
,
281 _Out_
bool& FoundTarget
288 if (Info
.Family
== AF_INET6
)
290 PICMPV6_ECHO_REPLY EchoReplyV6
;
291 EchoReplyV6
= (PICMPV6_ECHO_REPLY
)ReplyBuffer
;
292 Status
= EchoReplyV6
->Status
;
293 RoundTripTime
= EchoReplyV6
->RoundTripTime
;
294 AddressInfo
= &EchoReplyV6
->Address
;
298 PICMP_ECHO_REPLY EchoReplyV4
;
299 EchoReplyV4
= (PICMP_ECHO_REPLY
)ReplyBuffer
;
300 Status
= EchoReplyV4
->Status
;
301 RoundTripTime
= EchoReplyV4
->RoundTripTime
;
302 AddressInfo
= &EchoReplyV4
->Address
;
308 case IP_TTL_EXPIRED_TRANSIT
:
311 OutputText(IDS_HOP_TIME
, RoundTripTime
);
315 OutputText(IDS_HOP_ZERO
);
319 case IP_DEST_HOST_UNREACHABLE
:
320 case IP_DEST_NET_UNREACHABLE
:
322 PrintHopInfo(AddressInfo
);
323 OutputText(IDS_HOP_RESPONSE
);
324 if (Status
== IP_DEST_HOST_UNREACHABLE
)
326 OutputText(IDS_DEST_HOST_UNREACHABLE
);
328 else if (Status
== IP_DEST_NET_UNREACHABLE
)
330 OutputText(IDS_DEST_NET_UNREACHABLE
);
334 case IP_REQ_TIMED_OUT
:
335 OutputText(IDS_TIMEOUT
);
338 case IP_GENERAL_FAILURE
:
339 OutputText(IDS_GEN_FAILURE
);
343 OutputText(IDS_TRANSMIT_FAILED
, Status
);
347 if (OutputHopAddress
)
349 if (Status
== IP_SUCCESS
)
353 if (Status
== IP_TTL_EXPIRED_TRANSIT
|| Status
== IP_SUCCESS
)
355 PrintHopInfo(AddressInfo
);
356 OutputText(IDS_LINEBREAK
);
358 else if (Status
== IP_REQ_TIMED_OUT
)
360 OutputText(IDS_REQ_TIMED_OUT
);
370 bool Success
= false;
371 Success
= ResolveTarget();
374 OutputText(IDS_UNABLE_RESOLVE
, Info
.HostName
);
378 BYTE SendBuffer
[PACKET_SIZE
];
379 ICMPV6_ECHO_REPLY ReplyBufferv6
;
381 ICMP_ECHO_REPLY32 ReplyBufferv432
;
383 ICMP_ECHO_REPLY ReplyBufferv4
;
387 DWORD ReplySize
= PACKET_SIZE
+ SIZEOF_ICMP_ERROR
+ SIZEOF_IO_STATUS_BLOCK
;
388 if (Info
.Family
== AF_INET6
)
390 ReplyBuffer
= &ReplyBufferv6
;
391 ReplySize
+= sizeof(ICMPV6_ECHO_REPLY
);
396 ReplyBuffer
= &ReplyBufferv432
;
397 ReplySize
+= sizeof(ICMP_ECHO_REPLY32
);
399 ReplyBuffer
= &ReplyBufferv4
;
400 ReplySize
+= sizeof(ICMP_ECHO_REPLY
);
404 if (Info
.Family
== AF_INET6
)
406 Info
.hIcmpFile
= Icmp6CreateFile();
410 Info
.hIcmpFile
= IcmpCreateFile();
412 if (Info
.hIcmpFile
== INVALID_HANDLE_VALUE
)
414 FreeAddrInfoW(Info
.Target
);
418 OutputText(IDS_TRACE_INFO
, Info
.HostName
, Info
.TargetIP
, Info
.MaxHops
);
420 IP_OPTION_INFORMATION IpOptionInfo
;
421 ZeroMemory(&IpOptionInfo
, sizeof(IpOptionInfo
));
425 bool FoundTarget
= false;
426 while ((HopCount
<= Info
.MaxHops
) && (FoundTarget
== false) && (Quit
== false))
428 OutputText(IDS_HOP_COUNT
, HopCount
);
430 for (int Ping
= 1; Ping
<= NUM_OF_PINGS
; Ping
++)
432 IpOptionInfo
.Ttl
= static_cast<UCHAR
>(HopCount
);
434 if (Info
.Family
== AF_INET6
)
436 struct sockaddr_in6 Source
;
438 ZeroMemory(&Source
, sizeof(Source
));
439 Source
.sin6_family
= AF_INET6
;
441 (void)Icmp6SendEcho2(Info
.hIcmpFile
,
446 (struct sockaddr_in6
*)Info
.Target
->ai_addr
,
456 (void)IcmpSendEcho2(Info
.hIcmpFile
,
460 ((PSOCKADDR_IN
)Info
.Target
->ai_addr
)->sin_addr
.s_addr
,
469 if (DecodeResponse(ReplyBuffer
, (Ping
== NUM_OF_PINGS
), FoundTarget
) == false)
486 OutputText(IDS_TRACE_COMPLETE
);
488 FreeAddrInfoW(Info
.Target
);
491 IcmpCloseHandle(Info
.hIcmpFile
);
498 ParseCmdline(int argc
, wchar_t *argv
[])
506 for (int i
= 1; i
< argc
; i
++)
508 if (argv
[i
][0] == '-')
513 Info
.ResolveAddresses
= FALSE
;
517 Info
.MaxHops
= GetULONG(argv
[++i
]);
521 printf("-j is not yet implemented.\n");
525 Info
.Timeout
= GetULONG(argv
[++i
]);
529 Info
.Family
= AF_INET
;
533 Info
.Family
= AF_INET6
;
538 OutputText(IDS_INVALID_OPTION
, argv
[i
]);
546 StringCchCopyW(Info
.HostName
, NI_MAXHOST
, argv
[i
]);
555 int wmain(int argc
, wchar_t *argv
[])
557 Info
.ResolveAddresses
= true;
560 Info
.Family
= AF_UNSPEC
;
562 if (!ParseCmdline(argc
, argv
))
568 if (WSAStartup(MAKEWORD(2, 2), &WsaData
))
574 Success
= RunTraceRoute();
578 return Success
? 0 : 1;