Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netinet/so_reuseport_lb_test.c
107074 views
1
/*-
2
* Copyright (c) 2018 The FreeBSD Foundation
3
*
4
* This software was developed by Mark Johnston under sponsorship from
5
* the FreeBSD Foundation.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are
9
* met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in
14
* the documentation and/or other materials provided with the
15
* distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/param.h>
31
#include <sys/event.h>
32
#include <sys/filio.h>
33
#include <sys/ioccom.h>
34
#include <sys/socket.h>
35
36
#include <netinet/in.h>
37
#include <netinet/tcp.h>
38
39
#include <err.h>
40
#include <errno.h>
41
#include <pthread.h>
42
#include <stdatomic.h>
43
#include <stdlib.h>
44
#include <unistd.h>
45
46
#include <atf-c.h>
47
48
/*
49
* Given an array of non-blocking listening sockets configured in a LB group
50
* for "addr", try connecting to "addr" in a loop and verify that connections
51
* are roughly balanced across the sockets.
52
*/
53
static void
54
lb_simple_accept_loop(int domain, const struct sockaddr *addr, int sds[],
55
size_t nsds, int nconns)
56
{
57
size_t i;
58
int *acceptcnt;
59
int csd, error, excnt, sd;
60
const struct linger lopt = { 1, 0 };
61
62
/*
63
* We expect each listening socket to accept roughly nconns/nsds
64
* connections, but allow for some error.
65
*/
66
excnt = nconns / nsds / 8;
67
acceptcnt = calloc(nsds, sizeof(*acceptcnt));
68
ATF_REQUIRE_MSG(acceptcnt != NULL, "calloc() failed: %s",
69
strerror(errno));
70
71
while (nconns-- > 0) {
72
sd = socket(domain, SOCK_STREAM, 0);
73
ATF_REQUIRE_MSG(sd >= 0, "socket() failed: %s",
74
strerror(errno));
75
76
error = connect(sd, addr, addr->sa_len);
77
ATF_REQUIRE_MSG(error == 0, "connect() failed: %s",
78
strerror(errno));
79
80
error = setsockopt(sd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt));
81
ATF_REQUIRE_MSG(error == 0, "Setting linger failed: %s",
82
strerror(errno));
83
84
/*
85
* Poll the listening sockets.
86
*/
87
do {
88
for (i = 0; i < nsds; i++) {
89
csd = accept(sds[i], NULL, NULL);
90
if (csd < 0) {
91
ATF_REQUIRE_MSG(errno == EWOULDBLOCK ||
92
errno == EAGAIN,
93
"accept() failed: %s",
94
strerror(errno));
95
continue;
96
}
97
98
error = close(csd);
99
ATF_REQUIRE_MSG(error == 0,
100
"close() failed: %s", strerror(errno));
101
102
acceptcnt[i]++;
103
break;
104
}
105
} while (i == nsds);
106
107
error = close(sd);
108
ATF_REQUIRE_MSG(error == 0, "close() failed: %s",
109
strerror(errno));
110
}
111
112
for (i = 0; i < nsds; i++)
113
ATF_REQUIRE_MSG(acceptcnt[i] > excnt, "uneven balancing");
114
}
115
116
static int
117
lb_listen_socket(int domain, int flags)
118
{
119
int one;
120
int error, sd;
121
122
sd = socket(domain, SOCK_STREAM | flags, 0);
123
ATF_REQUIRE_MSG(sd >= 0, "socket() failed: %s", strerror(errno));
124
125
one = 1;
126
error = setsockopt(sd, SOL_SOCKET, SO_REUSEPORT_LB, &one, sizeof(one));
127
ATF_REQUIRE_MSG(error == 0, "setsockopt(SO_REUSEPORT_LB) failed: %s",
128
strerror(errno));
129
130
return (sd);
131
}
132
133
ATF_TC_WITHOUT_HEAD(basic_ipv4);
134
ATF_TC_BODY(basic_ipv4, tc)
135
{
136
struct sockaddr_in addr;
137
socklen_t slen;
138
size_t i;
139
const int nconns = 16384;
140
int error, sds[16];
141
uint16_t port;
142
143
sds[0] = lb_listen_socket(PF_INET, SOCK_NONBLOCK);
144
145
memset(&addr, 0, sizeof(addr));
146
addr.sin_len = sizeof(addr);
147
addr.sin_family = AF_INET;
148
addr.sin_port = htons(0);
149
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
150
error = bind(sds[0], (const struct sockaddr *)&addr, sizeof(addr));
151
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
152
error = listen(sds[0], 1);
153
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
154
155
slen = sizeof(addr);
156
error = getsockname(sds[0], (struct sockaddr *)&addr, &slen);
157
ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s",
158
strerror(errno));
159
ATF_REQUIRE_MSG(slen == sizeof(addr), "sockaddr size changed");
160
port = addr.sin_port;
161
162
memset(&addr, 0, sizeof(addr));
163
addr.sin_len = sizeof(addr);
164
addr.sin_family = AF_INET;
165
addr.sin_port = port;
166
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
167
for (i = 1; i < nitems(sds); i++) {
168
sds[i] = lb_listen_socket(PF_INET, SOCK_NONBLOCK);
169
170
error = bind(sds[i], (const struct sockaddr *)&addr,
171
sizeof(addr));
172
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s",
173
strerror(errno));
174
error = listen(sds[i], 1);
175
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s",
176
strerror(errno));
177
}
178
179
lb_simple_accept_loop(PF_INET, (struct sockaddr *)&addr, sds,
180
nitems(sds), nconns);
181
for (i = 0; i < nitems(sds); i++) {
182
error = close(sds[i]);
183
ATF_REQUIRE_MSG(error == 0, "close() failed: %s",
184
strerror(errno));
185
}
186
}
187
188
ATF_TC_WITHOUT_HEAD(basic_ipv6);
189
ATF_TC_BODY(basic_ipv6, tc)
190
{
191
const struct in6_addr loopback6 = IN6ADDR_LOOPBACK_INIT;
192
struct sockaddr_in6 addr;
193
socklen_t slen;
194
size_t i;
195
const int nconns = 16384;
196
int error, sds[16];
197
uint16_t port;
198
199
sds[0] = lb_listen_socket(PF_INET6, SOCK_NONBLOCK);
200
201
memset(&addr, 0, sizeof(addr));
202
addr.sin6_len = sizeof(addr);
203
addr.sin6_family = AF_INET6;
204
addr.sin6_port = htons(0);
205
addr.sin6_addr = loopback6;
206
error = bind(sds[0], (const struct sockaddr *)&addr, sizeof(addr));
207
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
208
error = listen(sds[0], 1);
209
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
210
211
slen = sizeof(addr);
212
error = getsockname(sds[0], (struct sockaddr *)&addr, &slen);
213
ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s",
214
strerror(errno));
215
ATF_REQUIRE_MSG(slen == sizeof(addr), "sockaddr size changed");
216
port = addr.sin6_port;
217
218
memset(&addr, 0, sizeof(addr));
219
addr.sin6_len = sizeof(addr);
220
addr.sin6_family = AF_INET6;
221
addr.sin6_port = port;
222
addr.sin6_addr = loopback6;
223
for (i = 1; i < nitems(sds); i++) {
224
sds[i] = lb_listen_socket(PF_INET6, SOCK_NONBLOCK);
225
226
error = bind(sds[i], (const struct sockaddr *)&addr,
227
sizeof(addr));
228
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s",
229
strerror(errno));
230
error = listen(sds[i], 1);
231
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s",
232
strerror(errno));
233
}
234
235
lb_simple_accept_loop(PF_INET6, (struct sockaddr *)&addr, sds,
236
nitems(sds), nconns);
237
for (i = 0; i < nitems(sds); i++) {
238
error = close(sds[i]);
239
ATF_REQUIRE_MSG(error == 0, "close() failed: %s",
240
strerror(errno));
241
}
242
}
243
244
struct concurrent_add_softc {
245
struct sockaddr_storage ss;
246
int socks[128];
247
int kq;
248
};
249
250
static void *
251
listener(void *arg)
252
{
253
for (struct concurrent_add_softc *sc = arg;;) {
254
struct kevent kev;
255
ssize_t n;
256
int error, count, cs, s;
257
uint8_t b;
258
259
count = kevent(sc->kq, NULL, 0, &kev, 1, NULL);
260
ATF_REQUIRE_MSG(count == 1,
261
"kevent() failed: %s", strerror(errno));
262
263
s = (int)kev.ident;
264
cs = accept(s, NULL, NULL);
265
ATF_REQUIRE_MSG(cs >= 0,
266
"accept() failed: %s", strerror(errno));
267
268
b = 'M';
269
n = write(cs, &b, sizeof(b));
270
ATF_REQUIRE_MSG(n >= 0, "write() failed: %s", strerror(errno));
271
ATF_REQUIRE(n == 1);
272
273
error = close(cs);
274
ATF_REQUIRE_MSG(error == 0 || errno == ECONNRESET,
275
"close() failed: %s", strerror(errno));
276
}
277
}
278
279
static void *
280
connector(void *arg)
281
{
282
for (struct concurrent_add_softc *sc = arg;;) {
283
ssize_t n;
284
int error, s;
285
uint8_t b;
286
287
s = socket(sc->ss.ss_family, SOCK_STREAM, 0);
288
ATF_REQUIRE_MSG(s >= 0, "socket() failed: %s", strerror(errno));
289
290
error = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (int[]){1},
291
sizeof(int));
292
293
error = connect(s, (struct sockaddr *)&sc->ss, sc->ss.ss_len);
294
ATF_REQUIRE_MSG(error == 0, "connect() failed: %s",
295
strerror(errno));
296
297
n = read(s, &b, sizeof(b));
298
ATF_REQUIRE_MSG(n >= 0, "read() failed: %s",
299
strerror(errno));
300
ATF_REQUIRE(n == 1);
301
ATF_REQUIRE(b == 'M');
302
error = close(s);
303
ATF_REQUIRE_MSG(error == 0,
304
"close() failed: %s", strerror(errno));
305
}
306
}
307
308
/*
309
* Run three threads. One accepts connections from listening sockets on a
310
* kqueue, while the other makes connections. The third thread slowly adds
311
* sockets to the LB group. This is meant to help flush out race conditions.
312
*/
313
ATF_TC_WITHOUT_HEAD(concurrent_add);
314
ATF_TC_BODY(concurrent_add, tc)
315
{
316
struct concurrent_add_softc sc;
317
struct sockaddr_in *sin;
318
pthread_t threads[4];
319
int error;
320
321
sc.kq = kqueue();
322
ATF_REQUIRE_MSG(sc.kq >= 0, "kqueue() failed: %s", strerror(errno));
323
324
error = pthread_create(&threads[0], NULL, listener, &sc);
325
ATF_REQUIRE_MSG(error == 0, "pthread_create() failed: %s",
326
strerror(error));
327
328
sin = (struct sockaddr_in *)&sc.ss;
329
memset(sin, 0, sizeof(*sin));
330
sin->sin_len = sizeof(*sin);
331
sin->sin_family = AF_INET;
332
sin->sin_port = htons(0);
333
sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
334
335
for (size_t i = 0; i < nitems(sc.socks); i++) {
336
struct kevent kev;
337
int s;
338
339
sc.socks[i] = s = socket(AF_INET, SOCK_STREAM, 0);
340
ATF_REQUIRE_MSG(s >= 0, "socket() failed: %s", strerror(errno));
341
342
error = setsockopt(s, SOL_SOCKET, SO_REUSEPORT_LB, (int[]){1},
343
sizeof(int));
344
ATF_REQUIRE_MSG(error == 0,
345
"setsockopt(SO_REUSEPORT_LB) failed: %s", strerror(errno));
346
347
error = bind(s, (struct sockaddr *)sin, sizeof(*sin));
348
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s",
349
strerror(errno));
350
351
error = listen(s, 5);
352
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s",
353
strerror(errno));
354
355
EV_SET(&kev, s, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
356
error = kevent(sc.kq, &kev, 1, NULL, 0, NULL);
357
ATF_REQUIRE_MSG(error == 0, "kevent() failed: %s",
358
strerror(errno));
359
360
if (i == 0) {
361
socklen_t slen = sizeof(sc.ss);
362
363
error = getsockname(sc.socks[i],
364
(struct sockaddr *)&sc.ss, &slen);
365
ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s",
366
strerror(errno));
367
ATF_REQUIRE(sc.ss.ss_family == AF_INET);
368
369
for (size_t j = 1; j < nitems(threads); j++) {
370
error = pthread_create(&threads[j], NULL,
371
connector, &sc);
372
ATF_REQUIRE_MSG(error == 0,
373
"pthread_create() failed: %s",
374
strerror(error));
375
}
376
}
377
378
usleep(20000);
379
}
380
381
for (size_t j = nitems(threads); j > 0; j--) {
382
ATF_REQUIRE(pthread_cancel(threads[j - 1]) == 0);
383
ATF_REQUIRE(pthread_join(threads[j - 1], NULL) == 0);
384
}
385
}
386
387
/*
388
* Try calling listen(2) twice on a socket with SO_REUSEPORT_LB set.
389
*/
390
ATF_TC_WITHOUT_HEAD(double_listen_ipv4);
391
ATF_TC_BODY(double_listen_ipv4, tc)
392
{
393
struct sockaddr_in sin;
394
int error, s;
395
396
s = lb_listen_socket(PF_INET, 0);
397
398
memset(&sin, 0, sizeof(sin));
399
sin.sin_len = sizeof(sin);
400
sin.sin_family = AF_INET;
401
sin.sin_port = htons(0);
402
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
403
error = bind(s, (struct sockaddr *)&sin, sizeof(sin));
404
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
405
406
error = listen(s, 1);
407
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
408
error = listen(s, 2);
409
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
410
411
error = close(s);
412
ATF_REQUIRE_MSG(error == 0, "close() failed: %s", strerror(errno));
413
}
414
415
/*
416
* Try calling listen(2) twice on a socket with SO_REUSEPORT_LB set.
417
*/
418
ATF_TC_WITHOUT_HEAD(double_listen_ipv6);
419
ATF_TC_BODY(double_listen_ipv6, tc)
420
{
421
struct sockaddr_in6 sin6;
422
int error, s;
423
424
s = lb_listen_socket(PF_INET6, 0);
425
426
memset(&sin6, 0, sizeof(sin6));
427
sin6.sin6_len = sizeof(sin6);
428
sin6.sin6_family = AF_INET6;
429
sin6.sin6_port = htons(0);
430
sin6.sin6_addr = in6addr_loopback;
431
error = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
432
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
433
434
error = listen(s, 1);
435
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
436
error = listen(s, 2);
437
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
438
439
error = close(s);
440
ATF_REQUIRE_MSG(error == 0, "close() failed: %s", strerror(errno));
441
}
442
443
/*
444
* Try binding many sockets to the same lbgroup without calling listen(2) on
445
* them.
446
*/
447
ATF_TC_WITHOUT_HEAD(bind_without_listen);
448
ATF_TC_BODY(bind_without_listen, tc)
449
{
450
const int nsockets = 100;
451
struct sockaddr_in sin;
452
socklen_t socklen;
453
int error, s, s2[nsockets];
454
455
s = lb_listen_socket(PF_INET, 0);
456
457
memset(&sin, 0, sizeof(sin));
458
sin.sin_len = sizeof(sin);
459
sin.sin_family = AF_INET;
460
sin.sin_port = htons(0);
461
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
462
error = bind(s, (struct sockaddr *)&sin, sizeof(sin));
463
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
464
465
socklen = sizeof(sin);
466
error = getsockname(s, (struct sockaddr *)&sin, &socklen);
467
ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s",
468
strerror(errno));
469
470
for (int i = 0; i < nsockets; i++) {
471
s2[i] = lb_listen_socket(PF_INET, 0);
472
error = bind(s2[i], (struct sockaddr *)&sin, sizeof(sin));
473
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
474
}
475
for (int i = 0; i < nsockets; i++) {
476
error = listen(s2[i], 1);
477
ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno));
478
}
479
for (int i = 0; i < nsockets; i++) {
480
error = close(s2[i]);
481
ATF_REQUIRE_MSG(error == 0, "close() failed: %s", strerror(errno));
482
}
483
484
error = close(s);
485
ATF_REQUIRE_MSG(error == 0, "close() failed: %s", strerror(errno));
486
}
487
488
/*
489
* Check that SO_REUSEPORT_LB doesn't mess with connect(2).
490
* Two sockets:
491
* 1) auxiliary peer socket 'p', where we connect to
492
* 2) test socket 's', that sets SO_REUSEPORT_LB and then connect(2)s to 'p'
493
*/
494
ATF_TC_WITHOUT_HEAD(connect_not_bound);
495
ATF_TC_BODY(connect_not_bound, tc)
496
{
497
struct sockaddr_in sin = {
498
.sin_family = AF_INET,
499
.sin_len = sizeof(sin),
500
.sin_addr = { htonl(INADDR_LOOPBACK) },
501
};
502
socklen_t slen = sizeof(struct sockaddr_in);
503
int p, s, rv;
504
505
ATF_REQUIRE((p = socket(PF_INET, SOCK_STREAM, 0)) > 0);
506
ATF_REQUIRE(bind(p, (struct sockaddr *)&sin, sizeof(sin)) == 0);
507
ATF_REQUIRE(listen(p, 1) == 0);
508
ATF_REQUIRE(getsockname(p, (struct sockaddr *)&sin, &slen) == 0);
509
510
s = lb_listen_socket(PF_INET, 0);
511
rv = connect(s, (struct sockaddr *)&sin, sizeof(sin));
512
ATF_REQUIRE_MSG(rv == -1 && errno == EOPNOTSUPP,
513
"Expected EOPNOTSUPP on connect(2) not met. Got %d, errno %d",
514
rv, errno);
515
rv = sendto(s, "test", 4, 0, (struct sockaddr *)&sin,
516
sizeof(sin));
517
ATF_REQUIRE_MSG(rv == -1 && errno == EOPNOTSUPP,
518
"Expected EOPNOTSUPP on sendto(2) not met. Got %d, errno %d",
519
rv, errno);
520
521
close(p);
522
close(s);
523
}
524
525
/*
526
* Same as above, but we also bind(2) between setsockopt(2) of SO_REUSEPORT_LB
527
* and the connect(2).
528
*/
529
ATF_TC_WITHOUT_HEAD(connect_bound);
530
ATF_TC_BODY(connect_bound, tc)
531
{
532
struct sockaddr_in sin = {
533
.sin_family = AF_INET,
534
.sin_len = sizeof(sin),
535
.sin_addr = { htonl(INADDR_LOOPBACK) },
536
};
537
socklen_t slen = sizeof(struct sockaddr_in);
538
int p, s, rv;
539
540
ATF_REQUIRE((p = socket(PF_INET, SOCK_STREAM, 0)) > 0);
541
ATF_REQUIRE(bind(p, (struct sockaddr *)&sin, sizeof(sin)) == 0);
542
ATF_REQUIRE(listen(p, 1) == 0);
543
544
s = lb_listen_socket(PF_INET, 0);
545
ATF_REQUIRE(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0);
546
ATF_REQUIRE(getsockname(p, (struct sockaddr *)&sin, &slen) == 0);
547
rv = connect(s, (struct sockaddr *)&sin, sizeof(sin));
548
ATF_REQUIRE_MSG(rv == -1 && errno == EOPNOTSUPP,
549
"Expected EOPNOTSUPP on connect(2) not met. Got %d, errno %d",
550
rv, errno);
551
rv = sendto(s, "test", 4, 0, (struct sockaddr *)&sin,
552
sizeof(sin));
553
ATF_REQUIRE_MSG(rv == -1 && errno == EOPNOTSUPP,
554
"Expected EOPNOTSUPP on sendto(2) not met. Got %d, errno %d",
555
rv, errno);
556
557
close(p);
558
close(s);
559
}
560
561
/*
562
* The kernel erroneously permits calling connect() on a UDP socket with
563
* SO_REUSEPORT_LB set. Verify that packets sent to the bound address are
564
* dropped unless they come from the connected address.
565
*/
566
ATF_TC_WITHOUT_HEAD(connect_udp);
567
ATF_TC_BODY(connect_udp, tc)
568
{
569
struct sockaddr_in sin = {
570
.sin_family = AF_INET,
571
.sin_len = sizeof(sin),
572
.sin_addr = { htonl(INADDR_LOOPBACK) },
573
};
574
ssize_t n;
575
int error, len, s1, s2, s3;
576
char ch;
577
578
s1 = socket(PF_INET, SOCK_DGRAM, 0);
579
ATF_REQUIRE(s1 >= 0);
580
s2 = socket(PF_INET, SOCK_DGRAM, 0);
581
ATF_REQUIRE(s2 >= 0);
582
s3 = socket(PF_INET, SOCK_DGRAM, 0);
583
ATF_REQUIRE(s3 >= 0);
584
585
error = setsockopt(s1, SOL_SOCKET, SO_REUSEPORT_LB, (int[]){1},
586
sizeof(int));
587
ATF_REQUIRE_MSG(error == 0,
588
"setsockopt(SO_REUSEPORT_LB) failed: %s", strerror(errno));
589
error = bind(s1, (struct sockaddr *)&sin, sizeof(sin));
590
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
591
592
error = bind(s2, (struct sockaddr *)&sin, sizeof(sin));
593
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
594
595
error = bind(s3, (struct sockaddr *)&sin, sizeof(sin));
596
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
597
598
/* Connect to an address not owned by s2. */
599
error = getsockname(s3, (struct sockaddr *)&sin,
600
(socklen_t[]){sizeof(sin)});
601
ATF_REQUIRE(error == 0);
602
error = connect(s1, (struct sockaddr *)&sin, sizeof(sin));
603
ATF_REQUIRE_MSG(error == 0, "connect() failed: %s", strerror(errno));
604
605
/* Try to send a packet to s1 from s2. */
606
error = getsockname(s1, (struct sockaddr *)&sin,
607
(socklen_t[]){sizeof(sin)});
608
ATF_REQUIRE(error == 0);
609
610
ch = 42;
611
n = sendto(s2, &ch, sizeof(ch), 0, (struct sockaddr *)&sin,
612
sizeof(sin));
613
ATF_REQUIRE(n == 1);
614
615
/* Give the packet some time to arrive. */
616
usleep(100000);
617
618
/* s1 is connected to s3 and shouldn't receive from s2. */
619
error = ioctl(s1, FIONREAD, &len);
620
ATF_REQUIRE(error == 0);
621
ATF_REQUIRE_MSG(len == 0, "unexpected data available");
622
623
/* ... but s3 can of course send to s1. */
624
n = sendto(s3, &ch, sizeof(ch), 0, (struct sockaddr *)&sin,
625
sizeof(sin));
626
ATF_REQUIRE(n == 1);
627
usleep(100000);
628
error = ioctl(s1, FIONREAD, &len);
629
ATF_REQUIRE(error == 0);
630
ATF_REQUIRE_MSG(len == 1, "expected data available");
631
}
632
633
/*
634
* The kernel erroneously permits calling connect() on a UDP socket with
635
* SO_REUSEPORT_LB set. Verify that packets sent to the bound address are
636
* dropped unless they come from the connected address.
637
*/
638
ATF_TC_WITHOUT_HEAD(connect_udp6);
639
ATF_TC_BODY(connect_udp6, tc)
640
{
641
struct sockaddr_in6 sin6 = {
642
.sin6_family = AF_INET6,
643
.sin6_len = sizeof(sin6),
644
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
645
};
646
ssize_t n;
647
int error, len, s1, s2, s3;
648
char ch;
649
650
s1 = socket(PF_INET6, SOCK_DGRAM, 0);
651
ATF_REQUIRE(s1 >= 0);
652
s2 = socket(PF_INET6, SOCK_DGRAM, 0);
653
ATF_REQUIRE(s2 >= 0);
654
s3 = socket(PF_INET6, SOCK_DGRAM, 0);
655
ATF_REQUIRE(s3 >= 0);
656
657
error = setsockopt(s1, SOL_SOCKET, SO_REUSEPORT_LB, (int[]){1},
658
sizeof(int));
659
ATF_REQUIRE_MSG(error == 0,
660
"setsockopt(SO_REUSEPORT_LB) failed: %s", strerror(errno));
661
error = bind(s1, (struct sockaddr *)&sin6, sizeof(sin6));
662
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
663
664
error = bind(s2, (struct sockaddr *)&sin6, sizeof(sin6));
665
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
666
667
error = bind(s3, (struct sockaddr *)&sin6, sizeof(sin6));
668
ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno));
669
670
/* Connect to an address not owned by s2. */
671
error = getsockname(s3, (struct sockaddr *)&sin6,
672
(socklen_t[]){sizeof(sin6)});
673
ATF_REQUIRE(error == 0);
674
error = connect(s1, (struct sockaddr *)&sin6, sizeof(sin6));
675
ATF_REQUIRE_MSG(error == 0, "connect() failed: %s", strerror(errno));
676
677
/* Try to send a packet to s1 from s2. */
678
error = getsockname(s1, (struct sockaddr *)&sin6,
679
(socklen_t[]){sizeof(sin6)});
680
ATF_REQUIRE(error == 0);
681
682
ch = 42;
683
n = sendto(s2, &ch, sizeof(ch), 0, (struct sockaddr *)&sin6,
684
sizeof(sin6));
685
ATF_REQUIRE(n == 1);
686
687
/* Give the packet some time to arrive. */
688
usleep(100000);
689
690
/* s1 is connected to s3 and shouldn't receive from s2. */
691
error = ioctl(s1, FIONREAD, &len);
692
ATF_REQUIRE(error == 0);
693
ATF_REQUIRE_MSG(len == 0, "unexpected data available");
694
695
/* ... but s3 can of course send to s1. */
696
n = sendto(s3, &ch, sizeof(ch), 0, (struct sockaddr *)&sin6,
697
sizeof(sin6));
698
ATF_REQUIRE(n == 1);
699
usleep(100000);
700
error = ioctl(s1, FIONREAD, &len);
701
ATF_REQUIRE(error == 0);
702
ATF_REQUIRE_MSG(len == 1, "expected data available");
703
}
704
705
ATF_TP_ADD_TCS(tp)
706
{
707
ATF_TP_ADD_TC(tp, basic_ipv4);
708
ATF_TP_ADD_TC(tp, basic_ipv6);
709
ATF_TP_ADD_TC(tp, concurrent_add);
710
ATF_TP_ADD_TC(tp, double_listen_ipv4);
711
ATF_TP_ADD_TC(tp, double_listen_ipv6);
712
ATF_TP_ADD_TC(tp, bind_without_listen);
713
ATF_TP_ADD_TC(tp, connect_not_bound);
714
ATF_TP_ADD_TC(tp, connect_bound);
715
ATF_TP_ADD_TC(tp, connect_udp);
716
ATF_TP_ADD_TC(tp, connect_udp6);
717
718
return (atf_no_error());
719
}
720
721