Add Bluetooth socket support
[platform/upstream/net-tools.git] / netstat.c
1 /*
2  * netstat    This file contains an implementation of the command
3  *              that helps in debugging the networking modules.
4  *
5  * NET-TOOLS    A collection of programs that form the base set of the
6  *              NET-3 Networking Distribution for the LINUX operating
7  *              system.
8  *
9  * Version:     $Id: netstat.c,v 1.73 2011-04-20 01:35:22 ecki Exp $
10  *
11  * Authors:     Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
12  *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
13  *              Phil Packer, <pep@wicked.demon.co.uk>
14  *              Johannes Stille, <johannes@titan.os.open.de>
15  *              Bernd Eckenfels, <net-tools@lina.inka.de>
16  *              Phil Blundell <philb@gnu.org>
17  *              Tuan Hoang <tqhoang@bigfoot.com>
18  *
19  * Tuned for NET3 by:
20  *              Alan Cox, <A.Cox@swansea.ac.uk>
21  *              Copyright (c) 1993  Fred Baumgarten
22  *
23  * Modified:
24  *
25  *960116 {1.01} Bernd Eckenfels:        verbose, cleanups
26  *960204 {1.10} Bernd Eckenfels:        aftrans, usage, new route_info, 
27  *                                      DLFT_AF
28  *960204 {1.11} Bernd Eckenfels:        netlink support
29  *960204 {1.12} Bernd Eckenfels:        route_init()
30  *960215 {1.13} Bernd Eckenfels:        netlink_print honors HAVE_
31  *960217 {1.14} Bernd Eckenfels:        masq_info from Jos Vos and 
32  *                                      ax25_info from Jonathan Naylor.
33  *960218 {1.15} Bernd Eckenfels:        ipx_info rewritten, -e for tcp/ipx
34  *960220 {1.16} Bernd Eckenfels:        minor output reformats, -a for -x
35  *960221 {1.17} Bernd Eckenfels:        route_init->getroute_init
36  *960426 {1.18} Bernd Eckenfels:        new RTACTION, SYM/NUM, FIB/CACHE
37  *960517 {1.19} Bernd Eckenfels:        usage() spelling fix and --unix inode, 
38  *                                      ':' is part of sock_addr for --inet
39  *960822 {x.xx} Frank Strauss:          INET6 support
40  *
41  *970406 {1.33} Philip Copeland         Added snmp reporting support module -s
42  *                                      code provided by Andi Kleen
43  *                                      (relly needs to be kernel hooked but 
44  *                                      this will do in the meantime)
45  *                                      minor header file misplacement tidy up.
46  *980815 {1.xx} Stephane Fillod:       X.25 support
47  *980411 {1.34} Arnaldo Carvalho        i18n: catgets -> gnu gettext, substitution
48  *                                      of sprintf for snprintf
49  *10/1998       Andi Kleen              Use new interface primitives.
50  *990101 {1.36} Bernd Eckenfels         usage updated to include -s and -C -F,
51  *                                      fixed netstat -rC output (lib/inet_gr.c)
52  *                                      removed broken NETLINK Support
53  *                                      fixed format for /proc/net/udp|tcp|raw
54  *                                      added -w,-t,-u TcpExt support to -s
55  *990131 {1.37} Jan Kratochvil          added -p for prg_cache() & friends
56  *                                      Flames to <short@ucw.cz>.
57  *              Tuan Hoang              added IGMP support for IPv4 and IPv6
58  *
59  *990420 {1.38} Tuan Hoang              removed a useless assignment from igmp_do_one()
60  *20010404 {1.39} Arnaldo Carvalho de Melo - use setlocale
61  *20081201 {1.42} Brian Micek           added -L|--udplite options for RFC 3828 
62  *20020722 {1.51} Thomas Preusser       added SCTP over IPv4 support
63  *
64  *              This program is free software; you can redistribute it
65  *              and/or  modify it under  the terms of  the GNU General
66  *              Public  License as  published  by  the  Free  Software
67  *              Foundation;  either  version 2 of the License, or  (at
68  *              your option) any later version.
69  *
70  */
71 #include <errno.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <strings.h>
76 #include <unistd.h>
77 #include <ctype.h>
78 #include <fcntl.h>
79 #include <netdb.h>
80 #include <paths.h>
81 #include <pwd.h>
82 #include <getopt.h>
83 #include <sys/param.h>
84 #include <sys/socket.h>
85 #include <arpa/inet.h>
86 #include <netinet/in.h>
87 #include <sys/ioctl.h>
88 #include <sys/stat.h>
89 #include <net/if.h>
90 #include <dirent.h>
91
92 #include "net-support.h"
93 #include "pathnames.h"
94 #include "version.h"
95 #include "config.h"
96 #include "intl.h"
97 #include "sockets.h"
98 #include "interface.h"
99 #include "util.h"
100 #include "proc.h"
101
102 #if HAVE_BLUETOOTH
103 #include <bluetooth/bluetooth.h>
104 #endif
105
106 #define PROGNAME_WIDTH 20
107
108 #if !defined(s6_addr32) && defined(in6a_words)
109 #define s6_addr32 in6a_words    /* libinet6                     */
110 #endif
111
112 /* prototypes for statistics.c */
113 void parsesnmp(int, int, int);
114 void inittab(void);
115 void parsesnmp6(int, int, int);
116 void inittab6(void);
117
118 typedef enum {
119     SS_FREE = 0,                /* not allocated                */
120     SS_UNCONNECTED,             /* unconnected to any socket    */
121     SS_CONNECTING,              /* in process of connecting     */
122     SS_CONNECTED,               /* connected to socket          */
123     SS_DISCONNECTING            /* in process of disconnecting  */
124 } socket_state;
125
126 #define SO_ACCEPTCON    (1<<16) /* performed a listen           */
127 #define SO_WAITDATA     (1<<17) /* wait data to read            */
128 #define SO_NOSPACE      (1<<18) /* no space to write            */
129
130 #define DFLT_AF "inet"
131
132 #define FEATURE_NETSTAT
133 #include "lib/net-features.h"
134
135 char *Release = RELEASE, *Version = "netstat 1.42 (2001-04-15)", *Signature = "Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang, Brian Micek and others";
136
137
138 #define E_READ  -1
139 #define E_IOCTL -3
140
141 int flag_int = 0;
142 int flag_rou = 0;
143 int flag_mas = 0;
144 int flag_sta = 0;
145
146 int flag_all = 0;
147 int flag_lst = 0;
148 int flag_cnt = 0;
149 int flag_deb = 0;
150 int flag_not = 0;
151 int flag_cf  = 0;
152 int flag_opt = 0;
153 int flag_raw = 0;
154 int flag_tcp = 0;
155 int flag_sctp= 0;
156 int flag_udp = 0;
157 int flag_udplite = 0;
158 int flag_igmp= 0;
159 int flag_rom = 0;
160 int flag_exp = 1;
161 int flag_wide= 0;
162 int flag_prg = 0;
163 int flag_arg = 0;
164 int flag_ver = 0;
165 int flag_l2cap = 0;
166 int flag_rfcomm = 0;
167
168 FILE *procinfo;
169
170 #define INFO_GUTS1(file,name,proc,prot)                 \
171   procinfo = proc_fopen((file));                        \
172   if (procinfo == NULL) {                               \
173     if (errno != ENOENT) {                              \
174       perror((file));                                   \
175       return -1;                                        \
176     }                                                   \
177     if (flag_arg || flag_ver)                           \
178       ESYSNOT("netstat", (name));                       \
179     if (flag_arg)                                       \
180       rc = 1;                                           \
181   } else {                                              \
182     do {                                                \
183       if (fgets(buffer, sizeof(buffer), procinfo))      \
184         (proc)(lnr++, buffer,prot);                     \
185     } while (!feof(procinfo));                          \
186     fclose(procinfo);                                   \
187   }
188
189 #if HAVE_AFINET6
190 #define INFO_GUTS2(file,proc,prot)                      \
191   lnr = 0;                                              \
192   procinfo = proc_fopen((file));                        \
193   if (procinfo != NULL) {                               \
194     do {                                                \
195       if (fgets(buffer, sizeof(buffer), procinfo))      \
196         (proc)(lnr++, buffer,prot);                     \
197     } while (!feof(procinfo));                          \
198     fclose(procinfo);                                   \
199   }
200 #else
201 #define INFO_GUTS2(file,proc,prot)
202 #endif
203
204 #define INFO_GUTS3                                      \
205  return rc;
206
207 #define INFO_GUTS6(file,file6,name,proc,prot4,prot6)    \
208  char buffer[8192];                                     \
209  int rc = 0;                                            \
210  int lnr = 0;                                           \
211  if (!flag_arg || flag_inet) {                          \
212     INFO_GUTS1(file,name,proc,prot4)                    \
213  }                                                      \
214  if (!flag_arg || flag_inet6) {                         \
215     INFO_GUTS2(file6,proc,prot6)                        \
216  }                                                      \
217  INFO_GUTS3
218
219 #define INFO_GUTS(file,name,proc,prot)                  \
220  char buffer[8192];                                     \
221  int rc = 0;                                            \
222  int lnr = 0;                                           \
223  INFO_GUTS1(file,name,proc,prot)                        \
224  INFO_GUTS3
225
226 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
227 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
228 #define PROGNAME_WIDTH2(s) #s
229
230 #define PRG_HASH_SIZE 211
231
232 static struct prg_node {
233     struct prg_node *next;
234     unsigned long inode;
235     char name[PROGNAME_WIDTH];
236 } *prg_hash[PRG_HASH_SIZE];
237
238 static char prg_cache_loaded = 0;
239
240 #define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
241
242 #define PROGNAME_BANNER "PID/Program name"
243
244 #define print_progname_banner() do { if (flag_prg) printf(" %-" PROGNAME_WIDTHs "s",PROGNAME_BANNER); } while (0)
245
246 #define PRG_LOCAL_ADDRESS "local_address"
247 #define PRG_INODE        "inode"
248 #define PRG_SOCKET_PFX    "socket:["
249 #define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
250 #define PRG_SOCKET_PFX2   "[0000]:"
251 #define PRG_SOCKET_PFX2l  (strlen(PRG_SOCKET_PFX2))
252
253
254 #ifndef LINE_MAX
255 #define LINE_MAX 4096
256 #endif
257
258 #define PATH_PROC          "/proc"
259 #define PATH_FD_SUFF    "fd"
260 #define PATH_FD_SUFFl       strlen(PATH_FD_SUFF)
261 #define PATH_PROC_X_FD      PATH_PROC "/%s/" PATH_FD_SUFF
262 #define PATH_CMDLINE    "cmdline"
263 #define PATH_CMDLINEl       strlen(PATH_CMDLINE)
264
265 static void prg_cache_add(unsigned long inode, char *name)
266 {
267     unsigned hi = PRG_HASHIT(inode);
268     struct prg_node **pnp,*pn;
269
270     prg_cache_loaded=2;
271     for (pnp=prg_hash+hi;(pn=*pnp);pnp=&pn->next) {
272         if (pn->inode==inode) {
273             /* Some warning should be appropriate here
274                as we got multiple processes for one i-node */
275             return;
276         }
277     }
278     if (!(*pnp=malloc(sizeof(**pnp)))) 
279         return;
280     pn=*pnp;
281     pn->next=NULL;
282     pn->inode=inode;
283     if (strlen(name)>sizeof(pn->name)-1) 
284         name[sizeof(pn->name)-1]='\0';
285     strcpy(pn->name,name);
286 }
287
288 static const char *prg_cache_get(unsigned long inode)
289 {
290     unsigned hi=PRG_HASHIT(inode);
291     struct prg_node *pn;
292
293     for (pn=prg_hash[hi];pn;pn=pn->next)
294         if (pn->inode==inode) return(pn->name);
295     return("-");
296 }
297
298 static void prg_cache_clear(void)
299 {
300     struct prg_node **pnp,*pn;
301
302     if (prg_cache_loaded == 2)
303         for (pnp=prg_hash;pnp<prg_hash+PRG_HASH_SIZE;pnp++)
304             while ((pn=*pnp)) {
305                 *pnp=pn->next;
306                 free(pn);
307             }
308     prg_cache_loaded=0;
309 }
310
311 static void wait_continous(void)
312 {
313     fflush(stdout);
314     sleep(1);
315 }
316
317 static int extract_type_1_socket_inode(const char lname[], unsigned long * inode_p) {
318
319     /* If lname is of the form "socket:[12345]", extract the "12345"
320        as *inode_p.  Otherwise, return -1 as *inode_p.
321        */
322
323     if (strlen(lname) < PRG_SOCKET_PFXl+3) return(-1);
324     
325     if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) return(-1);
326     if (lname[strlen(lname)-1] != ']') return(-1);
327
328     {
329         char inode_str[strlen(lname + 1)];  /* e.g. "12345" */
330         const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
331         char *serr;
332
333         strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
334         inode_str[inode_str_len] = '\0';
335         *inode_p = strtoul(inode_str, &serr, 0);
336         if (!serr || *serr || *inode_p == ~0)
337             return(-1);
338     }
339     return(0);
340 }
341
342
343
344 static int extract_type_2_socket_inode(const char lname[], unsigned long * inode_p) {
345
346     /* If lname is of the form "[0000]:12345", extract the "12345"
347        as *inode_p.  Otherwise, return -1 as *inode_p.
348        */
349
350     if (strlen(lname) < PRG_SOCKET_PFX2l+1) return(-1);
351     if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) return(-1);
352
353     {
354         char *serr;
355
356         *inode_p = strtoul(lname + PRG_SOCKET_PFX2l, &serr, 0);
357         if (!serr || *serr || *inode_p == ~0)
358             return(-1);
359     }
360     return(0);
361 }
362
363
364
365
366 static void prg_cache_load(void)
367 {
368     char line[LINE_MAX],eacces=0;
369     int procfdlen,fd,cmdllen,lnamelen;
370     char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH];
371     unsigned long inode;
372     const char *cs,*cmdlp;
373     DIR *dirproc=NULL,*dirfd=NULL;
374     struct dirent *direproc,*direfd;
375
376     if (prg_cache_loaded || !flag_prg) return;
377     prg_cache_loaded=1;
378     cmdlbuf[sizeof(cmdlbuf)-1]='\0';
379     if (!(dirproc=opendir(PATH_PROC))) goto fail;
380     while (errno=0,direproc=readdir(dirproc)) {
381         for (cs=direproc->d_name;*cs;cs++)
382             if (!isdigit(*cs)) 
383                 break;
384         if (*cs) 
385             continue;
386         procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
387         if (procfdlen<=0 || procfdlen>=sizeof(line)-5) 
388             continue;
389         errno=0;
390         dirfd=opendir(line);
391         if (! dirfd) {
392             if (errno==EACCES) 
393                 eacces=1;
394             continue;
395         }
396         line[procfdlen] = '/';
397         cmdlp = NULL;
398         while ((direfd = readdir(dirfd))) {
399            /* Skip . and .. */
400            if (!isdigit(direfd->d_name[0]))
401                continue;
402             if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line)) 
403                 continue;
404             memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
405                    PATH_FD_SUFFl+1);
406             strcpy(line + procfdlen + 1, direfd->d_name);
407             lnamelen=readlink(line,lname,sizeof(lname)-1);
408             lname[lnamelen] = '\0';  /*make it a null-terminated string*/
409
410             if (extract_type_1_socket_inode(lname, &inode) < 0)
411               if (extract_type_2_socket_inode(lname, &inode) < 0)
412                 continue;
413
414             if (!cmdlp) {
415                 if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >= 
416                     sizeof(line) - 5) 
417                     continue;
418                 strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
419                 fd = open(line, O_RDONLY);
420                 if (fd < 0) 
421                     continue;
422                 cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
423                 if (close(fd)) 
424                     continue;
425                 if (cmdllen == -1) 
426                     continue;
427                 if (cmdllen < sizeof(cmdlbuf) - 1) 
428                     cmdlbuf[cmdllen]='\0';
429                 if (cmdlbuf[0] == '/' && (cmdlp = strrchr(cmdlbuf, '/'))) 
430                     cmdlp++;
431                 else 
432                     cmdlp = cmdlbuf;
433             }
434
435             snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
436             prg_cache_add(inode, finbuf);
437         }
438         closedir(dirfd); 
439         dirfd = NULL;
440     }
441     if (dirproc) 
442         closedir(dirproc);
443     if (dirfd) 
444         closedir(dirfd);
445     if (!eacces) 
446         return;
447     if (prg_cache_loaded == 1) {
448     fail:
449         fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
450                 geteuid());
451     }
452     else
453         fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
454                          " will not be shown, you would have to be root to see it all.)\n"));
455 }
456
457 #if HAVE_AFNETROM
458 static const char *netrom_state[] =
459 {
460     N_("LISTENING"),
461     N_("CONN SENT"),
462     N_("DISC SENT"),
463     N_("ESTABLISHED")
464 };
465
466 static int netrom_info(void)
467 {
468     FILE *f;
469     char buffer[256], dev[16];
470     int st, vs, vr, sendq, recvq, ret;
471
472     f = proc_fopen(_PATH_PROCNET_NR);
473     if (f == NULL) {
474         if (errno != ENOENT) {
475             perror(_PATH_PROCNET_NR);
476             return (-1);
477         }
478         if (flag_arg || flag_ver)
479             ESYSNOT("netstat", "AF NETROM");
480         if (flag_arg)
481             return (1);
482         else
483             return (0);
484     }
485     printf(_("Active NET/ROM sockets\n"));
486     printf(_("User       Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q\n"));
487     if (fgets(buffer, 256, f))
488         /* eat line */;
489
490     while (fgets(buffer, 256, f)) {
491         buffer[9] = 0;
492         buffer[19] = 0;
493         buffer[29] = 0;
494         ret = sscanf(buffer + 30, "%s %*x/%*x %*x/%*x %d %d %d %*d %*d/%*d %*d/%*d %*d/%*d %*d/%*d %*d/%*d %*d %d %d %*d",
495                dev, &st, &vs, &vr, &sendq, &recvq);
496         if (ret != 6) {
497             printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
498             continue;
499         }
500         printf("%-9s  %-9s  %-9s  %-6s  %-11s  %03d/%03d  %-6d  %-6d\n",
501                buffer, buffer + 10, buffer + 20,
502                dev,
503                _(netrom_state[st]),
504                vr, vs, sendq, recvq);
505     }
506     fclose(f);
507     return 0;
508 }
509 #endif
510
511 /* These enums are used by IPX too. :-( */
512 enum {
513     TCP_ESTABLISHED = 1,
514     TCP_SYN_SENT,
515     TCP_SYN_RECV,
516     TCP_FIN_WAIT1,
517     TCP_FIN_WAIT2,
518     TCP_TIME_WAIT,
519     TCP_CLOSE,
520     TCP_CLOSE_WAIT,
521     TCP_LAST_ACK,
522     TCP_LISTEN,
523     TCP_CLOSING                 /* now a valid state */
524 };
525
526 #if HAVE_AFINET || HAVE_AFINET6
527
528 static const char *tcp_state[] =
529 {
530     "",
531     N_("ESTABLISHED"),
532     N_("SYN_SENT"),
533     N_("SYN_RECV"),
534     N_("FIN_WAIT1"),
535     N_("FIN_WAIT2"),
536     N_("TIME_WAIT"),
537     N_("CLOSE"),
538     N_("CLOSE_WAIT"),
539     N_("LAST_ACK"),
540     N_("LISTEN"),
541     N_("CLOSING")
542 };
543
544 static void finish_this_one(int uid, unsigned long inode, const char *timers)
545 {
546     struct passwd *pw;
547
548     if (flag_exp > 1) {
549         if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
550             printf(" %-10s ", pw->pw_name);
551         else
552             printf(" %-10d ", uid);
553         printf("%-10lu",inode);
554     }
555     if (flag_prg)
556         printf(" %-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
557     if (flag_opt)
558         printf(" %s", timers);
559     putchar('\n');
560 }
561
562 static void igmp_do_one(int lnr, const char *line,const char *prot)
563 {
564     char mcast_addr[128];
565 #if HAVE_AFINET6
566     struct sockaddr_in6 mcastaddr;
567     char addr6[INET6_ADDRSTRLEN];
568     struct in6_addr in6;
569     extern struct aftype inet6_aftype;
570 #else
571     struct sockaddr_in mcastaddr;
572 #endif
573     struct aftype *ap;
574     static int idx_flag = 0;
575     static int igmp6_flag = 0;
576     static char device[16];
577     int num, idx, refcnt;
578
579     if (lnr == 0) {
580         /* IPV6 ONLY */
581         /* igmp6 file does not have any comments on first line */
582         if ( strstr( line, "Device" ) == NULL ) {
583             igmp6_flag = 1;
584         } else {
585             /* IPV4 ONLY */
586             /* 2.1.x kernels and up have Idx field */
587             /* 2.0.x and below do not have Idx field */
588             if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
589                 idx_flag = 1;
590             else
591                 idx_flag = 0;
592             return;
593         }
594     }
595
596     if (igmp6_flag) {    /* IPV6 */
597 #if HAVE_AFINET6
598         num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
599         if (num == 4) {
600             /* Demangle what the kernel gives us */
601             sscanf(mcast_addr, "%08X%08X%08X%08X",
602                    &in6.s6_addr32[0], &in6.s6_addr32[1],
603            &in6.s6_addr32[2], &in6.s6_addr32[3]);
604             in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
605             in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
606             in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
607             in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
608         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
609             inet6_aftype.input(1, addr6, (struct sockaddr *) &mcastaddr);
610             mcastaddr.sin6_family = AF_INET6;
611         } else {
612             fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
613             return;
614         }
615
616         if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
617             fprintf(stderr, _("netstat: unsupported address family %d !\n"),
618                     ((struct sockaddr *) &mcastaddr)->sa_family);
619             return;
620         }
621         safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr, 
622                                       flag_not & FLAG_NUM_HOST), sizeof(mcast_addr));
623         printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
624 #endif
625     } else {    /* IPV4 */
626 #if HAVE_AFINET
627         if (line[0] != '\t') {
628             if (idx_flag) {
629                 if ((num = sscanf( line, "%d\t%10c", &idx, device)) < 2) {
630                     fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
631                     return;
632                 }
633             } else {
634                 if ( (num = sscanf( line, "%10c", device )) < 1 ) {
635                     fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
636                     return;
637                 }
638             }
639             device[10] = '\0';
640             return;
641         } else if ( line[0] == '\t' ) {
642             if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
643                 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
644                 return;
645             }
646             sscanf( mcast_addr, "%X",
647                     &((struct sockaddr_in *) &mcastaddr)->sin_addr.s_addr );
648             ((struct sockaddr *) &mcastaddr)->sa_family = AF_INET;
649         } else {
650             fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
651             return;
652         }
653         
654         if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
655             fprintf(stderr, _("netstat: unsupported address family %d !\n"),
656                     ((struct sockaddr *) &mcastaddr)->sa_family);
657             return;
658         }
659         safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr, 
660                                       flag_not & FLAG_NUM_HOST), sizeof(mcast_addr));
661         printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
662 #endif
663     }    /* IPV4 */
664 }
665
666 #if HAVE_AFX25
667 static int x25_info(void)
668 {
669        FILE *f=proc_fopen(_PATH_PROCNET_X25);
670        char buffer[256],dev[16];
671        int st,vs,vr,sendq,recvq,lci;
672        static char *x25_state[5]=
673        {
674                "LISTENING",
675                "SABM_SENT",
676                "DISC_SENT",
677                "ESTABLISHED",
678                "RECOVERY"
679        };
680        if(!(f=proc_fopen(_PATH_PROCNET_X25)))
681        {
682                if (errno != ENOENT) {
683                        perror(_PATH_PROCNET_X25);
684                        return(-1);
685                }
686                if (flag_arg || flag_ver)
687                        ESYSNOT("netstat","AF X25");
688                if (flag_arg)
689                        return(1);
690                else
691                        return(0);
692        }
693        printf( _("Active X.25 sockets\n"));
694        /* IMHO, Vr/Vs is not very usefull --SF */
695        printf( _("Dest         Source          Device  LCI  State        Vr/Vs  Send-Q  Recv-Q\n"));
696        if (fgets(buffer,256,f))
697                /* eat line */;
698        while(fgets(buffer,256,f))
699        {
700                buffer[10]=0;
701                buffer[20]=0;
702                sscanf(buffer+22,"%s %d %d %d %d %*d %*d %*d %*d %*d %*d %d %d %*d",
703                        dev,&lci,&st,&vs,&vr,&sendq,&recvq);
704                if (!(flag_all || lci))
705                        continue;
706                printf("%-15s %-15s %-7s %-3d  %-11s  %02d/%02d  %-6d  %-6d\n",
707                        buffer,buffer+11,
708                        dev,
709                        lci,
710                        x25_state[st],
711                        vr,vs,sendq,recvq);
712        }
713        fclose(f);
714        return 0;               
715 }
716 #endif
717
718 static int igmp_info(void)
719 {
720     INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
721                igmp_do_one, "igmp", "igmp6");
722 }
723
724 static int ip_parse_dots(uint32_t *addr, char const *src) {
725   unsigned  a, b, c, d;
726   unsigned  ret = 4-sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d);
727   *addr = htonl((a << 24)|(b << 16)|(c << 8)|d);
728   return  ret;
729 }
730
731 static void print_ip_service(struct sockaddr_in *addr, char const *protname,
732                              char *buf, unsigned size) {
733   struct aftype *ap;
734
735   if(size == 0)  return;
736
737   /* print host */
738   if((ap = get_afntype(addr->sin_family)) == NULL) {
739     fprintf(stderr, _("netstat: unsupported address family %d !\n"),
740             addr->sin_family);
741     return;
742   }
743   safe_strncpy(buf, ap->sprint((struct sockaddr*)addr, flag_not), size);
744
745   /* print service */
746   if(flag_all || (flag_lst && !addr->sin_port) || (!flag_lst && addr->sin_port)) {
747     char  bfs[32];
748
749     snprintf(bfs, sizeof(bfs), "%s",
750              get_sname(addr->sin_port, (char*)protname, flag_not & FLAG_NUM_PORT));
751
752     /* check if we must cut on host and/or service name */
753     {
754       unsigned const  bufl = strlen(buf);
755       unsigned const  bfsl = strlen(bfs);
756
757       if(bufl+bfsl+2 > size) {
758         unsigned const  half = (size-2)>>1;
759         if(bufl > half) {
760           if(bfsl > half) {
761             buf[size-2-half] = '\0';
762             bfs[half+1]      = '\0';
763           }
764           else  buf[size-2-bfsl] = '\0';
765         }
766         else  bfs[size-2-bufl] = '\0';
767       }  
768     }
769     strcat(buf, ":");
770     strcat(buf, bfs);
771   }
772 }
773
774 /* process single SCTP endpoint */
775 static void sctp_do_ept(int lnr, char const *line, const char *prot)
776 {
777   struct sockaddr_in  laddr, raddr;
778   unsigned            uid, inode;
779
780   char        l_addr[23], r_addr[23];
781
782   /* fill sockaddr_in structures */
783   {
784     unsigned  lport;
785     unsigned  ate;
786
787     if(lnr == 0)  return;
788     if(sscanf(line, "%*X %*X %*u %*u %*u %u %u %u %n",
789               &lport, &uid, &inode, &ate) < 3)  goto err;
790
791     /* decode IP address */
792     if(ip_parse_dots(&laddr.sin_addr.s_addr, line+ate))  goto err;
793     raddr.sin_addr.s_addr = htonl(0);
794     laddr.sin_family = raddr.sin_family = AF_INET;
795     laddr.sin_port = htons(lport);
796     raddr.sin_port = htons(0);
797   }
798
799   /* print IP:service to l_addr and r_addr */
800   print_ip_service(&laddr, prot, l_addr, sizeof(l_addr));
801   print_ip_service(&raddr, prot, r_addr, sizeof(r_addr));
802
803   /* Print line */
804   printf("%-4s  %6d %6d %-*s %-*s %-11s",
805          prot, 0, 0,
806          (int)netmax(23,strlen(l_addr)), l_addr,
807          (int)netmax(23,strlen(r_addr)), r_addr,
808          _(tcp_state[TCP_LISTEN]));
809   finish_this_one(uid, inode, "");
810   return;
811  err:
812   fprintf(stderr, "SCTP error in line: %d\n", lnr);
813 }
814
815 /* process single SCTP association */
816 static void sctp_do_assoc(int lnr, char const *line, const char *prot)
817 {
818   struct sockaddr_in  laddr, raddr;
819   unsigned long       rxq, txq;
820   unsigned            uid, inode;
821
822   char        l_addr[23], r_addr[23];
823
824   /* fill sockaddr_in structures */
825   {
826     unsigned    lport, rport;
827     unsigned    ate;
828     char const *addr;
829
830     if(lnr == 0)  return;
831     if(sscanf(line, "%*X %*X %*u %*u %*u %*u %*u %lu %lu %u %u %u %u %n",
832               &txq, &rxq, &uid, &inode, &lport, &rport, &ate) < 6)  goto err;
833
834     /* decode IP addresses */
835     addr = strchr(line+ate, '*');
836     if(addr == 0)  goto err;
837     if(ip_parse_dots(&laddr.sin_addr.s_addr, ++addr))  goto err;
838     addr = strchr(addr, '*');
839     if(addr == 0)  goto err;
840     if(ip_parse_dots(&raddr.sin_addr.s_addr, ++addr))  goto err;
841
842     /* complete sockaddr_in structures */
843     laddr.sin_family = raddr.sin_family = AF_INET;
844     laddr.sin_port = htons(lport);
845     raddr.sin_port = htons(rport);
846   }
847
848   /* print IP:service to l_addr and r_addr */
849   print_ip_service(&laddr, prot, l_addr, sizeof(l_addr));
850   print_ip_service(&raddr, prot, r_addr, sizeof(r_addr));
851
852   /* Print line */
853   printf("%-4s  %6ld %6ld %-*s %-*s %-11s",
854          prot, rxq, txq,
855          (int)netmax(23,strlen(l_addr)), l_addr,
856          (int)netmax(23,strlen(r_addr)), r_addr,
857          _(tcp_state[TCP_ESTABLISHED]));
858   finish_this_one(uid, inode, "");
859   return;
860  err:
861   fprintf(stderr, "SCTP error in line: %d\n", lnr);
862 }
863
864 static int sctp_info_epts(void) {
865   INFO_GUTS6(_PATH_PROCNET_SCTPEPTS, _PATH_PROCNET_SCTP6EPTS, "AF INET (sctp)",
866              sctp_do_ept, "sctp", "sctp6");
867 }
868
869 static int sctp_info_assocs(void) {
870   INFO_GUTS6(_PATH_PROCNET_SCTPASSOCS, _PATH_PROCNET_SCTP6ASSOCS, "AF INET (sctp)",
871              sctp_do_assoc, "sctp", "sctp6");
872 }
873
874 static int sctp_info(void) {
875   int  res;
876   res = sctp_info_epts();
877   if(res)  return  res;
878   return  sctp_info_assocs();
879 }
880
881 static void addr_do_one(char *buf, size_t buf_len, size_t short_len, struct aftype *ap,
882 #if HAVE_AFINET6
883                         struct sockaddr_in6 *addr,
884 #else
885                         struct sockaddr_in *addr,
886 #endif
887                         int port, const char *proto
888 )
889 {
890     const char *sport, *saddr;
891     size_t port_len, addr_len;
892
893     saddr = ap->sprint((struct sockaddr *)addr, flag_not & FLAG_NUM_HOST);
894     sport = get_sname(htons(port), proto, flag_not & FLAG_NUM_PORT);
895     addr_len = strlen(saddr);
896     port_len = strlen(sport);
897     if (!flag_wide && (addr_len + port_len > short_len)) {
898         /* Assume port name is short */
899         port_len = netmin(port_len, short_len - 4);
900         addr_len = short_len - port_len;
901         strncpy(buf, saddr, addr_len);
902         buf[addr_len] = '\0';
903         strcat(buf, ":");
904         strncat(buf, sport, port_len);
905     } else
906         snprintf(buf, buf_len, "%s:%s", saddr, sport);
907 }
908
909 static void tcp_do_one(int lnr, const char *line, const char *prot)
910 {
911     unsigned long rxq, txq, time_len, retr, inode;
912     int num, local_port, rem_port, d, state, uid, timer_run, timeout;
913     char rem_addr[128], local_addr[128], timers[64], more[512];
914     struct aftype *ap;
915 #if HAVE_AFINET6
916     struct sockaddr_in6 localaddr, remaddr;
917     char addr6[INET6_ADDRSTRLEN];
918     struct in6_addr in6;
919     extern struct aftype inet6_aftype;
920 #else
921     struct sockaddr_in localaddr, remaddr;
922 #endif
923
924     if (lnr == 0)
925         return;
926
927     num = sscanf(line,
928     "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %512s\n",
929                  &d, local_addr, &local_port, rem_addr, &rem_port, &state,
930                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
931
932     if (!flag_all && ((flag_lst && rem_port) || (!flag_lst && !rem_port)))
933       return;
934
935     if (strlen(local_addr) > 8) {
936 #if HAVE_AFINET6
937         /* Demangle what the kernel gives us */
938         sscanf(local_addr, "%08X%08X%08X%08X",
939                &in6.s6_addr32[0], &in6.s6_addr32[1],
940            &in6.s6_addr32[2], &in6.s6_addr32[3]);
941         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
942         inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
943         sscanf(rem_addr, "%08X%08X%08X%08X",
944                &in6.s6_addr32[0], &in6.s6_addr32[1],
945                &in6.s6_addr32[2], &in6.s6_addr32[3]);
946         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
947         inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
948         localaddr.sin6_family = AF_INET6;
949         remaddr.sin6_family = AF_INET6;
950 #endif
951     } else {
952         sscanf(local_addr, "%X",
953                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
954         sscanf(rem_addr, "%X",
955                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
956         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
957         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
958     }
959
960     if (num < 11) {
961         fprintf(stderr, _("warning, got bogus tcp line.\n"));
962         return;
963     }
964     if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
965         fprintf(stderr, _("netstat: unsupported address family %d !\n"),
966                 ((struct sockaddr *) &localaddr)->sa_family);
967         return;
968     }
969
970         addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "tcp");
971         addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "tcp");
972
973         timers[0] = '\0';
974         if (flag_opt)
975             switch (timer_run) {
976             case 0:
977                 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
978                 break;
979
980             case 1:
981                 snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
982                          (double) time_len / HZ, retr, timeout);
983                 break;
984
985             case 2:
986                 snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
987                          (double) time_len / HZ, retr, timeout);
988                 break;
989
990             case 3:
991                 snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
992                          (double) time_len / HZ, retr, timeout);
993                 break;
994
995             default:
996                 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
997                          timer_run, (double) time_len / HZ, retr, timeout);
998                 break;
999             }
1000
1001         printf("%-4s  %6ld %6ld %-*s %-*s %-11s",
1002                prot, rxq, txq, (int)netmax(23,strlen(local_addr)), local_addr, (int)netmax(23,strlen(rem_addr)), rem_addr, _(tcp_state[state]));
1003
1004         finish_this_one(uid,inode,timers);
1005 }
1006
1007 static int tcp_info(void)
1008 {
1009     INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
1010                tcp_do_one, "tcp", "tcp6");
1011 }
1012
1013 static void udp_do_one(int lnr, const char *line,const char *prot)
1014 {
1015     char local_addr[64], rem_addr[64];
1016     char *udp_state, timers[64], more[512];
1017     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
1018 #if HAVE_AFINET6
1019     struct sockaddr_in6 localaddr, remaddr;
1020     char addr6[INET6_ADDRSTRLEN];
1021     struct in6_addr in6;
1022     extern struct aftype inet6_aftype;
1023 #else
1024     struct sockaddr_in localaddr, remaddr;
1025 #endif
1026     struct aftype *ap;
1027     unsigned long rxq, txq, time_len, retr, inode;
1028
1029     if (lnr == 0)
1030         return;
1031
1032     more[0] = '\0';
1033     num = sscanf(line,
1034                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %511s\n",
1035                  &d, local_addr, &local_port,
1036                  rem_addr, &rem_port, &state,
1037           &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
1038
1039     if (strlen(local_addr) > 8) {
1040 #if HAVE_AFINET6
1041         sscanf(local_addr, "%08X%08X%08X%08X",
1042                &in6.s6_addr32[0], &in6.s6_addr32[1],
1043                &in6.s6_addr32[2], &in6.s6_addr32[3]);
1044         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1045         inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
1046         sscanf(rem_addr, "%08X%08X%08X%08X",
1047                &in6.s6_addr32[0], &in6.s6_addr32[1],
1048                &in6.s6_addr32[2], &in6.s6_addr32[3]);
1049         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1050         inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
1051         localaddr.sin6_family = AF_INET6;
1052         remaddr.sin6_family = AF_INET6;
1053 #endif
1054     } else {
1055         sscanf(local_addr, "%X",
1056                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1057         sscanf(rem_addr, "%X",
1058                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1059         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1060         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1061     }
1062
1063     retr = 0L;
1064     if (!flag_opt)
1065         more[0] = '\0';
1066
1067     if (num < 10) {
1068         fprintf(stderr, _("warning, got bogus udp line.\n"));
1069         return;
1070     }
1071     if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
1072         fprintf(stderr, _("netstat: unsupported address family %d !\n"),
1073                 ((struct sockaddr *) &localaddr)->sa_family);
1074         return;
1075     }
1076     switch (state) {
1077     case TCP_ESTABLISHED:
1078         udp_state = _("ESTABLISHED");
1079         break;
1080
1081     case TCP_CLOSE:
1082         udp_state = "";
1083         break;
1084
1085     default:
1086         udp_state = _("UNKNOWN");
1087         break;
1088     }
1089
1090 #if HAVE_AFINET6
1091 #define notnull(A) (((A.sin6_family == AF_INET6) && \
1092          ((A.sin6_addr.s6_addr32[0]) ||            \
1093           (A.sin6_addr.s6_addr32[1]) ||            \
1094           (A.sin6_addr.s6_addr32[2]) ||            \
1095           (A.sin6_addr.s6_addr32[3]))) ||          \
1096         ((A.sin6_family == AF_INET) &&             \
1097          ((struct sockaddr_in *) &A)->sin_addr.s_addr))
1098 #else
1099 #define notnull(A) (A.sin_addr.s_addr)
1100 #endif
1101
1102     if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1103     {
1104         addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "udp");
1105         addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "udp");
1106
1107         timers[0] = '\0';
1108         if (flag_opt)
1109             switch (timer_run) {
1110             case 0:
1111                 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1112                 break;
1113
1114             case 1:
1115             case 2:
1116                 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
1117                 break;
1118
1119             default:
1120                 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1121                          retr, timeout);
1122                 break;
1123             }
1124         printf("%-5s %6ld %6ld %-23s %-23s %-11s",
1125                prot, rxq, txq, local_addr, rem_addr, udp_state);
1126
1127         finish_this_one(uid,inode,timers);
1128     }
1129 }
1130
1131 static int udp_info(void)
1132 {
1133     INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
1134                udp_do_one, "udp", "udp6");
1135 }
1136
1137 static int udplite_info(void)
1138 {
1139     INFO_GUTS6(_PATH_PROCNET_UDPLITE, _PATH_PROCNET_UDPLITE6, 
1140                "AF INET (udplite)", udp_do_one, "udpl", "udpl6" );
1141 }
1142
1143 static void raw_do_one(int lnr, const char *line,const char *prot)
1144 {
1145     char local_addr[64], rem_addr[64];
1146     char timers[64], more[512];
1147     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
1148 #if HAVE_AFINET6
1149     struct sockaddr_in6 localaddr, remaddr;
1150     char addr6[INET6_ADDRSTRLEN];
1151     struct in6_addr in6;
1152     extern struct aftype inet6_aftype;
1153 #else
1154     struct sockaddr_in localaddr, remaddr;
1155 #endif
1156     struct aftype *ap;
1157     unsigned long rxq, txq, time_len, retr, inode;
1158
1159     if (lnr == 0)
1160         return;
1161
1162     more[0] = '\0';
1163     num = sscanf(line,
1164                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %511s\n",
1165                  &d, local_addr, &local_port, rem_addr, &rem_port, &state,
1166           &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
1167
1168     if (strlen(local_addr) > 8) {
1169 #if HAVE_AFINET6
1170         sscanf(local_addr, "%08X%08X%08X%08X",
1171                &in6.s6_addr32[0], &in6.s6_addr32[1],
1172            &in6.s6_addr32[2], &in6.s6_addr32[3]);
1173     inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1174         inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
1175         sscanf(rem_addr, "%08X%08X%08X%08X",
1176                &in6.s6_addr32[0], &in6.s6_addr32[1],
1177            &in6.s6_addr32[2], &in6.s6_addr32[3]);
1178     inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1179         inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
1180         localaddr.sin6_family = AF_INET6;
1181         remaddr.sin6_family = AF_INET6;
1182 #endif
1183     } else {
1184         sscanf(local_addr, "%X",
1185                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1186         sscanf(rem_addr, "%X",
1187                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1188         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1189         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1190     }
1191 #if HAVE_AFINET6
1192     if ((ap = get_afntype(localaddr.sin6_family)) == NULL) {
1193         fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin6_family);
1194         return;
1195     }
1196 #else
1197     if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
1198         fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin_family);
1199         return;
1200     }
1201 #endif
1202
1203     if (!flag_opt)
1204         more[0] = '\0';
1205
1206     if (num < 10) {
1207         fprintf(stderr, _("warning, got bogus raw line.\n"));
1208         return;
1209     }
1210
1211     if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1212     {
1213         addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "raw");
1214         addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "raw");
1215
1216         timers[0] = '\0';
1217         if (flag_opt)
1218             switch (timer_run) {
1219             case 0:
1220                 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1221                 break;
1222
1223             case 1:
1224             case 2:
1225                 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1226                          retr, timeout);
1227                 break;
1228
1229             default:
1230                 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
1231                          timer_run, (double) time_len / 100,
1232                          retr, timeout);
1233                 break;
1234             }
1235         printf("%-4s  %6ld %6ld %-23s %-23s %-11d",
1236                prot, rxq, txq, local_addr, rem_addr, state);
1237
1238         finish_this_one(uid,inode,timers);
1239     }
1240 }
1241
1242 static int raw_info(void)
1243 {
1244     INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
1245                raw_do_one, "raw", "raw6");
1246 }
1247
1248 #endif
1249
1250
1251 #if HAVE_AFUNIX
1252
1253 #define HAS_INODE 1
1254
1255 static void unix_do_one(int nr, const char *line, const char *prot)
1256 {
1257     static int has = 0;
1258     char path[MAXPATHLEN], ss_flags[32];
1259     char *ss_proto, *ss_state, *ss_type;
1260     int num, state, type;
1261     void *d;
1262     unsigned long refcnt, proto, flags, inode;
1263
1264     if (nr == 0) {
1265         if (strstr(line, "Inode"))
1266             has |= HAS_INODE;
1267         return;
1268     }
1269     path[0] = '\0';
1270     num = sscanf(line, "%p: %lX %lX %lX %X %X %lu %s",
1271                  &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
1272     if (num < 6) {
1273         fprintf(stderr, _("warning, got bogus unix line.\n"));
1274         return;
1275     }
1276     if (!(has & HAS_INODE))
1277         snprintf(path,sizeof(path),"%lu",inode);
1278
1279     if (!flag_all) {
1280         if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
1281                 if (!flag_lst)
1282                         return;
1283         } else {
1284                 if (flag_lst)
1285                         return;
1286         }
1287     }
1288
1289     switch (proto) {
1290     case 0:
1291         ss_proto = "unix";
1292         break;
1293
1294     default:
1295         ss_proto = "??";
1296     }
1297
1298     switch (type) {
1299     case SOCK_STREAM:
1300         ss_type = _("STREAM");
1301         break;
1302
1303     case SOCK_DGRAM:
1304         ss_type = _("DGRAM");
1305         break;
1306
1307     case SOCK_RAW:
1308         ss_type = _("RAW");
1309         break;
1310
1311     case SOCK_RDM:
1312         ss_type = _("RDM");
1313         break;
1314
1315     case SOCK_SEQPACKET:
1316         ss_type = _("SEQPACKET");
1317         break;
1318
1319     default:
1320         ss_type = _("UNKNOWN");
1321     }
1322
1323     switch (state) {
1324     case SS_FREE:
1325         ss_state = _("FREE");
1326         break;
1327
1328     case SS_UNCONNECTED:
1329         /*
1330          * Unconnected sockets may be listening
1331          * for something.
1332          */
1333         if (flags & SO_ACCEPTCON) {
1334             ss_state = _("LISTENING");
1335         } else {
1336             ss_state = "";
1337         }
1338         break;
1339
1340     case SS_CONNECTING:
1341         ss_state = _("CONNECTING");
1342         break;
1343
1344     case SS_CONNECTED:
1345         ss_state = _("CONNECTED");
1346         break;
1347
1348     case SS_DISCONNECTING:
1349         ss_state = _("DISCONNECTING");
1350         break;
1351
1352     default:
1353         ss_state = _("UNKNOWN");
1354     }
1355
1356     strcpy(ss_flags, "[ ");
1357     if (flags & SO_ACCEPTCON)
1358         strcat(ss_flags, "ACC ");
1359     if (flags & SO_WAITDATA)
1360         strcat(ss_flags, "W ");
1361     if (flags & SO_NOSPACE)
1362         strcat(ss_flags, "N ");
1363
1364     strcat(ss_flags, "]");
1365
1366     printf("%-5s %-6ld %-11s %-10s %-13s ",
1367            ss_proto, refcnt, ss_flags, ss_type, ss_state);
1368     if (has & HAS_INODE)
1369         printf("%-8lu",inode);
1370     else
1371         printf("-       ");
1372     if (flag_prg)
1373         printf(" %-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
1374         
1375     printf(" %s\n", path);
1376 }
1377
1378 static int unix_info(void)
1379 {
1380
1381     printf(_("Active UNIX domain sockets "));
1382     if (flag_all)
1383         printf(_("(servers and established)"));
1384     else {
1385       if (flag_lst)
1386         printf(_("(only servers)"));
1387       else
1388         printf(_("(w/o servers)"));
1389     }
1390
1391     printf(_("\nProto RefCnt Flags       Type       State         I-Node  "));
1392     print_progname_banner();
1393     printf(_(" Path\n"));       /* xxx */
1394
1395     {
1396         INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one, "unix");
1397     }
1398 }
1399 #endif
1400
1401
1402 #if HAVE_AFAX25
1403 static int ax25_info(void)
1404 {
1405     FILE *f;
1406     char buffer[256], buf[16];
1407     char *src, *dst, *dev, *p;
1408     int st, vs, vr, sendq, recvq, ret;
1409     int new = -1;               /* flag for new (2.1.x) kernels */
1410     static char *ax25_state[5] =
1411     {
1412         N_("LISTENING"),
1413         N_("SABM SENT"),
1414         N_("DISC SENT"),
1415         N_("ESTABLISHED"),
1416         N_("RECOVERY")
1417     };
1418     if (!(f = proc_fopen(_PATH_PROCNET_AX25))) {
1419         if (errno != ENOENT) {
1420             perror(_PATH_PROCNET_AX25);
1421             return (-1);
1422         }
1423         if (flag_arg || flag_ver)
1424             ESYSNOT("netstat", "AF AX25");
1425         if (flag_arg)
1426             return (1);
1427         else
1428             return (0);
1429     }
1430     printf(_("Active AX.25 sockets\n"));
1431     printf(_("Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q\n"));
1432     while (fgets(buffer, 256, f)) {
1433         if (new == -1) {
1434             if (!strncmp(buffer, "dest_addr", 9)) {
1435                 new = 0;
1436                 continue;       /* old kernels have a header line */
1437             } else
1438                 new = 1;
1439         }
1440         /*
1441          * In a network connection with no user socket the Snd-Q, Rcv-Q
1442          * and Inode fields are empty in 2.0.x and '*' in 2.1.x
1443          */
1444         sendq = 0;
1445         recvq = 0;
1446         if (new == 0) {
1447             dst = buffer;
1448             src = buffer + 10;
1449             dst[9] = 0;
1450             src[9] = 0;
1451             ret = sscanf(buffer + 20, "%s %d %d %d %*d %*d/%*d %*d/%*d %*d/%*d %*d/%*d %*d/%*d %*d %*d %*d %d %d %*d",
1452                    buf, &st, &vs, &vr, &sendq, &recvq);
1453             if (ret != 4 && ret != 6) {
1454                 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
1455                 continue;
1456             }
1457             dev = buf;
1458         } else {
1459             p = buffer;
1460             while (*p != ' ') p++;
1461             p++;
1462             dev = p;
1463             while (*p != ' ') p++;
1464             *p++ = 0;
1465             src = p;
1466             while (*p != ' ') p++;
1467             *p++ = 0;
1468             dst = p;
1469             while (*p != ' ') p++;
1470             *p++ = 0;
1471             ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
1472                    &st, &vs, &vr, &sendq, &recvq);
1473             if (ret != 3 && ret != 5) {
1474                     printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
1475                     continue;
1476             }
1477             /*
1478              * FIXME: digipeaters should be handled somehow.
1479              * For now we just strip them.
1480              */
1481             p = dst;
1482             while (*p && *p != ',') p++;
1483             *p = 0;
1484         }
1485         printf("%-9s  %-9s  %-6s  %-11s  %03d/%03d  %-6d  %-6d\n",
1486                dst, src,
1487                dev,
1488                _(ax25_state[st]),
1489                vr, vs, sendq, recvq);
1490     }
1491     fclose(f);
1492     return 0;
1493 }
1494 #endif
1495
1496
1497 #if HAVE_AFIPX
1498 static int ipx_info(void)
1499 {
1500     FILE *f;
1501     char buf[256];
1502     unsigned long txq, rxq;
1503     unsigned int state;
1504     unsigned int uid;
1505     char *st;
1506     int nc;
1507     struct aftype *ap;
1508     struct passwd *pw;
1509     char sad[50], dad[50];
1510     struct sockaddr sa;
1511     unsigned sport = 0, dport = 0;
1512     struct stat s;
1513     
1514     f = proc_fopen(_PATH_PROCNET_IPX_SOCKET1);
1515     if (!f) {
1516         if (errno != ENOENT) {
1517             perror(_PATH_PROCNET_IPX_SOCKET1);
1518             return (-1);
1519         }
1520         f = proc_fopen(_PATH_PROCNET_IPX_SOCKET2);
1521
1522         /* We need to check for directory */
1523         if (f) {
1524             fstat(fileno(f), &s);
1525             if (!S_ISREG(s.st_mode)) {
1526                 fclose(f);
1527                 f=NULL;
1528             }
1529         }
1530
1531         if (!f) {
1532             if (errno != ENOENT) {
1533                 perror(_PATH_PROCNET_IPX_SOCKET2);
1534                 return (-1);
1535             }
1536             if (flag_arg || flag_ver)
1537                 ESYSNOT("netstat", "AF IPX");
1538             if (flag_arg)
1539                 return (1);
1540             else
1541                 return (0);
1542         }
1543     }
1544     printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address              Foreign Address            State"));   /* xxx */
1545     if (flag_exp > 1)
1546         printf(_(" User"));     /* xxx */
1547     printf("\n");
1548     if ((ap = get_afntype(AF_IPX)) == NULL) {
1549         EINTERN("netstat.c", "AF_IPX missing");
1550         return (-1);
1551     }
1552     if (fgets(buf, 255, f))
1553         /* eat line */;
1554
1555     while (fgets(buf, 255, f) != NULL) {
1556         sscanf(buf, "%s %s %lX %lX %d %d",
1557                sad, dad, &txq, &rxq, &state, &uid);
1558         if ((st = rindex(sad, ':'))) {
1559             *st++ = '\0';
1560             sscanf(st, "%X", &sport);   /* net byt order */
1561             sport = ntohs(sport);
1562         } else {
1563             EINTERN("netstat.c", "ipx socket format error in source port");
1564             return (-1);
1565         }
1566         nc = 0;
1567         if (strcmp(dad, "Not_Connected") != 0) {
1568             if ((st = rindex(dad, ':'))) {
1569                 *st++ = '\0';
1570                 sscanf(st, "%X", &dport);       /* net byt order */
1571                 dport = ntohs(dport);
1572             } else {
1573                 EINTERN("netstat.c", "ipx soket format error in destination port");
1574                 return (-1);
1575             }
1576         } else
1577             nc = 1;
1578
1579         switch (state) {
1580         case TCP_ESTABLISHED:
1581             st = _("ESTAB");
1582             break;
1583
1584         case TCP_CLOSE:
1585             st = "";
1586             break;
1587
1588         default:
1589             st = _("UNK.");
1590             break;
1591         }
1592
1593         /* Fetch and resolve the Source */
1594         (void) ap->input(4, sad, &sa);
1595         safe_strncpy(buf, ap->sprint(&sa, flag_not & FLAG_NUM_HOST), sizeof(buf));
1596         snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
1597
1598         if (!nc) {
1599             /* Fetch and resolve the Destination */
1600             (void) ap->input(4, dad, &sa);
1601             safe_strncpy(buf, ap->sprint(&sa, flag_not & FLAG_NUM_HOST), sizeof(buf));
1602             snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
1603         } else
1604             strcpy(dad, "-");
1605
1606         printf("IPX   %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
1607         if (flag_exp > 1) {
1608             if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
1609                 printf(" %-10s", pw->pw_name);
1610             else
1611                 printf(" %-10d", uid);
1612         }
1613         printf("\n");
1614     }
1615     fclose(f);
1616     return 0;
1617 }
1618 #endif
1619
1620 #if HAVE_BLUETOOTH
1621 const char *bluetooth_state(int state)
1622 {
1623     switch (state) {
1624         case BT_CONNECTED:
1625             return _("CONNECTED");
1626         case BT_OPEN:
1627             return _("OPEN");
1628         case BT_BOUND:
1629             return _("BOUND");
1630         case BT_LISTEN:
1631             return _("LISTEN");
1632         case BT_CONNECT:
1633             return _("CONNECT");
1634         case BT_CONNECT2:
1635             return _("CONNECT2");
1636         case BT_CONFIG:
1637             return _("CONFIG");
1638         case BT_DISCONN:
1639             return _("DISCONN");
1640         case BT_CLOSED:
1641             return _("CLOSED");
1642         default:
1643             return _("UNKNOWN");
1644     }
1645 }
1646
1647 static void l2cap_do_one(int nr, const char *line, const char *prot)
1648 {
1649     char daddr[18], saddr[18];
1650     unsigned state, psm, dcid, scid, imtu, omtu, sec_level;
1651     int num;
1652     const char *bt_state, *bt_sec_level;
1653
1654     num = sscanf(line, "%17s %17s %d %d 0x%04x 0x%04x %d %d %d",
1655         daddr, saddr, &state, &psm, &dcid, &scid, &imtu, &omtu, &sec_level);
1656
1657     if (num < 9) {
1658         fprintf(stderr, _("warning, got bogus l2cap line.\n"));
1659         return;
1660     }
1661
1662     if (flag_lst && !(state == BT_LISTEN || state == BT_BOUND))
1663         return;
1664     if (!(flag_all || flag_lst) && (state == BT_LISTEN || state == BT_BOUND))
1665         return;
1666
1667     bt_state = bluetooth_state(state);
1668     switch (sec_level) {
1669         case BT_SECURITY_SDP:
1670             bt_sec_level = _("SDP");
1671             break;
1672         case BT_SECURITY_LOW:
1673             bt_sec_level = _("LOW");
1674             break;
1675         case BT_SECURITY_MEDIUM:
1676             bt_sec_level = _("MEDIUM");
1677             break;
1678         case BT_SECURITY_HIGH:
1679             bt_sec_level = _("HIGH");
1680             break;
1681         default:
1682             bt_sec_level = _("UNKNOWN");
1683     }
1684
1685     printf("l2cap  %-17s %-17s %-9s %7d 0x%04x 0x%04x %7d %7d %-7s\n",
1686         (strcmp (daddr, "00:00:00:00:00:00") == 0 ? "*" : daddr),
1687         (strcmp (saddr, "00:00:00:00:00:00") == 0 ? "*" : saddr),
1688         bt_state, psm, dcid, scid, imtu, omtu, bt_sec_level);
1689 }
1690
1691 static int l2cap_info(void)
1692 {
1693     printf("%-6s %-17s %-17s %-9s %7s %-6s %-6s %7s %7s %-7s\n",
1694         "Proto", "Destination", "Source", "State", "PSM", "DCID", "SCID", "IMTU", "OMTU", "Security");
1695     INFO_GUTS(_PATH_SYS_BLUETOOTH_L2CAP, "AF BLUETOOTH", l2cap_do_one, "l2cap");
1696 }
1697
1698 static void rfcomm_do_one(int nr, const char *line, const char *prot)
1699 {
1700     char daddr[18], saddr[18];
1701     unsigned state, channel;
1702     int num;
1703     const char *bt_state;
1704
1705     num = sscanf(line, "%17s %17s %d %d", daddr, saddr, &state, &channel);
1706     if (num < 4) {
1707         fprintf(stderr, _("warning, got bogus rfcomm line.\n"));
1708         return;
1709     }
1710
1711     if (flag_lst && !(state == BT_LISTEN || state == BT_BOUND))
1712         return;
1713     if (!(flag_all || flag_lst) && (state == BT_LISTEN || state == BT_BOUND))
1714         return;
1715
1716     bt_state = bluetooth_state(state);
1717     printf("rfcomm %-17s %-17s %-9s %7d\n",
1718         (strcmp (daddr, "00:00:00:00:00:00") == 0 ? "*" : daddr),
1719         (strcmp (saddr, "00:00:00:00:00:00") == 0 ? "*" : saddr),
1720         bt_state, channel);
1721 }
1722
1723 static int rfcomm_info(void)
1724 {
1725     printf("%-6s %-17s %-17s %-9s %7s\n", "Proto", "Destination", "Source", "State", "Channel");
1726     INFO_GUTS(_PATH_SYS_BLUETOOTH_RFCOMM, "AF BLUETOOTH", rfcomm_do_one, "rfcomm");
1727 }
1728 #endif
1729
1730 static int iface_info(void)
1731 {
1732     if (skfd < 0) {
1733         if ((skfd = sockets_open(0)) < 0) {
1734             perror("socket");
1735             exit(1);
1736         }
1737         printf(_("Kernel Interface table\n"));
1738     }
1739     if (flag_exp < 2) {
1740         ife_short = 1;
1741         printf(_("Iface   MTU Met   RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
1742     }
1743
1744     if (for_all_interfaces(do_if_print, &flag_all) < 0) {
1745         perror(_("missing interface information"));
1746         exit(1);
1747     }
1748     if (flag_cnt)
1749         if_cache_free();
1750     else {
1751         close(skfd);
1752         skfd = -1;
1753     }
1754
1755     return 0;
1756 }
1757
1758
1759 static void version(void)
1760 {
1761     printf("%s\n%s\n%s\n%s\n", Release, Version, Signature, Features);
1762     exit(E_VERSION);
1763 }
1764
1765
1766 static void usage(void)
1767 {
1768     fprintf(stderr, _("usage: netstat [-vWeenNcCF] [<Af>] -r         netstat {-V|--version|-h|--help}\n"));
1769     fprintf(stderr, _("       netstat [-vWnNcaeol] [<Socket> ...]\n"));
1770     fprintf(stderr, _("       netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }\n\n"));
1771
1772     fprintf(stderr, _("        -r, --route              display routing table\n"));
1773     fprintf(stderr, _("        -i, --interfaces         display interface table\n"));
1774     fprintf(stderr, _("        -g, --groups             display multicast group memberships\n"));
1775     fprintf(stderr, _("        -s, --statistics         display networking statistics (like SNMP)\n"));
1776 #if HAVE_FW_MASQUERADE
1777     fprintf(stderr, _("        -M, --masquerade         display masqueraded connections\n\n"));
1778 #endif
1779     fprintf(stderr, _("        -v, --verbose            be verbose\n"));
1780     fprintf(stderr, _("        -W, --wide               don't truncate IP addresses\n"));
1781     fprintf(stderr, _("        -n, --numeric            don't resolve names\n"));
1782     fprintf(stderr, _("        --numeric-hosts          don't resolve host names\n"));
1783     fprintf(stderr, _("        --numeric-ports          don't resolve port names\n"));
1784     fprintf(stderr, _("        --numeric-users          don't resolve user names\n"));
1785     fprintf(stderr, _("        -N, --symbolic           resolve hardware names\n"));
1786     fprintf(stderr, _("        -e, --extend             display other/more information\n"));
1787     fprintf(stderr, _("        -p, --programs           display PID/Program name for sockets\n"));
1788     fprintf(stderr, _("        -c, --continuous         continuous listing\n\n"));
1789     fprintf(stderr, _("        -l, --listening          display listening server sockets\n"));
1790     fprintf(stderr, _("        -a, --all, --listening   display all sockets (default: connected)\n"));
1791     fprintf(stderr, _("        -o, --timers             display timers\n"));
1792     fprintf(stderr, _("        -F, --fib                display Forwarding Information Base (default)\n"));
1793     fprintf(stderr, _("        -C, --cache              display routing cache instead of FIB\n\n"));
1794
1795     fprintf(stderr, _("  <Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
1796     fprintf(stderr, _("  <AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: %s\n"), DFLT_AF);
1797     fprintf(stderr, _("  List of possible address families (which support routing):\n"));
1798     print_aflist(1); /* 1 = routeable */
1799     exit(E_USAGE);
1800 }
1801
1802
1803 int main
1804  (int argc, char *argv[]) {
1805     int i;
1806     int lop;
1807     static struct option longopts[] =
1808     {
1809         AFTRANS_OPTS,
1810         {"version", 0, 0, 'V'},
1811         {"interfaces", 0, 0, 'i'},
1812         {"help", 0, 0, 'h'},
1813         {"route", 0, 0, 'r'},
1814 #if HAVE_FW_MASQUERADE
1815         {"masquerade", 0, 0, 'M'},
1816 #endif
1817         {"protocol", 1, 0, 'A'},
1818         {"tcp", 0, 0, 't'},
1819         {"sctp", 0, 0, 'S'},
1820         {"udp", 0, 0, 'u'},
1821         {"udplite", 0, 0, 'U'},
1822         {"raw", 0, 0, 'w'},
1823         {"unix", 0, 0, 'x'},
1824         {"l2cap", 0, 0, '2'},
1825         {"rfcomm", 0, 0, 'f'},
1826         {"listening", 0, 0, 'l'},
1827         {"all", 0, 0, 'a'},
1828         {"timers", 0, 0, 'o'},
1829         {"continuous", 0, 0, 'c'},
1830         {"extend", 0, 0, 'e'},
1831         {"programs", 0, 0, 'p'},
1832         {"verbose", 0, 0, 'v'},
1833         {"statistics", 0, 0, 's'},
1834         {"wide", 0, 0, 'W'},
1835         {"numeric", 0, 0, 'n'},
1836         {"numeric-hosts", 0, 0, '!'},
1837         {"numeric-ports", 0, 0, '@'},
1838         {"numeric-users", 0, 0, '#'},
1839         {"symbolic", 0, 0, 'N'},
1840         {"cache", 0, 0, 'C'},
1841         {"fib", 0, 0, 'F'},
1842         {"groups", 0, 0, 'g'},
1843         {NULL, 0, 0, 0}
1844     };
1845
1846 #if I18N
1847     setlocale (LC_ALL, "");
1848     bindtextdomain("net-tools", "/usr/share/locale");
1849     textdomain("net-tools");
1850 #endif
1851     getroute_init();            /* Set up AF routing support */
1852
1853     afname[0] = '\0';
1854     while ((i = getopt_long(argc, argv, "A:CFMacdeghilnNoprsStuUvVWwx64?", longopts, &lop)) != EOF)
1855         switch (i) {
1856         case -1:
1857             break;
1858         case 1:
1859             if (lop < 0 || lop >= AFTRANS_CNT) {
1860                 EINTERN("netstat.c", "longopts 1 range");
1861                 break;
1862             }
1863             if (aftrans_opt(longopts[lop].name))
1864                 exit(1);
1865             break;
1866         case 'A':
1867             if (aftrans_opt(optarg))
1868                 exit(1);
1869             break;
1870         case 'M':
1871             flag_mas++;
1872             break;
1873         case 'a':
1874             flag_all++;
1875             break;
1876         case 'l':
1877             flag_lst++;
1878             break;
1879         case 'c':
1880             flag_cnt++;
1881             break;
1882
1883         case 'd':
1884             flag_deb++;
1885             break;
1886         case 'g':
1887             flag_igmp++;
1888             break;
1889         case 'e':
1890             flag_exp++;
1891             break;
1892         case 'p':
1893             flag_prg++;
1894             break;
1895         case 'i':
1896             flag_int++;
1897             break;
1898         case 'W':
1899             flag_wide++;
1900             break;
1901         case 'n':
1902             flag_not |= FLAG_NUM;
1903             break;
1904         case '!':
1905             flag_not |= FLAG_NUM_HOST;
1906             break;
1907         case '@':
1908             flag_not |= FLAG_NUM_PORT;
1909             break;
1910         case '#':
1911             flag_not |= FLAG_NUM_USER;
1912             break;
1913         case 'N':
1914             flag_not |= FLAG_SYM;
1915             break;
1916         case 'C':
1917             flag_cf |= FLAG_CACHE;
1918             break;
1919         case 'F':
1920             flag_cf |= FLAG_FIB;
1921             break;
1922         case 'o':
1923             flag_opt++;
1924             break;
1925         case '6':
1926             if (aftrans_opt("inet6"))
1927                 exit(1);
1928             break;
1929         case '4':
1930             if (aftrans_opt("inet"))
1931                 exit(1);
1932             break;
1933         case 'V':
1934             version();
1935             /*NOTREACHED */
1936         case 'v':
1937             flag_ver |= FLAG_VERBOSE;
1938             break;
1939         case 'r':
1940             flag_rou++;
1941             break;
1942         case 't':
1943             flag_tcp++;
1944             break;
1945         case 'S':
1946             flag_sctp++;
1947             break;
1948         case 'u':
1949             flag_udp++;
1950             break;
1951         case 'U':
1952             flag_udplite++;
1953             break;
1954         case 'w':
1955             flag_raw++;
1956             break;
1957         case '2':
1958             flag_l2cap++;
1959             break;
1960         case 'f':
1961             flag_rfcomm++;
1962             break;
1963         case 'x':
1964             if (aftrans_opt("unix"))
1965                 exit(1);
1966             break;
1967         case '?':
1968         case 'h':
1969             usage();
1970         case 's':
1971             flag_sta++;
1972         }
1973
1974     if (flag_int + flag_rou + flag_mas + flag_sta > 1)
1975         usage();
1976
1977     if ((flag_inet || flag_inet6 || flag_sta) && 
1978         !(flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw))
1979            flag_tcp = flag_sctp = flag_udp = flag_udplite = flag_raw = 1;
1980
1981     if ((flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw || flag_igmp) && 
1982         !(flag_inet || flag_inet6))
1983         flag_inet = flag_inet6 = 1;
1984
1985     if (flag_bluetooth && !(flag_l2cap || flag_rfcomm))
1986            flag_l2cap = flag_rfcomm = 1;
1987
1988     flag_arg = flag_tcp + flag_sctp + flag_udplite + flag_udp + flag_raw + flag_unx 
1989         + flag_ipx + flag_ax25 + flag_netrom + flag_igmp + flag_x25 + flag_rose
1990         + flag_l2cap + flag_rfcomm;
1991
1992     if (flag_mas) {
1993 #if HAVE_FW_MASQUERADE && HAVE_AFINET
1994 #if MORE_THAN_ONE_MASQ_AF
1995         if (!afname[0])
1996             strcpy(afname, DFLT_AF);
1997 #endif
1998         for (;;) {
1999             i = ip_masq_info(flag_not & FLAG_NUM_HOST,
2000                              flag_not & FLAG_NUM_PORT, flag_exp);
2001             if (i || !flag_cnt)
2002                 break;
2003             wait_continous();
2004         }
2005 #else
2006         ENOSUPP("netstat", "FW_MASQUERADE");
2007         i = -1;
2008 #endif
2009         return (i);
2010     }
2011
2012     if (flag_sta) {
2013         if (!afname[0])
2014             strcpy(afname, DFLT_AF);
2015             
2016         if (!strcmp(afname, "inet")) {
2017 #if HAVE_AFINET
2018             inittab();
2019             parsesnmp(flag_raw, flag_tcp, flag_udp);
2020 #else
2021             ENOSUPP("netstat", "AF INET");
2022 #endif
2023         } else if(!strcmp(afname, "inet6")) {
2024 #if HAVE_AFINET6
2025             inittab6();
2026             parsesnmp6(flag_raw, flag_tcp, flag_udp);
2027 #else
2028             ENOSUPP("netstat", "AF INET6");
2029 #endif
2030         } else {
2031           printf(_("netstat: No statistics support for specified address family: %s\n"), afname);
2032           exit(1);
2033         }
2034         exit(0);
2035     }
2036     
2037     if (flag_rou) {
2038         int options = 0;
2039
2040         if (!afname[0])
2041             strcpy(afname, DFLT_AF);
2042
2043         if (flag_exp == 2)
2044             flag_exp = 1;
2045         else if (flag_exp == 1)
2046             flag_exp = 2;
2047
2048         options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
2049         if (!flag_cf)
2050             options |= FLAG_FIB;
2051
2052         for (;;) {
2053             i = route_info(afname, options);
2054             if (i || !flag_cnt)
2055                 break;
2056             wait_continous();
2057         }
2058         return (i);
2059     }
2060     if (flag_int) {
2061         for (;;) {
2062             i = iface_info();
2063             if (!flag_cnt || i)
2064                 break;
2065             wait_continous();
2066         }
2067         return (i);
2068     }
2069     for (;;) {
2070         if (!flag_arg || flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw) {
2071 #if HAVE_AFINET
2072             prg_cache_load();
2073             printf(_("Active Internet connections "));  /* xxx */
2074
2075             if (flag_all)
2076                 printf(_("(servers and established)"));
2077             else {
2078               if (flag_lst)
2079                 printf(_("(only servers)"));
2080               else
2081                 printf(_("(w/o servers)"));
2082             }
2083             printf(_("\nProto Recv-Q Send-Q Local Address           Foreign Address         State      "));     /* xxx */
2084             if (flag_exp > 1)
2085                 printf(_(" User       Inode     "));
2086             print_progname_banner();
2087             if (flag_opt)
2088                 printf(_(" Timer"));    /* xxx */
2089             printf("\n");
2090 #else
2091             if (flag_arg) {
2092                 i = 1;
2093                 ENOSUPP("netstat", "AF INET");
2094             }
2095 #endif
2096         }
2097 #if HAVE_AFINET
2098         if (!flag_arg || flag_tcp) {
2099             i = tcp_info();
2100             if (i)
2101                 return (i);
2102         }
2103
2104         if (!flag_arg || flag_sctp) {
2105             i = sctp_info();
2106             if (i)
2107                 return (i);
2108         }
2109
2110         if (!flag_arg || flag_udp) {
2111             i = udp_info();
2112             if (i)
2113                 return (i);
2114         }
2115
2116         if (!flag_arg || flag_udplite) {
2117             i = udplite_info();
2118             if (i)
2119                 return (i);
2120         }
2121
2122         if (!flag_arg || flag_raw) {
2123             i = raw_info();
2124             if (i)
2125                 return (i);
2126         }
2127
2128         if (flag_igmp) {
2129 #if HAVE_AFINET6
2130             printf( "IPv6/");
2131 #endif
2132             printf( _("IPv4 Group Memberships\n") );
2133             printf( _("Interface       RefCnt Group\n") );
2134             printf( "--------------- ------ ---------------------\n" );
2135             i = igmp_info();
2136             if (i)
2137                 return (i);
2138         }
2139 #endif
2140
2141         if (!flag_arg || flag_unx) {
2142 #if HAVE_AFUNIX
2143             prg_cache_load();
2144             i = unix_info();
2145             if (i)
2146                 return (i);
2147 #else
2148             if (flag_arg) {
2149                 i = 1;
2150                 ENOSUPP("netstat", "AF UNIX");
2151             }
2152 #endif
2153         }
2154         if (!flag_arg || flag_ipx) {
2155 #if HAVE_AFIPX
2156             i = ipx_info();
2157             if (i)
2158                 return (i);
2159 #else
2160             if (flag_arg) {
2161                 i = 1;
2162                 ENOSUPP("netstat", "AF IPX");
2163             }
2164 #endif
2165         }
2166         if (!flag_arg || flag_ax25) {
2167 #if HAVE_AFAX25
2168             i = ax25_info();
2169             if (i)
2170                 return (i);
2171 #else
2172             if (flag_arg) {
2173                 i = 1;
2174                 ENOSUPP("netstat", "AF AX25");
2175             }
2176 #endif
2177         }
2178         if(!flag_arg || flag_x25) {
2179 #if HAVE_AFX25
2180             /* FIXME */
2181             i = x25_info();
2182             if (i)
2183                 return(i);
2184 #else
2185             if (flag_arg) {
2186                 i = 1;
2187                 ENOSUPP("netstat", "AF X25");
2188             }
2189 #endif
2190         }
2191         if (!flag_arg || flag_netrom) {
2192 #if HAVE_AFNETROM
2193             i = netrom_info();
2194             if (i)
2195                 return (i);
2196 #else
2197             if (flag_arg) {
2198                 i = 1;
2199                 ENOSUPP("netstat", "AF NETROM");
2200             }
2201 #endif
2202         }
2203         if (!flag_arg || flag_rose) {
2204 #if 0 && HAVE_AFROSE
2205           i = rose_info();
2206           if (i)
2207             return (i);
2208 #else
2209           if (flag_arg) {
2210             i = 1;
2211             ENOSUPP("netstat", "AF ROSE");
2212           }
2213 #endif
2214         }
2215
2216         if (!flag_arg || flag_l2cap || flag_rfcomm) {
2217 #if HAVE_BLUETOOTH
2218             printf(_("Active Bluetooth connections ")); /* xxx */
2219
2220             if (flag_all)
2221                 printf(_("(servers and established)"));
2222             else {
2223               if (flag_lst)
2224                 printf(_("(only servers)"));
2225               else
2226                 printf(_("(w/o servers)"));
2227             }
2228             printf("\n");
2229 #else
2230             if (flag_arg) {
2231                 i = 1;
2232                 ENOSUPP("netstat", "AF BLUETOOTH");
2233             }
2234 #endif
2235         }
2236 #if HAVE_BLUETOOTH
2237         if (!flag_arg || flag_l2cap) {
2238             i = l2cap_info();
2239             if (i)
2240                 return (i);
2241         }
2242         if (!flag_arg || flag_rfcomm) {
2243             i = rfcomm_info();
2244             if (i)
2245                 return (i);
2246         }
2247 #endif
2248
2249         if (!flag_cnt || i)
2250             break;
2251         wait_continous();
2252         prg_cache_clear();
2253     }
2254     return (i);
2255 }