minor fix to return E_USAGE on -V instead of exit(0);
[oss-qm-packages.git] / netstat.c
blob2de173747fd6959c1d48be408d6466e61035fd92
1 /*
2 * netstat This file contains an implementation of the command
3 * that helps in debugging the networking modules.
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.
9 * Version: $Id: netstat.c,v 1.44 2001/08/26 05:25:21 ak Exp $
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>
19 * Tuned for NET3 by:
20 * Alan Cox, <A.Cox@swansea.ac.uk>
21 * Copyright (c) 1993 Fred Baumgarten
23 * Modified:
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
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
59 *990420 {1.38} Tuan Hoang removed a useless assignment from igmp_do_one()
60 *20010404 {1.39} Arnaldo Carvalho de Melo - use setlocale
62 * This program is free software; you can redistribute it
63 * and/or modify it under the terms of the GNU General
64 * Public License as published by the Free Software
65 * Foundation; either version 2 of the License, or (at
66 * your option) any later version.
69 #include <errno.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <strings.h>
74 #include <unistd.h>
75 #include <ctype.h>
76 #include <fcntl.h>
77 #include <netdb.h>
78 #include <paths.h>
79 #include <pwd.h>
80 #include <getopt.h>
81 #include <sys/param.h>
82 #include <sys/socket.h>
83 #include <arpa/inet.h>
84 #include <netinet/in.h>
85 #include <sys/ioctl.h>
86 #include <net/if.h>
87 #include <dirent.h>
89 #include "net-support.h"
90 #include "pathnames.h"
91 #include "version.h"
92 #include "config.h"
93 #include "intl.h"
94 #include "sockets.h"
95 #include "interface.h"
96 #include "util.h"
98 #define PROGNAME_WIDTH 20
100 #if !defined(s6_addr32) && defined(in6a_words)
101 #define s6_addr32 in6a_words /* libinet6 */
102 #endif
104 /* prototypes for statistics.c */
105 void parsesnmp(int, int, int);
106 void inittab(void);
108 typedef enum {
109 SS_FREE = 0, /* not allocated */
110 SS_UNCONNECTED, /* unconnected to any socket */
111 SS_CONNECTING, /* in process of connecting */
112 SS_CONNECTED, /* connected to socket */
113 SS_DISCONNECTING /* in process of disconnecting */
114 } socket_state;
116 #define SO_ACCEPTCON (1<<16) /* performed a listen */
117 #define SO_WAITDATA (1<<17) /* wait data to read */
118 #define SO_NOSPACE (1<<18) /* no space to write */
120 #define DFLT_AF "inet"
122 #define FEATURE_NETSTAT
123 #include "lib/net-features.h"
125 char *Release = RELEASE, *Version = "netstat 1.42 (2001-04-15)", *Signature = "Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang and others";
128 #define E_READ -1
129 #define E_IOCTL -3
131 int flag_int = 0;
132 int flag_rou = 0;
133 int flag_mas = 0;
134 int flag_sta = 0;
136 int flag_all = 0;
137 int flag_lst = 0;
138 int flag_cnt = 0;
139 int flag_deb = 0;
140 int flag_not = 0;
141 int flag_cf = 0;
142 int flag_opt = 0;
143 int flag_raw = 0;
144 int flag_tcp = 0;
145 int flag_udp = 0;
146 int flag_igmp= 0;
147 int flag_rom = 0;
148 int flag_exp = 1;
149 int flag_prg = 0;
150 int flag_arg = 0;
151 int flag_ver = 0;
153 FILE *procinfo;
155 #define INFO_GUTS1(file,name,proc) \
156 procinfo = fopen((file), "r"); \
157 if (procinfo == NULL) { \
158 if (errno != ENOENT) { \
159 perror((file)); \
160 return -1; \
162 if (flag_arg || flag_ver) \
163 ESYSNOT("netstat", (name)); \
164 if (flag_arg) \
165 rc = 1; \
166 } else { \
167 do { \
168 if (fgets(buffer, sizeof(buffer), procinfo)) \
169 (proc)(lnr++, buffer); \
170 } while (!feof(procinfo)); \
171 fclose(procinfo); \
174 #if HAVE_AFINET6
175 #define INFO_GUTS2(file,proc) \
176 lnr = 0; \
177 procinfo = fopen((file), "r"); \
178 if (procinfo != NULL) { \
179 do { \
180 if (fgets(buffer, sizeof(buffer), procinfo)) \
181 (proc)(lnr++, buffer); \
182 } while (!feof(procinfo)); \
183 fclose(procinfo); \
185 #else
186 #define INFO_GUTS2(file,proc)
187 #endif
189 #define INFO_GUTS3 \
190 return rc;
192 #define INFO_GUTS6(file,file6,name,proc) \
193 char buffer[8192]; \
194 int rc = 0; \
195 int lnr = 0; \
196 if (!flag_arg || flag_inet) { \
197 INFO_GUTS1(file,name,proc) \
199 if (!flag_arg || flag_inet6) { \
200 INFO_GUTS2(file6,proc) \
202 INFO_GUTS3
204 #define INFO_GUTS(file,name,proc) \
205 char buffer[8192]; \
206 int rc = 0; \
207 int lnr = 0; \
208 INFO_GUTS1(file,name,proc) \
209 INFO_GUTS3
211 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
212 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
213 #define PROGNAME_WIDTH2(s) #s
215 #define PRG_HASH_SIZE 211
217 static struct prg_node {
218 struct prg_node *next;
219 int inode;
220 char name[PROGNAME_WIDTH];
221 } *prg_hash[PRG_HASH_SIZE];
223 static char prg_cache_loaded = 0;
225 #define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
227 #define PROGNAME_BANNER "PID/Program name"
229 #define print_progname_banner() do { if (flag_prg) printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER); } while (0)
231 #define PRG_LOCAL_ADDRESS "local_address"
232 #define PRG_INODE "inode"
233 #define PRG_SOCKET_PFX "socket:["
234 #define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
235 #define PRG_SOCKET_PFX2 "[0000]:"
236 #define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2))
239 #ifndef LINE_MAX
240 #define LINE_MAX 4096
241 #endif
243 #define PATH_PROC "/proc"
244 #define PATH_FD_SUFF "fd"
245 #define PATH_FD_SUFFl strlen(PATH_FD_SUFF)
246 #define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF
247 #define PATH_CMDLINE "cmdline"
248 #define PATH_CMDLINEl strlen(PATH_CMDLINE)
249 /* NOT working as of glibc-2.0.7: */
250 #undef DIRENT_HAVE_D_TYPE_WORKS
252 static void prg_cache_add(int inode, char *name)
254 unsigned hi = PRG_HASHIT(inode);
255 struct prg_node **pnp,*pn;
257 prg_cache_loaded=2;
258 for (pnp=prg_hash+hi;(pn=*pnp);pnp=&pn->next) {
259 if (pn->inode==inode) {
260 /* Some warning should be appropriate here
261 as we got multiple processes for one i-node */
262 return;
265 if (!(*pnp=malloc(sizeof(**pnp))))
266 return;
267 pn=*pnp;
268 pn->next=NULL;
269 pn->inode=inode;
270 if (strlen(name)>sizeof(pn->name)-1)
271 name[sizeof(pn->name)-1]='\0';
272 strcpy(pn->name,name);
275 static const char *prg_cache_get(int inode)
277 unsigned hi=PRG_HASHIT(inode);
278 struct prg_node *pn;
280 for (pn=prg_hash[hi];pn;pn=pn->next)
281 if (pn->inode==inode) return(pn->name);
282 return("-");
285 static void prg_cache_clear(void)
287 struct prg_node **pnp,*pn;
289 if (prg_cache_loaded == 2)
290 for (pnp=prg_hash;pnp<prg_hash+PRG_HASH_SIZE;pnp++)
291 while ((pn=*pnp)) {
292 *pnp=pn->next;
293 free(pn);
295 prg_cache_loaded=0;
298 static void extract_type_1_socket_inode(const char lname[], long * inode_p) {
300 /* If lname is of the form "socket:[12345]", extract the "12345"
301 as *inode_p. Otherwise, return -1 as *inode_p.
304 if (strlen(lname) < PRG_SOCKET_PFXl+3) *inode_p = -1;
305 else if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) *inode_p = -1;
306 else if (lname[strlen(lname)-1] != ']') *inode_p = -1;
307 else {
308 char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
309 const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
310 char *serr;
312 strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
313 inode_str[inode_str_len] = '\0';
314 *inode_p = strtol(inode_str,&serr,0);
315 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
316 *inode_p = -1;
322 static void extract_type_2_socket_inode(const char lname[], long * inode_p) {
324 /* If lname is of the form "[0000]:12345", extract the "12345"
325 as *inode_p. Otherwise, return -1 as *inode_p.
328 if (strlen(lname) < PRG_SOCKET_PFX2l+1) *inode_p = -1;
329 else if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) *inode_p = -1;
330 else {
331 char *serr;
333 *inode_p=strtol(lname + PRG_SOCKET_PFX2l,&serr,0);
334 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
335 *inode_p = -1;
341 static void prg_cache_load(void)
343 char line[LINE_MAX],eacces=0;
344 int procfdlen,fd,cmdllen,lnamelen;
345 char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH];
346 long inode;
347 const char *cs,*cmdlp;
348 DIR *dirproc=NULL,*dirfd=NULL;
349 struct dirent *direproc,*direfd;
351 if (prg_cache_loaded || !flag_prg) return;
352 prg_cache_loaded=1;
353 cmdlbuf[sizeof(cmdlbuf)-1]='\0';
354 if (!(dirproc=opendir(PATH_PROC))) goto fail;
355 while (errno=0,direproc=readdir(dirproc)) {
356 #ifdef DIRENT_HAVE_D_TYPE_WORKS
357 if (direproc->d_type!=DT_DIR) continue;
358 #endif
359 for (cs=direproc->d_name;*cs;cs++)
360 if (!isdigit(*cs))
361 break;
362 if (*cs)
363 continue;
364 procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
365 if (procfdlen<=0 || procfdlen>=sizeof(line)-5)
366 continue;
367 errno=0;
368 dirfd=opendir(line);
369 if (! dirfd) {
370 if (errno==EACCES)
371 eacces=1;
372 continue;
374 line[procfdlen] = '/';
375 cmdlp = NULL;
376 while ((direfd = readdir(dirfd))) {
377 #ifdef DIRENT_HAVE_D_TYPE_WORKS
378 if (direfd->d_type!=DT_LNK)
379 continue;
380 #endif
381 if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line))
382 continue;
383 memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
384 PATH_FD_SUFFl+1);
385 strcpy(line + procfdlen + 1, direfd->d_name);
386 lnamelen=readlink(line,lname,sizeof(lname)-1);
387 lname[lnamelen] = '\0'; /*make it a null-terminated string*/
389 extract_type_1_socket_inode(lname, &inode);
391 if (inode < 0) extract_type_2_socket_inode(lname, &inode);
393 if (inode < 0) continue;
395 if (!cmdlp) {
396 if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
397 sizeof(line) - 5)
398 continue;
399 strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
400 fd = open(line, O_RDONLY);
401 if (fd < 0)
402 continue;
403 cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
404 if (close(fd))
405 continue;
406 if (cmdllen == -1)
407 continue;
408 if (cmdllen < sizeof(cmdlbuf) - 1)
409 cmdlbuf[cmdllen]='\0';
410 if ((cmdlp = strrchr(cmdlbuf, '/')))
411 cmdlp++;
412 else
413 cmdlp = cmdlbuf;
416 snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
417 prg_cache_add(inode, finbuf);
419 closedir(dirfd);
420 dirfd = NULL;
422 if (dirproc)
423 closedir(dirproc);
424 if (dirfd)
425 closedir(dirfd);
426 if (!eacces)
427 return;
428 if (prg_cache_loaded == 1) {
429 fail:
430 fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
431 geteuid());
433 else
434 fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
435 " will not be shown, you would have to be root to see it all.)\n"));
438 #if HAVE_AFNETROM
439 static const char *netrom_state[] =
441 N_("LISTENING"),
442 N_("CONN SENT"),
443 N_("DISC SENT"),
444 N_("ESTABLISHED")
447 static int netrom_info(void)
449 FILE *f;
450 char buffer[256], dev[16];
451 int st, vs, vr, sendq, recvq, ret;
453 f = fopen(_PATH_PROCNET_NR, "r");
454 if (f == NULL) {
455 if (errno != ENOENT) {
456 perror(_PATH_PROCNET_NR);
457 return (-1);
459 if (flag_arg || flag_ver)
460 ESYSNOT("netstat", "AF NETROM");
461 if (flag_arg)
462 return (1);
463 else
464 return (0);
466 printf(_("Active NET/ROM sockets\n"));
467 printf(_("User Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
468 fgets(buffer, 256, f);
470 while (fgets(buffer, 256, f)) {
471 buffer[9] = 0;
472 buffer[19] = 0;
473 buffer[29] = 0;
474 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",
475 dev, &st, &vs, &vr, &sendq, &recvq);
476 if (ret != 6) {
477 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
478 continue;
480 printf("%-9s %-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
481 buffer, buffer + 10, buffer + 20,
482 dev,
483 _(netrom_state[st]),
484 vr, vs, sendq, recvq);
486 fclose(f);
487 return 0;
489 #endif
491 /* These enums are used by IPX too. :-( */
492 enum {
493 TCP_ESTABLISHED = 1,
494 TCP_SYN_SENT,
495 TCP_SYN_RECV,
496 TCP_FIN_WAIT1,
497 TCP_FIN_WAIT2,
498 TCP_TIME_WAIT,
499 TCP_CLOSE,
500 TCP_CLOSE_WAIT,
501 TCP_LAST_ACK,
502 TCP_LISTEN,
503 TCP_CLOSING /* now a valid state */
506 #if HAVE_AFINET || HAVE_AFINET6
508 static const char *tcp_state[] =
511 N_("ESTABLISHED"),
512 N_("SYN_SENT"),
513 N_("SYN_RECV"),
514 N_("FIN_WAIT1"),
515 N_("FIN_WAIT2"),
516 N_("TIME_WAIT"),
517 N_("CLOSE"),
518 N_("CLOSE_WAIT"),
519 N_("LAST_ACK"),
520 N_("LISTEN"),
521 N_("CLOSING")
524 static void finish_this_one(int uid, unsigned long inode, const char *timers)
526 struct passwd *pw;
528 if (flag_exp > 1) {
529 if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
530 printf("%-10s ", pw->pw_name);
531 else
532 printf("%-10d ", uid);
533 printf("%-10ld ",inode);
535 if (flag_prg)
536 printf("%-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
537 if (flag_opt)
538 printf("%s", timers);
539 putchar('\n');
542 static void igmp_do_one(int lnr, const char *line)
544 char mcast_addr[128];
545 #if HAVE_AFINET6
546 struct sockaddr_in6 mcastaddr;
547 char addr6[INET6_ADDRSTRLEN];
548 struct in6_addr in6;
549 extern struct aftype inet6_aftype;
550 #else
551 struct sockaddr_in mcastaddr;
552 #endif
553 struct aftype *ap;
554 static int idx_flag = 0;
555 static int igmp6_flag = 0;
556 static char device[16];
557 int num, idx, refcnt;
559 if (lnr == 0) {
560 /* IPV6 ONLY */
561 /* igmp6 file does not have any comments on first line */
562 if ( strstr( line, "Device" ) == NULL ) {
563 igmp6_flag = 1;
564 } else {
565 /* IPV4 ONLY */
566 /* 2.1.x kernels and up have Idx field */
567 /* 2.0.x and below do not have Idx field */
568 if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
569 idx_flag = 1;
570 else
571 idx_flag = 0;
572 return;
576 if (igmp6_flag) { /* IPV6 */
577 #if HAVE_AFINET6
578 num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
579 if (num == 4) {
580 /* Demangle what the kernel gives us */
581 sscanf(mcast_addr, "%08X%08X%08X%08X",
582 &in6.s6_addr32[0], &in6.s6_addr32[1],
583 &in6.s6_addr32[2], &in6.s6_addr32[3]);
584 in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
585 in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
586 in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
587 in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
588 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
589 inet6_aftype.input(1, addr6, (struct sockaddr *) &mcastaddr);
590 mcastaddr.sin6_family = AF_INET6;
591 } else {
592 fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
593 return;
596 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
597 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
598 ((struct sockaddr *) &mcastaddr)->sa_family);
599 return;
601 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
602 flag_not), sizeof(mcast_addr));
603 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
604 #endif
605 } else { /* IPV4 */
606 #if HAVE_AFINET
607 if (line[0] != '\t') {
608 if (idx_flag) {
609 if ((num = sscanf( line, "%d\t%10c", &idx, device)) < 2) {
610 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
611 return;
613 } else {
614 if ( (num = sscanf( line, "%10c", device )) < 1 ) {
615 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
616 return;
619 device[10] = '\0';
620 return;
621 } else if ( line[0] == '\t' ) {
622 if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
623 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
624 return;
626 sscanf( mcast_addr, "%X",
627 &((struct sockaddr_in *) &mcastaddr)->sin_addr.s_addr );
628 ((struct sockaddr *) &mcastaddr)->sa_family = AF_INET;
629 } else {
630 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
631 return;
634 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
635 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
636 ((struct sockaddr *) &mcastaddr)->sa_family);
637 return;
639 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
640 flag_not), sizeof(mcast_addr));
641 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
642 #endif
643 } /* IPV4 */
646 #if HAVE_AFX25
647 static int x25_info(void)
649 FILE *f=fopen(_PATH_PROCNET_X25, "r");
650 char buffer[256],dev[16];
651 int st,vs,vr,sendq,recvq,lci;
652 static char *x25_state[5]=
654 "LISTENING",
655 "SABM_SENT",
656 "DISC_SENT",
657 "ESTABLISHED",
658 "RECOVERY"
660 if(!(f=fopen(_PATH_PROCNET_X25, "r")))
662 if (errno != ENOENT) {
663 perror(_PATH_PROCNET_X25);
664 return(-1);
666 if (flag_arg || flag_ver)
667 ESYSNOT("netstat","AF X25");
668 if (flag_arg)
669 return(1);
670 else
671 return(0);
673 printf( _("Active X.25 sockets\n"));
674 /* IMHO, Vr/Vs is not very usefull --SF */
675 printf( _("Dest Source Device LCI State Vr/Vs Send-Q Recv-Q\n"));
676 fgets(buffer,256,f);
677 while(fgets(buffer,256,f))
679 buffer[10]=0;
680 buffer[20]=0;
681 sscanf(buffer+22,"%s %d %d %d %d %*d %*d %*d %*d %*d %*d %d %d %*d",
682 dev,&lci,&st,&vs,&vr,&sendq,&recvq);
683 if (!(flag_all || lci))
684 continue;
685 printf("%-15s %-15s %-7s %-3d %-11s %02d/%02d %-6d %-6d\n",
686 buffer,buffer+11,
687 dev,
688 lci,
689 x25_state[st],
690 vr,vs,sendq,recvq);
692 fclose(f);
693 return 0;
695 #endif
697 static int igmp_info(void)
699 INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
700 igmp_do_one);
703 static void tcp_do_one(int lnr, const char *line)
705 unsigned long rxq, txq, time_len, retr, inode;
706 int num, local_port, rem_port, d, state, uid, timer_run, timeout;
707 char rem_addr[128], local_addr[128], timers[64], buffer[1024], more[512];
708 struct aftype *ap;
709 #if HAVE_AFINET6
710 struct sockaddr_in6 localaddr, remaddr;
711 char addr6[INET6_ADDRSTRLEN];
712 struct in6_addr in6;
713 extern struct aftype inet6_aftype;
714 #else
715 struct sockaddr_in localaddr, remaddr;
716 #endif
718 if (lnr == 0)
719 return;
721 num = sscanf(line,
722 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
723 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
724 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
726 if (strlen(local_addr) > 8) {
727 #if HAVE_AFINET6
728 /* Demangle what the kernel gives us */
729 sscanf(local_addr, "%08X%08X%08X%08X",
730 &in6.s6_addr32[0], &in6.s6_addr32[1],
731 &in6.s6_addr32[2], &in6.s6_addr32[3]);
732 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
733 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
734 sscanf(rem_addr, "%08X%08X%08X%08X",
735 &in6.s6_addr32[0], &in6.s6_addr32[1],
736 &in6.s6_addr32[2], &in6.s6_addr32[3]);
737 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
738 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
739 localaddr.sin6_family = AF_INET6;
740 remaddr.sin6_family = AF_INET6;
741 #endif
742 } else {
743 sscanf(local_addr, "%X",
744 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
745 sscanf(rem_addr, "%X",
746 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
747 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
748 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
751 if (num < 11) {
752 fprintf(stderr, _("warning, got bogus tcp line.\n"));
753 return;
755 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
756 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
757 ((struct sockaddr *) &localaddr)->sa_family);
758 return;
760 if (state == TCP_LISTEN) {
761 time_len = 0;
762 retr = 0L;
763 rxq = 0L;
764 txq = 0L;
766 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
767 flag_not), sizeof(local_addr));
768 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr, flag_not),
769 sizeof(rem_addr));
770 if (flag_all || (flag_lst && !rem_port) || (!flag_lst && rem_port)) {
771 snprintf(buffer, sizeof(buffer), "%s",
772 get_sname(htons(local_port), "tcp",
773 flag_not & FLAG_NUM_PORT));
775 if ((strlen(local_addr) + strlen(buffer)) > 22)
776 local_addr[22 - strlen(buffer)] = '\0';
778 strcat(local_addr, ":");
779 strcat(local_addr, buffer);
780 snprintf(buffer, sizeof(buffer), "%s",
781 get_sname(htons(rem_port), "tcp", flag_not & FLAG_NUM_PORT));
783 if ((strlen(rem_addr) + strlen(buffer)) > 22)
784 rem_addr[22 - strlen(buffer)] = '\0';
786 strcat(rem_addr, ":");
787 strcat(rem_addr, buffer);
788 timers[0] = '\0';
790 if (flag_opt)
791 switch (timer_run) {
792 case 0:
793 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
794 break;
796 case 1:
797 snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
798 (double) time_len / HZ, retr, timeout);
799 break;
801 case 2:
802 snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
803 (double) time_len / HZ, retr, timeout);
804 break;
806 case 3:
807 snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
808 (double) time_len / HZ, retr, timeout);
809 break;
811 default:
812 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
813 timer_run, (double) time_len / HZ, retr, timeout);
814 break;
816 printf("tcp %6ld %6ld %-*s %-*s %-12s",
817 rxq, txq, max(23,strlen(local_addr)+1), local_addr, max(23,strlen(rem_addr)), rem_addr, _(tcp_state[state]));
819 finish_this_one(uid,inode,timers);
823 static int tcp_info(void)
825 INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
826 tcp_do_one);
829 static void udp_do_one(int lnr, const char *line)
831 char buffer[8192], local_addr[64], rem_addr[64];
832 char *udp_state, timers[64], more[512];
833 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
834 #if HAVE_AFINET6
835 struct sockaddr_in6 localaddr, remaddr;
836 char addr6[INET6_ADDRSTRLEN];
837 struct in6_addr in6;
838 extern struct aftype inet6_aftype;
839 #else
840 struct sockaddr_in localaddr, remaddr;
841 #endif
842 struct aftype *ap;
843 unsigned long rxq, txq, time_len, retr, inode;
845 if (lnr == 0)
846 return;
848 more[0] = '\0';
849 num = sscanf(line,
850 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
851 &d, local_addr, &local_port,
852 rem_addr, &rem_port, &state,
853 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
855 if (strlen(local_addr) > 8) {
856 #if HAVE_AFINET6
857 sscanf(local_addr, "%08X%08X%08X%08X",
858 &in6.s6_addr32[0], &in6.s6_addr32[1],
859 &in6.s6_addr32[2], &in6.s6_addr32[3]);
860 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
861 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
862 sscanf(rem_addr, "%08X%08X%08X%08X",
863 &in6.s6_addr32[0], &in6.s6_addr32[1],
864 &in6.s6_addr32[2], &in6.s6_addr32[3]);
865 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
866 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
867 localaddr.sin6_family = AF_INET6;
868 remaddr.sin6_family = AF_INET6;
869 #endif
870 } else {
871 sscanf(local_addr, "%X",
872 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
873 sscanf(rem_addr, "%X",
874 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
875 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
876 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
879 retr = 0L;
880 if (!flag_opt)
881 more[0] = '\0';
883 if (num < 10) {
884 fprintf(stderr, _("warning, got bogus udp line.\n"));
885 return;
887 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
888 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
889 ((struct sockaddr *) &localaddr)->sa_family);
890 return;
892 switch (state) {
893 case TCP_ESTABLISHED:
894 udp_state = _("ESTABLISHED");
895 break;
897 case TCP_CLOSE:
898 udp_state = "";
899 break;
901 default:
902 udp_state = _("UNKNOWN");
903 break;
906 #if HAVE_AFINET6
907 #define notnull(A) (((A.sin6_family == AF_INET6) && \
908 ((A.sin6_addr.s6_addr32[0]) || \
909 (A.sin6_addr.s6_addr32[1]) || \
910 (A.sin6_addr.s6_addr32[2]) || \
911 (A.sin6_addr.s6_addr32[3]))) || \
912 ((A.sin6_family == AF_INET) && \
913 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
914 #else
915 #define notnull(A) (A.sin_addr.s_addr)
916 #endif
918 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
920 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
921 flag_not), sizeof(local_addr));
922 snprintf(buffer, sizeof(buffer), "%s",
923 get_sname(htons(local_port), "udp",
924 flag_not & FLAG_NUM_PORT));
925 if ((strlen(local_addr) + strlen(buffer)) > 22)
926 local_addr[22 - strlen(buffer)] = '\0';
927 strcat(local_addr, ":");
928 strcat(local_addr, buffer);
930 snprintf(buffer, sizeof(buffer), "%s",
931 get_sname(htons(rem_port), "udp", flag_not & FLAG_NUM_PORT));
932 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
933 flag_not), sizeof(rem_addr));
934 if ((strlen(rem_addr) + strlen(buffer)) > 22)
935 rem_addr[22 - strlen(buffer)] = '\0';
936 strcat(rem_addr, ":");
937 strcat(rem_addr, buffer);
939 timers[0] = '\0';
940 if (flag_opt)
941 switch (timer_run) {
942 case 0:
943 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
944 break;
946 case 1:
947 case 2:
948 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
949 break;
951 default:
952 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
953 retr, timeout);
954 break;
956 printf("udp %6ld %6ld %-23s %-23s %-12s",
957 rxq, txq, local_addr, rem_addr, udp_state);
959 finish_this_one(uid,inode,timers);
963 static int udp_info(void)
965 INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
966 udp_do_one);
969 static void raw_do_one(int lnr, const char *line)
971 char buffer[8192], local_addr[64], rem_addr[64];
972 char timers[64], more[512];
973 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
974 #if HAVE_AFINET6
975 struct sockaddr_in6 localaddr, remaddr;
976 char addr6[INET6_ADDRSTRLEN];
977 struct in6_addr in6;
978 extern struct aftype inet6_aftype;
979 #else
980 struct sockaddr_in localaddr, remaddr;
981 #endif
982 struct aftype *ap;
983 unsigned long rxq, txq, time_len, retr, inode;
985 if (lnr == 0)
986 return;
988 more[0] = '\0';
989 num = sscanf(line,
990 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
991 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
992 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
994 if (strlen(local_addr) > 8) {
995 #if HAVE_AFINET6
996 sscanf(local_addr, "%08X%08X%08X%08X",
997 &in6.s6_addr32[0], &in6.s6_addr32[1],
998 &in6.s6_addr32[2], &in6.s6_addr32[3]);
999 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1000 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
1001 sscanf(rem_addr, "%08X%08X%08X%08X",
1002 &in6.s6_addr32[0], &in6.s6_addr32[1],
1003 &in6.s6_addr32[2], &in6.s6_addr32[3]);
1004 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1005 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
1006 localaddr.sin6_family = AF_INET6;
1007 remaddr.sin6_family = AF_INET6;
1008 #endif
1009 } else {
1010 sscanf(local_addr, "%X",
1011 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1012 sscanf(rem_addr, "%X",
1013 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1014 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1015 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1017 #if HAVE_AFINET6
1018 if ((ap = get_afntype(localaddr.sin6_family)) == NULL) {
1019 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin6_family);
1020 return;
1022 #else
1023 if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
1024 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin_family);
1025 return;
1027 #endif
1029 if (!flag_opt)
1030 more[0] = '\0';
1032 if (num < 10) {
1033 fprintf(stderr, _("warning, got bogus raw line.\n"));
1034 return;
1037 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1039 snprintf(buffer, sizeof(buffer), "%s",
1040 get_sname(htons(local_port), "raw",
1041 flag_not & FLAG_NUM_PORT));
1042 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
1043 flag_not), sizeof(local_addr));
1044 if ((strlen(local_addr) + strlen(buffer)) > 22)
1045 local_addr[22 - strlen(buffer)] = '\0';
1046 strcat(local_addr, ":");
1047 strcat(local_addr, buffer);
1049 snprintf(buffer, sizeof(buffer), "%s",
1050 get_sname(htons(rem_port), "raw", flag_not & FLAG_NUM_PORT));
1051 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
1052 flag_not), sizeof(rem_addr));
1053 if ((strlen(rem_addr) + strlen(buffer)) > 22)
1054 rem_addr[22 - strlen(buffer)] = '\0';
1055 strcat(rem_addr, ":");
1056 strcat(rem_addr, buffer);
1058 timers[0] = '\0';
1059 if (flag_opt)
1060 switch (timer_run) {
1061 case 0:
1062 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1063 break;
1065 case 1:
1066 case 2:
1067 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1068 retr, timeout);
1069 break;
1071 default:
1072 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
1073 timer_run, (double) time_len / 100,
1074 retr, timeout);
1075 break;
1077 printf("raw %6ld %6ld %-23s %-23s %-12d",
1078 rxq, txq, local_addr, rem_addr, state);
1080 finish_this_one(uid,inode,timers);
1084 static int raw_info(void)
1086 INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
1087 raw_do_one);
1090 #endif
1093 #if HAVE_AFUNIX
1095 #define HAS_INODE 1
1097 static void unix_do_one(int nr, const char *line)
1099 static int has = 0;
1100 char path[MAXPATHLEN], ss_flags[32];
1101 char *ss_proto, *ss_state, *ss_type;
1102 int num, state, type, inode;
1103 void *d;
1104 unsigned long refcnt, proto, flags;
1106 if (nr == 0) {
1107 if (strstr(line, "Inode"))
1108 has |= HAS_INODE;
1109 return;
1111 path[0] = '\0';
1112 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
1113 &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
1114 if (num < 6) {
1115 fprintf(stderr, _("warning, got bogus unix line.\n"));
1116 return;
1118 if (!(has & HAS_INODE))
1119 snprintf(path,sizeof(path),"%d",inode);
1121 if (!flag_all) {
1122 if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
1123 if (!flag_lst)
1124 return;
1125 } else {
1126 if (flag_lst)
1127 return;
1131 switch (proto) {
1132 case 0:
1133 ss_proto = "unix";
1134 break;
1136 default:
1137 ss_proto = "??";
1140 switch (type) {
1141 case SOCK_STREAM:
1142 ss_type = _("STREAM");
1143 break;
1145 case SOCK_DGRAM:
1146 ss_type = _("DGRAM");
1147 break;
1149 case SOCK_RAW:
1150 ss_type = _("RAW");
1151 break;
1153 case SOCK_RDM:
1154 ss_type = _("RDM");
1155 break;
1157 case SOCK_SEQPACKET:
1158 ss_type = _("SEQPACKET");
1159 break;
1161 default:
1162 ss_type = _("UNKNOWN");
1165 switch (state) {
1166 case SS_FREE:
1167 ss_state = _("FREE");
1168 break;
1170 case SS_UNCONNECTED:
1172 * Unconnected sockets may be listening
1173 * for something.
1175 if (flags & SO_ACCEPTCON) {
1176 ss_state = _("LISTENING");
1177 } else {
1178 ss_state = "";
1180 break;
1182 case SS_CONNECTING:
1183 ss_state = _("CONNECTING");
1184 break;
1186 case SS_CONNECTED:
1187 ss_state = _("CONNECTED");
1188 break;
1190 case SS_DISCONNECTING:
1191 ss_state = _("DISCONNECTING");
1192 break;
1194 default:
1195 ss_state = _("UNKNOWN");
1198 strcpy(ss_flags, "[ ");
1199 if (flags & SO_ACCEPTCON)
1200 strcat(ss_flags, "ACC ");
1201 if (flags & SO_WAITDATA)
1202 strcat(ss_flags, "W ");
1203 if (flags & SO_NOSPACE)
1204 strcat(ss_flags, "N ");
1206 strcat(ss_flags, "]");
1208 printf("%-5s %-6ld %-11s %-10s %-13s ",
1209 ss_proto, refcnt, ss_flags, ss_type, ss_state);
1210 if (has & HAS_INODE)
1211 printf("%-6d ",inode);
1212 else
1213 printf("- ");
1214 if (flag_prg)
1215 printf("%-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
1216 puts(path);
1219 static int unix_info(void)
1222 printf(_("Active UNIX domain sockets "));
1223 if (flag_all)
1224 printf(_("(servers and established)"));
1225 else {
1226 if (flag_lst)
1227 printf(_("(only servers)"));
1228 else
1229 printf(_("(w/o servers)"));
1232 printf(_("\nProto RefCnt Flags Type State I-Node"));
1233 print_progname_banner();
1234 printf(_(" Path\n")); /* xxx */
1237 INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
1240 #endif
1243 #if HAVE_AFAX25
1244 static int ax25_info(void)
1246 FILE *f;
1247 char buffer[256], buf[16];
1248 char *src, *dst, *dev, *p;
1249 int st, vs, vr, sendq, recvq, ret;
1250 int new = -1; /* flag for new (2.1.x) kernels */
1251 static char *ax25_state[5] =
1253 N_("LISTENING"),
1254 N_("SABM SENT"),
1255 N_("DISC SENT"),
1256 N_("ESTABLISHED"),
1257 N_("RECOVERY")
1259 if (!(f = fopen(_PATH_PROCNET_AX25, "r"))) {
1260 if (errno != ENOENT) {
1261 perror(_PATH_PROCNET_AX25);
1262 return (-1);
1264 if (flag_arg || flag_ver)
1265 ESYSNOT("netstat", "AF AX25");
1266 if (flag_arg)
1267 return (1);
1268 else
1269 return (0);
1271 printf(_("Active AX.25 sockets\n"));
1272 printf(_("Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
1273 while (fgets(buffer, 256, f)) {
1274 if (new == -1) {
1275 if (!strncmp(buffer, "dest_addr", 9)) {
1276 new = 0;
1277 continue; /* old kernels have a header line */
1278 } else
1279 new = 1;
1282 * In a network connection with no user socket the Snd-Q, Rcv-Q
1283 * and Inode fields are empty in 2.0.x and '*' in 2.1.x
1285 sendq = 0;
1286 recvq = 0;
1287 if (new == 0) {
1288 dst = buffer;
1289 src = buffer + 10;
1290 dst[9] = 0;
1291 src[9] = 0;
1292 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",
1293 buf, &st, &vs, &vr, &sendq, &recvq);
1294 if (ret != 4 && ret != 6) {
1295 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
1296 continue;
1298 dev = buf;
1299 } else {
1300 p = buffer;
1301 while (*p != ' ') p++;
1302 p++;
1303 dev = p;
1304 while (*p != ' ') p++;
1305 *p++ = 0;
1306 src = p;
1307 while (*p != ' ') p++;
1308 *p++ = 0;
1309 dst = p;
1310 while (*p != ' ') p++;
1311 *p++ = 0;
1312 ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
1313 &st, &vs, &vr, &sendq, &recvq);
1314 if (ret != 3 && ret != 5) {
1315 printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
1316 continue;
1319 * FIXME: digipeaters should be handled somehow.
1320 * For now we just strip them.
1322 p = dst;
1323 while (*p && *p != ',') p++;
1324 *p = 0;
1326 printf("%-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
1327 dst, src,
1328 dev,
1329 _(ax25_state[st]),
1330 vr, vs, sendq, recvq);
1332 fclose(f);
1333 return 0;
1335 #endif
1338 #if HAVE_AFIPX
1339 static int ipx_info(void)
1341 FILE *f;
1342 char buf[256];
1343 unsigned long txq, rxq;
1344 unsigned int state;
1345 unsigned int uid;
1346 char *st;
1347 int nc;
1348 struct aftype *ap;
1349 struct passwd *pw;
1350 char sad[50], dad[50];
1351 struct sockaddr sa;
1352 unsigned sport = 0, dport = 0;
1354 if (!(f = fopen(_PATH_PROCNET_IPX, "r"))) {
1355 if (errno != ENOENT) {
1356 perror(_PATH_PROCNET_IPX);
1357 return (-1);
1359 if (flag_arg || flag_ver)
1360 ESYSNOT("netstat", "AF IPX");
1361 if (flag_arg)
1362 return (1);
1363 else
1364 return (0);
1366 printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address Foreign Address State")); /* xxx */
1367 if (flag_exp > 1)
1368 printf(_(" User")); /* xxx */
1369 printf("\n");
1370 if ((ap = get_afntype(AF_IPX)) == NULL) {
1371 EINTERN("netstat.c", "AF_IPX missing");
1372 return (-1);
1374 fgets(buf, 255, f);
1376 while (fgets(buf, 255, f) != NULL) {
1377 sscanf(buf, "%s %s %lX %lX %d %d",
1378 sad, dad, &txq, &rxq, &state, &uid);
1379 if ((st = rindex(sad, ':'))) {
1380 *st++ = '\0';
1381 sscanf(st, "%X", &sport); /* net byt order */
1382 sport = ntohs(sport);
1383 } else {
1384 EINTERN("netstat.c", _PATH_PROCNET_IPX " sport format error");
1385 return (-1);
1387 nc = 0;
1388 if (strcmp(dad, "Not_Connected") != 0) {
1389 if ((st = rindex(dad, ':'))) {
1390 *st++ = '\0';
1391 sscanf(st, "%X", &dport); /* net byt order */
1392 dport = ntohs(dport);
1393 } else {
1394 EINTERN("netstat.c", _PATH_PROCNET_IPX " dport format error");
1395 return (-1);
1397 } else
1398 nc = 1;
1400 switch (state) {
1401 case TCP_ESTABLISHED:
1402 st = _("ESTAB");
1403 break;
1405 case TCP_CLOSE:
1406 st = "";
1407 break;
1409 default:
1410 st = _("UNK.");
1411 break;
1414 /* Fetch and resolve the Source */
1415 (void) ap->input(4, sad, &sa);
1416 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1417 snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
1419 if (!nc) {
1420 /* Fetch and resolve the Destination */
1421 (void) ap->input(4, dad, &sa);
1422 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1423 snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
1424 } else
1425 strcpy(dad, "-");
1427 printf("IPX %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
1428 if (flag_exp > 1) {
1429 if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
1430 printf(" %-10s", pw->pw_name);
1431 else
1432 printf(" %-10d", uid);
1434 printf("\n");
1436 fclose(f);
1437 return 0;
1439 #endif
1441 static int iface_info(void)
1443 if (skfd < 0) {
1444 if ((skfd = sockets_open(0)) < 0) {
1445 perror("socket");
1446 exit(1);
1448 printf(_("Kernel Interface table\n"));
1450 if (flag_exp < 2) {
1451 ife_short = 1;
1452 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
1455 if (for_all_interfaces(do_if_print, &flag_all) < 0) {
1456 perror(_("missing interface information"));
1457 exit(1);
1459 if (flag_cnt)
1460 free_interface_list();
1461 else {
1462 close(skfd);
1463 skfd = -1;
1466 return 0;
1470 static void version(void)
1472 printf("%s\n%s\n%s\n%s\n", Release, Version, Signature, Features);
1473 exit(E_VERSION);
1477 static void usage(void)
1479 fprintf(stderr, _("usage: netstat [-veenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}\n"));
1480 fprintf(stderr, _(" netstat [-vnNcaeol] [<Socket> ...]\n"));
1481 fprintf(stderr, _(" netstat { [-veenNac] -i | [-cnNe] -M | -s }\n\n"));
1483 fprintf(stderr, _(" -r, --route display routing table\n"));
1484 fprintf(stderr, _(" -i, --interfaces display interface table\n"));
1485 fprintf(stderr, _(" -g, --groups display multicast group memberships\n"));
1486 fprintf(stderr, _(" -s, --statistics display networking statistics (like SNMP)\n"));
1487 #if HAVE_FW_MASQUERADE
1488 fprintf(stderr, _(" -M, --masquerade display masqueraded connections\n\n"));
1489 #endif
1490 fprintf(stderr, _(" -v, --verbose be verbose\n"));
1491 fprintf(stderr, _(" -n, --numeric don't resolve names\n"));
1492 fprintf(stderr, _(" --numeric-hosts don't resolve host names\n"));
1493 fprintf(stderr, _(" --numeric-ports don't resolve port names\n"));
1494 fprintf(stderr, _(" --numeric-users don't resolve user names\n"));
1495 fprintf(stderr, _(" -N, --symbolic resolve hardware names\n"));
1496 fprintf(stderr, _(" -e, --extend display other/more information\n"));
1497 fprintf(stderr, _(" -p, --programs display PID/Program name for sockets\n"));
1498 fprintf(stderr, _(" -c, --continuous continuous listing\n\n"));
1499 fprintf(stderr, _(" -l, --listening display listening server sockets\n"));
1500 fprintf(stderr, _(" -a, --all, --listening display all sockets (default: connected)\n"));
1501 fprintf(stderr, _(" -o, --timers display timers\n"));
1502 fprintf(stderr, _(" -F, --fib display Forwarding Information Base (default)\n"));
1503 fprintf(stderr, _(" -C, --cache display routing cache instead of FIB\n\n"));
1505 fprintf(stderr, _(" <Socket>={-t|--tcp} {-u|--udp} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
1506 fprintf(stderr, _(" <AF>=Use '-A <af>' or '--<af>'; default: %s\n"), DFLT_AF);
1507 fprintf(stderr, _(" List of possible address families (which support routing):\n"));
1508 print_aflist(1); /* 1 = routeable */
1509 exit(E_USAGE);
1513 int main
1514 (int argc, char *argv[]) {
1515 int i;
1516 int lop;
1517 static struct option longopts[] =
1519 AFTRANS_OPTS,
1520 {"version", 0, 0, 'V'},
1521 {"interfaces", 0, 0, 'i'},
1522 {"help", 0, 0, 'h'},
1523 {"route", 0, 0, 'r'},
1524 #if HAVE_FW_MASQUERADE
1525 {"masquerade", 0, 0, 'M'},
1526 #endif
1527 {"protocol", 1, 0, 'A'},
1528 {"tcp", 0, 0, 't'},
1529 {"udp", 0, 0, 'u'},
1530 {"raw", 0, 0, 'w'},
1531 {"unix", 0, 0, 'x'},
1532 {"listening", 0, 0, 'l'},
1533 {"all", 0, 0, 'a'},
1534 {"timers", 0, 0, 'o'},
1535 {"continuous", 0, 0, 'c'},
1536 {"extend", 0, 0, 'e'},
1537 {"programs", 0, 0, 'p'},
1538 {"verbose", 0, 0, 'v'},
1539 {"statistics", 0, 0, 's'},
1540 {"numeric", 0, 0, 'n'},
1541 {"numeric-hosts", 0, 0, '!'},
1542 {"numeric-ports", 0, 0, '@'},
1543 {"numeric-users", 0, 0, '#'},
1544 {"symbolic", 0, 0, 'N'},
1545 {"cache", 0, 0, 'C'},
1546 {"fib", 0, 0, 'F'},
1547 {"groups", 0, 0, 'g'},
1548 {NULL, 0, 0, 0}
1551 #if I18N
1552 setlocale (LC_ALL, "");
1553 bindtextdomain("net-tools", "/usr/share/locale");
1554 textdomain("net-tools");
1555 #endif
1556 getroute_init(); /* Set up AF routing support */
1558 afname[0] = '\0';
1559 while ((i = getopt_long(argc, argv, "MCFA:acdegphinNorstuVv?wxl", longopts, &lop)) != EOF)
1560 switch (i) {
1561 case -1:
1562 break;
1563 case 1:
1564 if (lop < 0 || lop >= AFTRANS_CNT) {
1565 EINTERN("netstat.c", "longopts 1 range");
1566 break;
1568 if (aftrans_opt(longopts[lop].name))
1569 exit(1);
1570 break;
1571 case 'A':
1572 if (aftrans_opt(optarg))
1573 exit(1);
1574 break;
1575 case 'M':
1576 flag_mas++;
1577 break;
1578 case 'a':
1579 flag_all++;
1580 break;
1581 case 'l':
1582 flag_lst++;
1583 break;
1584 case 'c':
1585 flag_cnt++;
1586 break;
1588 case 'd':
1589 flag_deb++;
1590 break;
1591 case 'g':
1592 flag_igmp++;
1593 break;
1594 case 'e':
1595 flag_exp++;
1596 break;
1597 case 'p':
1598 flag_prg++;
1599 break;
1600 case 'i':
1601 flag_int++;
1602 break;
1603 case 'n':
1604 flag_not |= FLAG_NUM;
1605 break;
1606 case '!':
1607 flag_not |= FLAG_NUM_HOST;
1608 break;
1609 case '@':
1610 flag_not |= FLAG_NUM_PORT;
1611 break;
1612 case '#':
1613 flag_not |= FLAG_NUM_USER;
1614 break;
1615 case 'N':
1616 flag_not |= FLAG_SYM;
1617 break;
1618 case 'C':
1619 flag_cf |= FLAG_CACHE;
1620 break;
1621 case 'F':
1622 flag_cf |= FLAG_FIB;
1623 break;
1624 case 'o':
1625 flag_opt++;
1626 break;
1627 case 'V':
1628 version();
1629 /*NOTREACHED */
1630 case 'v':
1631 flag_ver |= FLAG_VERBOSE;
1632 break;
1633 case 'r':
1634 flag_rou++;
1635 break;
1637 case 't':
1638 flag_tcp++;
1639 break;
1641 case 'u':
1642 flag_udp++;
1643 break;
1644 case 'w':
1645 flag_raw++;
1646 break;
1647 case 'x':
1648 if (aftrans_opt("unix"))
1649 exit(1);
1650 break;
1651 case '?':
1652 case 'h':
1653 usage();
1654 case 's':
1655 flag_sta++;
1658 if (flag_int + flag_rou + flag_mas + flag_sta > 1)
1659 usage();
1661 if ((flag_inet || flag_inet6 || flag_sta) && !(flag_tcp || flag_udp || flag_raw))
1662 flag_tcp = flag_udp = flag_raw = 1;
1664 if ((flag_tcp || flag_udp || flag_raw || flag_igmp) && !(flag_inet || flag_inet6))
1665 flag_inet = flag_inet6 = 1;
1667 flag_arg = flag_tcp + flag_udp + flag_raw + flag_unx + flag_ipx
1668 + flag_ax25 + flag_netrom + flag_igmp + flag_x25;
1670 if (flag_mas) {
1671 #if HAVE_FW_MASQUERADE && HAVE_AFINET
1672 #if MORE_THAN_ONE_MASQ_AF
1673 if (!afname[0])
1674 strcpy(afname, DFLT_AF);
1675 #endif
1676 for (;;) {
1677 i = ip_masq_info(flag_not & FLAG_NUM_HOST,
1678 flag_not & FLAG_NUM_PORT, flag_exp);
1679 if (i || !flag_cnt)
1680 break;
1681 sleep(1);
1683 #else
1684 ENOSUPP("netstat.c", "FW_MASQUERADE");
1685 i = -1;
1686 #endif
1687 return (i);
1690 if (flag_sta) {
1691 inittab();
1692 parsesnmp(flag_raw, flag_tcp, flag_udp);
1693 exit(0);
1696 if (flag_rou) {
1697 int options = 0;
1699 if (!afname[0])
1700 strcpy(afname, DFLT_AF);
1702 if (flag_exp == 2)
1703 flag_exp = 1;
1704 else if (flag_exp == 1)
1705 flag_exp = 2;
1707 options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
1708 if (!flag_cf)
1709 options |= FLAG_FIB;
1711 for (;;) {
1712 i = route_info(afname, options);
1713 if (i || !flag_cnt)
1714 break;
1715 sleep(1);
1717 return (i);
1719 if (flag_int) {
1720 for (;;) {
1721 i = iface_info();
1722 if (!flag_cnt || i)
1723 break;
1724 sleep(1);
1726 return (i);
1728 for (;;) {
1729 if (!flag_arg || flag_tcp || flag_udp || flag_raw) {
1730 #if HAVE_AFINET
1731 prg_cache_load();
1732 printf(_("Active Internet connections ")); /* xxx */
1734 if (flag_all)
1735 printf(_("(servers and established)"));
1736 else {
1737 if (flag_lst)
1738 printf(_("(only servers)"));
1739 else
1740 printf(_("(w/o servers)"));
1742 printf(_("\nProto Recv-Q Send-Q Local Address Foreign Address State ")); /* xxx */
1743 if (flag_exp > 1)
1744 printf(_(" User Inode "));
1745 print_progname_banner();
1746 if (flag_opt)
1747 printf(_(" Timer")); /* xxx */
1748 printf("\n");
1749 #else
1750 if (flag_arg) {
1751 i = 1;
1752 ENOSUPP("netstat", "AF INET");
1754 #endif
1756 #if HAVE_AFINET
1757 if (!flag_arg || flag_tcp) {
1758 i = tcp_info();
1759 if (i)
1760 return (i);
1762 if (!flag_arg || flag_udp) {
1763 i = udp_info();
1764 if (i)
1765 return (i);
1767 if (!flag_arg || flag_raw) {
1768 i = raw_info();
1769 if (i)
1770 return (i);
1773 if (flag_igmp) {
1774 #if HAVE_AFINET6
1775 printf( "IPv6/");
1776 #endif
1777 printf( _("IPv4 Group Memberships\n") );
1778 printf( _("Interface RefCnt Group\n") );
1779 printf( "--------------- ------ ---------------------\n" );
1780 i = igmp_info();
1781 if (i)
1782 return (i);
1784 #endif
1786 if (!flag_arg || flag_unx) {
1787 #if HAVE_AFUNIX
1788 prg_cache_load();
1789 i = unix_info();
1790 if (i)
1791 return (i);
1792 #else
1793 if (flag_arg) {
1794 i = 1;
1795 ENOSUPP("netstat", "AF UNIX");
1797 #endif
1799 if (!flag_arg || flag_ipx) {
1800 #if HAVE_AFIPX
1801 i = ipx_info();
1802 if (i)
1803 return (i);
1804 #else
1805 if (flag_arg) {
1806 i = 1;
1807 ENOSUPP("netstat", "AF IPX");
1809 #endif
1811 if (!flag_arg || flag_ax25) {
1812 #if HAVE_AFAX25
1813 i = ax25_info();
1814 if (i)
1815 return (i);
1816 #else
1817 if (flag_arg) {
1818 i = 1;
1819 ENOSUPP("netstat", "AF AX25");
1821 #endif
1823 if(!flag_arg || flag_x25) {
1824 #if HAVE_AFX25
1825 /* FIXME */
1826 i = x25_info();
1827 if (i)
1828 return(i);
1829 #else
1830 if (flag_arg) {
1831 i = 1;
1832 ENOSUPP("netstat", "AF X25");
1834 #endif
1836 if (!flag_arg || flag_netrom) {
1837 #if HAVE_AFNETROM
1838 i = netrom_info();
1839 if (i)
1840 return (i);
1841 #else
1842 if (flag_arg) {
1843 i = 1;
1844 ENOSUPP("netstat", "AF NETROM");
1846 #endif
1848 if (!flag_cnt || i)
1849 break;
1850 sleep(1);
1851 prg_cache_clear();
1853 return (i);