mirror of
https://github.com/ecki/net-tools.git
synced 2024-11-11 11:09:21 +00:00
2492 lines
64 KiB
C
2492 lines
64 KiB
C
/*
|
|
* 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
|
|
#include <bluetooth/bluetooth.h>
|
|
#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);
|
|
}
|