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