Start to alter print output so it correctly simulates the MS 'route print'
[reactos.git] / reactos / apps / utils / net / netstat / netstat.c
1 /*
2 * netstat - display IP stack statistics.
3 *
4 * This source code is in the PUBLIC DOMAIN and has NO WARRANTY.
5 *
6 * Robert Dickenson <robd@reactos.org>, August 15, 2002.
7 */
8
9 // Extensive reference made and use of source to netstatp by:
10 // Copyright (C) 1998-2002 Mark Russinovich
11 // www.sysinternals.com
12
13 #define ANY_SIZE 1
14
15 #include <windows.h>
16 #include <winsock.h>
17 #include <tchar.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <time.h>
21
22 #include <iptypes.h>
23 #include <ipexport.h>
24 #include <tlhelp32.h>
25 #include <iphlpapi.h>
26 #include <snmp.h>
27
28 #include "trace.h"
29 #include "resource.h"
30
31
32 #define MAX_RESLEN 4000
33
34 //
35 // Possible TCP endpoint states
36 //
37 static char TcpState[][32] = {
38 "???",
39 "CLOSED",
40 "LISTENING",
41 "SYN_SENT",
42 "SYN_RCVD",
43 "ESTABLISHED",
44 "FIN_WAIT1",
45 "FIN_WAIT2",
46 "CLOSE_WAIT",
47 "CLOSING",
48 "LAST_ACK",
49 "TIME_WAIT",
50 "DELETE_TCB"
51 };
52
53 VOID PrintError(DWORD ErrorCode)
54 {
55 LPVOID lpMsgBuf;
56
57 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
58 NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
59 (LPTSTR)&lpMsgBuf, 0, NULL);
60 printf("%s\n", (TCHAR*)lpMsgBuf);
61 LocalFree(lpMsgBuf);
62 }
63
64 #if 0
65 static void ShowTcpStatistics()
66 {
67 MIB_TCPSTATS TcpStatsMIB;
68 GetTcpStatistics(&TcpStatsMIB);
69
70 _tprintf(_T("TCP/IP Statistics\t\n"));
71 _tprintf(_T(" time-out algorithm:\t\t%lu\n"), TcpStatsMIB.dwRtoAlgorithm);
72 _tprintf(_T(" minimum time-out:\t\t%lu\n"), TcpStatsMIB.dwRtoMin);
73 _tprintf(_T(" maximum time-out:\t\t%lu\n"), TcpStatsMIB.dwRtoMax);
74 _tprintf(_T(" maximum connections:\t\t%lu\n"), TcpStatsMIB.dwMaxConn);
75 _tprintf(_T(" active opens:\t\t\t%lu\n"), TcpStatsMIB.dwActiveOpens);
76 _tprintf(_T(" passive opens:\t\t\t%lu\n"), TcpStatsMIB.dwPassiveOpens);
77 _tprintf(_T(" failed attempts:\t\t%lu\n"), TcpStatsMIB.dwAttemptFails);
78 _tprintf(_T(" established connections reset:\t%lu\n"), TcpStatsMIB.dwEstabResets);
79 _tprintf(_T(" established connections:\t%lu\n"), TcpStatsMIB.dwCurrEstab);
80 _tprintf(_T(" segments received:\t\t%lu\n"), TcpStatsMIB.dwInSegs);
81 _tprintf(_T(" segment sent:\t\t\t%lu\n"), TcpStatsMIB.dwOutSegs);
82 _tprintf(_T(" segments retransmitted:\t\t%lu\n"), TcpStatsMIB.dwRetransSegs);
83 _tprintf(_T(" incoming errors:\t\t%lu\n"), TcpStatsMIB.dwInErrs);
84 _tprintf(_T(" outgoing resets:\t\t%lu\n"), TcpStatsMIB.dwOutRsts);
85 _tprintf(_T(" cumulative connections:\t\t%lu\n"), TcpStatsMIB.dwNumConns);
86 }
87
88 static void ShowUdpStatistics()
89 {
90 MIB_UDPSTATS UDPStatsMIB;
91 GetUdpStatistics(&UDPStatsMIB);
92
93 _tprintf(_T("UDP Statistics\t\n"));
94 _tprintf(_T(" received datagrams:\t\t\t%lu\n"), UDPStatsMIB.dwInDatagrams);
95 _tprintf(_T(" datagrams for which no port exists:\t%lu\n"), UDPStatsMIB.dwNoPorts);
96 _tprintf(_T(" errors on received datagrams:\t\t%lu\n"), UDPStatsMIB.dwInErrors);
97 _tprintf(_T(" sent datagrams:\t\t\t\t%lu\n"), UDPStatsMIB.dwOutDatagrams);
98 _tprintf(_T(" number of entries in listener table:\t%lu\n"), UDPStatsMIB.dwNumAddrs);
99 }
100
101 static void ShowIpStatistics()
102 {
103 MIB_IPSTATS IPStatsMIB;
104 GetIpStatistics(&IPStatsMIB);
105
106 _tprintf(_T("IP Statistics\t\n"));
107 _tprintf(_T(" IP forwarding enabled or disabled:\t%lu\n"), IPStatsMIB.dwForwarding);
108 _tprintf(_T(" default time-to-live:\t\t\t%lu\n"), IPStatsMIB.dwDefaultTTL);
109 _tprintf(_T(" datagrams received:\t\t\t%lu\n"), IPStatsMIB.dwInReceives);
110 _tprintf(_T(" received header errors:\t\t\t%lu\n"), IPStatsMIB.dwInHdrErrors);
111 _tprintf(_T(" received address errors:\t\t%lu\n"), IPStatsMIB.dwInAddrErrors);
112 _tprintf(_T(" datagrams forwarded:\t\t\t%lu\n"), IPStatsMIB.dwForwDatagrams);
113 _tprintf(_T(" datagrams with unknown protocol:\t%lu\n"), IPStatsMIB.dwInUnknownProtos);
114 _tprintf(_T(" received datagrams discarded:\t\t%lu\n"), IPStatsMIB.dwInDiscards);
115 _tprintf(_T(" received datagrams delivered:\t\t%lu\n"), IPStatsMIB.dwInDelivers);
116 _tprintf(_T(" sent datagrams discarded:\t\t%lu\n"), IPStatsMIB.dwOutDiscards);
117 _tprintf(_T(" datagrams for which no route exists:\t%lu\n"), IPStatsMIB.dwOutNoRoutes);
118 _tprintf(_T(" datagrams for which frags didn't arrive:%lu\n"), IPStatsMIB.dwReasmTimeout);
119 _tprintf(_T(" datagrams requiring reassembly:\t\t%lu\n"), IPStatsMIB.dwReasmReqds);
120 _tprintf(_T(" successful reassemblies:\t\t%lu\n"), IPStatsMIB.dwReasmOks);
121 _tprintf(_T(" failed reassemblies:\t\t\t%lu\n"), IPStatsMIB.dwReasmFails);
122 _tprintf(_T(" successful fragmentations:\t\t%lu\n"), IPStatsMIB.dwFragOks);
123 _tprintf(_T(" failed fragmentations:\t\t\t%lu\n"), IPStatsMIB.dwFragFails);
124 _tprintf(_T(" datagrams fragmented:\t\t\t%lu\n"), IPStatsMIB.dwFragCreates);
125 _tprintf(_T(" number of interfaces on computer:\t%lu\n"), IPStatsMIB.dwNumIf);
126 _tprintf(_T(" number of IP address on computer:\t%lu\n"), IPStatsMIB.dwNumAddr);
127 _tprintf(_T(" number of routes in routing table:\t%lu\n"), IPStatsMIB.dwNumRoutes);
128 }
129
130 static void ShowNetworkParams()
131 {
132 FIXED_INFO* FixedInfo;
133 IP_ADDR_STRING* pIPAddr;
134 ULONG ulOutBufLen;
135 DWORD dwRetVal;
136
137 _tprintf(_T("Network Parameters\t\n"));
138
139 FixedInfo = (FIXED_INFO*)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
140 ulOutBufLen = sizeof(FIXED_INFO);
141 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &ulOutBufLen)) {
142 GlobalFree(FixedInfo);
143 FixedInfo =(FIXED_INFO*)GlobalAlloc(GPTR, ulOutBufLen);
144 }
145 if ((dwRetVal = GetNetworkParams(FixedInfo, &ulOutBufLen))) {
146 _tprintf(_T("Call to GetNetworkParams failed. Return Value: 0x%08lx\n"), dwRetVal);
147 } else {
148 printf(" Host Name: %s", FixedInfo->HostName);
149 printf("\n Domain Name: %s", FixedInfo->DomainName);
150 printf("\n DNS Servers:\t%s\n", FixedInfo->DnsServerList.IpAddress.String);
151 pIPAddr = FixedInfo->DnsServerList.Next;
152 while (pIPAddr) {
153 printf("\t\t\t%s\n", pIPAddr->IpAddress.String);
154 pIPAddr = pIPAddr->Next;
155 }
156 }
157 }
158
159 static void ShowAdapterInfo()
160 {
161 IP_ADAPTER_INFO* pAdaptorInfo;
162 ULONG ulOutBufLen;
163 DWORD dwRetVal;
164
165 _tprintf(_T("\nAdaptor Information\t\n"));
166 pAdaptorInfo = (IP_ADAPTER_INFO*)GlobalAlloc(GPTR, sizeof(IP_ADAPTER_INFO));
167 ulOutBufLen = sizeof(IP_ADAPTER_INFO);
168
169 if (ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(pAdaptorInfo, &ulOutBufLen)) {
170 GlobalFree(pAdaptorInfo);
171 pAdaptorInfo = (IP_ADAPTER_INFO*)GlobalAlloc(GPTR, ulOutBufLen);
172 }
173 if ((dwRetVal = GetAdaptersInfo(pAdaptorInfo, &ulOutBufLen))) {
174 _tprintf(_T("Call to GetAdaptersInfo failed. Return Value: 0x%08lx\n"), dwRetVal);
175 } else {
176 while (pAdaptorInfo) {
177 printf(" AdapterName: %s\n", pAdaptorInfo->AdapterName);
178 printf(" Description: %s\n", pAdaptorInfo->Description);
179 pAdaptorInfo = pAdaptorInfo->Next;
180 }
181 }
182 }
183 #endif
184
185 /*
186 typedef struct {
187 UINT idLength;
188 UINT* ids;
189 } AsnObjectIdentifier;
190
191 VOID SnmpUtilPrintAsnAny(AsnAny* pAny); // pointer to value to print
192 VOID SnmpUtilPrintOid(AsnObjectIdentifier* Oid); // object identifier to print
193
194 */
195 void test_snmp(void)
196 {
197 int nBytes = 500;
198 BYTE* pCache;
199
200 pCache = (BYTE*)SnmpUtilMemAlloc(nBytes);
201 if (pCache != NULL) {
202 AsnObjectIdentifier* pOidSrc = NULL;
203 AsnObjectIdentifier AsnObId;
204 if (SnmpUtilOidCpy(&AsnObId, pOidSrc)) {
205 //
206 //
207 //
208 SnmpUtilOidFree(&AsnObId);
209 }
210 SnmpUtilMemFree(pCache);
211 } else {
212 _tprintf(_T("ERROR: call to SnmpUtilMemAlloc() failed\n"));
213 }
214 }
215
216 // Maximum string lengths for ASCII ip address and port names
217 //
218 #define HOSTNAMELEN 256
219 #define PORTNAMELEN 256
220 #define ADDRESSLEN HOSTNAMELEN+PORTNAMELEN
221
222 //
223 // Our option flags
224 //
225 #define FLAG_SHOW_ALL_ENDPOINTS 1
226 #define FLAG_SHOW_ETH_STATS 2
227 #define FLAG_SHOW_NUMBERS 3
228 #define FLAG_SHOW_PROT_CONNECTIONS 4
229 #define FLAG_SHOW_ROUTE_TABLE 5
230 #define FLAG_SHOW_PROT_STATS 6
231 #define FLAG_SHOW_INTERVAL 7
232
233
234 // Undocumented extended information structures available only on XP and higher
235
236 typedef struct {
237 DWORD dwState; // state of the connection
238 DWORD dwLocalAddr; // address on local computer
239 DWORD dwLocalPort; // port number on local computer
240 DWORD dwRemoteAddr; // address on remote computer
241 DWORD dwRemotePort; // port number on remote computer
242 DWORD dwProcessId;
243 } MIB_TCPEXROW, *PMIB_TCPEXROW;
244
245 typedef struct {
246 DWORD dwNumEntries;
247 MIB_TCPEXROW table[ANY_SIZE];
248 } MIB_TCPEXTABLE, *PMIB_TCPEXTABLE;
249
250 typedef struct {
251 DWORD dwLocalAddr; // address on local computer
252 DWORD dwLocalPort; // port number on local computer
253 DWORD dwProcessId;
254 } MIB_UDPEXROW, *PMIB_UDPEXROW;
255
256 typedef struct {
257 DWORD dwNumEntries;
258 MIB_UDPEXROW table[ANY_SIZE];
259 } MIB_UDPEXTABLE, *PMIB_UDPEXTABLE;
260
261
262 //
263 // GetPortName
264 //
265 // Translate port numbers into their text equivalent if there is one
266 //
267 PCHAR
268 GetPortName(DWORD Flags, UINT port, PCHAR proto, PCHAR name, int namelen)
269 {
270 struct servent *psrvent;
271
272 if (Flags & FLAG_SHOW_NUMBERS) {
273 sprintf(name, "%d", htons((WORD)port));
274 return name;
275 }
276 // Try to translate to a name
277 if ((psrvent = getservbyport(port, proto))) {
278 strcpy(name, psrvent->s_name );
279 } else {
280 sprintf(name, "%d", htons((WORD)port));
281 }
282 return name;
283 }
284
285
286 //
287 // GetIpHostName
288 //
289 // Translate IP addresses into their name-resolved form if possible.
290 //
291 PCHAR
292 GetIpHostName(DWORD Flags, BOOL local, UINT ipaddr, PCHAR name, int namelen)
293 {
294 // struct hostent *phostent;
295 UINT nipaddr;
296
297 // Does the user want raw numbers?
298 nipaddr = htonl(ipaddr);
299 if (Flags & FLAG_SHOW_NUMBERS ) {
300 sprintf(name, "%d.%d.%d.%d",
301 (nipaddr >> 24) & 0xFF,
302 (nipaddr >> 16) & 0xFF,
303 (nipaddr >> 8) & 0xFF,
304 (nipaddr) & 0xFF);
305 return name;
306 }
307
308 name[0] = _T('\0');
309
310 // Try to translate to a name
311 if (!ipaddr) {
312 if (!local) {
313 sprintf(name, "%d.%d.%d.%d",
314 (nipaddr >> 24) & 0xFF,
315 (nipaddr >> 16) & 0xFF,
316 (nipaddr >> 8) & 0xFF,
317 (nipaddr) & 0xFF);
318 } else {
319 //gethostname(name, namelen);
320 }
321 } else if (ipaddr == 0x0100007f) {
322 if (local) {
323 //gethostname(name, namelen);
324 } else {
325 strcpy(name, "localhost");
326 }
327 // } else if (phostent = gethostbyaddr((char*)&ipaddr, sizeof(nipaddr), PF_INET)) {
328 // strcpy(name, phostent->h_name);
329 } else {
330 #if 0
331 int i1, i2, i3, i4;
332
333 i1 = (nipaddr >> 24) & 0x000000FF;
334 i2 = (nipaddr >> 16) & 0x000000FF;
335 i3 = (nipaddr >> 8) & 0x000000FF;
336 i4 = (nipaddr) & 0x000000FF;
337
338 i1 = 10;
339 i2 = 20;
340 i3 = 30;
341 i4 = 40;
342
343 sprintf(name, "%d.%d.%d.%d", i1,i2,i3,i4);
344 #else
345 sprintf(name, "%d.%d.%d.%d",
346 ((nipaddr >> 24) & 0x000000FF),
347 ((nipaddr >> 16) & 0x000000FF),
348 ((nipaddr >> 8) & 0x000000FF),
349 ((nipaddr) & 0x000000FF));
350 #endif
351 }
352 return name;
353 }
354
355 BOOLEAN usage(void)
356 {
357 TCHAR buffer[MAX_RESLEN];
358
359 LoadString(GetModuleHandle(NULL), IDS_APP_USAGE, buffer, sizeof(buffer)/sizeof(buffer[0]));
360 _fputts(buffer, stderr);
361 return FALSE;
362 }
363
364 //
365 // GetOptions
366 //
367 // Parses the command line arguments.
368 //
369 BOOLEAN
370 GetOptions(int argc, char *argv[], PDWORD pFlags)
371 {
372 int i, j;
373 BOOLEAN skipArgument;
374
375 *pFlags = 0;
376 for (i = 1; i < argc; i++) {
377 skipArgument = FALSE;
378 switch (argv[i][0]) {
379 case '-':
380 case '/':
381 j = 1;
382 while (argv[i][j]) {
383 switch (toupper(argv[i][j])) {
384 case 'A':
385 *pFlags |= FLAG_SHOW_ALL_ENDPOINTS;
386 break;
387 case 'E':
388 *pFlags |= FLAG_SHOW_ETH_STATS;
389 break;
390 case 'N':
391 *pFlags |= FLAG_SHOW_NUMBERS;
392 break;
393 case 'P':
394 *pFlags |= FLAG_SHOW_PROT_CONNECTIONS;
395 break;
396 case 'R':
397 *pFlags |= FLAG_SHOW_ROUTE_TABLE;
398 break;
399 case 'S':
400 *pFlags |= FLAG_SHOW_PROT_STATS;
401 break;
402 default:
403 return usage();
404 }
405 if (skipArgument) break;
406 j++;
407 }
408 break;
409 case 'i':
410 *pFlags |= FLAG_SHOW_INTERVAL;
411 break;
412 default:
413 return usage();
414 }
415 }
416 return TRUE;
417 }
418
419 #if 1
420
421 CHAR localname[HOSTNAMELEN], remotename[HOSTNAMELEN];
422 CHAR remoteport[PORTNAMELEN], localport[PORTNAMELEN];
423 CHAR localaddr[ADDRESSLEN], remoteaddr[ADDRESSLEN];
424
425 int main(int argc, char *argv[])
426 {
427 PMIB_TCPTABLE tcpTable;
428 PMIB_UDPTABLE udpTable;
429 DWORD error, dwSize;
430 DWORD i, flags;
431
432 // Get options
433 if (!GetOptions(argc, argv, &flags)) {
434 return -1;
435 } else {
436 // Get the table of TCP endpoints
437 dwSize = 0;
438 error = GetTcpTable(NULL, &dwSize, TRUE);
439 if (error != ERROR_INSUFFICIENT_BUFFER) {
440 printf("Failed to snapshot TCP endpoints.\n");
441 PrintError(error);
442 return -1;
443 }
444 tcpTable = (PMIB_TCPTABLE)malloc(dwSize);
445 error = GetTcpTable(tcpTable, &dwSize, TRUE );
446 if (error) {
447 printf("Failed to snapshot TCP endpoints table.\n");
448 PrintError(error);
449 return -1;
450 }
451
452 // Get the table of UDP endpoints
453 dwSize = 0;
454 error = GetUdpTable(NULL, &dwSize, TRUE);
455 if (error != ERROR_INSUFFICIENT_BUFFER) {
456 printf("Failed to snapshot UDP endpoints.\n");
457 PrintError(error);
458 return -1;
459 }
460 udpTable = (PMIB_UDPTABLE)malloc(dwSize);
461 error = GetUdpTable(udpTable, &dwSize, TRUE);
462 if (error) {
463 printf("Failed to snapshot UDP endpoints table.\n");
464 PrintError(error);
465 return -1;
466 }
467
468 // Dump the TCP table
469 for (i = 0; i < tcpTable->dwNumEntries; i++) {
470 if (flags & FLAG_SHOW_ALL_ENDPOINTS ||
471 tcpTable->table[i].dwState == MIB_TCP_STATE_ESTAB) {
472 sprintf(localaddr, "%s:%s",
473 GetIpHostName(flags, TRUE, tcpTable->table[i].dwLocalAddr, localname, HOSTNAMELEN),
474 GetPortName(flags, tcpTable->table[i].dwLocalPort, "tcp", localport, PORTNAMELEN));
475 sprintf(remoteaddr, "%s:%s",
476 GetIpHostName(flags, FALSE, tcpTable->table[i].dwRemoteAddr, remotename, HOSTNAMELEN),
477 tcpTable->table[i].dwRemoteAddr ?
478 GetPortName(flags, tcpTable->table[i].dwRemotePort, "tcp", remoteport, PORTNAMELEN):
479 "0");
480 printf("%4s\tState: %s\n", "[TCP]", TcpState[tcpTable->table[i].dwState]);
481 printf(" Local: %s\n Remote: %s\n", localaddr, remoteaddr);
482 }
483 }
484 // Dump the UDP table
485 if (flags & FLAG_SHOW_ALL_ENDPOINTS) {
486 for (i = 0; i < udpTable->dwNumEntries; i++) {
487 sprintf(localaddr, "%s:%s",
488 GetIpHostName(flags, TRUE, udpTable->table[i].dwLocalAddr, localname, HOSTNAMELEN),
489 GetPortName(flags, udpTable->table[i].dwLocalPort, "tcp", localport, PORTNAMELEN));
490 printf("%4s", "[UDP]");
491 printf(" Local: %s\n Remote: %s\n", localaddr, "*.*.*.*:*");
492 }
493 }
494 }
495 printf("\n");
496 return 0;
497 }
498
499 #else
500
501 int main(int argc, char *argv[])
502 {
503 if (argc > 1) {
504 usage();
505 return 1;
506 }
507
508 _tprintf(_T("\nActive Connections\n\n")\
509 _T(" Proto Local Address Foreign Address State\n\n"));
510 test_snmp();
511
512 ShowTcpStatistics();
513 ShowUdpStatistics();
514 ShowIpStatistics();
515 ShowNetworkParams();
516 ShowAdapterInfo();
517
518 return 0;
519 }
520
521 #endif