xref: /freebsd/tests/sys/netlink/netlink_socket.c (revision aab45f2aeec803d37514b574010cb5e7cfba8249)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2023 Gleb Smirnoff <glebius@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/ioctl.h>
30 #include <sys/time.h>
31 #include <sys/socket.h>
32 #include <sys/module.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 
39 #include <netlink/netlink.h>
40 #include <netlink/netlink_route.h>
41 
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 
45 #include <atf-c.h>
46 
47 static struct itimerval itv = {
48 	.it_interval = { 0, 0 },
49 	.it_value = { 1, 0 },	/* one second */
50 };
51 static sig_atomic_t timer_done = 0;
52 static void
sigalarm(int sig __unused)53 sigalarm(int sig __unused)
54 {
55 
56 	timer_done = 1;
57 }
58 
59 static struct sigaction sigact = {
60 	.sa_handler = sigalarm,
61 };
62 
63 static struct nlmsghdr hdr = (struct nlmsghdr) {
64 	.nlmsg_type = RTM_GETLINK,
65 	.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
66 	.nlmsg_len = sizeof(struct nlmsghdr),
67 };
68 
69 #define	BUFLEN	1000
70 
71 static int
fullsocket(void)72 fullsocket(void)
73 {
74 	char buf[BUFLEN];
75 	socklen_t slen = sizeof(int);
76 	int fd, sendspace, recvspace, sendavail, recvavail, rsize;
77 	u_int cnt = 0;
78 
79 	ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
80 	ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendspace,
81 	    &slen) == 0);
82 	ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvspace,
83 	    &slen) == 0);
84 
85 	/* Check the expected size of reply on a single RTM_GETLINK. */
86 	ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
87 	ATF_REQUIRE(recv(fd, buf, sizeof(hdr), MSG_WAITALL | MSG_PEEK) ==
88 	    sizeof(hdr));
89 	ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
90 
91 
92 	/*
93 	 * Flood the socket with requests, without reading out the replies.
94 	 * While we are flooding, the kernel tries to process the requests.
95 	 * Kernel takes off requests from the send buffer and puts replies
96 	 * on receive buffer.  Once the receive buffer is full it stops working
97 	 * on queue in the send buffer.  At this point we must get a solid
98 	 * failure.  However, if we flood faster than kernel taskqueue runs,
99 	 * we may get intermittent failures.
100 	 */
101 	do {
102 		ssize_t rv;
103 
104 		rv = send(fd, &hdr, sizeof(hdr), MSG_DONTWAIT);
105 		if (__predict_true(rv == sizeof(hdr)))
106 			cnt++;
107 		else {
108 			ATF_REQUIRE(errno == EAGAIN);
109 			ATF_REQUIRE(sizeof(hdr) * cnt > sendspace);
110 		}
111 		ATF_REQUIRE(ioctl(fd, FIONREAD, &recvavail) != -1);
112 		ATF_REQUIRE(ioctl(fd, FIONWRITE, &sendavail) != -1);
113 	} while (recvavail <= recvspace - rsize ||
114 		 sendavail <= sendspace - sizeof(hdr));
115 
116 	return (fd);
117 }
118 
119 ATF_TC(overflow);
ATF_TC_HEAD(overflow,tc)120 ATF_TC_HEAD(overflow, tc)
121 {
122 	atf_tc_set_md_var(tc, "require.kmods", "netlink");
123 }
ATF_TC_BODY(overflow,tc)124 ATF_TC_BODY(overflow, tc)
125 {
126 	char buf[BUFLEN];
127 	int fd;
128 
129 	fd = fullsocket();
130 
131 	/* Both buffers full: block. */
132 	timer_done = 0;
133 	ATF_REQUIRE(sigaction(SIGALRM, &sigact, NULL) == 0);
134 	ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0);
135 	ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == -1);
136 	ATF_REQUIRE(errno == EINTR);
137 	ATF_REQUIRE(timer_done == 1);
138 
139 	/*
140 	 * Now, reading something from the receive buffer should wake up the
141 	 * taskqueue and send buffer should start getting drained.
142 	 */
143 	ATF_REQUIRE(recv(fd, buf, BUFLEN, 0) > sizeof(hdr));
144 	timer_done = 0;
145 	ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0);
146 	ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
147 	ATF_REQUIRE(timer_done == 0);
148 }
149 
150 ATF_TC(peek);
ATF_TC_HEAD(peek,tc)151 ATF_TC_HEAD(peek, tc)
152 {
153 	atf_tc_set_md_var(tc, "require.kmods", "netlink");
154 }
ATF_TC_BODY(peek,tc)155 ATF_TC_BODY(peek, tc)
156 {
157 	char *buf;
158 	ssize_t ss, ss1;
159 	int fd;
160 
161 	ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
162 
163 	ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
164 	ss = recv(fd, buf, 0, MSG_WAITALL | MSG_PEEK | MSG_TRUNC);
165 	ATF_REQUIRE((buf = malloc(ss)) != NULL);
166 	ATF_REQUIRE(recv(fd, buf, ss, MSG_WAITALL) == ss);
167 }
168 
169 struct nl_control {
170 	struct nlattr nla;
171 	uint32_t val;
172 };
173 
174 static void
cmsg_check(struct msghdr * msg)175 cmsg_check(struct msghdr *msg)
176 {
177 	static pid_t pid = 0;
178 	struct cmsghdr *cmsg;
179 	struct nl_control *nlc;
180 
181 	ATF_REQUIRE((cmsg = CMSG_FIRSTHDR(msg)) != NULL);
182 	ATF_REQUIRE(cmsg->cmsg_level == SOL_NETLINK);
183 	ATF_REQUIRE(cmsg->cmsg_type == NETLINK_MSG_INFO);
184 	nlc = (struct nl_control *)CMSG_DATA(cmsg);
185 	ATF_REQUIRE(nlc[0].nla.nla_type == NLMSGINFO_ATTR_PROCESS_ID);
186 	if (pid == 0)
187 		pid = getpid();
188 	ATF_REQUIRE(nlc[0].val == pid);
189 	ATF_REQUIRE(nlc[1].nla.nla_type == NLMSGINFO_ATTR_PORT_ID);
190 	/* XXX need another test to test port id */
191 	ATF_REQUIRE(nlc[1].val == 0);
192 	ATF_REQUIRE(CMSG_NXTHDR(msg, cmsg) == NULL);
193 	ATF_REQUIRE((msg->msg_flags & MSG_CTRUNC) == 0);
194 }
195 
196 ATF_TC(sizes);
ATF_TC_HEAD(sizes,tc)197 ATF_TC_HEAD(sizes, tc)
198 {
199 	atf_tc_set_md_var(tc, "require.kmods", "netlink");
200 }
ATF_TC_BODY(sizes,tc)201 ATF_TC_BODY(sizes, tc)
202 {
203 #define	NLMSG_LARGE 2048		/* XXX: match kernel nl_buf */
204 	char buf[NLMSG_LARGE * 10];
205 	char cbuf[CMSG_SPACE(sizeof(struct nl_control) * 2)];
206 	struct iovec iov;
207 	struct msghdr msg = {
208 		.msg_iov = &iov,
209 		.msg_iovlen = 1,
210 		.msg_control = cbuf,
211 		.msg_controllen = sizeof(cbuf),
212 	};
213 	ssize_t ss;
214 	int fd, size, msize, rsize;
215 
216 	/*
217 	 * Create a socket with NMSGS messages in the receive buffer.
218 	 */
219 #define	NMSGS 5
220 	ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
221 	ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
222 	ATF_REQUIRE(recv(fd, buf, sizeof(hdr), MSG_WAITALL | MSG_PEEK) ==
223 	    sizeof(hdr));
224 	ATF_REQUIRE(ioctl(fd, FIONREAD, &msize) != -1);
225 	for (u_int i = 0; i < NMSGS; i++)
226 		ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr));
227 	do {
228 		ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
229 	} while (rsize < msize * (NMSGS + 1));
230 
231 	/*
232 	 * Set NETLINK_MSG_INFO, so that later cmsg_check will check that any
233 	 * read is accompanied with control data.
234 	 */
235 	ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_MSG_INFO,
236 	    &(int){1}, sizeof(int)) == 0);
237 
238 	iov = (struct iovec ){
239 		.iov_base = &hdr,
240 		.iov_len = sizeof(hdr),
241 	};
242 	/* Obtain size of the first message in the socket. */
243 	ss = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK | MSG_TRUNC);
244 	ATF_REQUIRE(ss == hdr.nlmsg_len);
245 	/* And overall amount of data in the socket. */
246 	ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
247 	cmsg_check(&msg);
248 
249 	/* Zero-sized read should not affect state of the socket buffer. */
250 	ATF_REQUIRE(recv(fd, buf, 0, 0) == 0);
251 	ATF_REQUIRE(ioctl(fd, FIONREAD, &size) != -1);
252 	ATF_REQUIRE(size == rsize);
253 
254 	/*
255 	 * Undersized read should lose a message.  This isn't exactly
256 	 * pronounced in the Netlink RFC, but it always says that Netlink
257 	 * socket is an analog of the BSD routing socket, and this is how
258 	 * a route(4) socket deals with undersized read.
259 	 */
260 	iov = (struct iovec ){
261 		.iov_base = buf,
262 		.iov_len = sizeof(hdr),
263 	};
264 	ATF_REQUIRE(recvmsg(fd, &msg, 0) == sizeof(hdr));
265 	ATF_REQUIRE(msg.msg_flags & MSG_TRUNC);
266 	ATF_REQUIRE(hdr.nlmsg_len > sizeof(hdr));
267 	size = rsize - hdr.nlmsg_len;
268 	ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1);
269 	ATF_REQUIRE(size == rsize);
270 	cmsg_check(&msg);
271 
272 	/*
273 	 * Large read should span several nl_bufs, seeing no boundaries.
274 	 */
275 	iov = (struct iovec ){
276 		.iov_base = buf,
277 		.iov_len = sizeof(buf) < rsize ? sizeof(buf) : rsize,
278 	};
279 	ss = recvmsg(fd, &msg, 0);
280 	ATF_REQUIRE(ss > hdr.nlmsg_len);
281 	ATF_REQUIRE(ss > NLMSG_LARGE * 9 || ss == rsize);
282 	cmsg_check(&msg);
283 }
284 
285 static struct nlattr *
nla_RTA_DST(struct nlattr * start,ssize_t len)286 nla_RTA_DST(struct nlattr *start, ssize_t len)
287 {
288 	struct nlattr *nla;
289 
290 	for (nla = start; (char *)nla < (char *)start + len;
291 	    nla = (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len))) {
292 		if (nla->nla_type == RTA_DST)
293 			return (nla);
294 	}
295 
296 	return (NULL);
297 }
298 /*
299  * Check that NETLINK_ADD_MEMBERSHIP subscribes us.  Add & delete a temporary
300  * route and check if announcements came in.
301  */
302 ATF_TC(membership);
ATF_TC_HEAD(membership,tc)303 ATF_TC_HEAD(membership, tc)
304 {
305 	atf_tc_set_md_var(tc, "require.kmods", "netlink");
306 }
ATF_TC_BODY(membership,tc)307 ATF_TC_BODY(membership, tc)
308 {
309 	struct {
310 		struct nlmsghdr hdr;
311 		struct rtmsg rtm;
312 		struct nlattr rta_dst;
313 		struct in_addr dst;
314 		struct nlattr rta_oif;
315 		uint32_t oif;
316 	} reply, msg = {
317 		.hdr.nlmsg_type = RTM_NEWROUTE,
318 		.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL,
319 		.hdr.nlmsg_len = sizeof(msg),
320 		.rtm.rtm_family = AF_INET,
321 		.rtm.rtm_protocol = RTPROT_STATIC,
322 		.rtm.rtm_type = RTN_UNICAST,
323 		.rtm.rtm_dst_len = 32,
324 		.rta_dst.nla_type = RTA_DST,
325 		.rta_dst.nla_len = sizeof(struct in_addr) +
326 		    sizeof(struct nlattr),
327 		.dst.s_addr = inet_addr("127.0.0.127"),
328 		.rta_oif.nla_type = RTA_OIF,
329 		.rta_oif.nla_len = sizeof(uint32_t) + sizeof(struct nlattr),
330 		.oif = 1,
331 	};
332 	struct nlattr *nla;
333 	int fd;
334 
335 	ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1);
336 	ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
337 	    &(int){RTNLGRP_IPV4_ROUTE}, sizeof(int)) == 0);
338 
339 	ATF_REQUIRE(send(fd, &msg, sizeof(msg), 0) == sizeof(msg));
340 	ATF_REQUIRE(recv(fd, &reply, sizeof(reply), 0) == sizeof(reply));
341 	ATF_REQUIRE(reply.hdr.nlmsg_type == msg.hdr.nlmsg_type);
342 	ATF_REQUIRE(reply.rtm.rtm_type == msg.rtm.rtm_type);
343 	ATF_REQUIRE(reply.rtm.rtm_dst_len == msg.rtm.rtm_dst_len);
344 	ATF_REQUIRE(nla = nla_RTA_DST(&reply.rta_dst, sizeof(reply)));
345 	ATF_REQUIRE(memcmp(&msg.dst, (char *)nla + sizeof(struct nlattr),
346 	    sizeof(struct in_addr)) == 0);
347 
348 	msg.hdr.nlmsg_type = RTM_DELROUTE;
349 	msg.hdr.nlmsg_len -= sizeof(struct nlattr) + sizeof(uint32_t);
350 	ATF_REQUIRE(send(fd, &msg, msg.hdr.nlmsg_len, 0) == msg.hdr.nlmsg_len);
351 	ATF_REQUIRE(recv(fd, &reply, sizeof(reply), 0) == sizeof(reply));
352 	ATF_REQUIRE(reply.hdr.nlmsg_type == msg.hdr.nlmsg_type);
353 	ATF_REQUIRE(reply.rtm.rtm_type == msg.rtm.rtm_type);
354 	ATF_REQUIRE(reply.rtm.rtm_dst_len == msg.rtm.rtm_dst_len);
355 	ATF_REQUIRE(nla = nla_RTA_DST(&reply.rta_dst, sizeof(reply)));
356 	ATF_REQUIRE(memcmp(&msg.dst, (char *)nla + sizeof(struct nlattr),
357 	    sizeof(struct in_addr)) == 0);
358 }
359 
ATF_TP_ADD_TCS(tp)360 ATF_TP_ADD_TCS(tp)
361 {
362 	ATF_TP_ADD_TC(tp, overflow);
363 	ATF_TP_ADD_TC(tp, peek);
364 	ATF_TP_ADD_TC(tp, sizes);
365 	ATF_TP_ADD_TC(tp, membership);
366 
367 	return (atf_no_error());
368 }
369