From: Lennart Poettering Date: Tue, 8 Apr 2025 10:16:39 +0000 (+0200) Subject: sd-netlink: add minimal support for sock_diag netlink sockets X-Git-Tag: v258-rc1~633^2~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89e546e927b8d1fb6b7d44d689586f949109f144;p=thirdparty%2Fsystemd.git sd-netlink: add minimal support for sock_diag netlink sockets This is just enough of the type info to determine AF_UNIX queue lengths information. --- diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 988e5e0ce78..60b73f4da1a 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -109,10 +109,12 @@ sd_netlink_sources = files( 'sd-netlink/netlink-message-rtnl.c', 'sd-netlink/netlink-message.c', 'sd-netlink/netlink-slot.c', + 'sd-netlink/netlink-sock-diag.c', 'sd-netlink/netlink-socket.c', 'sd-netlink/netlink-types-genl.c', 'sd-netlink/netlink-types-nfnl.c', 'sd-netlink/netlink-types-rtnl.c', + 'sd-netlink/netlink-types-sdnl.c', 'sd-netlink/netlink-types.c', 'sd-netlink/netlink-util.c', 'sd-netlink/sd-netlink.c', diff --git a/src/libsystemd/sd-netlink/netlink-sock-diag.c b/src/libsystemd/sd-netlink/netlink-sock-diag.c new file mode 100644 index 00000000000..0ed222ea200 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-sock-diag.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "netlink-internal.h" +#include "netlink-sock-diag.h" +#include "netlink-util.h" + +int sd_sock_diag_socket_open(sd_netlink **ret) { + return netlink_open_family(ret, NETLINK_SOCK_DIAG); +} + +int sd_sock_diag_message_new_unix( + sd_netlink *sdnl, + sd_netlink_message **ret, + ino_t inode, + uint64_t cookie, + uint32_t show) { + + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + assert_return(sdnl, -EINVAL); + assert_return(ret, -EINVAL); + + r = message_new(sdnl, &m, SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST | NLM_F_ACK); + if (r < 0) + return r; + + *(struct unix_diag_req*) NLMSG_DATA(m->hdr) = (struct unix_diag_req) { + .sdiag_family = AF_UNIX, + .udiag_ino = inode, + .udiag_show = show, + .udiag_cookie = { + cookie & UINT32_MAX, + (cookie >> 32) & UINT32_MAX, + }, + }; + + *ret = TAKE_PTR(m); + return 0; +} diff --git a/src/libsystemd/sd-netlink/netlink-sock-diag.h b/src/libsystemd/sd-netlink/netlink-sock-diag.h new file mode 100644 index 00000000000..043913889c8 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-sock-diag.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "sd-netlink.h" + +/* TODO: to be exported later */ + +int sd_sock_diag_socket_open(sd_netlink **ret); +int sd_sock_diag_message_new_unix(sd_netlink *sdnl, sd_netlink_message **ret, ino_t inode, uint64_t cookie, uint32_t show); diff --git a/src/libsystemd/sd-netlink/netlink-types-sdnl.c b/src/libsystemd/sd-netlink/netlink-types-sdnl.c new file mode 100644 index 00000000000..146f4177fde --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-types-sdnl.c @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "missing_network.h" +#include "netlink-types-internal.h" +#include "netlink-types.h" + +static const NLAPolicy unix_diag_req_policies[] = { +}; +DEFINE_POLICY_SET(unix_diag_req); + +static const NLAPolicy sdnl_req_policies[] = { + [SOCK_DIAG_BY_FAMILY] = BUILD_POLICY_NESTED_WITH_SIZE(unix_diag_req, sizeof(struct unix_diag_req)), +}; + +DEFINE_POLICY_SET(sdnl_req); + +static const NLAPolicy unix_diag_msg_policies[] = { + [UNIX_DIAG_RQLEN] = BUILD_POLICY_WITH_SIZE(BINARY, sizeof(struct unix_diag_rqlen)), +}; +DEFINE_POLICY_SET(unix_diag_msg); + +static const NLAPolicy sdnl_msg_policies[] = { + [SOCK_DIAG_BY_FAMILY] = BUILD_POLICY_NESTED_WITH_SIZE(unix_diag_msg, sizeof(struct unix_diag_msg)), +}; + +DEFINE_POLICY_SET(sdnl_msg); + +const NLAPolicy *sdnl_get_policy(uint16_t nlmsg_type, uint16_t flags) { + /* for sock_diag we need to look at whether a message is a response or request to determine how to decode it. */ + if (flags & NLM_F_REQUEST) + return policy_set_get_policy(&sdnl_req_policy_set, nlmsg_type); + + return policy_set_get_policy(&sdnl_msg_policy_set, nlmsg_type); +} diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 8ce3fc0ec9a..e10a90c5aad 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -71,6 +71,9 @@ int netlink_get_policy_set_and_header_size( break; case NETLINK_GENERIC: return genl_get_policy_set_and_header_size(nl, type, ret_policy_set, ret_header_size); + case NETLINK_SOCK_DIAG: + policy = sdnl_get_policy(type, flags); + break; default: return -EOPNOTSUPP; } diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index 46439527299..85ff925edd4 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -37,6 +37,7 @@ typedef struct NLAPolicySetUnion NLAPolicySetUnion; const NLAPolicy *rtnl_get_policy(uint16_t nlmsg_type); const NLAPolicy *nfnl_get_policy(uint16_t nlmsg_type); +const NLAPolicy *sdnl_get_policy(uint16_t nlmsg_type, uint16_t nlmsg_flags); const NLAPolicySet *genl_get_policy_set_by_name(const char *name); int genl_get_policy_set_and_header_size( sd_netlink *nl, diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index fd481dced0b..92138ec556a 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -5,18 +5,22 @@ #include #include #include +#include #include #include #include +#include #include #include "sd-netlink.h" #include "alloc-util.h" #include "ether-addr-util.h" +#include "fd-util.h" #include "macro.h" #include "netlink-genl.h" #include "netlink-internal.h" +#include "netlink-sock-diag.h" #include "netlink-util.h" #include "socket-util.h" #include "stdio-util.h" @@ -699,4 +703,28 @@ TEST(rtnl_set_link_name) { ASSERT_NULL(resolved = mfree(resolved)); } +TEST(sock_diag_unix) { + _cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL; + + ASSERT_OK(sd_sock_diag_socket_open(&nl)); + + _cleanup_close_ int unix_fd = ASSERT_FD(socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)); + ASSERT_OK(socket_autobind(unix_fd, /* ret_name= */ NULL)); + ASSERT_OK_ERRNO(listen(unix_fd, 123)); + + struct stat st; + ASSERT_OK_ERRNO(fstat(unix_fd, &st)); + + uint64_t cookie; + socklen_t cookie_len = sizeof(cookie); + ASSERT_OK_ERRNO(getsockopt(unix_fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len)); + ASSERT_EQ(cookie_len, sizeof(cookie)); + + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; + ASSERT_OK(sd_sock_diag_message_new_unix(nl, &message, st.st_ino, cookie, UDIAG_SHOW_RQLEN)); + + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; + ASSERT_OK(sd_netlink_call(nl, message, /* usec= */ 0, &reply)); +} + DEFINE_TEST_MAIN(LOG_DEBUG);