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"
37 extern void displayroutes(int noresolve, int netstatfmt);
40 #define NETSTAT_CONNECTED 0x01
41 #define NETSTAT_LISTENING 0x02
42 #define NETSTAT_NUMERIC 0x04
43 #define NETSTAT_TCP 0x10
44 #define NETSTAT_UDP 0x20
45 #define NETSTAT_RAW 0x40
46 #define NETSTAT_UNIX 0x80
48 int flags = NETSTAT_CONNECTED |
49 NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
51 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
52 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
53 #define PROGNAME_WIDTH2(s) #s
55 #define PRG_HASH_SIZE 211
68 TCP_CLOSING /* now a valid state */
71 static const char *tcp_state[] =
88 SS_FREE = 0, /* not allocated */
89 SS_UNCONNECTED, /* unconnected to any socket */
90 SS_CONNECTING, /* in process of connecting */
91 SS_CONNECTED, /* connected to socket */
92 SS_DISCONNECTING /* in process of disconnecting */
95 #define SO_ACCEPTCON (1<<16) /* performed a listen */
96 #define SO_WAITDATA (1<<17) /* wait data to read */
97 #define SO_NOSPACE (1<<18) /* no space to write */
99 static char *itoa(unsigned int i)
101 /* 21 digits plus null terminator, good for 64-bit or smaller ints */
102 static char local[22];
103 char *p = &local[21];
112 static char *get_sname(int port, const char *proto, int num)
114 char *str=itoa(ntohs(port));
117 struct servent *se=getservbyport(port,proto);
127 static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
131 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
132 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
134 port_name=get_sname(htons(port), proto, numeric);
135 if ((strlen(ip_port) + strlen(port_name)) > 22)
136 ip_port[22 - strlen(port_name)] = '\0';
137 ip_port+=strlen(ip_port);
138 strcat(ip_port, ":");
139 strcat(ip_port, port_name);
142 static void tcp_do_one(int lnr, const char *line)
144 char local_addr[64], rem_addr[64];
145 char *state_str, more[512];
146 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
147 struct sockaddr_in localaddr, remaddr;
148 unsigned long rxq, txq, time_len, retr, inode;
155 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
156 &d, local_addr, &local_port,
157 rem_addr, &rem_port, &state,
158 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
160 if (strlen(local_addr) > 8) {
162 sscanf(local_addr, "%X",
163 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
164 sscanf(rem_addr, "%X",
165 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
166 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
167 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
171 error_msg("warning, got bogus tcp line.\n");
174 state_str=(char*)tcp_state[state];
175 if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
176 (!rem_port && (flags&NETSTAT_LISTENING)))
178 snprint_ip_port(local_addr, sizeof(local_addr),
179 (struct sockaddr *) &localaddr, local_port,
180 "tcp", flags&NETSTAT_NUMERIC);
182 snprint_ip_port(rem_addr, sizeof(rem_addr),
183 (struct sockaddr *) &remaddr, rem_port,
184 "tcp", flags&NETSTAT_NUMERIC);
186 printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
187 rxq, txq, local_addr, rem_addr, state_str);
192 static void udp_do_one(int lnr, const char *line)
194 char local_addr[64], rem_addr[64];
195 char *state_str, more[512];
196 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
197 struct sockaddr_in localaddr, remaddr;
198 unsigned long rxq, txq, time_len, retr, inode;
205 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
206 &d, local_addr, &local_port,
207 rem_addr, &rem_port, &state,
208 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
210 if (strlen(local_addr) > 8) {
212 sscanf(local_addr, "%X",
213 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
214 sscanf(rem_addr, "%X",
215 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
216 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
217 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
221 error_msg("warning, got bogus udp line.\n");
225 case TCP_ESTABLISHED:
226 state_str = "ESTABLISHED";
234 state_str = "UNKNOWN";
238 #define notnull(A) (A.sin_addr.s_addr)
239 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
240 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
242 snprint_ip_port(local_addr, sizeof(local_addr),
243 (struct sockaddr *) &localaddr, local_port,
244 "udp", flags&NETSTAT_NUMERIC);
246 snprint_ip_port(rem_addr, sizeof(rem_addr),
247 (struct sockaddr *) &remaddr, rem_port,
248 "udp", flags&NETSTAT_NUMERIC);
250 printf("udp %6ld %6ld %-23s %-23s %-12s\n",
251 rxq, txq, local_addr, rem_addr, state_str);
256 static void raw_do_one(int lnr, const char *line)
258 char local_addr[64], rem_addr[64];
259 char *state_str, more[512];
260 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
261 struct sockaddr_in localaddr, remaddr;
262 unsigned long rxq, txq, time_len, retr, inode;
269 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
270 &d, local_addr, &local_port,
271 rem_addr, &rem_port, &state,
272 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
274 if (strlen(local_addr) > 8) {
276 sscanf(local_addr, "%X",
277 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
278 sscanf(rem_addr, "%X",
279 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
280 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
281 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
285 error_msg("warning, got bogus raw line.\n");
288 state_str=itoa(state);
290 #define notnull(A) (A.sin_addr.s_addr)
291 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
292 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
294 snprint_ip_port(local_addr, sizeof(local_addr),
295 (struct sockaddr *) &localaddr, local_port,
296 "raw", flags&NETSTAT_NUMERIC);
298 snprint_ip_port(rem_addr, sizeof(rem_addr),
299 (struct sockaddr *) &remaddr, rem_port,
300 "raw", flags&NETSTAT_NUMERIC);
302 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
303 rxq, txq, local_addr, rem_addr, state_str);
310 static void unix_do_one(int nr, const char *line)
313 char path[PATH_MAX], ss_flags[32];
314 char *ss_proto, *ss_state, *ss_type;
315 int num, state, type, inode;
317 unsigned long refcnt, proto, unix_flags;
320 if (strstr(line, "Inode"))
325 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
326 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
328 error_msg("warning, got bogus unix line.\n");
331 if (!(has & HAS_INODE))
332 snprintf(path,sizeof(path),"%d",inode);
334 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
335 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
336 if (!(flags&NETSTAT_LISTENING))
339 if (!(flags&NETSTAT_CONNECTED))
371 ss_type = "SEQPACKET";
385 * Unconnected sockets may be listening
388 if (unix_flags & SO_ACCEPTCON) {
389 ss_state = "LISTENING";
396 ss_state = "CONNECTING";
400 ss_state = "CONNECTED";
403 case SS_DISCONNECTING:
404 ss_state = "DISCONNECTING";
408 ss_state = "UNKNOWN";
411 strcpy(ss_flags, "[ ");
412 if (unix_flags & SO_ACCEPTCON)
413 strcat(ss_flags, "ACC ");
414 if (unix_flags & SO_WAITDATA)
415 strcat(ss_flags, "W ");
416 if (unix_flags & SO_NOSPACE)
417 strcat(ss_flags, "N ");
419 strcat(ss_flags, "]");
421 printf("%-5s %-6ld %-11s %-10s %-13s ",
422 ss_proto, refcnt, ss_flags, ss_type, ss_state);
424 printf("%-6d ",inode);
430 #define _PATH_PROCNET_UDP "/proc/net/udp"
431 #define _PATH_PROCNET_TCP "/proc/net/tcp"
432 #define _PATH_PROCNET_RAW "/proc/net/raw"
433 #define _PATH_PROCNET_UNIX "/proc/net/unix"
435 static int do_info(char *file, char *name, void (*proc)(int, const char *))
442 procinfo = fopen((file), "r");
443 if (procinfo == NULL) {
444 if (errno != ENOENT) {
448 error_msg("%s: no support for `%s' on this system.\n",
453 if (fgets(buffer, sizeof(buffer), procinfo))
454 (proc)(lnr++, buffer);
455 } while (!feof(procinfo));
465 int netstat_main(int argc, char **argv)
469 int showroute = 0, extended = 0;
470 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
473 flags &= ~NETSTAT_CONNECTED;
474 flags |= NETSTAT_LISTENING;
477 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
480 flags |= NETSTAT_NUMERIC;
489 new_flags |= NETSTAT_TCP;
492 new_flags |= NETSTAT_UDP;
495 new_flags |= NETSTAT_RAW;
498 new_flags |= NETSTAT_UNIX;
505 displayroutes ( flags & NETSTAT_NUMERIC, !extended );
508 printf( "-r (display routing table) is not compiled in.\n" );
514 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
517 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
518 printf("Active Internet connections "); /* xxx */
520 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
521 printf("(servers and established)");
523 if (flags&NETSTAT_LISTENING)
524 printf("(only servers)");
526 printf("(w/o servers)");
528 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
530 if (flags&NETSTAT_TCP)
531 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
532 if (flags&NETSTAT_UDP)
533 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
534 if (flags&NETSTAT_RAW)
535 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
536 if (flags&NETSTAT_UNIX) {
537 printf("Active UNIX domain sockets ");
538 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
539 printf("(servers and established)");
541 if (flags&NETSTAT_LISTENING)
542 printf("(only servers)");
544 printf("(w/o servers)");
547 printf("\nProto RefCnt Flags Type State I-Node Path\n");
548 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);