re applied the ipv6 addresses patch from Matthew (for intel platform)
[oss-qm-packages.git] / netstat.c
blob8586512273cf4039d64bcc25806b0618c1f04556
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.35 2000/04/05 00:59:56 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 *980411 {1.34} Arnaldo Carvalho i18n: catgets -> gnu gettext, substitution
47 * of sprintf for snprintf
48 *10/1998 Andi Kleen Use new interface primitives.
49 *990101 {1.36} Bernd Eckenfels usage updated to include -s and -C -F,
50 * fixed netstat -rC output (lib/inet_gr.c)
51 * removed broken NETLINK Support
52 * fixed format for /proc/net/udp|tcp|raw
53 * added -w,-t,-u TcpExt support to -s
54 *990131 {1.37} Jan Kratochvil added -p for prg_cache() & friends
55 * Flames to <short@ucw.cz>.
56 * Tuan Hoang added IGMP support for IPv4 and IPv6
58 *990420 {1.38} Tuan Hoang removed a useless assignment from igmp_do_one()
60 * This program is free software; you can redistribute it
61 * and/or modify it under the terms of the GNU General
62 * Public License as published by the Free Software
63 * Foundation; either version 2 of the License, or (at
64 * your option) any later version.
67 #include <errno.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <strings.h>
72 #include <unistd.h>
73 #include <ctype.h>
74 #include <fcntl.h>
75 #include <netdb.h>
76 #include <paths.h>
77 #include <pwd.h>
78 #include <getopt.h>
79 #include <sys/param.h>
80 #include <sys/socket.h>
81 #include <arpa/inet.h>
82 #include <netinet/in.h>
83 #include <sys/ioctl.h>
84 #include <net/if.h>
85 #include <dirent.h>
87 #include "net-support.h"
88 #include "pathnames.h"
89 #include "version.h"
90 #include "config.h"
91 #include "intl.h"
92 #include "sockets.h"
93 #include "interface.h"
94 #include "util.h"
96 #define PROGNAME_WIDTH 20
98 #if !defined(s6_addr32) && defined(in6a_words)
99 #define s6_addr32 in6a_words /* libinet6 */
100 #endif
102 /* prototypes for statistics.c */
103 void parsesnmp(int, int, int);
104 void inittab(void);
106 typedef enum {
107 SS_FREE = 0, /* not allocated */
108 SS_UNCONNECTED, /* unconnected to any socket */
109 SS_CONNECTING, /* in process of connecting */
110 SS_CONNECTED, /* connected to socket */
111 SS_DISCONNECTING /* in process of disconnecting */
112 } socket_state;
114 #define SO_ACCEPTCON (1<<16) /* performed a listen */
115 #define SO_WAITDATA (1<<17) /* wait data to read */
116 #define SO_NOSPACE (1<<18) /* no space to write */
118 #define DFLT_AF "inet"
120 #define FEATURE_NETSTAT
121 #include "lib/net-features.h"
123 char *Release = RELEASE, *Version = "netstat 1.38 (1999-04-20)", *Signature = "Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang and others";
126 #define E_READ -1
127 #define E_IOCTL -3
129 int flag_int = 0;
130 int flag_rou = 0;
131 int flag_mas = 0;
132 int flag_sta = 0;
134 int flag_all = 0;
135 int flag_lst = 0;
136 int flag_cnt = 0;
137 int flag_deb = 0;
138 int flag_not = 0;
139 int flag_cf = 0;
140 int flag_opt = 0;
141 int flag_raw = 0;
142 int flag_tcp = 0;
143 int flag_udp = 0;
144 int flag_igmp= 0;
145 int flag_rom = 0;
146 int flag_exp = 1;
147 int flag_prg = 0;
148 int flag_arg = 0;
149 int flag_ver = 0;
151 FILE *procinfo;
153 #define INFO_GUTS1(file,name,proc) \
154 procinfo = fopen((file), "r"); \
155 if (procinfo == NULL) { \
156 if (errno != ENOENT) { \
157 perror((file)); \
158 return -1; \
160 if (flag_arg || flag_ver) \
161 ESYSNOT("netstat", (name)); \
162 if (flag_arg) \
163 rc = 1; \
164 } else { \
165 do { \
166 if (fgets(buffer, sizeof(buffer), procinfo)) \
167 (proc)(lnr++, buffer); \
168 } while (!feof(procinfo)); \
169 fclose(procinfo); \
172 #if HAVE_AFINET6
173 #define INFO_GUTS2(file,proc) \
174 lnr = 0; \
175 procinfo = fopen((file), "r"); \
176 if (procinfo != NULL) { \
177 do { \
178 if (fgets(buffer, sizeof(buffer), procinfo)) \
179 (proc)(lnr++, buffer); \
180 } while (!feof(procinfo)); \
181 fclose(procinfo); \
183 #else
184 #define INFO_GUTS2(file,proc)
185 #endif
187 #define INFO_GUTS3 \
188 return rc;
190 #define INFO_GUTS6(file,file6,name,proc) \
191 char buffer[8192]; \
192 int rc = 0; \
193 int lnr = 0; \
194 if (!flag_arg || flag_inet) { \
195 INFO_GUTS1(file,name,proc) \
197 if (!flag_arg || flag_inet6) { \
198 INFO_GUTS2(file6,proc) \
200 INFO_GUTS3
202 #define INFO_GUTS(file,name,proc) \
203 char buffer[8192]; \
204 int rc = 0; \
205 int lnr = 0; \
206 INFO_GUTS1(file,name,proc) \
207 INFO_GUTS3
209 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
210 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
211 #define PROGNAME_WIDTH2(s) #s
213 #define PRG_HASH_SIZE 211
215 static struct prg_node {
216 struct prg_node *next;
217 int inode;
218 char name[PROGNAME_WIDTH];
219 } *prg_hash[PRG_HASH_SIZE];
221 static char prg_cache_loaded = 0;
223 #define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
225 #define PROGNAME_BANNER "PID/Program name"
227 #define print_progname_banner() do { if (flag_prg) printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER); } while (0)
229 #define PRG_LOCAL_ADDRESS "local_address"
230 #define PRG_INODE "inode"
231 #define PRG_SOCKET_PFX "socket:["
232 #define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
233 #define PRG_SOCKET_PFX2 "[0000]:"
234 #define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2))
237 #ifndef LINE_MAX
238 #define LINE_MAX 4096
239 #endif
241 #define PATH_PROC "/proc"
242 #define PATH_FD_SUFF "fd"
243 #define PATH_FD_SUFFl strlen(PATH_FD_SUFF)
244 #define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF
245 #define PATH_CMDLINE "cmdline"
246 #define PATH_CMDLINEl strlen(PATH_CMDLINE)
247 /* NOT working as of glibc-2.0.7: */
248 #undef DIRENT_HAVE_D_TYPE_WORKS
250 static void prg_cache_add(int inode, char *name)
252 unsigned hi = PRG_HASHIT(inode);
253 struct prg_node **pnp,*pn;
255 prg_cache_loaded=2;
256 for (pnp=prg_hash+hi;(pn=*pnp);pnp=&pn->next) {
257 if (pn->inode==inode) {
258 /* Some warning should be appropriate here
259 as we got multiple processes for one i-node */
260 return;
263 if (!(*pnp=malloc(sizeof(**pnp))))
264 return;
265 pn=*pnp;
266 pn->next=NULL;
267 pn->inode=inode;
268 if (strlen(name)>sizeof(pn->name)-1)
269 name[sizeof(pn->name)-1]='\0';
270 strcpy(pn->name,name);
273 static const char *prg_cache_get(int inode)
275 unsigned hi=PRG_HASHIT(inode);
276 struct prg_node *pn;
278 for (pn=prg_hash[hi];pn;pn=pn->next)
279 if (pn->inode==inode) return(pn->name);
280 return("-");
283 static void prg_cache_clear(void)
285 struct prg_node **pnp,*pn;
287 if (prg_cache_loaded == 2)
288 for (pnp=prg_hash;pnp<prg_hash+PRG_HASH_SIZE;pnp++)
289 while ((pn=*pnp)) {
290 *pnp=pn->next;
291 free(pn);
293 prg_cache_loaded=0;
296 static void extract_type_1_socket_inode(const char lname[], long * inode_p) {
298 /* If lname is of the form "socket:[12345]", extract the "12345"
299 as *inode_p. Otherwise, return -1 as *inode_p.
302 if (strlen(lname) < PRG_SOCKET_PFXl+3) *inode_p = -1;
303 else if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) *inode_p = -1;
304 else if (lname[strlen(lname)-1] != ']') *inode_p = -1;
305 else {
306 char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
307 const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
308 char *serr;
310 strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
311 inode_str[inode_str_len] = '\0';
312 *inode_p = strtol(inode_str,&serr,0);
313 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
314 *inode_p = -1;
320 static void extract_type_2_socket_inode(const char lname[], long * inode_p) {
322 /* If lname is of the form "[0000]:12345", extract the "12345"
323 as *inode_p. Otherwise, return -1 as *inode_p.
326 if (strlen(lname) < PRG_SOCKET_PFX2l+1) *inode_p = -1;
327 else if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) *inode_p = -1;
328 else {
329 char *serr;
331 *inode_p=strtol(lname + PRG_SOCKET_PFX2l,&serr,0);
332 if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
333 *inode_p = -1;
339 static void prg_cache_load(void)
341 char line[LINE_MAX],eacces=0;
342 int procfdlen,fd,cmdllen,lnamelen;
343 char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH];
344 long inode;
345 const char *cs,*cmdlp;
346 DIR *dirproc=NULL,*dirfd=NULL;
347 struct dirent *direproc,*direfd;
349 if (prg_cache_loaded || !flag_prg) return;
350 prg_cache_loaded=1;
351 cmdlbuf[sizeof(cmdlbuf)-1]='\0';
352 if (!(dirproc=opendir(PATH_PROC))) goto fail;
353 while (errno=0,direproc=readdir(dirproc)) {
354 #ifdef DIRENT_HAVE_D_TYPE_WORKS
355 if (direproc->d_type!=DT_DIR) continue;
356 #endif
357 for (cs=direproc->d_name;*cs;cs++)
358 if (!isdigit(*cs))
359 break;
360 if (*cs)
361 continue;
362 procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
363 if (procfdlen<=0 || procfdlen>=sizeof(line)-5)
364 continue;
365 errno=0;
366 dirfd=opendir(line);
367 if (! dirfd) {
368 if (errno==EACCES)
369 eacces=1;
370 continue;
372 line[procfdlen] = '/';
373 cmdlp = NULL;
374 while ((direfd = readdir(dirfd))) {
375 #ifdef DIRENT_HAVE_D_TYPE_WORKS
376 if (direfd->d_type!=DT_LNK)
377 continue;
378 #endif
379 if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line))
380 continue;
381 memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
382 PATH_FD_SUFFl+1);
383 strcpy(line + procfdlen + 1, direfd->d_name);
384 lnamelen=readlink(line,lname,sizeof(lname)-1);
385 lname[lnamelen] = '\0'; /*make it a null-terminated string*/
387 extract_type_1_socket_inode(lname, &inode);
389 if (inode < 0) extract_type_2_socket_inode(lname, &inode);
391 if (inode < 0) continue;
393 if (!cmdlp) {
394 if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
395 sizeof(line) - 5)
396 continue;
397 strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
398 fd = open(line, O_RDONLY);
399 if (fd < 0)
400 continue;
401 cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
402 if (close(fd))
403 continue;
404 if (cmdllen == -1)
405 continue;
406 if (cmdllen < sizeof(cmdlbuf) - 1)
407 cmdlbuf[cmdllen]='\0';
408 if ((cmdlp = strrchr(cmdlbuf, '/')))
409 cmdlp++;
410 else
411 cmdlp = cmdlbuf;
414 snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
415 prg_cache_add(inode, finbuf);
417 closedir(dirfd);
418 dirfd = NULL;
420 if (dirproc)
421 closedir(dirproc);
422 if (dirfd)
423 closedir(dirfd);
424 if (!eacces)
425 return;
426 if (prg_cache_loaded == 1) {
427 fail:
428 fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
429 geteuid());
431 else
432 fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
433 " will not be shown, you would have to be root to see it all.)\n"));
436 #if HAVE_AFNETROM
437 static const char *netrom_state[] =
439 N_("LISTENING"),
440 N_("CONN SENT"),
441 N_("DISC SENT"),
442 N_("ESTABLISHED")
445 static int netrom_info(void)
447 FILE *f;
448 char buffer[256], dev[16];
449 int st, vs, vr, sendq, recvq, ret;
451 f = fopen(_PATH_PROCNET_NR, "r");
452 if (f == NULL) {
453 if (errno != ENOENT) {
454 perror(_PATH_PROCNET_NR);
455 return (-1);
457 if (flag_arg || flag_ver)
458 ESYSNOT("netstat", "AF NETROM");
459 if (flag_arg)
460 return (1);
461 else
462 return (0);
464 printf(_("Active NET/ROM sockets\n"));
465 printf(_("User Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
466 fgets(buffer, 256, f);
468 while (fgets(buffer, 256, f)) {
469 buffer[9] = 0;
470 buffer[19] = 0;
471 buffer[29] = 0;
472 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",
473 dev, &st, &vs, &vr, &sendq, &recvq);
474 if (ret != 6) {
475 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
476 continue;
478 printf("%-9s %-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
479 buffer, buffer + 10, buffer + 20,
480 dev,
481 _(netrom_state[st]),
482 vr, vs, sendq, recvq);
484 fclose(f);
485 return 0;
487 #endif
489 /* These enums are used by IPX too. :-( */
490 enum {
491 TCP_ESTABLISHED = 1,
492 TCP_SYN_SENT,
493 TCP_SYN_RECV,
494 TCP_FIN_WAIT1,
495 TCP_FIN_WAIT2,
496 TCP_TIME_WAIT,
497 TCP_CLOSE,
498 TCP_CLOSE_WAIT,
499 TCP_LAST_ACK,
500 TCP_LISTEN,
501 TCP_CLOSING /* now a valid state */
504 #if HAVE_AFINET || HAVE_AFINET6
506 static const char *tcp_state[] =
509 N_("ESTABLISHED"),
510 N_("SYN_SENT"),
511 N_("SYN_RECV"),
512 N_("FIN_WAIT1"),
513 N_("FIN_WAIT2"),
514 N_("TIME_WAIT"),
515 N_("CLOSE"),
516 N_("CLOSE_WAIT"),
517 N_("LAST_ACK"),
518 N_("LISTEN"),
519 N_("CLOSING")
522 static void finish_this_one(int uid, unsigned long inode, const char *timers)
524 struct passwd *pw;
526 if (flag_exp > 1) {
527 if (!flag_not && ((pw = getpwuid(uid)) != NULL))
528 printf("%-10s ", pw->pw_name);
529 else
530 printf("%-10d ", uid);
531 printf("%-10ld ",inode);
533 if (flag_prg)
534 printf("%-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
535 if (flag_opt)
536 printf("%s", timers);
537 putchar('\n');
540 static void igmp_do_one(int lnr, const char *line)
542 char mcast_addr[128];
543 #if HAVE_AFINET6
544 struct sockaddr_in6 mcastaddr;
545 char addr6[INET6_ADDRSTRLEN];
546 struct in6_addr in6;
547 extern struct aftype inet6_aftype;
548 #else
549 struct sockaddr_in mcastaddr;
550 #endif
551 struct aftype *ap;
552 static int idx_flag = 0;
553 static int igmp6_flag = 0;
554 static char device[16];
555 int num, idx, refcnt;
557 if (lnr == 0) {
558 /* IPV6 ONLY */
559 /* igmp6 file does not have any comments on first line */
560 if ( strstr( line, "Device" ) == NULL ) {
561 igmp6_flag = 1;
562 } else {
563 /* IPV4 ONLY */
564 /* 2.1.x kernels and up have Idx field */
565 /* 2.0.x and below do not have Idx field */
566 if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
567 idx_flag = 1;
568 else
569 idx_flag = 0;
570 return;
574 if (igmp6_flag) { /* IPV6 */
575 #if HAVE_AFINET6
576 num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
577 if (num == 4) {
578 /* Demangle what the kernel gives us */
579 sscanf(mcast_addr, "%08X%08X%08X%08X",
580 &in6.s6_addr32[0], &in6.s6_addr32[1],
581 &in6.s6_addr32[2], &in6.s6_addr32[3]);
582 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
583 inet6_aftype.input(1, addr6, (struct sockaddr *) &mcastaddr);
584 mcastaddr.sin6_family = AF_INET6;
585 } else {
586 fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
587 return;
590 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
591 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
592 ((struct sockaddr *) &mcastaddr)->sa_family);
593 return;
595 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
596 flag_not), sizeof(mcast_addr));
597 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
598 #endif
599 } else { /* IPV4 */
600 #if HAVE_AFINET
601 if (line[0] != '\t') {
602 if (idx_flag) {
603 if ((num = sscanf( line, "%d\t%10c", &idx, device)) < 2) {
604 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
605 return;
607 } else {
608 if ( (num = sscanf( line, "%10c", device )) < 1 ) {
609 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
610 return;
613 device[10] = '\0';
614 return;
615 } else if ( line[0] == '\t' ) {
616 if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
617 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
618 return;
620 sscanf( mcast_addr, "%X",
621 &((struct sockaddr_in *) &mcastaddr)->sin_addr.s_addr );
622 ((struct sockaddr *) &mcastaddr)->sa_family = AF_INET;
623 } else {
624 fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
625 return;
628 if ((ap = get_afntype(((struct sockaddr *) &mcastaddr)->sa_family)) == NULL) {
629 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
630 ((struct sockaddr *) &mcastaddr)->sa_family);
631 return;
633 safe_strncpy(mcast_addr, ap->sprint((struct sockaddr *) &mcastaddr,
634 flag_not), sizeof(mcast_addr));
635 printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
636 #endif
637 } /* IPV4 */
640 static int igmp_info(void)
642 INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
643 igmp_do_one);
646 static void tcp_do_one(int lnr, const char *line)
648 unsigned long rxq, txq, time_len, retr, inode;
649 int num, local_port, rem_port, d, state, uid, timer_run, timeout;
650 char rem_addr[128], local_addr[128], timers[64], buffer[1024], more[512];
651 struct aftype *ap;
652 #if HAVE_AFINET6
653 struct sockaddr_in6 localaddr, remaddr;
654 char addr6[INET6_ADDRSTRLEN];
655 struct in6_addr in6;
656 extern struct aftype inet6_aftype;
657 #else
658 struct sockaddr_in localaddr, remaddr;
659 #endif
661 if (lnr == 0)
662 return;
664 num = sscanf(line,
665 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
666 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
667 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
669 if (strlen(local_addr) > 8) {
670 #if HAVE_AFINET6
671 /* Demangle what the kernel gives us */
672 sscanf(local_addr, "%08X%08X%08X%08X",
673 &in6.s6_addr32[0], &in6.s6_addr32[1],
674 &in6.s6_addr32[2], &in6.s6_addr32[3]);
675 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
676 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
677 sscanf(rem_addr, "%08X%08X%08X%08X",
678 &in6.s6_addr32[0], &in6.s6_addr32[1],
679 &in6.s6_addr32[2], &in6.s6_addr32[3]);
680 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
681 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
682 localaddr.sin6_family = AF_INET6;
683 remaddr.sin6_family = AF_INET6;
684 #endif
685 } else {
686 sscanf(local_addr, "%X",
687 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
688 sscanf(rem_addr, "%X",
689 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
690 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
691 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
694 if (num < 11) {
695 fprintf(stderr, _("warning, got bogus tcp line.\n"));
696 return;
698 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
699 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
700 ((struct sockaddr *) &localaddr)->sa_family);
701 return;
703 if (state == TCP_LISTEN) {
704 time_len = 0;
705 retr = 0L;
706 rxq = 0L;
707 txq = 0L;
709 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
710 flag_not), sizeof(local_addr));
711 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr, flag_not),
712 sizeof(rem_addr));
713 if (flag_all || (flag_lst && !rem_port) || (!flag_lst && rem_port)) {
714 snprintf(buffer, sizeof(buffer), "%s", get_sname(htons(local_port), "tcp", flag_not));
716 if ((strlen(local_addr) + strlen(buffer)) > 22)
717 local_addr[22 - strlen(buffer)] = '\0';
719 strcat(local_addr, ":");
720 strcat(local_addr, buffer);
721 snprintf(buffer, sizeof(buffer), "%s", get_sname(htons(rem_port), "tcp", flag_not));
723 if ((strlen(rem_addr) + strlen(buffer)) > 22)
724 rem_addr[22 - strlen(buffer)] = '\0';
726 strcat(rem_addr, ":");
727 strcat(rem_addr, buffer);
728 timers[0] = '\0';
730 if (flag_opt)
731 switch (timer_run) {
732 case 0:
733 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
734 break;
736 case 1:
737 snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
738 (double) time_len / HZ, retr, timeout);
739 break;
741 case 2:
742 snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
743 (double) time_len / HZ, retr, timeout);
744 break;
746 case 3:
747 snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
748 (double) time_len / HZ, retr, timeout);
749 break;
751 default:
752 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
753 timer_run, (double) time_len / HZ, retr, timeout);
754 break;
756 printf("tcp %6ld %6ld %-23s %-23s %-12s",
757 rxq, txq, local_addr, rem_addr, _(tcp_state[state]));
759 finish_this_one(uid,inode,timers);
763 static int tcp_info(void)
765 INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
766 tcp_do_one);
769 static void udp_do_one(int lnr, const char *line)
771 char buffer[8192], local_addr[64], rem_addr[64];
772 char *udp_state, timers[64], more[512];
773 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
774 #if HAVE_AFINET6
775 struct sockaddr_in6 localaddr, remaddr;
776 char addr6[INET6_ADDRSTRLEN];
777 struct in6_addr in6;
778 extern struct aftype inet6_aftype;
779 #else
780 struct sockaddr_in localaddr, remaddr;
781 #endif
782 struct aftype *ap;
783 unsigned long rxq, txq, time_len, retr, inode;
785 if (lnr == 0)
786 return;
788 more[0] = '\0';
789 num = sscanf(line,
790 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
791 &d, local_addr, &local_port,
792 rem_addr, &rem_port, &state,
793 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
795 if (strlen(local_addr) > 8) {
796 #if HAVE_AFINET6
797 sscanf(local_addr, "%08X%08X%08X%08X",
798 &in6.s6_addr32[0], &in6.s6_addr32[1],
799 &in6.s6_addr32[2], &in6.s6_addr32[3]);
800 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
801 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
802 sscanf(rem_addr, "%08X%08X%08X%08X",
803 &in6.s6_addr32[0], &in6.s6_addr32[1],
804 &in6.s6_addr32[2], &in6.s6_addr32[3]);
805 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
806 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
807 localaddr.sin6_family = AF_INET6;
808 remaddr.sin6_family = AF_INET6;
809 #endif
810 } else {
811 sscanf(local_addr, "%X",
812 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
813 sscanf(rem_addr, "%X",
814 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
815 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
816 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
819 retr = 0L;
820 if (!flag_opt)
821 more[0] = '\0';
823 if (num < 10) {
824 fprintf(stderr, _("warning, got bogus udp line.\n"));
825 return;
827 if ((ap = get_afntype(((struct sockaddr *) &localaddr)->sa_family)) == NULL) {
828 fprintf(stderr, _("netstat: unsupported address family %d !\n"),
829 ((struct sockaddr *) &localaddr)->sa_family);
830 return;
832 switch (state) {
833 case TCP_ESTABLISHED:
834 udp_state = _("ESTABLISHED");
835 break;
837 case TCP_CLOSE:
838 udp_state = "";
839 break;
841 default:
842 udp_state = _("UNKNOWN");
843 break;
846 #if HAVE_AFINET6
847 #define notnull(A) (((A.sin6_family == AF_INET6) && \
848 ((A.sin6_addr.s6_addr32[0]) || \
849 (A.sin6_addr.s6_addr32[1]) || \
850 (A.sin6_addr.s6_addr32[2]) || \
851 (A.sin6_addr.s6_addr32[3]))) || \
852 ((A.sin6_family == AF_INET) && \
853 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
854 #else
855 #define notnull(A) (A.sin_addr.s_addr)
856 #endif
858 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
860 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
861 flag_not), sizeof(local_addr));
862 snprintf(buffer, sizeof(buffer), "%s", get_sname(htons(local_port), "udp", flag_not));
863 if ((strlen(local_addr) + strlen(buffer)) > 22)
864 local_addr[22 - strlen(buffer)] = '\0';
865 strcat(local_addr, ":");
866 strcat(local_addr, buffer);
868 snprintf(buffer, sizeof(buffer), "%s", get_sname(htons(rem_port), "udp", flag_not));
869 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
870 flag_not), sizeof(rem_addr));
871 if ((strlen(rem_addr) + strlen(buffer)) > 22)
872 rem_addr[22 - strlen(buffer)] = '\0';
873 strcat(rem_addr, ":");
874 strcat(rem_addr, buffer);
876 timers[0] = '\0';
877 if (flag_opt)
878 switch (timer_run) {
879 case 0:
880 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
881 break;
883 case 1:
884 case 2:
885 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
886 break;
888 default:
889 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
890 retr, timeout);
891 break;
893 printf("udp %6ld %6ld %-23s %-23s %-12s",
894 rxq, txq, local_addr, rem_addr, udp_state);
896 finish_this_one(uid,inode,timers);
900 static int udp_info(void)
902 INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
903 udp_do_one);
906 static void raw_do_one(int lnr, const char *line)
908 char buffer[8192], local_addr[64], rem_addr[64];
909 char timers[64], more[512];
910 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
911 #if HAVE_AFINET6
912 struct sockaddr_in6 localaddr, remaddr;
913 char addr6[INET6_ADDRSTRLEN];
914 struct in6_addr in6;
915 extern struct aftype inet6_aftype;
916 #else
917 struct sockaddr_in localaddr, remaddr;
918 #endif
919 struct aftype *ap;
920 unsigned long rxq, txq, time_len, retr, inode;
922 if (lnr == 0)
923 return;
925 more[0] = '\0';
926 num = sscanf(line,
927 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
928 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
929 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
931 if (strlen(local_addr) > 8) {
932 #if HAVE_AFINET6
933 sscanf(local_addr, "%08X%08X%08X%08X",
934 &in6.s6_addr32[0], &in6.s6_addr32[1],
935 &in6.s6_addr32[2], &in6.s6_addr32[3]);
936 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
937 inet6_aftype.input(1, addr6, (struct sockaddr *) &localaddr);
938 sscanf(rem_addr, "%08X%08X%08X%08X",
939 &in6.s6_addr32[0], &in6.s6_addr32[1],
940 &in6.s6_addr32[2], &in6.s6_addr32[3]);
941 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
942 inet6_aftype.input(1, addr6, (struct sockaddr *) &remaddr);
943 localaddr.sin6_family = AF_INET6;
944 remaddr.sin6_family = AF_INET6;
945 #endif
946 } else {
947 sscanf(local_addr, "%X",
948 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
949 sscanf(rem_addr, "%X",
950 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
951 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
952 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
954 #if HAVE_AFINET6
955 if ((ap = get_afntype(localaddr.sin6_family)) == NULL) {
956 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin6_family);
957 return;
959 #else
960 if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
961 fprintf(stderr, _("netstat: unsupported address family %d !\n"), localaddr.sin_family);
962 return;
964 #endif
966 if (!flag_opt)
967 more[0] = '\0';
969 if (num < 10) {
970 fprintf(stderr, _("warning, got bogus raw line.\n"));
971 return;
974 if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst))
976 snprintf(buffer, sizeof(buffer), "%s", get_sname(htons(local_port), "raw", flag_not));
977 safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr,
978 flag_not), sizeof(local_addr));
979 if ((strlen(local_addr) + strlen(buffer)) > 22)
980 local_addr[22 - strlen(buffer)] = '\0';
981 strcat(local_addr, ":");
982 strcat(local_addr, buffer);
984 snprintf(buffer, sizeof(buffer), "%s", get_sname(htons(rem_port), "raw", flag_not));
985 safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr,
986 flag_not), sizeof(rem_addr));
987 if ((strlen(rem_addr) + strlen(buffer)) > 22)
988 rem_addr[22 - strlen(buffer)] = '\0';
989 strcat(rem_addr, ":");
990 strcat(rem_addr, buffer);
992 timers[0] = '\0';
993 if (flag_opt)
994 switch (timer_run) {
995 case 0:
996 snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
997 break;
999 case 1:
1000 case 2:
1001 snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
1002 retr, timeout);
1003 break;
1005 default:
1006 snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
1007 timer_run, (double) time_len / 100,
1008 retr, timeout);
1009 break;
1011 printf("raw %6ld %6ld %-23s %-23s %-12d",
1012 rxq, txq, local_addr, rem_addr, state);
1014 finish_this_one(uid,inode,timers);
1018 static int raw_info(void)
1020 INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
1021 raw_do_one);
1024 #endif
1027 #if HAVE_AFUNIX
1029 #define HAS_INODE 1
1031 static void unix_do_one(int nr, const char *line)
1033 static int has = 0;
1034 char path[MAXPATHLEN], ss_flags[32];
1035 char *ss_proto, *ss_state, *ss_type;
1036 int num, state, type, inode;
1037 void *d;
1038 unsigned long refcnt, proto, flags;
1040 if (nr == 0) {
1041 if (strstr(line, "Inode"))
1042 has |= HAS_INODE;
1043 return;
1045 path[0] = '\0';
1046 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
1047 &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
1048 if (num < 6) {
1049 fprintf(stderr, _("warning, got bogus unix line.\n"));
1050 return;
1052 if (!(has & HAS_INODE))
1053 snprintf(path,sizeof(path),"%d",inode);
1055 if (!flag_all) {
1056 if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
1057 if (!flag_lst)
1058 return;
1059 } else {
1060 if (flag_lst)
1061 return;
1065 switch (proto) {
1066 case 0:
1067 ss_proto = "unix";
1068 break;
1070 default:
1071 ss_proto = "??";
1074 switch (type) {
1075 case SOCK_STREAM:
1076 ss_type = _("STREAM");
1077 break;
1079 case SOCK_DGRAM:
1080 ss_type = _("DGRAM");
1081 break;
1083 case SOCK_RAW:
1084 ss_type = _("RAW");
1085 break;
1087 case SOCK_RDM:
1088 ss_type = _("RDM");
1089 break;
1091 case SOCK_SEQPACKET:
1092 ss_type = _("SEQPACKET");
1093 break;
1095 default:
1096 ss_type = _("UNKNOWN");
1099 switch (state) {
1100 case SS_FREE:
1101 ss_state = _("FREE");
1102 break;
1104 case SS_UNCONNECTED:
1106 * Unconnected sockets may be listening
1107 * for something.
1109 if (flags & SO_ACCEPTCON) {
1110 ss_state = _("LISTENING");
1111 } else {
1112 ss_state = "";
1114 break;
1116 case SS_CONNECTING:
1117 ss_state = _("CONNECTING");
1118 break;
1120 case SS_CONNECTED:
1121 ss_state = _("CONNECTED");
1122 break;
1124 case SS_DISCONNECTING:
1125 ss_state = _("DISCONNECTING");
1126 break;
1128 default:
1129 ss_state = _("UNKNOWN");
1132 strcpy(ss_flags, "[ ");
1133 if (flags & SO_ACCEPTCON)
1134 strcat(ss_flags, "ACC ");
1135 if (flags & SO_WAITDATA)
1136 strcat(ss_flags, "W ");
1137 if (flags & SO_NOSPACE)
1138 strcat(ss_flags, "N ");
1140 strcat(ss_flags, "]");
1142 printf("%-5s %-6ld %-11s %-10s %-13s ",
1143 ss_proto, refcnt, ss_flags, ss_type, ss_state);
1144 if (has & HAS_INODE)
1145 printf("%-6d ",inode);
1146 else
1147 printf("- ");
1148 if (flag_prg)
1149 printf("%-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
1150 puts(path);
1153 static int unix_info(void)
1156 printf(_("Active UNIX domain sockets "));
1157 if (flag_all)
1158 printf(_("(servers and established)"));
1159 else {
1160 if (flag_lst)
1161 printf(_("(only servers)"));
1162 else
1163 printf(_("(w/o servers)"));
1166 printf(_("\nProto RefCnt Flags Type State I-Node"));
1167 print_progname_banner();
1168 printf(_(" Path\n")); /* xxx */
1171 INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
1174 #endif
1177 #if HAVE_AFAX25
1178 static int ax25_info(void)
1180 FILE *f;
1181 char buffer[256], buf[16];
1182 char *src, *dst, *dev, *p;
1183 int st, vs, vr, sendq, recvq, ret;
1184 int new = -1; /* flag for new (2.1.x) kernels */
1185 static char *ax25_state[5] =
1187 N_("LISTENING"),
1188 N_("SABM SENT"),
1189 N_("DISC SENT"),
1190 N_("ESTABLISHED"),
1191 N_("RECOVERY")
1193 if (!(f = fopen(_PATH_PROCNET_AX25, "r"))) {
1194 if (errno != ENOENT) {
1195 perror(_PATH_PROCNET_AX25);
1196 return (-1);
1198 if (flag_arg || flag_ver)
1199 ESYSNOT("netstat", "AF AX25");
1200 if (flag_arg)
1201 return (1);
1202 else
1203 return (0);
1205 printf(_("Active AX.25 sockets\n"));
1206 printf(_("Dest Source Device State Vr/Vs Send-Q Recv-Q\n"));
1207 while (fgets(buffer, 256, f)) {
1208 if (new == -1) {
1209 if (!strncmp(buffer, "dest_addr", 9)) {
1210 new = 0;
1211 continue; /* old kernels have a header line */
1212 } else
1213 new = 1;
1216 * In a network connection with no user socket the Snd-Q, Rcv-Q
1217 * and Inode fields are empty in 2.0.x and '*' in 2.1.x
1219 sendq = 0;
1220 recvq = 0;
1221 if (new == 0) {
1222 dst = buffer;
1223 src = buffer + 10;
1224 dst[9] = 0;
1225 src[9] = 0;
1226 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",
1227 buf, &st, &vs, &vr, &sendq, &recvq);
1228 if (ret != 4 && ret != 6) {
1229 printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
1230 continue;
1232 dev = buf;
1233 } else {
1234 p = buffer;
1235 while (*p != ' ') p++;
1236 p++;
1237 dev = p;
1238 while (*p != ' ') p++;
1239 *p++ = 0;
1240 src = p;
1241 while (*p != ' ') p++;
1242 *p++ = 0;
1243 dst = p;
1244 while (*p != ' ') p++;
1245 *p++ = 0;
1246 ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
1247 &st, &vs, &vr, &sendq, &recvq);
1248 if (ret != 3 && ret != 5) {
1249 printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
1250 continue;
1253 * FIXME: digipeaters should be handled somehow.
1254 * For now we just strip them.
1256 p = dst;
1257 while (*p && *p != ',') p++;
1258 *p = 0;
1260 printf("%-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n",
1261 dst, src,
1262 dev,
1263 _(ax25_state[st]),
1264 vr, vs, sendq, recvq);
1266 fclose(f);
1267 return 0;
1269 #endif
1272 #if HAVE_AFIPX
1273 static int ipx_info(void)
1275 FILE *f;
1276 char buf[256];
1277 unsigned long txq, rxq;
1278 unsigned int state;
1279 unsigned int uid;
1280 char *st;
1281 int nc;
1282 struct aftype *ap;
1283 struct passwd *pw;
1284 char sad[50], dad[50];
1285 struct sockaddr sa;
1286 unsigned sport = 0, dport = 0;
1288 if (!(f = fopen(_PATH_PROCNET_IPX, "r"))) {
1289 if (errno != ENOENT) {
1290 perror(_PATH_PROCNET_IPX);
1291 return (-1);
1293 if (flag_arg || flag_ver)
1294 ESYSNOT("netstat", "AF IPX");
1295 if (flag_arg)
1296 return (1);
1297 else
1298 return (0);
1300 printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address Foreign Address State")); /* xxx */
1301 if (flag_exp > 1)
1302 printf(_(" User")); /* xxx */
1303 printf("\n");
1304 if ((ap = get_afntype(AF_IPX)) == NULL) {
1305 EINTERN("netstat.c", "AF_IPX missing");
1306 return (-1);
1308 fgets(buf, 255, f);
1310 while (fgets(buf, 255, f) != NULL) {
1311 sscanf(buf, "%s %s %lX %lX %d %d",
1312 sad, dad, &txq, &rxq, &state, &uid);
1313 if ((st = rindex(sad, ':'))) {
1314 *st++ = '\0';
1315 sscanf(st, "%X", &sport); /* net byt order */
1316 sport = ntohs(sport);
1317 } else {
1318 EINTERN("netstat.c", _PATH_PROCNET_IPX " sport format error");
1319 return (-1);
1321 nc = 0;
1322 if (strcmp(dad, "Not_Connected") != 0) {
1323 if ((st = rindex(dad, ':'))) {
1324 *st++ = '\0';
1325 sscanf(st, "%X", &dport); /* net byt order */
1326 dport = ntohs(dport);
1327 } else {
1328 EINTERN("netstat.c", _PATH_PROCNET_IPX " dport format error");
1329 return (-1);
1331 } else
1332 nc = 1;
1334 switch (state) {
1335 case TCP_ESTABLISHED:
1336 st = _("ESTAB");
1337 break;
1339 case TCP_CLOSE:
1340 st = "";
1341 break;
1343 default:
1344 st = _("UNK.");
1345 break;
1348 /* Fetch and resolve the Source */
1349 (void) ap->input(4, sad, &sa);
1350 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1351 snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
1353 if (!nc) {
1354 /* Fetch and resolve the Destination */
1355 (void) ap->input(4, dad, &sa);
1356 safe_strncpy(buf, ap->sprint(&sa, flag_not), sizeof(buf));
1357 snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
1358 } else
1359 strcpy(dad, "-");
1361 printf("IPX %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
1362 if (flag_exp > 1) {
1363 if (!flag_not && ((pw = getpwuid(uid)) != NULL))
1364 printf(" %-10s", pw->pw_name);
1365 else
1366 printf(" %-10d", uid);
1368 printf("\n");
1370 fclose(f);
1371 return 0;
1373 #endif
1375 void ife_print(struct interface *ptr)
1377 printf("%-5.5s ", ptr->name);
1378 printf("%5d %3d ", ptr->mtu, ptr->metric);
1379 /* If needed, display the interface statistics. */
1380 if (ptr->statistics_valid) {
1381 printf("%8lu %6lu %6lu %6lu ",
1382 ptr->stats.rx_packets, ptr->stats.rx_errors,
1383 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
1384 printf("%8lu %6lu %6lu %6lu ",
1385 ptr->stats.tx_packets, ptr->stats.tx_errors,
1386 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
1387 } else {
1388 printf("%-56s", _(" - no statistics available -"));
1390 if (ptr->flags == 0)
1391 printf(_("[NO FLAGS]"));
1392 if (ptr->flags & IFF_ALLMULTI)
1393 printf("A");
1394 if (ptr->flags & IFF_BROADCAST)
1395 printf("B");
1396 if (ptr->flags & IFF_DEBUG)
1397 printf("D");
1398 if (ptr->flags & IFF_LOOPBACK)
1399 printf("L");
1400 if (ptr->flags & IFF_PROMISC)
1401 printf("M");
1402 if (ptr->flags & IFF_NOTRAILERS)
1403 printf("N");
1404 if (ptr->flags & IFF_NOARP)
1405 printf("O");
1406 if (ptr->flags & IFF_POINTOPOINT)
1407 printf("P");
1408 if (ptr->flags & IFF_RUNNING)
1409 printf("R");
1410 if (ptr->flags & IFF_UP)
1411 printf("U");
1412 printf("\n");
1415 static int iface_info(void)
1417 if (skfd < 0) {
1418 if ((skfd = sockets_open(0)) < 0) {
1419 perror("socket");
1420 exit(1);
1422 printf(_("Kernel Interface table\n"));
1424 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
1426 if (for_all_interfaces(do_if_print, &flag_all) < 0) {
1427 perror(_("missing interface information"));
1428 exit(1);
1430 if (flag_cnt)
1431 free_interface_list();
1432 else {
1433 close(skfd);
1434 skfd = -1;
1437 return 0;
1441 static void version(void)
1443 printf("%s\n%s\n%s\n%s\n", Release, Version, Signature, Features);
1444 exit(E_VERSION);
1448 static void usage(void)
1450 fprintf(stderr, _("usage: netstat [-veenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}\n"));
1451 fprintf(stderr, _(" netstat [-vnNcaeol] [<Socket> ...]\n"));
1452 fprintf(stderr, _(" netstat { [-veenNac] -i | [-cnNe] -M | -s }\n\n"));
1454 fprintf(stderr, _(" -r, --route display routing table\n"));
1455 fprintf(stderr, _(" -i, --interfaces display interface table\n"));
1456 fprintf(stderr, _(" -g, --groups display multicast group memberships\n"));
1457 fprintf(stderr, _(" -s, --statistics display networking statistics (like SNMP)\n"));
1458 #if HAVE_FW_MASQUERADE
1459 fprintf(stderr, _(" -M, --masquerade display masqueraded connections\n\n"));
1460 #endif
1461 fprintf(stderr, _(" -v, --verbose be verbose\n"));
1462 fprintf(stderr, _(" -n, --numeric dont resolve names\n"));
1463 fprintf(stderr, _(" -N, --symbolic resolve hardware names\n"));
1464 fprintf(stderr, _(" -e, --extend display other/more information\n"));
1465 fprintf(stderr, _(" -p, --programs display PID/Program name for sockets\n"));
1466 fprintf(stderr, _(" -c, --continuous continuous listing\n\n"));
1467 fprintf(stderr, _(" -l, --listening display listening server sockets\n"));
1468 fprintf(stderr, _(" -a, --all, --listening display all sockets (default: connected)\n"));
1469 fprintf(stderr, _(" -o, --timers display timers\n"));
1470 fprintf(stderr, _(" -F, --fib display Forwarding Information Base (default)\n"));
1471 fprintf(stderr, _(" -C, --cache display routing cache instead of FIB\n\n"));
1473 fprintf(stderr, _(" <Socket>={-t|--tcp} {-u|--udp} {-w|--raw} {-x|--unix} --ax25 --ipx --netrom\n"));
1474 fprintf(stderr, _(" <AF>=Use '-A <af>' or '--<af>' Default: %s\n"), DFLT_AF);
1475 fprintf(stderr, _(" List of possible address families (which support routing):\n"));
1476 print_aflist(1); /* 1 = routeable */
1477 exit(E_USAGE);
1481 int main
1482 (int argc, char *argv[]) {
1483 int i;
1484 int lop;
1485 struct option longopts[] =
1487 AFTRANS_OPTS,
1488 {"version", 0, 0, 'V'},
1489 {"interfaces", 0, 0, 'i'},
1490 {"help", 0, 0, 'h'},
1491 {"route", 0, 0, 'r'},
1492 {"netlink", 2, 0, 'L'},
1493 #if HAVE_FW_MASQUERADE
1494 {"masquerade", 0, 0, 'M'},
1495 #endif
1496 {"protocol", 1, 0, 'A'},
1497 {"tcp", 0, 0, 't'},
1498 {"udp", 0, 0, 'u'},
1499 {"raw", 0, 0, 'w'},
1500 {"unix", 0, 0, 'x'},
1501 {"listening", 0, 0, 'l'},
1502 {"all", 0, 0, 'a'},
1503 {"timers", 0, 0, 'o'},
1504 {"continuous", 0, 0, 'c'},
1505 {"extend", 0, 0, 'e'},
1506 {"programs", 0, 0, 'p'},
1507 {"verbose", 0, 0, 'v'},
1508 {"statistics", 0, 0, 's'},
1509 {"numeric", 0, 0, 'n'},
1510 {"symbolic", 0, 0, 'N'},
1511 {"cache", 0, 0, 'C'},
1512 {"fib", 0, 0, 'F'},
1513 {"groups", 0, 0, 'g'},
1514 {NULL, 0, 0, 0}
1517 #if I18N
1518 bindtextdomain("net-tools", "/usr/share/locale");
1519 textdomain("net-tools");
1520 #endif
1521 getroute_init(); /* Set up AF routing support */
1523 afname[0] = '\0';
1524 while ((i = getopt_long(argc, argv, "MCFA:acdegphinNorstuVv?wxl", longopts, &lop)) != EOF)
1525 switch (i) {
1526 case -1:
1527 break;
1528 case 1:
1529 if (lop < 0 || lop >= AFTRANS_CNT) {
1530 EINTERN("netstat.c", "longopts 1 range");
1531 break;
1533 if (aftrans_opt(longopts[lop].name))
1534 exit(1);
1535 break;
1536 case 'A':
1537 if (aftrans_opt(optarg))
1538 exit(1);
1539 break;
1540 case 'M':
1541 flag_mas++;
1542 break;
1543 case 'a':
1544 flag_all++;
1545 break;
1546 case 'l':
1547 flag_lst++;
1548 break;
1549 case 'c':
1550 flag_cnt++;
1551 break;
1553 case 'd':
1554 flag_deb++;
1555 break;
1556 case 'g':
1557 flag_igmp++;
1558 break;
1559 case 'e':
1560 flag_exp++;
1561 break;
1562 case 'p':
1563 flag_prg++;
1564 break;
1565 case 'i':
1566 flag_int++;
1567 break;
1569 case 'n':
1570 flag_not |= FLAG_NUM;
1571 break;
1572 case 'N':
1573 flag_not |= FLAG_SYM;
1574 break;
1575 case 'C':
1576 flag_cf |= FLAG_CACHE;
1577 break;
1578 case 'F':
1579 flag_cf |= FLAG_FIB;
1580 break;
1581 case 'o':
1582 flag_opt++;
1583 break;
1584 case 'V':
1585 version();
1586 /*NOTREACHED */
1587 case 'v':
1588 flag_ver |= FLAG_VERBOSE;
1589 break;
1590 case 'r':
1591 flag_rou++;
1592 break;
1594 case 't':
1595 flag_tcp++;
1596 break;
1598 case 'u':
1599 flag_udp++;
1600 break;
1601 case 'w':
1602 flag_raw++;
1603 break;
1604 case 'x':
1605 if (aftrans_opt("unix"))
1606 exit(1);
1607 break;
1608 case '?':
1609 case 'h':
1610 usage();
1611 case 's':
1612 flag_sta++;
1615 if (flag_int + flag_rou + flag_mas + flag_sta > 1)
1616 usage();
1618 if ((flag_inet || flag_inet6 || flag_sta) && !(flag_tcp || flag_udp || flag_raw))
1619 flag_tcp = flag_udp = flag_raw = 1;
1621 if ((flag_tcp || flag_udp || flag_raw || flag_igmp) && !(flag_inet || flag_inet6))
1622 flag_inet = flag_inet6 = 1;
1624 flag_arg = flag_tcp + flag_udp + flag_raw + flag_unx + flag_ipx
1625 + flag_ax25 + flag_netrom + flag_igmp;
1627 if (flag_mas) {
1628 #if HAVE_FW_MASQUERADE && HAVE_AFINET
1629 #if MORE_THAN_ONE_MASQ_AF
1630 if (!afname[0])
1631 strcpy(afname, DFLT_AF);
1632 #endif
1633 for (;;) {
1634 i = ip_masq_info(flag_not, flag_exp);
1635 if (i || !flag_cnt)
1636 break;
1637 sleep(1);
1639 #else
1640 ENOSUPP("netstat.c", "FW_MASQUERADE");
1641 i = -1;
1642 #endif
1643 return (i);
1646 if (flag_sta) {
1647 inittab();
1648 parsesnmp(flag_raw, flag_tcp, flag_udp);
1649 exit(0);
1652 if (flag_rou) {
1653 int options = 0;
1655 if (!afname[0])
1656 strcpy(afname, DFLT_AF);
1658 if (flag_exp == 2)
1659 flag_exp = 1;
1660 else if (flag_exp == 1)
1661 flag_exp = 2;
1663 options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
1664 if (!flag_cf)
1665 options |= FLAG_FIB;
1667 for (;;) {
1668 i = route_info(afname, options);
1669 if (i || !flag_cnt)
1670 break;
1671 sleep(1);
1673 return (i);
1675 if (flag_int) {
1676 for (;;) {
1677 i = iface_info();
1678 if (!flag_cnt || i)
1679 break;
1680 sleep(1);
1682 return (i);
1684 for (;;) {
1685 if (!flag_arg || flag_tcp || flag_udp || flag_raw) {
1686 #if HAVE_AFINET
1687 prg_cache_load();
1688 printf(_("Active Internet connections ")); /* xxx */
1690 if (flag_all)
1691 printf(_("(servers and established)"));
1692 else {
1693 if (flag_lst)
1694 printf(_("(only servers)"));
1695 else
1696 printf(_("(w/o servers)"));
1698 printf(_("\nProto Recv-Q Send-Q Local Address Foreign Address State ")); /* xxx */
1699 if (flag_exp > 1)
1700 printf(_(" User Inode "));
1701 print_progname_banner();
1702 if (flag_opt)
1703 printf(_(" Timer")); /* xxx */
1704 printf("\n");
1705 #else
1706 if (flag_arg) {
1707 i = 1;
1708 ENOSUPP("netstat", "AF INET");
1710 #endif
1712 #if HAVE_AFINET
1713 if (!flag_arg || flag_tcp) {
1714 i = tcp_info();
1715 if (i)
1716 return (i);
1718 if (!flag_arg || flag_udp) {
1719 i = udp_info();
1720 if (i)
1721 return (i);
1723 if (!flag_arg || flag_raw) {
1724 i = raw_info();
1725 if (i)
1726 return (i);
1729 if (flag_igmp) {
1730 #if HAVE_AFINET6
1731 printf( "IPv6/");
1732 #endif
1733 printf( _("IPv4 Group Memberships\n") );
1734 printf( _("Interface RefCnt Group\n") );
1735 printf( "--------------- ------ ---------------------\n" );
1736 i = igmp_info();
1737 if (i)
1738 return (i);
1740 #endif
1742 if (!flag_arg || flag_unx) {
1743 #if HAVE_AFUNIX
1744 prg_cache_load();
1745 i = unix_info();
1746 if (i)
1747 return (i);
1748 #else
1749 if (flag_arg) {
1750 i = 1;
1751 ENOSUPP("netstat", "AF UNIX");
1753 #endif
1755 if (!flag_arg || flag_ipx) {
1756 #if HAVE_AFIPX
1757 i = ipx_info();
1758 if (i)
1759 return (i);
1760 #else
1761 if (flag_arg) {
1762 i = 1;
1763 ENOSUPP("netstat", "AF IPX");
1765 #endif
1767 if (!flag_arg || flag_ax25) {
1768 #if HAVE_AFAX25
1769 i = ax25_info();
1770 if (i)
1771 return (i);
1772 #else
1773 if (flag_arg) {
1774 i = 1;
1775 ENOSUPP("netstat", "AF AX25");
1777 #endif
1779 if (!flag_arg || flag_netrom) {
1780 #if HAVE_AFNETROM
1781 i = netrom_info();
1782 if (i)
1783 return (i);
1784 #else
1785 if (flag_arg) {
1786 i = 1;
1787 ENOSUPP("netstat", "AF NETROM");
1789 #endif
1791 if (!flag_cnt || i)
1792 break;
1793 sleep(1);
1794 prg_cache_clear();
1796 return (i);