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.
This commit is contained in:
Lennart Poettering
2025-05-13 14:42:34 +02:00
parent 6e196011ca
commit 89e546e927
7 changed files with 125 additions and 0 deletions
+2
View 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',
@@ -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;
}
@@ -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);
@@ -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);
}
@@ -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;
}
@@ -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,
+28
View 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);