]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: add minimal support for sock_diag netlink sockets
authorLennart Poettering <lennart@poettering.net>
Tue, 8 Apr 2025 10:16:39 +0000 (12:16 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 13 May 2025 12:42:34 +0000 (14:42 +0200)
This is just enough of the type info to determine AF_UNIX queue lengths
information.

src/libsystemd/meson.build
src/libsystemd/sd-netlink/netlink-sock-diag.c [new file with mode: 0644]
src/libsystemd/sd-netlink/netlink-sock-diag.h [new file with mode: 0644]
src/libsystemd/sd-netlink/netlink-types-sdnl.c [new file with mode: 0644]
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/libsystemd/sd-netlink/test-netlink.c

index 988e5e0ce78e7805aedd2f2157bf14295d3a0afb..60b73f4da1a19ea605d327829af5887a8a316ed1 100644 (file)
@@ -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 (file)
index 0000000..0ed222e
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/sock_diag.h>
+#include <linux/unix_diag.h>
+
+#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 (file)
index 0000000..0439138
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <sys/types.h>
+
+#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 (file)
index 0000000..146f417
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/sock_diag.h>
+#include <linux/unix_diag.h>
+
+#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);
+}
index 8ce3fc0ec9a88b7909ffdc1765330cdc2591d41c..e10a90c5aadbec81382beda22779099823868139 100644 (file)
@@ -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;
                 }
index 46439527299d79205515465c09777baaf33b3b5a..85ff925edd41571d79cb6d9eb8014ea466b89388 100644 (file)
@@ -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,
index fd481dced0b1ce16a11f6edd5a2bfd3abd85afff..92138ec556ab44500d2f464e003ccd0d03ac4b6a 100644 (file)
@@ -5,18 +5,22 @@
 #include <linux/if_macsec.h>
 #include <linux/l2tp.h>
 #include <linux/nl80211.h>
+#include <linux/unix_diag.h>
 #include <net/if.h>
 #include <netinet/ether.h>
 #include <netinet/in.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #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);