[NETSTAT] Add support for displaying TCP connections owning process
[reactos.git] / base / applications / network / netstat / netstat.c
1 /*
2 * PROJECT: ReactOS netstat utility
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/network/netstat/netstat.c
5 * PURPOSE: display IP stack statistics
6 * COPYRIGHT: Copyright 2005 Ged Murphy <gedmurphy@gmail.com>
7 */
8 /*
9 * TODO:
10 * sort function return values.
11 * implement -b, -o and -v
12 * clean up GetIpHostName
13 * command line parser needs more work
14 */
15
16 #define WIN32_NO_STATUS
17 #include <stdarg.h>
18 #include <windef.h>
19 #include <winbase.h>
20 #define _INC_WINDOWS
21 #include <winsock2.h>
22 #include <tchar.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <iphlpapi.h>
26
27 #include "netstat.h"
28
29 enum ProtoType {IP, TCP, UDP, ICMP} Protocol;
30 DWORD Interval; /* time to pause between printing output */
31
32 /* TCP endpoint states */
33 TCHAR TcpState[][32] = {
34 _T("???"),
35 _T("CLOSED"),
36 _T("LISTENING"),
37 _T("SYN_SENT"),
38 _T("SYN_RCVD"),
39 _T("ESTABLISHED"),
40 _T("FIN_WAIT1"),
41 _T("FIN_WAIT2"),
42 _T("CLOSE_WAIT"),
43 _T("CLOSING"),
44 _T("LAST_ACK"),
45 _T("TIME_WAIT"),
46 _T("DELETE_TCB")
47 };
48
49 /*
50 * format message string and display output
51 */
52 DWORD DoFormatMessage(DWORD ErrorCode)
53 {
54 LPVOID lpMsgBuf;
55 DWORD RetVal;
56
57 if ((RetVal = FormatMessage(
58 FORMAT_MESSAGE_ALLOCATE_BUFFER |
59 FORMAT_MESSAGE_FROM_SYSTEM |
60 FORMAT_MESSAGE_IGNORE_INSERTS,
61 NULL,
62 ErrorCode,
63 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
64 (LPTSTR) &lpMsgBuf,
65 0,
66 NULL )))
67 {
68 _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
69
70 LocalFree(lpMsgBuf);
71 /* return number of TCHAR's stored in output buffer
72 * excluding '\0' - as FormatMessage does*/
73 return RetVal;
74 }
75 else
76 return 0;
77 }
78
79 /*
80 *
81 * Parse command line parameters and set any options
82 *
83 */
84 BOOL ParseCmdline(int argc, char* argv[])
85 {
86 LPSTR Proto;
87 CHAR c;
88 INT i;
89
90 if ((argc == 1) || (_istdigit(*argv[1])))
91 bNoOptions = TRUE;
92
93 /* Parse command line for options we have been given. */
94 for (i = 1; i < argc; i++)
95 {
96 if ((argc > 1) && (argv[i][0] == '-' || argv[i][0] == '/'))
97 {
98 while ((c = *++argv[i]) != '\0')
99 {
100 switch (tolower(c))
101 {
102 case 'a' :
103 bDoShowAllCons = TRUE;
104 break;
105 case 'b' :
106 bDoShowProcName = TRUE;
107 break;
108 case 'e' :
109 bDoShowEthStats = TRUE;
110 break;
111 case 'n' :
112 bDoShowNumbers = TRUE;
113 break;
114 case 'p' :
115 bDoShowProtoCons = TRUE;
116 Proto = argv[i+1];
117 if (!_stricmp("IP", Proto))
118 Protocol = IP;
119 else if (!_stricmp("ICMP", Proto))
120 Protocol = ICMP;
121 else if (!_stricmp("TCP", Proto))
122 Protocol = TCP;
123 else if (!_stricmp("UDP", Proto))
124 Protocol = UDP;
125 else
126 {
127 Usage();
128 return EXIT_FAILURE;
129 }
130 break;
131 case 'r' :
132 bDoShowRouteTable = TRUE;
133 break;
134 case 's' :
135 bDoShowProtoStats = TRUE;
136 break;
137 case 'o' :
138 bDoShowProcessId = TRUE;
139 break;
140 case 'v' :
141 _tprintf(_T("got v\n"));
142 bDoDispSeqComp = TRUE;
143 break;
144 default :
145 Usage();
146 return EXIT_FAILURE;
147 }
148 }
149 }
150 else if (_istdigit(*argv[i]))
151 {
152 if (_stscanf(argv[i], "%lu", &Interval) != EOF)
153 bLoopOutput = TRUE;
154 else
155 return EXIT_FAILURE;
156 }
157 // else
158 // {
159 // Usage();
160 // EXIT_FAILURE;
161 // }
162 }
163
164 return EXIT_SUCCESS;
165 }
166
167 /*
168 * Display table header
169 */
170 VOID DisplayTableHeader()
171 {
172 _tprintf(_T("\n Proto Local Address Foreign Address State"));
173 if (bDoShowProcessId)
174 _tprintf(_T(" Process\n"));
175 else
176 _tprintf(_T("\n"));
177 }
178
179
180 /*
181 * Simulate Microsofts netstat utility output
182 */
183 BOOL DisplayOutput()
184 {
185 if (bNoOptions)
186 {
187 DisplayTableHeader();
188 ShowTcpTable();
189 return EXIT_SUCCESS;
190 }
191
192 if (bDoShowRouteTable)
193 {
194 /* mingw doesn't have lib for _tsystem */
195 if (system("route print") == -1)
196 {
197 _tprintf(_T("cannot find 'route.exe'\n"));
198 return EXIT_FAILURE;
199 }
200 return EXIT_SUCCESS;
201 }
202
203 if (bDoShowEthStats)
204 {
205 ShowEthernetStatistics();
206 return EXIT_SUCCESS;
207 }
208
209 if (bDoShowProtoCons)
210 {
211 switch (Protocol)
212 {
213 case IP :
214 if (bDoShowProtoStats)
215 {
216 ShowIpStatistics();
217 return EXIT_SUCCESS;
218 }
219 break;
220 case ICMP :
221 if (bDoShowProtoStats)
222 {
223 ShowIcmpStatistics();
224 return EXIT_SUCCESS;
225 }
226 break;
227 case TCP :
228 if (bDoShowProtoStats)
229 ShowTcpStatistics();
230 _tprintf(_T("\nActive Connections\n"));
231 DisplayTableHeader();
232 ShowTcpTable();
233 break;
234 case UDP :
235 if (bDoShowProtoStats)
236 ShowUdpStatistics();
237 _tprintf(_T("\nActive Connections\n"));
238 DisplayTableHeader();
239 ShowUdpTable();
240 break;
241 default :
242 break;
243 }
244 }
245 else if (bDoShowProtoStats)
246 {
247 ShowIpStatistics();
248 ShowIcmpStatistics();
249 ShowTcpStatistics();
250 ShowUdpStatistics();
251 return EXIT_SUCCESS;
252 }
253 else
254 {
255 _tprintf(_T("\nActive Connections\n"));
256 DisplayTableHeader();
257 ShowTcpTable();
258 if (bDoShowAllCons)
259 ShowUdpTable();
260 }
261 return EXIT_SUCCESS;
262 }
263
264 VOID ShowIpStatistics()
265 {
266 PMIB_IPSTATS pIpStats;
267 DWORD dwRetVal;
268
269 pIpStats = (MIB_IPSTATS*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPSTATS));
270
271 if ((dwRetVal = GetIpStatistics(pIpStats)) == NO_ERROR)
272 {
273 _tprintf(_T("\nIPv4 Statistics\n\n"));
274 _tprintf(_T(" %-34s = %lu\n"), _T("Packets Received"), pIpStats->dwInReceives);
275 _tprintf(_T(" %-34s = %lu\n"), _T("Received Header Errors"), pIpStats->dwInHdrErrors);
276 _tprintf(_T(" %-34s = %lu\n"), _T("Received Address Errors"), pIpStats->dwInAddrErrors);
277 _tprintf(_T(" %-34s = %lu\n"), _T("Datagrams Forwarded"), pIpStats->dwForwDatagrams);
278 _tprintf(_T(" %-34s = %lu\n"), _T("Unknown Protocols Received"), pIpStats->dwInUnknownProtos);
279 _tprintf(_T(" %-34s = %lu\n"), _T("Received Packets Discarded"), pIpStats->dwInDiscards);
280 _tprintf(_T(" %-34s = %lu\n"), _T("Received Packets Delivered"), pIpStats->dwInDelivers);
281 _tprintf(_T(" %-34s = %lu\n"), _T("Output Requests"), pIpStats->dwOutRequests);
282 _tprintf(_T(" %-34s = %lu\n"), _T("Routing Discards"), pIpStats->dwRoutingDiscards);
283 _tprintf(_T(" %-34s = %lu\n"), _T("Discarded Output Packets"), pIpStats->dwOutDiscards);
284 _tprintf(_T(" %-34s = %lu\n"), _T("Output Packets No Route"), pIpStats->dwOutNoRoutes);
285 _tprintf(_T(" %-34s = %lu\n"), _T("Reassembly Required"), pIpStats->dwReasmReqds);
286 _tprintf(_T(" %-34s = %lu\n"), _T("Reassembly Succesful"), pIpStats->dwReasmOks);
287 _tprintf(_T(" %-34s = %lu\n"), _T("Reassembly Failures"), pIpStats->dwReasmFails);
288 // _tprintf(_T(" %-34s = %lu\n"), _T("Datagrams successfully fragmented"), NULL); /* FIXME: what is this one? */
289 _tprintf(_T(" %-34s = %lu\n"), _T("Datagrams Failing Fragmentation"), pIpStats->dwFragFails);
290 _tprintf(_T(" %-34s = %lu\n"), _T("Fragments Created"), pIpStats->dwFragCreates);
291 }
292 else
293 DoFormatMessage(dwRetVal);
294
295 HeapFree(GetProcessHeap(), 0, pIpStats);
296 }
297
298 VOID ShowIcmpStatistics()
299 {
300 PMIB_ICMP pIcmpStats;
301 DWORD dwRetVal;
302
303 pIcmpStats = (MIB_ICMP*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_ICMP));
304
305 if ((dwRetVal = GetIcmpStatistics(pIcmpStats)) == NO_ERROR)
306 {
307 _tprintf(_T("\nICMPv4 Statistics\n\n"));
308 _tprintf(_T(" Received Sent\n"));
309 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Messages"),
310 pIcmpStats->stats.icmpInStats.dwMsgs, pIcmpStats->stats.icmpOutStats.dwMsgs);
311 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Errors"),
312 pIcmpStats->stats.icmpInStats.dwErrors, pIcmpStats->stats.icmpOutStats.dwErrors);
313 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Destination Unreachable"),
314 pIcmpStats->stats.icmpInStats.dwDestUnreachs, pIcmpStats->stats.icmpOutStats.dwDestUnreachs);
315 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Time Exceeded"),
316 pIcmpStats->stats.icmpInStats.dwTimeExcds, pIcmpStats->stats.icmpOutStats.dwTimeExcds);
317 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Parameter Problems"),
318 pIcmpStats->stats.icmpInStats.dwParmProbs, pIcmpStats->stats.icmpOutStats.dwParmProbs);
319 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Source Quenches"),
320 pIcmpStats->stats.icmpInStats.dwSrcQuenchs, pIcmpStats->stats.icmpOutStats.dwSrcQuenchs);
321 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Redirects"),
322 pIcmpStats->stats.icmpInStats.dwRedirects, pIcmpStats->stats.icmpOutStats.dwRedirects);
323 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Echos"),
324 pIcmpStats->stats.icmpInStats.dwEchos, pIcmpStats->stats.icmpOutStats.dwEchos);
325 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Echo Replies"),
326 pIcmpStats->stats.icmpInStats.dwEchoReps, pIcmpStats->stats.icmpOutStats.dwEchoReps);
327 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Timestamps"),
328 pIcmpStats->stats.icmpInStats.dwTimestamps, pIcmpStats->stats.icmpOutStats.dwTimestamps);
329 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Timestamp Replies"),
330 pIcmpStats->stats.icmpInStats.dwTimestampReps, pIcmpStats->stats.icmpOutStats.dwTimestampReps);
331 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Address Masks"),
332 pIcmpStats->stats.icmpInStats.dwAddrMasks, pIcmpStats->stats.icmpOutStats.dwAddrMasks);
333 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Address Mask Replies"),
334 pIcmpStats->stats.icmpInStats.dwAddrMaskReps, pIcmpStats->stats.icmpOutStats.dwAddrMaskReps);
335 }
336 else
337 DoFormatMessage(dwRetVal);
338
339 HeapFree(GetProcessHeap(), 0, pIcmpStats);
340
341 }
342
343 VOID ShowTcpStatistics()
344 {
345 PMIB_TCPSTATS pTcpStats;
346 DWORD dwRetVal;
347
348 pTcpStats = (MIB_TCPSTATS*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_TCPSTATS));
349
350 if ((dwRetVal = GetTcpStatistics(pTcpStats)) == NO_ERROR)
351 {
352 _tprintf(_T("\nTCP Statistics for IPv4\n\n"));
353 _tprintf(_T(" %-35s = %lu\n"), _T("Active Opens"), pTcpStats->dwActiveOpens);
354 _tprintf(_T(" %-35s = %lu\n"), _T("Passive Opens"), pTcpStats->dwPassiveOpens);
355 _tprintf(_T(" %-35s = %lu\n"), _T("Failed Connection Attempts"), pTcpStats->dwAttemptFails);
356 _tprintf(_T(" %-35s = %lu\n"), _T("Reset Connections"), pTcpStats->dwEstabResets);
357 _tprintf(_T(" %-35s = %lu\n"), _T("Current Connections"), pTcpStats->dwCurrEstab);
358 _tprintf(_T(" %-35s = %lu\n"), _T("Segments Received"), pTcpStats->dwInSegs);
359 _tprintf(_T(" %-35s = %lu\n"), _T("Segments Sent"), pTcpStats->dwOutSegs);
360 _tprintf(_T(" %-35s = %lu\n"), _T("Segments Retransmitted"), pTcpStats->dwRetransSegs);
361 }
362 else
363 DoFormatMessage(dwRetVal);
364
365 HeapFree(GetProcessHeap(), 0, pTcpStats);
366 }
367
368 VOID ShowUdpStatistics()
369 {
370 PMIB_UDPSTATS pUdpStats;
371 DWORD dwRetVal;
372
373 pUdpStats = (MIB_UDPSTATS*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_UDPSTATS));
374
375 if ((dwRetVal = GetUdpStatistics(pUdpStats)) == NO_ERROR)
376 {
377 _tprintf(_T("\nUDP Statistics for IPv4\n\n"));
378 _tprintf(_T(" %-21s = %lu\n"), _T("Datagrams Received"), pUdpStats->dwInDatagrams);
379 _tprintf(_T(" %-21s = %lu\n"), _T("No Ports"), pUdpStats->dwNoPorts);
380 _tprintf(_T(" %-21s = %lu\n"), _T("Receive Errors"), pUdpStats->dwInErrors);
381 _tprintf(_T(" %-21s = %lu\n"), _T("Datagrams Sent"), pUdpStats->dwOutDatagrams);
382 }
383 else
384 DoFormatMessage(dwRetVal);
385
386 HeapFree(GetProcessHeap(), 0, pUdpStats);
387 }
388
389 VOID ShowEthernetStatistics()
390 {
391 PMIB_IFTABLE pIfTable;
392 DWORD dwSize = 0;
393 DWORD dwRetVal = 0;
394
395 pIfTable = (MIB_IFTABLE*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IFTABLE));
396
397 if (GetIfTable(pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
398 {
399 HeapFree(GetProcessHeap(), 0, pIfTable);
400 pIfTable = (MIB_IFTABLE*) HeapAlloc(GetProcessHeap(), 0, dwSize);
401
402 if ((dwRetVal = GetIfTable(pIfTable, &dwSize, 0)) == NO_ERROR)
403 {
404 _tprintf(_T("Interface Statistics\n\n"));
405 _tprintf(_T(" Received Sent\n\n"));
406 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Bytes"),
407 pIfTable->table[0].dwInOctets, pIfTable->table[0].dwOutOctets);
408 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Unicast packets"),
409 pIfTable->table[0].dwInUcastPkts, pIfTable->table[0].dwOutUcastPkts);
410 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Non-unicast packets"),
411 pIfTable->table[0].dwInNUcastPkts, pIfTable->table[0].dwOutNUcastPkts);
412 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Discards"),
413 pIfTable->table[0].dwInDiscards, pIfTable->table[0].dwOutDiscards);
414 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Errors"),
415 pIfTable->table[0].dwInErrors, pIfTable->table[0].dwOutErrors);
416 _tprintf(_T("%-20s %14lu\n"), _T("Unknown Protocols"),
417 pIfTable->table[0].dwInUnknownProtos);
418 }
419 else
420 DoFormatMessage(dwRetVal);
421 }
422 HeapFree(GetProcessHeap(), 0, pIfTable);
423 }
424
425 VOID ShowTcpTable()
426 {
427 PMIB_TCPTABLE_OWNER_PID tcpTable;
428 DWORD error, dwSize;
429 DWORD i;
430 CHAR HostIp[HOSTNAMELEN], HostPort[PORTNAMELEN];
431 CHAR RemoteIp[HOSTNAMELEN], RemotePort[PORTNAMELEN];
432 CHAR Host[ADDRESSLEN];
433 CHAR Remote[ADDRESSLEN];
434 CHAR PID[64];
435
436 /* Get the table of TCP endpoints */
437 dwSize = sizeof (MIB_TCPTABLE_OWNER_PID);
438 /* Should also work when we get new connections between 2 GetTcpTable()
439 * calls: */
440 do
441 {
442 tcpTable = (PMIB_TCPTABLE_OWNER_PID) HeapAlloc(GetProcessHeap(), 0, dwSize);
443 error = GetExtendedTcpTable(tcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
444 if ( error != NO_ERROR )
445 HeapFree(GetProcessHeap(), 0, tcpTable);
446 }
447 while ( error == ERROR_INSUFFICIENT_BUFFER );
448
449 if (error != NO_ERROR)
450 {
451 printf("Failed to snapshot TCP endpoints.\n");
452 DoFormatMessage(error);
453 exit(EXIT_FAILURE);
454 }
455
456 /* Dump the TCP table */
457 for (i = 0; i < tcpTable->dwNumEntries; i++)
458 {
459 /* If we aren't showing all connections, only display established, close wait
460 * and time wait. This is the default output for netstat */
461 if (bDoShowAllCons || (tcpTable->table[i].dwState == MIB_TCP_STATE_ESTAB)
462 || (tcpTable->table[i].dwState == MIB_TCP_STATE_CLOSE_WAIT)
463 || (tcpTable->table[i].dwState == MIB_TCP_STATE_TIME_WAIT))
464 {
465 /* I've split this up so it's easier to follow */
466 GetIpHostName(TRUE, tcpTable->table[i].dwLocalAddr, HostIp, HOSTNAMELEN);
467 GetPortName(tcpTable->table[i].dwLocalPort, "tcp", HostPort, PORTNAMELEN);
468 sprintf(Host, "%s:%s", HostIp, HostPort);
469
470 if (tcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
471 {
472 sprintf(Remote, "%s:0", HostIp);
473 }
474 else
475 {
476 GetIpHostName(FALSE, tcpTable->table[i].dwRemoteAddr, RemoteIp, HOSTNAMELEN);
477 GetPortName(tcpTable->table[i].dwRemotePort, "tcp", RemotePort, PORTNAMELEN);
478 sprintf(Remote, "%s:%s", RemoteIp, RemotePort);
479 }
480
481 if (bDoShowProcessId)
482 {
483 sprintf(PID, "%ld", tcpTable->table[i].dwOwningPid);
484 }
485 else
486 {
487 PID[0] = 0;
488 }
489
490 _tprintf(_T(" %-6s %-22s %-22s %-11s %s\n"), _T("TCP"),
491 Host, Remote, TcpState[tcpTable->table[i].dwState], PID);
492 }
493 }
494 HeapFree(GetProcessHeap(), 0, tcpTable);
495 }
496
497 VOID ShowUdpTable()
498 {
499 PMIB_UDPTABLE udpTable;
500 DWORD error, dwSize;
501 DWORD i;
502 CHAR HostIp[HOSTNAMELEN], HostPort[PORTNAMELEN];
503 CHAR Host[ADDRESSLEN];
504
505 /* Get the table of UDP endpoints */
506 dwSize = 0;
507 error = GetUdpTable(NULL, &dwSize, TRUE);
508 if (error != ERROR_INSUFFICIENT_BUFFER)
509 {
510 printf("Failed to snapshot UDP endpoints.\n");
511 DoFormatMessage(error);
512 exit(EXIT_FAILURE);
513 }
514 udpTable = (PMIB_UDPTABLE) HeapAlloc(GetProcessHeap(), 0, dwSize);
515 error = GetUdpTable(udpTable, &dwSize, TRUE);
516 if (error)
517 {
518 printf("Failed to snapshot UDP endpoints table.\n");
519 DoFormatMessage(error);
520 HeapFree(GetProcessHeap(), 0, udpTable);
521 exit(EXIT_FAILURE);
522 }
523
524 /* Dump the UDP table */
525 for (i = 0; i < udpTable->dwNumEntries; i++)
526 {
527
528 /* I've split this up so it's easier to follow */
529 GetIpHostName(TRUE, udpTable->table[i].dwLocalAddr, HostIp, HOSTNAMELEN);
530 GetPortName(udpTable->table[i].dwLocalPort, "tcp", HostPort, PORTNAMELEN);
531
532 sprintf(Host, "%s:%s", HostIp, HostPort);
533
534 _tprintf(_T(" %-6s %-22s %-22s\n"), _T("UDP"), Host, _T("*:*"));
535 }
536
537 HeapFree(GetProcessHeap(), 0, udpTable);
538 }
539
540 /*
541 * Translate port numbers into their text equivalent if there is one
542 */
543 PCHAR
544 GetPortName(UINT Port, PCSTR Proto, CHAR Name[], INT NameLen)
545 {
546 struct servent *pServent;
547
548 if (bDoShowNumbers)
549 {
550 sprintf(Name, "%d", htons((WORD)Port));
551 return Name;
552 }
553 /* Try to translate to a name */
554 if ((pServent = getservbyport(Port, Proto)))
555 strcpy(Name, pServent->s_name );
556 else
557 sprintf(Name, "%d", htons((WORD)Port));
558 return Name;
559 }
560
561 /*
562 * convert addresses into dotted decimal or hostname
563 */
564 PCHAR
565 GetIpHostName(BOOL Local, UINT IpAddr, CHAR Name[], int NameLen)
566 {
567 // struct hostent *phostent;
568 UINT nIpAddr;
569
570 /* display dotted decimal */
571 nIpAddr = htonl(IpAddr);
572 if (bDoShowNumbers) {
573 sprintf(Name, "%d.%d.%d.%d",
574 (nIpAddr >> 24) & 0xFF,
575 (nIpAddr >> 16) & 0xFF,
576 (nIpAddr >> 8) & 0xFF,
577 (nIpAddr) & 0xFF);
578 return Name;
579 }
580
581 Name[0] = _T('\0');
582
583 /* try to resolve the name */
584 if (!IpAddr) {
585 if (!Local) {
586 sprintf(Name, "%d.%d.%d.%d",
587 (nIpAddr >> 24) & 0xFF,
588 (nIpAddr >> 16) & 0xFF,
589 (nIpAddr >> 8) & 0xFF,
590 (nIpAddr) & 0xFF);
591 } else {
592 if (gethostname(Name, NameLen) != 0)
593 DoFormatMessage(WSAGetLastError());
594 }
595 } else if (IpAddr == 0x0100007f) {
596 if (Local) {
597 if (gethostname(Name, NameLen) != 0)
598 DoFormatMessage(WSAGetLastError());
599 } else {
600 _tcsncpy(Name, _T("localhost"), 10);
601 }
602 // } else if (phostent = gethostbyaddr((char*)&ipaddr, sizeof(nipaddr), PF_INET)) {
603 // strcpy(name, phostent->h_name);
604 } else {
605 sprintf(Name, "%d.%d.%d.%d",
606 ((nIpAddr >> 24) & 0x000000FF),
607 ((nIpAddr >> 16) & 0x000000FF),
608 ((nIpAddr >> 8) & 0x000000FF),
609 ((nIpAddr) & 0x000000FF));
610 }
611 return Name;
612 }
613
614 VOID Usage()
615 {
616 _tprintf(_T("\nDisplays current TCP/IP protocol statistics and network connections.\n\n"
617 "NETSTAT [-a] [-e] [-n] [-p proto] [-r] [-s] [interval]\n\n"
618 " -a Displays all connections and listening ports.\n"
619 " -e Displays Ethernet statistics. May be combined with -s\n"
620 " option\n"
621 " -n Displays address and port numbers in numeric form.\n"
622 " -p proto Shows connections for protocol 'proto' TCP or UDP.\n"
623 " If used with the -s option to display\n"
624 " per-protocol statistics, 'proto' may be TCP, UDP, or IP.\n"
625 " -r Displays the current routing table.\n"
626 " -s Displays per-protocol statistics. By default, Statistics are\n"
627 " shown for IP, ICMP, TCP and UDP;\n"
628 " the -p option may be used to specify a subset of the default.\n"
629 " -o Displays the process ID for each connection.\n"
630 " interval Redisplays selected statistics every 'interval' seconds.\n"
631 " Press CTRL+C to stop redisplaying. By default netstat will\n"
632 " print the current information only once.\n"));
633 }
634
635 /*
636 *
637 * Parse command line parameters and set any options
638 * Run display output, looping over set intervals if a number is given
639 *
640 */
641 int main(int argc, char *argv[])
642 {
643 WSADATA wsaData;
644
645 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
646 {
647 _tprintf(_T("WSAStartup() failed : %d\n"), WSAGetLastError());
648 return -1;
649 }
650
651 if (ParseCmdline(argc, argv))
652 return -1;
653
654 if (bLoopOutput)
655 {
656 while (1)
657 {
658 if (DisplayOutput())
659 return -1;
660 Sleep(Interval*1000);
661 }
662 }
663
664 if (DisplayOutput())
665 return -1;
666 else
667 return 0;
668 }