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
checked_close(int s)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
mksockp(int domain,int type,int fib,int proto)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
mksock(int domain,int type,int fib)110 mksock(int domain, int type, int fib)
111 {
112 return (mksockp(domain, type, fib, 0));
113 }
114
115 static void
require_fibs_multibind(int socktype,int minfibs)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
multibind_different_user(int domain,int type,const atf_tc_t * tc)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
per_fib_listening_socket(int domain,int type,const atf_tc_t * tc __unused)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
per_fib_dgram_socket(int domain,int type,const atf_tc_t * tc __unused)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
ping(int s,const struct sockaddr * sa,socklen_t salen)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
ping6(int s,const struct sockaddr * sa,socklen_t salen)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
per_fib_raw_socket(int domain,int type,const atf_tc_t * tc __unused)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
multibind_lbgroup_stream(int domain,int type,const atf_tc_t * tc __unused)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
multibind_lbgroup_dgram(int domain,int type,const atf_tc_t * tc __unused)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
no_setfib_after_bind(int domain,int type,const atf_tc_t * tc __unused)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
ATF_TP_ADD_TCS(tp)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