blob: 6d91bb3f4fc5dbac5201d6f4fc5b177394ac7514 [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
Eric Andersen31a0ece2001-10-31 11:00:46 +000014#include "busybox.h"
Rob Landleyc9c1a412006-07-12 19:17:55 +000015#include "inet_common.h"
Eric Andersen31a0ece2001-10-31 11:00:46 +000016
Robert Griebl820098f2002-05-14 23:03:23 +000017#ifdef CONFIG_ROUTE
18extern void displayroutes(int noresolve, int netstatfmt);
19#endif
20
Eric Andersen31a0ece2001-10-31 11:00:46 +000021#define NETSTAT_CONNECTED 0x01
22#define NETSTAT_LISTENING 0x02
23#define NETSTAT_NUMERIC 0x04
24#define NETSTAT_TCP 0x10
25#define NETSTAT_UDP 0x20
26#define NETSTAT_RAW 0x40
27#define NETSTAT_UNIX 0x80
28
Eric Andersenb0c39a82002-06-22 17:32:58 +000029static int flags = NETSTAT_CONNECTED |
Eric Andersen31a0ece2001-10-31 11:00:46 +000030 NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
31
32#define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
33#define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
34#define PROGNAME_WIDTH2(s) #s
35
36#define PRG_HASH_SIZE 211
37
38enum {
39 TCP_ESTABLISHED = 1,
40 TCP_SYN_SENT,
41 TCP_SYN_RECV,
42 TCP_FIN_WAIT1,
43 TCP_FIN_WAIT2,
44 TCP_TIME_WAIT,
45 TCP_CLOSE,
46 TCP_CLOSE_WAIT,
47 TCP_LAST_ACK,
48 TCP_LISTEN,
49 TCP_CLOSING /* now a valid state */
50};
51
Eric Andersenb0c39a82002-06-22 17:32:58 +000052static const char * const tcp_state[] =
Eric Andersen31a0ece2001-10-31 11:00:46 +000053{
54 "",
55 "ESTABLISHED",
56 "SYN_SENT",
57 "SYN_RECV",
58 "FIN_WAIT1",
59 "FIN_WAIT2",
60 "TIME_WAIT",
61 "CLOSE",
62 "CLOSE_WAIT",
63 "LAST_ACK",
64 "LISTEN",
65 "CLOSING"
66};
67
68typedef enum {
69 SS_FREE = 0, /* not allocated */
70 SS_UNCONNECTED, /* unconnected to any socket */
71 SS_CONNECTING, /* in process of connecting */
72 SS_CONNECTED, /* connected to socket */
73 SS_DISCONNECTING /* in process of disconnecting */
74} socket_state;
75
76#define SO_ACCEPTCON (1<<16) /* performed a listen */
77#define SO_WAITDATA (1<<17) /* wait data to read */
78#define SO_NOSPACE (1<<18) /* no space to write */
79
Eric Andersencd8c4362001-11-10 11:22:46 +000080static char *get_sname(int port, const char *proto, int num)
Eric Andersen31a0ece2001-10-31 11:00:46 +000081{
82 char *str=itoa(ntohs(port));
83 if (num) {
84 } else {
85 struct servent *se=getservbyport(port,proto);
86 if (se)
87 str=se->s_name;
88 }
89 if (!port) {
90 str="*";
91 }
92 return str;
93}
94
Eric Andersencd8c4362001-11-10 11:22:46 +000095static 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 +000096{
97 char *port_name;
Eric Andersencd8c4362001-11-10 11:22:46 +000098
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +000099#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000100 if (addr->sa_family == AF_INET6) {
101 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
102 (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
103 } else
104#endif
105 {
Eric Andersencd8c4362001-11-10 11:22:46 +0000106 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
107 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
108 0xffffffff);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000109 }
Eric Andersen31a0ece2001-10-31 11:00:46 +0000110 port_name=get_sname(htons(port), proto, numeric);
111 if ((strlen(ip_port) + strlen(port_name)) > 22)
112 ip_port[22 - strlen(port_name)] = '\0';
113 ip_port+=strlen(ip_port);
114 strcat(ip_port, ":");
115 strcat(ip_port, port_name);
116}
117
118static void tcp_do_one(int lnr, const char *line)
119{
120 char local_addr[64], rem_addr[64];
Eric Andersenb0c39a82002-06-22 17:32:58 +0000121 const char *state_str;
122 char more[512];
Eric Andersen31a0ece2001-10-31 11:00:46 +0000123 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000124#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000125 struct sockaddr_in6 localaddr, remaddr;
126 char addr6[INET6_ADDRSTRLEN];
127 struct in6_addr in6;
128#else
Eric Andersen31a0ece2001-10-31 11:00:46 +0000129 struct sockaddr_in localaddr, remaddr;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000130#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000131 unsigned long rxq, txq, time_len, retr, inode;
132
133 if (lnr == 0)
134 return;
135
136 more[0] = '\0';
137 num = sscanf(line,
138 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
139 &d, local_addr, &local_port,
140 rem_addr, &rem_port, &state,
141 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
142
143 if (strlen(local_addr) > 8) {
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000144#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000145 sscanf(local_addr, "%08X%08X%08X%08X",
146 &in6.s6_addr32[0], &in6.s6_addr32[1],
147 &in6.s6_addr32[2], &in6.s6_addr32[3]);
148 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
149 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
150 sscanf(rem_addr, "%08X%08X%08X%08X",
151 &in6.s6_addr32[0], &in6.s6_addr32[1],
152 &in6.s6_addr32[2], &in6.s6_addr32[3]);
153 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
154 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
155 localaddr.sin6_family = AF_INET6;
156 remaddr.sin6_family = AF_INET6;
157#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000158 } else {
159 sscanf(local_addr, "%X",
160 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
161 sscanf(rem_addr, "%X",
162 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
163 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
164 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
165 }
166
167 if (num < 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000168 bb_error_msg("warning, got bogus tcp line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000169 return;
170 }
Eric Andersenb0c39a82002-06-22 17:32:58 +0000171 state_str = tcp_state[state];
Eric Andersen31a0ece2001-10-31 11:00:46 +0000172 if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
173 (!rem_port && (flags&NETSTAT_LISTENING)))
174 {
175 snprint_ip_port(local_addr, sizeof(local_addr),
176 (struct sockaddr *) &localaddr, local_port,
177 "tcp", flags&NETSTAT_NUMERIC);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000178
Eric Andersen31a0ece2001-10-31 11:00:46 +0000179 snprint_ip_port(rem_addr, sizeof(rem_addr),
180 (struct sockaddr *) &remaddr, rem_port,
181 "tcp", flags&NETSTAT_NUMERIC);
182
183 printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
184 rxq, txq, local_addr, rem_addr, state_str);
185
186 }
187}
188
189static void udp_do_one(int lnr, const char *line)
190{
191 char local_addr[64], rem_addr[64];
192 char *state_str, more[512];
193 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000194#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000195 struct sockaddr_in6 localaddr, remaddr;
196 char addr6[INET6_ADDRSTRLEN];
197 struct in6_addr in6;
198#else
Eric Andersen31a0ece2001-10-31 11:00:46 +0000199 struct sockaddr_in localaddr, remaddr;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000200#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000201 unsigned long rxq, txq, time_len, retr, inode;
202
203 if (lnr == 0)
204 return;
205
206 more[0] = '\0';
207 num = sscanf(line,
208 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
209 &d, local_addr, &local_port,
210 rem_addr, &rem_port, &state,
211 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
212
213 if (strlen(local_addr) > 8) {
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000214#ifdef CONFIG_FEATURE_IPV6
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000215 /* Demangle what the kernel gives us */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000216 sscanf(local_addr, "%08X%08X%08X%08X",
217 &in6.s6_addr32[0], &in6.s6_addr32[1],
218 &in6.s6_addr32[2], &in6.s6_addr32[3]);
219 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
220 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
221 sscanf(rem_addr, "%08X%08X%08X%08X",
222 &in6.s6_addr32[0], &in6.s6_addr32[1],
223 &in6.s6_addr32[2], &in6.s6_addr32[3]);
224 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
225 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
226 localaddr.sin6_family = AF_INET6;
227 remaddr.sin6_family = AF_INET6;
228#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000229 } else {
230 sscanf(local_addr, "%X",
231 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
232 sscanf(rem_addr, "%X",
233 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
234 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
235 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
236 }
237
238 if (num < 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000239 bb_error_msg("warning, got bogus udp line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000240 return;
241 }
242 switch (state) {
243 case TCP_ESTABLISHED:
244 state_str = "ESTABLISHED";
245 break;
246
247 case TCP_CLOSE:
248 state_str = "";
249 break;
250
251 default:
252 state_str = "UNKNOWN";
253 break;
254 }
255
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000256#ifdef CONFIG_FEATURE_IPV6
257# define notnull(A) (((A.sin6_family == AF_INET6) && \
Eric Andersen51b8bd62002-07-03 11:46:38 +0000258 ((A.sin6_addr.s6_addr32[0]) || \
259 (A.sin6_addr.s6_addr32[1]) || \
260 (A.sin6_addr.s6_addr32[2]) || \
261 (A.sin6_addr.s6_addr32[3]))) || \
262 ((A.sin6_family == AF_INET) && \
263 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
264#else
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000265# define notnull(A) (A.sin_addr.s_addr)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000266#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000267 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
268 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
269 {
270 snprint_ip_port(local_addr, sizeof(local_addr),
271 (struct sockaddr *) &localaddr, local_port,
272 "udp", flags&NETSTAT_NUMERIC);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000273
Eric Andersen31a0ece2001-10-31 11:00:46 +0000274 snprint_ip_port(rem_addr, sizeof(rem_addr),
275 (struct sockaddr *) &remaddr, rem_port,
276 "udp", flags&NETSTAT_NUMERIC);
277
278 printf("udp %6ld %6ld %-23s %-23s %-12s\n",
279 rxq, txq, local_addr, rem_addr, state_str);
280
281 }
282}
283
284static void raw_do_one(int lnr, const char *line)
285{
286 char local_addr[64], rem_addr[64];
287 char *state_str, more[512];
288 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000289#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000290 struct sockaddr_in6 localaddr, remaddr;
291 char addr6[INET6_ADDRSTRLEN];
292 struct in6_addr in6;
293#else
Eric Andersen31a0ece2001-10-31 11:00:46 +0000294 struct sockaddr_in localaddr, remaddr;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000295#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000296 unsigned long rxq, txq, time_len, retr, inode;
297
298 if (lnr == 0)
299 return;
300
301 more[0] = '\0';
302 num = sscanf(line,
303 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
304 &d, local_addr, &local_port,
305 rem_addr, &rem_port, &state,
306 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
307
308 if (strlen(local_addr) > 8) {
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000309#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000310 sscanf(local_addr, "%08X%08X%08X%08X",
311 &in6.s6_addr32[0], &in6.s6_addr32[1],
312 &in6.s6_addr32[2], &in6.s6_addr32[3]);
313 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
314 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
315 sscanf(rem_addr, "%08X%08X%08X%08X",
316 &in6.s6_addr32[0], &in6.s6_addr32[1],
317 &in6.s6_addr32[2], &in6.s6_addr32[3]);
318 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
319 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
320 localaddr.sin6_family = AF_INET6;
321 remaddr.sin6_family = AF_INET6;
322#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000323 } else {
324 sscanf(local_addr, "%X",
325 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
326 sscanf(rem_addr, "%X",
327 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
328 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
329 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
330 }
331
332 if (num < 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000333 bb_error_msg("warning, got bogus raw line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000334 return;
335 }
336 state_str=itoa(state);
337
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000338#ifdef CONFIG_FEATURE_IPV6
339# define notnull(A) (((A.sin6_family == AF_INET6) && \
Eric Andersen51b8bd62002-07-03 11:46:38 +0000340 ((A.sin6_addr.s6_addr32[0]) || \
341 (A.sin6_addr.s6_addr32[1]) || \
342 (A.sin6_addr.s6_addr32[2]) || \
343 (A.sin6_addr.s6_addr32[3]))) || \
344 ((A.sin6_family == AF_INET) && \
345 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
346#else
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000347# define notnull(A) (A.sin_addr.s_addr)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000348#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000349 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
350 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
351 {
352 snprint_ip_port(local_addr, sizeof(local_addr),
353 (struct sockaddr *) &localaddr, local_port,
354 "raw", flags&NETSTAT_NUMERIC);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000355
Eric Andersen31a0ece2001-10-31 11:00:46 +0000356 snprint_ip_port(rem_addr, sizeof(rem_addr),
357 (struct sockaddr *) &remaddr, rem_port,
358 "raw", flags&NETSTAT_NUMERIC);
359
360 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
361 rxq, txq, local_addr, rem_addr, state_str);
362
363 }
364}
365
366#define HAS_INODE 1
367
368static void unix_do_one(int nr, const char *line)
369{
370 static int has = 0;
371 char path[PATH_MAX], ss_flags[32];
372 char *ss_proto, *ss_state, *ss_type;
373 int num, state, type, inode;
374 void *d;
375 unsigned long refcnt, proto, unix_flags;
376
377 if (nr == 0) {
378 if (strstr(line, "Inode"))
379 has |= HAS_INODE;
380 return;
381 }
382 path[0] = '\0';
383 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
384 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
385 if (num < 6) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000386 bb_error_msg("warning, got bogus unix line.");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000387 return;
388 }
389 if (!(has & HAS_INODE))
390 snprintf(path,sizeof(path),"%d",inode);
391
392 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
393 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
394 if (!(flags&NETSTAT_LISTENING))
395 return;
396 } else {
397 if (!(flags&NETSTAT_CONNECTED))
398 return;
399 }
400 }
401
402 switch (proto) {
403 case 0:
404 ss_proto = "unix";
405 break;
406
407 default:
408 ss_proto = "??";
409 }
410
411 switch (type) {
412 case SOCK_STREAM:
413 ss_type = "STREAM";
414 break;
415
416 case SOCK_DGRAM:
417 ss_type = "DGRAM";
418 break;
419
420 case SOCK_RAW:
421 ss_type = "RAW";
422 break;
423
424 case SOCK_RDM:
425 ss_type = "RDM";
426 break;
427
428 case SOCK_SEQPACKET:
429 ss_type = "SEQPACKET";
430 break;
431
432 default:
433 ss_type = "UNKNOWN";
434 }
435
436 switch (state) {
437 case SS_FREE:
438 ss_state = "FREE";
439 break;
440
441 case SS_UNCONNECTED:
442 /*
443 * Unconnected sockets may be listening
444 * for something.
445 */
446 if (unix_flags & SO_ACCEPTCON) {
447 ss_state = "LISTENING";
448 } else {
449 ss_state = "";
450 }
451 break;
452
453 case SS_CONNECTING:
454 ss_state = "CONNECTING";
455 break;
456
457 case SS_CONNECTED:
458 ss_state = "CONNECTED";
459 break;
460
461 case SS_DISCONNECTING:
462 ss_state = "DISCONNECTING";
463 break;
464
465 default:
466 ss_state = "UNKNOWN";
467 }
468
469 strcpy(ss_flags, "[ ");
470 if (unix_flags & SO_ACCEPTCON)
471 strcat(ss_flags, "ACC ");
472 if (unix_flags & SO_WAITDATA)
473 strcat(ss_flags, "W ");
474 if (unix_flags & SO_NOSPACE)
475 strcat(ss_flags, "N ");
476
477 strcat(ss_flags, "]");
478
479 printf("%-5s %-6ld %-11s %-10s %-13s ",
480 ss_proto, refcnt, ss_flags, ss_type, ss_state);
481 if (has & HAS_INODE)
482 printf("%-6d ",inode);
483 else
484 printf("- ");
485 puts(path);
486}
487
488#define _PATH_PROCNET_UDP "/proc/net/udp"
Eric Andersen51b8bd62002-07-03 11:46:38 +0000489#define _PATH_PROCNET_UDP6 "/proc/net/udp6"
Eric Andersen31a0ece2001-10-31 11:00:46 +0000490#define _PATH_PROCNET_TCP "/proc/net/tcp"
Eric Andersen51b8bd62002-07-03 11:46:38 +0000491#define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
Eric Andersen31a0ece2001-10-31 11:00:46 +0000492#define _PATH_PROCNET_RAW "/proc/net/raw"
Eric Andersen51b8bd62002-07-03 11:46:38 +0000493#define _PATH_PROCNET_RAW6 "/proc/net/raw6"
Eric Andersen31a0ece2001-10-31 11:00:46 +0000494#define _PATH_PROCNET_UNIX "/proc/net/unix"
495
Eric Andersenb0c39a82002-06-22 17:32:58 +0000496static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
Eric Andersen31a0ece2001-10-31 11:00:46 +0000497{
498 char buffer[8192];
Eric Andersen31a0ece2001-10-31 11:00:46 +0000499 int lnr = 0;
500 FILE *procinfo;
501
Eric Andersenb0c39a82002-06-22 17:32:58 +0000502 procinfo = fopen(file, "r");
Eric Andersen31a0ece2001-10-31 11:00:46 +0000503 if (procinfo == NULL) {
504 if (errno != ENOENT) {
Eric Andersenb0c39a82002-06-22 17:32:58 +0000505 perror(file);
506 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000507 bb_error_msg("no support for `%s' on this system.", name);
Eric Andersen31a0ece2001-10-31 11:00:46 +0000508 }
Eric Andersen31a0ece2001-10-31 11:00:46 +0000509 } else {
510 do {
511 if (fgets(buffer, sizeof(buffer), procinfo))
512 (proc)(lnr++, buffer);
513 } while (!feof(procinfo));
514 fclose(procinfo);
515 }
Eric Andersen31a0ece2001-10-31 11:00:46 +0000516}
517
518/*
519 * Our main function.
520 */
521
522int netstat_main(int argc, char **argv)
523{
524 int opt;
525 int new_flags=0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000526 int showroute = 0, extended = 0;
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000527#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000528 int inet=1;
529 int inet6=1;
530#else
Glenn L McGrathd7fb1b32002-11-26 02:40:56 +0000531# define inet 1
532# define inet6 0
Eric Andersen51b8bd62002-07-03 11:46:38 +0000533#endif
Robert Griebl820098f2002-05-14 23:03:23 +0000534 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000535 switch (opt) {
536 case 'l':
537 flags &= ~NETSTAT_CONNECTED;
538 flags |= NETSTAT_LISTENING;
539 break;
540 case 'a':
541 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
542 break;
543 case 'n':
544 flags |= NETSTAT_NUMERIC;
545 break;
Robert Griebl820098f2002-05-14 23:03:23 +0000546 case 'r':
547 showroute = 1;
548 break;
549 case 'e':
550 extended = 1;
551 break;
Eric Andersen31a0ece2001-10-31 11:00:46 +0000552 case 't':
553 new_flags |= NETSTAT_TCP;
554 break;
555 case 'u':
556 new_flags |= NETSTAT_UDP;
557 break;
558 case 'w':
559 new_flags |= NETSTAT_RAW;
560 break;
561 case 'x':
562 new_flags |= NETSTAT_UNIX;
563 break;
564 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000565 bb_show_usage();
Eric Andersen31a0ece2001-10-31 11:00:46 +0000566 }
Robert Griebl820098f2002-05-14 23:03:23 +0000567 if ( showroute ) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000568#ifdef CONFIG_ROUTE
Robert Griebl820098f2002-05-14 23:03:23 +0000569 displayroutes ( flags & NETSTAT_NUMERIC, !extended );
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000570 return 0;
Robert Griebl820098f2002-05-14 23:03:23 +0000571#else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000572 bb_error_msg_and_die( "-r (display routing table) is not compiled in." );
Robert Griebl820098f2002-05-14 23:03:23 +0000573#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000574 }
575
Eric Andersen31a0ece2001-10-31 11:00:46 +0000576 if (new_flags) {
577 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
578 flags |= new_flags;
579 }
580 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
581 printf("Active Internet connections "); /* xxx */
582
583 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
584 printf("(servers and established)");
585 else {
586 if (flags&NETSTAT_LISTENING)
587 printf("(only servers)");
588 else
589 printf("(w/o servers)");
590 }
591 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
592 }
Eric Andersen51b8bd62002-07-03 11:46:38 +0000593 if (inet && flags&NETSTAT_TCP)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000594 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000595#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000596 if (inet6 && flags&NETSTAT_TCP)
597 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
598#endif
599 if (inet && flags&NETSTAT_UDP)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000600 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000601#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000602 if (inet6 && flags&NETSTAT_UDP)
603 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
604#endif
605 if (inet && flags&NETSTAT_RAW)
Eric Andersen31a0ece2001-10-31 11:00:46 +0000606 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000607#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000608 if (inet6 && flags&NETSTAT_RAW)
609 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
610#endif
Eric Andersen31a0ece2001-10-31 11:00:46 +0000611 if (flags&NETSTAT_UNIX) {
612 printf("Active UNIX domain sockets ");
613 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
614 printf("(servers and established)");
615 else {
616 if (flags&NETSTAT_LISTENING)
617 printf("(only servers)");
618 else
619 printf("(w/o servers)");
620 }
621
622 printf("\nProto RefCnt Flags Type State I-Node Path\n");
623 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);
624 }
625 return 0;
626}