1344f3672SGed Murphy /*
2344f3672SGed Murphy  * PROJECT:     ReactOS trace route utility
3*846c9aa1SStanislav Motylkov  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4344f3672SGed Murphy  * PURPOSE:     Trace network paths through networks
5344f3672SGed Murphy  * COPYRIGHT:   Copyright 2018 Ged Murphy <gedmurphy@reactos.org>
6344f3672SGed Murphy  */
7344f3672SGed Murphy 
8344f3672SGed Murphy #ifdef __REACTOS__
93d66048bSJoachim Henze #define USE_CONUTILS
10344f3672SGed Murphy #define WIN32_NO_STATUS
11344f3672SGed Murphy #include <stdarg.h>
12344f3672SGed Murphy #include <windef.h>
13344f3672SGed Murphy #include <winbase.h>
14344f3672SGed Murphy #include <winuser.h>
15344f3672SGed Murphy #define _INC_WINDOWS
16344f3672SGed Murphy #include <stdlib.h>
17344f3672SGed Murphy #include <winsock2.h>
183d66048bSJoachim Henze #include <conutils.h>
19344f3672SGed Murphy #else
20344f3672SGed Murphy #include <winsock2.h>
21344f3672SGed Murphy #include <Windows.h>
22344f3672SGed Murphy #endif
23344f3672SGed Murphy #include <ws2tcpip.h>
24344f3672SGed Murphy #include <iphlpapi.h>
25344f3672SGed Murphy #include <icmpapi.h>
26344f3672SGed Murphy #include <strsafe.h>
27344f3672SGed Murphy #include "resource.h"
28344f3672SGed Murphy 
29344f3672SGed Murphy #define SIZEOF_ICMP_ERROR       8
30344f3672SGed Murphy #define SIZEOF_IO_STATUS_BLOCK  8
31344f3672SGed Murphy #define PACKET_SIZE             32
32344f3672SGed Murphy #define MAX_IPADDRESS           32
33344f3672SGed Murphy #define NUM_OF_PINGS            3
34344f3672SGed Murphy 
35344f3672SGed Murphy struct TraceInfo
36344f3672SGed Murphy {
37344f3672SGed Murphy     bool ResolveAddresses;
38344f3672SGed Murphy     ULONG MaxHops;
39344f3672SGed Murphy     ULONG Timeout;
40344f3672SGed Murphy     WCHAR HostName[NI_MAXHOST];
41344f3672SGed Murphy     WCHAR TargetIP[MAX_IPADDRESS];
42344f3672SGed Murphy     int Family;
43344f3672SGed Murphy 
44344f3672SGed Murphy     HANDLE hIcmpFile;
45344f3672SGed Murphy     PADDRINFOW Target;
46344f3672SGed Murphy 
47344f3672SGed Murphy } Info = { 0 };
48344f3672SGed Murphy 
49344f3672SGed Murphy 
50344f3672SGed Murphy 
51344f3672SGed Murphy #ifndef USE_CONUTILS
52344f3672SGed Murphy static
53344f3672SGed Murphy INT
LengthOfStrResource(_In_ HINSTANCE hInst,_In_ UINT uID)54344f3672SGed Murphy LengthOfStrResource(
55344f3672SGed Murphy     _In_ HINSTANCE hInst,
56344f3672SGed Murphy     _In_ UINT uID
57344f3672SGed Murphy )
58344f3672SGed Murphy {
59344f3672SGed Murphy     HRSRC hrSrc;
60344f3672SGed Murphy     HGLOBAL hRes;
61344f3672SGed Murphy     LPWSTR lpName, lpStr;
62344f3672SGed Murphy 
63344f3672SGed Murphy     if (hInst == NULL) return -1;
64344f3672SGed Murphy 
65344f3672SGed Murphy     lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
66344f3672SGed Murphy 
67344f3672SGed Murphy     if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
68344f3672SGed Murphy         (hRes = LoadResource(hInst, hrSrc)) &&
69344f3672SGed Murphy         (lpStr = (WCHAR*)LockResource(hRes)))
70344f3672SGed Murphy     {
71344f3672SGed Murphy         UINT x;
72344f3672SGed Murphy         uID &= 0xF;
73344f3672SGed Murphy         for (x = 0; x < uID; x++)
74344f3672SGed Murphy         {
75344f3672SGed Murphy             lpStr += (*lpStr) + 1;
76344f3672SGed Murphy         }
77344f3672SGed Murphy         return (int)(*lpStr);
78344f3672SGed Murphy     }
79344f3672SGed Murphy     return -1;
80344f3672SGed Murphy }
81344f3672SGed Murphy 
82344f3672SGed Murphy static
83344f3672SGed Murphy INT
AllocAndLoadString(_In_ UINT uID,_Out_ LPWSTR * lpTarget)84344f3672SGed Murphy AllocAndLoadString(
85344f3672SGed Murphy     _In_ UINT uID,
86344f3672SGed Murphy     _Out_ LPWSTR *lpTarget
87344f3672SGed Murphy )
88344f3672SGed Murphy {
89344f3672SGed Murphy     HMODULE hInst;
90344f3672SGed Murphy     INT Length;
91344f3672SGed Murphy 
92344f3672SGed Murphy     hInst = GetModuleHandleW(NULL);
93344f3672SGed Murphy     Length = LengthOfStrResource(hInst, uID);
94344f3672SGed Murphy     if (Length++ > 0)
95344f3672SGed Murphy     {
96344f3672SGed Murphy         (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
97344f3672SGed Murphy                                          Length * sizeof(WCHAR));
98344f3672SGed Murphy         if ((*lpTarget) != NULL)
99344f3672SGed Murphy         {
100344f3672SGed Murphy             INT Ret;
101344f3672SGed Murphy             if (!(Ret = LoadStringW(hInst, uID, *lpTarget, Length)))
102344f3672SGed Murphy             {
103344f3672SGed Murphy                 LocalFree((HLOCAL)(*lpTarget));
104344f3672SGed Murphy             }
105344f3672SGed Murphy             return Ret;
106344f3672SGed Murphy         }
107344f3672SGed Murphy     }
108344f3672SGed Murphy     return 0;
109344f3672SGed Murphy }
110344f3672SGed Murphy 
111344f3672SGed Murphy static
112344f3672SGed Murphy INT
OutputText(_In_ UINT uID,...)113344f3672SGed Murphy OutputText(
114344f3672SGed Murphy     _In_ UINT uID,
115344f3672SGed Murphy     ...)
116344f3672SGed Murphy {
117344f3672SGed Murphy     LPWSTR Format;
118344f3672SGed Murphy     DWORD Ret = 0;
119344f3672SGed Murphy     va_list lArgs;
120344f3672SGed Murphy 
121344f3672SGed Murphy     if (AllocAndLoadString(uID, &Format) > 0)
122344f3672SGed Murphy     {
123344f3672SGed Murphy         va_start(lArgs, uID);
124344f3672SGed Murphy 
125344f3672SGed Murphy         LPWSTR Buffer;
126344f3672SGed Murphy         Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
127344f3672SGed Murphy                              Format,
128344f3672SGed Murphy                              0,
129344f3672SGed Murphy                              0,
130344f3672SGed Murphy                              (LPWSTR)&Buffer,
131344f3672SGed Murphy                              0,
132344f3672SGed Murphy                              &lArgs);
133344f3672SGed Murphy         va_end(lArgs);
134344f3672SGed Murphy 
135344f3672SGed Murphy         if (Ret)
136344f3672SGed Murphy         {
137344f3672SGed Murphy             wprintf(Buffer);
138344f3672SGed Murphy             LocalFree(Buffer);
139344f3672SGed Murphy         }
140344f3672SGed Murphy         LocalFree((HLOCAL)Format);
141344f3672SGed Murphy     }
142344f3672SGed Murphy 
143344f3672SGed Murphy     return Ret;
144344f3672SGed Murphy }
145344f3672SGed Murphy #else
1463d66048bSJoachim Henze #define OutputText(Id, ...) ConResMsgPrintfEx(StdOut, NULL, 0, Id, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), ##__VA_ARGS__)
147344f3672SGed Murphy #endif //USE_CONUTILS
148344f3672SGed Murphy 
149344f3672SGed Murphy static
150344f3672SGed Murphy VOID
Usage()151344f3672SGed Murphy Usage()
152344f3672SGed Murphy {
153344f3672SGed Murphy     OutputText(IDS_USAGE);
154344f3672SGed Murphy }
155344f3672SGed Murphy 
156344f3672SGed Murphy static ULONG
GetULONG(_In_z_ LPWSTR String)157344f3672SGed Murphy GetULONG(
158344f3672SGed Murphy     _In_z_ LPWSTR String
159344f3672SGed Murphy )
160344f3672SGed Murphy {
161344f3672SGed Murphy     ULONG Length;
162344f3672SGed Murphy     Length = wcslen(String);
163344f3672SGed Murphy 
164344f3672SGed Murphy     ULONG i = 0;
165344f3672SGed Murphy     while ((i < Length) && ((String[i] < L'0') || (String[i] > L'9'))) i++;
166344f3672SGed Murphy     if ((i >= Length) || ((String[i] < L'0') || (String[i] > L'9')))
167344f3672SGed Murphy     {
168344f3672SGed Murphy         return (ULONG)-1;
169344f3672SGed Murphy     }
170344f3672SGed Murphy 
171344f3672SGed Murphy     LPWSTR StopString;
172344f3672SGed Murphy     return wcstoul(&String[i], &StopString, 10);
173344f3672SGed Murphy }
174344f3672SGed Murphy 
175344f3672SGed Murphy static bool
ResolveTarget()176344f3672SGed Murphy ResolveTarget()
177344f3672SGed Murphy {
178344f3672SGed Murphy     ADDRINFOW Hints;
179344f3672SGed Murphy     ZeroMemory(&Hints, sizeof(Hints));
180344f3672SGed Murphy     Hints.ai_family = Info.Family;
181344f3672SGed Murphy     Hints.ai_flags = AI_CANONNAME;
182344f3672SGed Murphy 
183344f3672SGed Murphy     int Status;
184344f3672SGed Murphy     Status = GetAddrInfoW(Info.HostName,
185344f3672SGed Murphy                           NULL,
186344f3672SGed Murphy                           &Hints,
187344f3672SGed Murphy                           &Info.Target);
188344f3672SGed Murphy     if (Status != 0)
189344f3672SGed Murphy     {
190344f3672SGed Murphy         return false;
191344f3672SGed Murphy     }
192344f3672SGed Murphy 
193344f3672SGed Murphy     Status = GetNameInfoW(Info.Target->ai_addr,
194344f3672SGed Murphy                           Info.Target->ai_addrlen,
195344f3672SGed Murphy                           Info.TargetIP,
196344f3672SGed Murphy                           MAX_IPADDRESS,
197344f3672SGed Murphy                           NULL,
198344f3672SGed Murphy                           0,
199344f3672SGed Murphy                           NI_NUMERICHOST);
200344f3672SGed Murphy     if (Status != 0)
201344f3672SGed Murphy     {
202344f3672SGed Murphy         return false;
203344f3672SGed Murphy     }
204344f3672SGed Murphy 
205344f3672SGed Murphy     return true;
206344f3672SGed Murphy }
207344f3672SGed Murphy 
208344f3672SGed Murphy static bool
PrintHopInfo(_In_ PVOID Buffer)209344f3672SGed Murphy PrintHopInfo(_In_ PVOID Buffer)
210344f3672SGed Murphy {
211344f3672SGed Murphy     SOCKADDR_IN6 SockAddrIn6 = { 0 };
212344f3672SGed Murphy     SOCKADDR_IN SockAddrIn = { 0 };
213344f3672SGed Murphy     PSOCKADDR SockAddr;
214344f3672SGed Murphy     socklen_t Size;
215344f3672SGed Murphy 
216344f3672SGed Murphy     if (Info.Family == AF_INET6)
217344f3672SGed Murphy     {
218344f3672SGed Murphy         PIPV6_ADDRESS_EX Ipv6Addr = (PIPV6_ADDRESS_EX)Buffer;
219344f3672SGed Murphy         SockAddrIn6.sin6_family = AF_INET6;
220344f3672SGed Murphy         CopyMemory(SockAddrIn6.sin6_addr.u.Word, Ipv6Addr->sin6_addr, sizeof(SockAddrIn6.sin6_addr));
221344f3672SGed Murphy         //SockAddrIn6.sin6_addr = Ipv6Addr->sin6_addr;
222344f3672SGed Murphy         SockAddr = (PSOCKADDR)&SockAddrIn6;
223344f3672SGed Murphy         Size = sizeof(SOCKADDR_IN6);
224344f3672SGed Murphy 
225344f3672SGed Murphy     }
226344f3672SGed Murphy     else
227344f3672SGed Murphy     {
228344f3672SGed Murphy         IPAddr *Address = (IPAddr *)Buffer;
229344f3672SGed Murphy         SockAddrIn.sin_family = AF_INET;
230344f3672SGed Murphy         SockAddrIn.sin_addr.S_un.S_addr = *Address;
231344f3672SGed Murphy         SockAddr = (PSOCKADDR)&SockAddrIn;
232344f3672SGed Murphy         Size = sizeof(SOCKADDR_IN);
233344f3672SGed Murphy     }
234344f3672SGed Murphy 
235344f3672SGed Murphy     INT Status;
236344f3672SGed Murphy     bool Resolved = false;
237344f3672SGed Murphy     WCHAR HostName[NI_MAXHOST];
238344f3672SGed Murphy     if (Info.ResolveAddresses)
239344f3672SGed Murphy     {
240344f3672SGed Murphy         Status = GetNameInfoW(SockAddr,
241344f3672SGed Murphy                               Size,
242344f3672SGed Murphy                               HostName,
243344f3672SGed Murphy                               NI_MAXHOST,
244344f3672SGed Murphy                               NULL,
245344f3672SGed Murphy                               0,
246344f3672SGed Murphy                               NI_NAMEREQD);
247344f3672SGed Murphy         if (Status == 0)
248344f3672SGed Murphy         {
249344f3672SGed Murphy             Resolved = true;
250344f3672SGed Murphy         }
251344f3672SGed Murphy     }
252344f3672SGed Murphy 
253344f3672SGed Murphy     WCHAR IpAddress[MAX_IPADDRESS];
254344f3672SGed Murphy     Status = GetNameInfoW(SockAddr,
255344f3672SGed Murphy                           Size,
256344f3672SGed Murphy                           IpAddress,
25740288a70SPako Smith                           MAX_IPADDRESS,
258344f3672SGed Murphy                           NULL,
259344f3672SGed Murphy                           0,
260344f3672SGed Murphy                           NI_NUMERICHOST);
261344f3672SGed Murphy     if (Status == 0)
262344f3672SGed Murphy     {
263344f3672SGed Murphy         if (Resolved)
264344f3672SGed Murphy         {
265344f3672SGed Murphy             OutputText(IDS_HOP_RES_INFO, HostName, IpAddress);
266344f3672SGed Murphy         }
267344f3672SGed Murphy         else
268344f3672SGed Murphy         {
269344f3672SGed Murphy             OutputText(IDS_HOP_IP_INFO, IpAddress);
270344f3672SGed Murphy         }
271344f3672SGed Murphy     }
272344f3672SGed Murphy 
273344f3672SGed Murphy     return (Status == 0);
274344f3672SGed Murphy }
275344f3672SGed Murphy 
276*846c9aa1SStanislav Motylkov static ULONG
GetResponseStats(_In_ PVOID ReplyBuffer,_Out_ ULONG & RoundTripTime,_Out_ PVOID & AddressInfo)277*846c9aa1SStanislav Motylkov GetResponseStats(
278344f3672SGed Murphy     _In_ PVOID ReplyBuffer,
279*846c9aa1SStanislav Motylkov     _Out_ ULONG& RoundTripTime,
280*846c9aa1SStanislav Motylkov     _Out_ PVOID& AddressInfo
281344f3672SGed Murphy )
282344f3672SGed Murphy {
283344f3672SGed Murphy     ULONG Status;
284344f3672SGed Murphy 
285344f3672SGed Murphy     if (Info.Family == AF_INET6)
286344f3672SGed Murphy     {
287344f3672SGed Murphy         PICMPV6_ECHO_REPLY EchoReplyV6;
288344f3672SGed Murphy         EchoReplyV6 = (PICMPV6_ECHO_REPLY)ReplyBuffer;
289344f3672SGed Murphy         Status = EchoReplyV6->Status;
290344f3672SGed Murphy         RoundTripTime = EchoReplyV6->RoundTripTime;
291344f3672SGed Murphy         AddressInfo = &EchoReplyV6->Address;
292344f3672SGed Murphy     }
293344f3672SGed Murphy     else
294344f3672SGed Murphy     {
2958532c3b6SSerge Gautherie #ifdef _WIN64
2968532c3b6SSerge Gautherie         PICMP_ECHO_REPLY32 EchoReplyV4;
2978532c3b6SSerge Gautherie         EchoReplyV4 = (PICMP_ECHO_REPLY32)ReplyBuffer;
2988532c3b6SSerge Gautherie #else
299344f3672SGed Murphy         PICMP_ECHO_REPLY EchoReplyV4;
300344f3672SGed Murphy         EchoReplyV4 = (PICMP_ECHO_REPLY)ReplyBuffer;
3018532c3b6SSerge Gautherie #endif
302344f3672SGed Murphy         Status = EchoReplyV4->Status;
303344f3672SGed Murphy         RoundTripTime = EchoReplyV4->RoundTripTime;
304344f3672SGed Murphy         AddressInfo = &EchoReplyV4->Address;
305344f3672SGed Murphy     }
306344f3672SGed Murphy 
307*846c9aa1SStanislav Motylkov     return Status;
308*846c9aa1SStanislav Motylkov }
309*846c9aa1SStanislav Motylkov 
310*846c9aa1SStanislav Motylkov static bool
DecodeResponse(_In_ PVOID ReplyBuffer,_In_ PVOID LastGoodResponse,_In_ bool OutputHopAddress,_Out_ bool & GoodResponse,_Out_ bool & FoundTarget)311*846c9aa1SStanislav Motylkov DecodeResponse(
312*846c9aa1SStanislav Motylkov     _In_ PVOID ReplyBuffer,
313*846c9aa1SStanislav Motylkov     _In_ PVOID LastGoodResponse,
314*846c9aa1SStanislav Motylkov     _In_ bool OutputHopAddress,
315*846c9aa1SStanislav Motylkov     _Out_ bool& GoodResponse,
316*846c9aa1SStanislav Motylkov     _Out_ bool& FoundTarget
317*846c9aa1SStanislav Motylkov )
318*846c9aa1SStanislav Motylkov {
319*846c9aa1SStanislav Motylkov     ULONG RoundTripTime;
320*846c9aa1SStanislav Motylkov     PVOID AddressInfo;
321*846c9aa1SStanislav Motylkov     ULONG Status = GetResponseStats(ReplyBuffer, RoundTripTime, AddressInfo);
322*846c9aa1SStanislav Motylkov 
323344f3672SGed Murphy     switch (Status)
324344f3672SGed Murphy     {
325344f3672SGed Murphy     case IP_SUCCESS:
326344f3672SGed Murphy     case IP_TTL_EXPIRED_TRANSIT:
327344f3672SGed Murphy         if (RoundTripTime)
328344f3672SGed Murphy         {
329344f3672SGed Murphy             OutputText(IDS_HOP_TIME, RoundTripTime);
330344f3672SGed Murphy         }
331344f3672SGed Murphy         else
332344f3672SGed Murphy         {
333344f3672SGed Murphy             OutputText(IDS_HOP_ZERO);
334344f3672SGed Murphy         }
335*846c9aa1SStanislav Motylkov         GoodResponse = true;
336344f3672SGed Murphy         break;
337344f3672SGed Murphy 
338344f3672SGed Murphy     case IP_DEST_HOST_UNREACHABLE:
339010c7bfcSStanislav Motylkov     case IP_DEST_NET_UNREACHABLE:
340010c7bfcSStanislav Motylkov         FoundTarget = true;
341010c7bfcSStanislav Motylkov         PrintHopInfo(AddressInfo);
342010c7bfcSStanislav Motylkov         OutputText(IDS_HOP_RESPONSE);
343010c7bfcSStanislav Motylkov         if (Status == IP_DEST_HOST_UNREACHABLE)
344010c7bfcSStanislav Motylkov         {
345010c7bfcSStanislav Motylkov             OutputText(IDS_DEST_HOST_UNREACHABLE);
346010c7bfcSStanislav Motylkov         }
347010c7bfcSStanislav Motylkov         else if (Status == IP_DEST_NET_UNREACHABLE)
348010c7bfcSStanislav Motylkov         {
349010c7bfcSStanislav Motylkov             OutputText(IDS_DEST_NET_UNREACHABLE);
350010c7bfcSStanislav Motylkov         }
351010c7bfcSStanislav Motylkov         return true;
352344f3672SGed Murphy 
353344f3672SGed Murphy     case IP_REQ_TIMED_OUT:
354344f3672SGed Murphy         OutputText(IDS_TIMEOUT);
355344f3672SGed Murphy         break;
356344f3672SGed Murphy 
357344f3672SGed Murphy     case IP_GENERAL_FAILURE:
358344f3672SGed Murphy         OutputText(IDS_GEN_FAILURE);
359344f3672SGed Murphy         return false;
360344f3672SGed Murphy 
361344f3672SGed Murphy     default:
362010c7bfcSStanislav Motylkov         OutputText(IDS_TRANSMIT_FAILED, Status);
363344f3672SGed Murphy         return false;
364344f3672SGed Murphy     }
365344f3672SGed Murphy 
366344f3672SGed Murphy     if (OutputHopAddress)
367344f3672SGed Murphy     {
368*846c9aa1SStanislav Motylkov         if (Status == IP_REQ_TIMED_OUT && LastGoodResponse)
369*846c9aa1SStanislav Motylkov         {
370*846c9aa1SStanislav Motylkov             Status = GetResponseStats(LastGoodResponse, RoundTripTime, AddressInfo);
371*846c9aa1SStanislav Motylkov         }
372344f3672SGed Murphy         if (Status == IP_SUCCESS)
373344f3672SGed Murphy         {
374344f3672SGed Murphy             FoundTarget = true;
375344f3672SGed Murphy         }
376344f3672SGed Murphy         if (Status == IP_TTL_EXPIRED_TRANSIT || Status == IP_SUCCESS)
377344f3672SGed Murphy         {
378344f3672SGed Murphy             PrintHopInfo(AddressInfo);
379010c7bfcSStanislav Motylkov             OutputText(IDS_LINEBREAK);
380344f3672SGed Murphy         }
381344f3672SGed Murphy         else if (Status == IP_REQ_TIMED_OUT)
382344f3672SGed Murphy         {
383344f3672SGed Murphy             OutputText(IDS_REQ_TIMED_OUT);
384344f3672SGed Murphy         }
385344f3672SGed Murphy     }
386344f3672SGed Murphy 
387344f3672SGed Murphy     return true;
388344f3672SGed Murphy }
389344f3672SGed Murphy 
390344f3672SGed Murphy static bool
RunTraceRoute()391344f3672SGed Murphy RunTraceRoute()
392344f3672SGed Murphy {
393344f3672SGed Murphy     bool Success = false;
394*846c9aa1SStanislav Motylkov     PVOID ReplyBuffer = NULL, LastGoodResponse = NULL;
395*846c9aa1SStanislav Motylkov     DWORD ReplySize;
396*846c9aa1SStanislav Motylkov 
397*846c9aa1SStanislav Motylkov     HANDLE heap = GetProcessHeap();
398*846c9aa1SStanislav Motylkov     bool Quit = false;
399*846c9aa1SStanislav Motylkov     ULONG HopCount = 1;
400*846c9aa1SStanislav Motylkov     bool FoundTarget = false;
401*846c9aa1SStanislav Motylkov 
402344f3672SGed Murphy     Success = ResolveTarget();
403344f3672SGed Murphy     if (!Success)
404344f3672SGed Murphy     {
405344f3672SGed Murphy         OutputText(IDS_UNABLE_RESOLVE, Info.HostName);
406*846c9aa1SStanislav Motylkov         goto Cleanup;
407344f3672SGed Murphy     }
408344f3672SGed Murphy 
409*846c9aa1SStanislav Motylkov     ReplySize = PACKET_SIZE + SIZEOF_ICMP_ERROR + SIZEOF_IO_STATUS_BLOCK;
410344f3672SGed Murphy     if (Info.Family == AF_INET6)
411344f3672SGed Murphy     {
412344f3672SGed Murphy         ReplySize += sizeof(ICMPV6_ECHO_REPLY);
413344f3672SGed Murphy     }
414344f3672SGed Murphy     else
415344f3672SGed Murphy     {
416344f3672SGed Murphy #ifdef _WIN64
417344f3672SGed Murphy         ReplySize += sizeof(ICMP_ECHO_REPLY32);
418344f3672SGed Murphy #else
419344f3672SGed Murphy         ReplySize += sizeof(ICMP_ECHO_REPLY);
420344f3672SGed Murphy #endif
421344f3672SGed Murphy     }
422344f3672SGed Murphy 
4230ddf0a06SErdem Ersoy     ReplyBuffer = HeapAlloc(heap, HEAP_ZERO_MEMORY, ReplySize);
4240ddf0a06SErdem Ersoy     if (ReplyBuffer == NULL)
4250ddf0a06SErdem Ersoy     {
426*846c9aa1SStanislav Motylkov         Success = false;
427*846c9aa1SStanislav Motylkov         goto Cleanup;
4280ddf0a06SErdem Ersoy     }
4290ddf0a06SErdem Ersoy 
430344f3672SGed Murphy     if (Info.Family == AF_INET6)
431344f3672SGed Murphy     {
432344f3672SGed Murphy         Info.hIcmpFile = Icmp6CreateFile();
433344f3672SGed Murphy     }
434344f3672SGed Murphy     else
435344f3672SGed Murphy     {
436344f3672SGed Murphy         Info.hIcmpFile = IcmpCreateFile();
437344f3672SGed Murphy     }
438344f3672SGed Murphy     if (Info.hIcmpFile == INVALID_HANDLE_VALUE)
439344f3672SGed Murphy     {
440*846c9aa1SStanislav Motylkov         Success = false;
441*846c9aa1SStanislav Motylkov         goto Cleanup;
442344f3672SGed Murphy     }
443344f3672SGed Murphy 
444344f3672SGed Murphy     OutputText(IDS_TRACE_INFO, Info.HostName, Info.TargetIP, Info.MaxHops);
445344f3672SGed Murphy 
446344f3672SGed Murphy     IP_OPTION_INFORMATION IpOptionInfo;
447344f3672SGed Murphy     ZeroMemory(&IpOptionInfo, sizeof(IpOptionInfo));
448344f3672SGed Murphy 
449344f3672SGed Murphy     while ((HopCount <= Info.MaxHops) && (FoundTarget == false) && (Quit == false))
450344f3672SGed Murphy     {
451344f3672SGed Murphy         OutputText(IDS_HOP_COUNT, HopCount);
452344f3672SGed Murphy 
453*846c9aa1SStanislav Motylkov         if (LastGoodResponse)
454*846c9aa1SStanislav Motylkov         {
455*846c9aa1SStanislav Motylkov             HeapFree(heap, 0, LastGoodResponse);
456*846c9aa1SStanislav Motylkov             LastGoodResponse = NULL;
457*846c9aa1SStanislav Motylkov         }
458*846c9aa1SStanislav Motylkov 
459344f3672SGed Murphy         for (int Ping = 1; Ping <= NUM_OF_PINGS; Ping++)
460344f3672SGed Murphy         {
461*846c9aa1SStanislav Motylkov             BYTE SendBuffer[PACKET_SIZE];
462*846c9aa1SStanislav Motylkov             bool GoodResponse = false;
463*846c9aa1SStanislav Motylkov 
464344f3672SGed Murphy             IpOptionInfo.Ttl = static_cast<UCHAR>(HopCount);
465344f3672SGed Murphy 
466344f3672SGed Murphy             if (Info.Family == AF_INET6)
467344f3672SGed Murphy             {
468344f3672SGed Murphy                 struct sockaddr_in6 Source;
469344f3672SGed Murphy 
470344f3672SGed Murphy                 ZeroMemory(&Source, sizeof(Source));
471344f3672SGed Murphy                 Source.sin6_family = AF_INET6;
472344f3672SGed Murphy 
473344f3672SGed Murphy                 (void)Icmp6SendEcho2(Info.hIcmpFile,
474344f3672SGed Murphy                                      NULL,
475344f3672SGed Murphy                                      NULL,
476344f3672SGed Murphy                                      NULL,
477344f3672SGed Murphy                                      &Source,
478344f3672SGed Murphy                                      (struct sockaddr_in6 *)Info.Target->ai_addr,
479344f3672SGed Murphy                                      SendBuffer,
480344f3672SGed Murphy                                      (USHORT)PACKET_SIZE,
481344f3672SGed Murphy                                      &IpOptionInfo,
482344f3672SGed Murphy                                      ReplyBuffer,
483344f3672SGed Murphy                                      ReplySize,
484344f3672SGed Murphy                                      Info.Timeout);
485344f3672SGed Murphy             }
486344f3672SGed Murphy             else
487344f3672SGed Murphy             {
488344f3672SGed Murphy                 (void)IcmpSendEcho2(Info.hIcmpFile,
489344f3672SGed Murphy                                      NULL,
490344f3672SGed Murphy                                      NULL,
491344f3672SGed Murphy                                      NULL,
492344f3672SGed Murphy                                      ((PSOCKADDR_IN)Info.Target->ai_addr)->sin_addr.s_addr,
493344f3672SGed Murphy                                      SendBuffer,
494344f3672SGed Murphy                                      (USHORT)PACKET_SIZE,
495344f3672SGed Murphy                                      &IpOptionInfo,
496344f3672SGed Murphy                                      ReplyBuffer,
497344f3672SGed Murphy                                      ReplySize,
498344f3672SGed Murphy                                      Info.Timeout);
499344f3672SGed Murphy             }
500344f3672SGed Murphy 
501*846c9aa1SStanislav Motylkov             if (DecodeResponse(ReplyBuffer,
502*846c9aa1SStanislav Motylkov                                LastGoodResponse,
503*846c9aa1SStanislav Motylkov                                (Ping == NUM_OF_PINGS),
504*846c9aa1SStanislav Motylkov                                GoodResponse,
505*846c9aa1SStanislav Motylkov                                FoundTarget) == false)
506344f3672SGed Murphy             {
507344f3672SGed Murphy                 Quit = true;
508344f3672SGed Murphy                 break;
509344f3672SGed Murphy             }
510344f3672SGed Murphy 
511344f3672SGed Murphy             if (FoundTarget)
512344f3672SGed Murphy             {
513344f3672SGed Murphy                 Success = true;
514344f3672SGed Murphy                 break;
515344f3672SGed Murphy             }
516*846c9aa1SStanislav Motylkov 
517*846c9aa1SStanislav Motylkov             if (GoodResponse)
518*846c9aa1SStanislav Motylkov             {
519*846c9aa1SStanislav Motylkov                 if (LastGoodResponse)
520*846c9aa1SStanislav Motylkov                 {
521*846c9aa1SStanislav Motylkov                     HeapFree(heap, 0, LastGoodResponse);
522*846c9aa1SStanislav Motylkov                 }
523*846c9aa1SStanislav Motylkov                 LastGoodResponse = HeapAlloc(heap, HEAP_ZERO_MEMORY, ReplySize);
524*846c9aa1SStanislav Motylkov                 if (LastGoodResponse == NULL)
525*846c9aa1SStanislav Motylkov                 {
526*846c9aa1SStanislav Motylkov                     Success = false;
527*846c9aa1SStanislav Motylkov                     goto Cleanup;
528*846c9aa1SStanislav Motylkov                 }
529*846c9aa1SStanislav Motylkov                 CopyMemory(LastGoodResponse, ReplyBuffer, ReplySize);
530*846c9aa1SStanislav Motylkov             }
531344f3672SGed Murphy         }
532344f3672SGed Murphy 
533344f3672SGed Murphy         HopCount++;
534344f3672SGed Murphy         Sleep(100);
535344f3672SGed Murphy     }
536344f3672SGed Murphy 
537344f3672SGed Murphy     OutputText(IDS_TRACE_COMPLETE);
538344f3672SGed Murphy 
539*846c9aa1SStanislav Motylkov Cleanup:
540*846c9aa1SStanislav Motylkov     if (ReplyBuffer)
541*846c9aa1SStanislav Motylkov     {
5420ddf0a06SErdem Ersoy         HeapFree(heap, 0, ReplyBuffer);
543*846c9aa1SStanislav Motylkov     }
544*846c9aa1SStanislav Motylkov     if (LastGoodResponse)
545*846c9aa1SStanislav Motylkov     {
546*846c9aa1SStanislav Motylkov         HeapFree(heap, 0, LastGoodResponse);
547*846c9aa1SStanislav Motylkov     }
548*846c9aa1SStanislav Motylkov     if (Info.Target)
549*846c9aa1SStanislav Motylkov     {
550344f3672SGed Murphy         FreeAddrInfoW(Info.Target);
551*846c9aa1SStanislav Motylkov     }
552344f3672SGed Murphy     if (Info.hIcmpFile)
553344f3672SGed Murphy     {
554344f3672SGed Murphy         IcmpCloseHandle(Info.hIcmpFile);
555344f3672SGed Murphy     }
556344f3672SGed Murphy 
557344f3672SGed Murphy     return Success;
558344f3672SGed Murphy }
559344f3672SGed Murphy 
560344f3672SGed Murphy static bool
ParseCmdline(int argc,wchar_t * argv[])561344f3672SGed Murphy ParseCmdline(int argc, wchar_t *argv[])
562344f3672SGed Murphy {
563344f3672SGed Murphy     if (argc < 2)
564344f3672SGed Murphy     {
565344f3672SGed Murphy         Usage();
566344f3672SGed Murphy         return false;
567344f3672SGed Murphy     }
568344f3672SGed Murphy 
569344f3672SGed Murphy     for (int i = 1; i < argc; i++)
570344f3672SGed Murphy     {
571344f3672SGed Murphy         if (argv[i][0] == '-')
572344f3672SGed Murphy         {
573344f3672SGed Murphy             switch (argv[i][1])
574344f3672SGed Murphy             {
575344f3672SGed Murphy             case 'd':
576344f3672SGed Murphy                 Info.ResolveAddresses = FALSE;
577344f3672SGed Murphy                 break;
578344f3672SGed Murphy 
579344f3672SGed Murphy             case 'h':
580344f3672SGed Murphy                 Info.MaxHops = GetULONG(argv[++i]);
581344f3672SGed Murphy                 break;
582344f3672SGed Murphy 
583344f3672SGed Murphy             case 'j':
584344f3672SGed Murphy                 printf("-j is not yet implemented.\n");
585344f3672SGed Murphy                 return false;
586344f3672SGed Murphy 
587344f3672SGed Murphy             case 'w':
588344f3672SGed Murphy                 Info.Timeout = GetULONG(argv[++i]);
589344f3672SGed Murphy                 break;
590344f3672SGed Murphy 
591344f3672SGed Murphy             case '4':
592344f3672SGed Murphy                 Info.Family = AF_INET;
593344f3672SGed Murphy                 break;
594344f3672SGed Murphy 
595344f3672SGed Murphy             case '6':
596344f3672SGed Murphy                 Info.Family = AF_INET6;
597344f3672SGed Murphy                 break;
598344f3672SGed Murphy 
599344f3672SGed Murphy             default:
600344f3672SGed Murphy             {
601344f3672SGed Murphy                 OutputText(IDS_INVALID_OPTION, argv[i]);
602344f3672SGed Murphy                 Usage();
603344f3672SGed Murphy                 return false;
604344f3672SGed Murphy             }
605344f3672SGed Murphy             }
606344f3672SGed Murphy         }
607344f3672SGed Murphy         else
608344f3672SGed Murphy         {
609344f3672SGed Murphy             StringCchCopyW(Info.HostName, NI_MAXHOST, argv[i]);
610344f3672SGed Murphy             break;
611344f3672SGed Murphy         }
612344f3672SGed Murphy     }
613344f3672SGed Murphy 
614344f3672SGed Murphy     return true;
615344f3672SGed Murphy }
616344f3672SGed Murphy 
617344f3672SGed Murphy EXTERN_C
wmain(int argc,wchar_t * argv[])618344f3672SGed Murphy int wmain(int argc, wchar_t *argv[])
619344f3672SGed Murphy {
6203d66048bSJoachim Henze #ifdef USE_CONUTILS
6213d66048bSJoachim Henze     /* Initialize the Console Standard Streams */
6223d66048bSJoachim Henze     ConInitStdStreams();
6233d66048bSJoachim Henze #endif
6243d66048bSJoachim Henze 
625344f3672SGed Murphy     Info.ResolveAddresses = true;
626344f3672SGed Murphy     Info.MaxHops = 30;
627344f3672SGed Murphy     Info.Timeout = 4000;
628344f3672SGed Murphy     Info.Family = AF_UNSPEC;
629344f3672SGed Murphy 
630344f3672SGed Murphy     if (!ParseCmdline(argc, argv))
631344f3672SGed Murphy     {
632344f3672SGed Murphy         return 1;
633344f3672SGed Murphy     }
634344f3672SGed Murphy 
635344f3672SGed Murphy     WSADATA WsaData;
636344f3672SGed Murphy     if (WSAStartup(MAKEWORD(2, 2), &WsaData))
637344f3672SGed Murphy     {
638344f3672SGed Murphy         return 1;
639344f3672SGed Murphy     }
640344f3672SGed Murphy 
641344f3672SGed Murphy     bool Success;
642344f3672SGed Murphy     Success = RunTraceRoute();
643344f3672SGed Murphy 
644344f3672SGed Murphy     WSACleanup();
645344f3672SGed Murphy 
646344f3672SGed Murphy     return Success ? 0 : 1;
647344f3672SGed Murphy }
648