i am sorry for that double change, didnt noticed, my cvs change mail seems
[oss-qm-packages.git] / netstat.c
blobbc1ac1cc8213383ebc2917db9ece12da3a8823c8
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.40 2000/12/19 01:28:34 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()
61 * This program is free software; you can redistribute it
62 * and/or modify it under the terms of the GNU General
63 * Public License as published by the Free Software
64 * Foundation; either version 2 of the License, or (at
65 * your option) any later version.
68 #include <errno.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <strings.h>
73 #include <unistd.h>
74 #include <ctype.h>
75 #include <fcntl.h>
76 #include <netdb.h>
77 #include <paths.h>
78 #include <pwd.h>
79 #include <getopt.h>
80 #include <sys/param.h>
81 #include <sys/socket.h>
82 #include <arpa/inet.h>
83 #include <netinet/in.h>
84 #include <sys/ioctl.h>
85 #include <net/if.h>
86 #include <dirent.h>
88 #include "net-support.h"
89 #include "pathnames.h"
90 #include "version.h"
91 #include "config.h"
92 #include "intl.h"
93 #include "sockets.h"
94 #include "interface.h"
95 #include "util.h"
97 #define PROGNAME_WIDTH 20
99 #if !defined(s6_addr32) && defined(in6a_words)
100 #define s6_addr32 in6a_words /* libinet6 */
101 #endif
103 /* prototypes for statistics.c */
104 void parsesnmp(int, int, int);
105 void inittab(void);
107 typedef enum {
108 SS_FREE = 0, /* not allocated */
109 SS_UNCONNECTED, /* unconnected to any socket */
110 SS_CONNECTING, /* in process of connecting */
111 SS_CONNECTED, /* connected to socket */
112 SS_DISCONNECTING /* in process of disconnecting */
113 } socket_state;
115 #define SO_ACCEPTCON (1<<16) /* performed a listen */
116 #define SO_WAITDATA (1<<17) /* wait data to read */
117 #define SO_NOSPACE (1<<18) /* no space to write */
119 #define DFLT_AF "inet"
121 #define FEATURE_NETSTAT
122 #include "lib/net-features.h"
124 char *Release = RELEASE, *Version = "netstat 1.39 (2000-05-21)", *Signature = "Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang and others";
127 #define E_READ -1
128 #define E_IOCTL -3
130 int flag_int = 0;
131 int flag_rou = 0;
132 int flag_mas = 0;
133 int flag_sta = 0;
135 int flag_all = 0;
136 int flag_lst = 0;
137 int flag_cnt = 0;
138 int flag_deb = 0;
139 int flag_not = 0;
140 int flag_cf = 0;
141 int flag_opt = 0;
142 int flag_raw = 0;
143 int flag_tcp = 0;
144 int flag_udp = 0;
145 int flag_igmp= 0;
146 int flag_rom = 0;
147 int flag_exp = 1;
148 int flag_prg = 0;
149 int flag_arg = 0;
150 int flag_ver = 0;
152 FILE *procinfo;
154 #define INFO_GUTS1(file,name,proc) \
155 procinfo = fopen((file), "r"); \
156 if (procinfo == NULL) { \
157 if (errno != ENOENT) { \
158 perror((file)); \
159 return -1; \
161 if (flag_arg || flag_ver) \
162 ESYSNOT("netstat", (name)); \
163 if (flag_arg) \
164 rc = 1; \
165 } else { \
166 do { \
167 if (fgets(buffer, sizeof(buffer), procinfo)) \
168 (proc)(lnr++, buffer); \
169 } while (!feof(procinfo)); \
170 fclose(procinfo); \
173 #if HAVE_AFINET6
174 #define INFO_GUTS2(file,proc) \
175 lnr = 0; \
176 procinfo = fopen((file), "r"); \
177 if (procinfo != NULL) { \
178 do { \
179 if (fgets(buffer, sizeof(buffer), procinfo)) \
180 (proc)(lnr++, buffer); \
181 } while (!feof(procinfo)); \
182 fclose(procinfo); \
184 #else
185 #define INFO_GUTS2(file,proc)
186 #endif
188 #define INFO_GUTS3 \
189 return rc;
191 #define INFO_GUTS6(file,file6,name,proc) \
192 char buffer[8192]; \
193 int rc = 0; \
194 int lnr = 0; \
195 if (!flag_arg || flag_inet) { \
196 INFO_GUTS1(file,name,proc) \
198 if (!flag_arg || flag_inet6) { \
199 INFO_GUTS2(file6,proc) \
201 INFO_GUTS3
203 #define INFO_GUTS(file,name,proc) \
204 char buffer[8192]; \
205 int rc = 0; \
206 int lnr = 0; \
207 INFO_GUTS1(file,name,proc) \
208 INFO_GUTS3
210 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
211 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
212 #define PROGNAME_WIDTH2(s) #s
214 #define PRG_HASH_SIZE 211
216 static struct prg_node {
217 struct prg_node *next;
218 int inode;
219 char name[PROGNAME_WIDTH];
220 } *prg_hash[PRG_HASH_SIZE];
222 static char prg_cache_loaded = 0;
224 #define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
226 #define PROGNAME_BANNER "PID/Program name"
228 #define print_progname_banner() do { if (flag_prg) printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER); } while (0)
230 #define PRG_LOCAL_ADDRESS "local_address"
231 #define PRG_INODE "inode"
232 #define PRG_SOCKET_PFX "socket:["
233 #define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
234 #define PRG_SOCKET_PFX2 "[0000]:"
235 #define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2))
238 #ifndef LINE_MAX
239 #define LINE_MAX 4096
240 #endif
242 #define PATH_PROC "/proc"
243 #define PATH_FD_SUFF "fd"
244 #define PATH_FD_SUFFl strlen(PATH_FD_SUFF)
245 #define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF
246 #define PATH_CMDLINE "cmdline"
247 #define PATH_CMDLINEl strlen(PATH_CMDLINE)
248 /* NOT working as of glibc-2.0.7: */
249 #undef DIRENT_HAVE_D_TYPE_WORKS
251 static void prg_cache_add(int inode, char *name)
253 unsigned hi = PRG_HASHIT(inode);
254 struct prg_node **pnp,*pn;
256 prg_cache_loaded=2;
257 for (pnp=prg_hash+hi;(pn=*pnp);pnp=&pn->next) {
258 if (pn->inode==inode) {
259 /* Some warning should be appropriate here
260 as we got multiple processes for one i-node */
261 return;
264 if (!(*pnp=malloc(sizeof(**pnp))))
265 return;
266 pn=*pnp;
267 pn->next=NULL;
268 pn->inode=inode;
269 if (strlen(name)>sizeof(pn->name)-1)
270 name[sizeof(pn->name)-1]='\0';
271 strcpy(pn->name,name);
274 static const char *prg_cache_get(int inode)
276 unsigned hi=PRG_HASHIT(inode);
277 struct prg_node *pn;
279 for (pn=prg_hash[hi];pn;pn=pn->next)
280 if (pn->inode==inode) return(pn->name);
281 return("-");
284 static void prg_cache_clear(void)
286 struct prg_node **pnp,*pn;
288 if (prg_cache_loaded == 2)
289 for (pnp=prg_hash;pnp<prg_hash+PRG_HASH_SIZE;pnp++)
290 while ((pn=*pnp)) {
291 *pnp=pn->next;
292 free(pn);
294 prg_cache_loaded=0;
297 static void extract_type_1_socket_inode(const char lname[], long * inode_p) {
299 /* If lname is of the form "socket:[12345]", extract the "12345"
300 as *inode_p. Otherwise, return -1 as *inode_p.
303 if (strlen(lname) < PRG_SOCKET_PFXl+3) *inode_p = -1;
304 else if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) *inode_p = -1;
305 else if (lname[strlen(lname)-1] != ']') *inode_p = -1;
306 else {
307 char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
308 const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
309 char *serr;
311 strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
312 inode_str[inode_str_len] = '\0';
313 *inode_p = strtol(inode_str,&serr,0);
314 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
315 *inode_p = -1;
321 static void extract_type_2_socket_inode(const char lname[], long * inode_p) {
323 /* If lname is of the form "[0000]:12345", extract the "12345"
324 as *inode_p. Otherwise, return -1 as *inode_p.
327 if (strlen(lname) < PRG_SOCKET_PFX2l+1) *inode_p = -1;
328 else if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) *inode_p = -1;
329 else {
330 char *serr;
332 *inode_p=strtol(lname + PRG_SOCKET_PFX2l,&serr,0);
333 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
334 *inode_p = -1;
340 static void prg_cache_load(void)
342 char line[LINE_MAX],eacces=0;
343 int procfdlen,fd,cmdllen,lnamelen;
344 char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH];
345 long inode;
346 const char *cs,*cmdlp;
347 DIR *dirproc=NULL,*dirfd=NULL;
348 struct dirent *direproc,*direfd;
350 if (prg_cache_loaded || !flag_prg) return;
351 prg_cache_loaded=1;
352 cmdlbuf[sizeof(cmdlbuf)-1]='\0';
353 if (!(dirproc=opendir(PATH_PROC))) goto fail;
354 while (errno=0,direproc=readdir(dirproc)) {
355 #ifdef DIRENT_HAVE_D_TYPE_WORKS
356 if (direproc->d_type!=DT_DIR) continue;
357 #endif
358 for (cs=direproc->d_name;*cs;cs++)
359 if (!isdigit(*cs))
360 break;
361 if (*cs)
362 continue;
363 procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
364 if (procfdlen<=0 || procfdlen>=sizeof(line)-5)
365 continue;
366 errno=0;
367 dirfd=opendir(line);
368 if (! dirfd) {
369 if (errno==EACCES)
370 eacces=1;
371 continue;
373 line[procfdlen] = '/';
374 cmdlp = NULL;
375 while ((direfd = readdir(dirfd))) {
376 #ifdef DIRENT_HAVE_D_TYPE_WORKS
377 if (direfd->d_type!=DT_LNK)
378 continue;
379 #endif
380 if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line))
381 continue;
382 memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
383 PATH_FD_SUFFl+1);
384 strcpy(line + procfdlen + 1, direfd->d_name);
385 lnamelen=readlink(line,lname,sizeof(lname)-1);
386 lname[lnamelen] = '\0'; /*make it a null-terminated string*/
388 extract_type_1_socket_inode(lname, &inode);
390 if (inode < 0) extract_type_2_socket_inode(lname, &inode);
392 if (inode < 0) continue;
394 if (!cmdlp) {
395 if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
396 sizeof(line) - 5)
397 continue;
398 strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
399 fd = open(line, O_RDONLY);
400 if (fd < 0)
401 continue;
402 cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
403 if (close(fd))
404 continue;
405 if (cmdllen == -1)
406 continue;
407 if (cmdllen < sizeof(cmdlbuf) - 1)
408 cmdlbuf[cmdllen]='\0';
409 if ((cmdlp = strrchr(cmdlbuf, '/')))
410 cmdlp++;
411 else
412 cmdlp = cmdlbuf;
415 snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
416 prg_cache_add(inode, finbuf);
418 closedir(dirfd);
419 dirfd = NULL;
421 if (dirproc)
422 closedir(dirproc);
423 if (dirfd)
424 closedir(dirfd);
425 if (!eacces)
426 return;
427 if (prg_cache_loaded == 1) {
428 fail:
429 fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
430 geteuid());
432 else
433 fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
434 " will not be shown, you would have to be root to see it all.)\n"));
437 #if HAVE_AFNETROM
438 static const char *netrom_state[] =
440 N_("LISTENING"),
441 N_("CONN SENT"),
442 N_("DISC SENT"),
443 N_("ESTABLISHED")
446 static int netrom_info(void)
448 FILE *f;
449 char buffer[256], dev[16];
450 int st, vs, vr, sendq, recvq, ret;
452 f = fopen(_PATH_PROCNET_NR, "r");
453 if (f == NULL) {
454 if (errno != ENOENT) {
455 perror(_PATH_PROCNET_NR);
456 return (-1);
458 if (flag_arg || flag_ver)
459 ESYSNOT("netstat", "AF NETROM");
460 if (flag_arg)
461 return (1);
462 else
463 return (0);
465 printf(_("Active NET/ROM sockets\n"));
466 printf(_("User Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
467 fgets(buffer, 256, f);
469 while (fgets(buffer, 256, f)) {
470 buffer[9] = 0;
471 buffer[19] = 0;
472 buffer[29] = 0;
473 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",
474 dev, &st, &vs, &vr, &sendq, &recvq);
475 if (ret != 6) {
476 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
477 continue;
479 printf("%-9s %-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
480 buffer, buffer + 10, buffer + 20,
481 dev,
482 _(netrom_state[st]),
483 vr, vs, sendq, recvq);
485 fclose(f);
486 return 0;
488 #endif
490 /* These enums are used by IPX too. :-( */
491 enum {
492 TCP_ESTABLISHED = 1,
493 TCP_SYN_SENT,
494 TCP_SYN_RECV,
495 TCP_FIN_WAIT1,
496 TCP_FIN_WAIT2,
497 TCP_TIME_WAIT,
498 TCP_CLOSE,
499 TCP_CLOSE_WAIT,
500 TCP_LAST_ACK,
501 TCP_LISTEN,
502 TCP_CLOSING /* now a valid state */
505 #if HAVE_AFINET || HAVE_AFINET6
507 static const char *tcp_state[] =
510 N_("ESTABLISHED"),
511 N_("SYN_SENT"),
512 N_("SYN_RECV"),
513 N_("FIN_WAIT1"),
514 N_("FIN_WAIT2"),
515 N_("TIME_WAIT"),
516 N_("CLOSE"),
517 N_("CLOSE_WAIT"),
518 N_("LAST_ACK"),
519 N_("LISTEN"),
520 N_("CLOSING")
523 static void finish_this_one(int uid, unsigned long inode, const char *timers)
525 struct passwd *pw;
527 if (flag_exp > 1) {
528 if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
529 printf("%-10s ", pw->pw_name);
530 else
531 printf("%-10d ", uid);
532 printf("%-10ld ",inode);
534 if (flag_prg)
535 printf("%-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
536 if (flag_opt)
537 printf("%s", timers);
538 putchar('\n');
541 static void igmp_do_one(int lnr, const char *line)
543 char mcast_addr[128];
544 #if HAVE_AFINET6
545 struct sockaddr_in6 mcastaddr;
546 char addr6[INET6_ADDRSTRLEN];
547 struct in6_addr in6;
548 extern struct aftype inet6_aftype;
549 #else
550 struct sockaddr_in mcastaddr;
551 #endif
552 struct aftype *ap;
553 static int idx_flag = 0;
554 static int igmp6_flag = 0;
555 static char device[16];
556 int num, idx, refcnt;
558 if (lnr == 0) {
559 /* IPV6 ONLY */
560 /* igmp6 file does not have any comments on first line */
561 if ( strstr( line, "Device" ) == NULL ) {
562 igmp6_flag = 1;
563 } else {
564 /* IPV4 ONLY */
565 /* 2.1.x kernels and up have Idx field */
566 /* 2.0.x and below do not have Idx field */
567 if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
568 idx_flag = 1;
569 else
570 idx_flag = 0;
571 return;
575 if (igmp6_flag) { /* IPV6 */
576 #if HAVE_AFINET6
577 num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
578 if (num == 4) {
579 /* Demangle what the kernel gives us */
580 sscanf(mcast_addr, "%08X%08X%08X%08X",
581 &in6.s6_addr32[0], &in6.s6_addr32[1],
582 &in6.s6_addr32[2], &in6.s6_addr32[3]);
583 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
584 inet6_aftype.input(1, addr6, (struct sockaddr *) &mcastaddr);
585 mcastaddr.sin6_family = AF_INET6;
586 } else {
587 fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
588 return;
591 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
592 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
593 ((struct sockaddr *) &mcastaddr)->sa_family);
594 return;
596 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
597 flag_not), sizeof(mcast_addr));
598 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
599 #endif
600 } else { /* IPV4 */
601 #if HAVE_AFINET
602 if (line[0] != '\t') {
603 if (idx_flag) {
604 if ((num = sscanf( line, "%d\t%10c", &idx, device)) < 2) {
605 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
606 return;
608 } else {
609 if ( (num = sscanf( line, "%10c", device )) < 1 ) {
610 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
611 return;
614 device[10] = '\0';
615 return;
616 } else if ( line[0] == '\t' ) {
617 if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
618 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
619 return;
621 sscanf( mcast_addr, "%X",
622 &((struct sockaddr_in *) &mcastaddr)->sin_addr.s_addr );
623 ((struct sockaddr *) &mcastaddr)->sa_family = AF_INET;
624 } else {
625 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
626 return;
629 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
630 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
631 ((struct sockaddr *) &mcastaddr)->sa_family);
632 return;
634 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
635 flag_not), sizeof(mcast_addr));
636 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
637 #endif
638 } /* IPV4 */
641 #if HAVE_AFX25
642 static int x25_info(void)
644 FILE *f=fopen(_PATH_PROCNET_X25, "r");
645 char buffer[256],dev[16];
646 int st,vs,vr,sendq,recvq,lci;
647 static char *x25_state[5]=
649 "LISTENING",
650 "SABM_SENT",
651 "DISC_SENT",
652 "ESTABLISHED",
653 "RECOVERY"
655 if(!(f=fopen(_PATH_PROCNET_X25, "r")))
657 if (errno != ENOENT) {
658 perror(_PATH_PROCNET_X25);
659 return(-1);
661 if (flag_arg || flag_ver)
662 ESYSNOT("netstat","AF X25");
663 if (flag_arg)
664 return(1);
665 else
666 return(0);
668 printf( _("Active X.25 sockets\n"));
669 /* IMHO, Vr/Vs is not very usefull --SF */
670 printf( _("Dest Source Device LCI State Vr/Vs Send-Q Recv-Q\n"));
671 fgets(buffer,256,f);
672 while(fgets(buffer,256,f))
674 buffer[10]=0;
675 buffer[20]=0;
676 sscanf(buffer+22,"%s %d %d %d %d %*d %*d %*d %*d %*d %*d %d %d %*d",
677 dev,&lci,&st,&vs,&vr,&sendq,&recvq);
678 if (!(flag_all || lci))
679 continue;
680 printf("%-15s %-15s %-7s %-3d %-11s %02d/%02d %-6d %-6d\n",
681 buffer,buffer+11,
682 dev,
683 lci,
684 x25_state[st],
685 vr,vs,sendq,recvq);
687 fclose(f);
688 return 0;
690 #endif
692 static int igmp_info(void)
694 INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
695 igmp_do_one);
698 static void tcp_do_one(int lnr, const char *line)
700 unsigned long rxq, txq, time_len, retr, inode;
701 int num, local_port, rem_port, d, state, uid, timer_run, timeout;
702 char rem_addr[128], local_addr[128], timers[64], buffer[1024], more[512];
703 struct aftype *ap;
704 #if HAVE_AFINET6
705 struct sockaddr_in6 localaddr, remaddr;
706 char addr6[INET6_ADDRSTRLEN];
707 struct in6_addr in6;
708 extern struct aftype inet6_aftype;
709 #else
710 struct sockaddr_in localaddr, remaddr;
711 #endif
713 if (lnr == 0)
714 return;
716 num = sscanf(line,
717 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
718 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
719 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
721 if (strlen(local_addr) > 8) {
722 #if HAVE_AFINET6
723 /* Demangle what the kernel gives us */
724 sscanf(local_addr, "%08X%08X%08X%08X",
725 &in6.s6_addr32[0], &in6.s6_addr32[1],
726 &in6.s6_addr32[2], &in6.s6_addr32[3]);
727 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
728 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
729 sscanf(rem_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 *) &remaddr);
734 localaddr.sin6_family = AF_INET6;
735 remaddr.sin6_family = AF_INET6;
736 #endif
737 } else {
738 sscanf(local_addr, "%X",
739 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
740 sscanf(rem_addr, "%X",
741 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
742 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
743 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
746 if (num < 11) {
747 fprintf(stderr, _("warning, got bogus tcp line.\n"));
748 return;
750 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
751 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
752 ((struct sockaddr *) &localaddr)->sa_family);
753 return;
755 if (state == TCP_LISTEN) {
756 time_len = 0;
757 retr = 0L;
758 rxq = 0L;
759 txq = 0L;
761 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
762 flag_not), sizeof(local_addr));
763 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr, flag_not),
764 sizeof(rem_addr));
765 if (flag_all || (flag_lst && !rem_port) || (!flag_lst && rem_port)) {
766 snprintf(buffer, sizeof(buffer), "%s",
767 get_sname(htons(local_port), "tcp",
768 flag_not & FLAG_NUM_PORT));
770 if ((strlen(local_addr) + strlen(buffer)) > 22)
771 local_addr[22 - strlen(buffer)] = '\0';
773 strcat(local_addr, ":");
774 strcat(local_addr, buffer);
775 snprintf(buffer, sizeof(buffer), "%s",
776 get_sname(htons(rem_port), "tcp", flag_not & FLAG_NUM_PORT));
778 if ((strlen(rem_addr) + strlen(buffer)) > 22)
779 rem_addr[22 - strlen(buffer)] = '\0';
781 strcat(rem_addr, ":");
782 strcat(rem_addr, buffer);
783 timers[0] = '\0';
785 if (flag_opt)
786 switch (timer_run) {
787 case 0:
788 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
789 break;
791 case 1:
792 snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
793 (double) time_len / HZ, retr, timeout);
794 break;
796 case 2:
797 snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
798 (double) time_len / HZ, retr, timeout);
799 break;
801 case 3:
802 snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
803 (double) time_len / HZ, retr, timeout);
804 break;
806 default:
807 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
808 timer_run, (double) time_len / HZ, retr, timeout);
809 break;
811 printf("tcp %6ld %6ld %-23s %-23s %-12s",
812 rxq, txq, local_addr, rem_addr, _(tcp_state[state]));
814 finish_this_one(uid,inode,timers);
818 static int tcp_info(void)
820 INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
821 tcp_do_one);
824 static void udp_do_one(int lnr, const char *line)
826 char buffer[8192], local_addr[64], rem_addr[64];
827 char *udp_state, timers[64], more[512];
828 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
829 #if HAVE_AFINET6
830 struct sockaddr_in6 localaddr, remaddr;
831 char addr6[INET6_ADDRSTRLEN];
832 struct in6_addr in6;
833 extern struct aftype inet6_aftype;
834 #else
835 struct sockaddr_in localaddr, remaddr;
836 #endif
837 struct aftype *ap;
838 unsigned long rxq, txq, time_len, retr, inode;
840 if (lnr == 0)
841 return;
843 more[0] = '\0';
844 num = sscanf(line,
845 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
846 &d, local_addr, &local_port,
847 rem_addr, &rem_port, &state,
848 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
850 if (strlen(local_addr) > 8) {
851 #if HAVE_AFINET6
852 sscanf(local_addr, "%08X%08X%08X%08X",
853 &in6.s6_addr32[0], &in6.s6_addr32[1],
854 &in6.s6_addr32[2], &in6.s6_addr32[3]);
855 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
856 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
857 sscanf(rem_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 *) &remaddr);
862 localaddr.sin6_family = AF_INET6;
863 remaddr.sin6_family = AF_INET6;
864 #endif
865 } else {
866 sscanf(local_addr, "%X",
867 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
868 sscanf(rem_addr, "%X",
869 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
870 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
871 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
874 retr = 0L;
875 if (!flag_opt)
876 more[0] = '\0';
878 if (num < 10) {
879 fprintf(stderr, _("warning, got bogus udp line.\n"));
880 return;
882 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
883 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
884 ((struct sockaddr *) &localaddr)->sa_family);
885 return;
887 switch (state) {
888 case TCP_ESTABLISHED:
889 udp_state = _("ESTABLISHED");
890 break;
892 case TCP_CLOSE:
893 udp_state = "";
894 break;
896 default:
897 udp_state = _("UNKNOWN");
898 break;
901 #if HAVE_AFINET6
902 #define notnull(A) (((A.sin6_family == AF_INET6) && \
903 ((A.sin6_addr.s6_addr32[0]) || \
904 (A.sin6_addr.s6_addr32[1]) || \
905 (A.sin6_addr.s6_addr32[2]) || \
906 (A.sin6_addr.s6_addr32[3]))) || \
907 ((A.sin6_family == AF_INET) && \
908 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
909 #else
910 #define notnull(A) (A.sin_addr.s_addr)
911 #endif
913 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
915 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
916 flag_not), sizeof(local_addr));
917 snprintf(buffer, sizeof(buffer), "%s",
918 get_sname(htons(local_port), "udp",
919 flag_not & FLAG_NUM_PORT));
920 if ((strlen(local_addr) + strlen(buffer)) > 22)
921 local_addr[22 - strlen(buffer)] = '\0';
922 strcat(local_addr, ":");
923 strcat(local_addr, buffer);
925 snprintf(buffer, sizeof(buffer), "%s",
926 get_sname(htons(rem_port), "udp", flag_not & FLAG_NUM_PORT));
927 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
928 flag_not), sizeof(rem_addr));
929 if ((strlen(rem_addr) + strlen(buffer)) > 22)
930 rem_addr[22 - strlen(buffer)] = '\0';
931 strcat(rem_addr, ":");
932 strcat(rem_addr, buffer);
934 timers[0] = '\0';
935 if (flag_opt)
936 switch (timer_run) {
937 case 0:
938 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
939 break;
941 case 1:
942 case 2:
943 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
944 break;
946 default:
947 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
948 retr, timeout);
949 break;
951 printf("udp %6ld %6ld %-23s %-23s %-12s",
952 rxq, txq, local_addr, rem_addr, udp_state);
954 finish_this_one(uid,inode,timers);
958 static int udp_info(void)
960 INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
961 udp_do_one);
964 static void raw_do_one(int lnr, const char *line)
966 char buffer[8192], local_addr[64], rem_addr[64];
967 char timers[64], more[512];
968 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
969 #if HAVE_AFINET6
970 struct sockaddr_in6 localaddr, remaddr;
971 char addr6[INET6_ADDRSTRLEN];
972 struct in6_addr in6;
973 extern struct aftype inet6_aftype;
974 #else
975 struct sockaddr_in localaddr, remaddr;
976 #endif
977 struct aftype *ap;
978 unsigned long rxq, txq, time_len, retr, inode;
980 if (lnr == 0)
981 return;
983 more[0] = '\0';
984 num = sscanf(line,
985 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
986 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
987 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
989 if (strlen(local_addr) > 8) {
990 #if HAVE_AFINET6
991 sscanf(local_addr, "%08X%08X%08X%08X",
992 &in6.s6_addr32[0], &in6.s6_addr32[1],
993 &in6.s6_addr32[2], &in6.s6_addr32[3]);
994 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
995 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
996 sscanf(rem_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 *) &remaddr);
1001 localaddr.sin6_family = AF_INET6;
1002 remaddr.sin6_family = AF_INET6;
1003 #endif
1004 } else {
1005 sscanf(local_addr, "%X",
1006 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
1007 sscanf(rem_addr, "%X",
1008 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
1009 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
1010 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
1012 #if HAVE_AFINET6
1013 if ((ap = get_afntype(localaddr.sin6_family)) == NULL) {
1014 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin6_family);
1015 return;
1017 #else
1018 if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
1019 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin_family);
1020 return;
1022 #endif
1024 if (!flag_opt)
1025 more[0] = '\0';
1027 if (num < 10) {
1028 fprintf(stderr, _("warning, got bogus raw line.\n"));
1029 return;
1032 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
1034 snprintf(buffer, sizeof(buffer), "%s",
1035 get_sname(htons(local_port), "raw",
1036 flag_not & FLAG_NUM_PORT));
1037 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
1038 flag_not), sizeof(local_addr));
1039 if ((strlen(local_addr) + strlen(buffer)) > 22)
1040 local_addr[22 - strlen(buffer)] = '\0';
1041 strcat(local_addr, ":");
1042 strcat(local_addr, buffer);
1044 snprintf(buffer, sizeof(buffer), "%s",
1045 get_sname(htons(rem_port), "raw", flag_not & FLAG_NUM_PORT));
1046 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
1047 flag_not), sizeof(rem_addr));
1048 if ((strlen(rem_addr) + strlen(buffer)) > 22)
1049 rem_addr[22 - strlen(buffer)] = '\0';
1050 strcat(rem_addr, ":");
1051 strcat(rem_addr, buffer);
1053 timers[0] = '\0';
1054 if (flag_opt)
1055 switch (timer_run) {
1056 case 0:
1057 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
1058 break;
1060 case 1:
1061 case 2:
1062 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1063 retr, timeout);
1064 break;
1066 default:
1067 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
1068 timer_run, (double) time_len / 100,
1069 retr, timeout);
1070 break;
1072 printf("raw %6ld %6ld %-23s %-23s %-12d",
1073 rxq, txq, local_addr, rem_addr, state);
1075 finish_this_one(uid,inode,timers);
1079 static int raw_info(void)
1081 INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
1082 raw_do_one);
1085 #endif
1088 #if HAVE_AFUNIX
1090 #define HAS_INODE 1
1092 static void unix_do_one(int nr, const char *line)
1094 static int has = 0;
1095 char path[MAXPATHLEN], ss_flags[32];
1096 char *ss_proto, *ss_state, *ss_type;
1097 int num, state, type, inode;
1098 void *d;
1099 unsigned long refcnt, proto, flags;
1101 if (nr == 0) {
1102 if (strstr(line, "Inode"))
1103 has |= HAS_INODE;
1104 return;
1106 path[0] = '\0';
1107 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
1108 &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
1109 if (num < 6) {
1110 fprintf(stderr, _("warning, got bogus unix line.\n"));
1111 return;
1113 if (!(has & HAS_INODE))
1114 snprintf(path,sizeof(path),"%d",inode);
1116 if (!flag_all) {
1117 if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
1118 if (!flag_lst)
1119 return;
1120 } else {
1121 if (flag_lst)
1122 return;
1126 switch (proto) {
1127 case 0:
1128 ss_proto = "unix";
1129 break;
1131 default:
1132 ss_proto = "??";
1135 switch (type) {
1136 case SOCK_STREAM:
1137 ss_type = _("STREAM");
1138 break;
1140 case SOCK_DGRAM:
1141 ss_type = _("DGRAM");
1142 break;
1144 case SOCK_RAW:
1145 ss_type = _("RAW");
1146 break;
1148 case SOCK_RDM:
1149 ss_type = _("RDM");
1150 break;
1152 case SOCK_SEQPACKET:
1153 ss_type = _("SEQPACKET");
1154 break;
1156 default:
1157 ss_type = _("UNKNOWN");
1160 switch (state) {
1161 case SS_FREE:
1162 ss_state = _("FREE");
1163 break;
1165 case SS_UNCONNECTED:
1167 * Unconnected sockets may be listening
1168 * for something.
1170 if (flags & SO_ACCEPTCON) {
1171 ss_state = _("LISTENING");
1172 } else {
1173 ss_state = "";
1175 break;
1177 case SS_CONNECTING:
1178 ss_state = _("CONNECTING");
1179 break;
1181 case SS_CONNECTED:
1182 ss_state = _("CONNECTED");
1183 break;
1185 case SS_DISCONNECTING:
1186 ss_state = _("DISCONNECTING");
1187 break;
1189 default:
1190 ss_state = _("UNKNOWN");
1193 strcpy(ss_flags, "[ ");
1194 if (flags & SO_ACCEPTCON)
1195 strcat(ss_flags, "ACC ");
1196 if (flags & SO_WAITDATA)
1197 strcat(ss_flags, "W ");
1198 if (flags & SO_NOSPACE)
1199 strcat(ss_flags, "N ");
1201 strcat(ss_flags, "]");
1203 printf("%-5s %-6ld %-11s %-10s %-13s ",
1204 ss_proto, refcnt, ss_flags, ss_type, ss_state);
1205 if (has & HAS_INODE)
1206 printf("%-6d ",inode);
1207 else
1208 printf("- ");
1209 if (flag_prg)
1210 printf("%-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
1211 puts(path);
1214 static int unix_info(void)
1217 printf(_("Active UNIX domain sockets "));
1218 if (flag_all)
1219 printf(_("(servers and established)"));
1220 else {
1221 if (flag_lst)
1222 printf(_("(only servers)"));
1223 else
1224 printf(_("(w/o servers)"));
1227 printf(_("\nProto RefCnt Flags Type State I-Node"));
1228 print_progname_banner();
1229 printf(_(" Path\n")); /* xxx */
1232 INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
1235 #endif
1238 #if HAVE_AFAX25
1239 static int ax25_info(void)
1241 FILE *f;
1242 char buffer[256], buf[16];
1243 char *src, *dst, *dev, *p;
1244 int st, vs, vr, sendq, recvq, ret;
1245 int new = -1; /* flag for new (2.1.x) kernels */
1246 static char *ax25_state[5] =
1248 N_("LISTENING"),
1249 N_("SABM SENT"),
1250 N_("DISC SENT"),
1251 N_("ESTABLISHED"),
1252 N_("RECOVERY")
1254 if (!(f = fopen(_PATH_PROCNET_AX25, "r"))) {
1255 if (errno != ENOENT) {
1256 perror(_PATH_PROCNET_AX25);
1257 return (-1);
1259 if (flag_arg || flag_ver)
1260 ESYSNOT("netstat", "AF AX25");
1261 if (flag_arg)
1262 return (1);
1263 else
1264 return (0);
1266 printf(_("Active AX.25 sockets\n"));
1267 printf(_("Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
1268 while (fgets(buffer, 256, f)) {
1269 if (new == -1) {
1270 if (!strncmp(buffer, "dest_addr", 9)) {
1271 new = 0;
1272 continue; /* old kernels have a header line */
1273 } else
1274 new = 1;
1277 * In a network connection with no user socket the Snd-Q, Rcv-Q
1278 * and Inode fields are empty in 2.0.x and '*' in 2.1.x
1280 sendq = 0;
1281 recvq = 0;
1282 if (new == 0) {
1283 dst = buffer;
1284 src = buffer + 10;
1285 dst[9] = 0;
1286 src[9] = 0;
1287 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",
1288 buf, &st, &vs, &vr, &sendq, &recvq);
1289 if (ret != 4 && ret != 6) {
1290 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
1291 continue;
1293 dev = buf;
1294 } else {
1295 p = buffer;
1296 while (*p != ' ') p++;
1297 p++;
1298 dev = p;
1299 while (*p != ' ') p++;
1300 *p++ = 0;
1301 src = p;
1302 while (*p != ' ') p++;
1303 *p++ = 0;
1304 dst = p;
1305 while (*p != ' ') p++;
1306 *p++ = 0;
1307 ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
1308 &st, &vs, &vr, &sendq, &recvq);
1309 if (ret != 3 && ret != 5) {
1310 printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
1311 continue;
1314 * FIXME: digipeaters should be handled somehow.
1315 * For now we just strip them.
1317 p = dst;
1318 while (*p && *p != ',') p++;
1319 *p = 0;
1321 printf("%-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
1322 dst, src,
1323 dev,
1324 _(ax25_state[st]),
1325 vr, vs, sendq, recvq);
1327 fclose(f);
1328 return 0;
1330 #endif
1333 #if HAVE_AFIPX
1334 static int ipx_info(void)
1336 FILE *f;
1337 char buf[256];
1338 unsigned long txq, rxq;
1339 unsigned int state;
1340 unsigned int uid;
1341 char *st;
1342 int nc;
1343 struct aftype *ap;
1344 struct passwd *pw;
1345 char sad[50], dad[50];
1346 struct sockaddr sa;
1347 unsigned sport = 0, dport = 0;
1349 if (!(f = fopen(_PATH_PROCNET_IPX, "r"))) {
1350 if (errno != ENOENT) {
1351 perror(_PATH_PROCNET_IPX);
1352 return (-1);
1354 if (flag_arg || flag_ver)
1355 ESYSNOT("netstat", "AF IPX");
1356 if (flag_arg)
1357 return (1);
1358 else
1359 return (0);
1361 printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address Foreign Address State")); /* xxx */
1362 if (flag_exp > 1)
1363 printf(_(" User")); /* xxx */
1364 printf("\n");
1365 if ((ap = get_afntype(AF_IPX)) == NULL) {
1366 EINTERN("netstat.c", "AF_IPX missing");
1367 return (-1);
1369 fgets(buf, 255, f);
1371 while (fgets(buf, 255, f) != NULL) {
1372 sscanf(buf, "%s %s %lX %lX %d %d",
1373 sad, dad, &txq, &rxq, &state, &uid);
1374 if ((st = rindex(sad, ':'))) {
1375 *st++ = '\0';
1376 sscanf(st, "%X", &sport); /* net byt order */
1377 sport = ntohs(sport);
1378 } else {
1379 EINTERN("netstat.c", _PATH_PROCNET_IPX " sport format error");
1380 return (-1);
1382 nc = 0;
1383 if (strcmp(dad, "Not_Connected") != 0) {
1384 if ((st = rindex(dad, ':'))) {
1385 *st++ = '\0';
1386 sscanf(st, "%X", &dport); /* net byt order */
1387 dport = ntohs(dport);
1388 } else {
1389 EINTERN("netstat.c", _PATH_PROCNET_IPX " dport format error");
1390 return (-1);
1392 } else
1393 nc = 1;
1395 switch (state) {
1396 case TCP_ESTABLISHED:
1397 st = _("ESTAB");
1398 break;
1400 case TCP_CLOSE:
1401 st = "";
1402 break;
1404 default:
1405 st = _("UNK.");
1406 break;
1409 /* Fetch and resolve the Source */
1410 (void) ap->input(4, sad, &sa);
1411 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1412 snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
1414 if (!nc) {
1415 /* Fetch and resolve the Destination */
1416 (void) ap->input(4, dad, &sa);
1417 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1418 snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
1419 } else
1420 strcpy(dad, "-");
1422 printf("IPX %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
1423 if (flag_exp > 1) {
1424 if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
1425 printf(" %-10s", pw->pw_name);
1426 else
1427 printf(" %-10d", uid);
1429 printf("\n");
1431 fclose(f);
1432 return 0;
1434 #endif
1436 static int iface_info(void)
1438 if (skfd < 0) {
1439 if ((skfd = sockets_open(0)) < 0) {
1440 perror("socket");
1441 exit(1);
1443 printf(_("Kernel Interface table\n"));
1445 if (flag_exp < 2) {
1446 ife_short = 1;
1447 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
1450 if (for_all_interfaces(do_if_print, &flag_all) < 0) {
1451 perror(_("missing interface information"));
1452 exit(1);
1454 if (flag_cnt)
1455 free_interface_list();
1456 else {
1457 close(skfd);
1458 skfd = -1;
1461 return 0;
1465 static void version(void)
1467 printf("%s\n%s\n%s\n%s\n", Release, Version, Signature, Features);
1468 exit(E_VERSION);
1472 static void usage(void)
1474 fprintf(stderr, _("usage: netstat [-veenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}\n"));
1475 fprintf(stderr, _(" netstat [-vnNcaeol] [<Socket> ...]\n"));
1476 fprintf(stderr, _(" netstat { [-veenNac] -i | [-cnNe] -M | -s }\n\n"));
1478 fprintf(stderr, _(" -r, --route display routing table\n"));
1479 fprintf(stderr, _(" -i, --interfaces display interface table\n"));
1480 fprintf(stderr, _(" -g, --groups display multicast group memberships\n"));
1481 fprintf(stderr, _(" -s, --statistics display networking statistics (like SNMP)\n"));
1482 #if HAVE_FW_MASQUERADE
1483 fprintf(stderr, _(" -M, --masquerade display masqueraded connections\n\n"));
1484 #endif
1485 fprintf(stderr, _(" -v, --verbose be verbose\n"));
1486 fprintf(stderr, _(" -n, --numeric dont resolve names\n"));
1487 fprintf(stderr, _(" --numeric-hosts dont resolve host names\n"));
1488 fprintf(stderr, _(" --numeric-ports dont resolve port names\n"));
1489 fprintf(stderr, _(" --numeric-users dont resolve user names\n"));
1490 fprintf(stderr, _(" -N, --symbolic resolve hardware names\n"));
1491 fprintf(stderr, _(" -e, --extend display other/more information\n"));
1492 fprintf(stderr, _(" -p, --programs display PID/Program name for sockets\n"));
1493 fprintf(stderr, _(" -c, --continuous continuous listing\n\n"));
1494 fprintf(stderr, _(" -l, --listening display listening server sockets\n"));
1495 fprintf(stderr, _(" -a, --all, --listening display all sockets (default: connected)\n"));
1496 fprintf(stderr, _(" -o, --timers display timers\n"));
1497 fprintf(stderr, _(" -F, --fib display Forwarding Information Base (default)\n"));
1498 fprintf(stderr, _(" -C, --cache display routing cache instead of FIB\n\n"));
1500 fprintf(stderr, _(" <Socket>={-t|--tcp} {-u|--udp} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
1501 fprintf(stderr, _(" <AF>=Use '-A <af>' or '--<af>' Default: %s\n"), DFLT_AF);
1502 fprintf(stderr, _(" List of possible address families (which support routing):\n"));
1503 print_aflist(1); /* 1 = routeable */
1504 exit(E_USAGE);
1508 int main
1509 (int argc, char *argv[]) {
1510 int i;
1511 int lop;
1512 struct option longopts[] =
1514 AFTRANS_OPTS,
1515 {"version", 0, 0, 'V'},
1516 {"interfaces", 0, 0, 'i'},
1517 {"help", 0, 0, 'h'},
1518 {"route", 0, 0, 'r'},
1519 #if HAVE_FW_MASQUERADE
1520 {"masquerade", 0, 0, 'M'},
1521 #endif
1522 {"protocol", 1, 0, 'A'},
1523 {"tcp", 0, 0, 't'},
1524 {"udp", 0, 0, 'u'},
1525 {"raw", 0, 0, 'w'},
1526 {"unix", 0, 0, 'x'},
1527 {"listening", 0, 0, 'l'},
1528 {"all", 0, 0, 'a'},
1529 {"timers", 0, 0, 'o'},
1530 {"continuous", 0, 0, 'c'},
1531 {"extend", 0, 0, 'e'},
1532 {"programs", 0, 0, 'p'},
1533 {"verbose", 0, 0, 'v'},
1534 {"statistics", 0, 0, 's'},
1535 {"numeric", 0, 0, 'n'},
1536 {"numeric-hosts", 0, 0, '!'},
1537 {"numeric-ports", 0, 0, '@'},
1538 {"numeric-users", 0, 0, '#'},
1539 {"symbolic", 0, 0, 'N'},
1540 {"cache", 0, 0, 'C'},
1541 {"fib", 0, 0, 'F'},
1542 {"groups", 0, 0, 'g'},
1543 {NULL, 0, 0, 0}
1546 #if I18N
1547 bindtextdomain("net-tools", "/usr/share/locale");
1548 textdomain("net-tools");
1549 #endif
1550 getroute_init(); /* Set up AF routing support */
1552 afname[0] = '\0';
1553 while ((i = getopt_long(argc, argv, "MCFA:acdegphinNorstuVv?wxl", longopts, &lop)) != EOF)
1554 switch (i) {
1555 case -1:
1556 break;
1557 case 1:
1558 if (lop < 0 || lop >= AFTRANS_CNT) {
1559 EINTERN("netstat.c", "longopts 1 range");
1560 break;
1562 if (aftrans_opt(longopts[lop].name))
1563 exit(1);
1564 break;
1565 case 'A':
1566 if (aftrans_opt(optarg))
1567 exit(1);
1568 break;
1569 case 'M':
1570 flag_mas++;
1571 break;
1572 case 'a':
1573 flag_all++;
1574 break;
1575 case 'l':
1576 flag_lst++;
1577 break;
1578 case 'c':
1579 flag_cnt++;
1580 break;
1582 case 'd':
1583 flag_deb++;
1584 break;
1585 case 'g':
1586 flag_igmp++;
1587 break;
1588 case 'e':
1589 flag_exp++;
1590 break;
1591 case 'p':
1592 flag_prg++;
1593 break;
1594 case 'i':
1595 flag_int++;
1596 break;
1597 case 'n':
1598 flag_not |= FLAG_NUM;
1599 break;
1600 case '!':
1601 flag_not |= FLAG_NUM_HOST;
1602 break;
1603 case '@':
1604 flag_not |= FLAG_NUM_PORT;
1605 break;
1606 case '#':
1607 flag_not |= FLAG_NUM_USER;
1608 break;
1609 case 'N':
1610 flag_not |= FLAG_SYM;
1611 break;
1612 case 'C':
1613 flag_cf |= FLAG_CACHE;
1614 break;
1615 case 'F':
1616 flag_cf |= FLAG_FIB;
1617 break;
1618 case 'o':
1619 flag_opt++;
1620 break;
1621 case 'V':
1622 version();
1623 /*NOTREACHED */
1624 case 'v':
1625 flag_ver |= FLAG_VERBOSE;
1626 break;
1627 case 'r':
1628 flag_rou++;
1629 break;
1631 case 't':
1632 flag_tcp++;
1633 break;
1635 case 'u':
1636 flag_udp++;
1637 break;
1638 case 'w':
1639 flag_raw++;
1640 break;
1641 case 'x':
1642 if (aftrans_opt("unix"))
1643 exit(1);
1644 break;
1645 case '?':
1646 case 'h':
1647 usage();
1648 case 's':
1649 flag_sta++;
1652 if (flag_int + flag_rou + flag_mas + flag_sta > 1)
1653 usage();
1655 if ((flag_inet || flag_inet6 || flag_sta) && !(flag_tcp || flag_udp || flag_raw))
1656 flag_tcp = flag_udp = flag_raw = 1;
1658 if ((flag_tcp || flag_udp || flag_raw || flag_igmp) && !(flag_inet || flag_inet6))
1659 flag_inet = flag_inet6 = 1;
1661 flag_arg = flag_tcp + flag_udp + flag_raw + flag_unx + flag_ipx
1662 + flag_ax25 + flag_netrom + flag_igmp + flag_x25;
1664 if (flag_mas) {
1665 #if HAVE_FW_MASQUERADE && HAVE_AFINET
1666 #if MORE_THAN_ONE_MASQ_AF
1667 if (!afname[0])
1668 strcpy(afname, DFLT_AF);
1669 #endif
1670 for (;;) {
1671 i = ip_masq_info(flag_not & FLAG_NUM_HOST,
1672 flag_not & FLAG_NUM_PORT, flag_exp);
1673 if (i || !flag_cnt)
1674 break;
1675 sleep(1);
1677 #else
1678 ENOSUPP("netstat.c", "FW_MASQUERADE");
1679 i = -1;
1680 #endif
1681 return (i);
1684 if (flag_sta) {
1685 inittab();
1686 parsesnmp(flag_raw, flag_tcp, flag_udp);
1687 exit(0);
1690 if (flag_rou) {
1691 int options = 0;
1693 if (!afname[0])
1694 strcpy(afname, DFLT_AF);
1696 if (flag_exp == 2)
1697 flag_exp = 1;
1698 else if (flag_exp == 1)
1699 flag_exp = 2;
1701 options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
1702 if (!flag_cf)
1703 options |= FLAG_FIB;
1705 for (;;) {
1706 i = route_info(afname, options);
1707 if (i || !flag_cnt)
1708 break;
1709 sleep(1);
1711 return (i);
1713 if (flag_int) {
1714 for (;;) {
1715 i = iface_info();
1716 if (!flag_cnt || i)
1717 break;
1718 sleep(1);
1720 return (i);
1722 for (;;) {
1723 if (!flag_arg || flag_tcp || flag_udp || flag_raw) {
1724 #if HAVE_AFINET
1725 prg_cache_load();
1726 printf(_("Active Internet connections ")); /* xxx */
1728 if (flag_all)
1729 printf(_("(servers and established)"));
1730 else {
1731 if (flag_lst)
1732 printf(_("(only servers)"));
1733 else
1734 printf(_("(w/o servers)"));
1736 printf(_("\nProto Recv-Q Send-Q Local Address Foreign Address State ")); /* xxx */
1737 if (flag_exp > 1)
1738 printf(_(" User Inode "));
1739 print_progname_banner();
1740 if (flag_opt)
1741 printf(_(" Timer")); /* xxx */
1742 printf("\n");
1743 #else
1744 if (flag_arg) {
1745 i = 1;
1746 ENOSUPP("netstat", "AF INET");
1748 #endif
1750 #if HAVE_AFINET
1751 if (!flag_arg || flag_tcp) {
1752 i = tcp_info();
1753 if (i)
1754 return (i);
1756 if (!flag_arg || flag_udp) {
1757 i = udp_info();
1758 if (i)
1759 return (i);
1761 if (!flag_arg || flag_raw) {
1762 i = raw_info();
1763 if (i)
1764 return (i);
1767 if (flag_igmp) {
1768 #if HAVE_AFINET6
1769 printf( "IPv6/");
1770 #endif
1771 printf( _("IPv4 Group Memberships\n") );
1772 printf( _("Interface RefCnt Group\n") );
1773 printf( "--------------- ------ ---------------------\n" );
1774 i = igmp_info();
1775 if (i)
1776 return (i);
1778 #endif
1780 if (!flag_arg || flag_unx) {
1781 #if HAVE_AFUNIX
1782 prg_cache_load();
1783 i = unix_info();
1784 if (i)
1785 return (i);
1786 #else
1787 if (flag_arg) {
1788 i = 1;
1789 ENOSUPP("netstat", "AF UNIX");
1791 #endif
1793 if (!flag_arg || flag_ipx) {
1794 #if HAVE_AFIPX
1795 i = ipx_info();
1796 if (i)
1797 return (i);
1798 #else
1799 if (flag_arg) {
1800 i = 1;
1801 ENOSUPP("netstat", "AF IPX");
1803 #endif
1805 if (!flag_arg || flag_ax25) {
1806 #if HAVE_AFAX25
1807 i = ax25_info();
1808 if (i)
1809 return (i);
1810 #else
1811 if (flag_arg) {
1812 i = 1;
1813 ENOSUPP("netstat", "AF AX25");
1815 #endif
1817 if(!flag_arg || flag_x25) {
1818 #if HAVE_AFX25
1819 /* FIXME */
1820 i = x25_info();
1821 if (i)
1822 return(i);
1823 #else
1824 if (flag_arg) {
1825 i = 1;
1826 ENOSUPP("netstat", "AF X25");
1828 #endif
1830 if (!flag_arg || flag_netrom) {
1831 #if HAVE_AFNETROM
1832 i = netrom_info();
1833 if (i)
1834 return (i);
1835 #else
1836 if (flag_arg) {
1837 i = 1;
1838 ENOSUPP("netstat", "AF NETROM");
1840 #endif
1842 if (!flag_cnt || i)
1843 break;
1844 sleep(1);
1845 prg_cache_clear();
1847 return (i);