Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netinet/fibs_multibind_test.c
39483 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2024-2025 Stormshield
5
*/
6
7
#include <sys/types.h>
8
#include <sys/ioctl.h>
9
#include <sys/socket.h>
10
#include <sys/sysctl.h>
11
12
#include <netinet/in.h>
13
#include <netinet/ip.h>
14
#include <netinet/ip6.h>
15
#include <netinet/ip_icmp.h>
16
#include <netinet/icmp6.h>
17
18
#include <errno.h>
19
#include <fcntl.h>
20
#include <pwd.h>
21
#include <stdio.h>
22
#include <string.h>
23
24
#include <atf-c.h>
25
26
#define MAKETEST_TCP(name) \
27
ATF_TC_WITHOUT_HEAD(name ## _tcp); \
28
ATF_TC_BODY(name ## _tcp, tc) \
29
{ \
30
name(PF_INET, SOCK_STREAM, tc); \
31
} \
32
ATF_TC_WITHOUT_HEAD(name ## _tcp6); \
33
ATF_TC_BODY(name ## _tcp6, tc) \
34
{ \
35
name(PF_INET6, SOCK_STREAM, tc); \
36
}
37
#define MAKETEST_UDP(name) \
38
ATF_TC_WITHOUT_HEAD(name ## _udp); \
39
ATF_TC_BODY(name ## _udp, tc) \
40
{ \
41
name(PF_INET, SOCK_DGRAM, tc); \
42
} \
43
ATF_TC_WITHOUT_HEAD(name ## _udp6); \
44
ATF_TC_BODY(name ## _udp6, tc) \
45
{ \
46
name(PF_INET6, SOCK_DGRAM, tc); \
47
}
48
#define MAKETEST_RAW(name) \
49
ATF_TC(name ## _raw); \
50
ATF_TC_HEAD(name ## _raw, tc) \
51
{ \
52
atf_tc_set_md_var(tc, "require.user", \
53
"root"); \
54
} \
55
ATF_TC_BODY(name ## _raw, tc) \
56
{ \
57
name(PF_INET, SOCK_RAW, tc); \
58
} \
59
ATF_TC(name ## _raw6); \
60
ATF_TC_HEAD(name ## _raw6, tc) \
61
{ \
62
atf_tc_set_md_var(tc, "require.user", \
63
"root"); \
64
} \
65
ATF_TC_BODY(name ## _raw6, tc) \
66
{ \
67
name(PF_INET6, SOCK_RAW, tc); \
68
}
69
70
#define MAKETEST(name) \
71
MAKETEST_TCP(name) \
72
MAKETEST_UDP(name)
73
74
#define LISTTEST_TCP(name) \
75
ATF_TP_ADD_TC(tp, name ## _tcp); \
76
ATF_TP_ADD_TC(tp, name ## _tcp6);
77
#define LISTTEST_UDP(name) \
78
ATF_TP_ADD_TC(tp, name ## _udp); \
79
ATF_TP_ADD_TC(tp, name ## _udp6);
80
#define LISTTEST_RAW(name) \
81
ATF_TP_ADD_TC(tp, name ## _raw); \
82
ATF_TP_ADD_TC(tp, name ## _raw6);
83
#define LISTTEST(name) \
84
LISTTEST_TCP(name) \
85
LISTTEST_UDP(name)
86
87
static void
88
checked_close(int s)
89
{
90
int error;
91
92
error = close(s);
93
ATF_REQUIRE_MSG(error == 0, "close failed: %s", strerror(errno));
94
}
95
96
static int
97
mksockp(int domain, int type, int fib, int proto)
98
{
99
int error, s;
100
101
s = socket(domain, type, proto);
102
ATF_REQUIRE(s != -1);
103
error = setsockopt(s, SOL_SOCKET, SO_SETFIB, &fib, sizeof(fib));
104
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
105
106
return (s);
107
}
108
109
static int
110
mksock(int domain, int type, int fib)
111
{
112
return (mksockp(domain, type, fib, 0));
113
}
114
115
static void
116
require_fibs_multibind(int socktype, int minfibs)
117
{
118
const char *sysctl;
119
size_t sz;
120
int error, fibs, multibind;
121
122
fibs = 0;
123
sz = sizeof(fibs);
124
error = sysctlbyname("net.fibs", &fibs, &sz, NULL, 0);
125
ATF_REQUIRE_MSG(error == 0, "sysctlbyname failed: %s", strerror(errno));
126
ATF_REQUIRE_MSG(fibs >= 1, "strange FIB count %d", fibs);
127
if (fibs == 1)
128
atf_tc_skip("multiple FIBs not enabled");
129
if (fibs < minfibs)
130
atf_tc_skip("not enough FIBs, need %d", minfibs);
131
132
switch (socktype) {
133
case SOCK_STREAM:
134
sysctl = "net.inet.tcp.bind_all_fibs";
135
break;
136
case SOCK_DGRAM:
137
sysctl = "net.inet.udp.bind_all_fibs";
138
break;
139
case SOCK_RAW:
140
sysctl = "net.inet.raw.bind_all_fibs";
141
break;
142
default:
143
atf_tc_fail("unknown socket type %d", socktype);
144
break;
145
}
146
147
multibind = -1;
148
sz = sizeof(multibind);
149
error = sysctlbyname(sysctl, &multibind, &sz, NULL, 0);
150
ATF_REQUIRE_MSG(error == 0, "sysctlbyname failed: %s", strerror(errno));
151
if (multibind != 0)
152
atf_tc_skip("FIB multibind not configured (%s)", sysctl);
153
}
154
155
/*
156
* Make sure that different users can't bind to the same port from different
157
* FIBs.
158
*/
159
static void
160
multibind_different_user(int domain, int type, const atf_tc_t *tc)
161
{
162
struct sockaddr_storage ss;
163
struct passwd *passwd;
164
const char *user;
165
socklen_t sslen;
166
int error, s[2];
167
168
if (geteuid() != 0)
169
atf_tc_skip("need root privileges");
170
if (!atf_tc_has_config_var(tc, "unprivileged_user"))
171
atf_tc_skip("unprivileged_user not set");
172
173
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
174
sslen = domain == PF_INET ? sizeof(struct sockaddr_in) :
175
sizeof(struct sockaddr_in6);
176
177
require_fibs_multibind(type, 2);
178
179
s[0] = mksock(domain, type, 0);
180
181
memset(&ss, 0, sizeof(ss));
182
ss.ss_family = domain;
183
ss.ss_len = sslen;
184
error = bind(s[0], (struct sockaddr *)&ss, sslen);
185
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
186
187
error = getsockname(s[0], (struct sockaddr *)&ss, &sslen);
188
ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
189
190
/*
191
* Create a second socket in a different FIB, and bind it to the same
192
* address/port tuple. This should succeed if done as the same user as
193
* the first socket, and should fail otherwise.
194
*/
195
s[1] = mksock(domain, type, 1);
196
error = bind(s[1], (struct sockaddr *)&ss, sslen);
197
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
198
ATF_REQUIRE_MSG(close(s[1]) == 0, "close failed: %s", strerror(errno));
199
200
user = atf_tc_get_config_var(tc, "unprivileged_user");
201
passwd = getpwnam(user);
202
ATF_REQUIRE(passwd != NULL);
203
error = seteuid(passwd->pw_uid);
204
ATF_REQUIRE_MSG(error == 0, "seteuid failed: %s", strerror(errno));
205
206
/* Repeat the bind as a different user. */
207
s[1] = mksock(domain, type, 1);
208
error = bind(s[1], (struct sockaddr *)&ss, sslen);
209
ATF_REQUIRE_ERRNO(EADDRINUSE, error == -1);
210
ATF_REQUIRE_MSG(close(s[1]) == 0, "close failed: %s", strerror(errno));
211
}
212
MAKETEST(multibind_different_user);
213
214
/*
215
* Verify that a listening socket only accepts connections originating from the
216
* same FIB.
217
*/
218
static void
219
per_fib_listening_socket(int domain, int type, const atf_tc_t *tc __unused)
220
{
221
struct sockaddr_storage ss;
222
socklen_t sslen;
223
int cs1, cs2, error, fib1, fib2, ls1, ls2, ns;
224
225
ATF_REQUIRE(type == SOCK_STREAM);
226
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
227
require_fibs_multibind(type, 2);
228
229
fib1 = 0;
230
fib2 = 1;
231
232
ls1 = mksock(domain, type, fib1);
233
ls2 = mksock(domain, type, fib2);
234
235
sslen = domain == PF_INET ? sizeof(struct sockaddr_in) :
236
sizeof(struct sockaddr_in6);
237
238
memset(&ss, 0, sizeof(ss));
239
ss.ss_family = domain;
240
ss.ss_len = sslen;
241
error = bind(ls1, (struct sockaddr *)&ss, sslen);
242
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
243
244
error = getsockname(ls1, (struct sockaddr *)&ss, &sslen);
245
ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
246
247
error = listen(ls1, 5);
248
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
249
250
cs1 = mksock(domain, type, fib1);
251
cs2 = mksock(domain, type, fib2);
252
253
/*
254
* Make sure we can connect from the same FIB.
255
*/
256
error = connect(cs1, (struct sockaddr *)&ss, sslen);
257
ATF_REQUIRE_MSG(error == 0, "connect failed: %s", strerror(errno));
258
ns = accept(ls1, NULL, NULL);
259
ATF_REQUIRE_MSG(ns != -1, "accept failed: %s", strerror(errno));
260
checked_close(ns);
261
checked_close(cs1);
262
cs1 = mksock(domain, type, fib1);
263
264
/*
265
* ... but not from a different FIB.
266
*/
267
error = connect(cs2, (struct sockaddr *)&ss, sslen);
268
ATF_REQUIRE_MSG(error == -1, "connect succeeded unexpectedly");
269
ATF_REQUIRE_MSG(errno == ECONNREFUSED, "unexpected error %d", errno);
270
checked_close(cs2);
271
cs2 = mksock(domain, type, fib2);
272
273
/*
274
* ... but if there are multiple listening sockets, we always connect to
275
* the same FIB.
276
*/
277
error = bind(ls2, (struct sockaddr *)&ss, sslen);
278
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
279
error = listen(ls2, 5);
280
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
281
282
for (int i = 0; i < 10; i++) {
283
error = connect(cs1, (struct sockaddr *)&ss, sslen);
284
ATF_REQUIRE_MSG(error == 0, "connect failed: %s",
285
strerror(errno));
286
ns = accept(ls1, NULL, NULL);
287
ATF_REQUIRE_MSG(ns != -1, "accept failed: %s", strerror(errno));
288
289
checked_close(ns);
290
checked_close(cs1);
291
cs1 = mksock(domain, type, fib1);
292
}
293
for (int i = 0; i < 10; i++) {
294
error = connect(cs2, (struct sockaddr *)&ss, sslen);
295
ATF_REQUIRE_MSG(error == 0, "connect failed: %s",
296
strerror(errno));
297
ns = accept(ls2, NULL, NULL);
298
ATF_REQUIRE_MSG(ns != -1, "accept failed: %s", strerror(errno));
299
300
checked_close(ns);
301
checked_close(cs2);
302
cs2 = mksock(domain, type, fib2);
303
}
304
305
/*
306
* ... and if we close one of the listening sockets, we're back to only
307
* being able to connect from the same FIB.
308
*/
309
checked_close(ls1);
310
error = connect(cs1, (struct sockaddr *)&ss, sslen);
311
ATF_REQUIRE_MSG(error == -1, "connect succeeded unexpectedly");
312
ATF_REQUIRE_MSG(errno == ECONNREFUSED, "unexpected error %d", errno);
313
checked_close(cs1);
314
315
error = connect(cs2, (struct sockaddr *)&ss, sslen);
316
ATF_REQUIRE_MSG(error == 0, "connect failed: %s", strerror(errno));
317
ns = accept(ls2, NULL, NULL);
318
ATF_REQUIRE_MSG(ns != -1, "accept failed: %s", strerror(errno));
319
checked_close(ns);
320
checked_close(cs2);
321
checked_close(ls2);
322
}
323
MAKETEST_TCP(per_fib_listening_socket);
324
325
/*
326
* Verify that a bound datagram socket only accepts data from the same FIB.
327
*/
328
static void
329
per_fib_dgram_socket(int domain, int type, const atf_tc_t *tc __unused)
330
{
331
struct sockaddr_storage ss;
332
struct sockaddr_in6 *sin6p;
333
socklen_t sslen;
334
ssize_t n;
335
int error, cs1, cs2, fib1, fib2, ss1, ss2;
336
char b;
337
338
ATF_REQUIRE(type == SOCK_DGRAM);
339
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
340
require_fibs_multibind(type, 2);
341
342
fib1 = 0;
343
fib2 = 1;
344
345
cs1 = mksock(domain, type, fib1);
346
cs2 = mksock(domain, type, fib2);
347
348
ss1 = mksock(domain, type, fib1);
349
ss2 = mksock(domain, type, fib2);
350
351
sslen = domain == PF_INET ? sizeof(struct sockaddr_in) :
352
sizeof(struct sockaddr_in6);
353
354
memset(&ss, 0, sizeof(ss));
355
ss.ss_family = domain;
356
ss.ss_len = sslen;
357
error = bind(ss1, (struct sockaddr *)&ss, sslen);
358
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
359
360
error = getsockname(ss1, (struct sockaddr *)&ss, &sslen);
361
ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
362
363
if (domain == PF_INET6) {
364
sin6p = (struct sockaddr_in6 *)&ss;
365
sin6p->sin6_addr = in6addr_loopback;
366
}
367
368
/* If we send a byte from cs1, it should be recieved by ss1. */
369
b = 42;
370
n = sendto(cs1, &b, sizeof(b), 0, (struct sockaddr *)&ss, sslen);
371
ATF_REQUIRE_MSG(n == 1, "sendto failed: %s", strerror(errno));
372
n = recv(ss1, &b, sizeof(b), 0);
373
ATF_REQUIRE(n == 1);
374
ATF_REQUIRE(b == 42);
375
376
/* If we send a byte from cs2, it should not be received by ss1. */
377
b = 42;
378
n = sendto(cs2, &b, sizeof(b), 0, (struct sockaddr *)&ss, sslen);
379
ATF_REQUIRE_MSG(n == 1, "sendto failed: %s", strerror(errno));
380
usleep(10000);
381
n = recv(ss1, &b, sizeof(b), MSG_DONTWAIT);
382
ATF_REQUIRE_ERRNO(EWOULDBLOCK, n == -1);
383
384
error = bind(ss2, (struct sockaddr *)&ss, sslen);
385
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
386
387
/* Repeat now that ss2 is bound. */
388
b = 42;
389
n = sendto(cs1, &b, sizeof(b), 0, (struct sockaddr *)&ss, sslen);
390
ATF_REQUIRE_MSG(n == 1, "sendto failed: %s", strerror(errno));
391
n = recv(ss1, &b, sizeof(b), 0);
392
ATF_REQUIRE(n == 1);
393
ATF_REQUIRE(b == 42);
394
395
b = 42;
396
n = sendto(cs2, &b, sizeof(b), 0, (struct sockaddr *)&ss, sslen);
397
ATF_REQUIRE_MSG(n == 1, "sendto failed: %s", strerror(errno));
398
n = recv(ss2, &b, sizeof(b), 0);
399
ATF_REQUIRE(n == 1);
400
ATF_REQUIRE(b == 42);
401
402
checked_close(ss1);
403
checked_close(ss2);
404
checked_close(cs1);
405
checked_close(cs2);
406
}
407
MAKETEST_UDP(per_fib_dgram_socket);
408
409
static size_t
410
ping(int s, const struct sockaddr *sa, socklen_t salen)
411
{
412
struct {
413
struct icmphdr icmp;
414
char data[64];
415
} icmp;
416
ssize_t n;
417
418
memset(&icmp, 0, sizeof(icmp));
419
icmp.icmp.icmp_type = ICMP_ECHO;
420
icmp.icmp.icmp_code = 0;
421
icmp.icmp.icmp_cksum = htons((unsigned short)~(ICMP_ECHO << 8));
422
n = sendto(s, &icmp, sizeof(icmp), 0, sa, salen);
423
ATF_REQUIRE_MSG(n == (ssize_t)sizeof(icmp), "sendto failed: %s",
424
strerror(errno));
425
426
return (sizeof(icmp) + sizeof(struct ip));
427
}
428
429
static size_t
430
ping6(int s, const struct sockaddr *sa, socklen_t salen)
431
{
432
struct {
433
struct icmp6_hdr icmp6;
434
char data[64];
435
} icmp6;
436
ssize_t n;
437
438
memset(&icmp6, 0, sizeof(icmp6));
439
icmp6.icmp6.icmp6_type = ICMP6_ECHO_REQUEST;
440
icmp6.icmp6.icmp6_code = 0;
441
icmp6.icmp6.icmp6_cksum =
442
htons((unsigned short)~(ICMP6_ECHO_REQUEST << 8));
443
n = sendto(s, &icmp6, sizeof(icmp6), 0, sa, salen);
444
ATF_REQUIRE_MSG(n == (ssize_t)sizeof(icmp6), "sendto failed: %s",
445
strerror(errno));
446
447
return (sizeof(icmp6));
448
}
449
450
static void
451
per_fib_raw_socket(int domain, int type, const atf_tc_t *tc __unused)
452
{
453
struct sockaddr_in sin;
454
struct sockaddr_in6 sin6;
455
ssize_t n;
456
size_t sz;
457
int error, cs, s[2], proto;
458
uint8_t b[256];
459
460
ATF_REQUIRE(type == SOCK_RAW);
461
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
462
require_fibs_multibind(type, 2);
463
464
proto = domain == PF_INET ? IPPROTO_ICMP : IPPROTO_ICMPV6;
465
s[0] = mksockp(domain, type, 0, proto);
466
s[1] = mksockp(domain, type, 1, proto);
467
468
if (domain == PF_INET) {
469
memset(&sin, 0, sizeof(sin));
470
sin.sin_family = domain;
471
sin.sin_len = sizeof(sin);
472
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
473
error = bind(s[0], (struct sockaddr *)&sin, sizeof(sin));
474
} else /* if (domain == PF_INET6) */ {
475
memset(&sin6, 0, sizeof(sin6));
476
sin6.sin6_family = domain;
477
sin6.sin6_len = sizeof(sin6);
478
sin6.sin6_addr = in6addr_loopback;
479
error = bind(s[0], (struct sockaddr *)&sin6, sizeof(sin6));
480
}
481
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
482
483
for (int i = 0; i < 2; i++) {
484
cs = mksockp(domain, type, i, proto);
485
if (domain == PF_INET) {
486
sz = ping(cs, (struct sockaddr *)&sin, sizeof(sin));
487
} else /* if (domain == PF_INET6) */ {
488
sz = ping6(cs, (struct sockaddr *)&sin6, sizeof(sin6));
489
}
490
n = recv(s[i], b, sizeof(b), 0);
491
ATF_REQUIRE_MSG(n > 0, "recv failed: %s", strerror(errno));
492
ATF_REQUIRE_MSG(n == (ssize_t)sz,
493
"short packet received: %zd", n);
494
495
if (domain == PF_INET6) {
496
/* Get the echo reply as well. */
497
n = recv(s[i], b, sizeof(b), 0);
498
ATF_REQUIRE_MSG(n > 0,
499
"recv failed: %s", strerror(errno));
500
ATF_REQUIRE_MSG(n == (ssize_t)sz,
501
"short packet received: %zd", n);
502
}
503
504
/* Make sure that the other socket didn't receive anything. */
505
n = recv(s[1 - i], b, sizeof(b), MSG_DONTWAIT);
506
printf("n = %zd i = %d\n", n, i);
507
ATF_REQUIRE_ERRNO(EWOULDBLOCK, n == -1);
508
509
checked_close(cs);
510
}
511
512
checked_close(s[0]);
513
checked_close(s[1]);
514
}
515
MAKETEST_RAW(per_fib_raw_socket);
516
517
/*
518
* Create a pair of load-balancing listening socket groups, one in each FIB, and
519
* make sure that connections to the group are only load-balanced within the
520
* same FIB.
521
*/
522
static void
523
multibind_lbgroup_stream(int domain, int type, const atf_tc_t *tc __unused)
524
{
525
struct sockaddr_storage ss;
526
socklen_t sslen;
527
int error, as, cs, s[3];
528
529
ATF_REQUIRE(type == SOCK_STREAM);
530
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
531
require_fibs_multibind(type, 2);
532
533
s[0] = mksock(domain, type, 0);
534
ATF_REQUIRE(setsockopt(s[0], SOL_SOCKET, SO_REUSEPORT_LB, &(int){1},
535
sizeof(int)) == 0);
536
ATF_REQUIRE(fcntl(s[0], F_SETFL, O_NONBLOCK) == 0);
537
s[1] = mksock(domain, type, 0);
538
ATF_REQUIRE(setsockopt(s[1], SOL_SOCKET, SO_REUSEPORT_LB, &(int){1},
539
sizeof(int)) == 0);
540
ATF_REQUIRE(fcntl(s[1], F_SETFL, O_NONBLOCK) == 0);
541
s[2] = mksock(domain, type, 1);
542
ATF_REQUIRE(setsockopt(s[2], SOL_SOCKET, SO_REUSEPORT_LB, &(int){1},
543
sizeof(int)) == 0);
544
545
sslen = domain == PF_INET ? sizeof(struct sockaddr_in) :
546
sizeof(struct sockaddr_in6);
547
memset(&ss, 0, sizeof(ss));
548
ss.ss_family = domain;
549
ss.ss_len = sslen;
550
error = bind(s[0], (struct sockaddr *)&ss, sslen);
551
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
552
error = listen(s[0], 5);
553
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
554
error = getsockname(s[0], (struct sockaddr *)&ss, &sslen);
555
ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
556
557
error = bind(s[1], (struct sockaddr *)&ss, sslen);
558
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
559
error = listen(s[1], 5);
560
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
561
562
error = bind(s[2], (struct sockaddr *)&ss, sslen);
563
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
564
error = listen(s[2], 5);
565
ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
566
567
/*
568
* Initiate connections from FIB 0, make sure they go to s[0] or s[1].
569
*/
570
for (int count = 0; count < 100; count++) {
571
cs = mksock(domain, type, 0);
572
error = connect(cs, (struct sockaddr *)&ss, sslen);
573
ATF_REQUIRE_MSG(error == 0, "connect failed: %s",
574
strerror(errno));
575
576
do {
577
as = accept(s[0], NULL, NULL);
578
if (as == -1) {
579
ATF_REQUIRE_MSG(errno == EWOULDBLOCK,
580
"accept failed: %s", strerror(errno));
581
as = accept(s[1], NULL, NULL);
582
if (as == -1) {
583
ATF_REQUIRE_MSG(errno == EWOULDBLOCK,
584
"accept failed: %s",
585
strerror(errno));
586
}
587
}
588
} while (as == -1);
589
checked_close(as);
590
checked_close(cs);
591
}
592
593
/*
594
* Initiate connections from FIB 1, make sure they go to s[2].
595
*/
596
for (int count = 0; count < 100; count++) {
597
cs = mksock(domain, type, 1);
598
error = connect(cs, (struct sockaddr *)&ss, sslen);
599
ATF_REQUIRE_MSG(error == 0, "connect failed: %s",
600
strerror(errno));
601
602
as = accept(s[2], NULL, NULL);
603
ATF_REQUIRE_MSG(as != -1, "accept failed: %s", strerror(errno));
604
checked_close(as);
605
checked_close(cs);
606
}
607
608
checked_close(s[0]);
609
checked_close(s[1]);
610
checked_close(s[2]);
611
}
612
MAKETEST_TCP(multibind_lbgroup_stream);
613
614
static void
615
multibind_lbgroup_dgram(int domain, int type, const atf_tc_t *tc __unused)
616
{
617
struct sockaddr_storage ss;
618
struct sockaddr_in6 *sin6p;
619
socklen_t sslen;
620
ssize_t n;
621
int error, cs, s[3];
622
char b;
623
624
ATF_REQUIRE(type == SOCK_DGRAM);
625
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
626
require_fibs_multibind(type, 2);
627
628
s[0] = mksock(domain, type, 0);
629
ATF_REQUIRE(setsockopt(s[0], SOL_SOCKET, SO_REUSEPORT_LB, &(int){1},
630
sizeof(int)) == 0);
631
s[1] = mksock(domain, type, 0);
632
ATF_REQUIRE(setsockopt(s[1], SOL_SOCKET, SO_REUSEPORT_LB, &(int){1},
633
sizeof(int)) == 0);
634
s[2] = mksock(domain, type, 1);
635
ATF_REQUIRE(setsockopt(s[2], SOL_SOCKET, SO_REUSEPORT_LB, &(int){1},
636
sizeof(int)) == 0);
637
638
sslen = domain == PF_INET ? sizeof(struct sockaddr_in) :
639
sizeof(struct sockaddr_in6);
640
memset(&ss, 0, sizeof(ss));
641
ss.ss_family = domain;
642
ss.ss_len = sslen;
643
error = bind(s[0], (struct sockaddr *)&ss, sslen);
644
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
645
error = getsockname(s[0], (struct sockaddr *)&ss, &sslen);
646
ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
647
648
error = bind(s[1], (struct sockaddr *)&ss, sslen);
649
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
650
error = bind(s[2], (struct sockaddr *)&ss, sslen);
651
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
652
653
if (domain == PF_INET6) {
654
sin6p = (struct sockaddr_in6 *)&ss;
655
sin6p->sin6_addr = in6addr_loopback;
656
}
657
658
/*
659
* Send a packet from FIB 0, make sure it goes to s[0] or s[1].
660
*/
661
cs = mksock(domain, type, 0);
662
for (int count = 0; count < 100; count++) {
663
int bytes, rs;
664
665
b = 42;
666
n = sendto(cs, &b, sizeof(b), 0, (struct sockaddr *)&ss, sslen);
667
ATF_REQUIRE_MSG(n == 1, "sendto failed: %s", strerror(errno));
668
usleep(1000);
669
670
error = ioctl(s[0], FIONREAD, &bytes);
671
ATF_REQUIRE_MSG(error == 0, "ioctl failed: %s",
672
strerror(errno));
673
if (bytes == 0) {
674
error = ioctl(s[1], FIONREAD, &bytes);
675
ATF_REQUIRE_MSG(error == 0, "ioctl failed: %s",
676
strerror(errno));
677
rs = s[1];
678
} else {
679
rs = s[0];
680
}
681
n = recv(rs, &b, sizeof(b), 0);
682
ATF_REQUIRE(n == 1);
683
ATF_REQUIRE(b == 42);
684
ATF_REQUIRE(bytes == 1);
685
}
686
checked_close(cs);
687
688
/*
689
* Send a packet from FIB 1, make sure it goes to s[2].
690
*/
691
cs = mksock(domain, type, 1);
692
for (int count = 0; count < 100; count++) {
693
b = 42;
694
n = sendto(cs, &b, sizeof(b), 0, (struct sockaddr *)&ss, sslen);
695
ATF_REQUIRE_MSG(n == 1, "sendto failed: %s", strerror(errno));
696
usleep(1000);
697
698
n = recv(s[2], &b, sizeof(b), 0);
699
ATF_REQUIRE(n == 1);
700
ATF_REQUIRE(b == 42);
701
}
702
checked_close(cs);
703
704
checked_close(s[0]);
705
checked_close(s[1]);
706
checked_close(s[2]);
707
}
708
MAKETEST_UDP(multibind_lbgroup_dgram);
709
710
/*
711
* Make sure that we can't change the FIB of a bound socket.
712
*/
713
static void
714
no_setfib_after_bind(int domain, int type, const atf_tc_t *tc __unused)
715
{
716
struct sockaddr_storage ss;
717
socklen_t sslen;
718
int error, s;
719
720
ATF_REQUIRE(domain == PF_INET || domain == PF_INET6);
721
require_fibs_multibind(type, 2);
722
723
s = mksock(domain, type, 0);
724
725
sslen = domain == PF_INET ? sizeof(struct sockaddr_in) :
726
sizeof(struct sockaddr_in6);
727
memset(&ss, 0, sizeof(ss));
728
ss.ss_family = domain;
729
ss.ss_len = sslen;
730
error = bind(s, (struct sockaddr *)&ss, sslen);
731
ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
732
733
error = setsockopt(s, SOL_SOCKET, SO_SETFIB, &(int){1}, sizeof(int));
734
ATF_REQUIRE_ERRNO(EISCONN, error == -1);
735
736
/* It's ok to set the FIB number to its current value. */
737
error = setsockopt(s, SOL_SOCKET, SO_SETFIB, &(int){0}, sizeof(int));
738
ATF_REQUIRE_MSG(error == 0, "setsockopt failed: %s", strerror(errno));
739
740
checked_close(s);
741
}
742
MAKETEST(no_setfib_after_bind);
743
744
ATF_TP_ADD_TCS(tp)
745
{
746
LISTTEST(multibind_different_user);
747
LISTTEST_TCP(per_fib_listening_socket);
748
LISTTEST_UDP(per_fib_dgram_socket);
749
LISTTEST_RAW(per_fib_raw_socket);
750
LISTTEST_TCP(multibind_lbgroup_stream);
751
LISTTEST_UDP(multibind_lbgroup_dgram);
752
LISTTEST(no_setfib_after_bind);
753
754
return (atf_no_error());
755
}
756
757