]> granicus.if.org Git - strace/blob - tests/netlink_netlink_diag.c
strace: terminate itself if interrupted by a signal
[strace] / tests / netlink_netlink_diag.c
1 /*
2  * This file is part of net-yy-netlink strace test.
3  *
4  * Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
6  * Copyright (c) 2016-2018 The strace developers.
7  * All rights reserved.
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 #include "tests.h"
13 #include <errno.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <netinet/in.h>
17 #include "netlink.h"
18 #include <linux/sock_diag.h>
19 #include <linux/netlink_diag.h>
20
21 static void
22 send_query(const int fd)
23 {
24         struct sockaddr_nl nladdr = {
25                 .nl_family = AF_NETLINK
26         };
27         struct {
28                 struct nlmsghdr nlh;
29                 struct netlink_diag_req ndr;
30         } req = {
31                 .nlh = {
32                         .nlmsg_len = sizeof(req),
33                         .nlmsg_type = SOCK_DIAG_BY_FAMILY,
34                         .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
35                 },
36                 .ndr = {
37                         .sdiag_family = AF_NETLINK,
38                         .sdiag_protocol = NDIAG_PROTO_ALL
39                 }
40         };
41         struct iovec iov = {
42                 .iov_base = &req,
43                 .iov_len = sizeof(req)
44         };
45         struct msghdr msg = {
46                 .msg_name = (void *) &nladdr,
47                 .msg_namelen = sizeof(nladdr),
48                 .msg_iov = &iov,
49                 .msg_iovlen = 1
50         };
51
52         if (sendmsg(fd, &msg, 0) <= 0)
53                 perror_msg_and_skip("sendmsg");
54 }
55
56 static void
57 check_responses(const int fd)
58 {
59         static union {
60                 struct nlmsghdr hdr;
61                 long buf[8192 / sizeof(long)];
62         } hdr_buf;
63
64         struct sockaddr_nl nladdr = {
65                 .nl_family = AF_NETLINK
66         };
67         struct iovec iov = {
68                 .iov_base = hdr_buf.buf,
69                 .iov_len = sizeof(hdr_buf.buf)
70         };
71         struct msghdr msg = {
72                 .msg_name = (void *) &nladdr,
73                 .msg_namelen = sizeof(nladdr),
74                 .msg_iov = &iov,
75                 .msg_iovlen = 1
76         };
77
78         ssize_t ret = recvmsg(fd, &msg, 0);
79         if (ret <= 0)
80                 perror_msg_and_skip("recvmsg");
81
82         struct nlmsghdr *h = &hdr_buf.hdr;
83         if (!is_nlmsg_ok(h, ret))
84                 error_msg_and_skip("!is_nlmsg_ok");
85         if (h->nlmsg_type == NLMSG_ERROR) {
86                 const struct nlmsgerr *err = NLMSG_DATA(h);
87                 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
88                         error_msg_and_skip("NLMSG_ERROR");
89                 errno = -err->error;
90                 perror_msg_and_skip("NLMSG_ERROR");
91         }
92         if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY)
93                 error_msg_and_skip("unexpected nlmsg_type %u",
94                                    (unsigned) h->nlmsg_type);
95
96         const struct netlink_diag_msg *diag = NLMSG_DATA(h);
97         if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*diag)))
98                 error_msg_and_skip("short response");
99 }
100
101 int main(void)
102 {
103         struct sockaddr_nl addr;
104         socklen_t len = sizeof(addr);
105
106         memset(&addr, 0, sizeof(addr));
107         addr.nl_family = AF_NETLINK;
108
109         close(0);
110         close(1);
111
112         if (socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG))
113                 perror_msg_and_skip("socket AF_NETLINK");
114         if (bind(0, (struct sockaddr *) &addr, len))
115                 perror_msg_and_skip("bind");
116
117         if (socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG) != 1)
118                 perror_msg_and_skip("socket AF_NETLINK");
119
120         send_query(1);
121         check_responses(1);
122         return 0;
123 }