#include "SNAPSHOT.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;
const char *pattern = "socket:[";
unsigned int ino;
char lnk[64];
- int fd, n;
+ 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);
+
+ link_len = readlink(name, lnk, sizeof(lnk)-1);
+ if (link_len == -1)
+ continue;
+ lnk[link_len] = '\0';
+
if (strncmp(lnk, pattern, strlen(pattern)))
continue;
}
}
}
+ pclose(fp);
}
}
{
if (!(*bytecode=malloc(4))) abort();
((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 };
- return 8;
+ return 4;
}
case SSF_DCOND:
case SSF_SCOND:
printf(" sack");
if (info->tcpi_options & TCPI_OPT_ECN)
printf(" ecn");
+ if (info->tcpi_options & TCPI_OPT_ECN_SEEN)
+ printf(" ecnseen");
}
if (tb[INET_DIAG_CONG])
}
if (status == 0) {
fprintf(stderr, "EOF on netlink\n");
+ close(fd);
return 0;
}
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))) {
errno = -err->error;
perror("TCPDIAG answers");
}
+ close(fd);
return 0;
}
if (!dump_fp) {
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;
}
}
}
+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 (!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);
cnt = 0;
}
}
-
+ fclose(fp);
if (list) {
unix_list_print(list, f);
unix_list_free(list);
" -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"
);
{ "packet", 0, 0, '0' },
{ "family", 1, 0, 'f' },
{ "socket", 1, 0, 'A' },
+ { "query", 1, 0, 'A' },
{ "summary", 0, 0, 's' },
- { "diag", 0, 0, 'D' },
+ { "diag", 1, 0, 'D' },
{ "filter", 1, 0, 'F' },
{ "version", 0, 0, 'V' },
{ "help", 0, 0, 'h' },
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;