This commit was manufactured by cvs2svn to create tag 'busybox_1_00'.
[oweals/busybox.git] / busybox / networking / netstat.c
1 /* 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  *
6  * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
7  *
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.
12  *
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.
17  *
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
21  *
22  * 2002-04-20
23  * IPV6 support added by Bart Visscher <magick@linux-fan.com>
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33 #include <dirent.h>
34 #include <unistd.h>
35 #include "inet_common.h"
36 #include "busybox.h"
37 #include "pwd_.h"
38
39 #ifdef CONFIG_ROUTE
40 extern void displayroutes(int noresolve, int netstatfmt);
41 #endif
42
43 #define NETSTAT_CONNECTED       0x01
44 #define NETSTAT_LISTENING       0x02
45 #define NETSTAT_NUMERIC         0x04
46 #define NETSTAT_TCP                     0x10
47 #define NETSTAT_UDP                     0x20
48 #define NETSTAT_RAW                     0x40
49 #define NETSTAT_UNIX            0x80
50
51 static int flags = NETSTAT_CONNECTED |
52                         NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
53
54 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
55 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
56 #define PROGNAME_WIDTH2(s) #s
57
58 #define PRG_HASH_SIZE 211
59
60 enum {
61     TCP_ESTABLISHED = 1,
62     TCP_SYN_SENT,
63     TCP_SYN_RECV,
64     TCP_FIN_WAIT1,
65     TCP_FIN_WAIT2,
66     TCP_TIME_WAIT,
67     TCP_CLOSE,
68     TCP_CLOSE_WAIT,
69     TCP_LAST_ACK,
70     TCP_LISTEN,
71     TCP_CLOSING                 /* now a valid state */
72 };
73
74 static const char * const tcp_state[] =
75 {
76     "",
77     "ESTABLISHED",
78     "SYN_SENT",
79     "SYN_RECV",
80     "FIN_WAIT1",
81     "FIN_WAIT2",
82     "TIME_WAIT",
83     "CLOSE",
84     "CLOSE_WAIT",
85     "LAST_ACK",
86     "LISTEN",
87     "CLOSING"
88 };
89
90 typedef enum {
91     SS_FREE = 0,                /* not allocated                */
92     SS_UNCONNECTED,             /* unconnected to any socket    */
93     SS_CONNECTING,              /* in process of connecting     */
94     SS_CONNECTED,               /* connected to socket          */
95     SS_DISCONNECTING            /* in process of disconnecting  */
96 } socket_state;
97
98 #define SO_ACCEPTCON    (1<<16) /* performed a listen           */
99 #define SO_WAITDATA     (1<<17) /* wait data to read            */
100 #define SO_NOSPACE      (1<<18) /* no space to write            */
101
102 static char *itoa(unsigned int i)
103 {
104         /* 21 digits plus null terminator, good for 64-bit or smaller ints */
105         static char local[22];
106         char *p = &local[21];
107         *p-- = '\0';
108         do {
109                 *p-- = '0' + i % 10;
110                 i /= 10;
111         } while (i > 0);
112         return p + 1;
113 }
114
115 static char *get_sname(int port, const char *proto, int num)
116 {
117         char *str=itoa(ntohs(port));
118         if (num) {
119         } else {
120                 struct servent *se=getservbyport(port,proto);
121                 if (se)
122                         str=se->s_name;
123         }
124         if (!port) {
125                 str="*";
126         }
127         return str;
128 }
129
130 static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
131 {
132         char *port_name;
133
134 #ifdef CONFIG_FEATURE_IPV6
135         if (addr->sa_family == AF_INET6) {
136                 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
137                                            (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
138         } else
139 #endif
140         {
141         INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
142                 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
143                 0xffffffff);
144         }
145         port_name=get_sname(htons(port), proto, numeric);
146         if ((strlen(ip_port) + strlen(port_name)) > 22)
147                 ip_port[22 - strlen(port_name)] = '\0';
148         ip_port+=strlen(ip_port);
149         strcat(ip_port, ":");
150         strcat(ip_port, port_name);
151 }
152
153 static void tcp_do_one(int lnr, const char *line)
154 {
155         char local_addr[64], rem_addr[64];
156         const char *state_str;
157         char more[512];
158         int num, local_port, rem_port, d, state, timer_run, uid, timeout;
159 #ifdef CONFIG_FEATURE_IPV6
160         struct sockaddr_in6 localaddr, remaddr;
161         char addr6[INET6_ADDRSTRLEN];
162         struct in6_addr in6;
163 #else
164         struct sockaddr_in localaddr, remaddr;
165 #endif
166         unsigned long rxq, txq, time_len, retr, inode;
167
168         if (lnr == 0)
169                 return;
170
171         more[0] = '\0';
172         num = sscanf(line,
173                                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
174                                  &d, local_addr, &local_port,
175                                  rem_addr, &rem_port, &state,
176                                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
177
178         if (strlen(local_addr) > 8) {
179 #ifdef CONFIG_FEATURE_IPV6
180                 sscanf(local_addr, "%08X%08X%08X%08X",
181                            &in6.s6_addr32[0], &in6.s6_addr32[1],
182                            &in6.s6_addr32[2], &in6.s6_addr32[3]);
183                 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
184                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
185                 sscanf(rem_addr, "%08X%08X%08X%08X",
186                            &in6.s6_addr32[0], &in6.s6_addr32[1],
187                            &in6.s6_addr32[2], &in6.s6_addr32[3]);
188                 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
189                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
190                 localaddr.sin6_family = AF_INET6;
191                 remaddr.sin6_family = AF_INET6;
192 #endif
193         } else {
194                 sscanf(local_addr, "%X",
195                            &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
196                 sscanf(rem_addr, "%X",
197                            &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
198                 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
199                 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
200         }
201
202         if (num < 10) {
203                 bb_error_msg("warning, got bogus tcp line.");
204                 return;
205         }
206         state_str = tcp_state[state];
207         if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
208                 (!rem_port && (flags&NETSTAT_LISTENING)))
209         {
210                 snprint_ip_port(local_addr, sizeof(local_addr),
211                                                 (struct sockaddr *) &localaddr, local_port,
212                                                 "tcp", flags&NETSTAT_NUMERIC);
213
214                 snprint_ip_port(rem_addr, sizeof(rem_addr),
215                                                 (struct sockaddr *) &remaddr, rem_port,
216                                                 "tcp", flags&NETSTAT_NUMERIC);
217
218                 printf("tcp   %6ld %6ld %-23s %-23s %-12s\n",
219                            rxq, txq, local_addr, rem_addr, state_str);
220
221         }
222 }
223
224 static void udp_do_one(int lnr, const char *line)
225 {
226         char local_addr[64], rem_addr[64];
227         char *state_str, more[512];
228         int num, local_port, rem_port, d, state, timer_run, uid, timeout;
229 #ifdef CONFIG_FEATURE_IPV6
230         struct sockaddr_in6 localaddr, remaddr;
231         char addr6[INET6_ADDRSTRLEN];
232         struct in6_addr in6;
233 #else
234         struct sockaddr_in localaddr, remaddr;
235 #endif
236         unsigned long rxq, txq, time_len, retr, inode;
237
238         if (lnr == 0)
239                 return;
240
241         more[0] = '\0';
242         num = sscanf(line,
243                                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
244                                  &d, local_addr, &local_port,
245                                  rem_addr, &rem_port, &state,
246                                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
247
248         if (strlen(local_addr) > 8) {
249 #ifdef CONFIG_FEATURE_IPV6
250         /* Demangle what the kernel gives us */
251                 sscanf(local_addr, "%08X%08X%08X%08X",
252                            &in6.s6_addr32[0], &in6.s6_addr32[1],
253                            &in6.s6_addr32[2], &in6.s6_addr32[3]);
254                 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
255                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
256                 sscanf(rem_addr, "%08X%08X%08X%08X",
257                            &in6.s6_addr32[0], &in6.s6_addr32[1],
258                            &in6.s6_addr32[2], &in6.s6_addr32[3]);
259                 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
260                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
261                 localaddr.sin6_family = AF_INET6;
262                 remaddr.sin6_family = AF_INET6;
263 #endif
264         } else {
265                 sscanf(local_addr, "%X",
266                            &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
267                 sscanf(rem_addr, "%X",
268                            &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
269                 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
270                 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
271         }
272
273         if (num < 10) {
274                 bb_error_msg("warning, got bogus udp line.");
275                 return;
276         }
277         switch (state) {
278                 case TCP_ESTABLISHED:
279                         state_str = "ESTABLISHED";
280                         break;
281
282                 case TCP_CLOSE:
283                         state_str = "";
284                         break;
285
286                 default:
287                         state_str = "UNKNOWN";
288                         break;
289         }
290
291 #ifdef CONFIG_FEATURE_IPV6
292 # define notnull(A) (((A.sin6_family == AF_INET6) &&            \
293                                          ((A.sin6_addr.s6_addr32[0]) ||            \
294                                           (A.sin6_addr.s6_addr32[1]) ||            \
295                                           (A.sin6_addr.s6_addr32[2]) ||            \
296                                           (A.sin6_addr.s6_addr32[3]))) ||          \
297                                         ((A.sin6_family == AF_INET) &&             \
298                                          ((struct sockaddr_in *) &A)->sin_addr.s_addr))
299 #else
300 # define notnull(A) (A.sin_addr.s_addr)
301 #endif
302         if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
303                 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
304         {
305                 snprint_ip_port(local_addr, sizeof(local_addr),
306                                                 (struct sockaddr *) &localaddr, local_port,
307                                                 "udp", flags&NETSTAT_NUMERIC);
308
309                 snprint_ip_port(rem_addr, sizeof(rem_addr),
310                                                 (struct sockaddr *) &remaddr, rem_port,
311                                                 "udp", flags&NETSTAT_NUMERIC);
312
313                 printf("udp   %6ld %6ld %-23s %-23s %-12s\n",
314                            rxq, txq, local_addr, rem_addr, state_str);
315
316         }
317 }
318
319 static void raw_do_one(int lnr, const char *line)
320 {
321         char local_addr[64], rem_addr[64];
322         char *state_str, more[512];
323         int num, local_port, rem_port, d, state, timer_run, uid, timeout;
324 #ifdef CONFIG_FEATURE_IPV6
325         struct sockaddr_in6 localaddr, remaddr;
326         char addr6[INET6_ADDRSTRLEN];
327         struct in6_addr in6;
328 #else
329         struct sockaddr_in localaddr, remaddr;
330 #endif
331         unsigned long rxq, txq, time_len, retr, inode;
332
333         if (lnr == 0)
334                 return;
335
336         more[0] = '\0';
337         num = sscanf(line,
338                                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
339                                  &d, local_addr, &local_port,
340                                  rem_addr, &rem_port, &state,
341                                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
342
343         if (strlen(local_addr) > 8) {
344 #ifdef CONFIG_FEATURE_IPV6
345                 sscanf(local_addr, "%08X%08X%08X%08X",
346                            &in6.s6_addr32[0], &in6.s6_addr32[1],
347                            &in6.s6_addr32[2], &in6.s6_addr32[3]);
348                 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
349                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
350                 sscanf(rem_addr, "%08X%08X%08X%08X",
351                            &in6.s6_addr32[0], &in6.s6_addr32[1],
352                            &in6.s6_addr32[2], &in6.s6_addr32[3]);
353                 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
354                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
355                 localaddr.sin6_family = AF_INET6;
356                 remaddr.sin6_family = AF_INET6;
357 #endif
358         } else {
359                 sscanf(local_addr, "%X",
360                            &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
361                 sscanf(rem_addr, "%X",
362                            &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
363                 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
364                 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
365         }
366
367         if (num < 10) {
368                 bb_error_msg("warning, got bogus raw line.");
369                 return;
370         }
371         state_str=itoa(state);
372
373 #ifdef CONFIG_FEATURE_IPV6
374 # define notnull(A) (((A.sin6_family == AF_INET6) &&            \
375                                          ((A.sin6_addr.s6_addr32[0]) ||            \
376                                           (A.sin6_addr.s6_addr32[1]) ||            \
377                                           (A.sin6_addr.s6_addr32[2]) ||            \
378                                           (A.sin6_addr.s6_addr32[3]))) ||          \
379                                         ((A.sin6_family == AF_INET) &&             \
380                                          ((struct sockaddr_in *) &A)->sin_addr.s_addr))
381 #else
382 # define notnull(A) (A.sin_addr.s_addr)
383 #endif
384         if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
385                 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
386         {
387                 snprint_ip_port(local_addr, sizeof(local_addr),
388                                                 (struct sockaddr *) &localaddr, local_port,
389                                                 "raw", flags&NETSTAT_NUMERIC);
390
391                 snprint_ip_port(rem_addr, sizeof(rem_addr),
392                                                 (struct sockaddr *) &remaddr, rem_port,
393                                                 "raw", flags&NETSTAT_NUMERIC);
394
395                 printf("raw   %6ld %6ld %-23s %-23s %-12s\n",
396                            rxq, txq, local_addr, rem_addr, state_str);
397
398         }
399 }
400
401 #define HAS_INODE 1
402
403 static void unix_do_one(int nr, const char *line)
404 {
405         static int has = 0;
406         char path[PATH_MAX], ss_flags[32];
407         char *ss_proto, *ss_state, *ss_type;
408         int num, state, type, inode;
409         void *d;
410         unsigned long refcnt, proto, unix_flags;
411
412         if (nr == 0) {
413                 if (strstr(line, "Inode"))
414                         has |= HAS_INODE;
415                 return;
416         }
417         path[0] = '\0';
418         num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
419                                  &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
420         if (num < 6) {
421                 bb_error_msg("warning, got bogus unix line.");
422                 return;
423         }
424         if (!(has & HAS_INODE))
425                 snprintf(path,sizeof(path),"%d",inode);
426
427         if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
428                 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
429                         if (!(flags&NETSTAT_LISTENING))
430                                 return;
431                 } else {
432                         if (!(flags&NETSTAT_CONNECTED))
433                                 return;
434                 }
435         }
436
437         switch (proto) {
438                 case 0:
439                         ss_proto = "unix";
440                         break;
441
442                 default:
443                         ss_proto = "??";
444         }
445
446         switch (type) {
447                 case SOCK_STREAM:
448                         ss_type = "STREAM";
449                         break;
450
451                 case SOCK_DGRAM:
452                         ss_type = "DGRAM";
453                         break;
454
455                 case SOCK_RAW:
456                         ss_type = "RAW";
457                         break;
458
459                 case SOCK_RDM:
460                         ss_type = "RDM";
461                         break;
462
463                 case SOCK_SEQPACKET:
464                         ss_type = "SEQPACKET";
465                         break;
466
467                 default:
468                         ss_type = "UNKNOWN";
469         }
470
471         switch (state) {
472                 case SS_FREE:
473                         ss_state = "FREE";
474                         break;
475
476                 case SS_UNCONNECTED:
477                         /*
478                          * Unconnected sockets may be listening
479                          * for something.
480                          */
481                         if (unix_flags & SO_ACCEPTCON) {
482                                 ss_state = "LISTENING";
483                         } else {
484                                 ss_state = "";
485                         }
486                         break;
487
488                 case SS_CONNECTING:
489                         ss_state = "CONNECTING";
490                         break;
491
492                 case SS_CONNECTED:
493                         ss_state = "CONNECTED";
494                         break;
495
496                 case SS_DISCONNECTING:
497                         ss_state = "DISCONNECTING";
498                         break;
499
500                 default:
501                         ss_state = "UNKNOWN";
502         }
503
504         strcpy(ss_flags, "[ ");
505         if (unix_flags & SO_ACCEPTCON)
506                 strcat(ss_flags, "ACC ");
507         if (unix_flags & SO_WAITDATA)
508                 strcat(ss_flags, "W ");
509         if (unix_flags & SO_NOSPACE)
510                 strcat(ss_flags, "N ");
511
512         strcat(ss_flags, "]");
513
514         printf("%-5s %-6ld %-11s %-10s %-13s ",
515                    ss_proto, refcnt, ss_flags, ss_type, ss_state);
516         if (has & HAS_INODE)
517                 printf("%-6d ",inode);
518         else
519                 printf("-      ");
520         puts(path);
521 }
522
523 #define _PATH_PROCNET_UDP "/proc/net/udp"
524 #define _PATH_PROCNET_UDP6 "/proc/net/udp6"
525 #define _PATH_PROCNET_TCP "/proc/net/tcp"
526 #define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
527 #define _PATH_PROCNET_RAW "/proc/net/raw"
528 #define _PATH_PROCNET_RAW6 "/proc/net/raw6"
529 #define _PATH_PROCNET_UNIX "/proc/net/unix"
530
531 static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
532 {
533         char buffer[8192];
534         int lnr = 0;
535         FILE *procinfo;
536
537         procinfo = fopen(file, "r");
538         if (procinfo == NULL) {
539                 if (errno != ENOENT) {
540                         perror(file);
541                 } else {
542                 bb_error_msg("no support for `%s' on this system.", name);
543                 }
544         } else {
545                 do {
546                         if (fgets(buffer, sizeof(buffer), procinfo))
547                                 (proc)(lnr++, buffer);
548                 } while (!feof(procinfo));
549                 fclose(procinfo);
550         }
551 }
552
553 /*
554  * Our main function.
555  */
556
557 int netstat_main(int argc, char **argv)
558 {
559         int opt;
560         int new_flags=0;
561         int showroute = 0, extended = 0;
562 #ifdef CONFIG_FEATURE_IPV6
563         int inet=1;
564         int inet6=1;
565 #else
566 # define inet 1
567 # define inet6 0
568 #endif
569         while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
570                 switch (opt) {
571                 case 'l':
572                         flags &= ~NETSTAT_CONNECTED;
573                         flags |= NETSTAT_LISTENING;
574                         break;
575                 case 'a':
576                         flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
577                         break;
578                 case 'n':
579                         flags |= NETSTAT_NUMERIC;
580                         break;
581                 case 'r':
582                         showroute = 1;
583                         break;
584                 case 'e':
585                         extended = 1;
586                         break;
587                 case 't':
588                         new_flags |= NETSTAT_TCP;
589                         break;
590                 case 'u':
591                         new_flags |= NETSTAT_UDP;
592                         break;
593                 case 'w':
594                         new_flags |= NETSTAT_RAW;
595                         break;
596                 case 'x':
597                         new_flags |= NETSTAT_UNIX;
598                         break;
599                 default:
600                         bb_show_usage();
601                 }
602         if ( showroute ) {
603 #ifdef CONFIG_ROUTE
604                 displayroutes ( flags & NETSTAT_NUMERIC, !extended );
605                 return 0;
606 #else
607                 bb_error_msg_and_die( "-r (display routing table) is not compiled in." );
608 #endif
609         }
610
611         if (new_flags) {
612                 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
613                 flags |= new_flags;
614         }
615         if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
616                 printf("Active Internet connections "); /* xxx */
617
618                 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
619                         printf("(servers and established)");
620                 else {
621                         if (flags&NETSTAT_LISTENING)
622                                 printf("(only servers)");
623                         else
624                                 printf("(w/o servers)");
625                 }
626                 printf("\nProto Recv-Q Send-Q Local Address           Foreign Address         State      \n");
627         }
628         if (inet && flags&NETSTAT_TCP)
629                 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
630 #ifdef CONFIG_FEATURE_IPV6
631         if (inet6 && flags&NETSTAT_TCP)
632                 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
633 #endif
634         if (inet && flags&NETSTAT_UDP)
635                 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
636 #ifdef CONFIG_FEATURE_IPV6
637         if (inet6 && flags&NETSTAT_UDP)
638                 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
639 #endif
640         if (inet && flags&NETSTAT_RAW)
641                 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
642 #ifdef CONFIG_FEATURE_IPV6
643         if (inet6 && flags&NETSTAT_RAW)
644                 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
645 #endif
646         if (flags&NETSTAT_UNIX) {
647                 printf("Active UNIX domain sockets ");
648                 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
649                         printf("(servers and established)");
650                 else {
651                         if (flags&NETSTAT_LISTENING)
652                                 printf("(only servers)");
653                         else
654                                 printf("(w/o servers)");
655                 }
656
657                 printf("\nProto RefCnt Flags       Type       State         I-Node Path\n");
658                 do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);
659         }
660         return 0;
661 }