Commit b9e6a27c authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

sockets: dump netlink sockets

All info about bound sockets are got via socket diag interface.
All connected sockets are automatically bound.
For other sockets only protocol must be dumped, which is got
with help getsockopt.

A netlink sockets with pending data are not supported yet and
probably will not be supported in a near future.
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent b17c9f64
...@@ -54,6 +54,7 @@ extern struct socket_desc *lookup_socket(int ino, int family); ...@@ -54,6 +54,7 @@ extern struct socket_desc *lookup_socket(int ino, int family);
extern int dump_one_inet(struct fd_parms *p, int lfd, const int fdinfo); extern int dump_one_inet(struct fd_parms *p, int lfd, const int fdinfo);
extern int dump_one_inet6(struct fd_parms *p, int lfd, const int fdinfo); extern int dump_one_inet6(struct fd_parms *p, int lfd, const int fdinfo);
extern int dump_one_unix(struct fd_parms *p, int lfd, const int fdinfo); extern int dump_one_unix(struct fd_parms *p, int lfd, const int fdinfo);
extern int dump_one_netlink(struct fd_parms *p, int lfd, const int fdinfo);
extern int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto); extern int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto);
extern int unix_receive_one(struct nlmsghdr *h, void *); extern int unix_receive_one(struct nlmsghdr *h, void *);
......
...@@ -12,6 +12,7 @@ enum fd_types { ...@@ -12,6 +12,7 @@ enum fd_types {
PACKETSK = 10; PACKETSK = 10;
TTY = 11; TTY = 11;
FANOTIFY = 12; FANOTIFY = 12;
NETLINKSK = 13;
} }
message fdinfo_entry { message fdinfo_entry {
......
#include <unistd.h> #include <unistd.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <poll.h>
#include "crtools.h" #include "crtools.h"
#include "files.h" #include "files.h"
...@@ -68,3 +69,95 @@ void show_netlinksk(int fd, struct cr_options *o) ...@@ -68,3 +69,95 @@ void show_netlinksk(int fd, struct cr_options *o)
{ {
pb_show_plain(fd, PB_NETLINKSK); pb_show_plain(fd, PB_NETLINKSK);
} }
static bool can_dump_netlink_sk(int lfd)
{
struct pollfd pfd = {lfd, POLLIN, 0};
int ret;
ret = poll(&pfd, 1, 0);
if (ret < 0) {
pr_perror("poll() failed");
} else if (ret == 1)
pr_err("The socket has data to read\n");
return ret == 0;
}
static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
{
struct netlink_sk_desc *sk;
NetlinkSkEntry ne = NETLINK_SK_ENTRY__INIT;
SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
sk = (struct netlink_sk_desc *)lookup_socket(p->stat.st_ino, PF_NETLINK);
ne.id = id;
ne.ino = p->stat.st_ino;
if (!can_dump_netlink_sk(lfd))
goto err;
if (sk) {
BUG_ON(sk->sd.already_dumped);
ne.protocol = sk->protocol;
ne.portid = sk->portid;
ne.groups = sk->groups;
ne.n_groups = sk->gsize / sizeof(ne.groups[0]);
/*
* On 64-bit sk->gsize is multiple to 8 bytes (sizeof(long)),
* so remove the last 4 bytes if they are empty.
*/
if (ne.n_groups && sk->groups[ne.n_groups - 1] == 0)
ne.n_groups -= 1;
if (ne.n_groups > 1) {
pr_err("%d %x\n", sk->gsize, sk->groups[1]);
pr_err("The netlink socket 0x%x has more than 32 groups\n", ne.ino);
return -1;
}
if (sk->groups && !sk->portid) {
pr_err("The netlink socket 0x%x is bound to groups but not to portid\n", ne.ino);
return -1;
}
ne.state = sk->state;
ne.dst_portid = sk->dst_portid;
ne.dst_group = sk->dst_group;
} else { /* unconnected and unbound socket */
int val;
socklen_t aux = sizeof(val);
if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
pr_perror("Unable to get protocol for netlink socket");
goto err;
}
ne.protocol = val;
}
ne.fown = (FownEntry *)&p->fown;
ne.opts = &skopts;
if (dump_socket_opts(lfd, &skopts))
goto err;
if (pb_write_one(fdset_fd(glob_fdset, CR_FD_NETLINKSK), &ne, PB_NETLINKSK))
goto err;
return 0;
err:
return -1;
}
static const struct fdtype_ops netlink_dump_ops = {
.type = FD_TYPES__NETLINKSK,
.dump = dump_one_netlink_fd,
};
int dump_one_netlink(struct fd_parms *p, int lfd, const int fdinfo)
{
return do_dump_gen_file(p, lfd, &netlink_dump_ops, fdinfo);
}
...@@ -378,6 +378,8 @@ int dump_socket(struct fd_parms *p, int lfd, const int fdinfo) ...@@ -378,6 +378,8 @@ int dump_socket(struct fd_parms *p, int lfd, const int fdinfo)
return dump_one_inet6(p, lfd, fdinfo); return dump_one_inet6(p, lfd, fdinfo);
case AF_PACKET: case AF_PACKET:
return dump_one_packet_sk(p, lfd, fdinfo); return dump_one_packet_sk(p, lfd, fdinfo);
case AF_NETLINK:
return dump_one_netlink(p, lfd, fdinfo);
default: default:
pr_err("BUG! Unknown socket collected (family %d)\n", family); pr_err("BUG! Unknown socket collected (family %d)\n", family);
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment