diff options
Diffstat (limited to 'src/libsystemd/sd-rtnl')
-rw-r--r-- | src/libsystemd/sd-rtnl/local-addresses.c | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-rtnl/rtnl-message.c | 48 | ||||
-rw-r--r-- | src/libsystemd/sd-rtnl/rtnl-util.c | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-rtnl/sd-rtnl.c | 109 | ||||
-rw-r--r-- | src/libsystemd/sd-rtnl/test-rtnl.c | 14 |
5 files changed, 90 insertions, 89 deletions
diff --git a/src/libsystemd/sd-rtnl/local-addresses.c b/src/libsystemd/sd-rtnl/local-addresses.c index 31bfa06066..f05cbf1f47 100644 --- a/src/libsystemd/sd-rtnl/local-addresses.c +++ b/src/libsystemd/sd-rtnl/local-addresses.c @@ -66,7 +66,7 @@ int local_addresses(sd_rtnl *context, int ifindex, int af, struct local_address if (context) rtnl = sd_rtnl_ref(context); else { - r = sd_rtnl_open(&rtnl, 0); + r = sd_rtnl_open(&rtnl); if (r < 0) return r; } @@ -177,7 +177,7 @@ int local_gateways(sd_rtnl *context, int ifindex, int af, struct local_address * if (context) rtnl = sd_rtnl_ref(context); else { - r = sd_rtnl_open(&rtnl, 0); + r = sd_rtnl_open(&rtnl); if (r < 0) return r; } diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index 9dcf7df559..79e67f6953 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -24,6 +24,7 @@ #include <unistd.h> #include "util.h" +#include "socket-util.h" #include "formats-util.h" #include "refcnt.h" #include "missing.h" @@ -1415,17 +1416,18 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { } static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) { - uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) + - CMSG_SPACE(sizeof(struct nl_pktinfo))]; + union sockaddr_union sender; + uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))]; struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1, - .msg_control = cred_buffer, - .msg_controllen = sizeof(cred_buffer), + .msg_name = &sender, + .msg_namelen = sizeof(sender), + .msg_control = cmsg_buffer, + .msg_controllen = sizeof(cmsg_buffer), }; struct cmsghdr *cmsg; uint32_t group = 0; - bool auth = false; int r; assert(fd >= 0); @@ -1442,29 +1444,10 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool return (errno == EAGAIN || errno == EINTR) ? 0 : -errno; } - CMSG_FOREACH(cmsg, &msg) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_CREDENTIALS && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { - struct ucred *ucred = (void *)CMSG_DATA(cmsg); - - /* from the kernel */ - if (ucred->pid == 0) - auth = true; - else - log_debug("rtnl: ignoring message from PID "PID_FMT, ucred->pid); - } else if (cmsg->cmsg_level == SOL_NETLINK && - cmsg->cmsg_type == NETLINK_PKTINFO && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) { - struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg); - - /* multi-cast group */ - group = pktinfo->group; - } - } - - if (!auth) { + if (sender.nl.nl_pid != 0) { /* not from the kernel, ignore */ + log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid); + if (peek) { /* drop the message */ r = recvmsg(fd, &msg, 0); @@ -1475,6 +1458,17 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool return 0; } + CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_NETLINK && + cmsg->cmsg_type == NETLINK_PKTINFO && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) { + struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg); + + /* multi-cast group */ + group = pktinfo->group; + } + } + if (_group) *_group = group; diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c index 9ddf074c24..c2b1a5c65d 100644 --- a/src/libsystemd/sd-rtnl/rtnl-util.c +++ b/src/libsystemd/sd-rtnl/rtnl-util.c @@ -34,7 +34,7 @@ int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name) { assert(name); if (!*rtnl) { - r = sd_rtnl_open(rtnl, 0); + r = sd_rtnl_open(rtnl); if (r < 0) return r; } @@ -66,7 +66,7 @@ int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias, return 0; if (!*rtnl) { - r = sd_rtnl_open(rtnl, 0); + r = sd_rtnl_open(rtnl); if (r < 0) return r; } diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c index 40dea1252f..5bafc282c0 100644 --- a/src/libsystemd/sd-rtnl/sd-rtnl.c +++ b/src/libsystemd/sd-rtnl/sd-rtnl.c @@ -106,25 +106,7 @@ static bool rtnl_pid_changed(sd_rtnl *rtnl) { return rtnl->original_pid != getpid(); } -static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) { - uint32_t groups = 0; - unsigned i; - - for (i = 0; i < n_groups; i++) { - unsigned group; - - group = va_arg(ap, unsigned); - assert_return(group < 32, -EINVAL); - - groups |= group ? (1 << (group - 1)) : 0; - } - - *_groups = groups; - - return 0; -} - -static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) { +int sd_rtnl_open_fd(sd_rtnl **ret, int fd) { _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; socklen_t addrlen; int r, one = 1; @@ -136,18 +118,10 @@ static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) if (r < 0) return r; - r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); - if (r < 0) - return -errno; - r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one)); if (r < 0) return -errno; - r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap); - if (r < 0) - return r; - addrlen = sizeof(rtnl->sockaddr); r = bind(fd, &rtnl->sockaddr.sa, addrlen); @@ -167,33 +141,33 @@ static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) return 0; } -int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) { - va_list ap; +int sd_rtnl_open(sd_rtnl **ret) { + _cleanup_close_ int fd = -1; int r; - va_start(ap, n_groups); - r = rtnl_open_fd_ap(ret, fd, n_groups, ap); - va_end(ap); - - return r; -} - -int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) { - va_list ap; - int fd, r; - fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE); if (fd < 0) return -errno; - va_start(ap, n_groups); - r = rtnl_open_fd_ap(ret, fd, n_groups, ap); - va_end(ap); - - if (r < 0) { - safe_close(fd); + r = sd_rtnl_open_fd(ret, fd); + if (r < 0) return r; - } + + fd = -1; + + return 0; +} + +static int rtnl_join_broadcast_group(sd_rtnl *rtnl, unsigned group) { + int r; + + assert(rtnl); + assert(rtnl->fd >= 0); + assert(group > 0); + + r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); + if (r < 0) + return -errno; return 0; } @@ -1005,14 +979,12 @@ int sd_rtnl_add_match(sd_rtnl *rtnl, uint16_t type, sd_rtnl_message_handler_t callback, void *userdata) { - struct match_callback *c; + _cleanup_free_ struct match_callback *c = NULL; + int r; assert_return(rtnl, -EINVAL); assert_return(callback, -EINVAL); assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - assert_return(rtnl_message_type_is_link(type) || - rtnl_message_type_is_addr(type) || - rtnl_message_type_is_route(type), -EOPNOTSUPP); c = new0(struct match_callback, 1); if (!c) @@ -1022,8 +994,36 @@ int sd_rtnl_add_match(sd_rtnl *rtnl, c->type = type; c->userdata = userdata; + switch (type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK); + if (r < 0) + return r; + + break; + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR); + if (r < 0) + return r; + + r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR); + if (r < 0) + return r; + + break; + default: + return -EOPNOTSUPP; + } + LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c); + c = NULL; + return 0; } @@ -1037,6 +1037,13 @@ int sd_rtnl_remove_match(sd_rtnl *rtnl, assert_return(callback, -EINVAL); assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + /* we should unsubscribe from the broadcast groups at this point, but it is not so + trivial for a few reasons: the refcounting is a bit of a mess and not obvious + how it will look like after we add genetlink support, and it is also not possible + to query what broadcast groups were subscribed to when we inherit the socket to get + the initial refcount. The latter could indeed be done for the first 32 broadcast + groups (which incidentally is all we currently support in .socket units anyway), + but we better not rely on only ever using 32 groups. */ LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) if (c->callback == callback && c->type == type && c->userdata == userdata) { LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c); diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c index 47cce64816..94b1cb7c72 100644 --- a/src/libsystemd/sd-rtnl/test-rtnl.c +++ b/src/libsystemd/sd-rtnl/test-rtnl.c @@ -184,8 +184,8 @@ static void test_route(void) { static void test_multiple(void) { sd_rtnl *rtnl1, *rtnl2; - assert_se(sd_rtnl_open(&rtnl1, 0) >= 0); - assert_se(sd_rtnl_open(&rtnl2, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl1) >= 0); + assert_se(sd_rtnl_open(&rtnl2) >= 0); rtnl1 = sd_rtnl_unref(rtnl1); rtnl2 = sd_rtnl_unref(rtnl2); @@ -216,7 +216,7 @@ static void test_event_loop(int ifindex) { ifname = strdup("lo2"); assert_se(ifname); - assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0); @@ -256,7 +256,7 @@ static void test_async(int ifindex) { ifname = strdup("lo"); assert_se(ifname); - assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); @@ -273,7 +273,7 @@ static void test_pipe(int ifindex) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL; int counter = 0; - assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0); @@ -330,7 +330,7 @@ static void test_container(void) { static void test_match(void) { _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; - assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl) >= 0); assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0); assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0); @@ -395,7 +395,7 @@ int main(void) { test_container(); - assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl) >= 0); assert_se(rtnl); if_loopback = (int) if_nametoindex("lo"); |