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