blob: 4faa40cd4faba46702e3af3d2782942333d6f9fa [file] [log] [blame]
Eric Andersen31a0ece2001-10-31 11:00:46 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Mini netstat implementation(s) for busybox
4 * based in part on the netstat implementation from net-tools.
5 *
Eric Andersen51b8bd62002-07-03 11:46:38 +00006 * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
Eric Andersen31a0ece2001-10-31 11:00:46 +00007 *
Eric Andersen51b8bd62002-07-03 11:46:38 +00008 * 2002-04-20
9 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
"Robert P. J. Day"2819f752006-07-11 11:32:31 +000010 *
11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersen31a0ece2001-10-31 11:00:46 +000012 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <stdarg.h>
18#include <signal.h>
19#include <errno.h>
20#include <sys/stat.h>
21#include <dirent.h>
22#include <unistd.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000023#include "inet_common.h"
Eric Andersen31a0ece2001-10-31 11:00:46 +000024#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000025#include "pwd_.h"
Eric Andersen31a0ece2001-10-31 11:00:46 +000026
Robert Griebl820098f2002-05-14 23:03:23 +000027#ifdef CONFIG_ROUTE
28extern void displayroutes(int noresolve, int netstatfmt);
29#endif
30
Eric Andersen31a0ece2001-10-31 11:00:46 +000031#define NETSTAT_CONNECTED 0x01
32#define NETSTAT_LISTENING 0x02
33#define NETSTAT_NUMERIC 0x04
34#define NETSTAT_TCP 0x10
35#define NETSTAT_UDP 0x20
36#define NETSTAT_RAW 0x40
37#define NETSTAT_UNIX 0x80
38
Eric Andersenb0c39a82002-06-22 17:32:58 +000039static int flags = NETSTAT_CONNECTED |
Eric Andersen31a0ece2001-10-31 11:00:46 +000040 NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
41
42#define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
43#define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
44#define PROGNAME_WIDTH2(s) #s
45
46#define PRG_HASH_SIZE 211
47
48enum {
49 TCP_ESTABLISHED = 1,
50 TCP_SYN_SENT,
51 TCP_SYN_RECV,
52 TCP_FIN_WAIT1,
53 TCP_FIN_WAIT2,
54 TCP_TIME_WAIT,
55 TCP_CLOSE,
56 TCP_CLOSE_WAIT,
57 TCP_LAST_ACK,
58 TCP_LISTEN,
59 TCP_CLOSING /* now a valid state */
60};
61
Eric Andersenb0c39a82002-06-22 17:32:58 +000062static const char * const tcp_state[] =
Eric Andersen31a0ece2001-10-31 11:00:46 +000063{
64 "",
65 "ESTABLISHED",
66 "SYN_SENT",
67 "SYN_RECV",
68 "FIN_WAIT1",
69 "FIN_WAIT2",
70 "TIME_WAIT",
71 "CLOSE",
72 "CLOSE_WAIT",
73 "LAST_ACK",
74 "LISTEN",
75 "CLOSING"
76};
77
78typedef enum {
79 SS_FREE = 0, /* not allocated */
80 SS_UNCONNECTED, /* unconnected to any socket */
81 SS_CONNECTING, /* in process of connecting */
82 SS_CONNECTED, /* connected to socket */
83 SS_DISCONNECTING /* in process of disconnecting */
84} socket_state;
85
86#define SO_ACCEPTCON (1<<16) /* performed a listen */
87#define SO_WAITDATA (1<<17) /* wait data to read */
88#define SO_NOSPACE (1<<18) /* no space to write */
89
Eric Andersencd8c4362001-11-10 11:22:46 +000090static char *itoa(unsigned int i)
Eric Andersen31a0ece2001-10-31 11:00:46 +000091{
92 /* 21 digits plus null terminator, good for 64-bit or smaller ints */
93 static char local[22];
94 char *p = &local[21];
95 *p-- = '\0';
96 do {
97 *p-- = '0' + i % 10;
98 i /= 10;
99 } while (i > 0);
100 return p + 1;
101}
102
Eric Andersencd8c4362001-11-10 11:22:46 +0000103static char *get_sname(int port, const char *proto, int num)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000104{
105 char *str=itoa(ntohs(port));
106 if (num) {
107 } else {
108 struct servent *se=getservbyport(port,proto);
109 if (se)
110 str=se->s_name;
111 }
112 if (!port) {
113 str="*";
114 }
115 return str;
116}
117
Eric Andersencd8c4362001-11-10 11:22:46 +0000118static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000119{
120 char *port_name;
Eric Andersencd8c4362001-11-10 11:22:46 +0000121
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000122#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000123 if (addr->sa_family == AF_INET6) {
124 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
125 (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
126 } else
127#endif
128 {
Eric Andersencd8c4362001-11-10 11:22:46 +0000129 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
130 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
131 0xffffffff);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000132 }
Eric Andersen31a0ece2001-10-31 11:00:46 +0000133 port_name=get_sname(htons(port), proto, numeric);
134 if ((strlen(ip_port) + strlen(port_name)) > 22)
135 ip_port[22 - strlen(port_name)] = '\0';
136 ip_port+=strlen(ip_port);
137 strcat(ip_port, ":");
138 strcat(ip_port, port_name);
139}
140
141static void tcp_do_one(int lnr, const char *line)
142{
143 char local_addr[64], rem_addr[64];
Eric Andersenb0c39a82002-06-22 17:32:58 +0000144 const char *state_str;
145 char more[512];
Eric Andersen31a0ece2001-10-31 11:00:46 +0000146 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000147#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000148 struct sockaddr_in6 localaddr, remaddr;
149 char addr6[INET6_ADDRSTRLEN];
150 struct in6_addr in6;
151#else
Eric Andersen31a0ece2001-10-31 11:00:46 +0000152 struct sockaddr_in localaddr, remaddr;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000153#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000154 unsigned long rxq, txq, time_len, retr, inode;
155
156 if (lnr == 0)
157 return;
158
159 more[0] = '\0';
160 num = sscanf(line,
161 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
162 &d, local_addr, &local_port,
163 rem_addr, &rem_port, &state,
164 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
165
166 if (strlen(local_addr) > 8) {
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000167#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000168 sscanf(local_addr, "%08X%08X%08X%08X",
169 &in6.s6_addr32[0], &in6.s6_addr32[1],
170 &in6.s6_addr32[2], &in6.s6_addr32[3]);
171 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
172 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
173 sscanf(rem_addr, "%08X%08X%08X%08X",
174 &in6.s6_addr32[0], &in6.s6_addr32[1],
175 &in6.s6_addr32[2], &in6.s6_addr32[3]);
176 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
177 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
178 localaddr.sin6_family = AF_INET6;
179 remaddr.sin6_family = AF_INET6;
180#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000181 } else {
182 sscanf(local_addr, "%X",
183 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
184 sscanf(rem_addr, "%X",
185 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
186 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
187 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
188 }
189
190 if (num < 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000191 bb_error_msg("warning, got bogus tcp line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000192 return;
193 }
Eric Andersenb0c39a82002-06-22 17:32:58 +0000194 state_str = tcp_state[state];
Eric Andersen31a0ece2001-10-31 11:00:46 +0000195 if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
196 (!rem_port && (flags&NETSTAT_LISTENING)))
197 {
198 snprint_ip_port(local_addr, sizeof(local_addr),
199 (struct sockaddr *) &localaddr, local_port,
200 "tcp", flags&NETSTAT_NUMERIC);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000201
Eric Andersen31a0ece2001-10-31 11:00:46 +0000202 snprint_ip_port(rem_addr, sizeof(rem_addr),
203 (struct sockaddr *) &remaddr, rem_port,
204 "tcp", flags&NETSTAT_NUMERIC);
205
206 printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
207 rxq, txq, local_addr, rem_addr, state_str);
208
209 }
210}
211
212static void udp_do_one(int lnr, const char *line)
213{
214 char local_addr[64], rem_addr[64];
215 char *state_str, more[512];
216 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000217#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000218 struct sockaddr_in6 localaddr, remaddr;
219 char addr6[INET6_ADDRSTRLEN];
220 struct in6_addr in6;
221#else
Eric Andersen31a0ece2001-10-31 11:00:46 +0000222 struct sockaddr_in localaddr, remaddr;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000223#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000224 unsigned long rxq, txq, time_len, retr, inode;
225
226 if (lnr == 0)
227 return;
228
229 more[0] = '\0';
230 num = sscanf(line,
231 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
232 &d, local_addr, &local_port,
233 rem_addr, &rem_port, &state,
234 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
235
236 if (strlen(local_addr) > 8) {
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000237#ifdef CONFIG_FEATURE_IPV6
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000238 /* Demangle what the kernel gives us */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000239 sscanf(local_addr, "%08X%08X%08X%08X",
240 &in6.s6_addr32[0], &in6.s6_addr32[1],
241 &in6.s6_addr32[2], &in6.s6_addr32[3]);
242 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
243 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
244 sscanf(rem_addr, "%08X%08X%08X%08X",
245 &in6.s6_addr32[0], &in6.s6_addr32[1],
246 &in6.s6_addr32[2], &in6.s6_addr32[3]);
247 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
248 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
249 localaddr.sin6_family = AF_INET6;
250 remaddr.sin6_family = AF_INET6;
251#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000252 } else {
253 sscanf(local_addr, "%X",
254 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
255 sscanf(rem_addr, "%X",
256 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
257 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
258 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
259 }
260
261 if (num < 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000262 bb_error_msg("warning, got bogus udp line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000263 return;
264 }
265 switch (state) {
266 case TCP_ESTABLISHED:
267 state_str = "ESTABLISHED";
268 break;
269
270 case TCP_CLOSE:
271 state_str = "";
272 break;
273
274 default:
275 state_str = "UNKNOWN";
276 break;
277 }
278
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000279#ifdef CONFIG_FEATURE_IPV6
280# define notnull(A) (((A.sin6_family == AF_INET6) && \
Eric Andersen51b8bd62002-07-03 11:46:38 +0000281 ((A.sin6_addr.s6_addr32[0]) || \
282 (A.sin6_addr.s6_addr32[1]) || \
283 (A.sin6_addr.s6_addr32[2]) || \
284 (A.sin6_addr.s6_addr32[3]))) || \
285 ((A.sin6_family == AF_INET) && \
286 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
287#else
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000288# define notnull(A) (A.sin_addr.s_addr)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000289#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000290 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
291 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
292 {
293 snprint_ip_port(local_addr, sizeof(local_addr),
294 (struct sockaddr *) &localaddr, local_port,
295 "udp", flags&NETSTAT_NUMERIC);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000296
Eric Andersen31a0ece2001-10-31 11:00:46 +0000297 snprint_ip_port(rem_addr, sizeof(rem_addr),
298 (struct sockaddr *) &remaddr, rem_port,
299 "udp", flags&NETSTAT_NUMERIC);
300
301 printf("udp %6ld %6ld %-23s %-23s %-12s\n",
302 rxq, txq, local_addr, rem_addr, state_str);
303
304 }
305}
306
307static void raw_do_one(int lnr, const char *line)
308{
309 char local_addr[64], rem_addr[64];
310 char *state_str, more[512];
311 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000312#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000313 struct sockaddr_in6 localaddr, remaddr;
314 char addr6[INET6_ADDRSTRLEN];
315 struct in6_addr in6;
316#else
Eric Andersen31a0ece2001-10-31 11:00:46 +0000317 struct sockaddr_in localaddr, remaddr;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000318#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000319 unsigned long rxq, txq, time_len, retr, inode;
320
321 if (lnr == 0)
322 return;
323
324 more[0] = '\0';
325 num = sscanf(line,
326 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
327 &d, local_addr, &local_port,
328 rem_addr, &rem_port, &state,
329 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
330
331 if (strlen(local_addr) > 8) {
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000332#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000333 sscanf(local_addr, "%08X%08X%08X%08X",
334 &in6.s6_addr32[0], &in6.s6_addr32[1],
335 &in6.s6_addr32[2], &in6.s6_addr32[3]);
336 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
337 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
338 sscanf(rem_addr, "%08X%08X%08X%08X",
339 &in6.s6_addr32[0], &in6.s6_addr32[1],
340 &in6.s6_addr32[2], &in6.s6_addr32[3]);
341 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
342 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
343 localaddr.sin6_family = AF_INET6;
344 remaddr.sin6_family = AF_INET6;
345#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000346 } else {
347 sscanf(local_addr, "%X",
348 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
349 sscanf(rem_addr, "%X",
350 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
351 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
352 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
353 }
354
355 if (num < 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000356 bb_error_msg("warning, got bogus raw line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000357 return;
358 }
359 state_str=itoa(state);
360
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000361#ifdef CONFIG_FEATURE_IPV6
362# define notnull(A) (((A.sin6_family == AF_INET6) && \
Eric Andersen51b8bd62002-07-03 11:46:38 +0000363 ((A.sin6_addr.s6_addr32[0]) || \
364 (A.sin6_addr.s6_addr32[1]) || \
365 (A.sin6_addr.s6_addr32[2]) || \
366 (A.sin6_addr.s6_addr32[3]))) || \
367 ((A.sin6_family == AF_INET) && \
368 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
369#else
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000370# define notnull(A) (A.sin_addr.s_addr)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000371#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000372 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
373 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
374 {
375 snprint_ip_port(local_addr, sizeof(local_addr),
376 (struct sockaddr *) &localaddr, local_port,
377 "raw", flags&NETSTAT_NUMERIC);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000378
Eric Andersen31a0ece2001-10-31 11:00:46 +0000379 snprint_ip_port(rem_addr, sizeof(rem_addr),
380 (struct sockaddr *) &remaddr, rem_port,
381 "raw", flags&NETSTAT_NUMERIC);
382
383 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
384 rxq, txq, local_addr, rem_addr, state_str);
385
386 }
387}
388
389#define HAS_INODE 1
390
391static void unix_do_one(int nr, const char *line)
392{
393 static int has = 0;
394 char path[PATH_MAX], ss_flags[32];
395 char *ss_proto, *ss_state, *ss_type;
396 int num, state, type, inode;
397 void *d;
398 unsigned long refcnt, proto, unix_flags;
399
400 if (nr == 0) {
401 if (strstr(line, "Inode"))
402 has |= HAS_INODE;
403 return;
404 }
405 path[0] = '\0';
406 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
407 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
408 if (num < 6) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000409 bb_error_msg("warning, got bogus unix line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000410 return;
411 }
412 if (!(has & HAS_INODE))
413 snprintf(path,sizeof(path),"%d",inode);
414
415 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
416 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
417 if (!(flags&NETSTAT_LISTENING))
418 return;
419 } else {
420 if (!(flags&NETSTAT_CONNECTED))
421 return;
422 }
423 }
424
425 switch (proto) {
426 case 0:
427 ss_proto = "unix";
428 break;
429
430 default:
431 ss_proto = "??";
432 }
433
434 switch (type) {
435 case SOCK_STREAM:
436 ss_type = "STREAM";
437 break;
438
439 case SOCK_DGRAM:
440 ss_type = "DGRAM";
441 break;
442
443 case SOCK_RAW:
444 ss_type = "RAW";
445 break;
446
447 case SOCK_RDM:
448 ss_type = "RDM";
449 break;
450
451 case SOCK_SEQPACKET:
452 ss_type = "SEQPACKET";
453 break;
454
455 default:
456 ss_type = "UNKNOWN";
457 }
458
459 switch (state) {
460 case SS_FREE:
461 ss_state = "FREE";
462 break;
463
464 case SS_UNCONNECTED:
465 /*
466 * Unconnected sockets may be listening
467 * for something.
468 */
469 if (unix_flags & SO_ACCEPTCON) {
470 ss_state = "LISTENING";
471 } else {
472 ss_state = "";
473 }
474 break;
475
476 case SS_CONNECTING:
477 ss_state = "CONNECTING";
478 break;
479
480 case SS_CONNECTED:
481 ss_state = "CONNECTED";
482 break;
483
484 case SS_DISCONNECTING:
485 ss_state = "DISCONNECTING";
486 break;
487
488 default:
489 ss_state = "UNKNOWN";
490 }
491
492 strcpy(ss_flags, "[ ");
493 if (unix_flags & SO_ACCEPTCON)
494 strcat(ss_flags, "ACC ");
495 if (unix_flags & SO_WAITDATA)
496 strcat(ss_flags, "W ");
497 if (unix_flags & SO_NOSPACE)
498 strcat(ss_flags, "N ");
499
500 strcat(ss_flags, "]");
501
502 printf("%-5s %-6ld %-11s %-10s %-13s ",
503 ss_proto, refcnt, ss_flags, ss_type, ss_state);
504 if (has & HAS_INODE)
505 printf("%-6d ",inode);
506 else
507 printf("- ");
508 puts(path);
509}
510
511#define _PATH_PROCNET_UDP "/proc/net/udp"
Eric Andersen51b8bd62002-07-03 11:46:38 +0000512#define _PATH_PROCNET_UDP6 "/proc/net/udp6"
Eric Andersen31a0ece2001-10-31 11:00:46 +0000513#define _PATH_PROCNET_TCP "/proc/net/tcp"
Eric Andersen51b8bd62002-07-03 11:46:38 +0000514#define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
Eric Andersen31a0ece2001-10-31 11:00:46 +0000515#define _PATH_PROCNET_RAW "/proc/net/raw"
Eric Andersen51b8bd62002-07-03 11:46:38 +0000516#define _PATH_PROCNET_RAW6 "/proc/net/raw6"
Eric Andersen31a0ece2001-10-31 11:00:46 +0000517#define _PATH_PROCNET_UNIX "/proc/net/unix"
518
Eric Andersenb0c39a82002-06-22 17:32:58 +0000519static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
Eric Andersen31a0ece2001-10-31 11:00:46 +0000520{
521 char buffer[8192];
Eric Andersen31a0ece2001-10-31 11:00:46 +0000522 int lnr = 0;
523 FILE *procinfo;
524
Eric Andersenb0c39a82002-06-22 17:32:58 +0000525 procinfo = fopen(file, "r");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000526 if (procinfo == NULL) {
527 if (errno != ENOENT) {
Eric Andersenb0c39a82002-06-22 17:32:58 +0000528 perror(file);
529 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000530 bb_error_msg("no support for `%s' on this system.", name);
Eric Andersen31a0ece2001-10-31 11:00:46 +0000531 }
Eric Andersen31a0ece2001-10-31 11:00:46 +0000532 } else {
533 do {
534 if (fgets(buffer, sizeof(buffer), procinfo))
535 (proc)(lnr++, buffer);
536 } while (!feof(procinfo));
537 fclose(procinfo);
538 }
Eric Andersen31a0ece2001-10-31 11:00:46 +0000539}
540
541/*
542 * Our main function.
543 */
544
545int netstat_main(int argc, char **argv)
546{
547 int opt;
548 int new_flags=0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000549 int showroute = 0, extended = 0;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000550#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000551 int inet=1;
552 int inet6=1;
553#else
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000554# define inet 1
555# define inet6 0
Eric Andersen51b8bd62002-07-03 11:46:38 +0000556#endif
Robert Griebl820098f2002-05-14 23:03:23 +0000557 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000558 switch (opt) {
559 case 'l':
560 flags &= ~NETSTAT_CONNECTED;
561 flags |= NETSTAT_LISTENING;
562 break;
563 case 'a':
564 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
565 break;
566 case 'n':
567 flags |= NETSTAT_NUMERIC;
568 break;
Robert Griebl820098f2002-05-14 23:03:23 +0000569 case 'r':
570 showroute = 1;
571 break;
572 case 'e':
573 extended = 1;
574 break;
Eric Andersen31a0ece2001-10-31 11:00:46 +0000575 case 't':
576 new_flags |= NETSTAT_TCP;
577 break;
578 case 'u':
579 new_flags |= NETSTAT_UDP;
580 break;
581 case 'w':
582 new_flags |= NETSTAT_RAW;
583 break;
584 case 'x':
585 new_flags |= NETSTAT_UNIX;
586 break;
587 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000588 bb_show_usage();
Eric Andersen31a0ece2001-10-31 11:00:46 +0000589 }
Robert Griebl820098f2002-05-14 23:03:23 +0000590 if ( showroute ) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000591#ifdef CONFIG_ROUTE
Robert Griebl820098f2002-05-14 23:03:23 +0000592 displayroutes ( flags & NETSTAT_NUMERIC, !extended );
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000593 return 0;
Robert Griebl820098f2002-05-14 23:03:23 +0000594#else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000595 bb_error_msg_and_die( "-r (display routing table) is not compiled in." );
Robert Griebl820098f2002-05-14 23:03:23 +0000596#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000597 }
598
Eric Andersen31a0ece2001-10-31 11:00:46 +0000599 if (new_flags) {
600 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
601 flags |= new_flags;
602 }
603 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
604 printf("Active Internet connections "); /* xxx */
605
606 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
607 printf("(servers and established)");
608 else {
609 if (flags&NETSTAT_LISTENING)
610 printf("(only servers)");
611 else
612 printf("(w/o servers)");
613 }
614 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
615 }
Eric Andersen51b8bd62002-07-03 11:46:38 +0000616 if (inet && flags&NETSTAT_TCP)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000617 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000618#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000619 if (inet6 && flags&NETSTAT_TCP)
620 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
621#endif
622 if (inet && flags&NETSTAT_UDP)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000623 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000624#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000625 if (inet6 && flags&NETSTAT_UDP)
626 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
627#endif
628 if (inet && flags&NETSTAT_RAW)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000629 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000630#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000631 if (inet6 && flags&NETSTAT_RAW)
632 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
633#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000634 if (flags&NETSTAT_UNIX) {
635 printf("Active UNIX domain sockets ");
636 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
637 printf("(servers and established)");
638 else {
639 if (flags&NETSTAT_LISTENING)
640 printf("(only servers)");
641 else
642 printf("(w/o servers)");
643 }
644
645 printf("\nProto RefCnt Flags Type State I-Node Path\n");
646 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);
647 }
648 return 0;
649}