#include <linux/sock_diag.h>
#include <linux/inet_diag.h>
#include <linux/unix_diag.h>
+#include <linux/netdevice.h> /* for MAX_ADDR_LEN */
+#include <linux/filter.h>
+#include <linux/packet_diag.h>
int resolve_hosts = 0;
int resolve_services = 1;
int show_users = 0;
int show_mem = 0;
int show_tcpinfo = 0;
+int show_bpf = 0;
int netid_width;
int state_width;
return 0;
}
+static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f)
+{
+ struct packet_diag_msg *r = NLMSG_DATA(nlh);
+ struct rtattr *tb[PACKET_DIAG_MAX+1];
+ __u32 rq;
+
+ parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
+ nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+ /* use /proc/net/packet if all info are not available */
+ if (!tb[PACKET_DIAG_MEMINFO])
+ return -1;
+
+ if (netid_width)
+ printf("%-*s ", netid_width,
+ r->pdiag_type == SOCK_RAW ? "p_raw" : "p_dgr");
+ if (state_width)
+ printf("%-*s ", state_width, "UNCONN");
+
+ if (tb[PACKET_DIAG_MEMINFO]) {
+ __u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
+
+ rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
+ } else
+ rq = 0;
+ printf("%-6d %-6d ", rq, 0);
+
+ if (r->pdiag_num == 3) {
+ printf("%*s:", addr_width, "*");
+ } else {
+ char tb2[16];
+ printf("%*s:", addr_width,
+ ll_proto_n2a(htons(r->pdiag_num), tb2, sizeof(tb2)));
+ }
+ if (tb[PACKET_DIAG_INFO]) {
+ struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
+
+ if (pinfo->pdi_index == 0)
+ printf("%-*s ", serv_width, "*");
+ else
+ printf("%-*s ", serv_width, xll_index_to_name(pinfo->pdi_index));
+ } else
+ printf("%-*s ", serv_width, "*");
+
+ printf("%*s*%-*s",
+ addr_width, "", serv_width, "");
+
+ if (show_users) {
+ char ubuf[4096];
+ if (find_users(r->pdiag_ino, ubuf, sizeof(ubuf)) > 0)
+ printf(" users:(%s)", ubuf);
+ }
+ if (show_details) {
+ __u32 uid = 0;
+
+ if (tb[PACKET_DIAG_UID])
+ uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
+
+ printf(" ino=%u uid=%u sk=", r->pdiag_ino, uid);
+ if (r->pdiag_cookie[1] != 0)
+ printf("%08x", r->pdiag_cookie[1]);
+ printf("%08x", r->pdiag_cookie[0]);
+ }
+
+ if (show_bpf && tb[PACKET_DIAG_FILTER]) {
+ struct sock_filter *fil =
+ RTA_DATA(tb[PACKET_DIAG_FILTER]);
+ int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
+ sizeof(struct sock_filter);
+
+ printf("\n\tbpf filter (%d): ", num);
+ while (num) {
+ printf(" 0x%02x %u %u %u,",
+ fil->code, fil->jt, fil->jf, fil->k);
+ num--;
+ fil++;
+ }
+ }
+ printf("\n");
+ return 0;
+}
+
+static int packet_show_netlink(struct filter *f, FILE *dump_fp)
+{
+ int fd;
+ struct {
+ struct nlmsghdr nlh;
+ struct packet_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_PACKET;
+ req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO | PACKET_SHOW_FILTER;
+
+ 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_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 = packet_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;
+}
+
static int packet_show(struct filter *f)
{
if (!(f->states & (1<<SS_CLOSE)))
return 0;
+ if (packet_show_netlink(f, NULL) == 0)
+ return 0;
+
if ((fp = net_packet_open()) == NULL)
return -1;
fgets(buf, sizeof(buf)-1, fp);
" -p, --processes show process using socket\n"
" -i, --info show internal TCP information\n"
" -s, --summary show socket usage summary\n"
+" -b, --bfp show bpf filter socket information\n"
"\n"
" -4, --ipv4 display only IP version 4 sockets\n"
" -6, --ipv6 display only IP version 6 sockets\n"
{ "memory", 0, 0, 'm' },
{ "info", 0, 0, 'i' },
{ "processes", 0, 0, 'p' },
+ { "bpf", 0, 0, 'b' },
{ "dccp", 0, 0, 'd' },
{ "tcp", 0, 0, 't' },
{ "udp", 0, 0, 'u' },
current_filter.states = default_filter.states;
- while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spf:miA:D:F:vV",
+ while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vV",
long_opts, NULL)) != EOF) {
switch(ch) {
case 'n':
show_users++;
user_ent_hash_build();
break;
+ case 'b':
+ show_options = 1;
+ show_bpf++;
+ break;
case 'd':
current_filter.dbs |= (1<<DCCP_DB);
do_default = 0;