mii-tool: use <linux/mii.h> instead of "mii.h" and fix RHBZ #491358
[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_AFBLUETOOTH
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             if (lnamelen == -1)
409                     continue;
410             lname[lnamelen] = '\0';  /*make it a null-terminated string*/
411
412             if (extract_type_1_socket_inode(lname, &inode) < 0)
413               if (extract_type_2_socket_inode(lname, &inode) < 0)
414                 continue;
415
416             if (!cmdlp) {
417                 if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >= 
418                     sizeof(line) - 5) 
419                     continue;
420                 strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
421                 fd = open(line, O_RDONLY);
422                 if (fd < 0) 
423                     continue;
424                 cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
425                 if (close(fd)) 
426                     continue;
427                 if (cmdllen == -1) 
428                     continue;
429                 if (cmdllen < sizeof(cmdlbuf) - 1) 
430                     cmdlbuf[cmdllen]='\0';
431                 if (cmdlbuf[0] == '/' && (cmdlp = strrchr(cmdlbuf, '/'))) 
432                     cmdlp++;
433                 else 
434                     cmdlp = cmdlbuf;
435             }
436
437             snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
438             prg_cache_add(inode, finbuf);
439         }
440         closedir(dirfd); 
441         dirfd = NULL;
442     }
443     if (dirproc) 
444         closedir(dirproc);
445     if (dirfd) 
446         closedir(dirfd);
447     if (!eacces) 
448         return;
449     if (prg_cache_loaded == 1) {
450     fail:
451         fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
452                 geteuid());
453     }
454     else
455         fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
456                          " will not be shown, you would have to be root to see it all.)\n"));
457 }
458
459 #if HAVE_AFNETROM
460 static const char *netrom_state[] =
461 {
462     N_("LISTENING"),
463     N_("CONN SENT"),
464     N_("DISC SENT"),
465     N_("ESTABLISHED")
466 };
467
468 static int netrom_info(void)
469 {
470     FILE *f;
471     char buffer[256], dev[16];
472     int st, vs, vr, sendq, recvq, ret;
473
474     f = proc_fopen(_PATH_PROCNET_NR);
475     if (f == NULL) {
476         if (errno != ENOENT) {
477             perror(_PATH_PROCNET_NR);
478             return (-1);
479         }
480         if (flag_arg || flag_ver)
481             ESYSNOT("netstat", "AF NETROM");
482         if (flag_arg)
483             return (1);
484         else
485             return (0);
486     }
487     printf(_("Active NET/ROM sockets\n"));
488     printf(_("User       Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q\n"));
489     if (fgets(buffer, 256, f))
490         /* eat line */;
491
492     while (fgets(buffer, 256, f)) {
493         buffer[9] = 0;
494         buffer[19] = 0;
495         buffer[29] = 0;
496         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",
497                dev, &st, &vs, &vr, &sendq, &recvq);
498         if (ret != 6) {
499             printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
500             continue;
501         }
502         printf("%-9s  %-9s  %-9s  %-6s  %-11s  %03d/%03d  %-6d  %-6d\n",
503                buffer, buffer + 10, buffer + 20,
504                dev,
505                _(netrom_state[st]),
506                vr, vs, sendq, recvq);
507     }
508     fclose(f);
509     return 0;
510 }
511 #endif
512
513 /* These enums are used by IPX too. :-( */
514 enum {
515     TCP_ESTABLISHED = 1,
516     TCP_SYN_SENT,
517     TCP_SYN_RECV,
518     TCP_FIN_WAIT1,
519     TCP_FIN_WAIT2,
520     TCP_TIME_WAIT,
521     TCP_CLOSE,
522     TCP_CLOSE_WAIT,
523     TCP_LAST_ACK,
524     TCP_LISTEN,
525     TCP_CLOSING                 /* now a valid state */
526 };
527
528 #if HAVE_AFINET || HAVE_AFINET6
529
530 static const char *tcp_state[] =
531 {
532     "",
533     N_("ESTABLISHED"),
534     N_("SYN_SENT"),
535     N_("SYN_RECV"),
536     N_("FIN_WAIT1"),
537     N_("FIN_WAIT2"),
538     N_("TIME_WAIT"),
539     N_("CLOSE"),
540     N_("CLOSE_WAIT"),
541     N_("LAST_ACK"),
542     N_("LISTEN"),
543     N_("CLOSING")
544 };
545
546 static void finish_this_one(int uid, unsigned long inode, const char *timers)
547 {
548     struct passwd *pw;
549
550     if (flag_exp > 1) {
551         if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
552             printf(" %-10s ", pw->pw_name);
553         else
554             printf(" %-10d ", uid);
555         printf("%-10lu",inode);
556     }
557     if (flag_prg)
558         printf(" %-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
559     if (flag_opt)
560         printf(" %s", timers);
561     putchar('\n');
562 }
563
564 static void igmp_do_one(int lnr, const char *line,const char *prot)
565 {
566     char mcast_addr[128];
567 #if HAVE_AFINET6
568     struct sockaddr_in6 mcastaddr;
569     char addr6[INET6_ADDRSTRLEN];
570     struct in6_addr in6;
571     extern struct aftype inet6_aftype;
572 #else
573     struct sockaddr_in mcastaddr;
574 #endif
575     struct aftype *ap;
576     static int idx_flag = 0;
577     static int igmp6_flag = 0;
578     static char device[16];
579     int num, idx, refcnt;
580
581     if (lnr == 0) {
582         /* IPV6 ONLY */
583         /* igmp6 file does not have any comments on first line */
584         if ( strstr( line, "Device" ) == NULL ) {
585             igmp6_flag = 1;
586         } else {
587             /* IPV4 ONLY */
588             /* 2.1.x kernels and up have Idx field */
589             /* 2.0.x and below do not have Idx field */
590             if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
591                 idx_flag = 1;
592             else
593                 idx_flag = 0;
594             return;
595         }
596     }
597
598     if (igmp6_flag) {    /* IPV6 */
599 #if HAVE_AFINET6
600         num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
601         if (num == 4) {
602             /* Demangle what the kernel gives us */
603             sscanf(mcast_addr, "%08X%08X%08X%08X",
604                    &in6.s6_addr32[0], &in6.s6_addr32[1],
605            &in6.s6_addr32[2], &in6.s6_addr32[3]);
606             in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
607             in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
608             in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
609             in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
610         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
611             inet6_aftype.input(1, addr6, (struct sockaddr *) &mcastaddr);
612             mcastaddr.sin6_family = AF_INET6;
613         } else {
614             fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
615             return;
616         }
617
618         if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
619             fprintf(stderr, _("netstat: unsupported address family %d !\n"),
620                     ((struct sockaddr *) &mcastaddr)->sa_family);
621             return;
622         }
623         safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr, 
624                                       flag_not & FLAG_NUM_HOST), sizeof(mcast_addr));
625         printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
626 #endif
627     } else {    /* IPV4 */
628 #if HAVE_AFINET
629         if (line[0] != '\t') {
630             if (idx_flag) {
631                 if ((num = sscanf( line, "%d\t%10c", &idx, device)) < 2) {
632                     fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
633                     return;
634                 }
635             } else {
636                 if ( (num = sscanf( line, "%10c", device )) < 1 ) {
637                     fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
638                     return;
639                 }
640             }
641             device[10] = '\0';
642             return;
643         } else if ( line[0] == '\t' ) {
644             if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
645                 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
646                 return;
647             }
648             sscanf( mcast_addr, "%X",
649                     &((struct sockaddr_in *) &mcastaddr)->sin_addr.s_addr );
650             ((struct sockaddr *) &mcastaddr)->sa_family = AF_INET;
651         } else {
652             fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
653             return;
654         }
655         
656         if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
657             fprintf(stderr, _("netstat: unsupported address family %d !\n"),
658                     ((struct sockaddr *) &mcastaddr)->sa_family);
659             return;
660         }
661         safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr, 
662                                       flag_not & FLAG_NUM_HOST), sizeof(mcast_addr));
663         printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
664 #endif
665     }    /* IPV4 */
666 }
667
668 #if HAVE_AFX25
669 static int x25_info(void)
670 {
671        FILE *f=proc_fopen(_PATH_PROCNET_X25);
672        char buffer[256],dev[16];
673        int st,vs,vr,sendq,recvq,lci;
674        static char *x25_state[5]=
675        {
676                "LISTENING",
677                "SABM_SENT",
678                "DISC_SENT",
679                "ESTABLISHED",
680                "RECOVERY"
681        };
682        if(!f)
683        {
684                if (errno != ENOENT) {
685                        perror(_PATH_PROCNET_X25);
686                        return(-1);
687                }
688                if (flag_arg || flag_ver)
689                        ESYSNOT("netstat","AF X25");
690                if (flag_arg)
691                        return(1);
692                else
693                        return(0);
694        }
695        printf( _("Active X.25 sockets\n"));
696        /* IMHO, Vr/Vs is not very usefull --SF */
697        printf( _("Dest         Source          Device  LCI  State        Vr/Vs  Send-Q  Recv-Q\n"));
698        if (fgets(buffer,256,f))
699                /* eat line */;
700        while(fgets(buffer,256,f))
701        {
702                buffer[10]=0;
703                buffer[20]=0;
704                sscanf(buffer+22,"%s %d %d %d %d %*d %*d %*d %*d %*d %*d %d %d %*d",
705                        dev,&lci,&st,&vs,&vr,&sendq,&recvq);
706                if (!(flag_all || lci))
707                        continue;
708                printf("%-15s %-15s %-7s %-3d  %-11s  %02d/%02d  %-6d  %-6d\n",
709                        buffer,buffer+11,
710                        dev,
711                        lci,
712                        x25_state[st],
713                        vr,vs,sendq,recvq);
714        }
715        fclose(f);
716        return 0;               
717 }
718 #endif
719
720 static int igmp_info(void)
721 {
722     INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
723                igmp_do_one, "igmp", "igmp6");
724 }
725
726 static int ip_parse_dots(uint32_t *addr, char const *src) {
727   unsigned  a, b, c, d;
728   unsigned  ret = 4-sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d);
729   *addr = htonl((a << 24)|(b << 16)|(c << 8)|d);
730   return  ret;
731 }
732
733 static void print_ip_service(struct sockaddr_in *addr, char const *protname,
734                              char *buf, unsigned size) {
735   struct aftype *ap;
736
737   if(size == 0)  return;
738
739   /* print host */
740   if((ap = get_afntype(addr->sin_family)) == NULL) {
741     fprintf(stderr, _("netstat: unsupported address family %d !\n"),
742             addr->sin_family);
743     return;
744   }
745   safe_strncpy(buf, ap->sprint((struct sockaddr*)addr, flag_not), size);
746
747   /* print service */
748   if(flag_all || (flag_lst && !addr->sin_port) || (!flag_lst && addr->sin_port)) {
749     char  bfs[32];
750
751     snprintf(bfs, sizeof(bfs), "%s",
752              get_sname(addr->sin_port, (char*)protname, flag_not & FLAG_NUM_PORT));
753
754     /* check if we must cut on host and/or service name */
755     {
756       unsigned const  bufl = strlen(buf);
757       unsigned const  bfsl = strlen(bfs);
758
759       if(bufl+bfsl+2 > size) {
760         unsigned const  half = (size-2)>>1;
761         if(bufl > half) {
762           if(bfsl > half) {
763             buf[size-2-half] = '\0';
764             bfs[half+1]      = '\0';
765           }
766           else  buf[size-2-bfsl] = '\0';
767         }
768         else  bfs[size-2-bufl] = '\0';
769       }  
770     }
771     strcat(buf, ":");
772     strcat(buf, bfs);
773   }
774 }
775
776 /* process single SCTP endpoint */
777 static void sctp_do_ept(int lnr, char const *line, const char *prot)
778 {
779   struct sockaddr_in  laddr, raddr;
780   unsigned            uid, inode;
781
782   char        l_addr[23], r_addr[23];
783
784   /* fill sockaddr_in structures */
785   {
786     unsigned  lport;
787     unsigned  ate;
788
789     if(lnr == 0)  return;
790     if(sscanf(line, "%*X %*X %*u %*u %*u %u %u %u %n",
791               &lport, &uid, &inode, &ate) < 3)  goto err;
792
793     /* decode IP address */
794     if(ip_parse_dots(&laddr.sin_addr.s_addr, line+ate))  goto err;
795     raddr.sin_addr.s_addr = htonl(0);
796     laddr.sin_family = raddr.sin_family = AF_INET;
797     laddr.sin_port = htons(lport);
798     raddr.sin_port = htons(0);
799   }
800
801   /* print IP:service to l_addr and r_addr */
802   print_ip_service(&laddr, prot, l_addr, sizeof(l_addr));
803   print_ip_service(&raddr, prot, r_addr, sizeof(r_addr));
804
805   /* Print line */
806   printf("%-4s  %6d %6d %-*s %-*s %-11s",
807          prot, 0, 0,
808          (int)netmax(23,strlen(l_addr)), l_addr,
809          (int)netmax(23,strlen(r_addr)), r_addr,
810          _(tcp_state[TCP_LISTEN]));
811   finish_this_one(uid, inode, "");
812   return;
813  err:
814   fprintf(stderr, "SCTP error in line: %d\n", lnr);
815 }
816
817 /* process single SCTP association */
818 static void sctp_do_assoc(int lnr, char const *line, const char *prot)
819 {
820   struct sockaddr_in  laddr, raddr;
821   unsigned long       rxq, txq;
822   unsigned            uid, inode;
823
824   char        l_addr[23], r_addr[23];
825
826   /* fill sockaddr_in structures */
827   {
828     unsigned    lport, rport;
829     unsigned    ate;
830     char const *addr;
831
832     if(lnr == 0)  return;
833     if(sscanf(line, "%*X %*X %*u %*u %*u %*u %*u %lu %lu %u %u %u %u %n",
834               &txq, &rxq, &uid, &inode, &lport, &rport, &ate) < 6)  goto err;
835
836     /* decode IP addresses */
837     addr = strchr(line+ate, '*');
838     if(addr == 0)  goto err;
839     if(ip_parse_dots(&laddr.sin_addr.s_addr, ++addr))  goto err;
840     addr = strchr(addr, '*');
841     if(addr == 0)  goto err;
842     if(ip_parse_dots(&raddr.sin_addr.s_addr, ++addr))  goto err;
843
844     /* complete sockaddr_in structures */
845     laddr.sin_family = raddr.sin_family = AF_INET;
846     laddr.sin_port = htons(lport);
847     raddr.sin_port = htons(rport);
848   }
849
850   /* print IP:service to l_addr and r_addr */
851   print_ip_service(&laddr, prot, l_addr, sizeof(l_addr));
852   print_ip_service(&raddr, prot, r_addr, sizeof(r_addr));
853
854   /* Print line */
855   printf("%-4s  %6ld %6ld %-*s %-*s %-11s",
856          prot, rxq, txq,
857          (int)netmax(23,strlen(l_addr)), l_addr,
858          (int)netmax(23,strlen(r_addr)), r_addr,
859          _(tcp_state[TCP_ESTABLISHED]));
860   finish_this_one(uid, inode, "");
861   return;
862  err:
863   fprintf(stderr, "SCTP error in line: %d\n", lnr);
864 }
865
866 static int sctp_info_epts(void) {
867   INFO_GUTS6(_PATH_PROCNET_SCTPEPTS, _PATH_PROCNET_SCTP6EPTS, "AF INET (sctp)",
868              sctp_do_ept, "sctp", "sctp6");
869 }
870
871 static int sctp_info_assocs(void) {
872   INFO_GUTS6(_PATH_PROCNET_SCTPASSOCS, _PATH_PROCNET_SCTP6ASSOCS, "AF INET (sctp)",
873              sctp_do_assoc, "sctp", "sctp6");
874 }
875
876 static int sctp_info(void) {
877   int  res;
878   res = sctp_info_epts();
879   if(res)  return  res;
880   return  sctp_info_assocs();
881 }
882
883 static void addr_do_one(char *buf, size_t buf_len, size_t short_len, struct aftype *ap,
884 #if HAVE_AFINET6
885                         struct sockaddr_in6 *addr,
886 #else
887                         struct sockaddr_in *addr,
888 #endif
889                         int port, const char *proto
890 )
891 {
892     const char *sport, *saddr;
893     size_t port_len, addr_len;
894
895     saddr = ap->sprint((struct sockaddr *)addr, flag_not & FLAG_NUM_HOST);
896     sport = get_sname(htons(port), proto, flag_not & FLAG_NUM_PORT);
897     addr_len = strlen(saddr);
898     port_len = strlen(sport);
899     if (!flag_wide && (addr_len + port_len > short_len)) {
900         /* Assume port name is short */
901         port_len = netmin(port_len, short_len - 4);
902         addr_len = short_len - port_len;
903         strncpy(buf, saddr, addr_len);
904         buf[addr_len] = '\0';
905         strcat(buf, ":");
906         strncat(buf, sport, port_len);
907     } else
908         snprintf(buf, buf_len, "%s:%s", saddr, sport);
909 }
910
911 static void tcp_do_one(int lnr, const char *line, const char *prot)
912 {
913     unsigned long rxq, txq, time_len, retr, inode;
914     int num, local_port, rem_port, d, state, uid, timer_run, timeout;
915     char rem_addr[128], local_addr[128], timers[64], more[512];
916     struct aftype *ap;
917 #if HAVE_AFINET6
918     struct sockaddr_in6 localaddr, remaddr;
919     char addr6[INET6_ADDRSTRLEN];
920     struct in6_addr in6;
921     extern struct aftype inet6_aftype;
922 #else
923     struct sockaddr_in localaddr, remaddr;
924 #endif
925
926     if (lnr == 0)
927         return;
928
929     num = sscanf(line,
930     "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %512s\n",
931                  &d, local_addr, &local_port, rem_addr, &rem_port, &state,
932                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
933
934     if (!flag_all && ((flag_lst && rem_port) || (!flag_lst && !rem_port)))
935       return;
936
937     if (strlen(local_addr) > 8) {
938 #if HAVE_AFINET6
939         /* Demangle what the kernel gives us */
940         sscanf(local_addr, "%08X%08X%08X%08X",
941                &in6.s6_addr32[0], &in6.s6_addr32[1],
942            &in6.s6_addr32[2], &in6.s6_addr32[3]);
943         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
944         inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
945         sscanf(rem_addr, "%08X%08X%08X%08X",
946                &in6.s6_addr32[0], &in6.s6_addr32[1],
947                &in6.s6_addr32[2], &in6.s6_addr32[3]);
948         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
949         inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
950         localaddr.sin6_family = AF_INET6;
951         remaddr.sin6_family = AF_INET6;
952 #endif
953     } else {
954         sscanf(local_addr, "%X",
955                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
956         sscanf(rem_addr, "%X",
957                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
958         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
959         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
960     }
961
962     if (num < 11) {
963         fprintf(stderr, _("warning, got bogus tcp line.\n"));
964         return;
965     }
966     if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
967         fprintf(stderr, _("netstat: unsupported address family %d !\n"),
968                 ((struct sockaddr *) &localaddr)->sa_family);
969         return;
970     }
971
972         addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "tcp");
973         addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "tcp");
974
975         timers[0] = '\0';
976         if (flag_opt)
977             switch (timer_run) {
978             case 0:
979                 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
980                 break;
981
982             case 1:
983                 snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
984                          (double) time_len / HZ, retr, timeout);
985                 break;
986
987             case 2:
988                 snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
989                          (double) time_len / HZ, retr, timeout);
990                 break;
991
992             case 3:
993                 snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
994                          (double) time_len / HZ, retr, timeout);
995                 break;
996
997             default:
998                 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
999                          timer_run, (double) time_len / HZ, retr, timeout);
1000                 break;
1001             }
1002
1003         printf("%-4s  %6ld %6ld %-*s %-*s %-11s",
1004                prot, rxq, txq, (int)netmax(23,strlen(local_addr)), local_addr, (int)netmax(23,strlen(rem_addr)), rem_addr, _(tcp_state[state]));
1005
1006         finish_this_one(uid,inode,timers);
1007 }
1008
1009 static int tcp_info(void)
1010 {
1011     INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
1012                tcp_do_one, "tcp", "tcp6");
1013 }
1014
1015 static void udp_do_one(int lnr, const char *line,const char *prot)
1016 {
1017     char local_addr[64], rem_addr[64];
1018     char *udp_state, timers[64], more[512];
1019     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
1020 #if HAVE_AFINET6
1021     struct sockaddr_in6 localaddr, remaddr;
1022     char addr6[INET6_ADDRSTRLEN];
1023     struct in6_addr in6;
1024     extern struct aftype inet6_aftype;
1025 #else
1026     struct sockaddr_in localaddr, remaddr;
1027 #endif
1028     struct aftype *ap;
1029     unsigned long rxq, txq, time_len, retr, inode;
1030
1031     if (lnr == 0)
1032         return;
1033
1034     more[0] = '\0';
1035     num = sscanf(line,
1036                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %511s\n",
1037                  &d, local_addr, &local_port,
1038                  rem_addr, &rem_port, &state,
1039           &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
1040
1041     if (strlen(local_addr) > 8) {
1042 #if HAVE_AFINET6
1043         sscanf(local_addr, "%08X%08X%08X%08X",
1044                &in6.s6_addr32[0], &in6.s6_addr32[1],
1045                &in6.s6_addr32[2], &in6.s6_addr32[3]);
1046         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1047         inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
1048         sscanf(rem_addr, "%08X%08X%08X%08X",
1049                &in6.s6_addr32[0], &in6.s6_addr32[1],
1050                &in6.s6_addr32[2], &in6.s6_addr32[3]);
1051         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1052         inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
1053         localaddr.sin6_family = AF_INET6;
1054         remaddr.sin6_family = AF_INET6;
1055 #endif
1056     } else {
1057         sscanf(local_addr, "%X",
1058                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1059         sscanf(rem_addr, "%X",
1060                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1061         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1062         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1063     }
1064
1065     retr = 0L;
1066     if (!flag_opt)
1067         more[0] = '\0';
1068
1069     if (num < 10) {
1070         fprintf(stderr, _("warning, got bogus udp line.\n"));
1071         return;
1072     }
1073     if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
1074         fprintf(stderr, _("netstat: unsupported address family %d !\n"),
1075                 ((struct sockaddr *) &localaddr)->sa_family);
1076         return;
1077     }
1078     switch (state) {
1079     case TCP_ESTABLISHED:
1080         udp_state = _("ESTABLISHED");
1081         break;
1082
1083     case TCP_CLOSE:
1084         udp_state = "";
1085         break;
1086
1087     default:
1088         udp_state = _("UNKNOWN");
1089         break;
1090     }
1091
1092 #if HAVE_AFINET6
1093 #define notnull(A) (((A.sin6_family == AF_INET6) && \
1094          ((A.sin6_addr.s6_addr32[0]) ||            \
1095           (A.sin6_addr.s6_addr32[1]) ||            \
1096           (A.sin6_addr.s6_addr32[2]) ||            \
1097           (A.sin6_addr.s6_addr32[3]))) ||          \
1098         ((A.sin6_family == AF_INET) &&             \
1099          ((struct sockaddr_in *) &A)->sin_addr.s_addr))
1100 #else
1101 #define notnull(A) (A.sin_addr.s_addr)
1102 #endif
1103
1104     if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1105     {
1106         addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "udp");
1107         addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "udp");
1108
1109         timers[0] = '\0';
1110         if (flag_opt)
1111             switch (timer_run) {
1112             case 0:
1113                 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1114                 break;
1115
1116             case 1:
1117             case 2:
1118                 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
1119                 break;
1120
1121             default:
1122                 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1123                          retr, timeout);
1124                 break;
1125             }
1126         printf("%-5s %6ld %6ld %-23s %-23s %-11s",
1127                prot, rxq, txq, local_addr, rem_addr, udp_state);
1128
1129         finish_this_one(uid,inode,timers);
1130     }
1131 }
1132
1133 static int udp_info(void)
1134 {
1135     INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
1136                udp_do_one, "udp", "udp6");
1137 }
1138
1139 static int udplite_info(void)
1140 {
1141     INFO_GUTS6(_PATH_PROCNET_UDPLITE, _PATH_PROCNET_UDPLITE6, 
1142                "AF INET (udplite)", udp_do_one, "udpl", "udpl6" );
1143 }
1144
1145 static void raw_do_one(int lnr, const char *line,const char *prot)
1146 {
1147     char local_addr[64], rem_addr[64];
1148     char timers[64], more[512];
1149     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
1150 #if HAVE_AFINET6
1151     struct sockaddr_in6 localaddr, remaddr;
1152     char addr6[INET6_ADDRSTRLEN];
1153     struct in6_addr in6;
1154     extern struct aftype inet6_aftype;
1155 #else
1156     struct sockaddr_in localaddr, remaddr;
1157 #endif
1158     struct aftype *ap;
1159     unsigned long rxq, txq, time_len, retr, inode;
1160
1161     if (lnr == 0)
1162         return;
1163
1164     more[0] = '\0';
1165     num = sscanf(line,
1166                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %511s\n",
1167                  &d, local_addr, &local_port, rem_addr, &rem_port, &state,
1168           &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
1169
1170     if (strlen(local_addr) > 8) {
1171 #if HAVE_AFINET6
1172         sscanf(local_addr, "%08X%08X%08X%08X",
1173                &in6.s6_addr32[0], &in6.s6_addr32[1],
1174            &in6.s6_addr32[2], &in6.s6_addr32[3]);
1175     inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1176         inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
1177         sscanf(rem_addr, "%08X%08X%08X%08X",
1178                &in6.s6_addr32[0], &in6.s6_addr32[1],
1179            &in6.s6_addr32[2], &in6.s6_addr32[3]);
1180     inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1181         inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
1182         localaddr.sin6_family = AF_INET6;
1183         remaddr.sin6_family = AF_INET6;
1184 #endif
1185     } else {
1186         sscanf(local_addr, "%X",
1187                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1188         sscanf(rem_addr, "%X",
1189                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1190         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1191         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1192     }
1193 #if HAVE_AFINET6
1194     if ((ap = get_afntype(localaddr.sin6_family)) == NULL) {
1195         fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin6_family);
1196         return;
1197     }
1198 #else
1199     if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
1200         fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin_family);
1201         return;
1202     }
1203 #endif
1204
1205     if (!flag_opt)
1206         more[0] = '\0';
1207
1208     if (num < 10) {
1209         fprintf(stderr, _("warning, got bogus raw line.\n"));
1210         return;
1211     }
1212
1213     if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1214     {
1215         addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "raw");
1216         addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "raw");
1217
1218         timers[0] = '\0';
1219         if (flag_opt)
1220             switch (timer_run) {
1221             case 0:
1222                 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1223                 break;
1224
1225             case 1:
1226             case 2:
1227                 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1228                          retr, timeout);
1229                 break;
1230
1231             default:
1232                 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
1233                          timer_run, (double) time_len / 100,
1234                          retr, timeout);
1235                 break;
1236             }
1237         printf("%-4s  %6ld %6ld %-23s %-23s %-11d",
1238                prot, rxq, txq, local_addr, rem_addr, state);
1239
1240         finish_this_one(uid,inode,timers);
1241     }
1242 }
1243
1244 static int raw_info(void)
1245 {
1246     INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
1247                raw_do_one, "raw", "raw6");
1248 }
1249
1250 #endif
1251
1252
1253 #if HAVE_AFUNIX
1254
1255 #define HAS_INODE 1
1256
1257 static void unix_do_one(int nr, const char *line, const char *prot)
1258 {
1259     static int has = 0;
1260     char path[MAXPATHLEN], ss_flags[32];
1261     char *ss_proto, *ss_state, *ss_type;
1262     int num, state, type;
1263     void *d;
1264     unsigned long refcnt, proto, flags, inode;
1265
1266     if (nr == 0) {
1267         if (strstr(line, "Inode"))
1268             has |= HAS_INODE;
1269         return;
1270     }
1271     path[0] = '\0';
1272     num = sscanf(line, "%p: %lX %lX %lX %X %X %lu %s",
1273                  &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
1274     if (num < 6) {
1275         fprintf(stderr, _("warning, got bogus unix line.\n"));
1276         return;
1277     }
1278     if (!(has & HAS_INODE))
1279         snprintf(path,sizeof(path),"%lu",inode);
1280
1281     if (!flag_all) {
1282         if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
1283                 if (!flag_lst)
1284                         return;
1285         } else {
1286                 if (flag_lst)
1287                         return;
1288         }
1289     }
1290
1291     switch (proto) {
1292     case 0:
1293         ss_proto = "unix";
1294         break;
1295
1296     default:
1297         ss_proto = "??";
1298     }
1299
1300     switch (type) {
1301     case SOCK_STREAM:
1302         ss_type = _("STREAM");
1303         break;
1304
1305     case SOCK_DGRAM:
1306         ss_type = _("DGRAM");
1307         break;
1308
1309     case SOCK_RAW:
1310         ss_type = _("RAW");
1311         break;
1312
1313     case SOCK_RDM:
1314         ss_type = _("RDM");
1315         break;
1316
1317     case SOCK_SEQPACKET:
1318         ss_type = _("SEQPACKET");
1319         break;
1320
1321     default:
1322         ss_type = _("UNKNOWN");
1323     }
1324
1325     switch (state) {
1326     case SS_FREE:
1327         ss_state = _("FREE");
1328         break;
1329
1330     case SS_UNCONNECTED:
1331         /*
1332          * Unconnected sockets may be listening
1333          * for something.
1334          */
1335         if (flags & SO_ACCEPTCON) {
1336             ss_state = _("LISTENING");
1337         } else {
1338             ss_state = "";
1339         }
1340         break;
1341
1342     case SS_CONNECTING:
1343         ss_state = _("CONNECTING");
1344         break;
1345
1346     case SS_CONNECTED:
1347         ss_state = _("CONNECTED");
1348         break;
1349
1350     case SS_DISCONNECTING:
1351         ss_state = _("DISCONNECTING");
1352         break;
1353
1354     default:
1355         ss_state = _("UNKNOWN");
1356     }
1357
1358     strcpy(ss_flags, "[ ");
1359     if (flags & SO_ACCEPTCON)
1360         strcat(ss_flags, "ACC ");
1361     if (flags & SO_WAITDATA)
1362         strcat(ss_flags, "W ");
1363     if (flags & SO_NOSPACE)
1364         strcat(ss_flags, "N ");
1365
1366     strcat(ss_flags, "]");
1367
1368     printf("%-5s %-6ld %-11s %-10s %-13s ",
1369            ss_proto, refcnt, ss_flags, ss_type, ss_state);
1370     if (has & HAS_INODE)
1371         printf("%-8lu",inode);
1372     else
1373         printf("-       ");
1374     if (flag_prg)
1375         printf(" %-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
1376         
1377     printf(" %s\n", path);
1378 }
1379
1380 static int unix_info(void)
1381 {
1382
1383     printf(_("Active UNIX domain sockets "));
1384     if (flag_all)
1385         printf(_("(servers and established)"));
1386     else {
1387       if (flag_lst)
1388         printf(_("(only servers)"));
1389       else
1390         printf(_("(w/o servers)"));
1391     }
1392
1393     printf(_("\nProto RefCnt Flags       Type       State         I-Node  "));
1394     print_progname_banner();
1395     printf(_(" Path\n"));       /* xxx */
1396
1397     {
1398         INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one, "unix");
1399     }
1400 }
1401 #endif
1402
1403
1404 #if HAVE_AFAX25
1405 static int ax25_info(void)
1406 {
1407     FILE *f;
1408     char buffer[256], buf[16];
1409     char *src, *dst, *dev, *p;
1410     int st, vs, vr, sendq, recvq, ret;
1411     int new = -1;               /* flag for new (2.1.x) kernels */
1412     static char *ax25_state[5] =
1413     {
1414         N_("LISTENING"),
1415         N_("SABM SENT"),
1416         N_("DISC SENT"),
1417         N_("ESTABLISHED"),
1418         N_("RECOVERY")
1419     };
1420     if (!(f = proc_fopen(_PATH_PROCNET_AX25))) {
1421         if (errno != ENOENT) {
1422             perror(_PATH_PROCNET_AX25);
1423             return (-1);
1424         }
1425         if (flag_arg || flag_ver)
1426             ESYSNOT("netstat", "AF AX25");
1427         if (flag_arg)
1428             return (1);
1429         else
1430             return (0);
1431     }
1432     printf(_("Active AX.25 sockets\n"));
1433     printf(_("Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q\n"));
1434     while (fgets(buffer, 256, f)) {
1435         if (new == -1) {
1436             if (!strncmp(buffer, "dest_addr", 9)) {
1437                 new = 0;
1438                 continue;       /* old kernels have a header line */
1439             } else
1440                 new = 1;
1441         }
1442         /*
1443          * In a network connection with no user socket the Snd-Q, Rcv-Q
1444          * and Inode fields are empty in 2.0.x and '*' in 2.1.x
1445          */
1446         sendq = 0;
1447         recvq = 0;
1448         if (new == 0) {
1449             dst = buffer;
1450             src = buffer + 10;
1451             dst[9] = 0;
1452             src[9] = 0;
1453             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",
1454                    buf, &st, &vs, &vr, &sendq, &recvq);
1455             if (ret != 4 && ret != 6) {
1456                 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
1457                 continue;
1458             }
1459             dev = buf;
1460         } else {
1461             p = buffer;
1462             while (*p != ' ') p++;
1463             p++;
1464             dev = p;
1465             while (*p != ' ') p++;
1466             *p++ = 0;
1467             src = p;
1468             while (*p != ' ') p++;
1469             *p++ = 0;
1470             dst = p;
1471             while (*p != ' ') p++;
1472             *p++ = 0;
1473             ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
1474                    &st, &vs, &vr, &sendq, &recvq);
1475             if (ret != 3 && ret != 5) {
1476                     printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
1477                     continue;
1478             }
1479             /*
1480              * FIXME: digipeaters should be handled somehow.
1481              * For now we just strip them.
1482              */
1483             p = dst;
1484             while (*p && *p != ',') p++;
1485             *p = 0;
1486         }
1487         printf("%-9s  %-9s  %-6s  %-11s  %03d/%03d  %-6d  %-6d\n",
1488                dst, src,
1489                dev,
1490                _(ax25_state[st]),
1491                vr, vs, sendq, recvq);
1492     }
1493     fclose(f);
1494     return 0;
1495 }
1496 #endif
1497
1498
1499 #if HAVE_AFIPX
1500 static int ipx_info(void)
1501 {
1502     FILE *f;
1503     char buf[256];
1504     unsigned long txq, rxq;
1505     unsigned int state;
1506     unsigned int uid;
1507     char *st;
1508     int nc;
1509     struct aftype *ap;
1510     struct passwd *pw;
1511     char sad[50], dad[50];
1512     struct sockaddr sa;
1513     unsigned sport = 0, dport = 0;
1514     struct stat s;
1515     
1516     f = proc_fopen(_PATH_PROCNET_IPX_SOCKET1);
1517     if (!f) {
1518         if (errno != ENOENT) {
1519             perror(_PATH_PROCNET_IPX_SOCKET1);
1520             return (-1);
1521         }
1522         f = proc_fopen(_PATH_PROCNET_IPX_SOCKET2);
1523
1524         /* We need to check for directory */
1525         if (f) {
1526             fstat(fileno(f), &s);
1527             if (!S_ISREG(s.st_mode)) {
1528                 fclose(f);
1529                 f=NULL;
1530             }
1531         }
1532
1533         if (!f) {
1534             if (errno != ENOENT) {
1535                 perror(_PATH_PROCNET_IPX_SOCKET2);
1536                 return (-1);
1537             }
1538             if (flag_arg || flag_ver)
1539                 ESYSNOT("netstat", "AF IPX");
1540             if (flag_arg)
1541                 return (1);
1542             else
1543                 return (0);
1544         }
1545     }
1546     printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address              Foreign Address            State"));   /* xxx */
1547     if (flag_exp > 1)
1548         printf(_(" User"));     /* xxx */
1549     printf("\n");
1550     if ((ap = get_afntype(AF_IPX)) == NULL) {
1551         EINTERN("netstat.c", "AF_IPX missing");
1552         fclose(f);
1553         return (-1);
1554     }
1555     if (fgets(buf, 255, f))
1556         /* eat line */;
1557
1558     while (fgets(buf, 255, f) != NULL) {
1559         sscanf(buf, "%s %s %lX %lX %d %d",
1560                sad, dad, &txq, &rxq, &state, &uid);
1561         if ((st = rindex(sad, ':'))) {
1562             *st++ = '\0';
1563             sscanf(st, "%X", &sport);   /* net byt order */
1564             sport = ntohs(sport);
1565         } else {
1566             EINTERN("netstat.c", "ipx socket format error in source port");
1567             fclose(f);
1568             return (-1);
1569         }
1570         nc = 0;
1571         if (strcmp(dad, "Not_Connected") != 0) {
1572             if ((st = rindex(dad, ':'))) {
1573                 *st++ = '\0';
1574                 sscanf(st, "%X", &dport);       /* net byt order */
1575                 dport = ntohs(dport);
1576             } else {
1577                 EINTERN("netstat.c", "ipx soket format error in destination port");
1578                 fclose(f);
1579                 return (-1);
1580             }
1581         } else
1582             nc = 1;
1583
1584         switch (state) {
1585         case TCP_ESTABLISHED:
1586             st = _("ESTAB");
1587             break;
1588
1589         case TCP_CLOSE:
1590             st = "";
1591             break;
1592
1593         default:
1594             st = _("UNK.");
1595             break;
1596         }
1597
1598         /* Fetch and resolve the Source */
1599         (void) ap->input(4, sad, &sa);
1600         safe_strncpy(buf, ap->sprint(&sa, flag_not & FLAG_NUM_HOST), sizeof(buf));
1601         snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
1602
1603         if (!nc) {
1604             /* Fetch and resolve the Destination */
1605             (void) ap->input(4, dad, &sa);
1606             safe_strncpy(buf, ap->sprint(&sa, flag_not & FLAG_NUM_HOST), sizeof(buf));
1607             snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
1608         } else
1609             strcpy(dad, "-");
1610
1611         printf("IPX   %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
1612         if (flag_exp > 1) {
1613             if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
1614                 printf(" %-10s", pw->pw_name);
1615             else
1616                 printf(" %-10d", uid);
1617         }
1618         printf("\n");
1619     }
1620     fclose(f);
1621     return 0;
1622 }
1623 #endif
1624
1625 #if HAVE_AFBLUETOOTH
1626 const char *bluetooth_state(int state)
1627 {
1628     switch (state) {
1629         case BT_CONNECTED:
1630             return _("CONNECTED");
1631         case BT_OPEN:
1632             return _("OPEN");
1633         case BT_BOUND:
1634             return _("BOUND");
1635         case BT_LISTEN:
1636             return _("LISTEN");
1637         case BT_CONNECT:
1638             return _("CONNECT");
1639         case BT_CONNECT2:
1640             return _("CONNECT2");
1641         case BT_CONFIG:
1642             return _("CONFIG");
1643         case BT_DISCONN:
1644             return _("DISCONN");
1645         case BT_CLOSED:
1646             return _("CLOSED");
1647         default:
1648             return _("UNKNOWN");
1649     }
1650 }
1651
1652 static void l2cap_do_one(int nr, const char *line, const char *prot)
1653 {
1654     char daddr[18], saddr[18];
1655     unsigned state, psm, dcid, scid, imtu, omtu, sec_level;
1656     int num;
1657     const char *bt_state, *bt_sec_level;
1658
1659     num = sscanf(line, "%17s %17s %d %d 0x%04x 0x%04x %d %d %d",
1660         daddr, saddr, &state, &psm, &dcid, &scid, &imtu, &omtu, &sec_level);
1661
1662     if (num < 9) {
1663         fprintf(stderr, _("warning, got bogus l2cap line.\n"));
1664         return;
1665     }
1666
1667     if (flag_lst && !(state == BT_LISTEN || state == BT_BOUND))
1668         return;
1669     if (!(flag_all || flag_lst) && (state == BT_LISTEN || state == BT_BOUND))
1670         return;
1671
1672     bt_state = bluetooth_state(state);
1673     switch (sec_level) {
1674         case BT_SECURITY_SDP:
1675             bt_sec_level = _("SDP");
1676             break;
1677         case BT_SECURITY_LOW:
1678             bt_sec_level = _("LOW");
1679             break;
1680         case BT_SECURITY_MEDIUM:
1681             bt_sec_level = _("MEDIUM");
1682             break;
1683         case BT_SECURITY_HIGH:
1684             bt_sec_level = _("HIGH");
1685             break;
1686         default:
1687             bt_sec_level = _("UNKNOWN");
1688     }
1689
1690     printf("l2cap  %-17s %-17s %-9s %7d 0x%04x 0x%04x %7d %7d %-7s\n",
1691         (strcmp (daddr, "00:00:00:00:00:00") == 0 ? "*" : daddr),
1692         (strcmp (saddr, "00:00:00:00:00:00") == 0 ? "*" : saddr),
1693         bt_state, psm, dcid, scid, imtu, omtu, bt_sec_level);
1694 }
1695
1696 static int l2cap_info(void)
1697 {
1698     printf("%-6s %-17s %-17s %-9s %7s %-6s %-6s %7s %7s %-7s\n",
1699         "Proto", "Destination", "Source", "State", "PSM", "DCID", "SCID", "IMTU", "OMTU", "Security");
1700     INFO_GUTS(_PATH_SYS_BLUETOOTH_L2CAP, "AF BLUETOOTH", l2cap_do_one, "l2cap");
1701 }
1702
1703 static void rfcomm_do_one(int nr, const char *line, const char *prot)
1704 {
1705     char daddr[18], saddr[18];
1706     unsigned state, channel;
1707     int num;
1708     const char *bt_state;
1709
1710     num = sscanf(line, "%17s %17s %d %d", daddr, saddr, &state, &channel);
1711     if (num < 4) {
1712         fprintf(stderr, _("warning, got bogus rfcomm line.\n"));
1713         return;
1714     }
1715
1716     if (flag_lst && !(state == BT_LISTEN || state == BT_BOUND))
1717         return;
1718     if (!(flag_all || flag_lst) && (state == BT_LISTEN || state == BT_BOUND))
1719         return;
1720
1721     bt_state = bluetooth_state(state);
1722     printf("rfcomm %-17s %-17s %-9s %7d\n",
1723         (strcmp (daddr, "00:00:00:00:00:00") == 0 ? "*" : daddr),
1724         (strcmp (saddr, "00:00:00:00:00:00") == 0 ? "*" : saddr),
1725         bt_state, channel);
1726 }
1727
1728 static int rfcomm_info(void)
1729 {
1730     printf("%-6s %-17s %-17s %-9s %7s\n", "Proto", "Destination", "Source", "State", "Channel");
1731     INFO_GUTS(_PATH_SYS_BLUETOOTH_RFCOMM, "AF BLUETOOTH", rfcomm_do_one, "rfcomm");
1732 }
1733 #endif
1734
1735 static int iface_info(void)
1736 {
1737     if (skfd < 0) {
1738         if ((skfd = sockets_open(0)) < 0) {
1739             perror("socket");
1740             exit(1);
1741         }
1742         printf(_("Kernel Interface table\n"));
1743     }
1744     if (flag_exp < 2) {
1745         ife_short = 1;
1746         printf(_("Iface   MTU Met   RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
1747     }
1748
1749     if (for_all_interfaces(do_if_print, &flag_all) < 0) {
1750         perror(_("missing interface information"));
1751         exit(1);
1752     }
1753     if (flag_cnt)
1754         if_cache_free();
1755     else {
1756         close(skfd);
1757         skfd = -1;
1758     }
1759
1760     return 0;
1761 }
1762
1763
1764 static void version(void)
1765 {
1766     printf("%s\n%s\n%s\n%s\n", Release, Version, Signature, Features);
1767     exit(E_VERSION);
1768 }
1769
1770
1771 static void usage(void)
1772 {
1773     fprintf(stderr, _("usage: netstat [-vWeenNcCF] [<Af>] -r         netstat {-V|--version|-h|--help}\n"));
1774     fprintf(stderr, _("       netstat [-vWnNcaeol] [<Socket> ...]\n"));
1775     fprintf(stderr, _("       netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }\n\n"));
1776
1777     fprintf(stderr, _("        -r, --route              display routing table\n"));
1778     fprintf(stderr, _("        -i, --interfaces         display interface table\n"));
1779     fprintf(stderr, _("        -g, --groups             display multicast group memberships\n"));
1780     fprintf(stderr, _("        -s, --statistics         display networking statistics (like SNMP)\n"));
1781 #if HAVE_FW_MASQUERADE
1782     fprintf(stderr, _("        -M, --masquerade         display masqueraded connections\n\n"));
1783 #endif
1784     fprintf(stderr, _("        -v, --verbose            be verbose\n"));
1785     fprintf(stderr, _("        -W, --wide               don't truncate IP addresses\n"));
1786     fprintf(stderr, _("        -n, --numeric            don't resolve names\n"));
1787     fprintf(stderr, _("        --numeric-hosts          don't resolve host names\n"));
1788     fprintf(stderr, _("        --numeric-ports          don't resolve port names\n"));
1789     fprintf(stderr, _("        --numeric-users          don't resolve user names\n"));
1790     fprintf(stderr, _("        -N, --symbolic           resolve hardware names\n"));
1791     fprintf(stderr, _("        -e, --extend             display other/more information\n"));
1792     fprintf(stderr, _("        -p, --programs           display PID/Program name for sockets\n"));
1793     fprintf(stderr, _("        -c, --continuous         continuous listing\n\n"));
1794     fprintf(stderr, _("        -l, --listening          display listening server sockets\n"));
1795     fprintf(stderr, _("        -a, --all, --listening   display all sockets (default: connected)\n"));
1796     fprintf(stderr, _("        -o, --timers             display timers\n"));
1797     fprintf(stderr, _("        -F, --fib                display Forwarding Information Base (default)\n"));
1798     fprintf(stderr, _("        -C, --cache              display routing cache instead of FIB\n\n"));
1799
1800     fprintf(stderr, _("  <Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
1801     fprintf(stderr, _("  <AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: %s\n"), DFLT_AF);
1802     fprintf(stderr, _("  List of possible address families (which support routing):\n"));
1803     print_aflist(1); /* 1 = routeable */
1804     exit(E_USAGE);
1805 }
1806
1807
1808 int main
1809  (int argc, char *argv[]) {
1810     int i;
1811     int lop;
1812     static struct option longopts[] =
1813     {
1814         AFTRANS_OPTS,
1815         {"version", 0, 0, 'V'},
1816         {"interfaces", 0, 0, 'i'},
1817         {"help", 0, 0, 'h'},
1818         {"route", 0, 0, 'r'},
1819 #if HAVE_FW_MASQUERADE
1820         {"masquerade", 0, 0, 'M'},
1821 #endif
1822         {"protocol", 1, 0, 'A'},
1823         {"tcp", 0, 0, 't'},
1824         {"sctp", 0, 0, 'S'},
1825         {"udp", 0, 0, 'u'},
1826         {"udplite", 0, 0, 'U'},
1827         {"raw", 0, 0, 'w'},
1828         {"unix", 0, 0, 'x'},
1829         {"l2cap", 0, 0, '2'},
1830         {"rfcomm", 0, 0, 'f'},
1831         {"listening", 0, 0, 'l'},
1832         {"all", 0, 0, 'a'},
1833         {"timers", 0, 0, 'o'},
1834         {"continuous", 0, 0, 'c'},
1835         {"extend", 0, 0, 'e'},
1836         {"programs", 0, 0, 'p'},
1837         {"verbose", 0, 0, 'v'},
1838         {"statistics", 0, 0, 's'},
1839         {"wide", 0, 0, 'W'},
1840         {"numeric", 0, 0, 'n'},
1841         {"numeric-hosts", 0, 0, '!'},
1842         {"numeric-ports", 0, 0, '@'},
1843         {"numeric-users", 0, 0, '#'},
1844         {"symbolic", 0, 0, 'N'},
1845         {"cache", 0, 0, 'C'},
1846         {"fib", 0, 0, 'F'},
1847         {"groups", 0, 0, 'g'},
1848         {NULL, 0, 0, 0}
1849     };
1850
1851 #if I18N
1852     setlocale (LC_ALL, "");
1853     bindtextdomain("net-tools", "/usr/share/locale");
1854     textdomain("net-tools");
1855 #endif
1856     getroute_init();            /* Set up AF routing support */
1857
1858     afname[0] = '\0';
1859     while ((i = getopt_long(argc, argv, "A:CFMacdeghilnNoprsStuUvVWwx64?", longopts, &lop)) != EOF)
1860         switch (i) {
1861         case -1:
1862             break;
1863         case 1:
1864             if (lop < 0 || lop >= AFTRANS_CNT) {
1865                 EINTERN("netstat.c", "longopts 1 range");
1866                 break;
1867             }
1868             if (aftrans_opt(longopts[lop].name))
1869                 exit(1);
1870             break;
1871         case 'A':
1872             if (aftrans_opt(optarg))
1873                 exit(1);
1874             break;
1875         case 'M':
1876             flag_mas++;
1877             break;
1878         case 'a':
1879             flag_all++;
1880             break;
1881         case 'l':
1882             flag_lst++;
1883             break;
1884         case 'c':
1885             flag_cnt++;
1886             break;
1887
1888         case 'd':
1889             flag_deb++;
1890             break;
1891         case 'g':
1892             flag_igmp++;
1893             break;
1894         case 'e':
1895             flag_exp++;
1896             break;
1897         case 'p':
1898             flag_prg++;
1899             break;
1900         case 'i':
1901             flag_int++;
1902             break;
1903         case 'W':
1904             flag_wide++;
1905             break;
1906         case 'n':
1907             flag_not |= FLAG_NUM;
1908             break;
1909         case '!':
1910             flag_not |= FLAG_NUM_HOST;
1911             break;
1912         case '@':
1913             flag_not |= FLAG_NUM_PORT;
1914             break;
1915         case '#':
1916             flag_not |= FLAG_NUM_USER;
1917             break;
1918         case 'N':
1919             flag_not |= FLAG_SYM;
1920             break;
1921         case 'C':
1922             flag_cf |= FLAG_CACHE;
1923             break;
1924         case 'F':
1925             flag_cf |= FLAG_FIB;
1926             break;
1927         case 'o':
1928             flag_opt++;
1929             break;
1930         case '6':
1931             if (aftrans_opt("inet6"))
1932                 exit(1);
1933             break;
1934         case '4':
1935             if (aftrans_opt("inet"))
1936                 exit(1);
1937             break;
1938         case 'V':
1939             version();
1940             /*NOTREACHED */
1941         case 'v':
1942             flag_ver |= FLAG_VERBOSE;
1943             break;
1944         case 'r':
1945             flag_rou++;
1946             break;
1947         case 't':
1948             flag_tcp++;
1949             break;
1950         case 'S':
1951             flag_sctp++;
1952             break;
1953         case 'u':
1954             flag_udp++;
1955             break;
1956         case 'U':
1957             flag_udplite++;
1958             break;
1959         case 'w':
1960             flag_raw++;
1961             break;
1962         case '2':
1963             flag_l2cap++;
1964             break;
1965         case 'f':
1966             flag_rfcomm++;
1967             break;
1968         case 'x':
1969             if (aftrans_opt("unix"))
1970                 exit(1);
1971             break;
1972         case '?':
1973         case 'h':
1974             usage();
1975         case 's':
1976             flag_sta++;
1977         }
1978
1979     if (flag_int + flag_rou + flag_mas + flag_sta > 1)
1980         usage();
1981
1982     if ((flag_inet || flag_inet6 || flag_sta) && 
1983         !(flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw))
1984            flag_tcp = flag_sctp = flag_udp = flag_udplite = flag_raw = 1;
1985
1986     if ((flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw || flag_igmp) && 
1987         !(flag_inet || flag_inet6))
1988         flag_inet = flag_inet6 = 1;
1989
1990     if (flag_bluetooth && !(flag_l2cap || flag_rfcomm))
1991            flag_l2cap = flag_rfcomm = 1;
1992
1993     flag_arg = flag_tcp + flag_sctp + flag_udplite + flag_udp + flag_raw + flag_unx 
1994         + flag_ipx + flag_ax25 + flag_netrom + flag_igmp + flag_x25 + flag_rose
1995         + flag_l2cap + flag_rfcomm;
1996
1997     if (flag_mas) {
1998 #if HAVE_FW_MASQUERADE && HAVE_AFINET
1999 #if MORE_THAN_ONE_MASQ_AF
2000         if (!afname[0])
2001             strcpy(afname, DFLT_AF);
2002 #endif
2003         for (;;) {
2004             i = ip_masq_info(flag_not & FLAG_NUM_HOST,
2005                              flag_not & FLAG_NUM_PORT, flag_exp);
2006             if (i || !flag_cnt)
2007                 break;
2008             wait_continous();
2009         }
2010 #else
2011         ENOSUPP("netstat", "FW_MASQUERADE");
2012         i = -1;
2013 #endif
2014         return (i);
2015     }
2016
2017     if (flag_sta) {
2018         if (!afname[0])
2019             strcpy(afname, DFLT_AF);
2020             
2021         if (!strcmp(afname, "inet")) {
2022 #if HAVE_AFINET
2023             inittab();
2024             parsesnmp(flag_raw, flag_tcp, flag_udp);
2025 #else
2026             ENOSUPP("netstat", "AF INET");
2027 #endif
2028         } else if(!strcmp(afname, "inet6")) {
2029 #if HAVE_AFINET6
2030             inittab6();
2031             parsesnmp6(flag_raw, flag_tcp, flag_udp);
2032 #else
2033             ENOSUPP("netstat", "AF INET6");
2034 #endif
2035         } else {
2036           printf(_("netstat: No statistics support for specified address family: %s\n"), afname);
2037           exit(1);
2038         }
2039         exit(0);
2040     }
2041     
2042     if (flag_rou) {
2043         int options = 0;
2044
2045         if (!afname[0])
2046             strcpy(afname, DFLT_AF);
2047
2048         if (flag_exp == 2)
2049             flag_exp = 1;
2050         else if (flag_exp == 1)
2051             flag_exp = 2;
2052
2053         options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
2054         if (!flag_cf)
2055             options |= FLAG_FIB;
2056
2057         for (;;) {
2058             i = route_info(afname, options);
2059             if (i || !flag_cnt)
2060                 break;
2061             wait_continous();
2062         }
2063         return (i);
2064     }
2065     if (flag_int) {
2066         for (;;) {
2067             i = iface_info();
2068             if (!flag_cnt || i)
2069                 break;
2070             wait_continous();
2071         }
2072         return (i);
2073     }
2074     for (;;) {
2075         if (!flag_arg || flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw) {
2076 #if HAVE_AFINET
2077             prg_cache_load();
2078             printf(_("Active Internet connections "));  /* xxx */
2079
2080             if (flag_all)
2081                 printf(_("(servers and established)"));
2082             else {
2083               if (flag_lst)
2084                 printf(_("(only servers)"));
2085               else
2086                 printf(_("(w/o servers)"));
2087             }
2088             printf(_("\nProto Recv-Q Send-Q Local Address           Foreign Address         State      "));     /* xxx */
2089             if (flag_exp > 1)
2090                 printf(_(" User       Inode     "));
2091             print_progname_banner();
2092             if (flag_opt)
2093                 printf(_(" Timer"));    /* xxx */
2094             printf("\n");
2095 #else
2096             if (flag_arg) {
2097                 i = 1;
2098                 ENOSUPP("netstat", "AF INET");
2099             }
2100 #endif
2101         }
2102 #if HAVE_AFINET
2103         if (!flag_arg || flag_tcp) {
2104             i = tcp_info();
2105             if (i)
2106                 return (i);
2107         }
2108
2109         if (!flag_arg || flag_sctp) {
2110             i = sctp_info();
2111             if (i)
2112                 return (i);
2113         }
2114
2115         if (!flag_arg || flag_udp) {
2116             i = udp_info();
2117             if (i)
2118                 return (i);
2119         }
2120
2121         if (!flag_arg || flag_udplite) {
2122             i = udplite_info();
2123             if (i)
2124                 return (i);
2125         }
2126
2127         if (!flag_arg || flag_raw) {
2128             i = raw_info();
2129             if (i)
2130                 return (i);
2131         }
2132
2133         if (flag_igmp) {
2134 #if HAVE_AFINET6
2135             printf( "IPv6/");
2136 #endif
2137             printf( _("IPv4 Group Memberships\n") );
2138             printf( _("Interface       RefCnt Group\n") );
2139             printf( "--------------- ------ ---------------------\n" );
2140             i = igmp_info();
2141             if (i)
2142                 return (i);
2143         }
2144 #endif
2145
2146         if (!flag_arg || flag_unx) {
2147 #if HAVE_AFUNIX
2148             prg_cache_load();
2149             i = unix_info();
2150             if (i)
2151                 return (i);
2152 #else
2153             if (flag_arg) {
2154                 i = 1;
2155                 ENOSUPP("netstat", "AF UNIX");
2156             }
2157 #endif
2158         }
2159         if (!flag_arg || flag_ipx) {
2160 #if HAVE_AFIPX
2161             i = ipx_info();
2162             if (i)
2163                 return (i);
2164 #else
2165             if (flag_arg) {
2166                 i = 1;
2167                 ENOSUPP("netstat", "AF IPX");
2168             }
2169 #endif
2170         }
2171         if (!flag_arg || flag_ax25) {
2172 #if HAVE_AFAX25
2173             i = ax25_info();
2174             if (i)
2175                 return (i);
2176 #else
2177             if (flag_arg) {
2178                 i = 1;
2179                 ENOSUPP("netstat", "AF AX25");
2180             }
2181 #endif
2182         }
2183         if(!flag_arg || flag_x25) {
2184 #if HAVE_AFX25
2185             /* FIXME */
2186             i = x25_info();
2187             if (i)
2188                 return(i);
2189 #else
2190             if (flag_arg) {
2191                 i = 1;
2192                 ENOSUPP("netstat", "AF X25");
2193             }
2194 #endif
2195         }
2196         if (!flag_arg || flag_netrom) {
2197 #if HAVE_AFNETROM
2198             i = netrom_info();
2199             if (i)
2200                 return (i);
2201 #else
2202             if (flag_arg) {
2203                 i = 1;
2204                 ENOSUPP("netstat", "AF NETROM");
2205             }
2206 #endif
2207         }
2208         if (!flag_arg || flag_rose) {
2209 #if 0 && HAVE_AFROSE
2210           i = rose_info();
2211           if (i)
2212             return (i);
2213 #else
2214           if (flag_arg) {
2215             i = 1;
2216             ENOSUPP("netstat", "AF ROSE");
2217           }
2218 #endif
2219         }
2220
2221         if (!flag_arg || flag_l2cap || flag_rfcomm) {
2222 #if HAVE_AFBLUETOOTH
2223             printf(_("Active Bluetooth connections ")); /* xxx */
2224
2225             if (flag_all)
2226                 printf(_("(servers and established)"));
2227             else {
2228               if (flag_lst)
2229                 printf(_("(only servers)"));
2230               else
2231                 printf(_("(w/o servers)"));
2232             }
2233             printf("\n");
2234 #else
2235             if (flag_arg) {
2236                 i = 1;
2237                 ENOSUPP("netstat", "AF BLUETOOTH");
2238             }
2239 #endif
2240         }
2241 #if HAVE_AFBLUETOOTH
2242         if (!flag_arg || flag_l2cap) {
2243             i = l2cap_info();
2244             if (i)
2245                 return (i);
2246         }
2247         if (!flag_arg || flag_rfcomm) {
2248             i = rfcomm_info();
2249             if (i)
2250                 return (i);
2251         }
2252 #endif
2253
2254         if (!flag_cnt || i)
2255             break;
2256         wait_continous();
2257         prg_cache_clear();
2258     }
2259     return (i);
2260 }