104 lines
2.0 KiB
C
104 lines
2.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include "libnetlink.h"
|
|
#include "ssfilter.h"
|
|
#include "ss_util.h"
|
|
|
|
static int dummy_filter(struct nlmsghdr *n, void *arg)
|
|
{
|
|
/* just stops rtnl_dump_filter() */
|
|
return -1;
|
|
}
|
|
|
|
static bool cgroup_filter_check(void)
|
|
{
|
|
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
|
DIAG_REQUEST(req, struct inet_diag_req_v2 r);
|
|
struct instr {
|
|
struct inet_diag_bc_op op;
|
|
__u64 cgroup_id;
|
|
} __attribute__((packed));
|
|
int inslen = sizeof(struct instr);
|
|
struct instr instr = {
|
|
{ INET_DIAG_BC_CGROUP_COND, inslen, inslen + 4 },
|
|
0
|
|
};
|
|
struct rtnl_handle rth;
|
|
struct iovec iov[3];
|
|
struct msghdr msg;
|
|
struct rtattr rta;
|
|
int ret = false;
|
|
int iovlen = 3;
|
|
|
|
if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
|
|
return false;
|
|
rth.dump = MAGIC_SEQ;
|
|
rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR;
|
|
|
|
memset(&req.r, 0, sizeof(req.r));
|
|
req.r.sdiag_family = AF_INET;
|
|
req.r.sdiag_protocol = IPPROTO_TCP;
|
|
req.nlh.nlmsg_len += RTA_LENGTH(inslen);
|
|
|
|
rta.rta_type = INET_DIAG_REQ_BYTECODE;
|
|
rta.rta_len = RTA_LENGTH(inslen);
|
|
|
|
iov[0] = (struct iovec) { &req, sizeof(req) };
|
|
iov[1] = (struct iovec) { &rta, sizeof(rta) };
|
|
iov[2] = (struct iovec) { &instr, inslen };
|
|
|
|
msg = (struct msghdr) {
|
|
.msg_name = (void *)&nladdr,
|
|
.msg_namelen = sizeof(nladdr),
|
|
.msg_iov = iov,
|
|
.msg_iovlen = iovlen,
|
|
};
|
|
|
|
if (sendmsg(rth.fd, &msg, 0) < 0)
|
|
goto out;
|
|
|
|
if (rtnl_dump_filter(&rth, dummy_filter, NULL) < 0) {
|
|
ret = (errno != EINVAL);
|
|
goto out;
|
|
}
|
|
|
|
ret = true;
|
|
|
|
out:
|
|
rtnl_close(&rth);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
struct filter_check_t {
|
|
bool (*check)(void);
|
|
int checked:1,
|
|
supported:1;
|
|
};
|
|
|
|
static struct filter_check_t filter_checks[SSF__MAX] = {
|
|
[SSF_CGROUPCOND] = { cgroup_filter_check, 0 },
|
|
};
|
|
|
|
bool ssfilter_is_supported(int type)
|
|
{
|
|
struct filter_check_t f;
|
|
|
|
if (type >= SSF__MAX)
|
|
return false;
|
|
|
|
f = filter_checks[type];
|
|
if (!f.check)
|
|
return true;
|
|
|
|
if (!f.checked) {
|
|
f.supported = f.check();
|
|
f.checked = 1;
|
|
}
|
|
|
|
return f.supported;
|
|
}
|