diff options
Diffstat (limited to 'src/libnm-systemd-shared/src/basic/socket-util.c')
| -rw-r--r-- | src/libnm-systemd-shared/src/basic/socket-util.c | 99 |
1 files changed, 75 insertions, 24 deletions
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c index df3e2c17..9cb0d7f4 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.c +++ b/src/libnm-systemd-shared/src/basic/socket-util.c @@ -2,10 +2,11 @@ #include "nm-sd-adapt-shared.h" +/* Make sure the net/if.h header is included before any linux/ one */ +#include <net/if.h> #include <arpa/inet.h> #include <errno.h> #include <limits.h> -#include <net/if.h> #include <netdb.h> #include <netinet/ip.h> #include <poll.h> @@ -24,7 +25,7 @@ #include "escape.h" #include "fd-util.h" #include "fileio.h" -#include "format-util.h" +#include "format-ifname.h" #include "io-util.h" #include "log.h" #include "memory-util.h" @@ -458,6 +459,7 @@ int sockaddr_pretty( assert(sa); assert(salen >= sizeof(sa->sa.sa_family)); + assert(ret); switch (sa->sa.sa_family) { @@ -638,7 +640,8 @@ int socknameinfo_pretty(const struct sockaddr *sa, socklen_t salen, char **ret) int r; assert(sa); - assert(salen > sizeof(sa_family_t)); + assert(salen >= sizeof(sa_family_t)); + assert(ret); r = getnameinfo(sa, salen, host, sizeof(host), /* service= */ NULL, /* service_len= */ 0, IDN_FLAGS); if (r != 0) { @@ -652,15 +655,7 @@ int socknameinfo_pretty(const struct sockaddr *sa, socklen_t salen, char **ret) return sockaddr_pretty(sa, salen, /* translate_ipv6= */ true, /* include_port= */ true, ret); } - if (ret) { - char *copy = strdup(host); - if (!copy) - return -ENOMEM; - - *ret = copy; - } - - return 0; + return strdup_to(ret, host); } static const char* const netlink_family_table[] = { @@ -987,6 +982,28 @@ int getpeerpidfd(int fd) { return pidfd; } +int getpeerpidref(int fd, PidRef *ret) { + int r; + + assert(fd >= 0); + assert(ret); + + int pidfd = getpeerpidfd(fd); + if (pidfd < 0) { + if (!ERRNO_IS_NEG_NOT_SUPPORTED(pidfd)) + return pidfd; + + struct ucred ucred; + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + return pidref_set_pid(ret, ucred.pid); + } + + return pidref_set_pidfd_consume(ret, pidfd); +} + ssize_t send_many_fds_iov_sa( int transport_fd, int *fds_array, size_t n_fds_array, @@ -1124,14 +1141,10 @@ ssize_t receive_many_fds_iov( if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { size_t n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - fds_array = GREEDY_REALLOC(fds_array, n_fds_array + n); - if (!fds_array) { + if (!GREEDY_REALLOC_APPEND(fds_array, n_fds_array, CMSG_TYPED_DATA(cmsg, int), n)) { cmsg_close_all(&mh); return -ENOMEM; } - - memcpy(fds_array + n_fds_array, CMSG_TYPED_DATA(cmsg, int), sizeof(int) * n); - n_fds_array += n; } if (n_fds_array == 0) { @@ -1468,18 +1481,22 @@ int socket_bind_to_ifindex(int fd, int ifindex) { ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { ssize_t n; - /* A wrapper around recvmsg() that checks for MSG_CTRUNC, and turns it into an error, in a reasonably - * safe way, closing any SCM_RIGHTS fds in the error path. + /* A wrapper around recvmsg() that checks for MSG_CTRUNC and MSG_TRUNC, and turns them into an error, + * in a reasonably safe way, closing any received fds in the error path. * * Note that unlike our usual coding style this might modify *msg on failure. */ + assert(sockfd >= 0); + assert(msg); + n = recvmsg(sockfd, msg, flags); if (n < 0) return -errno; - if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) { + if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC) || + (!FLAGS_SET(flags, MSG_PEEK) && FLAGS_SET(msg->msg_flags, MSG_TRUNC))) { cmsg_close_all(msg); - return -EXFULL; /* a recognizable error code */ + return FLAGS_SET(msg->msg_flags, MSG_CTRUNC) ? -ECHRNG : -EXFULL; } return n; @@ -1781,15 +1798,49 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) { int vsock_get_local_cid(unsigned *ret) { _cleanup_close_ int vsock_fd = -EBADF; - assert(ret); - vsock_fd = open("/dev/vsock", O_RDONLY|O_CLOEXEC); if (vsock_fd < 0) return log_debug_errno(errno, "Failed to open /dev/vsock: %m"); - if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ret) < 0) + unsigned tmp; + if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ret ?: &tmp) < 0) return log_debug_errno(errno, "Failed to query local AF_VSOCK CID: %m"); return 0; } + +int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups) { + _cleanup_free_ uint32_t *groups = NULL; + socklen_t len = 0, old_len; + + assert(fd >= 0); + + /* This returns ENOPROTOOPT if the kernel is older than 4.2. */ + + if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len) < 0) + return -errno; + + if (len == 0) + goto finalize; + + groups = new0(uint32_t, len); + if (!groups) + return -ENOMEM; + + old_len = len; + + if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len) < 0) + return -errno; + + if (old_len != len) + return -EIO; + +finalize: + if (ret_len) + *ret_len = len; + if (ret_groups) + *ret_groups = TAKE_PTR(groups); + + return 0; +} #endif /* NM_IGNORED */ |