Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netlink/netlink_socket.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2023 Gleb Smirnoff <[email protected]>
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
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
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);
120
ATF_TC_HEAD(overflow, tc)
121
{
122
atf_tc_set_md_var(tc, "require.kmods", "netlink");
123
}
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);
151
ATF_TC_HEAD(peek, tc)
152
{
153
atf_tc_set_md_var(tc, "require.kmods", "netlink");
154
}
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
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);
197
ATF_TC_HEAD(sizes, tc)
198
{
199
atf_tc_set_md_var(tc, "require.kmods", "netlink");
200
}
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 *
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);
303
ATF_TC_HEAD(membership, tc)
304
{
305
atf_tc_set_md_var(tc, "require.kmods", "netlink");
306
}
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
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
370