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