#include #include #include #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; }