simple patch from Ajax <ajax@firest0rm.org> (corrected) to print DDP
[oss-qm-packages.git] / netstat.c
blobfe4f620c888caceb6dd06d3b5da4a9cf929797e0
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.47 2002/02/19 01:12:49 ecki 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 unsigned long 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(unsigned long 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(unsigned long 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 int extract_type_1_socket_inode(const char lname[], unsigned 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) return(-1);
306 if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) return(-1);
307 if (lname[strlen(lname)-1] != ']') return(-1);
310 char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
311 const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
312 char *serr;
314 strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
315 inode_str[inode_str_len] = '\0';
316 *inode_p = strtol(inode_str,&serr,0);
317 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
318 return(-1);
320 return(0);
325 static int extract_type_2_socket_inode(const char lname[], unsigned long * inode_p) {
327 /* If lname is of the form "[0000]:12345", extract the "12345"
328 as *inode_p. Otherwise, return -1 as *inode_p.
331 if (strlen(lname) < PRG_SOCKET_PFX2l+1) return(-1);
332 if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) return(-1);
335 char *serr;
337 *inode_p=strtol(lname + PRG_SOCKET_PFX2l,&serr,0);
338 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
339 return(-1);
341 return(0);
347 static void prg_cache_load(void)
349 char line[LINE_MAX],eacces=0;
350 int procfdlen,fd,cmdllen,lnamelen;
351 char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH];
352 unsigned long inode;
353 const char *cs,*cmdlp;
354 DIR *dirproc=NULL,*dirfd=NULL;
355 struct dirent *direproc,*direfd;
357 if (prg_cache_loaded || !flag_prg) return;
358 prg_cache_loaded=1;
359 cmdlbuf[sizeof(cmdlbuf)-1]='\0';
360 if (!(dirproc=opendir(PATH_PROC))) goto fail;
361 while (errno=0,direproc=readdir(dirproc)) {
362 #ifdef DIRENT_HAVE_D_TYPE_WORKS
363 if (direproc->d_type!=DT_DIR) continue;
364 #endif
365 for (cs=direproc->d_name;*cs;cs++)
366 if (!isdigit(*cs))
367 break;
368 if (*cs)
369 continue;
370 procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
371 if (procfdlen<=0 || procfdlen>=sizeof(line)-5)
372 continue;
373 errno=0;
374 dirfd=opendir(line);
375 if (! dirfd) {
376 if (errno==EACCES)
377 eacces=1;
378 continue;
380 line[procfdlen] = '/';
381 cmdlp = NULL;
382 while ((direfd = readdir(dirfd))) {
383 #ifdef DIRENT_HAVE_D_TYPE_WORKS
384 if (direfd->d_type!=DT_LNK)
385 continue;
386 #endif
387 if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line))
388 continue;
389 memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
390 PATH_FD_SUFFl+1);
391 strcpy(line + procfdlen + 1, direfd->d_name);
392 lnamelen=readlink(line,lname,sizeof(lname)-1);
393 lname[lnamelen] = '\0'; /*make it a null-terminated string*/
395 if (extract_type_1_socket_inode(lname, &inode) < 0)
396 if (extract_type_2_socket_inode(lname, &inode) < 0)
397 continue;
399 if (!cmdlp) {
400 if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
401 sizeof(line) - 5)
402 continue;
403 strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
404 fd = open(line, O_RDONLY);
405 if (fd < 0)
406 continue;
407 cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
408 if (close(fd))
409 continue;
410 if (cmdllen == -1)
411 continue;
412 if (cmdllen < sizeof(cmdlbuf) - 1)
413 cmdlbuf[cmdllen]='\0';
414 if ((cmdlp = strrchr(cmdlbuf, '/')))
415 cmdlp++;
416 else
417 cmdlp = cmdlbuf;
420 snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
421 prg_cache_add(inode, finbuf);
423 closedir(dirfd);
424 dirfd = NULL;
426 if (dirproc)
427 closedir(dirproc);
428 if (dirfd)
429 closedir(dirfd);
430 if (!eacces)
431 return;
432 if (prg_cache_loaded == 1) {
433 fail:
434 fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
435 geteuid());
437 else
438 fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
439 " will not be shown, you would have to be root to see it all.)\n"));
442 #if HAVE_AFNETROM
443 static const char *netrom_state[] =
445 N_("LISTENING"),
446 N_("CONN SENT"),
447 N_("DISC SENT"),
448 N_("ESTABLISHED")
451 static int netrom_info(void)
453 FILE *f;
454 char buffer[256], dev[16];
455 int st, vs, vr, sendq, recvq, ret;
457 f = fopen(_PATH_PROCNET_NR, "r");
458 if (f == NULL) {
459 if (errno != ENOENT) {
460 perror(_PATH_PROCNET_NR);
461 return (-1);
463 if (flag_arg || flag_ver)
464 ESYSNOT("netstat", "AF NETROM");
465 if (flag_arg)
466 return (1);
467 else
468 return (0);
470 printf(_("Active NET/ROM sockets\n"));
471 printf(_("User Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
472 fgets(buffer, 256, f);
474 while (fgets(buffer, 256, f)) {
475 buffer[9] = 0;
476 buffer[19] = 0;
477 buffer[29] = 0;
478 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",
479 dev, &st, &vs, &vr, &sendq, &recvq);
480 if (ret != 6) {
481 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
482 continue;
484 printf("%-9s %-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
485 buffer, buffer + 10, buffer + 20,
486 dev,
487 _(netrom_state[st]),
488 vr, vs, sendq, recvq);
490 fclose(f);
491 return 0;
493 #endif
495 /* These enums are used by IPX too. :-( */
496 enum {
497 TCP_ESTABLISHED = 1,
498 TCP_SYN_SENT,
499 TCP_SYN_RECV,
500 TCP_FIN_WAIT1,
501 TCP_FIN_WAIT2,
502 TCP_TIME_WAIT,
503 TCP_CLOSE,
504 TCP_CLOSE_WAIT,
505 TCP_LAST_ACK,
506 TCP_LISTEN,
507 TCP_CLOSING /* now a valid state */
510 #if HAVE_AFINET || HAVE_AFINET6
512 static const char *tcp_state[] =
515 N_("ESTABLISHED"),
516 N_("SYN_SENT"),
517 N_("SYN_RECV"),
518 N_("FIN_WAIT1"),
519 N_("FIN_WAIT2"),
520 N_("TIME_WAIT"),
521 N_("CLOSE"),
522 N_("CLOSE_WAIT"),
523 N_("LAST_ACK"),
524 N_("LISTEN"),
525 N_("CLOSING")
528 static void finish_this_one(int uid, unsigned long inode, const char *timers)
530 struct passwd *pw;
532 if (flag_exp > 1) {
533 if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
534 printf("%-10s ", pw->pw_name);
535 else
536 printf("%-10d ", uid);
537 printf("%-10lu ",inode);
539 if (flag_prg)
540 printf("%-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
541 if (flag_opt)
542 printf("%s", timers);
543 putchar('\n');
546 static void igmp_do_one(int lnr, const char *line)
548 char mcast_addr[128];
549 #if HAVE_AFINET6
550 struct sockaddr_in6 mcastaddr;
551 char addr6[INET6_ADDRSTRLEN];
552 struct in6_addr in6;
553 extern struct aftype inet6_aftype;
554 #else
555 struct sockaddr_in mcastaddr;
556 #endif
557 struct aftype *ap;
558 static int idx_flag = 0;
559 static int igmp6_flag = 0;
560 static char device[16];
561 int num, idx, refcnt;
563 if (lnr == 0) {
564 /* IPV6 ONLY */
565 /* igmp6 file does not have any comments on first line */
566 if ( strstr( line, "Device" ) == NULL ) {
567 igmp6_flag = 1;
568 } else {
569 /* IPV4 ONLY */
570 /* 2.1.x kernels and up have Idx field */
571 /* 2.0.x and below do not have Idx field */
572 if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
573 idx_flag = 1;
574 else
575 idx_flag = 0;
576 return;
580 if (igmp6_flag) { /* IPV6 */
581 #if HAVE_AFINET6
582 num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
583 if (num == 4) {
584 /* Demangle what the kernel gives us */
585 sscanf(mcast_addr, "%08X%08X%08X%08X",
586 &in6.s6_addr32[0], &in6.s6_addr32[1],
587 &in6.s6_addr32[2], &in6.s6_addr32[3]);
588 in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
589 in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
590 in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
591 in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
592 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
593 inet6_aftype.input(1, addr6, (struct sockaddr *) &mcastaddr);
594 mcastaddr.sin6_family = AF_INET6;
595 } else {
596 fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
597 return;
600 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
601 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
602 ((struct sockaddr *) &mcastaddr)->sa_family);
603 return;
605 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
606 flag_not), sizeof(mcast_addr));
607 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
608 #endif
609 } else { /* IPV4 */
610 #if HAVE_AFINET
611 if (line[0] != '\t') {
612 if (idx_flag) {
613 if ((num = sscanf( line, "%d\t%10c", &idx, device)) < 2) {
614 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
615 return;
617 } else {
618 if ( (num = sscanf( line, "%10c", device )) < 1 ) {
619 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
620 return;
623 device[10] = '\0';
624 return;
625 } else if ( line[0] == '\t' ) {
626 if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
627 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
628 return;
630 sscanf( mcast_addr, "%X",
631 &((struct sockaddr_in *) &mcastaddr)->sin_addr.s_addr );
632 ((struct sockaddr *) &mcastaddr)->sa_family = AF_INET;
633 } else {
634 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
635 return;
638 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
639 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
640 ((struct sockaddr *) &mcastaddr)->sa_family);
641 return;
643 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
644 flag_not), sizeof(mcast_addr));
645 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
646 #endif
647 } /* IPV4 */
650 #if HAVE_AFX25
651 static int x25_info(void)
653 FILE *f=fopen(_PATH_PROCNET_X25, "r");
654 char buffer[256],dev[16];
655 int st,vs,vr,sendq,recvq,lci;
656 static char *x25_state[5]=
658 "LISTENING",
659 "SABM_SENT",
660 "DISC_SENT",
661 "ESTABLISHED",
662 "RECOVERY"
664 if(!(f=fopen(_PATH_PROCNET_X25, "r")))
666 if (errno != ENOENT) {
667 perror(_PATH_PROCNET_X25);
668 return(-1);
670 if (flag_arg || flag_ver)
671 ESYSNOT("netstat","AF X25");
672 if (flag_arg)
673 return(1);
674 else
675 return(0);
677 printf( _("Active X.25 sockets\n"));
678 /* IMHO, Vr/Vs is not very usefull --SF */
679 printf( _("Dest Source Device LCI State Vr/Vs Send-Q Recv-Q\n"));
680 fgets(buffer,256,f);
681 while(fgets(buffer,256,f))
683 buffer[10]=0;
684 buffer[20]=0;
685 sscanf(buffer+22,"%s %d %d %d %d %*d %*d %*d %*d %*d %*d %d %d %*d",
686 dev,&lci,&st,&vs,&vr,&sendq,&recvq);
687 if (!(flag_all || lci))
688 continue;
689 printf("%-15s %-15s %-7s %-3d %-11s %02d/%02d %-6d %-6d\n",
690 buffer,buffer+11,
691 dev,
692 lci,
693 x25_state[st],
694 vr,vs,sendq,recvq);
696 fclose(f);
697 return 0;
699 #endif
701 static int igmp_info(void)
703 INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
704 igmp_do_one);
707 static void tcp_do_one(int lnr, const char *line)
709 unsigned long rxq, txq, time_len, retr, inode;
710 int num, local_port, rem_port, d, state, uid, timer_run, timeout;
711 char rem_addr[128], local_addr[128], timers[64], buffer[1024], more[512];
712 struct aftype *ap;
713 #if HAVE_AFINET6
714 struct sockaddr_in6 localaddr, remaddr;
715 char addr6[INET6_ADDRSTRLEN];
716 struct in6_addr in6;
717 extern struct aftype inet6_aftype;
718 #else
719 struct sockaddr_in localaddr, remaddr;
720 #endif
722 if (lnr == 0)
723 return;
725 num = sscanf(line,
726 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %512s\n",
727 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
728 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
730 if (strlen(local_addr) > 8) {
731 #if HAVE_AFINET6
732 /* Demangle what the kernel gives us */
733 sscanf(local_addr, "%08X%08X%08X%08X",
734 &in6.s6_addr32[0], &in6.s6_addr32[1],
735 &in6.s6_addr32[2], &in6.s6_addr32[3]);
736 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
737 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
738 sscanf(rem_addr, "%08X%08X%08X%08X",
739 &in6.s6_addr32[0], &in6.s6_addr32[1],
740 &in6.s6_addr32[2], &in6.s6_addr32[3]);
741 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
742 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
743 localaddr.sin6_family = AF_INET6;
744 remaddr.sin6_family = AF_INET6;
745 #endif
746 } else {
747 sscanf(local_addr, "%X",
748 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
749 sscanf(rem_addr, "%X",
750 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
751 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
752 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
755 if (num < 11) {
756 fprintf(stderr, _("warning, got bogus tcp line.\n"));
757 return;
759 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
760 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
761 ((struct sockaddr *) &localaddr)->sa_family);
762 return;
764 if (state == TCP_LISTEN) {
765 time_len = 0;
766 retr = 0L;
767 rxq = 0L;
768 txq = 0L;
770 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
771 flag_not), sizeof(local_addr));
772 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr, flag_not),
773 sizeof(rem_addr));
774 if (flag_all || (flag_lst && !rem_port) || (!flag_lst && rem_port)) {
775 snprintf(buffer, sizeof(buffer), "%s",
776 get_sname(htons(local_port), "tcp",
777 flag_not & FLAG_NUM_PORT));
779 if ((strlen(local_addr) + strlen(buffer)) > 22)
780 local_addr[22 - strlen(buffer)] = '\0';
782 strcat(local_addr, ":");
783 strcat(local_addr, buffer);
784 snprintf(buffer, sizeof(buffer), "%s",
785 get_sname(htons(rem_port), "tcp", flag_not & FLAG_NUM_PORT));
787 if ((strlen(rem_addr) + strlen(buffer)) > 22)
788 rem_addr[22 - strlen(buffer)] = '\0';
790 strcat(rem_addr, ":");
791 strcat(rem_addr, buffer);
792 timers[0] = '\0';
794 if (flag_opt)
795 switch (timer_run) {
796 case 0:
797 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
798 break;
800 case 1:
801 snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
802 (double) time_len / HZ, retr, timeout);
803 break;
805 case 2:
806 snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
807 (double) time_len / HZ, retr, timeout);
808 break;
810 case 3:
811 snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
812 (double) time_len / HZ, retr, timeout);
813 break;
815 default:
816 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
817 timer_run, (double) time_len / HZ, retr, timeout);
818 break;
820 printf("tcp %6ld %6ld %-*s %-*s %-12s",
821 rxq, txq, max(23,strlen(local_addr)+1), local_addr, max(23,strlen(rem_addr)), rem_addr, _(tcp_state[state]));
823 finish_this_one(uid,inode,timers);
827 static int tcp_info(void)
829 INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
830 tcp_do_one);
833 static void udp_do_one(int lnr, const char *line)
835 char buffer[8192], local_addr[64], rem_addr[64];
836 char *udp_state, timers[64], more[512];
837 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
838 #if HAVE_AFINET6
839 struct sockaddr_in6 localaddr, remaddr;
840 char addr6[INET6_ADDRSTRLEN];
841 struct in6_addr in6;
842 extern struct aftype inet6_aftype;
843 #else
844 struct sockaddr_in localaddr, remaddr;
845 #endif
846 struct aftype *ap;
847 unsigned long rxq, txq, time_len, retr, inode;
849 if (lnr == 0)
850 return;
852 more[0] = '\0';
853 num = sscanf(line,
854 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %512s\n",
855 &d, local_addr, &local_port,
856 rem_addr, &rem_port, &state,
857 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
859 if (strlen(local_addr) > 8) {
860 #if HAVE_AFINET6
861 sscanf(local_addr, "%08X%08X%08X%08X",
862 &in6.s6_addr32[0], &in6.s6_addr32[1],
863 &in6.s6_addr32[2], &in6.s6_addr32[3]);
864 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
865 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
866 sscanf(rem_addr, "%08X%08X%08X%08X",
867 &in6.s6_addr32[0], &in6.s6_addr32[1],
868 &in6.s6_addr32[2], &in6.s6_addr32[3]);
869 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
870 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
871 localaddr.sin6_family = AF_INET6;
872 remaddr.sin6_family = AF_INET6;
873 #endif
874 } else {
875 sscanf(local_addr, "%X",
876 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
877 sscanf(rem_addr, "%X",
878 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
879 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
880 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
883 retr = 0L;
884 if (!flag_opt)
885 more[0] = '\0';
887 if (num < 10) {
888 fprintf(stderr, _("warning, got bogus udp line.\n"));
889 return;
891 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
892 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
893 ((struct sockaddr *) &localaddr)->sa_family);
894 return;
896 switch (state) {
897 case TCP_ESTABLISHED:
898 udp_state = _("ESTABLISHED");
899 break;
901 case TCP_CLOSE:
902 udp_state = "";
903 break;
905 default:
906 udp_state = _("UNKNOWN");
907 break;
910 #if HAVE_AFINET6
911 #define notnull(A) (((A.sin6_family == AF_INET6) && \
912 ((A.sin6_addr.s6_addr32[0]) || \
913 (A.sin6_addr.s6_addr32[1]) || \
914 (A.sin6_addr.s6_addr32[2]) || \
915 (A.sin6_addr.s6_addr32[3]))) || \
916 ((A.sin6_family == AF_INET) && \
917 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
918 #else
919 #define notnull(A) (A.sin_addr.s_addr)
920 #endif
922 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
924 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
925 flag_not), sizeof(local_addr));
926 snprintf(buffer, sizeof(buffer), "%s",
927 get_sname(htons(local_port), "udp",
928 flag_not & FLAG_NUM_PORT));
929 if ((strlen(local_addr) + strlen(buffer)) > 22)
930 local_addr[22 - strlen(buffer)] = '\0';
931 strcat(local_addr, ":");
932 strcat(local_addr, buffer);
934 snprintf(buffer, sizeof(buffer), "%s",
935 get_sname(htons(rem_port), "udp", flag_not & FLAG_NUM_PORT));
936 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
937 flag_not), sizeof(rem_addr));
938 if ((strlen(rem_addr) + strlen(buffer)) > 22)
939 rem_addr[22 - strlen(buffer)] = '\0';
940 strcat(rem_addr, ":");
941 strcat(rem_addr, buffer);
943 timers[0] = '\0';
944 if (flag_opt)
945 switch (timer_run) {
946 case 0:
947 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
948 break;
950 case 1:
951 case 2:
952 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
953 break;
955 default:
956 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
957 retr, timeout);
958 break;
960 printf("udp %6ld %6ld %-23s %-23s %-12s",
961 rxq, txq, local_addr, rem_addr, udp_state);
963 finish_this_one(uid,inode,timers);
967 static int udp_info(void)
969 INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
970 udp_do_one);
973 static void raw_do_one(int lnr, const char *line)
975 char buffer[8192], local_addr[64], rem_addr[64];
976 char timers[64], more[512];
977 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
978 #if HAVE_AFINET6
979 struct sockaddr_in6 localaddr, remaddr;
980 char addr6[INET6_ADDRSTRLEN];
981 struct in6_addr in6;
982 extern struct aftype inet6_aftype;
983 #else
984 struct sockaddr_in localaddr, remaddr;
985 #endif
986 struct aftype *ap;
987 unsigned long rxq, txq, time_len, retr, inode;
989 if (lnr == 0)
990 return;
992 more[0] = '\0';
993 num = sscanf(line,
994 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %512s\n",
995 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
996 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
998 if (strlen(local_addr) > 8) {
999 #if HAVE_AFINET6
1000 sscanf(local_addr, "%08X%08X%08X%08X",
1001 &in6.s6_addr32[0], &in6.s6_addr32[1],
1002 &in6.s6_addr32[2], &in6.s6_addr32[3]);
1003 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1004 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
1005 sscanf(rem_addr, "%08X%08X%08X%08X",
1006 &in6.s6_addr32[0], &in6.s6_addr32[1],
1007 &in6.s6_addr32[2], &in6.s6_addr32[3]);
1008 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
1009 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
1010 localaddr.sin6_family = AF_INET6;
1011 remaddr.sin6_family = AF_INET6;
1012 #endif
1013 } else {
1014 sscanf(local_addr, "%X",
1015 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1016 sscanf(rem_addr, "%X",
1017 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1018 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1019 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1021 #if HAVE_AFINET6
1022 if ((ap = get_afntype(localaddr.sin6_family)) == NULL) {
1023 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin6_family);
1024 return;
1026 #else
1027 if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
1028 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin_family);
1029 return;
1031 #endif
1033 if (!flag_opt)
1034 more[0] = '\0';
1036 if (num < 10) {
1037 fprintf(stderr, _("warning, got bogus raw line.\n"));
1038 return;
1041 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1043 snprintf(buffer, sizeof(buffer), "%s",
1044 get_sname(htons(local_port), "raw",
1045 flag_not & FLAG_NUM_PORT));
1046 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
1047 flag_not), sizeof(local_addr));
1048 if ((strlen(local_addr) + strlen(buffer)) > 22)
1049 local_addr[22 - strlen(buffer)] = '\0';
1050 strcat(local_addr, ":");
1051 strcat(local_addr, buffer);
1053 snprintf(buffer, sizeof(buffer), "%s",
1054 get_sname(htons(rem_port), "raw", flag_not & FLAG_NUM_PORT));
1055 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
1056 flag_not), sizeof(rem_addr));
1057 if ((strlen(rem_addr) + strlen(buffer)) > 22)
1058 rem_addr[22 - strlen(buffer)] = '\0';
1059 strcat(rem_addr, ":");
1060 strcat(rem_addr, buffer);
1062 timers[0] = '\0';
1063 if (flag_opt)
1064 switch (timer_run) {
1065 case 0:
1066 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1067 break;
1069 case 1:
1070 case 2:
1071 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1072 retr, timeout);
1073 break;
1075 default:
1076 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
1077 timer_run, (double) time_len / 100,
1078 retr, timeout);
1079 break;
1081 printf("raw %6ld %6ld %-23s %-23s %-12d",
1082 rxq, txq, local_addr, rem_addr, state);
1084 finish_this_one(uid,inode,timers);
1088 static int raw_info(void)
1090 INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
1091 raw_do_one);
1094 #endif
1097 #if HAVE_AFUNIX
1099 #define HAS_INODE 1
1101 static void unix_do_one(int nr, const char *line)
1103 static int has = 0;
1104 char path[MAXPATHLEN], ss_flags[32];
1105 char *ss_proto, *ss_state, *ss_type;
1106 int num, state, type;
1107 void *d;
1108 unsigned long refcnt, proto, flags, inode;
1110 if (nr == 0) {
1111 if (strstr(line, "Inode"))
1112 has |= HAS_INODE;
1113 return;
1115 path[0] = '\0';
1116 num = sscanf(line, "%p: %lX %lX %lX %X %X %lu %s",
1117 &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
1118 if (num < 6) {
1119 fprintf(stderr, _("warning, got bogus unix line.\n"));
1120 return;
1122 if (!(has & HAS_INODE))
1123 snprintf(path,sizeof(path),"%lu",inode);
1125 if (!flag_all) {
1126 if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
1127 if (!flag_lst)
1128 return;
1129 } else {
1130 if (flag_lst)
1131 return;
1135 switch (proto) {
1136 case 0:
1137 ss_proto = "unix";
1138 break;
1140 default:
1141 ss_proto = "??";
1144 switch (type) {
1145 case SOCK_STREAM:
1146 ss_type = _("STREAM");
1147 break;
1149 case SOCK_DGRAM:
1150 ss_type = _("DGRAM");
1151 break;
1153 case SOCK_RAW:
1154 ss_type = _("RAW");
1155 break;
1157 case SOCK_RDM:
1158 ss_type = _("RDM");
1159 break;
1161 case SOCK_SEQPACKET:
1162 ss_type = _("SEQPACKET");
1163 break;
1165 default:
1166 ss_type = _("UNKNOWN");
1169 switch (state) {
1170 case SS_FREE:
1171 ss_state = _("FREE");
1172 break;
1174 case SS_UNCONNECTED:
1176 * Unconnected sockets may be listening
1177 * for something.
1179 if (flags & SO_ACCEPTCON) {
1180 ss_state = _("LISTENING");
1181 } else {
1182 ss_state = "";
1184 break;
1186 case SS_CONNECTING:
1187 ss_state = _("CONNECTING");
1188 break;
1190 case SS_CONNECTED:
1191 ss_state = _("CONNECTED");
1192 break;
1194 case SS_DISCONNECTING:
1195 ss_state = _("DISCONNECTING");
1196 break;
1198 default:
1199 ss_state = _("UNKNOWN");
1202 strcpy(ss_flags, "[ ");
1203 if (flags & SO_ACCEPTCON)
1204 strcat(ss_flags, "ACC ");
1205 if (flags & SO_WAITDATA)
1206 strcat(ss_flags, "W ");
1207 if (flags & SO_NOSPACE)
1208 strcat(ss_flags, "N ");
1210 strcat(ss_flags, "]");
1212 printf("%-5s %-6ld %-11s %-10s %-13s ",
1213 ss_proto, refcnt, ss_flags, ss_type, ss_state);
1214 if (has & HAS_INODE)
1215 printf("%-8lu ",inode);
1216 else
1217 printf("- ");
1218 if (flag_prg)
1219 printf("%-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
1220 puts(path);
1223 static int unix_info(void)
1226 printf(_("Active UNIX domain sockets "));
1227 if (flag_all)
1228 printf(_("(servers and established)"));
1229 else {
1230 if (flag_lst)
1231 printf(_("(only servers)"));
1232 else
1233 printf(_("(w/o servers)"));
1236 printf(_("\nProto RefCnt Flags Type State I-Node"));
1237 print_progname_banner();
1238 printf(_(" Path\n")); /* xxx */
1241 INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
1244 #endif
1247 #if HAVE_AFAX25
1248 static int ax25_info(void)
1250 FILE *f;
1251 char buffer[256], buf[16];
1252 char *src, *dst, *dev, *p;
1253 int st, vs, vr, sendq, recvq, ret;
1254 int new = -1; /* flag for new (2.1.x) kernels */
1255 static char *ax25_state[5] =
1257 N_("LISTENING"),
1258 N_("SABM SENT"),
1259 N_("DISC SENT"),
1260 N_("ESTABLISHED"),
1261 N_("RECOVERY")
1263 if (!(f = fopen(_PATH_PROCNET_AX25, "r"))) {
1264 if (errno != ENOENT) {
1265 perror(_PATH_PROCNET_AX25);
1266 return (-1);
1268 if (flag_arg || flag_ver)
1269 ESYSNOT("netstat", "AF AX25");
1270 if (flag_arg)
1271 return (1);
1272 else
1273 return (0);
1275 printf(_("Active AX.25 sockets\n"));
1276 printf(_("Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
1277 while (fgets(buffer, 256, f)) {
1278 if (new == -1) {
1279 if (!strncmp(buffer, "dest_addr", 9)) {
1280 new = 0;
1281 continue; /* old kernels have a header line */
1282 } else
1283 new = 1;
1286 * In a network connection with no user socket the Snd-Q, Rcv-Q
1287 * and Inode fields are empty in 2.0.x and '*' in 2.1.x
1289 sendq = 0;
1290 recvq = 0;
1291 if (new == 0) {
1292 dst = buffer;
1293 src = buffer + 10;
1294 dst[9] = 0;
1295 src[9] = 0;
1296 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",
1297 buf, &st, &vs, &vr, &sendq, &recvq);
1298 if (ret != 4 && ret != 6) {
1299 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
1300 continue;
1302 dev = buf;
1303 } else {
1304 p = buffer;
1305 while (*p != ' ') p++;
1306 p++;
1307 dev = p;
1308 while (*p != ' ') p++;
1309 *p++ = 0;
1310 src = p;
1311 while (*p != ' ') p++;
1312 *p++ = 0;
1313 dst = p;
1314 while (*p != ' ') p++;
1315 *p++ = 0;
1316 ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
1317 &st, &vs, &vr, &sendq, &recvq);
1318 if (ret != 3 && ret != 5) {
1319 printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
1320 continue;
1323 * FIXME: digipeaters should be handled somehow.
1324 * For now we just strip them.
1326 p = dst;
1327 while (*p && *p != ',') p++;
1328 *p = 0;
1330 printf("%-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
1331 dst, src,
1332 dev,
1333 _(ax25_state[st]),
1334 vr, vs, sendq, recvq);
1336 fclose(f);
1337 return 0;
1339 #endif
1342 #if HAVE_AFIPX
1343 static int ipx_info(void)
1345 FILE *f;
1346 char buf[256];
1347 unsigned long txq, rxq;
1348 unsigned int state;
1349 unsigned int uid;
1350 char *st;
1351 int nc;
1352 struct aftype *ap;
1353 struct passwd *pw;
1354 char sad[50], dad[50];
1355 struct sockaddr sa;
1356 unsigned sport = 0, dport = 0;
1358 if (!(f = fopen(_PATH_PROCNET_IPX, "r"))) {
1359 if (errno != ENOENT) {
1360 perror(_PATH_PROCNET_IPX);
1361 return (-1);
1363 if (flag_arg || flag_ver)
1364 ESYSNOT("netstat", "AF IPX");
1365 if (flag_arg)
1366 return (1);
1367 else
1368 return (0);
1370 printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address Foreign Address State")); /* xxx */
1371 if (flag_exp > 1)
1372 printf(_(" User")); /* xxx */
1373 printf("\n");
1374 if ((ap = get_afntype(AF_IPX)) == NULL) {
1375 EINTERN("netstat.c", "AF_IPX missing");
1376 return (-1);
1378 fgets(buf, 255, f);
1380 while (fgets(buf, 255, f) != NULL) {
1381 sscanf(buf, "%s %s %lX %lX %d %d",
1382 sad, dad, &txq, &rxq, &state, &uid);
1383 if ((st = rindex(sad, ':'))) {
1384 *st++ = '\0';
1385 sscanf(st, "%X", &sport); /* net byt order */
1386 sport = ntohs(sport);
1387 } else {
1388 EINTERN("netstat.c", _PATH_PROCNET_IPX " sport format error");
1389 return (-1);
1391 nc = 0;
1392 if (strcmp(dad, "Not_Connected") != 0) {
1393 if ((st = rindex(dad, ':'))) {
1394 *st++ = '\0';
1395 sscanf(st, "%X", &dport); /* net byt order */
1396 dport = ntohs(dport);
1397 } else {
1398 EINTERN("netstat.c", _PATH_PROCNET_IPX " dport format error");
1399 return (-1);
1401 } else
1402 nc = 1;
1404 switch (state) {
1405 case TCP_ESTABLISHED:
1406 st = _("ESTAB");
1407 break;
1409 case TCP_CLOSE:
1410 st = "";
1411 break;
1413 default:
1414 st = _("UNK.");
1415 break;
1418 /* Fetch and resolve the Source */
1419 (void) ap->input(4, sad, &sa);
1420 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1421 snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
1423 if (!nc) {
1424 /* Fetch and resolve the Destination */
1425 (void) ap->input(4, dad, &sa);
1426 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1427 snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
1428 } else
1429 strcpy(dad, "-");
1431 printf("IPX %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
1432 if (flag_exp > 1) {
1433 if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
1434 printf(" %-10s", pw->pw_name);
1435 else
1436 printf(" %-10d", uid);
1438 printf("\n");
1440 fclose(f);
1441 return 0;
1443 #endif
1445 static int iface_info(void)
1447 if (skfd < 0) {
1448 if ((skfd = sockets_open(0)) < 0) {
1449 perror("socket");
1450 exit(1);
1452 printf(_("Kernel Interface table\n"));
1454 if (flag_exp < 2) {
1455 ife_short = 1;
1456 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
1459 if (for_all_interfaces(do_if_print, &flag_all) < 0) {
1460 perror(_("missing interface information"));
1461 exit(1);
1463 if (flag_cnt)
1464 if_cache_free();
1465 else {
1466 close(skfd);
1467 skfd = -1;
1470 return 0;
1474 static void version(void)
1476 printf("%s\n%s\n%s\n%s\n", Release, Version, Signature, Features);
1477 exit(E_VERSION);
1481 static void usage(void)
1483 fprintf(stderr, _("usage: netstat [-veenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}\n"));
1484 fprintf(stderr, _(" netstat [-vnNcaeol] [<Socket> ...]\n"));
1485 fprintf(stderr, _(" netstat { [-veenNac] -i | [-cnNe] -M | -s }\n\n"));
1487 fprintf(stderr, _(" -r, --route display routing table\n"));
1488 fprintf(stderr, _(" -i, --interfaces display interface table\n"));
1489 fprintf(stderr, _(" -g, --groups display multicast group memberships\n"));
1490 fprintf(stderr, _(" -s, --statistics display networking statistics (like SNMP)\n"));
1491 #if HAVE_FW_MASQUERADE
1492 fprintf(stderr, _(" -M, --masquerade display masqueraded connections\n\n"));
1493 #endif
1494 fprintf(stderr, _(" -v, --verbose be verbose\n"));
1495 fprintf(stderr, _(" -n, --numeric don't resolve names\n"));
1496 fprintf(stderr, _(" --numeric-hosts don't resolve host names\n"));
1497 fprintf(stderr, _(" --numeric-ports don't resolve port names\n"));
1498 fprintf(stderr, _(" --numeric-users don't resolve user names\n"));
1499 fprintf(stderr, _(" -N, --symbolic resolve hardware names\n"));
1500 fprintf(stderr, _(" -e, --extend display other/more information\n"));
1501 fprintf(stderr, _(" -p, --programs display PID/Program name for sockets\n"));
1502 fprintf(stderr, _(" -c, --continuous continuous listing\n\n"));
1503 fprintf(stderr, _(" -l, --listening display listening server sockets\n"));
1504 fprintf(stderr, _(" -a, --all, --listening display all sockets (default: connected)\n"));
1505 fprintf(stderr, _(" -o, --timers display timers\n"));
1506 fprintf(stderr, _(" -F, --fib display Forwarding Information Base (default)\n"));
1507 fprintf(stderr, _(" -C, --cache display routing cache instead of FIB\n\n"));
1509 fprintf(stderr, _(" <Socket>={-t|--tcp} {-u|--udp} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
1510 fprintf(stderr, _(" <AF>=Use '-A <af>' or '--<af>'; default: %s\n"), DFLT_AF);
1511 fprintf(stderr, _(" List of possible address families (which support routing):\n"));
1512 print_aflist(1); /* 1 = routeable */
1513 exit(E_USAGE);
1517 int main
1518 (int argc, char *argv[]) {
1519 int i;
1520 int lop;
1521 static struct option longopts[] =
1523 AFTRANS_OPTS,
1524 {"version", 0, 0, 'V'},
1525 {"interfaces", 0, 0, 'i'},
1526 {"help", 0, 0, 'h'},
1527 {"route", 0, 0, 'r'},
1528 #if HAVE_FW_MASQUERADE
1529 {"masquerade", 0, 0, 'M'},
1530 #endif
1531 {"protocol", 1, 0, 'A'},
1532 {"tcp", 0, 0, 't'},
1533 {"udp", 0, 0, 'u'},
1534 {"raw", 0, 0, 'w'},
1535 {"unix", 0, 0, 'x'},
1536 {"listening", 0, 0, 'l'},
1537 {"all", 0, 0, 'a'},
1538 {"timers", 0, 0, 'o'},
1539 {"continuous", 0, 0, 'c'},
1540 {"extend", 0, 0, 'e'},
1541 {"programs", 0, 0, 'p'},
1542 {"verbose", 0, 0, 'v'},
1543 {"statistics", 0, 0, 's'},
1544 {"numeric", 0, 0, 'n'},
1545 {"numeric-hosts", 0, 0, '!'},
1546 {"numeric-ports", 0, 0, '@'},
1547 {"numeric-users", 0, 0, '#'},
1548 {"symbolic", 0, 0, 'N'},
1549 {"cache", 0, 0, 'C'},
1550 {"fib", 0, 0, 'F'},
1551 {"groups", 0, 0, 'g'},
1552 {NULL, 0, 0, 0}
1555 #if I18N
1556 setlocale (LC_ALL, "");
1557 bindtextdomain("net-tools", "/usr/share/locale");
1558 textdomain("net-tools");
1559 #endif
1560 getroute_init(); /* Set up AF routing support */
1562 afname[0] = '\0';
1563 while ((i = getopt_long(argc, argv, "MCFA:acdegphinNorstuVv?wxl", longopts, &lop)) != EOF)
1564 switch (i) {
1565 case -1:
1566 break;
1567 case 1:
1568 if (lop < 0 || lop >= AFTRANS_CNT) {
1569 EINTERN("netstat.c", "longopts 1 range");
1570 break;
1572 if (aftrans_opt(longopts[lop].name))
1573 exit(1);
1574 break;
1575 case 'A':
1576 if (aftrans_opt(optarg))
1577 exit(1);
1578 break;
1579 case 'M':
1580 flag_mas++;
1581 break;
1582 case 'a':
1583 flag_all++;
1584 break;
1585 case 'l':
1586 flag_lst++;
1587 break;
1588 case 'c':
1589 flag_cnt++;
1590 break;
1592 case 'd':
1593 flag_deb++;
1594 break;
1595 case 'g':
1596 flag_igmp++;
1597 break;
1598 case 'e':
1599 flag_exp++;
1600 break;
1601 case 'p':
1602 flag_prg++;
1603 break;
1604 case 'i':
1605 flag_int++;
1606 break;
1607 case 'n':
1608 flag_not |= FLAG_NUM;
1609 break;
1610 case '!':
1611 flag_not |= FLAG_NUM_HOST;
1612 break;
1613 case '@':
1614 flag_not |= FLAG_NUM_PORT;
1615 break;
1616 case '#':
1617 flag_not |= FLAG_NUM_USER;
1618 break;
1619 case 'N':
1620 flag_not |= FLAG_SYM;
1621 break;
1622 case 'C':
1623 flag_cf |= FLAG_CACHE;
1624 break;
1625 case 'F':
1626 flag_cf |= FLAG_FIB;
1627 break;
1628 case 'o':
1629 flag_opt++;
1630 break;
1631 case 'V':
1632 version();
1633 /*NOTREACHED */
1634 case 'v':
1635 flag_ver |= FLAG_VERBOSE;
1636 break;
1637 case 'r':
1638 flag_rou++;
1639 break;
1641 case 't':
1642 flag_tcp++;
1643 break;
1645 case 'u':
1646 flag_udp++;
1647 break;
1648 case 'w':
1649 flag_raw++;
1650 break;
1651 case 'x':
1652 if (aftrans_opt("unix"))
1653 exit(1);
1654 break;
1655 case '?':
1656 case 'h':
1657 usage();
1658 case 's':
1659 flag_sta++;
1662 if (flag_int + flag_rou + flag_mas + flag_sta > 1)
1663 usage();
1665 if ((flag_inet || flag_inet6 || flag_sta) && !(flag_tcp || flag_udp || flag_raw))
1666 flag_tcp = flag_udp = flag_raw = 1;
1668 if ((flag_tcp || flag_udp || flag_raw || flag_igmp) && !(flag_inet || flag_inet6))
1669 flag_inet = flag_inet6 = 1;
1671 flag_arg = flag_tcp + flag_udp + flag_raw + flag_unx + flag_ipx
1672 + flag_ax25 + flag_netrom + flag_igmp + flag_x25;
1674 if (flag_mas) {
1675 #if HAVE_FW_MASQUERADE && HAVE_AFINET
1676 #if MORE_THAN_ONE_MASQ_AF
1677 if (!afname[0])
1678 strcpy(afname, DFLT_AF);
1679 #endif
1680 for (;;) {
1681 i = ip_masq_info(flag_not & FLAG_NUM_HOST,
1682 flag_not & FLAG_NUM_PORT, flag_exp);
1683 if (i || !flag_cnt)
1684 break;
1685 sleep(1);
1687 #else
1688 ENOSUPP("netstat.c", "FW_MASQUERADE");
1689 i = -1;
1690 #endif
1691 return (i);
1694 if (flag_sta) {
1695 inittab();
1696 parsesnmp(flag_raw, flag_tcp, flag_udp);
1697 exit(0);
1700 if (flag_rou) {
1701 int options = 0;
1703 if (!afname[0])
1704 strcpy(afname, DFLT_AF);
1706 if (flag_exp == 2)
1707 flag_exp = 1;
1708 else if (flag_exp == 1)
1709 flag_exp = 2;
1711 options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
1712 if (!flag_cf)
1713 options |= FLAG_FIB;
1715 for (;;) {
1716 i = route_info(afname, options);
1717 if (i || !flag_cnt)
1718 break;
1719 sleep(1);
1721 return (i);
1723 if (flag_int) {
1724 for (;;) {
1725 i = iface_info();
1726 if (!flag_cnt || i)
1727 break;
1728 sleep(1);
1730 return (i);
1732 for (;;) {
1733 if (!flag_arg || flag_tcp || flag_udp || flag_raw) {
1734 #if HAVE_AFINET
1735 prg_cache_load();
1736 printf(_("Active Internet connections ")); /* xxx */
1738 if (flag_all)
1739 printf(_("(servers and established)"));
1740 else {
1741 if (flag_lst)
1742 printf(_("(only servers)"));
1743 else
1744 printf(_("(w/o servers)"));
1746 printf(_("\nProto Recv-Q Send-Q Local Address Foreign Address State ")); /* xxx */
1747 if (flag_exp > 1)
1748 printf(_(" User Inode "));
1749 print_progname_banner();
1750 if (flag_opt)
1751 printf(_(" Timer")); /* xxx */
1752 printf("\n");
1753 #else
1754 if (flag_arg) {
1755 i = 1;
1756 ENOSUPP("netstat", "AF INET");
1758 #endif
1760 #if HAVE_AFINET
1761 if (!flag_arg || flag_tcp) {
1762 i = tcp_info();
1763 if (i)
1764 return (i);
1766 if (!flag_arg || flag_udp) {
1767 i = udp_info();
1768 if (i)
1769 return (i);
1771 if (!flag_arg || flag_raw) {
1772 i = raw_info();
1773 if (i)
1774 return (i);
1777 if (flag_igmp) {
1778 #if HAVE_AFINET6
1779 printf( "IPv6/");
1780 #endif
1781 printf( _("IPv4 Group Memberships\n") );
1782 printf( _("Interface RefCnt Group\n") );
1783 printf( "--------------- ------ ---------------------\n" );
1784 i = igmp_info();
1785 if (i)
1786 return (i);
1788 #endif
1790 if (!flag_arg || flag_unx) {
1791 #if HAVE_AFUNIX
1792 prg_cache_load();
1793 i = unix_info();
1794 if (i)
1795 return (i);
1796 #else
1797 if (flag_arg) {
1798 i = 1;
1799 ENOSUPP("netstat", "AF UNIX");
1801 #endif
1803 if (!flag_arg || flag_ipx) {
1804 #if HAVE_AFIPX
1805 i = ipx_info();
1806 if (i)
1807 return (i);
1808 #else
1809 if (flag_arg) {
1810 i = 1;
1811 ENOSUPP("netstat", "AF IPX");
1813 #endif
1815 if (!flag_arg || flag_ax25) {
1816 #if HAVE_AFAX25
1817 i = ax25_info();
1818 if (i)
1819 return (i);
1820 #else
1821 if (flag_arg) {
1822 i = 1;
1823 ENOSUPP("netstat", "AF AX25");
1825 #endif
1827 if(!flag_arg || flag_x25) {
1828 #if HAVE_AFX25
1829 /* FIXME */
1830 i = x25_info();
1831 if (i)
1832 return(i);
1833 #else
1834 if (flag_arg) {
1835 i = 1;
1836 ENOSUPP("netstat", "AF X25");
1838 #endif
1840 if (!flag_arg || flag_netrom) {
1841 #if HAVE_AFNETROM
1842 i = netrom_info();
1843 if (i)
1844 return (i);
1845 #else
1846 if (flag_arg) {
1847 i = 1;
1848 ENOSUPP("netstat", "AF NETROM");
1850 #endif
1852 if (!flag_cnt || i)
1853 break;
1854 sleep(1);
1855 prg_cache_clear();
1857 return (i);