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);
+}