#include "libnetlink.h"
#include "SNAPSHOT.h"
-#include <asm/byteorder.h>
-#include <linux/tcp.h>
-#include <linux/tcp_diag.h>
+#include <netinet/tcp.h>
+#include <linux/sock_diag.h>
+#include <linux/inet_diag.h>
+#include <linux/unix_diag.h>
int resolve_hosts = 0;
int resolve_services = 1;
enum
{
TCP_DB,
+ DCCP_DB,
UDP_DB,
RAW_DB,
UNIX_DG_DB,
};
struct filter default_filter = {
- dbs: (1<<TCP_DB),
- states: SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
- families: (1<<AF_INET)|(1<<AF_INET6),
+ .dbs = (1<<TCP_DB),
+ .states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
+ .families= (1<<AF_INET)|(1<<AF_INET6),
};
struct filter current_filter;
-int generic_proc_open(char *env, char *name)
+static FILE *generic_proc_open(const char *env, const char *name)
{
+ const char *p = getenv(env);
char store[128];
- char *p = getenv(env);
+
if (!p) {
p = getenv("PROC_ROOT") ? : "/proc";
snprintf(store, sizeof(store)-1, "%s/%s", p, name);
p = store;
}
- return open(store, O_RDONLY);
+
+ return fopen(p, "r");
}
-int net_tcp_open(void)
+static FILE *net_tcp_open(void)
{
return generic_proc_open("PROC_NET_TCP", "net/tcp");
}
-int net_tcp6_open(void)
+static FILE *net_tcp6_open(void)
{
return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
}
-int net_udp_open(void)
+static FILE *net_udp_open(void)
{
return generic_proc_open("PROC_NET_UDP", "net/udp");
}
-int net_udp6_open(void)
+static FILE *net_udp6_open(void)
{
return generic_proc_open("PROC_NET_UDP6", "net/udp6");
}
-int net_raw_open(void)
+static FILE *net_raw_open(void)
{
return generic_proc_open("PROC_NET_RAW", "net/raw");
}
-int net_raw6_open(void)
+static FILE *net_raw6_open(void)
{
return generic_proc_open("PROC_NET_RAW6", "net/raw6");
}
-int net_unix_open(void)
+static FILE *net_unix_open(void)
{
return generic_proc_open("PROC_NET_UNIX", "net/unix");
}
-int net_packet_open(void)
+static FILE *net_packet_open(void)
{
return generic_proc_open("PROC_NET_PACKET", "net/packet");
}
-int net_netlink_open(void)
+static FILE *net_netlink_open(void)
{
return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
}
-int slabinfo_open(void)
+static FILE *slabinfo_open(void)
{
return generic_proc_open("PROC_SLABINFO", "slabinfo");
}
-int net_sockstat_open(void)
+static FILE *net_sockstat_open(void)
{
return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
}
-int net_sockstat6_open(void)
+static FILE *net_sockstat6_open(void)
{
return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
}
-int net_snmp_open(void)
+static FILE *net_snmp_open(void)
{
return generic_proc_open("PROC_NET_SNMP", "net/snmp");
}
-int net_netstat_open(void)
+static FILE *ephemeral_ports_open(void)
{
- return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
+ return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
}
-int ephemeral_ports_open(void)
+struct user_ent {
+ struct user_ent *next;
+ unsigned int ino;
+ int pid;
+ int fd;
+ char process[0];
+};
+
+#define USER_ENT_HASH_SIZE 256
+struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
+
+static int user_ent_hashfn(unsigned int ino)
{
- return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
+ int val = (ino >> 24) ^ (ino >> 16) ^ (ino >> 8) ^ ino;
+
+ return val & (USER_ENT_HASH_SIZE - 1);
}
-int find_users(int ino, char *buf, int buflen)
+static void user_ent_add(unsigned int ino, const char *process, int pid, int fd)
{
- char pattern[64];
- int pattern_len;
- char *ptr = buf;
- char name[1024];
- DIR *dir;
- struct dirent *d;
- int cnt = 0;
- int nameoff;
+ struct user_ent *p, **pp;
+ int str_len;
- if (!ino)
- return 0;
+ str_len = strlen(process) + 1;
+ p = malloc(sizeof(struct user_ent) + str_len);
+ if (!p)
+ abort();
+ p->next = NULL;
+ p->ino = ino;
+ p->pid = pid;
+ p->fd = fd;
+ strcpy(p->process, process);
+
+ pp = &user_ent_hash[user_ent_hashfn(ino)];
+ p->next = *pp;
+ *pp = p;
+}
- sprintf(pattern, "socket:[%d]", ino);
- pattern_len = strlen(pattern);
+static void user_ent_hash_build(void)
+{
+ const char *root = getenv("PROC_ROOT") ? : "/proc/";
+ struct dirent *d;
+ char name[1024];
+ int nameoff;
+ DIR *dir;
- strncpy(name, getenv("PROC_ROOT") ? : "/proc/", sizeof(name)/2);
- name[sizeof(name)/2] = 0;
- if (strlen(name) == 0 ||
- name[strlen(name)-1] != '/')
+ strcpy(name, root);
+ if (strlen(name) == 0 || name[strlen(name)-1] != '/')
strcat(name, "/");
+
nameoff = strlen(name);
- if ((dir = opendir(name)) == NULL)
- return 0;
+
+ dir = opendir(name);
+ if (!dir)
+ return;
while ((d = readdir(dir)) != NULL) {
- DIR *dir1;
struct dirent *d1;
- int pid;
- int pos;
- char crap;
char process[16];
+ int pid, pos;
+ DIR *dir1;
+ char crap;
if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
continue;
- sprintf(name+nameoff, "%d/fd/", pid);
+ sprintf(name + nameoff, "%d/fd/", pid);
pos = strlen(name);
if ((dir1 = opendir(name)) == NULL)
continue;
- process[0] = 0;
+ process[0] = '\0';
while ((d1 = readdir(dir1)) != NULL) {
- int fd, n;
+ const char *pattern = "socket:[";
+ unsigned int ino;
char lnk[64];
+ int fd;
+ ssize_t link_len;
if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
continue;
sprintf(name+pos, "%d", fd);
- n = readlink(name, lnk, sizeof(lnk)-1);
- if (n != pattern_len ||
- memcmp(lnk, pattern, n))
+
+ link_len = readlink(name, lnk, sizeof(lnk)-1);
+ if (link_len == -1)
continue;
+ lnk[link_len] = '\0';
- if (ptr-buf >= buflen-1)
- break;
+ if (strncmp(lnk, pattern, strlen(pattern)))
+ continue;
- if (process[0] == 0) {
+ sscanf(lnk, "socket:[%u]", &ino);
+
+ if (process[0] == '\0') {
char tmp[1024];
FILE *fp;
- snprintf(tmp, sizeof(tmp), "%s/%d/stat",
- getenv("PROC_ROOT") ? : "/proc", pid);
+
+ snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
if ((fp = fopen(tmp, "r")) != NULL) {
fscanf(fp, "%*d (%[^)])", process);
fclose(fp);
}
}
- snprintf(ptr, buflen-(ptr-buf), "(\"%s\",%d,%d),", process, pid, fd);
- ptr += strlen(ptr);
- cnt++;
+ user_ent_add(ino, process, pid, fd);
}
closedir(dir1);
}
closedir(dir);
+}
+
+int find_users(unsigned ino, char *buf, int buflen)
+{
+ struct user_ent *p;
+ int cnt = 0;
+ char *ptr;
+
+ if (!ino)
+ return 0;
+
+ p = user_ent_hash[user_ent_hashfn(ino)];
+ ptr = buf;
+ while (p) {
+ if (p->ino != ino)
+ goto next;
+
+ if (ptr - buf >= buflen - 1)
+ break;
+
+ snprintf(ptr, buflen - (ptr - buf),
+ "(\"%s\",%d,%d),",
+ p->process, p->pid, p->fd);
+ ptr += strlen(ptr);
+ cnt++;
+
+ next:
+ p = p->next;
+ }
+
if (ptr != buf)
- ptr[-1] = 0;
+ ptr[-1] = '\0';
+
return cnt;
}
-
/* Get stats from slab */
struct slabstat
struct slabstat slabstat;
-static const char *slabstat_ids[] =
+static const char *slabstat_ids[] =
{
"sock",
"tcp_bind_bucket",
memset(s, 0, sizeof(*s));
- if ((fp = fdopen(slabinfo_open(), "r")) == NULL)
+ fp = slabinfo_open();
+ if (!fp)
return -1;
cnt = sizeof(*s)/sizeof(int);
int timer;
int timeout;
int retrs;
- int ino;
+ unsigned ino;
int probes;
- int uid;
+ unsigned uid;
int refcnt;
unsigned long long sk;
int rto, ato, qack, cwnd, ssthresh;
if (msecs)
sprintf(buf+strlen(buf), "%03dms", msecs);
return buf;
-};
+}
const char *print_hz_timer(int timeout)
{
- int hz = get_hz();
+ int hz = get_user_hz();
return print_ms_timer(((timeout*1000) + hz-1)/hz);
-};
+}
struct scache
{
}
}
}
+ pclose(fp);
}
}
static int is_ephemeral(int port)
{
if (!ip_local_port_min) {
- FILE *f = fdopen(ephemeral_ports_open(), "r");
+ FILE *f = ephemeral_ports_open();
if (f) {
- fscanf(f, "%d %d",
+ fscanf(f, "%d %d",
&ip_local_port_min, &ip_local_port_max);
fclose(f);
} else {
if (!notfirst) {
setservent(1);
notfirst = 1;
- }
+ }
se = getservbyport(htons(port), dg_proto);
if (se)
return se->s_name;
const char *res;
int hash = (port^(((unsigned long)dg_proto)>>2))&255;
- for (c = &cache[hash]; c; c = c->next) {
+ for (c = &cache[hash]; c; c = c->next) {
if (c->port == port &&
c->proto == dg_proto) {
if (c->name)
char *p;
memcpy(&p, s->local.data, sizeof(p));
return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
- strspn(p+1, "0123456789abcdef") == 5);
+ strspn(p+1, "0123456789abcdef") == 5);
}
if (s->local.family == AF_PACKET)
return s->lport == 0 && s->local.data == 0;
return s->lport < 0;
if (!low) {
- FILE *fp = fdopen(ephemeral_ports_open(), "r");
+ FILE *fp = ephemeral_ports_open();
if (fp) {
fscanf(fp, "%d%d", &low, &high);
fclose(fp);
do {
if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen))
return 1;
- } while ((a = a->next) != NULL);
+ } while ((a = a->next) != NULL);
return 0;
}
return 1;
}
}
-/* Relocate external jumps by reloc. */
+/* Relocate external jumps by reloc. */
static void ssfilter_patch(char *a, int len, int reloc)
{
while (len > 0) {
- struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)a;
+ struct inet_diag_bc_op *op = (struct inet_diag_bc_op*)a;
if (op->no == len+4)
op->no += reloc;
len -= op->yes;
case SSF_S_AUTO:
{
if (!(*bytecode=malloc(4))) abort();
- ((struct tcpdiag_bc_op*)*bytecode)[0] = (struct tcpdiag_bc_op){ TCPDIAG_BC_AUTO, 4, 8 };
- return 8;
+ ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 };
+ return 4;
}
case SSF_DCOND:
case SSF_SCOND:
struct aafilter *a = (void*)f->pred;
struct aafilter *b;
char *ptr;
- int code = (f->type == SSF_DCOND ? TCPDIAG_BC_D_COND : TCPDIAG_BC_S_COND);
+ int code = (f->type == SSF_DCOND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND);
int len = 0;
for (b=a; b; b=b->next) {
- len += 4 + sizeof(struct tcpdiag_hostcond);
+ len += 4 + sizeof(struct inet_diag_hostcond);
if (a->addr.family == AF_INET6)
len += 16;
else
if (!(ptr = malloc(len))) abort();
*bytecode = ptr;
for (b=a; b; b=b->next) {
- struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op *)ptr;
+ struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr;
int alen = (a->addr.family == AF_INET6 ? 16 : 4);
- int oplen = alen + 4 + sizeof(struct tcpdiag_hostcond);
- struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(ptr+4);
+ int oplen = alen + 4 + sizeof(struct inet_diag_hostcond);
+ struct inet_diag_hostcond *cond = (struct inet_diag_hostcond*)(ptr+4);
- *op = (struct tcpdiag_bc_op){ code, oplen, oplen+4 };
+ *op = (struct inet_diag_bc_op){ code, oplen, oplen+4 };
cond->family = a->addr.family;
cond->port = a->port;
cond->prefix_len = a->addr.bitlen;
memcpy(cond->addr, a->addr.data, alen);
ptr += oplen;
if (b->next) {
- op = (struct tcpdiag_bc_op *)ptr;
- *op = (struct tcpdiag_bc_op){ TCPDIAG_BC_JMP, 4, len - (ptr-*bytecode)};
+ op = (struct inet_diag_bc_op *)ptr;
+ *op = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, len - (ptr-*bytecode)};
ptr += 4;
}
}
{
struct aafilter *x = (void*)f->pred;
if (!(*bytecode=malloc(8))) abort();
- ((struct tcpdiag_bc_op*)*bytecode)[0] = (struct tcpdiag_bc_op){ TCPDIAG_BC_D_GE, 8, 12 };
- ((struct tcpdiag_bc_op*)*bytecode)[1] = (struct tcpdiag_bc_op){ 0, 0, x->port };
+ ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 };
+ ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
return 8;
}
case SSF_D_LE:
{
struct aafilter *x = (void*)f->pred;
if (!(*bytecode=malloc(8))) abort();
- ((struct tcpdiag_bc_op*)*bytecode)[0] = (struct tcpdiag_bc_op){ TCPDIAG_BC_D_LE, 8, 12 };
- ((struct tcpdiag_bc_op*)*bytecode)[1] = (struct tcpdiag_bc_op){ 0, 0, x->port };
+ ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 };
+ ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
return 8;
}
case SSF_S_GE:
{
struct aafilter *x = (void*)f->pred;
if (!(*bytecode=malloc(8))) abort();
- ((struct tcpdiag_bc_op*)*bytecode)[0] = (struct tcpdiag_bc_op){ TCPDIAG_BC_S_GE, 8, 12 };
- ((struct tcpdiag_bc_op*)*bytecode)[1] = (struct tcpdiag_bc_op){ 0, 0, x->port };
+ ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 };
+ ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
return 8;
}
case SSF_S_LE:
{
struct aafilter *x = (void*)f->pred;
if (!(*bytecode=malloc(8))) abort();
- ((struct tcpdiag_bc_op*)*bytecode)[0] = (struct tcpdiag_bc_op){ TCPDIAG_BC_S_LE, 8, 12 };
- ((struct tcpdiag_bc_op*)*bytecode)[1] = (struct tcpdiag_bc_op){ 0, 0, x->port };
+ ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 };
+ ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
return 8;
}
memcpy(a, a1, l1);
memcpy(a+l1+4, a2, l2);
free(a1); free(a2);
- *(struct tcpdiag_bc_op*)(a+l1) = (struct tcpdiag_bc_op){ TCPDIAG_BC_JMP, 4, l2+4 };
+ *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 };
*bytecode = a;
return l1+l2+4;
}
if (!(a = malloc(l1+4))) abort();
memcpy(a, a1, l1);
free(a1);
- *(struct tcpdiag_bc_op*)(a+l1) = (struct tcpdiag_bc_op){ TCPDIAG_BC_JMP, 4, 8 };
+ *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
*bytecode = a;
return l1+4;
}
static int remember_he(struct aafilter *a, struct hostent *he)
{
- char **ptr = he->h_addr_list;
+ char **ptr = he->h_addr_list;
int cnt = 0;
int len;
return res;
}
-static int tcp_show_line(char *line, struct filter *f, int family)
+static int tcp_show_line(char *line, const struct filter *f, int family)
{
struct tcpstat s;
char *loc, *rem, *data;
char opt[256];
int n;
char *p;
-
+
if ((p = strchr(line, ':')) == NULL)
return -1;
loc = p+2;
-
+
if ((p = strchr(loc, ':')) == NULL)
return -1;
p[5] = 0;
rem = p+6;
-
+
if ((p = strchr(rem, ':')) == NULL)
return -1;
p[5] = 0;
data = p+6;
-
+
do {
int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
if (!(f->states & (1<<state)))
return 0;
} while (0);
-
+
s.local.family = s.remote.family = family;
if (family == AF_INET) {
sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
&s.rport);
s.local.bytelen = s.remote.bytelen = 16;
}
-
+
if (f->f && run_ssfilter(f->f, &s) == 0)
return 0;
-
+
opt[0] = 0;
- n = sscanf(data, "%x %x:%x %x:%x %x %d %d %d %d %llx %d %d %d %d %d %[^\n]\n",
+ n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
&s.state, &s.wq, &s.rq,
&s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino,
&s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack,
&s.cwnd, &s.ssthresh, opt);
-
+
if (n < 17)
opt[0] = 0;
-
+
if (n < 12) {
s.rto = 0;
s.cwnd = 2;
s.ssthresh = -1;
s.ato = s.qack = 0;
}
-
+
if (netid_width)
printf("%-*s ", netid_width, "tcp");
if (state_width)
printf("%-*s ", state_width, sstate_name[s.state]);
-
+
printf("%-6d %-6d ", s.rq, s.wq);
-
+
formatted_print(&s.local, s.lport);
formatted_print(&s.remote, s.rport);
-
+
if (show_options) {
if (s.timer) {
if (s.timer > 4)
}
}
if (show_tcpinfo) {
- if (s.rto && s.rto != 3*get_hz())
- printf(" rto:%g", (double)s.rto/get_hz());
+ int hz = get_user_hz();
+ if (s.rto && s.rto != 3*hz)
+ printf(" rto:%g", (double)s.rto/hz);
if (s.ato)
- printf(" ato:%g", (double)s.ato/get_hz());
+ printf(" ato:%g", (double)s.ato/hz);
if (s.cwnd != 2)
printf(" cwnd:%d", s.cwnd);
if (s.ssthresh != -1)
if (show_details) {
if (s.uid)
printf(" uid:%u", (unsigned)s.uid);
- printf(" ino:%u", (unsigned)s.ino);
+ printf(" ino:%u", s.ino);
printf(" sk:%llx", s.sk);
if (opt[0])
printf(" opt:\"%s\"", opt);
return 0;
}
-static int generic_record_read(int fd, char *buf, int bufsize,
- int (*worker)(char*, struct filter *, int),
- struct filter *f, int fam)
+static int generic_record_read(FILE *fp,
+ int (*worker)(char*, const struct filter *, int),
+ const struct filter *f, int fam)
{
- int n;
- int recsize;
- int eof = 0;
- char *p;
+ char line[256];
- /* Load the first chunk and calculate record length from it. */
- n = read(fd, buf, bufsize);
- if (n < 0)
+ /* skip header */
+ if (fgets(line, sizeof(line), fp) == NULL)
goto outerr;
- /* I _know_ that this is wrong, do not remind. :-)
- * But this works nowadays. */
- if (n < bufsize)
- eof = 1;
- p = memchr(buf, '\n', n);
- if (p == NULL || (p-buf) >= n)
- goto outwrongformat;
- recsize = (p-buf)+1;
- p = buf+recsize;
-
- for (;;) {
- while ((p+recsize) - buf <= n) {
- if (p[recsize-1] != '\n')
- goto outwrongformat;
- p[recsize-1] = 0;
- if (worker(p, f, fam) < 0)
- goto done;
- p += recsize;
- }
- if (!eof) {
- int remains = (buf+bufsize) - p;
- memcpy(buf, p, remains);
- p = buf+remains;
- n = read(fd, p, (buf+bufsize) - p);
- if (n < 0)
- goto outerr;
- if (n < (buf+bufsize) - p) {
- eof = 1;
- if (n == 0) {
- if (remains)
- goto outwrongformat;
- goto done;
- }
- }
- n += remains;
- p = buf;
- } else {
- if (p != buf+n)
- goto outwrongformat;
- goto done;
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ int n = strlen(line);
+ if (n == 0 || line[n-1] != '\n') {
+ errno = -EINVAL;
+ return -1;
}
- }
-done:
- return 0;
+ line[n-1] = 0;
-outwrongformat:
- errno = EINVAL;
+ if (worker(line, f, fam) < 0)
+ return 0;
+ }
outerr:
- return -1;
+
+ return ferror(fp) ? -1 : 0;
}
-
+
static char *sprint_bw(char *buf, double bw)
{
- if (bw > 1000000.)
+ if (bw > 1000000.)
sprintf(buf,"%.1fM", bw / 1000000.);
else if (bw > 1000.)
sprintf(buf,"%.1fK", bw / 1000.);
return buf;
}
-static void tcp_show_info(const struct nlmsghdr *nlh, struct tcpdiagmsg *r)
+static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r)
{
- struct rtattr * tb[TCPDIAG_MAX+1];
+ struct rtattr * tb[INET_DIAG_MAX+1];
char b1[64];
double rtt = 0;
- memset(tb, 0, sizeof(tb));
- parse_rtattr(tb, TCPDIAG_MAX, (struct rtattr*)(r+1),
+ parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
- if (tb[TCPDIAG_MEMINFO]) {
- const struct tcpdiag_meminfo *minfo
- = RTA_DATA(tb[TCPDIAG_MEMINFO]);
+ if (tb[INET_DIAG_SKMEMINFO]) {
+ const __u32 *skmeminfo = RTA_DATA(tb[INET_DIAG_SKMEMINFO]);
+ printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u)",
+ skmeminfo[SK_MEMINFO_RMEM_ALLOC],
+ skmeminfo[SK_MEMINFO_RCVBUF],
+ skmeminfo[SK_MEMINFO_WMEM_ALLOC],
+ skmeminfo[SK_MEMINFO_SNDBUF],
+ skmeminfo[SK_MEMINFO_FWD_ALLOC],
+ skmeminfo[SK_MEMINFO_WMEM_QUEUED],
+ skmeminfo[SK_MEMINFO_OPTMEM]);
+ }else if (tb[INET_DIAG_MEMINFO]) {
+ const struct inet_diag_meminfo *minfo
+ = RTA_DATA(tb[INET_DIAG_MEMINFO]);
printf(" mem:(r%u,w%u,f%u,t%u)",
- minfo->tcpdiag_rmem,
- minfo->tcpdiag_wmem,
- minfo->tcpdiag_fmem,
- minfo->tcpdiag_tmem);
+ minfo->idiag_rmem,
+ minfo->idiag_wmem,
+ minfo->idiag_fmem,
+ minfo->idiag_tmem);
}
- if (tb[TCPDIAG_INFO]) {
+ if (tb[INET_DIAG_INFO]) {
struct tcp_info *info;
- int len = RTA_PAYLOAD(tb[TCPDIAG_INFO]);
+ int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
/* workaround for older kernels with less fields */
if (len < sizeof(*info)) {
info = alloca(sizeof(*info));
memset(info, 0, sizeof(*info));
- memcpy(info, RTA_DATA(tb[TCPDIAG_INFO]), len);
+ memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
} else
- info = RTA_DATA(tb[TCPDIAG_INFO]);
+ info = RTA_DATA(tb[INET_DIAG_INFO]);
if (show_options) {
if (info->tcpi_options & TCPI_OPT_TIMESTAMPS)
printf(" sack");
if (info->tcpi_options & TCPI_OPT_ECN)
printf(" ecn");
+ if (info->tcpi_options & TCPI_OPT_ECN_SEEN)
+ printf(" ecnseen");
}
- if (info->tcpi_options & TCPI_OPT_WSCALE)
+
+ if (tb[INET_DIAG_CONG])
+ printf(" %s", rta_getattr_str(tb[INET_DIAG_CONG]));
+
+ if (info->tcpi_options & TCPI_OPT_WSCALE)
printf(" wscale:%d,%d", info->tcpi_snd_wscale,
info->tcpi_rcv_wscale);
if (info->tcpi_rto && info->tcpi_rto != 3000000)
printf(" cwnd:%d", info->tcpi_snd_cwnd);
if (info->tcpi_snd_ssthresh < 0xFFFF)
printf(" ssthresh:%d", info->tcpi_snd_ssthresh);
-
+
rtt = (double) info->tcpi_rtt;
- if (tb[TCPDIAG_VEGASINFO]) {
+ if (tb[INET_DIAG_VEGASINFO]) {
const struct tcpvegas_info *vinfo
- = RTA_DATA(tb[TCPDIAG_VEGASINFO]);
+ = RTA_DATA(tb[INET_DIAG_VEGASINFO]);
- if (vinfo->tcpv_enabled)
- printf(" vegas");
-
- if (vinfo->tcpv_rtt &&
- vinfo->tcpv_rtt != 0x7fffffff)
- rtt = vinfo->tcpv_rtt;
+ if (vinfo->tcpv_enabled &&
+ vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
+ rtt = vinfo->tcpv_rtt;
}
if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
}
}
-int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
+static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
{
- struct tcpdiagmsg *r = NLMSG_DATA(nlh);
+ struct inet_diag_msg *r = NLMSG_DATA(nlh);
struct tcpstat s;
- s.state = r->tcpdiag_state;
- s.local.family = s.remote.family = r->tcpdiag_family;
- s.lport = ntohs(r->id.tcpdiag_sport);
- s.rport = ntohs(r->id.tcpdiag_dport);
+ s.state = r->idiag_state;
+ s.local.family = s.remote.family = r->idiag_family;
+ s.lport = ntohs(r->id.idiag_sport);
+ s.rport = ntohs(r->id.idiag_dport);
if (s.local.family == AF_INET) {
s.local.bytelen = s.remote.bytelen = 4;
} else {
s.local.bytelen = s.remote.bytelen = 16;
}
- memcpy(s.local.data, r->id.tcpdiag_src, s.local.bytelen);
- memcpy(s.remote.data, r->id.tcpdiag_dst, s.local.bytelen);
+ memcpy(s.local.data, r->id.idiag_src, s.local.bytelen);
+ memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen);
if (f && f->f && run_ssfilter(f->f, &s) == 0)
return 0;
if (state_width)
printf("%-*s ", state_width, sstate_name[s.state]);
- printf("%-6d %-6d ", r->tcpdiag_rqueue, r->tcpdiag_wqueue);
+ printf("%-6d %-6d ", r->idiag_rqueue, r->idiag_wqueue);
formatted_print(&s.local, s.lport);
formatted_print(&s.remote, s.rport);
if (show_options) {
- if (r->tcpdiag_timer) {
- if (r->tcpdiag_timer > 4)
- r->tcpdiag_timer = 5;
+ if (r->idiag_timer) {
+ if (r->idiag_timer > 4)
+ r->idiag_timer = 5;
printf(" timer:(%s,%s,%d)",
- tmr_name[r->tcpdiag_timer],
- print_ms_timer(r->tcpdiag_expires),
- r->tcpdiag_retrans);
+ tmr_name[r->idiag_timer],
+ print_ms_timer(r->idiag_expires),
+ r->idiag_retrans);
}
}
if (show_users) {
char ubuf[4096];
- if (find_users(r->tcpdiag_inode, ubuf, sizeof(ubuf)) > 0)
+ if (find_users(r->idiag_inode, ubuf, sizeof(ubuf)) > 0)
printf(" users:(%s)", ubuf);
}
if (show_details) {
- if (r->tcpdiag_uid)
- printf(" uid:%u", (unsigned)r->tcpdiag_uid);
- printf(" ino:%u", (unsigned)r->tcpdiag_inode);
- printf(" sk:%08x", r->id.tcpdiag_cookie[0]);
- if (r->id.tcpdiag_cookie[1] != 0)
- printf("%08x", r->id.tcpdiag_cookie[1]);
+ if (r->idiag_uid)
+ printf(" uid:%u", (unsigned)r->idiag_uid);
+ printf(" ino:%u", r->idiag_inode);
+ printf(" sk:");
+ if (r->id.idiag_cookie[1] != 0)
+ printf("%08x", r->id.idiag_cookie[1]);
+ printf("%08x", r->id.idiag_cookie[0]);
}
if (show_mem || show_tcpinfo) {
printf("\n\t");
printf("\n");
return 0;
-
}
-int tcp_show_netlink(struct filter *f, FILE *dump_fp)
+static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
{
int fd;
struct sockaddr_nl nladdr;
struct {
struct nlmsghdr nlh;
- struct tcpdiagreq r;
+ struct inet_diag_req r;
} req;
char *bc = NULL;
int bclen;
char buf[8192];
struct iovec iov[3];
- if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TCPDIAG)) < 0)
+ if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
return -1;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
req.nlh.nlmsg_len = sizeof(req);
- req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
+ req.nlh.nlmsg_type = socktype;
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = 123456;
memset(&req.r, 0, sizeof(req.r));
- req.r.tcpdiag_family = AF_INET;
- req.r.tcpdiag_states = f->states;
- if (show_mem)
- req.r.tcpdiag_ext |= (1<<(TCPDIAG_MEMINFO-1));
+ req.r.idiag_family = AF_INET;
+ req.r.idiag_states = f->states;
+ if (show_mem) {
+ req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
+ req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
+ }
if (show_tcpinfo) {
- req.r.tcpdiag_ext |= (1<<(TCPDIAG_INFO-1));
- req.r.tcpdiag_ext |= (1<<(TCPDIAG_VEGASINFO-1));
+ req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
+ req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
+ req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
}
- iov[0] = (struct iovec){ &req, sizeof(req) };
+ iov[0] = (struct iovec){
+ .iov_base = &req,
+ .iov_len = sizeof(req)
+ };
if (f->f) {
bclen = ssfilter_bytecompile(f->f, &bc);
- rta.rta_type = TCPDIAG_REQ_BYTECODE;
+ rta.rta_type = INET_DIAG_REQ_BYTECODE;
rta.rta_len = RTA_LENGTH(bclen);
iov[1] = (struct iovec){ &rta, sizeof(rta) };
iov[2] = (struct iovec){ bc, bclen };
}
msg = (struct msghdr) {
- (void*)&nladdr, sizeof(nladdr),
- iov, f->f ? 3 : 1,
- NULL, 0,
- 0
+ .msg_name = (void*)&nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = iov,
+ .msg_iovlen = f->f ? 3 : 1,
};
- if (sendmsg(fd, &msg, 0) < 0)
+ if (sendmsg(fd, &msg, 0) < 0) {
+ close(fd);
return -1;
+ }
-
- iov[0] = (struct iovec){ buf, sizeof(buf) };
+ iov[0] = (struct iovec){
+ .iov_base = buf,
+ .iov_len = sizeof(buf)
+ };
while (1) {
int status;
}
if (status == 0) {
fprintf(stderr, "EOF on netlink\n");
+ close(fd);
return 0;
}
h = (struct nlmsghdr*)buf;
while (NLMSG_OK(h, status)) {
int err;
+ struct inet_diag_msg *r = NLMSG_DATA(h);
if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
h->nlmsg_seq != 123456)
goto skip_it;
- if (h->nlmsg_type == NLMSG_DONE)
+ if (h->nlmsg_type == NLMSG_DONE) {
+ close(fd);
return 0;
+ }
if (h->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
fprintf(stderr, "ERROR truncated\n");
} else {
errno = -err->error;
+ if (errno == EOPNOTSUPP) {
+ close(fd);
+ return -1;
+ }
perror("TCPDIAG answers");
}
+ close(fd);
return 0;
}
if (!dump_fp) {
+ if (!(f->families & (1<<r->idiag_family))) {
+ h = NLMSG_NEXT(h, status);
+ continue;
+ }
err = tcp_show_sock(h, NULL);
- if (err < 0)
+ if (err < 0) {
+ close(fd);
return err;
+ }
}
skip_it:
exit(1);
}
}
+ close(fd);
return 0;
}
-int tcp_show_netlink_file(struct filter *f)
+static int tcp_show_netlink_file(struct filter *f)
{
FILE *fp;
char buf[8192];
}
}
-int tcp_show(struct filter *f)
+static int tcp_show(struct filter *f, int socktype)
{
- int fd = -1;
+ FILE *fp = NULL;
char *buf = NULL;
int bufsize = 64*1024;
return tcp_show_netlink_file(f);
if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
- && tcp_show_netlink(f, NULL) == 0)
+ && tcp_show_netlink(f, NULL, socktype) == 0)
return 0;
/* Sigh... We have to parse /proc/net/tcp... */
+
/* Estimate amount of sockets and try to allocate
* huge buffer to read all the table at one read.
* Limit it by 16MB though. The assumption is: as soon as
}
if (f->families & (1<<AF_INET)) {
- if ((fd = net_tcp_open()) < 0)
+ if ((fp = net_tcp_open()) == NULL)
goto outerr;
- if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET))
+
+ setbuffer(fp, buf, bufsize);
+ if (generic_record_read(fp, tcp_show_line, f, AF_INET))
goto outerr;
- close(fd);
+ fclose(fp);
}
if ((f->families & (1<<AF_INET6)) &&
- (fd = net_tcp6_open()) >= 0) {
- if (generic_record_read(fd, buf, bufsize, tcp_show_line, f, AF_INET6))
+ (fp = net_tcp6_open()) != NULL) {
+ setbuffer(fp, buf, bufsize);
+ if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
goto outerr;
- close(fd);
+ fclose(fp);
}
free(buf);
int saved_errno = errno;
if (buf)
free(buf);
- if (fd >= 0)
- close(fd);
+ if (fp)
+ fclose(fp);
errno = saved_errno;
return -1;
} while (0);
}
-int dgram_show_line(char *line, struct filter *f, int family)
+int dgram_show_line(char *line, const struct filter *f, int family)
{
struct tcpstat s;
char *loc, *rem, *data;
return 0;
opt[0] = 0;
- n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %d %d %llx %[^\n]\n",
+ n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
&s.state, &s.wq, &s.rq,
&s.uid, &s.ino,
&s.refcnt, &s.sk, opt);
if (show_details) {
if (s.uid)
printf(" uid=%u", (unsigned)s.uid);
- printf(" ino=%u", (unsigned)s.ino);
+ printf(" ino=%u", s.ino);
printf(" sk=%llx", s.sk);
if (opt[0])
printf(" opt:\"%s\"", opt);
int udp_show(struct filter *f)
{
- int fd = -1;
- char buf[8192];
- int bufsize = sizeof(buf);
+ FILE *fp = NULL;
dg_proto = UDP_PROTO;
if (f->families&(1<<AF_INET)) {
- if ((fd = net_udp_open()) < 0)
+ if ((fp = net_udp_open()) == NULL)
goto outerr;
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET))
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET))
goto outerr;
- close(fd);
+ fclose(fp);
}
if ((f->families&(1<<AF_INET6)) &&
- (fd = net_udp6_open()) >= 0) {
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6))
+ (fp = net_udp6_open()) != NULL) {
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
goto outerr;
- close(fd);
+ fclose(fp);
}
return 0;
outerr:
do {
int saved_errno = errno;
- if (fd >= 0)
- close(fd);
+ if (fp)
+ fclose(fp);
errno = saved_errno;
return -1;
} while (0);
int raw_show(struct filter *f)
{
- int fd = -1;
- char buf[8192];
- int bufsize = sizeof(buf);
+ FILE *fp = NULL;
dg_proto = RAW_PROTO;
if (f->families&(1<<AF_INET)) {
- if ((fd = net_raw_open()) < 0)
+ if ((fp = net_raw_open()) == NULL)
goto outerr;
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET))
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET))
goto outerr;
- close(fd);
+ fclose(fp);
}
if ((f->families&(1<<AF_INET6)) &&
- (fd = net_raw6_open()) >= 0) {
- if (generic_record_read(fd, buf, bufsize, dgram_show_line, f, AF_INET6))
+ (fp = net_raw6_open()) != NULL) {
+ if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
goto outerr;
- close(fd);
+ fclose(fp);
}
return 0;
outerr:
do {
int saved_errno = errno;
- if (fd >= 0)
- close(fd);
+ if (fp)
+ fclose(fp);
errno = saved_errno;
return -1;
} while (0);
if (strcmp(peer, "*") == 0)
memset(tst.remote.data, 0, sizeof(peer));
else
- memcpy(tst.remote.data, &peer, sizeof(peer));
+ memcpy(tst.remote.data, &peer, sizeof(peer));
if (run_ssfilter(f->f, &tst) == 0)
continue;
}
if (netid_width)
- printf("%-*s ", netid_width,
+ printf("%-*s ", netid_width,
s->type == SOCK_STREAM ? "u_str" : "u_dgr");
if (state_width)
printf("%-*s ", state_width, sstate_name[s->state]);
}
}
+static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)
+{
+ struct unix_diag_msg *r = NLMSG_DATA(nlh);
+ struct rtattr *tb[UNIX_DIAG_MAX+1];
+ char name[128];
+ int peer_ino;
+ int rqlen;
+
+ parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
+ nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+ if (netid_width)
+ printf("%-*s ", netid_width,
+ r->udiag_type == SOCK_STREAM ? "u_str" : "u_dgr");
+ if (state_width)
+ printf("%-*s ", state_width, sstate_name[r->udiag_state]);
+
+ if (tb[UNIX_DIAG_RQLEN])
+ rqlen = *(int *)RTA_DATA(tb[UNIX_DIAG_RQLEN]);
+ else
+ rqlen = 0;
+
+ printf("%-6d %-6d ", rqlen, 0);
+
+ if (tb[UNIX_DIAG_NAME]) {
+ int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
+
+ memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
+ name[len] = '\0';
+ if (name[0] == '\0')
+ name[0] = '@';
+ } else
+ sprintf(name, "*");
+
+ if (tb[UNIX_DIAG_PEER])
+ peer_ino = *(int *)RTA_DATA(tb[UNIX_DIAG_PEER]);
+ else
+ peer_ino = 0;
+
+ printf("%*s %-*d %*s %-*d",
+ addr_width, name,
+ serv_width, r->udiag_ino,
+ addr_width, "*", /* FIXME */
+ serv_width, peer_ino);
+
+ if (show_users) {
+ char ubuf[4096];
+ if (find_users(r->udiag_ino, ubuf, sizeof(ubuf)) > 0)
+ printf(" users:(%s)", ubuf);
+ }
+
+ printf("\n");
+
+ return 0;
+}
+
+static int unix_show_netlink(struct filter *f, FILE *dump_fp)
+{
+ int fd;
+ struct {
+ struct nlmsghdr nlh;
+ struct unix_diag_req r;
+ } req;
+ char buf[8192];
+
+ if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
+ return -1;
+
+ memset(&req, 0, sizeof(req));
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+ req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ req.nlh.nlmsg_seq = 123456;
+
+ req.r.sdiag_family = AF_UNIX;
+ req.r.udiag_states = f->states;
+ req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
+
+ if (send(fd, &req, sizeof(req), 0) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ while (1) {
+ ssize_t status;
+ struct nlmsghdr *h;
+ struct sockaddr_nl nladdr;
+ socklen_t slen = sizeof(nladdr);
+
+ status = recvfrom(fd, buf, sizeof(buf), 0,
+ (struct sockaddr *) &nladdr, &slen);
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("OVERRUN");
+ continue;
+ }
+ if (status == 0) {
+ fprintf(stderr, "EOF on netlink\n");
+ goto close_it;
+ }
+
+ if (dump_fp)
+ fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
+
+ h = (struct nlmsghdr*)buf;
+ while (NLMSG_OK(h, status)) {
+ int err;
+
+ if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
+ h->nlmsg_seq != 123456)
+ goto skip_it;
+
+ if (h->nlmsg_type == NLMSG_DONE)
+ goto close_it;
+
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+ if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ fprintf(stderr, "ERROR truncated\n");
+ } else {
+ errno = -err->error;
+ if (errno != ENOENT)
+ fprintf(stderr, "UDIAG answers %d\n", errno);
+ }
+ close(fd);
+ return -1;
+ }
+ if (!dump_fp) {
+ err = unix_show_sock(h, f);
+ if (err < 0) {
+ close(fd);
+ return err;
+ }
+ }
+
+skip_it:
+ h = NLMSG_NEXT(h, status);
+ }
+
+ if (status) {
+ fprintf(stderr, "!!!Remnant of size %zd\n", status);
+ exit(1);
+ }
+ }
+
+close_it:
+ close(fd);
+ return 0;
+}
+
int unix_show(struct filter *f)
{
FILE *fp;
int cnt;
struct unixstat *list = NULL;
- if ((fp = fdopen(net_unix_open(), "r")) == NULL)
+ if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
+ && unix_show_netlink(f, NULL) == 0)
+ return 0;
+
+ if ((fp = net_unix_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
- if (memcmp(buf, "Peer", 4) == 0)
+ if (memcmp(buf, "Peer", 4) == 0)
newformat = 1;
cnt = 0;
cnt = 0;
}
}
-
+ fclose(fp);
if (list) {
unix_list_print(list, f);
unix_list_free(list);
if (!(f->states & (1<<SS_CLOSE)))
return 0;
- if ((fp = fdopen(net_packet_open(), "r")) == NULL)
+ if ((fp = net_packet_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
}
if (netid_width)
- printf("%-*s ", netid_width,
+ printf("%-*s ", netid_width,
type == SOCK_RAW ? "p_raw" : "p_dgr");
if (state_width)
printf("%-*s ", state_width, "UNCONN");
printf("%*s:", addr_width, "*");
} else {
char tb[16];
- printf("%*s:", addr_width,
+ printf("%*s:", addr_width,
ll_proto_n2a(htons(prot), tb, sizeof(tb)));
}
if (iface == 0) {
if (!(f->states & (1<<SS_CLOSE)))
return 0;
- if ((fp = fdopen(net_netlink_open(), "r")) == NULL)
+ if ((fp = net_netlink_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
}
if (netid_width)
- printf("%-*s ", netid_width, "nl");
+ printf("%-*s ", netid_width, "nl");
if (state_width)
printf("%-*s ", state_width, "UNCONN");
printf("%-6d %-6d ", rq, wq);
getenv("PROC_ROOT") ? : "/proc", pid);
if ((fp = fopen(procname, "r")) != NULL) {
if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
- sprintf(procname+strlen(procname), "/%d", pid);
+ sprintf(procname+strlen(procname), "/%d", pid);
printf("%-*s ", serv_width, procname);
done = 1;
}
*result = 0;
- if ((fp = fdopen(net_snmp_open(), "r")) == NULL)
+ if ((fp = net_snmp_open()) == NULL)
return -1;
while (fgets(buf, sizeof(buf), fp) != NULL) {
memset(s, 0, sizeof(*s));
- if ((fp = fdopen(net_sockstat_open(), "r")) == NULL)
+ if ((fp = net_sockstat_open()) == NULL)
return -1;
while(fgets(buf, sizeof(buf), fp) != NULL)
get_sockstat_line(buf, s);
fclose(fp);
- if ((fp = fdopen(net_sockstat6_open(), "r")) == NULL)
+ if ((fp = net_sockstat6_open()) == NULL)
return 0;
while(fgets(buf, sizeof(buf), fp) != NULL)
get_sockstat_line(buf, s);
printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
- printf("INET %-9d %-9d %-9d\n",
+ printf("INET %-9d %-9d %-9d\n",
s.raw4+s.udp4+s.tcp4_hashed+
s.raw6+s.udp6+s.tcp6_hashed,
s.raw4+s.udp4+s.tcp4_hashed,
return 0;
}
-
-static void usage(void) __attribute__((noreturn));
-
-static void usage(void)
+static void _usage(FILE *dest)
{
- fprintf(stderr,
+ fprintf(dest,
"Usage: ss [ OPTIONS ]\n"
" ss [ OPTIONS ] [ FILTER ]\n"
" -h, --help this message\n"
" -0, --packet display PACKET sockets\n"
" -t, --tcp display only TCP sockets\n"
" -u, --udp display only UDP sockets\n"
+" -d, --dccp display only DCCP sockets\n"
" -w, --raw display only RAW sockets\n"
" -x, --unix display only Unix domain sockets\n"
" -f, --family=FAMILY display sockets of type FAMILY\n"
"\n"
-" -A, --query=QUERY\n"
+" -A, --query=QUERY, --socket=QUERY\n"
" QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]\n"
"\n"
+" -D, --diag=FILE Dump raw information about TCP sockets to FILE\n"
" -F, --filter=FILE read filter information from FILE\n"
" FILTER := [ state TCP-STATE ] [ EXPRESSION ]\n"
);
+}
+
+static void help(void) __attribute__((noreturn));
+static void help(void)
+{
+ _usage(stdout);
+ exit(0);
+}
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ _usage(stderr);
exit(-1);
}
{ "memory", 0, 0, 'm' },
{ "info", 0, 0, 'i' },
{ "processes", 0, 0, 'p' },
+ { "dccp", 0, 0, 'd' },
{ "tcp", 0, 0, 't' },
{ "udp", 0, 0, 'u' },
{ "raw", 0, 0, 'w' },
{ "packet", 0, 0, '0' },
{ "family", 1, 0, 'f' },
{ "socket", 1, 0, 'A' },
- { "summaary", 0, 0, 's' },
- { "diag", 0, 0, 'D' },
+ { "query", 1, 0, 'A' },
+ { "summary", 0, 0, 's' },
+ { "diag", 1, 0, 'D' },
{ "filter", 1, 0, 'F' },
{ "version", 0, 0, 'V' },
{ "help", 0, 0, 'h' },
{ 0 }
-
+
};
int main(int argc, char *argv[])
current_filter.states = default_filter.states;
- while ((ch = getopt_long(argc, argv, "haletuwxnro460spf:miA:D:F:vV",
+ while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spf:miA:D:F:vV",
long_opts, NULL)) != EOF) {
switch(ch) {
case 'n':
break;
case 'p':
show_users++;
+ user_ent_hash_build();
+ break;
+ case 'd':
+ current_filter.dbs |= (1<<DCCP_DB);
+ do_default = 0;
break;
case 't':
current_filter.dbs |= (1<<TCP_DB);
current_filter.states = SS_ALL;
break;
case 'l':
- current_filter.states = (1<<SS_LISTEN);
+ current_filter.states = (1<<SS_LISTEN) | (1<<SS_CLOSE);
break;
case '4':
preferred_family = AF_INET;
else if (strcmp(optarg, "netlink") == 0)
preferred_family = AF_NETLINK;
else if (strcmp(optarg, "help") == 0)
- usage();
+ help();
else {
fprintf(stderr, "ss: \"%s\" is invalid family\n", optarg);
usage();
p = p1 = optarg;
do {
if ((p1 = strchr(p, ',')) != NULL)
- *p1 = 0;
+ *p1 = 0;
if (strcmp(p, "all") == 0) {
current_filter.dbs = ALL_DB;
} else if (strcmp(p, "inet") == 0) {
- current_filter.dbs |= (1<<TCP_DB)|(1<<UDP_DB)|(1<<RAW_DB);
+ current_filter.dbs |= (1<<TCP_DB)|(1<<DCCP_DB)|(1<<UDP_DB)|(1<<RAW_DB);
} else if (strcmp(p, "udp") == 0) {
current_filter.dbs |= (1<<UDP_DB);
+ } else if (strcmp(p, "dccp") == 0) {
+ current_filter.dbs |= (1<<DCCP_DB);
} else if (strcmp(p, "tcp") == 0) {
current_filter.dbs |= (1<<TCP_DB);
} else if (strcmp(p, "raw") == 0) {
exit(0);
case 'h':
case '?':
+ help();
default:
usage();
}
int mask2;
if (preferred_family == AF_INET ||
preferred_family == AF_INET6) {
- mask2= (1<<TCP_DB);
- if (!do_default)
- mask2 = (1<<UDP_DB)|(1<<RAW_DB);
+ mask2= current_filter.dbs;
} else if (preferred_family == AF_PACKET) {
mask2 = PACKET_DBM;
} else if (preferred_family == AF_UNIX) {
}
if (resolve_services && resolve_hosts &&
- (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB))))
+ (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
init_service_resolver();
/* Now parse filter... */
exit(-1);
}
}
- tcp_show_netlink(¤t_filter, dump_fp);
+ tcp_show_netlink(¤t_filter, dump_fp, TCPDIAG_GETSOCK);
fflush(dump_fp);
exit(0);
}
if (addrp_width < 15+serv_width+1)
addrp_width = 15+serv_width+1;
- addr_width = addrp_width - serv_width - 1;
+ addr_width = addrp_width - serv_width - 1;
if (netid_width)
printf("%-*s ", netid_width, "Netid");
addr_width, "Local Address", serv_width, "Port",
addr_width, "Peer Address", serv_width, "Port");
-//printf("%08x %08x %08x\n", current_filter.dbs, current_filter.states, current_filter.families);
fflush(stdout);
if (current_filter.dbs & (1<<NETLINK_DB))
if (current_filter.dbs & (1<<UDP_DB))
udp_show(¤t_filter);
if (current_filter.dbs & (1<<TCP_DB))
- tcp_show(¤t_filter);
+ tcp_show(¤t_filter, TCPDIAG_GETSOCK);
+ if (current_filter.dbs & (1<<DCCP_DB))
+ tcp_show(¤t_filter, DCCPDIAG_GETSOCK);
return 0;
}