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) 2001 by Bart Visscher <magick@linux-fan.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "inet_common.h"
36 #define NETSTAT_CONNECTED 0x01
37 #define NETSTAT_LISTENING 0x02
38 #define NETSTAT_NUMERIC 0x04
39 #define NETSTAT_TCP 0x10
40 #define NETSTAT_UDP 0x20
41 #define NETSTAT_RAW 0x40
42 #define NETSTAT_UNIX 0x80
44 int flags = NETSTAT_CONNECTED |
45 NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
47 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
48 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
49 #define PROGNAME_WIDTH2(s) #s
51 #define PRG_HASH_SIZE 211
64 TCP_CLOSING /* now a valid state */
67 static const char *tcp_state[] =
84 SS_FREE = 0, /* not allocated */
85 SS_UNCONNECTED, /* unconnected to any socket */
86 SS_CONNECTING, /* in process of connecting */
87 SS_CONNECTED, /* connected to socket */
88 SS_DISCONNECTING /* in process of disconnecting */
91 #define SO_ACCEPTCON (1<<16) /* performed a listen */
92 #define SO_WAITDATA (1<<17) /* wait data to read */
93 #define SO_NOSPACE (1<<18) /* no space to write */
95 static char *itoa(unsigned int i)
97 /* 21 digits plus null terminator, good for 64-bit or smaller ints */
98 static char local[22];
108 static char *get_sname(int port, const char *proto, int num)
110 char *str=itoa(ntohs(port));
113 struct servent *se=getservbyport(port,proto);
123 static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
127 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
128 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
130 port_name=get_sname(htons(port), proto, numeric);
131 if ((strlen(ip_port) + strlen(port_name)) > 22)
132 ip_port[22 - strlen(port_name)] = '\0';
133 ip_port+=strlen(ip_port);
134 strcat(ip_port, ":");
135 strcat(ip_port, port_name);
138 static void tcp_do_one(int lnr, const char *line)
140 char local_addr[64], rem_addr[64];
141 char *state_str, more[512];
142 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
143 struct sockaddr_in localaddr, remaddr;
144 unsigned long rxq, txq, time_len, retr, inode;
151 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
152 &d, local_addr, &local_port,
153 rem_addr, &rem_port, &state,
154 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
156 if (strlen(local_addr) > 8) {
158 sscanf(local_addr, "%X",
159 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
160 sscanf(rem_addr, "%X",
161 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
162 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
163 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
167 error_msg("warning, got bogus tcp line.\n");
170 state_str=(char*)tcp_state[state];
171 if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
172 (!rem_port && (flags&NETSTAT_LISTENING)))
174 snprint_ip_port(local_addr, sizeof(local_addr),
175 (struct sockaddr *) &localaddr, local_port,
176 "tcp", flags&NETSTAT_NUMERIC);
178 snprint_ip_port(rem_addr, sizeof(rem_addr),
179 (struct sockaddr *) &remaddr, rem_port,
180 "tcp", flags&NETSTAT_NUMERIC);
182 printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
183 rxq, txq, local_addr, rem_addr, state_str);
188 static void udp_do_one(int lnr, const char *line)
190 char local_addr[64], rem_addr[64];
191 char *state_str, more[512];
192 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
193 struct sockaddr_in localaddr, remaddr;
194 unsigned long rxq, txq, time_len, retr, inode;
201 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
202 &d, local_addr, &local_port,
203 rem_addr, &rem_port, &state,
204 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
206 if (strlen(local_addr) > 8) {
208 sscanf(local_addr, "%X",
209 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
210 sscanf(rem_addr, "%X",
211 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
212 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
213 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
217 error_msg("warning, got bogus udp line.\n");
221 case TCP_ESTABLISHED:
222 state_str = "ESTABLISHED";
230 state_str = "UNKNOWN";
234 #define notnull(A) (A.sin_addr.s_addr)
235 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
236 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
238 snprint_ip_port(local_addr, sizeof(local_addr),
239 (struct sockaddr *) &localaddr, local_port,
240 "udp", flags&NETSTAT_NUMERIC);
242 snprint_ip_port(rem_addr, sizeof(rem_addr),
243 (struct sockaddr *) &remaddr, rem_port,
244 "udp", flags&NETSTAT_NUMERIC);
246 printf("udp %6ld %6ld %-23s %-23s %-12s\n",
247 rxq, txq, local_addr, rem_addr, state_str);
252 static void raw_do_one(int lnr, const char *line)
254 char local_addr[64], rem_addr[64];
255 char *state_str, more[512];
256 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
257 struct sockaddr_in localaddr, remaddr;
258 unsigned long rxq, txq, time_len, retr, inode;
265 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
266 &d, local_addr, &local_port,
267 rem_addr, &rem_port, &state,
268 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
270 if (strlen(local_addr) > 8) {
272 sscanf(local_addr, "%X",
273 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
274 sscanf(rem_addr, "%X",
275 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
276 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
277 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
281 error_msg("warning, got bogus raw line.\n");
284 state_str=itoa(state);
286 #define notnull(A) (A.sin_addr.s_addr)
287 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
288 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
290 snprint_ip_port(local_addr, sizeof(local_addr),
291 (struct sockaddr *) &localaddr, local_port,
292 "raw", flags&NETSTAT_NUMERIC);
294 snprint_ip_port(rem_addr, sizeof(rem_addr),
295 (struct sockaddr *) &remaddr, rem_port,
296 "raw", flags&NETSTAT_NUMERIC);
298 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
299 rxq, txq, local_addr, rem_addr, state_str);
306 static void unix_do_one(int nr, const char *line)
309 char path[PATH_MAX], ss_flags[32];
310 char *ss_proto, *ss_state, *ss_type;
311 int num, state, type, inode;
313 unsigned long refcnt, proto, unix_flags;
316 if (strstr(line, "Inode"))
321 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
322 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
324 error_msg("warning, got bogus unix line.\n");
327 if (!(has & HAS_INODE))
328 snprintf(path,sizeof(path),"%d",inode);
330 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
331 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
332 if (!(flags&NETSTAT_LISTENING))
335 if (!(flags&NETSTAT_CONNECTED))
367 ss_type = "SEQPACKET";
381 * Unconnected sockets may be listening
384 if (unix_flags & SO_ACCEPTCON) {
385 ss_state = "LISTENING";
392 ss_state = "CONNECTING";
396 ss_state = "CONNECTED";
399 case SS_DISCONNECTING:
400 ss_state = "DISCONNECTING";
404 ss_state = "UNKNOWN";
407 strcpy(ss_flags, "[ ");
408 if (unix_flags & SO_ACCEPTCON)
409 strcat(ss_flags, "ACC ");
410 if (unix_flags & SO_WAITDATA)
411 strcat(ss_flags, "W ");
412 if (unix_flags & SO_NOSPACE)
413 strcat(ss_flags, "N ");
415 strcat(ss_flags, "]");
417 printf("%-5s %-6ld %-11s %-10s %-13s ",
418 ss_proto, refcnt, ss_flags, ss_type, ss_state);
420 printf("%-6d ",inode);
426 #define _PATH_PROCNET_UDP "/proc/net/udp"
427 #define _PATH_PROCNET_TCP "/proc/net/tcp"
428 #define _PATH_PROCNET_RAW "/proc/net/raw"
429 #define _PATH_PROCNET_UNIX "/proc/net/unix"
431 static int do_info(char *file, char *name, void (*proc)(int, const char *))
438 procinfo = fopen((file), "r");
439 if (procinfo == NULL) {
440 if (errno != ENOENT) {
444 error_msg("%s: no support for `%s' on this system.\n",
449 if (fgets(buffer, sizeof(buffer), procinfo))
450 (proc)(lnr++, buffer);
451 } while (!feof(procinfo));
461 int netstat_main(int argc, char **argv)
465 while ((opt = getopt(argc, argv, "lantuwx")) != -1)
468 flags &= ~NETSTAT_CONNECTED;
469 flags |= NETSTAT_LISTENING;
472 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
475 flags |= NETSTAT_NUMERIC;
478 new_flags |= NETSTAT_TCP;
481 new_flags |= NETSTAT_UDP;
484 new_flags |= NETSTAT_RAW;
487 new_flags |= NETSTAT_UNIX;
493 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
496 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
497 printf("Active Internet connections "); /* xxx */
499 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
500 printf("(servers and established)");
502 if (flags&NETSTAT_LISTENING)
503 printf("(only servers)");
505 printf("(w/o servers)");
507 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
509 if (flags&NETSTAT_TCP)
510 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
511 if (flags&NETSTAT_UDP)
512 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
513 if (flags&NETSTAT_RAW)
514 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
515 if (flags&NETSTAT_UNIX) {
516 printf("Active UNIX domain sockets ");
517 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
518 printf("(servers and established)");
520 if (flags&NETSTAT_LISTENING)
521 printf("(only servers)");
523 printf("(w/o servers)");
526 printf("\nProto RefCnt Flags Type State I-Node Path\n");
527 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);