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
32 #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 static 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 * const 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 const char *state_str;
147 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
148 struct sockaddr_in localaddr, remaddr;
149 unsigned long rxq, txq, time_len, retr, inode;
156 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
157 &d, local_addr, &local_port,
158 rem_addr, &rem_port, &state,
159 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
161 if (strlen(local_addr) > 8) {
163 sscanf(local_addr, "%X",
164 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
165 sscanf(rem_addr, "%X",
166 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
167 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
168 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
172 error_msg("warning, got bogus tcp line.");
175 state_str = tcp_state[state];
176 if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
177 (!rem_port && (flags&NETSTAT_LISTENING)))
179 snprint_ip_port(local_addr, sizeof(local_addr),
180 (struct sockaddr *) &localaddr, local_port,
181 "tcp", flags&NETSTAT_NUMERIC);
183 snprint_ip_port(rem_addr, sizeof(rem_addr),
184 (struct sockaddr *) &remaddr, rem_port,
185 "tcp", flags&NETSTAT_NUMERIC);
187 printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
188 rxq, txq, local_addr, rem_addr, state_str);
193 static void udp_do_one(int lnr, const char *line)
195 char local_addr[64], rem_addr[64];
196 char *state_str, more[512];
197 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
198 struct sockaddr_in localaddr, remaddr;
199 unsigned long rxq, txq, time_len, retr, inode;
206 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
207 &d, local_addr, &local_port,
208 rem_addr, &rem_port, &state,
209 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
211 if (strlen(local_addr) > 8) {
213 sscanf(local_addr, "%X",
214 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
215 sscanf(rem_addr, "%X",
216 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
217 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
218 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
222 error_msg("warning, got bogus udp line.");
226 case TCP_ESTABLISHED:
227 state_str = "ESTABLISHED";
235 state_str = "UNKNOWN";
239 #define notnull(A) (A.sin_addr.s_addr)
240 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
241 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
243 snprint_ip_port(local_addr, sizeof(local_addr),
244 (struct sockaddr *) &localaddr, local_port,
245 "udp", flags&NETSTAT_NUMERIC);
247 snprint_ip_port(rem_addr, sizeof(rem_addr),
248 (struct sockaddr *) &remaddr, rem_port,
249 "udp", flags&NETSTAT_NUMERIC);
251 printf("udp %6ld %6ld %-23s %-23s %-12s\n",
252 rxq, txq, local_addr, rem_addr, state_str);
257 static void raw_do_one(int lnr, const char *line)
259 char local_addr[64], rem_addr[64];
260 char *state_str, more[512];
261 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
262 struct sockaddr_in localaddr, remaddr;
263 unsigned long rxq, txq, time_len, retr, inode;
270 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
271 &d, local_addr, &local_port,
272 rem_addr, &rem_port, &state,
273 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
275 if (strlen(local_addr) > 8) {
277 sscanf(local_addr, "%X",
278 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
279 sscanf(rem_addr, "%X",
280 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
281 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
282 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
286 error_msg("warning, got bogus raw line.");
289 state_str=itoa(state);
291 #define notnull(A) (A.sin_addr.s_addr)
292 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
293 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
295 snprint_ip_port(local_addr, sizeof(local_addr),
296 (struct sockaddr *) &localaddr, local_port,
297 "raw", flags&NETSTAT_NUMERIC);
299 snprint_ip_port(rem_addr, sizeof(rem_addr),
300 (struct sockaddr *) &remaddr, rem_port,
301 "raw", flags&NETSTAT_NUMERIC);
303 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
304 rxq, txq, local_addr, rem_addr, state_str);
311 static void unix_do_one(int nr, const char *line)
314 char path[PATH_MAX], ss_flags[32];
315 char *ss_proto, *ss_state, *ss_type;
316 int num, state, type, inode;
318 unsigned long refcnt, proto, unix_flags;
321 if (strstr(line, "Inode"))
326 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
327 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
329 error_msg("warning, got bogus unix line.");
332 if (!(has & HAS_INODE))
333 snprintf(path,sizeof(path),"%d",inode);
335 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
336 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
337 if (!(flags&NETSTAT_LISTENING))
340 if (!(flags&NETSTAT_CONNECTED))
372 ss_type = "SEQPACKET";
386 * Unconnected sockets may be listening
389 if (unix_flags & SO_ACCEPTCON) {
390 ss_state = "LISTENING";
397 ss_state = "CONNECTING";
401 ss_state = "CONNECTED";
404 case SS_DISCONNECTING:
405 ss_state = "DISCONNECTING";
409 ss_state = "UNKNOWN";
412 strcpy(ss_flags, "[ ");
413 if (unix_flags & SO_ACCEPTCON)
414 strcat(ss_flags, "ACC ");
415 if (unix_flags & SO_WAITDATA)
416 strcat(ss_flags, "W ");
417 if (unix_flags & SO_NOSPACE)
418 strcat(ss_flags, "N ");
420 strcat(ss_flags, "]");
422 printf("%-5s %-6ld %-11s %-10s %-13s ",
423 ss_proto, refcnt, ss_flags, ss_type, ss_state);
425 printf("%-6d ",inode);
431 #define _PATH_PROCNET_UDP "/proc/net/udp"
432 #define _PATH_PROCNET_TCP "/proc/net/tcp"
433 #define _PATH_PROCNET_RAW "/proc/net/raw"
434 #define _PATH_PROCNET_UNIX "/proc/net/unix"
436 static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
442 procinfo = fopen(file, "r");
443 if (procinfo == NULL) {
444 if (errno != ENOENT) {
447 error_msg("no support for `%s' on this system.", name);
451 if (fgets(buffer, sizeof(buffer), procinfo))
452 (proc)(lnr++, buffer);
453 } while (!feof(procinfo));
462 int netstat_main(int argc, char **argv)
466 int showroute = 0, extended = 0;
467 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
470 flags &= ~NETSTAT_CONNECTED;
471 flags |= NETSTAT_LISTENING;
474 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
477 flags |= NETSTAT_NUMERIC;
486 new_flags |= NETSTAT_TCP;
489 new_flags |= NETSTAT_UDP;
492 new_flags |= NETSTAT_RAW;
495 new_flags |= NETSTAT_UNIX;
502 displayroutes ( flags & NETSTAT_NUMERIC, !extended );
505 error_msg_and_die( "-r (display routing table) is not compiled in." );
510 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
513 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
514 printf("Active Internet connections "); /* xxx */
516 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
517 printf("(servers and established)");
519 if (flags&NETSTAT_LISTENING)
520 printf("(only servers)");
522 printf("(w/o servers)");
524 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
526 if (flags&NETSTAT_TCP)
527 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
528 if (flags&NETSTAT_UDP)
529 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
530 if (flags&NETSTAT_RAW)
531 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
532 if (flags&NETSTAT_UNIX) {
533 printf("Active UNIX domain sockets ");
534 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
535 printf("(servers and established)");
537 if (flags&NETSTAT_LISTENING)
538 printf("(only servers)");
540 printf("(w/o servers)");
543 printf("\nProto RefCnt Flags Type State I-Node Path\n");
544 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);