1 /* vi: set sw=4 ts=4: */
3 * Mini netstat implementation(s) for busybox
4 * based in part on the netstat implementation from net-tools.
6 * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
9 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
15 #include "inet_common.h"
18 extern void displayroutes(int noresolve, int netstatfmt);
21 #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
29 static int flags = NETSTAT_CONNECTED |
30 NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
32 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
33 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
34 #define PROGNAME_WIDTH2(s) #s
36 #define PRG_HASH_SIZE 211
49 TCP_CLOSING /* now a valid state */
52 static const char * const tcp_state[] =
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 */
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 */
80 static char *get_sname(int port, const char *proto, int num)
82 char *str=itoa(ntohs(port));
85 struct servent *se=getservbyport(port,proto);
95 static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
99 #ifdef CONFIG_FEATURE_IPV6
100 if (addr->sa_family == AF_INET6) {
101 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
102 (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
106 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
107 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
110 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);
118 static void tcp_do_one(int lnr, const char *line)
120 char local_addr[64], rem_addr[64];
121 const char *state_str;
123 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
124 #ifdef CONFIG_FEATURE_IPV6
125 struct sockaddr_in6 localaddr, remaddr;
126 char addr6[INET6_ADDRSTRLEN];
129 struct sockaddr_in localaddr, remaddr;
131 unsigned long rxq, txq, time_len, retr, inode;
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);
143 if (strlen(local_addr) > 8) {
144 #ifdef CONFIG_FEATURE_IPV6
145 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;
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;
168 bb_error_msg("warning, got bogus tcp line.");
171 state_str = tcp_state[state];
172 if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
173 (!rem_port && (flags&NETSTAT_LISTENING)))
175 snprint_ip_port(local_addr, sizeof(local_addr),
176 (struct sockaddr *) &localaddr, local_port,
177 "tcp", flags&NETSTAT_NUMERIC);
179 snprint_ip_port(rem_addr, sizeof(rem_addr),
180 (struct sockaddr *) &remaddr, rem_port,
181 "tcp", flags&NETSTAT_NUMERIC);
183 printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
184 rxq, txq, local_addr, rem_addr, state_str);
189 static void udp_do_one(int lnr, const char *line)
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;
194 #ifdef CONFIG_FEATURE_IPV6
195 struct sockaddr_in6 localaddr, remaddr;
196 char addr6[INET6_ADDRSTRLEN];
199 struct sockaddr_in localaddr, remaddr;
201 unsigned long rxq, txq, time_len, retr, inode;
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);
213 if (strlen(local_addr) > 8) {
214 #ifdef CONFIG_FEATURE_IPV6
215 /* Demangle what the kernel gives us */
216 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;
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;
239 bb_error_msg("warning, got bogus udp line.");
243 case TCP_ESTABLISHED:
244 state_str = "ESTABLISHED";
252 state_str = "UNKNOWN";
256 #ifdef CONFIG_FEATURE_IPV6
257 # define notnull(A) (((A.sin6_family == AF_INET6) && \
258 ((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))
265 # define notnull(A) (A.sin_addr.s_addr)
267 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
268 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
270 snprint_ip_port(local_addr, sizeof(local_addr),
271 (struct sockaddr *) &localaddr, local_port,
272 "udp", flags&NETSTAT_NUMERIC);
274 snprint_ip_port(rem_addr, sizeof(rem_addr),
275 (struct sockaddr *) &remaddr, rem_port,
276 "udp", flags&NETSTAT_NUMERIC);
278 printf("udp %6ld %6ld %-23s %-23s %-12s\n",
279 rxq, txq, local_addr, rem_addr, state_str);
284 static void raw_do_one(int lnr, const char *line)
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;
289 #ifdef CONFIG_FEATURE_IPV6
290 struct sockaddr_in6 localaddr, remaddr;
291 char addr6[INET6_ADDRSTRLEN];
294 struct sockaddr_in localaddr, remaddr;
296 unsigned long rxq, txq, time_len, retr, inode;
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);
308 if (strlen(local_addr) > 8) {
309 #ifdef CONFIG_FEATURE_IPV6
310 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;
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;
333 bb_error_msg("warning, got bogus raw line.");
336 state_str=itoa(state);
338 #ifdef CONFIG_FEATURE_IPV6
339 # define notnull(A) (((A.sin6_family == AF_INET6) && \
340 ((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))
347 # define notnull(A) (A.sin_addr.s_addr)
349 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
350 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
352 snprint_ip_port(local_addr, sizeof(local_addr),
353 (struct sockaddr *) &localaddr, local_port,
354 "raw", flags&NETSTAT_NUMERIC);
356 snprint_ip_port(rem_addr, sizeof(rem_addr),
357 (struct sockaddr *) &remaddr, rem_port,
358 "raw", flags&NETSTAT_NUMERIC);
360 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
361 rxq, txq, local_addr, rem_addr, state_str);
368 static void unix_do_one(int nr, const char *line)
371 char path[PATH_MAX], ss_flags[32];
372 char *ss_proto, *ss_state, *ss_type;
373 int num, state, type, inode;
375 unsigned long refcnt, proto, unix_flags;
378 if (strstr(line, "Inode"))
383 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
384 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
386 bb_error_msg("warning, got bogus unix line.");
389 if (!(has & HAS_INODE))
390 snprintf(path,sizeof(path),"%d",inode);
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))
397 if (!(flags&NETSTAT_CONNECTED))
429 ss_type = "SEQPACKET";
443 * Unconnected sockets may be listening
446 if (unix_flags & SO_ACCEPTCON) {
447 ss_state = "LISTENING";
454 ss_state = "CONNECTING";
458 ss_state = "CONNECTED";
461 case SS_DISCONNECTING:
462 ss_state = "DISCONNECTING";
466 ss_state = "UNKNOWN";
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 ");
477 strcat(ss_flags, "]");
479 printf("%-5s %-6ld %-11s %-10s %-13s ",
480 ss_proto, refcnt, ss_flags, ss_type, ss_state);
482 printf("%-6d ",inode);
488 #define _PATH_PROCNET_UDP "/proc/net/udp"
489 #define _PATH_PROCNET_UDP6 "/proc/net/udp6"
490 #define _PATH_PROCNET_TCP "/proc/net/tcp"
491 #define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
492 #define _PATH_PROCNET_RAW "/proc/net/raw"
493 #define _PATH_PROCNET_RAW6 "/proc/net/raw6"
494 #define _PATH_PROCNET_UNIX "/proc/net/unix"
496 static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
502 procinfo = fopen(file, "r");
503 if (procinfo == NULL) {
504 if (errno != ENOENT) {
507 bb_error_msg("no support for `%s' on this system.", name);
511 if (fgets(buffer, sizeof(buffer), procinfo))
512 (proc)(lnr++, buffer);
513 } while (!feof(procinfo));
522 int netstat_main(int argc, char **argv)
526 int showroute = 0, extended = 0;
527 #ifdef CONFIG_FEATURE_IPV6
534 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
537 flags &= ~NETSTAT_CONNECTED;
538 flags |= NETSTAT_LISTENING;
541 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
544 flags |= NETSTAT_NUMERIC;
553 new_flags |= NETSTAT_TCP;
556 new_flags |= NETSTAT_UDP;
559 new_flags |= NETSTAT_RAW;
562 new_flags |= NETSTAT_UNIX;
569 displayroutes ( flags & NETSTAT_NUMERIC, !extended );
572 bb_error_msg_and_die( "-r (display routing table) is not compiled in." );
577 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
580 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
581 printf("Active Internet connections "); /* xxx */
583 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
584 printf("(servers and established)");
586 if (flags&NETSTAT_LISTENING)
587 printf("(only servers)");
589 printf("(w/o servers)");
591 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
593 if (inet && flags&NETSTAT_TCP)
594 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
595 #ifdef CONFIG_FEATURE_IPV6
596 if (inet6 && flags&NETSTAT_TCP)
597 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
599 if (inet && flags&NETSTAT_UDP)
600 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
601 #ifdef CONFIG_FEATURE_IPV6
602 if (inet6 && flags&NETSTAT_UDP)
603 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
605 if (inet && flags&NETSTAT_RAW)
606 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
607 #ifdef CONFIG_FEATURE_IPV6
608 if (inet6 && flags&NETSTAT_RAW)
609 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
611 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)");
616 if (flags&NETSTAT_LISTENING)
617 printf("(only servers)");
619 printf("(w/o servers)");
622 printf("\nProto RefCnt Flags Type State I-Node Path\n");
623 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);