blob: 2b5be44fb950a37f1077e04ce4cc69fc01b179c9 [file] [log] [blame]
/*
* dsock.c - Linux socket processing functions for /proc-based lsof
*/
/*
* Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
* 47907. All rights reserved.
*
* Written by Victor A. Abell
*
* This software is not subject to any license of the American Telephone
* and Telegraph Company or the Regents of the University of California.
*
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to alter it and redistribute it freely, subject
* to the following restrictions:
*
* 1. Neither the authors nor Purdue University are responsible for any
* consequences of the use of this software.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Credit to the authors and Purdue
* University must appear in documentation and sources.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 4. This notice may not be removed or altered.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
static char *rcsid = "$Id: dsock.c,v 1.37 2011/09/27 17:38:39 abe Exp $";
#endif
#include "lsof.h"
/*
* Local definitions
*/
#define INOBUCKS 128 /* inode hash bucket count -- must be
* a power of two */
#define INOHASH(ino) ((int)((ino * 31415) >> 3) & (INOBUCKS - 1))
#define TCPUDPHASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp_bucks - 1))
#define TCPUDP6HASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp6_bucks - 1))
/*
* Local structures
*/
struct ax25sin { /* AX25 socket information */
char *da; /* destination address */
char *dev_ch; /* device characters */
char *sa; /* source address */
INODETYPE inode;
unsigned long sq, rq; /* send and receive queue values */
unsigned char sqs, rqs; /* send and receive queue states */
int state;
struct ax25sin *next;
};
struct ipxsin { /* IPX socket information */
INODETYPE inode;
char *la; /* local address */
char *ra; /* remote address */
int state;
unsigned long txq, rxq; /* transmit and receive queue values */
struct ipxsin *next;
};
struct nlksin { /* Netlink socket information */
INODETYPE inode; /* node number */
unsigned int pr; /* protocol */
struct nlksin *next;
};
struct packin { /* packet information */
INODETYPE inode;
int ty; /* socket type */
int pr; /* protocol */
struct packin *next;
};
struct rawsin { /* raw socket information */
INODETYPE inode;
char *la; /* local address */
char *ra; /* remote address */
char *sp; /* state characters */
MALLOC_S lal; /* strlen(la) */
MALLOC_S ral; /* strlen(ra) */
MALLOC_S spl; /* strlen(sp) */
struct rawsin *next;
};
struct tcp_udp { /* IPv4 TCP and UDP socket
* information */
INODETYPE inode;
unsigned long faddr, laddr; /* foreign & local IPv6 addresses */
int fport, lport; /* foreign & local ports */
unsigned long txq, rxq; /* transmit & receive queue values */
int proto; /* 0 = TCP, 1 = UDP, 2 = UDPLITE */
int state; /* protocol state */
struct tcp_udp *next;
};
#if defined(HASIPv6)
struct tcp_udp6 { /* IPv6 TCP and UDP socket
* information */
INODETYPE inode;
struct in6_addr faddr, laddr; /* foreign and local IPv6 addresses */
int fport, lport; /* foreign & local ports */
unsigned long txq, rxq; /* transmit & receive queue values */
int proto; /* 0 = TCP, 1 = UDP, 2 = UDPLITE */
int state; /* protocol state */
struct tcp_udp6 *next;
};
#endif /* defined(HASIPv6) */
struct uxsin { /* UNIX socket information */
INODETYPE inode; /* node number */
char *pcb; /* protocol control block */
char *path; /* file path */
unsigned char sb_def; /* stat(2) buffer definitions */
dev_t sb_dev; /* stat(2) buffer device */
INODETYPE sb_ino; /* stat(2) buffer node number */
dev_t sb_rdev; /* stat(2) raw device number */
struct uxsin *next;
};
/*
* Local static values
*/
static char *AX25path = (char *)NULL; /* path to AX25 /proc information */
static struct ax25sin **AX25sin = (struct ax25sin **)NULL;
/* AX25 socket info, hashed by inode */
static char *ax25st[] = {
"LISTENING", /* 0 */
"SABM SENT", /* 1 */
"DISC SENT", /* 2 */
"ESTABLISHED", /* 3 */
"RECOVERY" /* 4 */
};
#define NAX25ST (sizeof(ax25st) / sizeof(char *))
static char *Ipxpath = (char *)NULL; /* path to IPX /proc information */
static struct ipxsin **Ipxsin = (struct ipxsin **)NULL;
/* IPX socket info, hashed by inode */
static char *Nlkpath = (char *)NULL; /* path to Netlink /proc information */
static struct nlksin **Nlksin = (struct nlksin **)NULL;
/* Netlink socket info, hashed by
* inode */
static struct packin **Packin = (struct packin **)NULL;
/* packet info, hashed by inode */
static char *Packpath = (char *)NULL; /* path to packer /proc information */
static char *Rawpath = (char *)NULL; /* path to raw socket /proc
* information */
static struct rawsin **Rawsin = (struct rawsin **)NULL;
/* raw socket info, hashed by inode */
static char *SockStatPath = (char *)NULL;
/* path to /proc/net socket status */
static char *TCPpath = (char *)NULL; /* path to TCP /proc information */
static struct tcp_udp **TcpUdp = (struct tcp_udp **)NULL;
/* IPv4 TCP & UDP info, hashed by
* inode */
static int TcpUdp_bucks = 0; /* dynamically sized hash bucket
* count for TCP and UDP -- will
* be a power of two */
#if defined(HASIPv6)
static char *Raw6path = (char *)NULL; /* path to raw IPv6 /proc information */
static struct rawsin **Rawsin6 = (struct rawsin **)NULL;
/* IPv6 raw socket info, hashed by
* inode */
static char *SockStatPath6 = (char *)NULL;
/* path to /proc/net IPv6 socket
* status */
static char *TCP6path = (char *)NULL; /* path to IPv6 TCP /proc information */
static struct tcp_udp6 **TcpUdp6 = (struct tcp_udp6 **)NULL;
/* IPv6 TCP & UDP info, hashed by
* inode */
static int TcpUdp6_bucks = 0; /* dynamically sized hash bucket
* count for IPv6 TCP and UDP -- will
* be a power of two */
static char *UDP6path = (char *)NULL; /* path to IPv6 UDP /proc information */
static char *UDPLITE6path = (char *)NULL;
/* path to IPv6 UDPLITE /proc
* information */
#endif /* defined(HASIPv6) */
static char *UDPpath = (char *)NULL; /* path to UDP /proc information */
static char *UDPLITEpath = (char *)NULL;
/* path to UDPLITE /proc information */
static char *UNIXpath = (char *)NULL; /* path to UNIX /proc information */
static struct uxsin **Uxsin = (struct uxsin **)NULL;
/* UNIX socket info, hashed by inode */
/*
* Local function prototypes
*/
_PROTOTYPE(static struct ax25sin *check_ax25,(INODETYPE i));
_PROTOTYPE(static struct ipxsin *check_ipx,(INODETYPE i));
_PROTOTYPE(static struct nlksin *check_netlink,(INODETYPE i));
_PROTOTYPE(static struct packin *check_pack,(INODETYPE i));
_PROTOTYPE(static struct rawsin *check_raw,(INODETYPE i));
_PROTOTYPE(static struct tcp_udp *check_tcpudp,(INODETYPE i, char **p));
_PROTOTYPE(static struct uxsin *check_unix,(INODETYPE i));
_PROTOTYPE(static void get_ax25,(char *p));
_PROTOTYPE(static void get_ipx,(char *p));
_PROTOTYPE(static void get_netlink,(char *p));
_PROTOTYPE(static void get_pack,(char *p));
_PROTOTYPE(static void get_raw,(char *p));
_PROTOTYPE(static void get_tcpudp,(char *p, int pr, int clr));
_PROTOTYPE(static void get_unix,(char *p));
_PROTOTYPE(static void print_ax25info,(struct ax25sin *ap));
_PROTOTYPE(static void print_ipxinfo,(struct ipxsin *ip));
#if defined(HASIPv6)
_PROTOTYPE(static struct rawsin *check_raw6,(INODETYPE i));
_PROTOTYPE(static struct tcp_udp6 *check_tcpudp6,(INODETYPE i, char **p));
_PROTOTYPE(static void get_raw6,(char *p));
_PROTOTYPE(static void get_tcpudp6,(char *p, int pr, int clr));
_PROTOTYPE(static int net6a2in6,(char *as, struct in6_addr *ad));
#endif /* defined(HASIPv6) */
/*
* build_IPstates() -- build the TCP and UDP state tables
*/
void
build_IPstates()
{
if (!TcpSt) {
(void) enter_IPstate("TCP", "ESTABLISHED", TCP_ESTABLISHED);
(void) enter_IPstate("TCP", "SYN_SENT", TCP_SYN_SENT);
(void) enter_IPstate("TCP", "SYN_RECV", TCP_SYN_RECV);
(void) enter_IPstate("TCP", "FIN_WAIT1", TCP_FIN_WAIT1);
(void) enter_IPstate("TCP", "FIN_WAIT2", TCP_FIN_WAIT2);
(void) enter_IPstate("TCP", "TIME_WAIT", TCP_TIME_WAIT);
(void) enter_IPstate("TCP", "CLOSE", TCP_CLOSE);
(void) enter_IPstate("TCP", "CLOSE_WAIT", TCP_CLOSE_WAIT);
(void) enter_IPstate("TCP", "LAST_ACK", TCP_LAST_ACK);
(void) enter_IPstate("TCP", "LISTEN", TCP_LISTEN);
(void) enter_IPstate("TCP", "CLOSING", TCP_CLOSING);
(void) enter_IPstate("TCP", "CLOSED", 0);
(void) enter_IPstate("TCP", (char *)NULL, 0);
}
}
/*
* check_ax25() - check for AX25 socket file
*/
static struct ax25sin *
check_ax25(i)
INODETYPE i; /* socket file's inode number */
{
struct ax25sin *ap;
int h;
h = INOHASH(i);
for (ap = AX25sin[h]; ap; ap = ap->next) {
if (i == ap->inode)
return(ap);
}
return((struct ax25sin *)NULL);
}
/*
* check_ipx() - check for IPX socket file
*/
static struct ipxsin *
check_ipx(i)
INODETYPE i; /* socket file's inode number */
{
int h;
struct ipxsin *ip;
h = INOHASH(i);
for (ip = Ipxsin[h]; ip; ip = ip->next) {
if (i == ip->inode)
return(ip);
}
return((struct ipxsin *)NULL);
}
/*
* check_netlink() - check for Netlink socket file
*/
static struct nlksin *
check_netlink(i)
INODETYPE i; /* socket file's inode number */
{
int h;
struct nlksin *lp;
h = INOHASH(i);
for (lp = Nlksin[h]; lp; lp = lp->next) {
if (i == lp->inode)
return(lp);
}
return((struct nlksin *)NULL);
}
/*
* check_pack() - check for packet file
*/
static struct packin *
check_pack(i)
INODETYPE i; /* packet file's inode number */
{
int h;
struct packin *pp;
h = INOHASH(i);
for (pp = Packin[h]; pp; pp = pp->next) {
if (i == pp->inode)
return(pp);
}
return((struct packin *)NULL);
}
/*
* check_raw() - check for raw socket file
*/
static struct rawsin *
check_raw(i)
INODETYPE i; /* socket file's inode number */
{
int h;
struct rawsin *rp;
h = INOHASH(i);
for (rp = Rawsin[h]; rp; rp = rp->next) {
if (i == rp->inode)
return(rp);
}
return((struct rawsin *)NULL);
}
/*
* check_tcpudp() - check for IPv4 TCP or UDP socket file
*/
static struct tcp_udp *
check_tcpudp(i, p)
INODETYPE i; /* socket file's inode number */
char **p; /* protocol return */
{
int h;
struct tcp_udp *tp;
h = TCPUDPHASH(i);
for (tp = TcpUdp[h]; tp; tp = tp->next) {
if (i == tp->inode) {
switch (tp->proto) {
case 0:
*p = "TCP";
break;
case 1:
*p = "UDP";
break;
case 2:
*p = "UDPLITE";
break;
default:
*p = "unknown";
}
return(tp);
}
}
return((struct tcp_udp *)NULL);
}
#if defined(HASIPv6)
/*
* check_raw6() - check for raw IPv6 socket file
*/
static struct rawsin *
check_raw6(i)
INODETYPE i; /* socket file's inode number */
{
int h;
struct rawsin *rp;
h = INOHASH(i);
for (rp = Rawsin6[h]; rp; rp = rp->next) {
if (i == rp->inode)
return(rp);
}
return((struct rawsin *)NULL);
}
/*
* check_tcpudp6() - check for IPv6 TCP or UDP socket file
*/
static struct tcp_udp6 *
check_tcpudp6(i, p)
INODETYPE i; /* socket file's inode number */
char **p; /* protocol return */
{
int h;
struct tcp_udp6 *tp6;
h = TCPUDP6HASH(i);
for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) {
if (i == tp6->inode) {
switch (tp6->proto) {
case 0:
*p = "TCP";
break;
case 1:
*p = "UDP";
break;
case 2:
*p = "UDPLITE";
break;
default:
*p = "unknown";
}
return(tp6);
}
}
return((struct tcp_udp6 *)NULL);
}
#endif /* defined(HASIPv6) */
/*
* check_unix() - check for UNIX domain socket
*/
static struct uxsin *
check_unix(i)
INODETYPE i; /* socket file's inode number */
{
int h;
struct uxsin *up;
h = INOHASH(i);
for (up = Uxsin[h]; up; up = up->next) {
if (i == up->inode)
return(up);
}
return((struct uxsin *)NULL);
}
/*
* get_ax25() - get /proc/net/ax25 info
*/
static void
get_ax25(p)
char *p; /* /proc/net/ipx path */
{
struct ax25sin *ap, *np;
FILE *as;
char buf[MAXPATHLEN], *da, *dev_ch, *ep, **fp, *sa;
int h, nf;
INODETYPE inode;
unsigned long rq, sq, state;
MALLOC_S len;
unsigned char rqs, sqs;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
/*
* Do second time cleanup or first time setup.
*/
if (AX25sin) {
for (h = 0; h < INOBUCKS; h++) {
for (ap = AX25sin[h]; ap; ap = np) {
np = ap->next;
if (ap->da)
(void) free((FREE_P *)ap->da);
if (ap->dev_ch)
(void) free((FREE_P *)ap->dev_ch);
if (ap->sa)
(void) free((FREE_P *)ap->sa);
(void) free((FREE_P *)ap);
}
AX25sin[h] = (struct ax25sin *)NULL;
}
} else {
AX25sin = (struct ax25sin **)calloc(INOBUCKS,
sizeof(struct ax25sin *));
if (!AX25sin) {
(void) fprintf(stderr,
"%s: can't allocate %d AX25 hash pointer bytes\n",
Pn, (int)(INOBUCKS * sizeof(struct ax25sin *)));
Exit(1);
}
}
/*
* Open the /proc/net/ax25 file, assign a page size buffer to the stream,
* and read it. Store AX25 socket info in the AX25sin[] hash buckets.
*/
if (!(as = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, as)) {
if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) < 24)
continue;
/*
* /proc/net/ax25 has no title line, a very poor deficiency in its
* implementation.
*
* The ax25_get_info() function in kern module .../net/ax25/af_ax25.c
* says the format of the lines in the file is:
*
* magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 \
* t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q \
* inode
*
* The code in this function is forced to assume that format is in
* effect..
*/
/*
* Assemble the inode number and see if it has already been recorded.
* If it has, skip this line.
*/
ep = (char *)NULL;
if (!fp[23] || !*fp[23]
|| (inode = strtoull(fp[23], &ep, 0)) == ULONG_MAX
|| !ep || *ep)
continue;
h = INOHASH((INODETYPE)inode);
for (ap = AX25sin[h]; ap; ap = ap->next) {
if (inode == ap->inode)
break;
}
if (ap)
continue;
/*
* Assemble the send and receive queue values and the state.
*/
rq = sq = (unsigned long)0;
rqs = sqs = (unsigned char)0;
ep = (char *)NULL;
if (!fp[21] || !*fp[21]
|| (sq = strtoul(fp[21], &ep, 0)) == ULONG_MAX || !ep || *ep)
continue;
sqs = (unsigned char)1;
ep = (char *)NULL;
if (!fp[22] || !*fp[22]
|| (rq = strtoul(fp[22], &ep, 0)) == ULONG_MAX || !ep || *ep)
continue;
rqs = (unsigned char)1;
ep = (char *)NULL;
if (!fp[4] || !*fp[4]
|| (state = strtoul(fp[4], &ep, 0)) == ULONG_MAX || !ep || *ep)
continue;
/*
* Allocate space for the destination address.
*/
if (!fp[3] || !*fp[3])
da = (char *)NULL;
else if ((len = strlen(fp[3]))) {
if (!(da = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d destination AX25 addr bytes: %s\n",
Pn, (int)(len + 1), fp[3]);
Exit(1);
}
(void) snpf(da, len + 1, "%s", fp[3]);
} else
da = (char *)NULL;
/*
* Allocate space for the source address.
*/
if (!fp[2] || !*fp[2])
sa = (char *)NULL;
else if ((len = strlen(fp[2]))) {
if (!(sa = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d source AX25 address bytes: %s\n",
Pn, (int)(len + 1), fp[2]);
Exit(1);
}
(void) snpf(sa, len + 1, "%s", fp[2]);
} else
sa = (char *)NULL;
/*
* Allocate space for the device characters.
*/
if (!fp[1] || !*fp[1])
dev_ch = (char *)NULL;
else if ((len = strlen(fp[1]))) {
if (!(dev_ch = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d destination AX25 dev bytes: %s\n",
Pn, (int)(len + 1), fp[1]);
Exit(1);
}
(void) snpf(dev_ch, len + 1, "%s", fp[1]);
} else
dev_ch = (char *)NULL;
/*
* Allocate space for an ax25sin entry, fill it, and link it to its
* hash bucket.
*/
if (!(ap = (struct ax25sin *)malloc(sizeof(struct ax25sin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d byte ax25sin structure\n",
Pn, (int)sizeof(struct ax25sin));
Exit(1);
}
ap->da = da;
ap->dev_ch = dev_ch;
ap->inode = inode;
ap->rq = rq;
ap->rqs = rqs;
ap->sa = sa;
ap->sq = sq;
ap->sqs = sqs;
ap->state = (int)state;
ap->next = AX25sin[h];
AX25sin[h] = ap;
}
(void) fclose(as);
}
/*
* get_ipx() - get /proc/net/ipx info
*/
static void
get_ipx(p)
char *p; /* /proc/net/ipx path */
{
char buf[MAXPATHLEN], *ep, **fp, *la, *ra;
int fl = 1;
int h;
INODETYPE inode;
unsigned long rxq, state, txq;
struct ipxsin *ip, *np;
MALLOC_S len;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
FILE *xs;
/*
* Do second time cleanup or first time setup.
*/
if (Ipxsin) {
for (h = 0; h < INOBUCKS; h++) {
for (ip = Ipxsin[h]; ip; ip = np) {
np = ip->next;
if (ip->la)
(void) free((FREE_P *)ip->la);
if (ip->ra)
(void) free((FREE_P *)ip->ra);
(void) free((FREE_P *)ip);
}
Ipxsin[h] = (struct ipxsin *)NULL;
}
} else {
Ipxsin = (struct ipxsin **)calloc(INOBUCKS,
sizeof(struct ipxsin *));
if (!Ipxsin) {
(void) fprintf(stderr,
"%s: can't allocate %d IPX hash pointer bytes\n",
Pn, (int)(INOBUCKS * sizeof(struct ipxsin *)));
Exit(1);
}
}
/*
* Open the /proc/net/ipx file, assign a page size buffer to the stream,
* and read it. Store IPX socket info in the Ipxsin[] hash buckets.
*/
if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, xs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 7)
continue;
if (fl) {
/*
* Check the column labels in the first line.
*/
if (!fp[0] || strcmp(fp[0], "Local_Address")
|| !fp[1] || strcmp(fp[1], "Remote_Address")
|| !fp[2] || strcmp(fp[2], "Tx_Queue")
|| !fp[3] || strcmp(fp[3], "Rx_Queue")
|| !fp[4] || strcmp(fp[4], "State")
|| !fp[5] || strcmp(fp[5], "Uid")
|| !fp[6] || strcmp(fp[6], "Inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
fl = 0;
continue;
}
/*
* Assemble the inode number and see if the inode is already
* recorded.
*/
ep = (char *)NULL;
if (!fp[6] || !*fp[6]
|| (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX
|| !ep || *ep)
continue;
h = INOHASH(inode);
for (ip = Ipxsin[h]; ip; ip = ip->next) {
if (inode == ip->inode)
break;
}
if (ip)
continue;
/*
* Assemble the transmit and receive queue values and the state.
*/
ep = (char *)NULL;
if (!fp[2] || !*fp[2]
|| (txq = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[3] || !*fp[3]
|| (rxq = strtoul(fp[3], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[4] || !*fp[4]
|| (state = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
/*
* Allocate space for the local address, unless it is "Not_Connected".
*/
if (!fp[0] || !*fp[0] || strcmp(fp[0], "Not_Connected") == 0)
la = (char *)NULL;
else if ((len = strlen(fp[0]))) {
if (!(la = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d local IPX address bytes: %s\n",
Pn, (int)(len + 1), fp[0]);
Exit(1);
}
(void) snpf(la, len + 1, "%s", fp[0]);
} else
la = (char *)NULL;
/*
* Allocate space for the remote address, unless it is "Not_Connected".
*/
if (!fp[1] || !*fp[1] || strcmp(fp[1], "Not_Connected") == 0)
ra = (char *)NULL;
else if ((len = strlen(fp[1]))) {
if (!(ra = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d remote IPX address bytes: %s\n",
Pn, (int)(len + 1), fp[1]);
Exit(1);
}
(void) snpf(ra, len + 1, "%s", fp[1]);
} else
ra = (char *)NULL;
/*
* Allocate space for an ipxsin entry, fill it, and link it to its
* hash bucket.
*/
if (!(ip = (struct ipxsin *)malloc(sizeof(struct ipxsin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d byte ipxsin structure\n",
Pn, (int)sizeof(struct ipxsin));
Exit(1);
}
ip->inode = inode;
ip->la = la;
ip->ra = ra;
ip->txq = txq;
ip->rxq = rxq;
ip->state = (int)state;
ip->next = Ipxsin[h];
Ipxsin[h] = ip;
}
(void) fclose(xs);
}
/*
* get_netlink() - get /proc/net/netlink info
*/
static void
get_netlink(p)
char *p; /* /proc/net/netlink path */
{
char buf[MAXPATHLEN], *ep, **fp;
int fr = 1;
int h, l, pr;
INODETYPE inode;
struct nlksin *np, *lp;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
FILE *xs;
/*
* Do second time cleanup or first time setup.
*/
if (Nlksin) {
for (h = 0; h < INOBUCKS; h++) {
for (lp = Nlksin[h]; lp; lp = np) {
np = lp->next;
(void) free((FREE_P *)lp);
}
Nlksin[h] = (struct nlksin *)NULL;
}
} else {
Nlksin = (struct nlksin **)calloc(INOBUCKS,sizeof(struct nlksin *));
if (!Nlksin) {
(void) fprintf(stderr,
"%s: can't allocate %d netlink hash pointer bytes\n",
Pn, (int)(INOBUCKS * sizeof(struct nlksin *)));
Exit(1);
}
}
/*
* Open the /proc/net/netlink file, assign a page size buffer to its stream,
* and read the file. Store Netlink info in the Nlksin[] hash buckets.
*/
if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, xs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 10)
continue;
if (fr) {
/*
* Check the column labels in the first line.
*/
if (!fp[1] || strcmp(fp[1], "Eth")
|| !fp[9] || strcmp(fp[9], "Inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
fr = 0;
continue;
}
/*
* Assemble the inode number and see if the inode is already
* recorded.
*/
ep = (char *)NULL;
if (!fp[9] || !*fp[9]
|| (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
|| !ep || *ep)
continue;
h = INOHASH(inode);
for (lp = Nlksin[h]; lp; lp = lp->next) {
if (inode == lp->inode)
break;
}
if (lp)
continue;
/*
* Save the protocol from the Eth column.
*/
if (!fp[1] || !*fp[1] || (strlen(fp[1])) < 1)
continue;
pr = atoi(fp[1]);
/*
* Allocate space for a nlksin entry, fill it, and link it to its
* hash bucket.
*/
if (!(lp = (struct nlksin *)malloc(sizeof(struct nlksin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d byte Netlink structure\n",
Pn, (int)sizeof(struct nlksin));
Exit(1);
}
lp->inode = inode;
lp->pr = pr;
lp->next = Nlksin[h];
Nlksin[h] = lp;
}
(void) fclose(xs);
}
/*
* get_pack() - get /proc/net/packet info
*/
static void
get_pack(p)
char *p; /* /proc/net/raw path */
{
char buf[MAXPATHLEN], *ep, **fp;
int fl = 1;
int h, ty;
INODETYPE inode;
struct packin *np, *pp;
unsigned long pr;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
FILE *xs;
/*
* Do second time cleanup or first time setup.
*/
if (Packin) {
for (h = 0; h < INOBUCKS; h++) {
for (pp = Packin[h]; pp; pp = np) {
np = pp->next;
(void) free((FREE_P *)pp);
}
Packin[h] = (struct packin *)NULL;
}
} else {
Packin = (struct packin **)calloc(INOBUCKS,
sizeof(struct packin *));
if (!Packin) {
(void) fprintf(stderr,
"%s: can't allocate %d packet hash pointer bytes\n",
Pn, (int)(INOBUCKS * sizeof(struct packin *)));
Exit(1);
}
}
/*
* Open the /proc/net/packet file, assign a page size buffer to its stream,
* and read the file. Store packet info in the Packin[] hash buckets.
*/
if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, xs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 9)
continue;
if (fl) {
/*
* Check the column labels in the first line.
*/
if (!fp[2] || strcmp(fp[2], "Type")
|| !fp[3] || strcmp(fp[3], "Proto")
|| !fp[8] || strcmp(fp[8], "Inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
fl = 0;
continue;
}
/*
* Assemble the inode number and see if the inode is already
* recorded.
*/
ep = (char *)NULL;
if (!fp[8] || !*fp[8]
|| (inode = strtoull(fp[8], &ep, 0)) == ULONG_MAX
|| !ep || *ep)
continue;
h = INOHASH(inode);
for (pp = Packin[h]; pp; pp = pp->next) {
if (inode == pp->inode)
break;
}
if (pp)
continue;
/*
* Save the socket type and protocol.
*/
if (!fp[2] || !*fp[2] || (strlen(fp[2])) < 1)
continue;
ty = atoi(fp[2]);
ep = (char *)NULL;
if (!fp[3] || !*fp[3] || (strlen(fp[3]) < 1)
|| ((pr = strtoul(fp[3], &ep, 16)) == ULONG_MAX) || !ep || *ep)
continue;
/*
* Allocate space for a packin entry, fill it, and link it to its
* hash bucket.
*/
if (!(pp = (struct packin *)malloc(sizeof(struct packin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d byte packet structure\n",
Pn, (int)sizeof(struct packin));
Exit(1);
}
pp->inode = inode;
pp->pr = (int)pr;
pp->ty = ty;
pp->next = Packin[h];
Packin[h] = pp;
}
(void) fclose(xs);
}
/*
* get_raw() - get /proc/net/raw info
*/
static void
get_raw(p)
char *p; /* /proc/net/raw path */
{
char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp;
int h;
INODETYPE inode;
int nf = 12;
struct rawsin *np, *rp;
MALLOC_S lal, ral, spl;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
FILE *xs;
/*
* Do second time cleanup or first time setup.
*/
if (Rawsin) {
for (h = 0; h < INOBUCKS; h++) {
for (rp = Rawsin[h]; rp; rp = np) {
np = rp->next;
if (rp->la)
(void) free((FREE_P *)rp->la);
if (rp->ra)
(void) free((FREE_P *)rp->ra);
(void) free((FREE_P *)rp);
}
Rawsin[h] = (struct rawsin *)NULL;
}
} else {
Rawsin = (struct rawsin **)calloc(INOBUCKS,
sizeof(struct rawsin *));
if (!Rawsin) {
(void) fprintf(stderr,
"%s: can't allocate %d raw hash pointer bytes\n",
Pn, (int)(INOBUCKS * sizeof(struct rawsin *)));
Exit(1);
}
}
/*
* Open the /proc/net/raw file, assign a page size buffer to its stream,
* and read the file. Store raw socket info in the Rawsin[] hash buckets.
*/
if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, xs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf)
continue;
if (nf == 12) {
/*
* Check the column labels in the first line.
*/
if (!fp[1] || strcmp(fp[1], "local_address")
|| !fp[2] || strcmp(fp[2], "rem_address")
|| !fp[3] || strcmp(fp[3], "st")
|| !fp[11] || strcmp(fp[11], "inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
nf = 10;
continue;
}
/*
* Assemble the inode number and see if the inode is already
* recorded.
*/
ep = (char *)NULL;
if (!fp[9] || !*fp[9]
|| (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
|| !ep || *ep)
continue;
h = INOHASH(inode);
for (rp = Rawsin[h]; rp; rp = rp->next) {
if (inode == rp->inode)
break;
}
if (rp)
continue;
/*
* Save the local address, remote address, and state.
*/
if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) {
la = (char *)NULL;
lal = (MALLOC_S)0;
} else {
if (!(la = (char *)malloc(lal + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d local raw address bytes: %s\n",
Pn, (int)(lal + 1), fp[1]);
Exit(1);
}
(void) snpf(la, lal + 1, "%s", fp[1]);
}
if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) {
ra = (char *)NULL;
ral = (MALLOC_S)0;
} else {
if (!(ra = (char *)malloc(ral + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d remote raw address bytes: %s\n",
Pn, (int)(ral + 1), fp[2]);
Exit(1);
}
(void) snpf(ra, ral + 1, "%s", fp[2]);
}
if (!fp[3] || !*fp[3] || (spl = strlen(fp[3])) < 1) {
sp = (char *)NULL;
spl = (MALLOC_S)0;
} else {
if (!(sp = (char *)malloc(spl + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d remote raw state bytes: %s\n",
Pn, (int)(spl + 1), fp[2]);
Exit(1);
}
(void) snpf(sp, spl + 1, "%s", fp[3]);
}
/*
* Allocate space for an rawsin entry, fill it, and link it to its
* hash bucket.
*/
if (!(rp = (struct rawsin *)malloc(sizeof(struct rawsin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d byte rawsin structure\n",
Pn, (int)sizeof(struct rawsin));
Exit(1);
}
rp->inode = inode;
rp->la = la;
rp->lal = lal;
rp->ra = ra;
rp->ral = ral;
rp->sp = sp;
rp->spl = spl;
rp->next = Rawsin[h];
Rawsin[h] = rp;
}
(void) fclose(xs);
}
/*
* get_tcpudp() - get IPv4 TCP, UDP or UDPLITE net info
*/
static void
get_tcpudp(p, pr, clr)
char *p; /* /proc/net/{tcp,udp} path */
int pr; /* protocol: 0 = TCP, 1 = UDP,
* 2 = UDPLITE */
int clr; /* 1 == clear the table */
{
char buf[MAXPATHLEN], *ep, **fp;
unsigned long faddr, fport, laddr, lport, rxq, state, txq;
FILE *fs;
int h, nf;
INODETYPE inode;
struct tcp_udp *np, *tp;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
/*
* Delete previous table contents.
*/
if (TcpUdp) {
if (clr) {
for (h = 0; h < TcpUdp_bucks; h++) {
for (tp = TcpUdp[h]; tp; tp = np) {
np = tp->next;
(void) free((FREE_P *)tp);
}
TcpUdp[h] = (struct tcp_udp *)NULL;
}
}
/*
* If no hash buckets have been allocated, do so now.
*/
} else {
/*
* Open the /proc/net/sockstat file and establish the hash bucket
* count from its "sockets: used" line.
*/
TcpUdp_bucks = INOBUCKS;
if ((fs = fopen(SockStatPath, "r"))) {
while(fgets(buf, sizeof(buf) - 1, fs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3)
continue;
if (!fp[0] || strcmp(fp[0], "sockets:")
|| !fp[1] || strcmp(fp[1], "used")
|| !fp[2] || !*fp[2])
continue;
if ((h = atoi(fp[2])) < 1)
h = INOBUCKS;
while (TcpUdp_bucks < h)
TcpUdp_bucks *= 2;
break;
}
(void) fclose(fs);
}
if (!(TcpUdp = (struct tcp_udp **)calloc(TcpUdp_bucks,
sizeof(struct tcp_udp *))))
{
(void) fprintf(stderr,
"%s: can't allocate %d bytes for TCP&UDP hash buckets\n",
Pn, (int)(TcpUdp_bucks * sizeof(struct tcp_udp *)));
Exit(1);
}
}
/*
* Open the /proc/net file, assign a page size buffer to the stream, and
* read it.
*/
if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
nf = 12;
while(fgets(buf, sizeof(buf) - 1, fs)) {
if (get_fields(buf,
(nf == 12) ? (char *)NULL : ":",
&fp, (int *)NULL, 0)
< nf)
continue;
if (nf == 12) {
if (!fp[1] || strcmp(fp[1], "local_address")
|| !fp[2] || strcmp(fp[2], "rem_address")
|| !fp[3] || strcmp(fp[3], "st")
|| !fp[4] || strcmp(fp[4], "tx_queue")
|| !fp[5] || strcmp(fp[5], "rx_queue")
|| !fp[11] || strcmp(fp[11], "inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
nf = 14;
continue;
}
/*
* Get the local and remote addresses.
*/
ep = (char *)NULL;
if (!fp[1] || !*fp[1]
|| (laddr = strtoul(fp[1], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[2] || !*fp[2]
|| (lport = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[3] || !*fp[3]
|| (faddr = strtoul(fp[3], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[4] || !*fp[4]
|| (fport = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
/*
* Get the state and queue sizes.
*/
ep = (char *)NULL;
if (!fp[5] || !*fp[5]
|| (state = strtoul(fp[5], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[6] || !*fp[6]
|| (txq = strtoul(fp[6], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[7] || !*fp[7]
|| (rxq = strtoul(fp[7], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
/*
* Get the inode and use it for hashing and searching.
*/
ep = (char *)NULL;
if (!fp[13] || !*fp[13]
|| (inode = strtoull(fp[13], &ep, 0)) == ULONG_MAX || !ep || *ep)
continue;
h = TCPUDPHASH(inode);
for (tp = TcpUdp[h]; tp; tp = tp->next) {
if (tp->inode == inode)
break;
}
if (tp)
continue;
/*
* Create a new entry and link it to its hash bucket.
*/
if (!(tp = (struct tcp_udp *)malloc(sizeof(struct tcp_udp)))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for tcp_udp struct\n",
Pn, (int)sizeof(struct tcp_udp));
Exit(1);
}
tp->inode = inode;
tp->faddr = faddr;
tp->fport = (int)(fport & 0xffff);
tp->laddr = laddr;
tp->lport = (int)(lport & 0xffff);
tp->txq = txq;
tp->rxq = rxq;
tp->proto = pr;
tp->state = (int)state;
tp->next = TcpUdp[h];
TcpUdp[h] = tp;
}
(void) fclose(fs);
}
#if defined(HASIPv6)
/*
* get_raw6() - get /proc/net/raw6 info
*/
static void
get_raw6(p)
char *p; /* /proc/net/raw path */
{
char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp;
int h;
INODETYPE inode;
int nf = 12;
struct rawsin *np, *rp;
MALLOC_S lal, ral, spl;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
FILE *xs;
/*
* Do second time cleanup or first time setup.
*/
if (Rawsin6) {
for (h = 0; h < INOBUCKS; h++) {
for (rp = Rawsin6[h]; rp; rp = np) {
np = rp->next;
if (rp->la)
(void) free((FREE_P *)rp->la);
if (rp->ra)
(void) free((FREE_P *)rp->ra);
(void) free((FREE_P *)rp);
}
Rawsin6[h] = (struct rawsin *)NULL;
}
} else {
Rawsin6 = (struct rawsin **)calloc(INOBUCKS,
sizeof(struct rawsin *));
if (!Rawsin6) {
(void) fprintf(stderr,
"%s: can't allocate %d raw6 hash pointer bytes\n",
Pn, (int)(INOBUCKS * sizeof(struct rawsin *)));
Exit(1);
}
}
/*
* Open the /proc/net/raw6 file, assign a page size buffer to the stream,
* and read it. Store raw6 socket info in the Rawsin6[] hash buckets.
*/
if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, xs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf)
continue;
if (nf == 12) {
/*
* Check the column labels in the first line.
*/
if (!fp[1] || strcmp(fp[1], "local_address")
|| !fp[2] || strcmp(fp[2], "remote_address")
|| !fp[3] || strcmp(fp[3], "st")
|| !fp[11] || strcmp(fp[11], "inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
nf = 10;
continue;
}
/*
* Assemble the inode number and see if the inode is already
* recorded.
*/
ep = (char *)NULL;
if (!fp[9] || !*fp[9]
|| (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
|| !ep || *ep)
continue;
h = INOHASH(inode);
for (rp = Rawsin6[h]; rp; rp = rp->next) {
if (inode == rp->inode)
break;
}
if (rp)
continue;
/*
* Save the local address, remote address, and state.
*/
if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) {
la = (char *)NULL;
lal = (MALLOC_S)0;
} else {
if (!(la = (char *)malloc(lal + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d local raw6 address bytes: %s\n",
Pn, (int)(lal + 1), fp[1]);
Exit(1);
}
(void) snpf(la, lal + 1, "%s", fp[1]);
}
if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) {
ra = (char *)NULL;
ral = (MALLOC_S)0;
} else {
if (!(ra = (char *)malloc(ral + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d remote raw6 address bytes: %s\n",
Pn, (int)(ral + 1), fp[2]);
Exit(1);
}
(void) snpf(ra, ral + 1, "%s", fp[2]);
}
if (!fp[3] || !*fp[3] || (spl = strlen(fp[3])) < 1) {
sp = (char *)NULL;
spl = (MALLOC_S)0;
} else {
if (!(sp = (char *)malloc(spl + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d remote raw6 state bytes: %s\n",
Pn, (int)(spl + 1), fp[2]);
Exit(1);
}
(void) snpf(sp, spl + 1, "%s", fp[3]);
}
/*
* Allocate space for an rawsin entry, fill it, and link it to its
* hash bucket.
*/
if (!(rp = (struct rawsin *)malloc(sizeof(struct rawsin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d byte rawsin structure for IPv6\n",
Pn, (int)sizeof(struct rawsin));
Exit(1);
}
rp->inode = inode;
rp->la = la;
rp->lal = lal;
rp->ra = ra;
rp->ral = ral;
rp->sp = sp;
rp->spl = spl;
rp->next = Rawsin6[h];
Rawsin6[h] = rp;
}
(void) fclose(xs);
}
/*
* get_tcpudp6() - get IPv6 TCP, UDP or UDPLITE net info
*/
static void
get_tcpudp6(p, pr, clr)
char *p; /* /proc/net/{tcp,udp} path */
int pr; /* protocol: 0 = TCP, 1 = UDP */
int clr; /* 1 == clear the table */
{
char buf[MAXPATHLEN], *ep, **fp;
struct in6_addr faddr, laddr;
unsigned long fport, lport, rxq, state, txq;
FILE *fs;
int h, i, nf;
INODETYPE inode;
struct tcp_udp6 *np6, *tp6;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
/*
* Delete previous table contents. Allocate a table for the first time.
*/
if (TcpUdp6) {
if (clr) {
for (h = 0; h < TcpUdp6_bucks; h++) {
for (tp6 = TcpUdp6[h]; tp6; tp6 = np6) {
np6 = tp6->next;
(void) free((FREE_P *)tp6);
}
TcpUdp6[h] = (struct tcp_udp6 *)NULL;
}
}
} else {
/*
* Open the /proc/net/sockstat6 file and establish the hash bucket
* count from its "TCP6: inuse" and "UDP6: inuse" lines.
*/
TcpUdp6_bucks = INOBUCKS;
h = i = nf = 0;
if ((fs = fopen(SockStatPath6, "r"))) {
while(fgets(buf, sizeof(buf) - 1, fs)) {
if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3)
continue;
if (!fp[0]
|| !fp[1] || strcmp(fp[1], "inuse")
|| !fp[2] || !*fp[2])
continue;
if (!strcmp(fp[0], "TCP6:")) {
nf |= 1;
if ((h = atoi(fp[2])) < 1)
h = INOBUCKS;
i += h;
} else if (!strcmp(fp[0], "UDP6:")) {
nf |= 2;
if ((h = atoi(fp[2])) < 1)
h = INOBUCKS;
i += h;
} else
continue;
if (nf == 3) {
while (TcpUdp6_bucks < i)
TcpUdp6_bucks *= 2;
break;
}
}
(void) fclose(fs);
}
if (!(TcpUdp6 = (struct tcp_udp6 **)calloc(TcpUdp6_bucks,
sizeof(struct tcp_udp6 *))))
{
(void) fprintf(stderr,
"%s: can't allocate %d bytes for TCP6&UDP6 hash buckets\n",
Pn, (int)(TcpUdp6_bucks * sizeof(struct tcp_udp6 *)));
Exit(1);
}
}
/*
* Open the /proc/net file, assign a page size buffer to the stream,
* and read it.
*/
if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
nf = 12;
while(fgets(buf, sizeof(buf) - 1, fs)) {
if (get_fields(buf,
(nf == 12) ? (char *)NULL : ":",
&fp, (int *)NULL, 0)
< nf)
continue;
if (nf == 12) {
if (!fp[1] || strcmp(fp[1], "local_address")
|| !fp[2] || strcmp(fp[2], "remote_address")
|| !fp[3] || strcmp(fp[3], "st")
|| !fp[4] || strcmp(fp[4], "tx_queue")
|| !fp[5] || strcmp(fp[5], "rx_queue")
|| !fp[11] || strcmp(fp[11], "inode"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
nf = 14;
continue;
}
/*
* Get the local and remote addresses.
*/
if (!fp[1] || !*fp[1] || net6a2in6(fp[1], &laddr))
continue;
ep = (char *)NULL;
if (!fp[2] || !*fp[2]
|| (lport = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
if (!fp[3] || !*fp[3] || net6a2in6(fp[3], &faddr))
continue;
ep = (char *)NULL;
if (!fp[4] || !*fp[4]
|| (fport = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
/*
* Get the state and queue sizes.
*/
ep = (char *)NULL;
if (!fp[5] || !*fp[5]
|| (state = strtoul(fp[5], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[6] || !*fp[6]
|| (txq = strtoul(fp[6], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
ep = (char *)NULL;
if (!fp[7] || !*fp[7]
|| (rxq = strtoul(fp[7], &ep, 16)) == ULONG_MAX || !ep || *ep)
continue;
/*
* Get the inode and use it for hashing and searching.
*/
ep = (char *)NULL;
if (!fp[13] || !*fp[13]
|| (inode = strtoull(fp[13], &ep, 0)) == ULONG_MAX || !ep || *ep)
continue;
h = TCPUDP6HASH(inode);
for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) {
if (tp6->inode == inode)
break;
}
if (tp6)
continue;
/*
* Create a new entry and link it to its hash bucket.
*/
if (!(tp6 = (struct tcp_udp6 *)malloc(sizeof(struct tcp_udp6)))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for tcp_udp6 struct\n",
Pn, (int)sizeof(struct tcp_udp6));
Exit(1);
}
tp6->inode = inode;
tp6->faddr = faddr;
tp6->fport = (int)(fport & 0xffff);
tp6->laddr = laddr;
tp6->lport = (int)(lport & 0xffff);
tp6->txq = txq;
tp6->rxq = rxq;
tp6->proto = pr;
tp6->state = (int)state;
tp6->next = TcpUdp6[h];
TcpUdp6[h] = tp6;
}
(void) fclose(fs);
}
#endif /* defined(HASIPv6) */
/*
* get_unix() - get UNIX net info
*/
static void
get_unix(p)
char *p; /* /proc/net/unix path */
{
char buf[MAXPATHLEN], *ep, **fp, *path, *pcb;
int fl = 1;
int h, nf;
INODETYPE inode;
MALLOC_S len;
struct uxsin *np, *up;
FILE *us;
static char *vbuf = (char *)NULL;
static size_t vsz = (size_t)0;
/*
* Do second time cleanup or first time setup.
*/
if (Uxsin) {
for (h = 0; h < INOBUCKS; h++) {
for (up = Uxsin[h]; up; up = np) {
np = up->next;
if (up->path)
(void) free((FREE_P *)up->path);
if (up->pcb)
(void) free((FREE_P *)up->pcb);
(void) free((FREE_P *)up);
}
Uxsin[h] = (struct uxsin *)NULL;
}
} else {
Uxsin = (struct uxsin **)calloc(INOBUCKS, sizeof(struct uxsin *));
if (!Uxsin) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for Unix socket info\n",
Pn, (int)(INOBUCKS * sizeof(struct uxsin *)));
}
}
/*
* Open the /proc/net/unix file, assign a page size buffer to the stream,
* read the file's contents, and add them to the Uxsin hash buckets.
*/
if (!(us = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
return;
while (fgets(buf, sizeof(buf) - 1, us)) {
if ((nf = get_fields(buf, ":", &fp, (int *)NULL, 0)) < 7)
continue;
if (fl) {
/*
* Check the first line for header words.
*/
if (!fp[0] || strcmp(fp[0], "Num")
|| !fp[1] || strcmp(fp[1], "RefCount")
|| !fp[2] || strcmp(fp[2], "Protocol")
|| !fp[3] || strcmp(fp[3], "Flags")
|| !fp[4] || strcmp(fp[4], "Type")
|| !fp[5] || strcmp(fp[5], "St")
|| !fp[6] || strcmp(fp[6], "Inode")
|| nf < 8
|| !fp[7] || strcmp(fp[7], "Path"))
{
if (!Fwarn) {
(void) fprintf(stderr,
"%s: WARNING: unsupported format: %s\n",
Pn, p);
}
break;
}
fl = 0;
continue;
}
/*
* Assemble PCB address, inode number, and path name. If this
* inode is already represented in Uxsin, skip it.
*/
ep = (char *)NULL;
if (!fp[6] || !*fp[6]
|| (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX || !ep || *ep)
continue;
h = INOHASH(inode);
for (up = Uxsin[h]; up; up = up->next) {
if (inode == up->inode)
break;
}
if (up)
continue;
if (!fp[0] || !*fp[0])
pcb = (char *)NULL;
else {
len = strlen(fp[0]) + 2;
if (!(pcb = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for UNIX PCB: %s\n",
Pn, (int)(len + 1), fp[0]);
Exit(1);
}
(void) snpf(pcb, len + 1, "0x%s", fp[0]);
}
if (nf >= 8 && fp[7] && *fp[7] && (len = strlen(fp[7]))) {
if (!(path = (char *)malloc(len + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for UNIX path \"%s\"\n",
Pn, (int)(len + 1), fp[7]);
Exit(1);
}
(void) snpf(path, len + 1, "%s", fp[7]);
} else
path = (char *)NULL;
/*
* Allocate and fill a Unix socket info structure; link it to its
* hash bucket.
*/
if (!(up = (struct uxsin *)malloc(sizeof(struct uxsin)))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for uxsin struct\n",
Pn, (int)sizeof(struct uxsin));
Exit(1);
}
up->inode = inode;
up->pcb = pcb;
up->sb_def = 0;
if ((up->path = path) && (*path == '/')) {
/*
* If an absolute path (i.e., one that begins with a '/') exists
* for the line, attempt to stat(2) it and save the device and
* node numbers reported in the stat buffer.
*/
struct stat sb;
int sr;
if (HasNFS)
sr = statsafely(path, &sb);
else
sr = stat(path, &sb);
if (sr && ((sb.st_mode & S_IFMT) == S_IFSOCK)) {
up->sb_def = 1;
up->sb_dev = sb.st_dev;
up->sb_ino = (INODETYPE)sb.st_ino;
up->sb_rdev = sb.st_rdev;
}
}
up->next = Uxsin[h];
Uxsin[h] = up;
}
(void) fclose(us);
}
#if defined(HASIPv6)
/*
* net6a2in6() - convert ASCII IPv6 address in /proc/net/{tcp,udp} form to
* an in6_addr
*/
static int
net6a2in6(as, ad)
char *as; /* address source */
struct in6_addr *ad; /* address destination */
{
char buf[9], *ep;
int i;
size_t len;
/*
* Assemble four uint32_t's from 4 X 8 hex digits into s6_addr32[].
*/
for (i = 0, len = strlen(as);
(i < 4) && (len >= 8);
as += 8, i++, len -= 8)
{
(void) strncpy(buf, as, 8);
buf[8] = '\0';
ep = (char *)NULL;
if ((ad->s6_addr32[i] = (uint32_t)strtoul(buf, &ep, 16))
== (uint32_t)UINT32_MAX || !ep || *ep)
break;
}
return((*as || (i != 4) || len) ? 1 : 0);
}
#endif /* defined(HASIPv6) */
/*
* print_ax25info() - print AX25 socket info
*/
static void
print_ax25info(ap)
struct ax25sin *ap; /* AX25 socket info */
{
char *cp, pbuf[1024];
int ds;
MALLOC_S pl = (MALLOC_S)0;
if (Lf->nma)
return;
if (ap->sa) {
ds = (ap->da && strcmp(ap->da, "*")) ? 1 : 0;
(void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%s%s%s ", ap->sa,
ds ? "->" : "",
ds ? ap->da : "");
pl = strlen(pbuf);
}
if (ap->sqs) {
(void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "(Sq=%lu ", ap->sq);
pl = strlen(pbuf);
cp = "";
} else
cp = "(";
if (ap->rqs) {
(void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%sRq=%lu ", cp, ap->rq);
pl = strlen(pbuf);
cp = "";
}
(void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%sState=%d", cp, ap->state);
pl = strlen(pbuf);
if ((ap->state >= 0) && (ap->state < NAX25ST))
cp = ax25st[ap->state];
else
cp = NULL;
(void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%s%s)",
cp ? ", " : "",
cp ? cp : "");
pl = strlen(pbuf);
if (!(cp = (char *)malloc(pl + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for AX25 sock state, PID: %d\n",
Pn, (int)(pl + 1), Lp->pid);
Exit(1);
}
(void) snpf(cp, pl + 1, "%s", pbuf);
Lf->nma = cp;
}
/*
* print_ipxinfo() - print IPX socket info
*/
static void
print_ipxinfo(ip)
struct ipxsin *ip; /* IPX socket info */
{
char *cp, pbuf[256];
MALLOC_S pl;
if (Lf->nma)
return;
(void) snpf(pbuf, sizeof(pbuf), "(Tx=%lx Rx=%lx State=%02x)",
ip->txq, ip->rxq, ip->state);
pl = strlen(pbuf);
if (!(cp = (char *)malloc(pl + 1))) {
(void) fprintf(stderr,
"%s: can't allocate %d bytes for IPX sock state, PID: %d\n",
Pn, (int)(pl + 1), Lp->pid);
Exit(1);
}
(void) snpf(cp, pl + 1, "%s", pbuf);
Lf->nma = cp;
}
/*
* print_tcptpi() - print TCP/TPI state
*/
void
print_tcptpi(nl)
int nl; /* 1 == '\n' required */
{
char buf[128];
char *cp = (char *)NULL;
int ps = 0;
int s;
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
if (!TcpSt)
(void) build_IPstates();
if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) {
(void) snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d",
Lf->lts.state.i);
cp = buf;
} else
cp = TcpSt[s];
if (cp) {
if (Ffield)
(void) printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);
else {
putchar('(');
(void) fputs(cp, stdout);
}
ps++;
}
}
# if defined(HASTCPTPIQ)
if (Ftcptpi & TCPTPI_QUEUES) {
if (Lf->lts.rqs) {
if (Ffield)
putchar(LSOF_FID_TCPTPI);
else {
if (ps)
putchar(' ');
else
putchar('(');
}
(void) printf("QR=%lu", Lf->lts.rq);
if (Ffield)
putchar(Terminator);
ps++;
}
if (Lf->lts.sqs) {
if (Ffield)
putchar(LSOF_FID_TCPTPI);
else {
if (ps)
putchar(' ');
else
putchar('(');
}
(void) printf("QS=%lu", Lf->lts.sq);
if (Ffield)
putchar(Terminator);
ps++;
}
}
# endif /* defined(HASTCPTPIQ) */
# if defined(HASTCPTPIW)
if (Ftcptpi & TCPTPI_WINDOWS) {
if (Lf->lts.rws) {
if (Ffield)
putchar(LSOF_FID_TCPTPI);
else {
if (ps)
putchar(' ');
else
putchar('(');
}
(void) printf("WR=%lu", Lf->lts.rw);
if (Ffield)
putchar(Terminator);
ps++;
}
if (Lf->lts.wws) {
if (Ffield)
putchar(LSOF_FID_TCPTPI);
else {
if (ps)
putchar(' ');
else
putchar('(');
}
(void) printf("WW=%lu", Lf->lts.ww);
if (Ffield)
putchar(Terminator);
ps++;
}
}
# endif /* defined(HASTCPTPIW) */
if (!Ffield && ps)
putchar(')');
if (nl)
putchar('\n');
}
/*
* process_proc_sock() - process /proc-based socket
*/
void
process_proc_sock(p, s, ss, l, lss)
char *p; /* node's readlink() path */
struct stat *s; /* stat() result for path */
int ss; /* *s status -- i.e, SB_* values */
struct stat *l; /* lstat() result for FD (NULL for
* others) */
int lss; /* *l status -- i.e, SB_* values */
{
struct ax25sin *ap;
char *cp, *path, tbuf[64];
unsigned char *fa, *la;
struct in_addr fs, ls;
struct ipxsin *ip;
int i, len, nl;
struct nlksin *np;
struct packin *pp;
char *pr;
struct rawsin *rp;
struct tcp_udp *tp;
struct uxsin *up;
#if defined(HASIPv6)
int af;
struct tcp_udp6 *tp6;
#endif /* defined(HASIPv6) */
/*
* Enter offset, if possible.
*/
if (Foffset || !Fsize) {
if (l && (lss & SB_SIZE) && OffType) {
Lf->off = (SZOFFTYPE)l->st_size;
Lf->off_def = 1;
}
}
/*
* Check for socket's inode presence in the protocol info caches.
*/
if (AX25path) {
(void) get_ax25(AX25path);
(void) free((FREE_P *)AX25path);
AX25path = (char *)NULL;
}
if ((ss & SB_INO)
&& (ap = check_ax25((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to an AX25 /proc record.
*
* Set the type to "ax25"; save the device name; save the inode number;
* save the destination and source addresses; save the send and receive
* queue sizes; and save the connection state.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "ax25");
if (ap->dev_ch)
(void) enter_dev_ch(ap->dev_ch);
Lf->inode = ap->inode;
Lf->inp_ty = 1;
print_ax25info(ap);
return;
}
if (Ipxpath) {
(void) get_ipx(Ipxpath);
(void) free((FREE_P *)Ipxpath);
Ipxpath = (char *)NULL;
}
if ((ss & SB_INO)
&& (ip = check_ipx((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to an IPX /proc record.
*
* Set the type to "ipx"; enter the inode and device numbers; store
* the addresses, queue sizes, and state in the NAME column.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "ipx");
if (ss & SB_INO) {
Lf->inode = (INODETYPE)s->st_ino;
Lf->inp_ty = 1;
}
if (ss & SB_DEV) {
Lf->dev = s->st_dev;
Lf->dev_def = 1;
}
cp = Namech;
nl = Namechl;
*cp = '\0';
if (ip->la && nl) {
/*
* Store the local IPX address.
*/
len = strlen(ip->la);
if (len > nl)
len = nl;
(void) strncpy(cp, ip->la, len);
cp += len;
*cp = '\0';
nl -= len;
}
if (ip->ra && nl) {
/*
* Store the remote IPX address, prefixed with "->".
*/
if (nl > 2) {
(void) snpf(cp, nl, "->");
cp += 2;
nl -= 2;
}
if (nl) {
(void) snpf(cp, nl, "%s", ip->ra);
cp += len;
nl -= len;
}
}
(void) print_ipxinfo(ip);
if (Namech[0])
enter_nm(Namech);
return;
}
if (Rawpath) {
(void) get_raw(Rawpath);
(void) free((FREE_P *)Rawpath);
Rawpath = (char *)NULL;
}
if ((ss & SB_INO)
&& (rp = check_raw((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to a raw /proc record.
*
* Set the type to "raw"; enter the inode number; store the local
* address, remote address, and state in the NAME column.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "raw");
if (ss & SB_INO) {
Lf->inode = (INODETYPE)s->st_ino;
Lf->inp_ty = 1;
}
cp = Namech;
nl = Namechl - 2;
*cp = '\0';
if (rp->la && rp->lal) {
/*
* Store the local raw address.
*/
if (nl > rp->lal) {
(void) snpf(cp, nl, "%s", rp->la);
cp += rp->lal;
*cp = '\0';
nl -= rp->lal;
}
}
if (rp->ra && rp->ral) {
/*
* Store the remote raw address, prefixed with "->".
*/
if (nl > (rp->ral + 2)) {
(void) snpf(cp, nl, "->%s", rp->ra);
cp += (rp->ral + 2);
nl -= (rp->ral + 2);
}
}
if (rp->sp && rp->spl) {
/*
* Store the state, optionally prefixed by a space, in the
* form "st=x...x".
*/
if (nl > (len = ((cp == Namech) ? 0 : 1) + 3 + rp->spl)) {
(void) snpf(cp, nl, "%sst=%s",
(cp == Namech) ? "" : " ", rp->sp);
cp += len;
*cp = '\0';
nl -= len;
}
}
if (Namech[0])
enter_nm(Namech);
return;
}
if (Nlkpath) {
(void) get_netlink(Nlkpath);
(void) free((FREE_P *) Nlkpath);
Nlkpath = (char *)NULL;
}
if ((ss & SB_INO)
&& (np = check_netlink((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to a Netlink /proc record.
*
* Set the type to "netlink" and store the protocol in the NAME
* column. Save the inode number.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "netlink");
switch (np->pr) {
#if defined(NETLINK_ROUTE)
case NETLINK_ROUTE:
cp = "ROUTE";
break;
#endif /* defined(NETLINK_ROUTE) */
#if defined(NETLINK_UNUSED)
case NETLINK_UNUSED:
cp = "UNUSED";
break;
#endif /* defined(NETLINK_UNUSED) */
#if defined(NETLINK_USERSOCK)
case NETLINK_USERSOCK:
cp = "USERSOCK";
break;
#endif /* defined(NETLINK_USERSOCK) */
#if defined(NETLINK_FIREWALL)
case NETLINK_FIREWALL:
cp = "FIREWALL";
break;
#endif /* defined(NETLINK_FIREWALL) */
#if defined(NETLINK_INET_DIAG)
case NETLINK_INET_DIAG:
cp = "INET_DIAG";
break;
#endif /* defined(NETLINK_INET_DIAG) */
#if defined(NETLINK_NFLOG)
case NETLINK_NFLOG:
cp = "NFLOG";
break;
#endif /* defined(NETLINK_NFLOG) */
#if defined(NETLINK_XFRM)
case NETLINK_XFRM:
cp = "XFRM";
break;
#endif /* defined(NETLINK_XFRM) */
#if defined(NETLINK_SELINUX)
case NETLINK_SELINUX:
cp = "SELINUX";
break;
#endif /* defined(NETLINK_SELINUX) */
#if defined(NETLINK_ISCSI)
case NETLINK_ISCSI:
cp = "ISCSI";
break;
#endif /* defined(NETLINK_ISCSI) */
#if defined(NETLINK_AUDIT)
case NETLINK_AUDIT:
cp = "AUDIT";
break;
#endif /* defined(NETLINK_AUDIT) */
#if defined(NETLINK_FIB_LOOKUP)
case NETLINK_FIB_LOOKUP:
cp = "FIB_LOOKUP";
break;
#endif /* defined(NETLINK_FIB_LOOKUP) */
#if defined(NETLINK_CONNECTOR)
case NETLINK_CONNECTOR:
cp = "CONNECTOR";
break;
#endif /* defined(NETLINK_CONNECTOR) */
#if defined(NETLINK_NETFILTER)
case NETLINK_NETFILTER:
cp = "NETFILTER";
break;
#endif /* defined(NETLINK_NETFILTER) */
#if defined(NETLINK_IP6_FW)
case NETLINK_IP6_FW:
cp = "IP6_FW";
break;
#endif /* defined(NETLINK_IP6_FW) */
#if defined(NETLINK_DNRTMSG)
case NETLINK_DNRTMSG:
cp = "DNRTMSG";
break;
#endif /* defined(NETLINK_DNRTMSG) */
#if defined(NETLINK_KOBJECT_UEVENT)
case NETLINK_KOBJECT_UEVENT:
cp = "KOBJECT_UEVENT";
break;
#endif /* defined(NETLINK_KOBJECT_UEVENT) */
#if defined(NETLINK_GENERIC)
case NETLINK_GENERIC:
cp = "GENERIC";
break;
#endif /* defined(NETLINK_GENERIC) */
#if defined(NETLINK_SCSITRANSPORT)
case NETLINK_SCSITRANSPORT:
cp = "SCSITRANSPORT";
break;
#endif /* defined(NETLINK_SCSITRANSPORT) */
#if defined(NETLINK_ECRYPTFS)
case NETLINK_ECRYPTFS:
cp = "ECRYPTFS";
break;
#endif /* defined(NETLINK_ECRYPTFS) */
default:
snpf(Namech, Namechl, "unknown protocol: %d", np->pr);
cp = (char *)NULL;
}
if (cp)
(void) snpf(Namech, Namechl, "%s", cp);
Lf->inode = (INODETYPE)s->st_ino;
Lf->inp_ty = 1;
if (Namech[0])
enter_nm(Namech);
return;
}
if (Packpath) {
(void) get_pack(Packpath);
(void) free((FREE_P *)Packpath);
Packpath = (char *)NULL;
}
if ((ss & SB_INO)
&& (pp = check_pack((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to a packet /proc record.
*
* Set the type to "pack" and store the socket type in the NAME
* column. Put the protocol name in the NODE column and the inode
* number in the DEVICE column.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "pack");
switch(pp->ty) {
#if defined(SOCK_STREAM)
case SOCK_STREAM:
cp = "STREAM";
break;
#endif /* defined(SOCK_STREAM) */
#if defined(SOCK_DGRAM)
case SOCK_DGRAM:
cp = "DGRAM";
break;
#endif /* defined(SOCK_DGRAM) */
#if defined(SOCK_RAW)
case SOCK_RAW:
cp = "RAW";
break;
#endif /* defined(SOCK_RAW) */
#if defined(SOCK_RDM)
case SOCK_RDM:
cp = "RDM";
break;
#endif /* defined(SOCK_RDM) */
#if defined(SOCK_SEQPACKET)
case SOCK_SEQPACKET:
cp = "SEQPACKET";
break;
#endif /* defined(SOCK_SEQPACKET) */
#if defined(SOCK_PACKET)
case SOCK_PACKET:
cp = "PACKET";
break;
#endif /* defined(SOCK_PACKET) */
default:
snpf(Namech, Namechl, "unknown type: %d", pp->ty);
cp = (char *)NULL;
}
if (cp)
(void) snpf(Namech, Namechl, "type=SOCK_%s", cp);
switch (pp->pr) {
#if defined(ETH_P_LOOP)
case ETH_P_LOOP:
cp = "LOOP";
break;
#endif /* defined(ETH_P_LOOP) */
#if defined(ETH_P_PUP)
case ETH_P_PUP:
cp = "PUP";
break;
#endif /* defined(ETH_P_PUP) */
#if defined(ETH_P_PUPAT)
case ETH_P_PUPAT:
cp = "PUPAT";
break;
#endif /* defined(ETH_P_PUPAT) */
#if defined(ETH_P_IP)
case ETH_P_IP:
cp = "IP";
break;
#endif /* defined(ETH_P_IP) */
#if defined(ETH_P_X25)
case ETH_P_X25:
cp = "X25";
break;
#endif /* defined(ETH_P_X25) */
#if defined(ETH_P_ARP)
case ETH_P_ARP:
cp = "ARP";
break;
#endif /* defined(ETH_P_ARP) */
#if defined(ETH_P_BPQ)
case ETH_P_BPQ:
cp = "BPQ";
break;
#endif /* defined(ETH_P_BPQ) */
#if defined(ETH_P_IEEEPUP)
case ETH_P_IEEEPUP:
cp = "I3EPUP";
break;
#endif /* defined(ETH_P_IEEEPUP) */
#if defined(ETH_P_IEEEPUPAT)
case ETH_P_IEEEPUPAT:
cp = "I3EPUPA";
break;
#endif /* defined(ETH_P_IEEEPUPAT) */
#if defined(ETH_P_DEC)
case ETH_P_DEC:
cp = "DEC";
break;
#endif /* defined(ETH_P_DEC) */
#if defined(ETH_P_DNA_DL)
case ETH_P_DNA_DL:
cp = "DNA_DL";
break;
#endif /* defined(ETH_P_DNA_DL) */
#if defined(ETH_P_DNA_RC)
case ETH_P_DNA_RC:
cp = "DNA_RC";
break;
#endif /* defined(ETH_P_DNA_RC) */
#if defined(ETH_P_DNA_RT)
case ETH_P_DNA_RT:
cp = "DNA_RT";
break;
#endif /* defined(ETH_P_DNA_RT) */
#if defined(ETH_P_LAT)
case ETH_P_LAT:
cp = "LAT";
break;
#endif /* defined(ETH_P_LAT) */
#if defined(ETH_P_DIAG)
case ETH_P_DIAG:
cp = "DIAG";
break;
#endif /* defined(ETH_P_DIAG) */
#if defined(ETH_P_CUST)
case ETH_P_CUST:
cp = "CUST";
break;
#endif /* defined(ETH_P_CUST) */
#if defined(ETH_P_SCA)
case ETH_P_SCA:
cp = "SCA";
break;
#endif /* defined(ETH_P_SCA) */
#if defined(ETH_P_RARP)
case ETH_P_RARP:
cp = "RARP";
break;
#endif /* defined(ETH_P_RARP) */
#if defined(ETH_P_ATALK)
case ETH_P_ATALK:
cp = "ATALK";
break;
#endif /* defined(ETH_P_ATALK) */
#if defined(ETH_P_AARP)
case ETH_P_AARP:
cp = "AARP";
break;
#endif /* defined(ETH_P_AARP) */
#if defined(ETH_P_8021Q)
case ETH_P_8021Q:
cp = "8021Q";
break;
#endif /* defined(ETH_P_8021Q) */
#if defined(ETH_P_IPX)
case ETH_P_IPX:
cp = "IPX";
break;
#endif /* defined(ETH_P_IPX) */
#if defined(ETH_P_IPV6)
case ETH_P_IPV6:
cp = "IPV6";
break;
#endif /* defined(ETH_P_IPV6) */
#if defined(ETH_P_SLOW)
case ETH_P_SLOW:
cp = "SLOW";
break;
#endif /* defined(ETH_P_SLOW) */
#if defined(ETH_P_WCCP)
case ETH_P_WCCP:
cp = "WCCP";
break;
#endif /* defined(ETH_P_WCCP) */
#if defined(ETH_P_PPP_DISC)
case ETH_P_PPP_DISC:
cp = "PPP_DIS";
break;
#endif /* defined(ETH_P_PPP_DISC) */
#if defined(ETH_P_PPP_SES)
case ETH_P_PPP_SES:
cp = "PPP_SES";
break;
#endif /* defined(ETH_P_PPP_SES) */
#if defined(ETH_P_MPLS_UC)
case ETH_P_MPLS_UC:
cp = "MPLS_UC";
break;
#endif /* defined(ETH_P_MPLS_UC) */
#if defined(ETH_P_ATMMPOA)
case ETH_P_ATMMPOA:
cp = "ATMMPOA";
break;
#endif /* defined(ETH_P_ATMMPOA) */
#if defined(ETH_P_MPLS_MC)
case ETH_P_MPLS_MC:
cp = "MPLS_MC";
break;
#endif /* defined(ETH_P_MPLS_MC) */
#if defined(ETH_P_ATMFATE)
case ETH_P_ATMFATE:
cp = "ATMFATE";
break;
#endif /* defined(ETH_P_ATMFATE) */
#if defined(ETH_P_AOE)
case ETH_P_AOE:
cp = "AOE";
break;
#endif /* defined(ETH_P_AOE) */
#if defined(ETH_P_TIPC)
case ETH_P_TIPC:
cp = "TIPC";
break;
#endif /* defined(ETH_P_TIPC) */
#if defined(ETH_P_802_3)
case ETH_P_802_3:
cp = "802.3";
break;
#endif /* defined(ETH_P_802_3) */
#if defined(ETH_P_AX25)
case ETH_P_AX25:
cp = "AX25";
break;
#endif /* defined(ETH_P_AX25) */
#if defined(ETH_P_ALL)
case ETH_P_ALL:
cp = "ALL";
break;
#endif /* defined(ETH_P_ALL) */
#if defined(ETH_P_802_2)
case ETH_P_802_2:
cp = "802.2";
break;
#endif /* defined(ETH_P_802_2) */
#if defined(ETH_P_SNAP)
case ETH_P_SNAP:
cp = "SNAP";
break;
#endif /* defined(ETH_P_SNAP) */
#if defined(ETH_P_DDCMP)
case ETH_P_DDCMP:
cp = "DDCMP";
break;
#endif /* defined(ETH_P_DDCMP) */
#if defined(ETH_P_WAN_PPP)
case ETH_P_WAN_PPP:
cp = "WAN_PPP";
break;
#endif /* defined(ETH_P_WAN_PPP) */
#if defined(ETH_P_PPP_MP)
case ETH_P_PPP_MP:
cp = "PPP MP";
break;
#endif /* defined(ETH_P_PPP_MP) */
#if defined(ETH_P_LOCALTALK)
case ETH_P_LOCALTALK:
cp = "LCLTALK";
break;
#endif /* defined(ETH_P_LOCALTALK) */
#if defined(ETH_P_PPPTALK)
case ETH_P_PPPTALK:
cp = "PPPTALK";
break;
#endif /* defined(ETH_P_PPPTALK) */
#if defined(ETH_P_TR_802_2)
case ETH_P_TR_802_2:
cp = "802.2";
break;
#endif /* defined(ETH_P_TR_802_2) */
#if defined(ETH_P_MOBITEX)
case ETH_P_MOBITEX:
cp = "MOBITEX";
break;
#endif /* defined(ETH_P_MOBITEX) */
#if defined(ETH_P_CONTROL)
case ETH_P_CONTROL:
cp = "CONTROL";
break;
#endif /* defined(ETH_P_CONTROL) */
#if defined(ETH_P_IRDA)
case ETH_P_IRDA:
cp = "IRDA";
break;
#endif /* defined(ETH_P_IRDA) */
#if defined(ETH_P_ECONET)
case ETH_P_ECONET:
cp = "ECONET";
break;
#endif /* defined(ETH_P_ECONET) */
#if defined(ETH_P_HDLC)
case ETH_P_HDLC:
cp = "HDLC";
break;
#endif /* defined(ETH_P_HDLC) */
#if defined(ETH_P_ARCNET)
case ETH_P_ARCNET:
cp = "ARCNET";
break;
#endif /* defined(ETH_P_ARCNET) */
default:
snpf(tbuf, sizeof(tbuf) - 1, "%d", pp->pr);
tbuf[sizeof(tbuf) - 1] = '\0';
cp = tbuf;
}
(void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, cp);
Lf->inp_ty = 2;
if (ss & SB_INO) {
(void) snpf(tbuf, sizeof(tbuf), InodeFmt_d,
(INODETYPE)s->st_ino);
tbuf[sizeof(tbuf) - 1] = '\0';
enter_dev_ch(tbuf);
}
if (Namech[0])
enter_nm(Namech);
return;
}
if (UNIXpath) {
(void) get_unix(UNIXpath);
(void) free((FREE_P *)UNIXpath);
UNIXpath = (char *)NULL;
}
if ((ss & SB_INO)
&& (up = check_unix((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to a UNIX /proc record.
*
* Set the type to "unix"; enter the PCB address in the DEVICE column;
* enter the inode number; and save the optional path.
*/
if (Funix)
Lf->sf |= SELUNX;
(void) snpf(Lf->type, sizeof(Lf->type), "unix");
if (up->pcb)
enter_dev_ch(up->pcb);
if (ss & SB_INO) {
Lf->inode = (INODETYPE)s->st_ino;
Lf->inp_ty = 1;
}
path = up->path ? up->path : p;
(void) enter_nm(path);
if (Sfile) {
/*
* See if this UNIX domain socket was specified as a search
* argument.
*
* Search first by device and node numbers, if that is possible;
* then search by name.
*/
unsigned char f = 0; /* file-found flag */
if (up->sb_def) {
/*
* If the UNIX socket information includes stat(2) results, do
* a device and node number search.
*
* Note: that requires the saving, temporary modification and
* restoration of some *Lf values.
*/
unsigned char sv_dev_def; /* saved dev_def */
unsigned char sv_inp_ty; /* saved inp_ty */
unsigned char sv_rdev_def; /* saved rdev_def */
dev_t sv_dev; /* saved dev */
INODETYPE sv_inode; /* saved inode */
dev_t sv_rdev; /* saved rdev */
sv_dev_def = Lf->dev_def;
sv_dev = Lf->dev;
sv_inode = Lf->inode;
sv_inp_ty = Lf->inp_ty;
sv_rdev_def = Lf->rdev_def;
sv_rdev = Lf->rdev;
Lf->dev_def = Lf->inp_ty = Lf->rdev_def = 1;
Lf->dev = up->sb_dev;
Lf->inode = up->sb_ino;
Lf->rdev = up->sb_rdev;
if (is_file_named((char *)NULL, 0)) {
f = 1;
Lf->sf |= SELNM;
}
Lf->dev_def = sv_dev_def;
Lf->dev = sv_dev;
Lf->inode = sv_inode;
Lf->inp_ty = sv_inp_ty;
Lf->rdev_def = sv_rdev_def;
Lf->rdev = sv_rdev;
}
if (!f && (ss & SB_MODE)) {
/*
* If the file has not yet been found and the stat buffer has
* st_mode, search for the file by full path.
*/
if (is_file_named(path,
((s->st_mode & S_IFMT) == S_IFCHR)) ? 1 : 0)
{
Lf->sf |= SELNM;
}
}
}
return;
}
#if defined(HASIPv6)
if (Raw6path) {
if (!Fxopt)
(void) get_raw6(Raw6path);
(void) free((FREE_P *)Raw6path);
Raw6path = (char *)NULL;
}
if (!Fxopt && (ss & SB_INO)
&& (rp = check_raw6((INODETYPE)s->st_ino))
) {
/*
* The inode is connected to a raw IPv6 /proc record.
*
* Set the type to "raw6"; enter the inode number; store the local
* address, remote address, and state in the NAME column.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "raw6");
if (ss & SB_INO) {
Lf->inode = (INODETYPE)s->st_ino;
Lf->inp_ty = 1;
}
cp = Namech;
nl = MAXPATHLEN - 2;
if (rp->la && rp->lal) {
/*
* Store the local raw IPv6 address.
*/
if (nl > rp->lal) {
(void) snpf(cp, nl, "%s", rp->la);
cp += rp->lal;
*cp = '\0';
nl -= rp->lal;
}
}
if (rp->ra && rp->ral) {
/*
* Store the remote raw address, prefixed with "->".
*/
if (nl > (rp->ral + 2)) {
(void) snpf(cp, nl, "->%s", rp->ra);
cp += (rp->ral + 2);
nl -= (rp->ral + 2);
}
}
if (rp->sp && rp->spl) {
/*
* Store the state, optionally prefixed by a space, in the
* form "st=x...x".
*/
if (nl > (len = ((cp == Namech) ? 0 : 1) + 3 + rp->spl)) {
(void) snpf(cp, nl, "%sst=%s",
(cp == Namech) ? "" : " ", rp->sp);
cp += len;
*cp = '\0';
nl -= len;
}
}
if (Namech[0])
enter_nm(Namech);
return;
}
if (TCP6path) {
if (!Fxopt)
(void) get_tcpudp6(TCP6path, 0, 1);
(void) free((FREE_P *)TCP6path);
TCP6path = (char *)NULL;
}
if (UDP6path) {
if (!Fxopt)
(void) get_tcpudp6(UDP6path, 1, 0);
(void) free((FREE_P *)UDP6path);
UDP6path = (char *)NULL;
}
if (UDPLITE6path) {
if (!Fxopt)
(void) get_tcpudp6(UDPLITE6path, 2, 0);
(void) free((FREE_P *)UDPLITE6path);
UDPLITE6path = (char *)NULL;
}
if (!Fxopt && (ss & SB_INO)
&& (tp6 = check_tcpudp6((INODETYPE)s->st_ino, &pr))
) {
/*
* The inode is connected to an IPv6 TCP or UDP /proc record.
*
* Set the type to "IPv6"; enter the protocol; put the inode number
* in the DEVICE column in lieu of the PCB address; save the local
* and foreign IPv6 addresses; save the type and protocol; and
* (optionally) save the queue sizes.
*/
i = tp6->state + TcpStOff;
if (TcpStXn) {
/*
* Check for state exclusion.
*/
if (i >= 0 && i < TcpNstates) {
if (TcpStX[i]) {
Lf->sf |= SELEXCLF;
return;
}
}
}
if (TcpStIn) {
/*
* Check for state inclusion.
*/
if (i >= 0 && i < TcpNstates) {
if (TcpStI[i])
TcpStI[i] = 2;
else {
Lf->sf |= SELEXCLF;
return;
}
}
}
if (Fnet && (FnetTy != 4))
Lf->sf |= SELNET;
(void) snpf(Lf->type, sizeof(Lf->type), "IPv6");
(void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, pr);
Lf->inp_ty = 2;
if (ss && SB_INO) {
(void) snpf(tbuf, sizeof(tbuf), InodeFmt_d,
(INODETYPE)s->st_ino);
tbuf[sizeof(tbuf) - 1] = '\0';
enter_dev_ch(tbuf);
}
af = AF_INET6;
if (!IN6_IS_ADDR_UNSPECIFIED(&tp6->faddr) || tp6->fport)
fa = (unsigned char *)&tp6->faddr;
else
fa = (unsigned char *)NULL;
if (!IN6_IS_ADDR_UNSPECIFIED(&tp6->laddr) || tp6->lport)
la = (unsigned char *)&tp6->laddr;
else
la = (unsigned char *)NULL;
if ((fa && IN6_IS_ADDR_V4MAPPED(&tp6->faddr))
|| (la && IN6_IS_ADDR_V4MAPPED(&tp6->laddr))) {
af = AF_INET;
if (fa)
fa += 12;
if (la)
la += 12;
}
ent_inaddr(la, tp6->lport, fa, tp6->fport, af);
Lf->lts.type = tp6->proto;
Lf->lts.state.i = tp6->state;
#if defined(HASTCPTPIQ)
Lf->lts.rq = tp6->rxq;
Lf->lts.sq = tp6->txq;
Lf->lts.rqs = Lf->lts.sqs = 1;
#endif /* defined(HASTCPTPIQ) */
return;
}
#endif /* defined(HASIPv6) */
if (TCPpath) {
if (!Fxopt)
(void) get_tcpudp(TCPpath, 0, 1);
(void) free((FREE_P *)TCPpath);
TCPpath = (char *)NULL;
}
if (UDPpath) {
if (!Fxopt)
(void) get_tcpudp(UDPpath, 1, 0);
(void) free((FREE_P *)UDPpath);
UDPpath = (char *)NULL;
}
if (UDPLITEpath) {
if (!Fxopt)
(void) get_tcpudp(UDPLITEpath, 2, 0);
(void) free((FREE_P *)UDPLITEpath);
UDPLITEpath = (char *)NULL;
}
if (!Fxopt && (ss & SB_INO)
&& (tp = check_tcpudp((INODETYPE)s->st_ino, &pr))
) {
/*
* The inode is connected to an IPv4 TCP or UDP /proc record.
*
* Set the type to "inet" or "IPv4"; enter the protocol; put the
* inode number in the DEVICE column in lieu of the PCB address;
* save the local and foreign IPv4 addresses; save the type and
* protocol; and (optionally) save the queue sizes.
*/
i = tp->state + TcpStOff;
if (TcpStXn) {
/*
* Check for state exclusion.
*/
if (i >= 0 && i < TcpNstates) {
if (TcpStX[i]) {
Lf->sf |= SELEXCLF;
return;
}
}
}
if (TcpStIn) {
/*
* Check for state inclusion.
*/
if (i >= 0 && i < TcpNstates) {
if (TcpStI[i])
TcpStI[i] = 2;
else {
Lf->sf |= SELEXCLF;
return;
}
}
}
if (Fnet && (FnetTy != 6))
Lf->sf |= SELNET;
#if defined(HASIPv6)
(void) snpf(Lf->type, sizeof(Lf->type), "IPv4");
#else /* !defined(HASIPv6) */
(void) snpf(Lf->type, sizeof(Lf->type), "inet");
#endif /* defined(HASIPv6) */
(void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, pr);
Lf->inp_ty = 2;
if (ss & SB_INO) {
(void) snpf(tbuf, sizeof(tbuf), InodeFmt_d,
(INODETYPE)s->st_ino);
tbuf[sizeof(tbuf) - 1] = '\0';
enter_dev_ch(tbuf);
}
if (tp->faddr || tp->fport) {
fs.s_addr = tp->faddr;
fa = (unsigned char *)&fs;
} else
fa = (unsigned char *)NULL;
if (tp->laddr || tp->lport) {
ls.s_addr = tp->laddr;
la = (unsigned char *)&ls;
} else
la = (unsigned char *)NULL;
ent_inaddr(la, tp->lport, fa, tp->fport, AF_INET);
Lf->lts.type = tp->proto;
Lf->lts.state.i = tp->state;
#if defined(HASTCPTPIQ)
Lf->lts.rq = tp->rxq;
Lf->lts.sq = tp->txq;
Lf->lts.rqs = Lf->lts.sqs = 1;
#endif /* defined(HASTCPTPIQ) */
return;
}
/*
* The socket's protocol can't be identified.
*/
(void) snpf(Lf->type, sizeof(Lf->type), "sock");
if (ss & SB_INO) {
Lf->inode = (INODETYPE)s->st_ino;
Lf->inp_ty = 1;
}
if (ss & SB_DEV) {
Lf->dev = s->st_dev;
Lf->dev_def = 1;
}
enter_nm(Fxopt ? "can't identify protocol (-X specified)"
: "can't identify protocol");
}
/*
* set_net_paths() - set /proc/net paths
*/
void
set_net_paths(p, pl)
char *p; /* path to /proc/net/ */
int pl; /* strlen(p) */
{
int pathl;
pathl = 0;
(void) make_proc_path(p, pl, &AX25path, &pathl, "ax25");
pathl = 0;
(void) make_proc_path(p, pl, &Ipxpath, &pathl, "ipx");
pathl = 0;
(void) make_proc_path(p, pl, &Nlkpath, &pathl, "netlink");
pathl = 0;
(void) make_proc_path(p, pl, &Packpath, &pathl, "packet");
pathl = 0;
(void) make_proc_path(p, pl, &Rawpath, &pathl, "raw");
pathl = 0;
(void) make_proc_path(p, pl, &SockStatPath, &pathl, "sockstat");
pathl = 0;
(void) make_proc_path(p, pl, &TCPpath, &pathl, "tcp");
pathl = 0;
(void) make_proc_path(p, pl, &UDPpath, &pathl, "udp");
pathl = 0;
(void) make_proc_path(p, pl, &UDPLITEpath, &pathl, "udplite");
#if defined(HASIPv6)
pathl = 0;
(void) make_proc_path(p, pl, &Raw6path, &pathl, "raw6");
pathl = 0;
(void) make_proc_path(p, pl, &SockStatPath6, &pathl, "sockstat6");
pathl = 0;
(void) make_proc_path(p, pl, &TCP6path, &pathl, "tcp6");
pathl = 0;
(void) make_proc_path(p, pl, &UDP6path, &pathl, "udp6");
pathl = 0;
(void) make_proc_path(p, pl, &UDPLITE6path, &pathl, "udplite6");
#endif /* defined(HASIPv6) */
pathl = 0;
(void) make_proc_path(p, pl, &UNIXpath, &pathl, "unix");
}