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