Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: netstat.c
===================================================================
--- netstat.c	(nonexistent)
+++ netstat.c	(revision 5)
@@ -0,0 +1,2513 @@
+/*
+ * netstat    This file contains an implementation of the command
+ *              that helps in debugging the networking modules.
+ *
+ * NET-TOOLS    A collection of programs that form the base set of the
+ *              NET-3 Networking Distribution for the LINUX operating
+ *              system.
+ *
+ * Version:     $Id: netstat.c,v 1.73 2011-04-20 01:35:22 ecki Exp $
+ *
+ * Authors:     Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
+ *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *              Phil Packer, <pep@wicked.demon.co.uk>
+ *              Johannes Stille, <johannes@titan.os.open.de>
+ *              Bernd Eckenfels, <net-tools@lina.inka.de>
+ *              Phil Blundell <philb@gnu.org>
+ *              Tuan Hoang <tqhoang@bigfoot.com>
+ *
+ * Tuned for NET3 by:
+ *              Alan Cox, <A.Cox@swansea.ac.uk>
+ *              Copyright (c) 1993  Fred Baumgarten
+ *
+ * Modified:
+ *
+ *960116 {1.01} Bernd Eckenfels:        verbose, cleanups
+ *960204 {1.10} Bernd Eckenfels:        aftrans, usage, new route_info,
+ *                                      DLFT_AF
+ *960204 {1.11} Bernd Eckenfels:        netlink support
+ *960204 {1.12} Bernd Eckenfels:        route_init()
+ *960215 {1.13} Bernd Eckenfels:        netlink_print honors HAVE_
+ *960217 {1.14} Bernd Eckenfels:        masq_info from Jos Vos and
+ *                                      ax25_info from Jonathan Naylor.
+ *960218 {1.15} Bernd Eckenfels:        ipx_info rewritten, -e for tcp/ipx
+ *960220 {1.16} Bernd Eckenfels:        minor output reformats, -a for -x
+ *960221 {1.17} Bernd Eckenfels:        route_init->getroute_init
+ *960426 {1.18} Bernd Eckenfels:        new RTACTION, SYM/NUM, FIB/CACHE
+ *960517 {1.19} Bernd Eckenfels:        usage() spelling fix and --unix inode,
+ *                                      ':' is part of sock_addr for --inet
+ *960822 {x.xx} Frank Strauss:          INET6 support
+ *
+ *970406 {1.33} Philip Copeland         Added snmp reporting support module -s
+ *                                      code provided by Andi Kleen
+ *                                      (relly needs to be kernel hooked but
+ *                                      this will do in the meantime)
+ *                                      minor header file misplacement tidy up.
+ *980815 {1.xx} Stephane Fillod:       X.25 support
+ *980411 {1.34} Arnaldo Carvalho        i18n: catgets -> gnu gettext, substitution
+ *                                      of sprintf for snprintf
+ *10/1998	Andi Kleen              Use new interface primitives.
+ *990101 {1.36}	Bernd Eckenfels		usage updated to include -s and -C -F,
+ *					fixed netstat -rC output (lib/inet_gr.c)
+ *					removed broken NETLINK Support
+ *					fixed format for /proc/net/udp|tcp|raw
+ *					added -w,-t,-u TcpExt support to -s
+ *990131 {1.37} Jan Kratochvil          added -p for prg_cache() & friends
+ *                                      Flames to <short@ucw.cz>.
+ *              Tuan Hoang              added IGMP support for IPv4 and IPv6
+ *
+ *990420 {1.38} Tuan Hoang              removed a useless assignment from igmp_do_one()
+ *20010404 {1.39} Arnaldo Carvalho de Melo - use setlocale
+ *20081201 {1.42} Brian Micek           added -L|--udplite options for RFC 3828
+ *20020722 {1.51} Thomas Preusser       added SCTP over IPv4 support
+ *
+ *              This program is free software; you can redistribute it
+ *              and/or  modify it under  the terms of  the GNU General
+ *              Public  License as  published  by  the  Free  Software
+ *              Foundation;  either  version 2 of the License, or  (at
+ *              your option) any later version.
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <paths.h>
+#include <pwd.h>
+#include <getopt.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#include <dirent.h>
+
+#include "net-support.h"
+#include "pathnames.h"
+#include "version.h"
+#include "config.h"
+#include "intl.h"
+#include "sockets.h"
+#include "interface.h"
+#include "util.h"
+#include "proc.h"
+
+#if HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+#if HAVE_AFBLUETOOTH
+/*
+   Only following stuff is needed from
+   kernel:   net/bluetooth/bluetooth.h
+   or bluez: bluetooth/bluetooth.h
+ */
+#define BT_SECURITY_SDP         0
+#define BT_SECURITY_LOW         1
+#define BT_SECURITY_MEDIUM      2
+#define BT_SECURITY_HIGH        3
+#define BT_SECURITY_FIPS        4
+
+/* Connection and socket states */
+enum {
+  BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
+  BT_OPEN,
+  BT_BOUND,
+  BT_LISTEN,
+  BT_CONNECT,
+  BT_CONNECT2,
+  BT_CONFIG,
+  BT_DISCONN,
+  BT_CLOSED
+};
+#endif
+
+#define PROGNAME_WIDTH 20
+#define SELINUX_WIDTH 50
+
+#if !defined(s6_addr32) && defined(in6a_words)
+#define s6_addr32 in6a_words	/* libinet6			*/
+#endif
+
+/* prototypes for statistics.c */
+void parsesnmp(int, int, int, int);
+void parsesnmp6(int, int, int);
+
+typedef enum {
+    SS_FREE = 0,		/* not allocated                */
+    SS_UNCONNECTED,		/* unconnected to any socket    */
+    SS_CONNECTING,		/* in process of connecting     */
+    SS_CONNECTED,		/* connected to socket          */
+    SS_DISCONNECTING		/* in process of disconnecting  */
+} socket_state;
+
+#define SO_ACCEPTCON    (1<<16)	/* performed a listen           */
+#define SO_WAITDATA     (1<<17)	/* wait data to read            */
+#define SO_NOSPACE      (1<<18)	/* no space to write            */
+
+#define DFLT_AF "inet"
+
+#define FEATURE_NETSTAT
+#include "lib/net-features.h"
+
+static char *Release = RELEASE, *Signature = "Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang, Brian Micek and others";
+
+
+#define E_READ  -1
+#define E_IOCTL -3
+
+int flag_int = 0;
+int flag_rou = 0;
+int flag_mas = 0;
+int flag_sta = 0;
+
+int flag_all = 0;
+int flag_lst = 0;
+int flag_cnt = 0;
+int flag_deb = 0;
+int flag_not = 0;
+int flag_cf  = 0;
+int flag_opt = 0;
+int flag_raw = 0;
+int flag_tcp = 0;
+int flag_sctp= 0;
+int flag_udp = 0;
+int flag_udplite = 0;
+int flag_igmp= 0;
+int flag_rom = 0;
+int flag_exp = 1;
+int flag_wide= 0;
+int flag_prg = 0;
+int flag_arg = 0;
+int flag_noprot = 0;
+int flag_ver = 0;
+int flag_l2cap = 0;
+int flag_rfcomm = 0;
+int flag_selinux = 0;
+
+FILE *procinfo;
+
+#define INFO_GUTS1(file,name,proc,prot)			\
+  procinfo = proc_fopen((file));			\
+  if (procinfo == NULL) {				\
+    if (errno != ENOENT && errno != EACCES) {		\
+      perror((file));					\
+      return -1;					\
+    }							\
+    if (!flag_noprot && (flag_arg || flag_ver))		\
+      ESYSNOT("netstat", (name));			\
+    if (!flag_noprot && flag_arg)			\
+      rc = 1;						\
+  } else {						\
+    do {						\
+      if (fgets(buffer, sizeof(buffer), procinfo))	\
+        (proc)(lnr++, buffer,prot);			\
+    } while (!feof(procinfo));				\
+    fclose(procinfo);					\
+  }
+
+#if HAVE_AFINET6
+#define INFO_GUTS2(file,proc,prot)			\
+  lnr = 0;						\
+  procinfo = proc_fopen((file));		       	\
+  if (procinfo != NULL) {				\
+    do {						\
+      if (fgets(buffer, sizeof(buffer), procinfo))	\
+	(proc)(lnr++, buffer,prot);			\
+    } while (!feof(procinfo));				\
+    fclose(procinfo);					\
+  }
+#else
+#define INFO_GUTS2(file,proc,prot)
+#endif
+
+#define INFO_GUTS3					\
+ return rc;
+
+#define INFO_GUTS6(file,file6,name,proc,prot4,prot6)	\
+ char buffer[8192];					\
+ int rc = 0;						\
+ int lnr = 0;						\
+ if (!flag_arg || flag_inet) {				\
+    INFO_GUTS1(file,name,proc,prot4)			\
+ }							\
+ if (!flag_arg || flag_inet6) {				\
+    INFO_GUTS2(file6,proc,prot6)			\
+ }							\
+ INFO_GUTS3
+
+#define INFO_GUTS(file,name,proc,prot)			\
+ char buffer[8192];					\
+ int rc = 0;						\
+ int lnr = 0;						\
+ INFO_GUTS1(file,name,proc,prot)			\
+ INFO_GUTS3
+
+#define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
+#define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
+#define PROGNAME_WIDTH2(s) #s
+
+#define SELINUX_WIDTHs SELINUX_WIDTH1(SELINUX_WIDTH)
+#define SELINUX_WIDTH1(s) SELINUX_WIDTH2(s)
+#define SELINUX_WIDTH2(s) #s
+
+#define PRG_HASH_SIZE 211
+
+static struct prg_node {
+    struct prg_node *next;
+    unsigned long inode;
+    char name[PROGNAME_WIDTH];
+    char scon[SELINUX_WIDTH];
+} *prg_hash[PRG_HASH_SIZE];
+
+static char prg_cache_loaded = 0;
+
+#define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
+
+#define PROGNAME_BANNER "PID/Program name"
+#define SELINUX_BANNER "Security Context"
+
+#define print_progname_banner() do { if (flag_prg) printf(" %-" PROGNAME_WIDTHs "s",PROGNAME_BANNER); } while (0)
+
+#define print_selinux_banner() do { if (flag_selinux) printf("%-" SELINUX_WIDTHs "s"," " SELINUX_BANNER); } while (0)
+
+#define PRG_LOCAL_ADDRESS "local_address"
+#define PRG_INODE	 "inode"
+#define PRG_SOCKET_PFX    "socket:["
+#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
+#define PRG_SOCKET_PFX2   "[0000]:"
+#define PRG_SOCKET_PFX2l  (strlen(PRG_SOCKET_PFX2))
+
+
+#ifndef LINE_MAX
+#define LINE_MAX 4096
+#endif
+
+#define PATH_PROC	   "/proc"
+#define PATH_FD_SUFF	"fd"
+#define PATH_FD_SUFFl       strlen(PATH_FD_SUFF)
+#define PATH_PROC_X_FD      PATH_PROC "/%s/" PATH_FD_SUFF
+#define PATH_CMDLINE	"cmdline"
+#define PATH_CMDLINEl       strlen(PATH_CMDLINE)
+
+static void prg_cache_add(unsigned long inode, char *name, const char *scon)
+{
+    unsigned hi = PRG_HASHIT(inode);
+    struct prg_node **pnp,*pn;
+
+    prg_cache_loaded = 2;
+    for (pnp = prg_hash + hi; (pn = *pnp); pnp = &pn->next) {
+	if (pn->inode == inode) {
+	    /* Some warning should be appropriate here
+	       as we got multiple processes for one i-node */
+	    return;
+	}
+    }
+    if (!(*pnp = malloc(sizeof(**pnp))))
+	return;
+    pn = *pnp;
+    pn->next = NULL;
+    pn->inode = inode;
+    safe_strncpy(pn->name, name, sizeof(pn->name));
+
+    {
+	int len = (strlen(scon) - sizeof(pn->scon)) + 1;
+	if (len > 0)
+            safe_strncpy(pn->scon, &scon[len + 1], sizeof(pn->scon));
+	else
+            safe_strncpy(pn->scon, scon, sizeof(pn->scon));
+    }
+
+}
+
+static const char *prg_cache_get(unsigned long inode)
+{
+    unsigned hi = PRG_HASHIT(inode);
+    struct prg_node *pn;
+
+    for (pn = prg_hash[hi]; pn; pn = pn->next)
+	if (pn->inode == inode)
+	    return (pn->name);
+    return ("-");
+}
+
+static const char *prg_cache_get_con(unsigned long inode)
+{
+    unsigned hi = PRG_HASHIT(inode);
+    struct prg_node *pn;
+
+    for (pn = prg_hash[hi]; pn; pn = pn->next)
+	if (pn->inode == inode)
+	    return (pn->scon);
+    return ("-");
+}
+
+static void prg_cache_clear(void)
+{
+    struct prg_node **pnp,*pn;
+
+    if (prg_cache_loaded == 2)
+	for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++)
+	    while ((pn = *pnp)) {
+		*pnp = pn->next;
+		free(pn);
+	    }
+    prg_cache_loaded = 0;
+}
+
+static void wait_continous(void)
+{
+    fflush(stdout);
+    sleep(1);
+}
+
+static int extract_type_1_socket_inode(const char lname[], unsigned long * inode_p) {
+
+    /* If lname is of the form "socket:[12345]", extract the "12345"
+       as *inode_p.  Otherwise, return -1 as *inode_p.
+       */
+
+    if (strlen(lname) < PRG_SOCKET_PFXl+3) return(-1);
+
+    if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) return(-1);
+    if (lname[strlen(lname)-1] != ']') return(-1);
+
+    {
+        char inode_str[strlen(lname + 1)];  /* e.g. "12345" */
+        const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
+        char *serr;
+
+        strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
+        inode_str[inode_str_len] = '\0';
+        *inode_p = strtoul(inode_str, &serr, 0);
+        if (!serr || *serr || *inode_p == ~0)
+            return(-1);
+    }
+    return(0);
+}
+
+
+
+static int extract_type_2_socket_inode(const char lname[], unsigned long * inode_p) {
+
+    /* If lname is of the form "[0000]:12345", extract the "12345"
+       as *inode_p.  Otherwise, return -1 as *inode_p.
+       */
+
+    if (strlen(lname) < PRG_SOCKET_PFX2l+1) return(-1);
+    if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) return(-1);
+
+    {
+        char *serr;
+
+        *inode_p = strtoul(lname + PRG_SOCKET_PFX2l, &serr, 0);
+        if (!serr || *serr || *inode_p == ~0)
+            return(-1);
+    }
+    return(0);
+}
+
+
+
+
+static void prg_cache_load(void)
+{
+    char line[LINE_MAX], eacces=0;
+    int procfdlen, fd, cmdllen, lnamelen;
+    char lname[30], cmdlbuf[512], finbuf[PROGNAME_WIDTH];
+    unsigned long inode;
+    const char *cs, *cmdlp;
+    DIR *dirproc = NULL, *dirfd = NULL;
+    struct dirent *direproc, *direfd;
+#if HAVE_SELINUX
+    security_context_t scon = NULL;
+#endif
+
+    if (prg_cache_loaded || !flag_prg) return;
+    prg_cache_loaded = 1;
+    cmdlbuf[sizeof(cmdlbuf) - 1] = '\0';
+    if (!(dirproc=opendir(PATH_PROC))) goto fail;
+    while (errno = 0, direproc = readdir(dirproc)) {
+	for (cs = direproc->d_name; *cs; cs++)
+	    if (!isdigit(*cs))
+		break;
+	if (*cs)
+	    continue;
+	procfdlen = snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
+	if (procfdlen <= 0 || procfdlen >= sizeof(line) - 5)
+	    continue;
+	errno = 0;
+	dirfd = opendir(line);
+	if (! dirfd) {
+	    if (errno == EACCES)
+		eacces = 1;
+	    continue;
+	}
+	line[procfdlen] = '/';
+	cmdlp = NULL;
+	while ((direfd = readdir(dirfd))) {
+           /* Skip . and .. */
+           if (!isdigit(direfd->d_name[0]))
+               continue;
+	    if (procfdlen + 1 + strlen(direfd->d_name) + 1 > sizeof(line))
+		continue;
+	    memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
+		   PATH_FD_SUFFl + 1);
+        safe_strncpy(line + procfdlen + 1, direfd->d_name,
+                        sizeof(line) - procfdlen - 1);
+	    lnamelen = readlink(line, lname, sizeof(lname) - 1);
+	    if (lnamelen == -1)
+		    continue;
+            lname[lnamelen] = '\0';  /*make it a null-terminated string*/
+
+            if (extract_type_1_socket_inode(lname, &inode) < 0)
+              if (extract_type_2_socket_inode(lname, &inode) < 0)
+                continue;
+
+	    if (!cmdlp) {
+		if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
+		    sizeof(line) - 5)
+		    continue;
+        safe_strncpy(line + procfdlen - PATH_FD_SUFFl, PATH_CMDLINE,
+                        sizeof(line) - procfdlen + PATH_FD_SUFFl);
+		fd = open(line, O_RDONLY);
+		if (fd < 0)
+		    continue;
+		cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
+		if (close(fd))
+		    continue;
+		if (cmdllen == -1)
+		    continue;
+		if (cmdllen < sizeof(cmdlbuf) - 1)
+		    cmdlbuf[cmdllen]='\0';
+		if (cmdlbuf[0] == '/' && (cmdlp = strrchr(cmdlbuf, '/')))
+		    cmdlp++;
+		else
+		    cmdlp = cmdlbuf;
+	    }
+
+	    snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
+#if HAVE_SELINUX
+	    if (getpidcon(atoi(direproc->d_name), &scon) == -1) {
+		    scon=xstrdup("-");
+	    }
+	    prg_cache_add(inode, finbuf, scon);
+	    freecon(scon);
+#else
+	    prg_cache_add(inode, finbuf, "-");
+#endif
+	}
+	closedir(dirfd);
+	dirfd = NULL;
+    }
+    if (dirproc)
+	closedir(dirproc);
+    if (dirfd)
+	closedir(dirfd);
+    if (!eacces)
+	return;
+    if (prg_cache_loaded == 1) {
+    fail:
+	fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
+		geteuid());
+    }
+    else
+	fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
+			 " will not be shown, you would have to be root to see it all.)\n"));
+}
+
+#if HAVE_AFNETROM
+static const char *netrom_state[] =
+{
+    N_("LISTENING"),
+    N_("CONN SENT"),
+    N_("DISC SENT"),
+    N_("ESTABLISHED")
+};
+
+static int netrom_info(void)
+{
+    FILE *f;
+    char buffer[256], dev[16];
+    int st, vs, vr, sendq, recvq, ret;
+
+    f = proc_fopen(_PATH_PROCNET_NR);
+    if (f == NULL) {
+	if (errno != ENOENT) {
+	    perror(_PATH_PROCNET_NR);
+	    return (-1);
+	}
+	if (flag_arg || flag_ver)
+	    ESYSNOT("netstat", "AF NETROM");
+	if (flag_arg)
+	    return (1);
+	else
+	    return (0);
+    }
+    printf(_("Active NET/ROM sockets\n"));
+    printf(_("User       Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q\n"));
+    if (fgets(buffer, 256, f))
+	/* eat line */;
+
+    while (fgets(buffer, 256, f)) {
+	buffer[9] = 0;
+	buffer[19] = 0;
+	buffer[29] = 0;
+	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",
+	       dev, &st, &vs, &vr, &sendq, &recvq);
+	if (ret != 6) {
+	    printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR);
+	    continue;
+	}
+	printf("%-9s  %-9s  %-9s  %-6s  %-11s  %03d/%03d  %-6d  %-6d\n",
+	       buffer, buffer + 10, buffer + 20,
+	       dev,
+	       _(netrom_state[st]),
+	       vr, vs, sendq, recvq);
+    }
+    fclose(f);
+    return 0;
+}
+#endif
+
+#if HAVE_AFROSE
+static const char * const rose_state[] =
+{
+    N_("LISTENING"),
+    N_("CONN SENT"),
+    N_("DISC SENT"),
+    N_("ESTABLISHED"),
+};
+
+static int rose_info(void)
+{
+    FILE *f;
+    char buffer[256], dev[6];
+    int ret, st, lci, neigh;
+    char src_addr[10], src_call[9], dest_addr[10], dest_call[9];
+
+    f = fopen(_PATH_PROCNET_ROSE, "r");
+    if (f == NULL) {
+	if (errno != ENOENT) {
+	    perror(_PATH_PROCNET_ROSE);
+	    return (-1);
+	}
+	if (flag_arg || flag_ver)
+	    ESYSNOT("netstat", "AF ROSE");
+	if (flag_arg)
+	    return (1);
+	else
+	    return (0);
+    }
+    printf(_("Active ROSE sockets\n"));
+    printf(_("dest_addr   dest_call  src_addr    src_call  dev   lci neigh   state\n"));
+    if (fgets(buffer, 256, f))
+	/* eat line */;
+
+    while (fgets(buffer, 256, f)) {
+	ret = sscanf(buffer, "%s %s %s %s %s %d %d %d",
+		dest_addr, dest_call, src_addr, src_call, dev, &lci, &neigh, &st);
+	if (ret != 8) {
+	    printf(_("Problem reading data from %s\n"), _PATH_PROCNET_ROSE);
+	    continue;
+	}
+	printf("%-10s  %-9s  %-10s  %-9s %-5s %3d %5d   %s\n",
+		dest_addr, dest_call, src_addr, src_call, dev, lci, neigh, _(rose_state[st]));
+    }
+    fclose(f);
+    return 0;
+}
+#endif
+
+/* These enums are used by IPX too. :-( */
+enum {
+    TCP_ESTABLISHED = 1,
+    TCP_SYN_SENT,
+    TCP_SYN_RECV,
+    TCP_FIN_WAIT1,
+    TCP_FIN_WAIT2,
+    TCP_TIME_WAIT,
+    TCP_CLOSE,
+    TCP_CLOSE_WAIT,
+    TCP_LAST_ACK,
+    TCP_LISTEN,
+    TCP_CLOSING			/* now a valid state */
+};
+
+#if HAVE_AFINET || HAVE_AFINET6
+
+static const char *tcp_state[] =
+{
+    "",
+    N_("ESTABLISHED"),
+    N_("SYN_SENT"),
+    N_("SYN_RECV"),
+    N_("FIN_WAIT1"),
+    N_("FIN_WAIT2"),
+    N_("TIME_WAIT"),
+    N_("CLOSE"),
+    N_("CLOSE_WAIT"),
+    N_("LAST_ACK"),
+    N_("LISTEN"),
+    N_("CLOSING")
+};
+
+static void finish_this_one(int uid, unsigned long inode, const char *timers)
+{
+    struct passwd *pw;
+
+    if (flag_exp > 1) {
+	if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
+	    printf(" %-10s ", pw->pw_name);
+	else
+	    printf(" %-10d ", uid);
+	printf("%-10lu",inode);
+    }
+    if (flag_prg)
+	printf(" %-" PROGNAME_WIDTHs "s",prg_cache_get(inode));
+    if (flag_selinux)
+	printf(" %-" SELINUX_WIDTHs "s",prg_cache_get_con(inode));
+
+    if (flag_opt)
+	printf(" %s", timers);
+    putchar('\n');
+}
+
+static void igmp_do_one(int lnr, const char *line,const char *prot)
+{
+    char mcast_addr[128];
+    struct sockaddr_storage sas;
+    struct sockaddr_in *sin = (struct sockaddr_in *)&sas;
+#if HAVE_AFINET6
+    char addr6[INET6_ADDRSTRLEN];
+    struct in6_addr in6;
+    extern struct aftype inet6_aftype;
+#endif
+    const struct aftype *ap;
+    static int idx_flag = 0;
+    static int igmp6_flag = 0;
+    static char device[16];
+    int num, idx, refcnt;
+    char* offset;
+
+    if (lnr == 0) {
+	/* IPV6 ONLY */
+	/* igmp6 file does not have any comments on first line */
+	if ( strstr( line, "Device" ) == NULL ) {
+	    igmp6_flag = 1;
+	} else {
+	    /* IPV4 ONLY */
+	    /* 2.1.x kernels and up have Idx field */
+	    /* 2.0.x and below do not have Idx field */
+	    if ( strncmp( line, "Idx", strlen("Idx") ) == 0 )
+		idx_flag = 1;
+	    else
+		idx_flag = 0;
+	    return;
+	}
+    }
+
+    if (igmp6_flag) {    /* IPV6 */
+#if HAVE_AFINET6
+	num = sscanf( line, "%d %15s %64[0-9A-Fa-f] %d", &idx, device, mcast_addr, &refcnt );
+	if (num == 4) {
+	    /* Demangle what the kernel gives us */
+	    sscanf(mcast_addr, "%08X%08X%08X%08X",
+		   &in6.s6_addr32[0], &in6.s6_addr32[1],
+           &in6.s6_addr32[2], &in6.s6_addr32[3]);
+	    in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
+	    in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
+	    in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
+	    in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
+        inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	    inet6_aftype.input(1, addr6, &sas);
+	    sas.ss_family = AF_INET6;
+	} else {
+	    fprintf(stderr, _("warning, got bogus igmp6 line %d.\n"), lnr);
+	    return;
+	}
+
+	if ((ap = get_afntype(sas.ss_family)) == NULL) {
+	    fprintf(stderr, _("netstat: unsupported address family %d !\n"),
+		    sas.ss_family);
+	    return;
+	}
+	safe_strncpy(mcast_addr, ap->sprint(&sas, flag_not & FLAG_NUM_HOST),
+		sizeof(mcast_addr));
+	printf("%-15s %-6d %s\n", device, refcnt, mcast_addr);
+#endif
+    } else {    /* IPV4 */
+#if HAVE_AFINET
+	if (line[0] != '\t') {
+	    if (idx_flag) {
+		if ((num = sscanf(line, "%d\t%15c", &idx, device)) < 2) {
+		    fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
+		    return;
+		}
+	    } else {
+		if ((num = sscanf(line, "%15c", device)) < 1 ) {
+		    fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
+		    return;
+		}
+	    }
+
+	    offset = strrchr(device, ':');
+	    if (offset)
+		*offset = 0;
+
+	    return;
+	} else if ( line[0] == '\t' ) {
+	    if ( (num = sscanf(line, "\t%8[0-9A-Fa-f] %d", mcast_addr, &refcnt)) < 2 ) {
+		fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
+		return;
+	    }
+	    sscanf(mcast_addr, "%X", &sin->sin_addr.s_addr);
+	    sas.ss_family = AF_INET;
+	} else {
+	    fprintf(stderr, _("warning, got bogus igmp line %d.\n"), lnr);
+	    return;
+	}
+
+	if ((ap = get_afntype(sas.ss_family)) == NULL) {
+	    fprintf(stderr, _("netstat: unsupported address family %d !\n"),
+		    sas.ss_family);
+	    return;
+	}
+	safe_strncpy(mcast_addr, ap->sprint(&sas, flag_not & FLAG_NUM_HOST),
+		sizeof(mcast_addr));
+	printf("%-15s %-6d %s\n", device, refcnt, mcast_addr );
+#endif
+    }    /* IPV4 */
+}
+
+#if HAVE_AFX25
+static int x25_info(void)
+{
+       FILE *f=proc_fopen(_PATH_PROCNET_X25);
+       char buffer[256],dev[16];
+       int st,vs,vr,sendq,recvq,lci;
+       static char *x25_state[5]=
+       {
+               "LISTENING",
+               "SABM_SENT",
+               "DISC_SENT",
+               "ESTABLISHED",
+               "RECOVERY"
+       };
+       if(!f)
+       {
+               if (errno != ENOENT) {
+                       perror(_PATH_PROCNET_X25);
+                       return(-1);
+               }
+               if (flag_arg || flag_ver)
+                       ESYSNOT("netstat","AF X25");
+               if (flag_arg)
+                       return(1);
+               else
+                       return(0);
+       }
+       printf( _("Active X.25 sockets\n"));
+       /* IMHO, Vr/Vs is not very usefull --SF */
+       printf( _("Dest         Source          Device  LCI  State        Vr/Vs  Send-Q  Recv-Q\n"));
+       if (fgets(buffer,256,f))
+               /* eat line */;
+       while(fgets(buffer,256,f))
+       {
+               buffer[10]=0;
+               buffer[20]=0;
+               sscanf(buffer+22,"%s %d %d %d %d %*d %*d %*d %*d %*d %*d %d %d %*d",
+                       dev,&lci,&st,&vs,&vr,&sendq,&recvq);
+               if (!(flag_all || lci))
+                       continue;
+               printf("%-15s %-15s %-7s %-3d  %-11s  %02d/%02d  %-6d  %-6d\n",
+                       buffer,buffer+11,
+                       dev,
+                       lci,
+                       x25_state[st],
+                       vr,vs,sendq,recvq);
+       }
+       fclose(f);
+       return 0;
+}
+#endif
+
+static int igmp_info(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_IGMP, _PATH_PROCNET_IGMP6, "AF INET (igmp)",
+	       igmp_do_one, "igmp", "igmp6");
+}
+
+static const char *sctp_socket_state_str(int state)
+{
+    if (state >= 0 && state < ARRAY_SIZE(tcp_state))
+	return tcp_state[state];
+    else {
+	static char state_str_buf[64];
+	sprintf(state_str_buf, "UNKNOWN(%d)", state);
+	return state_str_buf;
+    }
+}
+
+static const struct aftype *process_sctp_addr_str(const char *addr_str, struct sockaddr_storage *sas)
+{
+    if (strchr(addr_str,':')) {
+#if HAVE_AFINET6
+	extern struct aftype inet6_aftype;
+	/* Demangle what the kernel gives us */
+	struct in6_addr in6;
+	char addr6_str[INET6_ADDRSTRLEN];
+	unsigned u0, u1, u2, u3, u4, u5, u6, u7;
+	sscanf(addr_str, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
+	       &u0, &u1, &u2, &u3, &u4, &u5, &u6, &u7);
+	in6.s6_addr16[0] = htons(u0);
+	in6.s6_addr16[1] = htons(u1);
+	in6.s6_addr16[2] = htons(u2);
+	in6.s6_addr16[3] = htons(u3);
+	in6.s6_addr16[4] = htons(u4);
+	in6.s6_addr16[5] = htons(u5);
+	in6.s6_addr16[6] = htons(u6);
+	in6.s6_addr16[7] = htons(u7);
+
+	inet_ntop(AF_INET6, &in6, addr6_str, sizeof(addr6_str));
+	inet6_aftype.input(1, addr6_str, sas);
+	sas->ss_family = AF_INET6;
+#endif
+    } else {
+	struct sockaddr_in *sin = (struct sockaddr_in *)sas;
+	sin->sin_addr.s_addr = inet_addr(addr_str);
+	sas->ss_family = AF_INET;
+    }
+    return get_afntype(sas->ss_family);
+}
+
+static void sctp_eps_do_one(int lnr, char *line, const char *proto)
+{
+    char buffer[1024];
+    int state, port;
+    int uid;
+    unsigned long inode;
+    const struct aftype *ap;
+    struct sockaddr_storage localsas;
+    const char *sst_str;
+    const char *lport_str;
+    const char *uid_str;
+    const char *inode_str;
+    char *laddrs_str;
+
+    if (lnr == 0) {
+	/* ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS */
+	return;
+    }
+    strtok(line, " \t\n");	/* skip endpt */
+    strtok(0, " \t\n");		/* skip sock */
+    strtok(0, " \t\n");		/* skip sty */
+    sst_str = strtok(0, " \t\n");
+    strtok(0, " \t\n");		/* skip hash bucket */
+    lport_str = strtok(0, " \t\n");
+    uid_str = strtok(0, " \t\n");
+    inode_str = strtok(0, " \t\n");
+    laddrs_str = strtok(0, "\t\n");
+
+    if (!sst_str || !lport_str || !uid_str || !inode_str) {
+	fprintf(stderr, _("warning, got bogus sctp eps line.\n"));
+	return;
+    }
+    state = atoi(sst_str);
+    port = atoi(lport_str);
+    uid = atoi(uid_str);
+    inode = strtoul(inode_str,0,0);
+
+    const char *this_local_addr;
+    int first = 1;
+    char local_port[16];
+    snprintf(local_port, sizeof(local_port), "%s",
+        get_sname(htons(port), proto, flag_not & FLAG_NUM_PORT));
+    for (this_local_addr = strtok(laddrs_str, " \t\n");
+         this_local_addr;
+         this_local_addr = strtok(0, " \t\n")) {
+	char local_addr[64];
+	ap = process_sctp_addr_str(this_local_addr, &localsas);
+	if (ap)
+	    safe_strncpy(local_addr, ap->sprint(&localsas, flag_not), sizeof(local_addr));
+	else
+	    sprintf(local_addr, _("unsupported address family %d"), localsas.ss_family);
+
+	if (first)
+	    printf("sctp                ");
+	else
+	    printf("\n                    ");
+	sprintf(buffer, "%s:%s", local_addr, local_port);
+	printf("%-47s", buffer);
+	printf(" %-11s", first ? sctp_socket_state_str(state) : "");
+	first = 0;
+    }
+    finish_this_one(uid, inode, "");
+}
+
+static void sctp_assoc_do_one(int lnr, char *line, const char *proto)
+{
+    char buffer[1024];
+    int state, lport,rport;
+    int uid;
+    unsigned rxqueue,txqueue;
+    unsigned long inode;
+
+    const struct aftype *ap;
+    struct sockaddr_storage localsas, remotesas;
+    const char *sst_str;
+    const char *txqueue_str;
+    const char *rxqueue_str;
+    const char *lport_str, *rport_str;
+    const char *uid_str;
+    const char *inode_str;
+    char *laddrs_str;
+    char *raddrs_str;
+
+    if (lnr == 0) {
+	/* ASSOC     SOCK   STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT RPORT LADDRS <-> RADDRS */
+	return;
+    }
+
+    strtok(line, " \t\n");	/* skip assoc */
+    strtok(0, " \t\n");		/* skip sock */
+    strtok(0, " \t\n");		/* skip sty */
+    sst_str = strtok(0, " \t\n");
+    strtok(0, " \t\n");
+    strtok(0, " \t\n");		/* skip hash bucket */
+    strtok(0, " \t\n");		/* skip hash assoc-id */
+    txqueue_str =  strtok(0, " \t\n");
+    rxqueue_str =  strtok(0, " \t\n");
+    uid_str = strtok(0, " \t\n");
+    inode_str = strtok(0, " \t\n");
+    lport_str = strtok(0, " \t\n");
+    rport_str = strtok(0, " \t\n");
+    laddrs_str = strtok(0, "<->\t\n");
+    raddrs_str = strtok(0, "<->\t\n");
+
+    if (!sst_str || !txqueue_str || !rxqueue_str || !uid_str ||
+        !inode_str || !lport_str || !rport_str) {
+	fprintf(stderr, _("warning, got bogus sctp assoc line.\n"));
+	return;
+    }
+
+    state = atoi(sst_str);
+    txqueue = atoi(txqueue_str);
+    rxqueue = atoi(rxqueue_str);
+    uid = atoi(uid_str);
+    inode = strtoul(inode_str, 0, 0);
+    lport = atoi(lport_str);
+    rport = atoi(rport_str);
+
+    /*print all addresses*/
+    const char *this_local_addr;
+    const char *this_remote_addr;
+    char *ss1, *ss2;
+    int first = 1;
+    char local_port[16];
+    char remote_port[16];
+    snprintf(local_port, sizeof(local_port), "%s",
+             get_sname(htons(lport), proto,
+             flag_not & FLAG_NUM_PORT));
+    snprintf(remote_port, sizeof(remote_port), "%s",
+             get_sname(htons(rport), proto,
+             flag_not & FLAG_NUM_PORT));
+
+    this_local_addr = strtok_r(laddrs_str, " \t\n", &ss1);
+    this_remote_addr = strtok_r(raddrs_str, " \t\n", &ss2);
+    while (this_local_addr || this_remote_addr) {
+	char local_addr[64];
+	char remote_addr[64];
+
+	if (this_local_addr) {
+	    if (this_local_addr[0] == '*') {
+		/* skip * */
+		this_local_addr++;
+	    }
+	    ap = process_sctp_addr_str(this_local_addr, &localsas);
+	    if (ap)
+		safe_strncpy(local_addr,
+		             ap->sprint(&localsas, flag_not), sizeof(local_addr));
+	    else
+		sprintf(local_addr, _("unsupported address family %d"), localsas.ss_family);
+	}
+	if (this_remote_addr) {
+	    if (this_remote_addr[0] == '*') {
+		/* skip * */
+		this_remote_addr++;
+	    }
+	    ap = process_sctp_addr_str(this_remote_addr, &remotesas);
+	    if (ap)
+		safe_strncpy(remote_addr,
+		             ap->sprint(&remotesas, flag_not), sizeof(remote_addr));
+	    else
+		sprintf(remote_addr, _("unsupported address family %d"), remotesas.ss_family);
+	}
+
+	if (first)
+	    printf("sctp  %6u %6u ", rxqueue, txqueue);
+	else
+	    printf("\n                    ");
+	if (this_local_addr) {
+	    if (first)
+		sprintf(buffer, "%s:%s", local_addr, local_port);
+	    else
+		sprintf(buffer, "%s", local_addr);
+	    printf("%-23s", buffer);
+	} else
+	    printf("%-23s", "");
+	printf(" ");
+	if (this_remote_addr) {
+	    if (first)
+		sprintf(buffer, "%s:%s", remote_addr, remote_port);
+	    else
+		sprintf(buffer, "%s", remote_addr);
+	    printf("%-23s", buffer);
+	} else
+	    printf("%-23s", "");
+
+       printf(" %-11s", first ? sctp_socket_state_str(state) : "");
+
+       first = 0;
+       this_local_addr = strtok_r(0, " \t\n", &ss1);
+       this_remote_addr = strtok_r(0, " \t\n", &ss2);
+    }
+    finish_this_one(uid, inode, "");
+}
+
+static int sctp_info_eps(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_SCTPEPTS, _PATH_PROCNET_SCTP6EPTS, "AF INET (sctp)",
+               sctp_eps_do_one, "sctp", "sctp6");
+}
+
+static int sctp_info_assocs(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_SCTPASSOCS, _PATH_PROCNET_SCTP6ASSOCS, "AF INET (sctp)",
+               sctp_assoc_do_one, "sctp", "sctp6");
+}
+
+static int sctp_info(void)
+{
+    int res;
+
+    if (flag_all || flag_lst) {
+	res = sctp_info_eps();
+	if (res)
+	    return res;
+    }
+
+    if (flag_all || !flag_lst) {
+	res = sctp_info_assocs();
+    }
+
+    return res;
+}
+
+static void addr_do_one(char *buf, size_t buf_len, size_t short_len, const struct aftype *ap,
+			const struct sockaddr_storage *addr,
+			int port, const char *proto
+)
+{
+    const char *sport, *saddr;
+    size_t port_len, addr_len;
+
+    saddr = ap->sprint(addr, flag_not & FLAG_NUM_HOST);
+    sport = get_sname(htons(port), proto, flag_not & FLAG_NUM_PORT);
+    addr_len = strlen(saddr);
+    port_len = strlen(sport);
+    if (!flag_wide && (addr_len + port_len > short_len)) {
+	/* Assume port name is short */
+	port_len = netmin(port_len, short_len - 4);
+	addr_len = short_len - port_len;
+	strncpy(buf, saddr, addr_len);
+	buf[addr_len] = '\0';
+	strcat(buf, ":");
+	strncat(buf, sport, port_len);
+    } else
+	snprintf(buf, buf_len, "%s:%s", saddr, sport);
+}
+
+static void tcp_do_one(int lnr, const char *line, const char *prot)
+{
+    unsigned long rxq, txq, time_len, retr, inode;
+    int num, local_port, rem_port, d, state, uid, timer_run, timeout;
+    char rem_addr[128], local_addr[128], timers[64];
+    const struct aftype *ap;
+    struct sockaddr_storage localsas, remsas;
+    struct sockaddr_in *localaddr = (struct sockaddr_in *)&localsas;
+    struct sockaddr_in *remaddr = (struct sockaddr_in *)&remsas;
+#if HAVE_AFINET6
+    char addr6[INET6_ADDRSTRLEN];
+    struct in6_addr in6;
+    extern struct aftype inet6_aftype;
+#endif
+    long clk_tck = ticks_per_second();
+
+    if (lnr == 0)
+	return;
+
+    num = sscanf(line,
+    "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
+		 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
+		 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
+
+    if (num < 11) {
+	fprintf(stderr, _("warning, got bogus tcp line.\n"));
+	return;
+    }
+
+    if (!flag_all && ((flag_lst && rem_port) || (!flag_lst && !rem_port)))
+      return;
+
+    if (strlen(local_addr) > 8) {
+#if HAVE_AFINET6
+	/* Demangle what the kernel gives us */
+	sscanf(local_addr, "%08X%08X%08X%08X",
+	       &in6.s6_addr32[0], &in6.s6_addr32[1],
+           &in6.s6_addr32[2], &in6.s6_addr32[3]);
+	inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	inet6_aftype.input(1, addr6, &localsas);
+	sscanf(rem_addr, "%08X%08X%08X%08X",
+	       &in6.s6_addr32[0], &in6.s6_addr32[1],
+	       &in6.s6_addr32[2], &in6.s6_addr32[3]);
+	inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	inet6_aftype.input(1, addr6, &remsas);
+	localsas.ss_family = AF_INET6;
+	remsas.ss_family = AF_INET6;
+#endif
+    } else {
+	sscanf(local_addr, "%X", &localaddr->sin_addr.s_addr);
+	sscanf(rem_addr, "%X", &remaddr->sin_addr.s_addr);
+	localsas.ss_family = AF_INET;
+	remsas.ss_family = AF_INET;
+    }
+
+    if ((ap = get_afntype(localsas.ss_family)) == NULL) {
+	fprintf(stderr, _("netstat: unsupported address family %d !\n"),
+		localsas.ss_family);
+	return;
+    }
+
+	addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localsas, local_port, "tcp");
+	addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remsas, rem_port, "tcp");
+
+	timers[0] = '\0';
+	if (flag_opt)
+	    switch (timer_run) {
+	    case 0:
+		snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
+		break;
+
+	    case 1:
+		snprintf(timers, sizeof(timers), _("on (%2.2f/%ld/%d)"),
+			 (double) time_len / clk_tck, retr, timeout);
+		break;
+
+	    case 2:
+		snprintf(timers, sizeof(timers), _("keepalive (%2.2f/%ld/%d)"),
+			 (double) time_len / clk_tck, retr, timeout);
+		break;
+
+	    case 3:
+		snprintf(timers, sizeof(timers), _("timewait (%2.2f/%ld/%d)"),
+			 (double) time_len / clk_tck, retr, timeout);
+		break;
+
+	    case 4:
+		snprintf(timers, sizeof(timers), _("probe (%2.2f/%ld/%d)"),
+			 (double) time_len / clk_tck, retr, timeout);
+		break;
+
+	    default:
+		snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
+			 timer_run, (double) time_len / clk_tck, retr, timeout);
+		break;
+	    }
+
+	printf("%-4s  %6ld %6ld %-*s %-*s %-11s",
+	       prot, rxq, txq, (int)netmax(23,strlen(local_addr)), local_addr, (int)netmax(23,strlen(rem_addr)), rem_addr, _(tcp_state[state]));
+
+	finish_this_one(uid,inode,timers);
+}
+
+static int tcp_info(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
+	       tcp_do_one, "tcp", "tcp6");
+}
+
+static int notnull(const struct sockaddr_storage *sas)
+{
+    const struct sockaddr_in *sin = (const struct sockaddr_in *)sas;
+
+#if HAVE_AFINET6
+    const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sas;
+
+    if (sin6->sin6_family == AF_INET6) {
+	return sin6->sin6_addr.s6_addr32[0] ||
+		sin6->sin6_addr.s6_addr32[1] ||
+		sin6->sin6_addr.s6_addr32[2] ||
+		sin6->sin6_addr.s6_addr32[3];
+    }
+#endif
+
+    return sin->sin_addr.s_addr;
+}
+
+static void udp_do_one(int lnr, const char *line,const char *prot)
+{
+    char local_addr[128], rem_addr[128];
+    char *udp_state, timers[64];
+    int num, local_port, rem_port, d, state, timer_run, uid, timeout;
+    struct sockaddr_storage localsas, remsas;
+    struct sockaddr_in *localaddr = (struct sockaddr_in *)&localsas;
+    struct sockaddr_in *remaddr = (struct sockaddr_in *)&remsas;
+#if HAVE_AFINET6
+    char addr6[INET6_ADDRSTRLEN];
+    struct in6_addr in6;
+    extern struct aftype inet6_aftype;
+#endif
+    const struct aftype *ap;
+    unsigned long rxq, txq, time_len, retr, inode;
+
+    if (lnr == 0)
+	return;
+
+    num = sscanf(line,
+		 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
+		 &d, local_addr, &local_port,
+		 rem_addr, &rem_port, &state,
+	  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
+
+    if (num < 10) {
+	fprintf(stderr, _("warning, got bogus udp line.\n"));
+	return;
+    }
+
+    if (strlen(local_addr) > 8) {
+#if HAVE_AFINET6
+	sscanf(local_addr, "%08X%08X%08X%08X",
+	       &in6.s6_addr32[0], &in6.s6_addr32[1],
+	       &in6.s6_addr32[2], &in6.s6_addr32[3]);
+	inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	inet6_aftype.input(1, addr6, &localsas);
+	sscanf(rem_addr, "%08X%08X%08X%08X",
+	       &in6.s6_addr32[0], &in6.s6_addr32[1],
+	       &in6.s6_addr32[2], &in6.s6_addr32[3]);
+	inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	inet6_aftype.input(1, addr6, &remsas);
+	localsas.ss_family = AF_INET6;
+	remsas.ss_family = AF_INET6;
+#endif
+    } else {
+	sscanf(local_addr, "%X", &localaddr->sin_addr.s_addr);
+	sscanf(rem_addr, "%X", &remaddr->sin_addr.s_addr);
+	localsas.ss_family = AF_INET;
+	remsas.ss_family = AF_INET;
+    }
+
+    retr = 0L;
+
+    if ((ap = get_afntype(localsas.ss_family)) == NULL) {
+	fprintf(stderr, _("netstat: unsupported address family %d !\n"),
+		localsas.ss_family);
+	return;
+    }
+    switch (state) {
+    case TCP_ESTABLISHED:
+	udp_state = _("ESTABLISHED");
+	break;
+
+    case TCP_CLOSE:
+	udp_state = "";
+	break;
+
+    default:
+	udp_state = _("UNKNOWN");
+	break;
+    }
+
+    if (flag_all || (notnull(&remsas) && !flag_lst) || (!notnull(&remsas) && flag_lst))
+    {
+	addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localsas, local_port, "udp");
+	addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remsas, rem_port, "udp");
+
+	timers[0] = '\0';
+	if (flag_opt)
+	    switch (timer_run) {
+	    case 0:
+		snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
+		break;
+
+	    case 1:
+	    case 2:
+		snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100, retr, timeout);
+		break;
+
+	    default:
+		snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
+			 retr, timeout);
+		break;
+	    }
+	printf("%-5s %6ld %6ld %-23s %-23s %-11s",
+	       prot, rxq, txq, local_addr, rem_addr, udp_state);
+
+	finish_this_one(uid,inode,timers);
+    }
+}
+
+static int udp_info(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_UDP, _PATH_PROCNET_UDP6, "AF INET (udp)",
+	       udp_do_one, "udp", "udp6");
+}
+
+static int udplite_info(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_UDPLITE, _PATH_PROCNET_UDPLITE6,
+               "AF INET (udplite)", udp_do_one, "udpl", "udpl6" );
+}
+
+static void raw_do_one(int lnr, const char *line,const char *prot)
+{
+    char local_addr[128], rem_addr[128];
+    char timers[64];
+    int num, local_port, rem_port, d, state, timer_run, uid, timeout;
+    struct sockaddr_storage localsas, remsas;
+    struct sockaddr_in *localaddr = (struct sockaddr_in *)&localsas;
+    struct sockaddr_in *remaddr = (struct sockaddr_in *)&remsas;
+#if HAVE_AFINET6
+    char addr6[INET6_ADDRSTRLEN];
+    struct in6_addr in6;
+    extern struct aftype inet6_aftype;
+#endif
+    const struct aftype *ap;
+    unsigned long rxq, txq, time_len, retr, inode;
+
+    if (lnr == 0)
+	return;
+
+    num = sscanf(line,
+		 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
+		 &d, local_addr, &local_port, rem_addr, &rem_port, &state,
+	  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
+
+    if (num < 10) {
+    	fprintf(stderr, _("warning, got bogus raw line.\n"));
+	return;
+    }
+
+    if (strlen(local_addr) > 8) {
+#if HAVE_AFINET6
+	sscanf(local_addr, "%08X%08X%08X%08X",
+	       &in6.s6_addr32[0], &in6.s6_addr32[1],
+           &in6.s6_addr32[2], &in6.s6_addr32[3]);
+    inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	inet6_aftype.input(1, addr6, &localsas);
+	sscanf(rem_addr, "%08X%08X%08X%08X",
+	       &in6.s6_addr32[0], &in6.s6_addr32[1],
+           &in6.s6_addr32[2], &in6.s6_addr32[3]);
+    inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
+	inet6_aftype.input(1, addr6, &remsas);
+	localsas.ss_family = AF_INET6;
+	remsas.ss_family = AF_INET6;
+#endif
+    } else {
+	sscanf(local_addr, "%X", &localaddr->sin_addr.s_addr);
+	sscanf(rem_addr, "%X", &remaddr->sin_addr.s_addr);
+	localsas.ss_family = AF_INET;
+	remsas.ss_family = AF_INET;
+    }
+
+    if ((ap = get_afntype(localsas.ss_family)) == NULL) {
+	fprintf(stderr, _("netstat: unsupported address family %d !\n"), localsas.ss_family);
+	return;
+    }
+
+    if (flag_all || (notnull(&remsas) && !flag_lst) || (!notnull(&remsas) && flag_lst))
+    {
+	addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localsas, local_port, "raw");
+	addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remsas, rem_port, "raw");
+
+	timers[0] = '\0';
+	if (flag_opt)
+	    switch (timer_run) {
+	    case 0:
+		snprintf(timers, sizeof(timers), _("off (0.00/%ld/%d)"), retr, timeout);
+		break;
+
+	    case 1:
+            case 2:
+		snprintf(timers, sizeof(timers), _("on%d (%2.2f/%ld/%d)"), timer_run, (double) time_len / 100,
+			 retr, timeout);
+		break;
+
+	    default:
+		snprintf(timers, sizeof(timers), _("unkn-%d (%2.2f/%ld/%d)"),
+			 timer_run, (double) time_len / 100,
+			 retr, timeout);
+		break;
+	    }
+	printf("%-4s  %6ld %6ld %-23s %-23s %-11d",
+	       prot, rxq, txq, local_addr, rem_addr, state);
+
+	finish_this_one(uid,inode,timers);
+    }
+}
+
+static int raw_info(void)
+{
+    INFO_GUTS6(_PATH_PROCNET_RAW, _PATH_PROCNET_RAW6, "AF INET (raw)",
+	       raw_do_one, "raw", "raw6");
+}
+
+#endif
+
+
+#if HAVE_AFUNIX
+
+#define HAS_INODE 1
+
+static void unix_do_one(int nr, const char *line, const char *prot)
+{
+    static int has = 0;
+    char path[MAXPATHLEN], ss_flags[32];
+    char *ss_proto, *ss_state, *ss_type;
+    int num, state, type;
+    void *d;
+    unsigned long refcnt, proto, flags, inode;
+
+    if (nr == 0) {
+	if (strstr(line, "Inode"))
+	    has |= HAS_INODE;
+	return;
+    }
+    path[0] = '\0';
+    num = sscanf(line, "%p: %lX %lX %lX %X %X %lu %s",
+		 &d, &refcnt, &proto, &flags, &type, &state, &inode, path);
+    if (num < 6) {
+	fprintf(stderr, _("warning, got bogus unix line.\n"));
+	return;
+    }
+    if (!(has & HAS_INODE))
+	snprintf(path,sizeof(path),"%lu",inode);
+
+    if (!flag_all) {
+    	if ((state == SS_UNCONNECTED) && (flags & SO_ACCEPTCON)) {
+    		if (!flag_lst)
+    			return;
+    	} else {
+    		if (flag_lst)
+    			return;
+    	}
+    }
+
+    switch (proto) {
+    case 0:
+	ss_proto = "unix";
+	break;
+
+    default:
+	ss_proto = "??";
+    }
+
+    switch (type) {
+    case SOCK_STREAM:
+	ss_type = _("STREAM");
+	break;
+
+    case SOCK_DGRAM:
+	ss_type = _("DGRAM");
+	break;
+
+    case SOCK_RAW:
+	ss_type = _("RAW");
+	break;
+
+    case SOCK_RDM:
+	ss_type = _("RDM");
+	break;
+
+    case SOCK_SEQPACKET:
+	ss_type = _("SEQPACKET");
+	break;
+
+    default:
+	ss_type = _("UNKNOWN");
+    }
+
+    switch (state) {
+    case SS_FREE:
+	ss_state = _("FREE");
+	break;
+
+    case SS_UNCONNECTED:
+	/*
+	 * Unconnected sockets may be listening
+	 * for something.
+	 */
+	if (flags & SO_ACCEPTCON) {
+	    ss_state = _("LISTENING");
+	} else {
+	    ss_state = "";
+	}
+	break;
+
+    case SS_CONNECTING:
+	ss_state = _("CONNECTING");
+	break;
+
+    case SS_CONNECTED:
+	ss_state = _("CONNECTED");
+	break;
+
+    case SS_DISCONNECTING:
+	ss_state = _("DISCONNECTING");
+	break;
+
+    default:
+	ss_state = _("UNKNOWN");
+    }
+
+    safe_strncpy(ss_flags, "[ ", sizeof(ss_flags));
+    if (flags & SO_ACCEPTCON)
+	strcat(ss_flags, "ACC ");
+    if (flags & SO_WAITDATA)
+	strcat(ss_flags, "W ");
+    if (flags & SO_NOSPACE)
+	strcat(ss_flags, "N ");
+
+    strcat(ss_flags, "]");
+
+    printf("%-5s %-6ld %-11s %-10s %-13s ",
+	   ss_proto, refcnt, ss_flags, ss_type, ss_state);
+    if (has & HAS_INODE)
+	printf("%-8lu",inode);
+    else
+	printf("-       ");
+    if (flag_prg)
+	printf(" %-" PROGNAME_WIDTHs "s",(has & HAS_INODE?prg_cache_get(inode):"-"));
+    if (flag_selinux)
+	printf(" %-" SELINUX_WIDTHs "s",(has & HAS_INODE?prg_cache_get_con(inode):"-"));
+
+    printf(" %s\n", path);
+}
+
+static int unix_info(void)
+{
+
+    printf(_("Active UNIX domain sockets "));
+    if (flag_all)
+	printf(_("(servers and established)"));
+    else {
+      if (flag_lst)
+	printf(_("(only servers)"));
+      else
+	printf(_("(w/o servers)"));
+    }
+
+    printf(_("\nProto RefCnt Flags       Type       State         I-Node  "));
+    print_progname_banner();
+    print_selinux_banner();
+    printf(_(" Path\n"));	/* xxx */
+
+    {
+	INFO_GUTS(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one, "unix");
+    }
+}
+#endif
+
+
+#if HAVE_AFAX25
+static int ax25_info(void)
+{
+    FILE *f;
+    char buffer[256], buf[16];
+    char *src, *dst, *dev, *p;
+    int st, vs, vr, sendq, recvq, ret;
+    int new = -1;		/* flag for new (2.1.x) kernels */
+    static char *ax25_state[5] =
+    {
+	N_("LISTENING"),
+	N_("SABM SENT"),
+	N_("DISC SENT"),
+	N_("ESTABLISHED"),
+	N_("RECOVERY")
+    };
+    if (!(f = proc_fopen(_PATH_PROCNET_AX25))) {
+	if (errno != ENOENT) {
+	    perror(_PATH_PROCNET_AX25);
+	    return (-1);
+	}
+	if (flag_arg || flag_ver)
+	    ESYSNOT("netstat", "AF AX25");
+	if (flag_arg)
+	    return (1);
+	else
+	    return (0);
+    }
+    printf(_("Active AX.25 sockets\n"));
+    printf(_("Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q\n"));
+    while (fgets(buffer, 256, f)) {
+	if (new == -1) {
+	    if (!strncmp(buffer, "dest_addr", 9)) {
+		new = 0;
+		continue;	/* old kernels have a header line */
+	    } else
+		new = 1;
+	}
+	/*
+	 * In a network connection with no user socket the Snd-Q, Rcv-Q
+	 * and Inode fields are empty in 2.0.x and '*' in 2.1.x
+	 */
+	sendq = 0;
+	recvq = 0;
+	if (new == 0) {
+	    dst = buffer;
+	    src = buffer + 10;
+	    dst[9] = 0;
+	    src[9] = 0;
+	    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",
+		   buf, &st, &vs, &vr, &sendq, &recvq);
+	    if (ret != 4 && ret != 6) {
+		printf(_("Problem reading data from %s\n"), _PATH_PROCNET_AX25);
+		continue;
+	    }
+	    dev = buf;
+	} else {
+	    p = buffer;
+	    while (*p != ' ') p++;
+	    p++;
+	    dev = p;
+	    while (*p != ' ') p++;
+	    *p++ = 0;
+	    src = p;
+	    while (*p != ' ') p++;
+	    *p++ = 0;
+	    dst = p;
+	    while (*p != ' ') p++;
+	    *p++ = 0;
+	    ret = sscanf(p, "%d %d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d %*d",
+		   &st, &vs, &vr, &sendq, &recvq);
+	    if (ret != 3 && ret != 5) {
+		    printf(_("problem reading data from %s\n"), _PATH_PROCNET_AX25);
+		    continue;
+	    }
+	    /*
+	     * FIXME: digipeaters should be handled somehow.
+	     * For now we just strip them.
+	     */
+	    p = dst;
+	    while (*p && *p != ',') p++;
+	    *p = 0;
+	}
+	printf("%-9s  %-9s  %-6s  %-11s  %03d/%03d  %-6d  %-6d\n",
+	       dst, src,
+	       dev,
+	       _(ax25_state[st]),
+	       vr, vs, sendq, recvq);
+    }
+    fclose(f);
+    return 0;
+}
+#endif
+
+
+#if HAVE_AFIPX
+static int ipx_info(void)
+{
+    FILE *f;
+    char buf[256];
+    unsigned long txq, rxq;
+    unsigned int state;
+    unsigned int uid;
+    char *st;
+    int nc;
+    const struct aftype *ap;
+    struct passwd *pw;
+    char sad[50], dad[50];
+    struct sockaddr_storage sa;
+    unsigned sport = 0, dport = 0;
+    struct stat s;
+
+    f = proc_fopen(_PATH_PROCNET_IPX_SOCKET1);
+    if (!f) {
+        if (errno != ENOENT) {
+            perror(_PATH_PROCNET_IPX_SOCKET1);
+            return (-1);
+        }
+        f = proc_fopen(_PATH_PROCNET_IPX_SOCKET2);
+
+        /* We need to check for directory */
+        if (f) {
+            if (fstat (fileno(f), &s) == -1 ||
+                !S_ISREG(s.st_mode)) {
+                fclose(f);
+                f=NULL;
+            }
+        }
+
+        if (!f) {
+            if (errno != ENOENT) {
+	        perror(_PATH_PROCNET_IPX_SOCKET2);
+	        return (-1);
+	    }
+	    if (flag_arg || flag_ver)
+	        ESYSNOT("netstat", "AF IPX");
+	    if (flag_arg)
+	        return (1);
+ 	    else
+	        return (0);
+        }
+    }
+    printf(_("Active IPX sockets\nProto Recv-Q Send-Q Local Address              Foreign Address            State"));	/* xxx */
+    if (flag_exp > 1)
+	printf(_(" User"));	/* xxx */
+    printf("\n");
+    if ((ap = get_afntype(AF_IPX)) == NULL) {
+	EINTERN("netstat.c", "AF_IPX missing");
+	fclose(f);
+	return (-1);
+    }
+    if (fgets(buf, 255, f))
+	/* eat line */;
+
+    while (fgets(buf, 255, f) != NULL) {
+	sscanf(buf, "%s %s %lX %lX %u %u",
+	       sad, dad, &txq, &rxq, &state, &uid);
+	if ((st = rindex(sad, ':'))) {
+	    *st++ = '\0';
+	    sscanf(st, "%X", &sport);	/* net byt order */
+	    sport = ntohs(sport);
+	} else {
+	    EINTERN("netstat.c", "ipx socket format error in source port");
+	    fclose(f);
+	    return (-1);
+	}
+	nc = 0;
+	if (strcmp(dad, "Not_Connected") != 0) {
+	    if ((st = rindex(dad, ':'))) {
+		*st++ = '\0';
+		sscanf(st, "%X", &dport);	/* net byt order */
+		dport = ntohs(dport);
+	    } else {
+		EINTERN("netstat.c", "ipx socket format error in destination port");
+		fclose(f);
+		return (-1);
+	    }
+	} else
+	    nc = 1;
+
+	switch (state) {
+	case TCP_ESTABLISHED:
+	    st = _("ESTAB");
+	    break;
+
+	case TCP_CLOSE:
+	    st = "";
+	    break;
+
+	default:
+	    st = _("UNK.");
+	    break;
+	}
+
+	/* Fetch and resolve the Source */
+	(void) ap->input(0, sad, &sa);
+	safe_strncpy(buf, ap->sprint(&sa, flag_not & FLAG_NUM_HOST), sizeof(buf));
+	snprintf(sad, sizeof(sad), "%s:%04X", buf, sport);
+
+	if (!nc) {
+	    /* Fetch and resolve the Destination */
+	    (void) ap->input(0, dad, &sa);
+	    safe_strncpy(buf, ap->sprint(&sa, flag_not & FLAG_NUM_HOST), sizeof(buf));
+	    snprintf(dad, sizeof(dad), "%s:%04X", buf, dport);
+	} else
+        safe_strncpy(dad, "-", sizeof(dad));
+
+	printf("IPX   %6ld %6ld %-26s %-26s %-5s", txq, rxq, sad, dad, st);
+	if (flag_exp > 1) {
+	    if (!(flag_not & FLAG_NUM_USER) && ((pw = getpwuid(uid)) != NULL))
+		printf(" %-10s", pw->pw_name);
+	    else
+		printf(" %-10d", uid);
+	}
+	printf("\n");
+    }
+    fclose(f);
+    return 0;
+}
+#endif
+
+#if HAVE_AFBLUETOOTH
+const char *bluetooth_state(int state)
+{
+    switch (state) {
+	case BT_CONNECTED:
+	    return _("CONNECTED");
+	case BT_OPEN:
+	    return _("OPEN");
+	case BT_BOUND:
+	    return _("BOUND");
+	case BT_LISTEN:
+	    return _("LISTEN");
+	case BT_CONNECT:
+	    return _("CONNECT");
+	case BT_CONNECT2:
+	    return _("CONNECT2");
+	case BT_CONFIG:
+	    return _("CONFIG");
+	case BT_DISCONN:
+	    return _("DISCONN");
+	case BT_CLOSED:
+	    return _("CLOSED");
+	default:
+	    return _("UNKNOWN");
+    }
+}
+
+static void l2cap_do_one(int nr, const char *line, const char *prot)
+{
+    char daddr[18], saddr[18];
+    unsigned dtype, stype, state, psm, dcid, scid, imtu, omtu, sec_level;
+    int num;
+    const char *bt_state, *bt_sec_level;
+
+    num = sscanf(line, "%17s (%u) %17s (%u) %d %d 0x%04x 0x%04x %d %d %d",
+	daddr, &dtype, saddr, &stype, &state, &psm, &dcid, &scid, &imtu, &omtu, &sec_level);
+
+    if (num != 11) {
+	num = sscanf(line, "%17s %17s %d %d 0x%04x 0x%04x %d %d %d",
+	    daddr, saddr, &state, &psm, &dcid, &scid, &imtu, &omtu, &sec_level);
+
+	if (num != 9) {
+	    fprintf(stderr, _("warning, got bogus l2cap line.\n"));
+	    return;
+	}
+    }
+
+    if (flag_lst && !(state == BT_LISTEN || state == BT_BOUND))
+	return;
+    if (!(flag_all || flag_lst) && (state == BT_LISTEN || state == BT_BOUND))
+	return;
+
+    bt_state = bluetooth_state(state);
+    switch (sec_level) {
+	case BT_SECURITY_SDP:
+	    bt_sec_level = _("SDP");
+	    break;
+	case BT_SECURITY_LOW:
+	    bt_sec_level = _("LOW");
+	    break;
+	case BT_SECURITY_MEDIUM:
+	    bt_sec_level = _("MEDIUM");
+	    break;
+	case BT_SECURITY_HIGH:
+	    bt_sec_level = _("HIGH");
+	    break;
+	default:
+	    bt_sec_level = _("UNKNOWN");
+    }
+
+    printf("l2cap  %-17s %-17s %-9s %7d 0x%04x 0x%04x %7d %7d %-7s\n",
+	(strcmp (daddr, "00:00:00:00:00:00") == 0 ? "*" : daddr),
+	(strcmp (saddr, "00:00:00:00:00:00") == 0 ? "*" : saddr),
+	bt_state, psm, dcid, scid, imtu, omtu, bt_sec_level);
+}
+
+static int l2cap_info(void)
+{
+    printf("%-6s %-17s %-17s %-9s %7s %-6s %-6s %7s %7s %-7s\n",
+	"Proto", "Destination", "Source", "State", "PSM", "DCID", "SCID", "IMTU", "OMTU", "Security");
+    INFO_GUTS(_PATH_SYS_BLUETOOTH_L2CAP, "BTPROTO L2CAP", l2cap_do_one, "l2cap");
+}
+
+static void rfcomm_do_one(int nr, const char *line, const char *prot)
+{
+    char daddr[18], saddr[18];
+    unsigned state, channel;
+    int num;
+    const char *bt_state;
+
+    num = sscanf(line, "%17s %17s %d %d", daddr, saddr, &state, &channel);
+    if (num < 4) {
+	fprintf(stderr, _("warning, got bogus rfcomm line.\n"));
+	return;
+    }
+
+    if (flag_lst && !(state == BT_LISTEN || state == BT_BOUND))
+	return;
+    if (!(flag_all || flag_lst) && (state == BT_LISTEN || state == BT_BOUND))
+	return;
+
+    bt_state = bluetooth_state(state);
+    printf("rfcomm %-17s %-17s %-9s %7d\n",
+	(strcmp (daddr, "00:00:00:00:00:00") == 0 ? "*" : daddr),
+	(strcmp (saddr, "00:00:00:00:00:00") == 0 ? "*" : saddr),
+	bt_state, channel);
+}
+
+static int rfcomm_info(void)
+{
+    printf("%-6s %-17s %-17s %-9s %7s\n", "Proto", "Destination", "Source", "State", "Channel");
+    INFO_GUTS(_PATH_SYS_BLUETOOTH_RFCOMM, "BTPROTO RFCOMM", rfcomm_do_one, "rfcomm");
+}
+#endif
+
+static int iface_info(void)
+{
+    if (skfd < 0) {
+	if ((skfd = sockets_open(0)) < 0) {
+	    perror("socket");
+	    exit(1);
+	}
+	printf(_("Kernel Interface table\n"));
+    }
+    if (flag_exp < 2) {
+	ife_short = 1;
+	printf(_("Iface             MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
+    }
+
+    if (for_all_interfaces(do_if_print, &flag_all) < 0) {
+	perror(_("missing interface information"));
+	exit(1);
+    }
+    if (flag_cnt)
+	if_cache_free();
+    else {
+	close(skfd);
+	skfd = -1;
+    }
+
+    return 0;
+}
+
+
+static void version(void)
+{
+    printf("%s\n%s\n%s\n", Release, Signature, Features);
+    exit(E_VERSION);
+}
+
+
+static void usage(int rc)
+{
+    FILE *fp = rc ? stderr : stdout;
+    fprintf(fp, _("usage: netstat [-vWeenNcCF] [<Af>] -r         netstat {-V|--version|-h|--help}\n"));
+    fprintf(fp, _("       netstat [-vWnNcaeol] [<Socket> ...]\n"));
+    fprintf(fp, _("       netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }\n\n"));
+
+    fprintf(fp, _("        -r, --route              display routing table\n"));
+    fprintf(fp, _("        -i, --interfaces         display interface table\n"));
+    fprintf(fp, _("        -g, --groups             display multicast group memberships\n"));
+    fprintf(fp, _("        -s, --statistics         display networking statistics (like SNMP)\n"));
+#if HAVE_FW_MASQUERADE
+    fprintf(fp, _("        -M, --masquerade         display masqueraded connections\n\n"));
+#endif
+
+    fprintf(fp, _("        -v, --verbose            be verbose\n"));
+    fprintf(fp, _("        -W, --wide               don't truncate IP addresses\n"));
+    fprintf(fp, _("        -n, --numeric            don't resolve names\n"));
+    fprintf(fp, _("        --numeric-hosts          don't resolve host names\n"));
+    fprintf(fp, _("        --numeric-ports          don't resolve port names\n"));
+    fprintf(fp, _("        --numeric-users          don't resolve user names\n"));
+    fprintf(fp, _("        -N, --symbolic           resolve hardware names\n"));
+    fprintf(fp, _("        -e, --extend             display other/more information\n"));
+    fprintf(fp, _("        -p, --programs           display PID/Program name for sockets\n"));
+    fprintf(fp, _("        -o, --timers             display timers\n"));
+    fprintf(fp, _("        -c, --continuous         continuous listing\n\n"));
+    fprintf(fp, _("        -l, --listening          display listening server sockets\n"));
+    fprintf(fp, _("        -a, --all                display all sockets (default: connected)\n"));
+    fprintf(fp, _("        -F, --fib                display Forwarding Information Base (default)\n"));
+    fprintf(fp, _("        -C, --cache              display routing cache instead of FIB\n"));
+#if HAVE_SELINUX
+    fprintf(fp, _("        -Z, --context            display SELinux security context for sockets\n"));
+#endif
+
+    fprintf(fp, _("\n  <Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-S|--sctp} {-w|--raw}\n"));
+    fprintf(fp, _("           {-x|--unix} --ax25 --ipx --netrom\n"));
+    fprintf(fp, _("  <AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: %s\n"), DFLT_AF);
+    fprintf(fp, _("  List of possible address families (which support routing):\n"));
+    print_aflist(1); /* 1 = routeable */
+    exit(rc);
+}
+
+
+int main
+ (int argc, char *argv[]) {
+    int i;
+    int lop;
+    static struct option longopts[] =
+    {
+	AFTRANS_OPTS,
+	{"version", 0, 0, 'V'},
+	{"interfaces", 0, 0, 'i'},
+	{"help", 0, 0, 'h'},
+	{"route", 0, 0, 'r'},
+#if HAVE_FW_MASQUERADE
+	{"masquerade", 0, 0, 'M'},
+#endif
+	{"protocol", 1, 0, 'A'},
+	{"tcp", 0, 0, 't'},
+	{"sctp", 0, 0, 'S'},
+	{"udp", 0, 0, 'u'},
+        {"udplite", 0, 0, 'U'},
+	{"raw", 0, 0, 'w'},
+	{"unix", 0, 0, 'x'},
+	{"l2cap", 0, 0, '2'},
+	{"rfcomm", 0, 0, 'f'},
+	{"listening", 0, 0, 'l'},
+	{"all", 0, 0, 'a'},
+	{"timers", 0, 0, 'o'},
+	{"continuous", 0, 0, 'c'},
+	{"extend", 0, 0, 'e'},
+	{"programs", 0, 0, 'p'},
+	{"verbose", 0, 0, 'v'},
+	{"statistics", 0, 0, 's'},
+	{"wide", 0, 0, 'W'},
+	{"numeric", 0, 0, 'n'},
+	{"numeric-hosts", 0, 0, '!'},
+	{"numeric-ports", 0, 0, '@'},
+	{"numeric-users", 0, 0, '#'},
+	{"symbolic", 0, 0, 'N'},
+	{"cache", 0, 0, 'C'},
+	{"fib", 0, 0, 'F'},
+	{"groups", 0, 0, 'g'},
+	{"context", 0, 0, 'Z'},
+	{NULL, 0, 0, 0}
+    };
+
+#if I18N
+    setlocale (LC_ALL, "");
+    bindtextdomain("net-tools", "/usr/share/locale");
+    textdomain("net-tools");
+#endif
+    getroute_init();		/* Set up AF routing support */
+
+    afname[0] = '\0';
+    while ((i = getopt_long(argc, argv, "A:CFMacdeghilnNoprsStuUvVWw2fx64?Z", longopts, &lop)) != EOF)
+	switch (i) {
+	case -1:
+	    break;
+	case 1:
+	    if (lop < 0 || lop >= AFTRANS_CNT) {
+		EINTERN("netstat.c", "longopts 1 range");
+		break;
+	    }
+	    if (aftrans_opt(longopts[lop].name))
+		exit(1);
+	    break;
+	case 'A':
+	    if (aftrans_opt(optarg))
+		exit(1);
+	    break;
+	case 'M':
+	    flag_mas++;
+	    break;
+	case 'a':
+	    flag_all++;
+	    break;
+	case 'l':
+	    flag_lst++;
+	    break;
+	case 'c':
+	    flag_cnt++;
+	    break;
+
+	case 'd':
+	    flag_deb++;
+	    break;
+	case 'g':
+	    flag_igmp++;
+	    break;
+	case 'e':
+	    flag_exp++;
+	    break;
+	case 'p':
+	    flag_prg++;
+	    break;
+	case 'i':
+	    flag_int++;
+	    break;
+	case 'W':
+	    flag_wide++;
+	    break;
+	case 'n':
+	    flag_not |= FLAG_NUM;
+	    break;
+	case '!':
+	    flag_not |= FLAG_NUM_HOST;
+	    break;
+	case '@':
+	    flag_not |= FLAG_NUM_PORT;
+	    break;
+	case '#':
+	    flag_not |= FLAG_NUM_USER;
+	    break;
+	case 'N':
+	    flag_not |= FLAG_SYM;
+	    break;
+	case 'C':
+	    flag_cf |= FLAG_CACHE;
+	    break;
+	case 'F':
+	    flag_cf |= FLAG_FIB;
+	    break;
+	case 'o':
+	    flag_opt++;
+	    break;
+	case '6':
+	    if (aftrans_opt("inet6"))
+		exit(1);
+	    break;
+	case '4':
+	    if (aftrans_opt("inet"))
+		exit(1);
+	    break;
+	case 'V':
+	    version();
+	    /*NOTREACHED */
+	case 'v':
+	    flag_ver |= FLAG_VERBOSE;
+	    break;
+	case 'r':
+	    flag_rou++;
+	    break;
+	case 't':
+	    flag_tcp++;
+	    break;
+	case 'S':
+	    flag_sctp++;
+	    break;
+	case 'u':
+	    flag_udp++;
+	    break;
+        case 'U':
+	    flag_udplite++;
+	    break;
+	case 'w':
+	    flag_raw++;
+	    break;
+        case '2':
+	    flag_l2cap++;
+	    break;
+        case 'f':
+	    flag_rfcomm++;
+	    break;
+	case 'x':
+	    if (aftrans_opt("unix"))
+		exit(1);
+	    break;
+	case 'Z':
+#if HAVE_SELINUX
+	    if (is_selinux_enabled() <= 0) {
+		fprintf(stderr, _("SELinux is not enabled on this machine.\n"));
+		exit(1);
+	    }
+	    flag_prg++;
+	    flag_selinux++;
+#else
+            fprintf(stderr, _("SELinux is not enabled for this application.\n"));
+	    exit(1);
+#endif
+
+	    break;
+	case '?':
+	    usage(E_OPTERR);
+	case 'h':
+	    usage(E_USAGE);
+	case 's':
+	    flag_sta++;
+	}
+
+    if (flag_int + flag_rou + flag_mas + flag_sta > 1)
+	usage(E_OPTERR);
+
+    if ((flag_inet || flag_inet6 || flag_sta) &&
+        !(flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw))
+	   flag_noprot = flag_tcp = flag_sctp = flag_udp = flag_udplite = flag_raw = 1;
+
+    if ((flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw || flag_igmp) &&
+        !(flag_inet || flag_inet6))
+        flag_inet = flag_inet6 = 1;
+
+    if (flag_bluetooth && !(flag_l2cap || flag_rfcomm))
+	   flag_l2cap = flag_rfcomm = 1;
+
+    flag_arg = flag_tcp + flag_sctp + flag_udplite + flag_udp + flag_raw + flag_unx
+        + flag_ipx + flag_ax25 + flag_netrom + flag_igmp + flag_x25 + flag_rose
+	+ flag_l2cap + flag_rfcomm;
+
+    if (flag_mas) {
+#if HAVE_FW_MASQUERADE && HAVE_AFINET
+#if MORE_THAN_ONE_MASQ_AF
+	if (!afname[0])
+        safe_strncpy(afname, DFLT_AF, sizeof(afname));
+#endif
+	for (;;) {
+	    i = ip_masq_info(flag_not & FLAG_NUM_HOST,
+			     flag_not & FLAG_NUM_PORT, flag_exp);
+	    if (i || !flag_cnt)
+		break;
+	    wait_continous();
+	}
+#else
+	ENOSUPP("netstat", "FW_MASQUERADE");
+	i = -1;
+#endif
+	return (i);
+    }
+
+    if (flag_sta) {
+        if (!afname[0])
+            safe_strncpy(afname, DFLT_AF, sizeof(afname));
+
+        if (!strcmp(afname, "inet")) {
+#if HAVE_AFINET
+            parsesnmp(flag_raw, flag_tcp, flag_udp, flag_sctp);
+#else
+            ENOSUPP("netstat", "AF INET");
+            exit(1);
+#endif
+        } else if(!strcmp(afname, "inet6")) {
+#if HAVE_AFINET6
+            parsesnmp6(flag_raw, flag_tcp, flag_udp);
+#else
+            ENOSUPP("netstat", "AF INET6");
+            exit(1);
+#endif
+        } else {
+          printf(_("netstat: No statistics support for specified address family: %s\n"), afname);
+          exit(1);
+        }
+        exit(0);
+    }
+
+    if (flag_rou) {
+	int options = 0;
+
+	if (!afname[0])
+        safe_strncpy(afname, DFLT_AF, sizeof(afname));
+
+	if (flag_exp == 2)
+	    flag_exp = 1;
+	else if (flag_exp == 1)
+	    flag_exp = 2;
+
+	options = (flag_exp & FLAG_EXT) | flag_not | flag_cf | flag_ver;
+	if (!flag_cf)
+	    options |= FLAG_FIB;
+
+	for (;;) {
+	    i = route_info(afname, options);
+	    if (i || !flag_cnt)
+		break;
+            wait_continous();
+	}
+	return (i);
+    }
+    if (flag_int) {
+	for (;;) {
+	    i = iface_info();
+	    if (!flag_cnt || i)
+		break;
+            wait_continous();
+	}
+	return (i);
+    }
+    for (;;) {
+	if (!flag_arg || flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw) {
+#if HAVE_AFINET
+	    prg_cache_load();
+	    printf(_("Active Internet connections "));	/* xxx */
+
+	    if (flag_all)
+		printf(_("(servers and established)"));
+	    else {
+	      if (flag_lst)
+		printf(_("(only servers)"));
+	      else
+		printf(_("(w/o servers)"));
+	    }
+	    printf(_("\nProto Recv-Q Send-Q Local Address           Foreign Address         State      "));	/* xxx */
+	    if (flag_exp > 1)
+		printf(_(" User       Inode     "));
+	    print_progname_banner();
+	    print_selinux_banner();
+	    if (flag_opt)
+		printf(_(" Timer"));	/* xxx */
+	    printf("\n");
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF INET");
+	    }
+#endif
+	}
+#if HAVE_AFINET
+	if (!flag_arg || flag_tcp) {
+	    i = tcp_info();
+	    if (i)
+		return (i);
+	}
+
+	if (!flag_arg || flag_sctp) {
+	    i = sctp_info();
+	    if (i)
+		return (i);
+	}
+
+	if (!flag_arg || flag_udp) {
+	    i = udp_info();
+	    if (i)
+		return (i);
+	}
+
+	if (!flag_arg || flag_udplite) {
+	    i = udplite_info();
+	    if (i)
+		return (i);
+	}
+
+	if (!flag_arg || flag_raw) {
+	    i = raw_info();
+	    if (i)
+		return (i);
+	}
+
+	if (flag_igmp) {
+#if HAVE_AFINET6
+	    printf( "IPv6/");
+#endif
+	    printf( _("IPv4 Group Memberships\n") );
+	    printf( _("Interface       RefCnt Group\n") );
+	    printf( "--------------- ------ ---------------------\n" );
+	    i = igmp_info();
+	    if (i)
+	        return (i);
+	}
+#endif
+
+	if (!flag_arg || flag_unx) {
+#if HAVE_AFUNIX
+	    prg_cache_load();
+	    i = unix_info();
+	    if (i)
+		return (i);
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF UNIX");
+	    }
+#endif
+	}
+	if (!flag_arg || flag_ipx) {
+#if HAVE_AFIPX
+	    i = ipx_info();
+	    if (i)
+		return (i);
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF IPX");
+	    }
+#endif
+	}
+	if (!flag_arg || flag_ax25) {
+#if HAVE_AFAX25
+	    i = ax25_info();
+	    if (i)
+		return (i);
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF AX25");
+	    }
+#endif
+	}
+	if(!flag_arg || flag_x25) {
+#if HAVE_AFX25
+	    /* FIXME */
+	    i = x25_info();
+	    if (i)
+		return(i);
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF X25");
+	    }
+#endif
+	}
+	if (!flag_arg || flag_netrom) {
+#if HAVE_AFNETROM
+	    i = netrom_info();
+	    if (i)
+		return (i);
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF NETROM");
+	    }
+#endif
+	}
+	if (!flag_arg || flag_rose) {
+#if HAVE_AFROSE
+          i = rose_info();
+          if (i)
+            return (i);
+#else
+          if (flag_arg) {
+            i = 1;
+            ENOSUPP("netstat", "AF ROSE");
+          }
+#endif
+        }
+
+	if (!flag_arg || flag_l2cap || flag_rfcomm) {
+#if HAVE_AFBLUETOOTH
+	    printf(_("Active Bluetooth connections "));	/* xxx */
+
+	    if (flag_all)
+		printf(_("(servers and established)"));
+	    else {
+	      if (flag_lst)
+		printf(_("(only servers)"));
+	      else
+		printf(_("(w/o servers)"));
+	    }
+	    printf("\n");
+#else
+	    if (flag_arg) {
+		i = 1;
+		ENOSUPP("netstat", "AF BLUETOOTH");
+	    }
+#endif
+	}
+#if HAVE_AFBLUETOOTH
+	if (!flag_arg || flag_l2cap) {
+	    i = l2cap_info();
+	    if (i)
+		return (i);
+	}
+	if (!flag_arg || flag_rfcomm) {
+	    i = rfcomm_info();
+	    if (i)
+		return (i);
+	}
+#endif
+
+	if (!flag_cnt || i)
+	    break;
+        wait_continous();
+	prg_cache_clear();
+    }
+    return (i);
+}