'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',
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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);
+}
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;
}
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,
#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"
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);