(root)/
strace-6.5/
tests/
netlink_unix_diag.c
       1  /*
       2   * This file is part of net-yy-unix strace test.
       3   *
       4   * Copyright (c) 2014-2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2014-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include <assert.h>
      13  #include <errno.h>
      14  #include <stddef.h>
      15  #include <stdint.h>
      16  #include <string.h>
      17  #include <unistd.h>
      18  #include <sys/socket.h>
      19  #include <sys/un.h>
      20  #include "netlink.h"
      21  #include <linux/sock_diag.h>
      22  #include <linux/unix_diag.h>
      23  
      24  static void
      25  send_query(const int fd)
      26  {
      27  	struct sockaddr_nl nladdr = {
      28  		.nl_family = AF_NETLINK
      29  	};
      30  	struct {
      31  		struct nlmsghdr nlh;
      32  		struct unix_diag_req udr;
      33  	} req = {
      34  		.nlh = {
      35  			.nlmsg_len = sizeof(req),
      36  			.nlmsg_type = SOCK_DIAG_BY_FAMILY,
      37  			.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP
      38  		},
      39  		.udr = {
      40  			.sdiag_family = AF_UNIX,
      41  			.udiag_states = -1,
      42  			.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER
      43  		}
      44  	};
      45  	struct iovec iov = {
      46  		.iov_base = &req,
      47  		.iov_len = sizeof(req)
      48  	};
      49  	struct msghdr msg = {
      50  		.msg_name = (void *) &nladdr,
      51  		.msg_namelen = sizeof(nladdr),
      52  		.msg_iov = &iov,
      53  		.msg_iovlen = 1
      54  	};
      55  
      56  	if (sendmsg(fd, &msg, 0) <= 0)
      57  		perror_msg_and_skip("sendmsg");
      58  }
      59  
      60  static void
      61  check_responses(const int fd)
      62  {
      63  	static union {
      64  		struct nlmsghdr hdr;
      65  		long buf[8192 / sizeof(long)];
      66  	} hdr_buf;
      67  
      68  	struct sockaddr_nl nladdr = {
      69  		.nl_family = AF_NETLINK
      70  	};
      71  	struct iovec iov = {
      72  		.iov_base = hdr_buf.buf,
      73  		.iov_len = sizeof(hdr_buf.buf)
      74  	};
      75  	struct msghdr msg = {
      76  		.msg_name = (void *) &nladdr,
      77  		.msg_namelen = sizeof(nladdr),
      78  		.msg_iov = &iov,
      79  		.msg_iovlen = 1
      80  	};
      81  
      82  	ssize_t ret = recvmsg(fd, &msg, 0);
      83  	if (ret <= 0)
      84  		perror_msg_and_skip("recvmsg");
      85  
      86  	struct nlmsghdr *h = &hdr_buf.hdr;
      87  	if (!is_nlmsg_ok(h, ret))
      88  		error_msg_and_skip("!is_nlmsg_ok");
      89  	if (h->nlmsg_type == NLMSG_ERROR) {
      90  		const struct nlmsgerr *err = NLMSG_DATA(h);
      91  		if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
      92  			error_msg_and_skip("NLMSG_ERROR");
      93  		errno = -err->error;
      94  		perror_msg_and_skip("NLMSG_ERROR");
      95  	}
      96  	if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY)
      97  		error_msg_and_skip("unexpected nlmsg_type %u",
      98  				   (unsigned) h->nlmsg_type);
      99  
     100  	const struct unix_diag_msg *diag = NLMSG_DATA(h);
     101  	if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*diag)))
     102  		error_msg_and_skip("short response");
     103  }
     104  
     105  #define SUN_PATH "netlink_unix_diag_socket"
     106  int main(void)
     107  {
     108  	struct sockaddr_un addr = {
     109  		.sun_family = AF_UNIX,
     110  		.sun_path = SUN_PATH
     111  	};
     112  	socklen_t len = offsetof(struct sockaddr_un, sun_path) + sizeof(SUN_PATH);
     113  
     114  	close(0);
     115  	close(1);
     116  
     117  	(void) unlink(SUN_PATH);
     118  	if (socket(AF_UNIX, SOCK_STREAM, 0))
     119  		perror_msg_and_skip("socket AF_UNIX");
     120  	if (bind(0, (struct sockaddr *) &addr, len))
     121  		perror_msg_and_skip("bind");
     122  	if (listen(0, 5))
     123  		perror_msg_and_skip("listen");
     124  
     125  	assert(unlink(SUN_PATH) == 0);
     126  
     127  	if (socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG) != 1)
     128  		perror_msg_and_skip("socket AF_NETLINK");
     129  
     130  	send_query(1);
     131  	check_responses(1);
     132  	return 0;
     133  }