1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Bjoern A. Zeeb 5 * Copyright (c) 2024 Stormshield 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are 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 the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/wait.h> 32 33 #include <netinet/in.h> 34 35 #include <errno.h> 36 #include <poll.h> 37 #include <pwd.h> 38 #include <stdio.h> 39 #include <unistd.h> 40 41 #include <atf-c.h> 42 43 ATF_TC_WITHOUT_HEAD(socket_afinet); 44 ATF_TC_BODY(socket_afinet, tc) 45 { 46 int sd; 47 48 sd = socket(PF_INET, SOCK_DGRAM, 0); 49 ATF_CHECK(sd >= 0); 50 51 close(sd); 52 } 53 54 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_zero); 55 ATF_TC_BODY(socket_afinet_bind_zero, tc) 56 { 57 int sd, rc; 58 struct sockaddr_in sin; 59 60 if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) 61 atf_tc_skip("doesn't work when mac_portacl(4) loaded (https://bugs.freebsd.org/238781)"); 62 63 sd = socket(PF_INET, SOCK_DGRAM, 0); 64 ATF_CHECK(sd >= 0); 65 66 bzero(&sin, sizeof(sin)); 67 /* 68 * For AF_INET we do not check the family in in_pcbbind_setup(9), 69 * sa_len gets set from the syscall argument in getsockaddr(9), 70 * so we bind to 0:0. 71 */ 72 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 73 ATF_CHECK_EQ(0, rc); 74 75 close(sd); 76 } 77 78 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok); 79 ATF_TC_BODY(socket_afinet_bind_ok, tc) 80 { 81 int sd, rc; 82 struct sockaddr_in sin; 83 84 sd = socket(PF_INET, SOCK_DGRAM, 0); 85 ATF_CHECK(sd >= 0); 86 87 bzero(&sin, sizeof(sin)); 88 sin.sin_family = AF_INET; 89 sin.sin_len = sizeof(sin); 90 sin.sin_port = htons(0); 91 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 92 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 93 ATF_CHECK_EQ(0, rc); 94 95 close(sd); 96 } 97 98 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup); 99 ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc) 100 { 101 int ss, ss2, cs, rc; 102 struct sockaddr_in sin; 103 socklen_t slen; 104 struct pollfd pfd; 105 int one = 1; 106 107 /* Verify that we don't expose POLLRDHUP if not requested. */ 108 109 /* Server setup. */ 110 ss = socket(PF_INET, SOCK_STREAM, 0); 111 ATF_CHECK(ss >= 0); 112 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 113 ATF_CHECK_EQ(0, rc); 114 bzero(&sin, sizeof(sin)); 115 sin.sin_family = AF_INET; 116 sin.sin_len = sizeof(sin); 117 sin.sin_port = htons(0); 118 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 119 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 120 ATF_CHECK_EQ(0, rc); 121 rc = listen(ss, 1); 122 ATF_CHECK_EQ(0, rc); 123 slen = sizeof(sin); 124 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 125 ATF_CHECK_EQ(0, rc); 126 127 /* Client connects, server accepts. */ 128 cs = socket(PF_INET, SOCK_STREAM, 0); 129 ATF_CHECK(cs >= 0); 130 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 131 ATF_CHECK_EQ(0, rc); 132 ss2 = accept(ss, NULL, NULL); 133 ATF_CHECK(ss2 >= 0); 134 135 /* Server can write, sees only POLLOUT. */ 136 pfd.fd = ss2; 137 pfd.events = POLLIN | POLLOUT; 138 rc = poll(&pfd, 1, 0); 139 ATF_CHECK_EQ(1, rc); 140 ATF_CHECK_EQ(POLLOUT, pfd.revents); 141 142 /* Client closes socket! */ 143 rc = close(cs); 144 ATF_CHECK_EQ(0, rc); 145 146 /* 147 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask. 148 * Need non-zero timeout to wait for the FIN to arrive and trigger the 149 * socket to become readable. 150 */ 151 pfd.fd = ss2; 152 pfd.events = POLLIN; 153 rc = poll(&pfd, 1, 60000); 154 ATF_CHECK_EQ(1, rc); 155 ATF_CHECK_EQ(POLLIN, pfd.revents); 156 157 close(ss2); 158 close(ss); 159 } 160 161 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup); 162 ATF_TC_BODY(socket_afinet_poll_rdhup, tc) 163 { 164 int ss, ss2, cs, rc; 165 struct sockaddr_in sin; 166 socklen_t slen; 167 struct pollfd pfd; 168 char buffer; 169 int one = 1; 170 171 /* Verify that server sees POLLRDHUP if it asks for it. */ 172 173 /* Server setup. */ 174 ss = socket(PF_INET, SOCK_STREAM, 0); 175 ATF_CHECK(ss >= 0); 176 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 177 ATF_CHECK_EQ(0, rc); 178 bzero(&sin, sizeof(sin)); 179 sin.sin_family = AF_INET; 180 sin.sin_len = sizeof(sin); 181 sin.sin_port = htons(0); 182 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 183 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 184 ATF_CHECK_EQ(0, rc); 185 rc = listen(ss, 1); 186 ATF_CHECK_EQ(0, rc); 187 slen = sizeof(sin); 188 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 189 ATF_CHECK_EQ(0, rc); 190 191 /* Client connects, server accepts. */ 192 cs = socket(PF_INET, SOCK_STREAM, 0); 193 ATF_CHECK(cs >= 0); 194 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 195 ATF_CHECK_EQ(0, rc); 196 ss2 = accept(ss, NULL, NULL); 197 ATF_CHECK(ss2 >= 0); 198 199 /* Server can write, so sees POLLOUT. */ 200 pfd.fd = ss2; 201 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 202 rc = poll(&pfd, 1, 0); 203 ATF_CHECK_EQ(1, rc); 204 ATF_CHECK_EQ(POLLOUT, pfd.revents); 205 206 /* Client writes two bytes, server reads only one of them. */ 207 rc = write(cs, "xx", 2); 208 ATF_CHECK_EQ(2, rc); 209 rc = read(ss2, &buffer, 1); 210 ATF_CHECK_EQ(1, rc); 211 212 /* Server can read, so sees POLLIN. */ 213 pfd.fd = ss2; 214 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 215 rc = poll(&pfd, 1, 0); 216 ATF_CHECK_EQ(1, rc); 217 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents); 218 219 /* Client closes socket! */ 220 rc = close(cs); 221 ATF_CHECK_EQ(0, rc); 222 223 /* 224 * Server sees Linux-style POLLRDHUP. Note that this is the case even 225 * though one byte of data remains unread. 226 * 227 * This races against the delivery of FIN caused by the close() above. 228 * Sometimes (more likely when run under truss or if another system 229 * call is added in between) it hits the path where sopoll_generic() 230 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag 231 * SB_SEL so that it's woken up almost immediately and runs again, 232 * which is why we need a non-zero timeout here. 233 */ 234 pfd.fd = ss2; 235 pfd.events = POLLRDHUP; 236 rc = poll(&pfd, 1, 60000); 237 ATF_CHECK_EQ(1, rc); 238 ATF_CHECK_EQ(POLLRDHUP, pfd.revents); 239 240 close(ss2); 241 close(ss); 242 } 243 244 ATF_TC_WITHOUT_HEAD(socket_afinet_stream_reconnect); 245 ATF_TC_BODY(socket_afinet_stream_reconnect, tc) 246 { 247 struct sockaddr_in sin; 248 socklen_t slen; 249 int ss, cs, rc; 250 251 /* 252 * Make sure that an attempt to connect(2) a connected or disconnected 253 * stream socket fails with EISCONN. 254 */ 255 256 /* Server setup. */ 257 ss = socket(PF_INET, SOCK_STREAM, 0); 258 ATF_CHECK(ss >= 0); 259 bzero(&sin, sizeof(sin)); 260 sin.sin_family = AF_INET; 261 sin.sin_len = sizeof(sin); 262 sin.sin_port = htons(0); 263 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 264 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 265 ATF_CHECK_EQ(0, rc); 266 rc = listen(ss, 1); 267 ATF_CHECK_EQ(0, rc); 268 slen = sizeof(sin); 269 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 270 ATF_CHECK_EQ(0, rc); 271 272 /* Client connects, shuts down. */ 273 cs = socket(PF_INET, SOCK_STREAM, 0); 274 ATF_CHECK(cs >= 0); 275 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 276 ATF_CHECK_EQ(0, rc); 277 rc = shutdown(cs, SHUT_RDWR); 278 ATF_CHECK_EQ(0, rc); 279 280 /* A subsequent connect(2) fails with EISCONN. */ 281 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 282 ATF_CHECK_EQ(-1, rc); 283 ATF_CHECK_EQ(errno, EISCONN); 284 285 rc = close(cs); 286 ATF_CHECK_EQ(0, rc); 287 rc = close(ss); 288 ATF_CHECK_EQ(0, rc); 289 } 290 291 /* 292 * Make sure that unprivileged users can't set the IP_BINDANY or IPV6_BINDANY 293 * socket options. 294 */ 295 ATF_TC(socket_afinet_bindany); 296 ATF_TC_HEAD(socket_afinet_bindany, tc) 297 { 298 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 299 } 300 ATF_TC_BODY(socket_afinet_bindany, tc) 301 { 302 int s; 303 304 s = socket(AF_INET, SOCK_STREAM, 0); 305 ATF_REQUIRE(s >= 0); 306 ATF_REQUIRE_ERRNO(EPERM, 307 setsockopt(s, IPPROTO_IP, IP_BINDANY, &(int){1}, sizeof(int)) == 308 -1); 309 ATF_REQUIRE(close(s) == 0); 310 311 s = socket(AF_INET, SOCK_DGRAM, 0); 312 ATF_REQUIRE(s >= 0); 313 ATF_REQUIRE_ERRNO(EPERM, 314 setsockopt(s, IPPROTO_IP, IP_BINDANY, &(int){1}, sizeof(int)) == 315 -1); 316 ATF_REQUIRE(close(s) == 0); 317 318 s = socket(AF_INET6, SOCK_STREAM, 0); 319 ATF_REQUIRE(s >= 0); 320 ATF_REQUIRE_ERRNO(EPERM, 321 setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, &(int){1}, sizeof(int)) == 322 -1); 323 ATF_REQUIRE(close(s) == 0); 324 325 s = socket(AF_INET6, SOCK_DGRAM, 0); 326 ATF_REQUIRE(s >= 0); 327 ATF_REQUIRE_ERRNO(EPERM, 328 setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, &(int){1}, sizeof(int)) == 329 -1); 330 ATF_REQUIRE(close(s) == 0); 331 } 332 333 /* 334 * Bind a socket to the specified address, optionally dropping privileges and 335 * setting one of the SO_REUSE* options first. 336 * 337 * Returns true if the bind succeeded, and false if it failed with EADDRINUSE. 338 */ 339 static bool 340 child_bind(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt, 341 bool unpriv) 342 { 343 const char *user; 344 pid_t child; 345 346 if (unpriv) { 347 if (!atf_tc_has_config_var(tc, "unprivileged_user")) 348 atf_tc_skip("unprivileged_user not set"); 349 user = atf_tc_get_config_var(tc, "unprivileged_user"); 350 } else { 351 user = NULL; 352 } 353 354 child = fork(); 355 ATF_REQUIRE(child != -1); 356 if (child == 0) { 357 int s; 358 359 if (user != NULL) { 360 struct passwd *passwd; 361 362 passwd = getpwnam(user); 363 if (seteuid(passwd->pw_uid) != 0) 364 _exit(1); 365 } 366 367 s = socket(sa->sa_family, type, 0); 368 if (s < 0) 369 _exit(2); 370 if (bind(s, sa, sa->sa_len) == 0) 371 _exit(3); 372 if (errno != EADDRINUSE) 373 _exit(4); 374 if (opt != 0) { 375 if (setsockopt(s, SOL_SOCKET, opt, &(int){1}, 376 sizeof(int)) != 0) 377 _exit(5); 378 } 379 if (bind(s, sa, sa->sa_len) == 0) 380 _exit(6); 381 if (errno != EADDRINUSE) 382 _exit(7); 383 _exit(0); 384 } else { 385 int status; 386 387 ATF_REQUIRE_EQ(waitpid(child, &status, 0), child); 388 ATF_REQUIRE(WIFEXITED(status)); 389 status = WEXITSTATUS(status); 390 ATF_REQUIRE_MSG(status == 0 || status == 6, 391 "child exited with %d", status); 392 return (status == 6); 393 } 394 } 395 396 static bool 397 child_bind_priv(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt) 398 { 399 return (child_bind(tc, type, sa, opt, false)); 400 } 401 402 static bool 403 child_bind_unpriv(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt) 404 { 405 return (child_bind(tc, type, sa, opt, true)); 406 } 407 408 static int 409 bind_socket(int domain, int type, int opt, bool unspec, struct sockaddr *sa) 410 { 411 socklen_t slen; 412 int s; 413 414 s = socket(domain, type, 0); 415 ATF_REQUIRE(s >= 0); 416 417 if (domain == AF_INET) { 418 struct sockaddr_in sin; 419 420 bzero(&sin, sizeof(sin)); 421 sin.sin_family = AF_INET; 422 sin.sin_len = sizeof(sin); 423 sin.sin_addr.s_addr = htonl(unspec ? 424 INADDR_ANY : INADDR_LOOPBACK); 425 sin.sin_port = htons(0); 426 ATF_REQUIRE(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0); 427 428 slen = sizeof(sin); 429 } else /* if (domain == AF_INET6) */ { 430 struct sockaddr_in6 sin6; 431 432 bzero(&sin6, sizeof(sin6)); 433 sin6.sin6_family = AF_INET6; 434 sin6.sin6_len = sizeof(sin6); 435 sin6.sin6_addr = unspec ? in6addr_any : in6addr_loopback; 436 sin6.sin6_port = htons(0); 437 ATF_REQUIRE(bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) == 0); 438 439 slen = sizeof(sin6); 440 } 441 442 if (opt != 0) { 443 ATF_REQUIRE(setsockopt(s, SOL_SOCKET, opt, &(int){1}, 444 sizeof(int)) == 0); 445 } 446 447 ATF_REQUIRE(getsockname(s, sa, &slen) == 0); 448 449 return (s); 450 } 451 452 static void 453 multibind_test(const atf_tc_t *tc, int domain, int type) 454 { 455 struct sockaddr_storage ss; 456 int opts[4] = { 0, SO_REUSEADDR, SO_REUSEPORT, SO_REUSEPORT_LB }; 457 int s; 458 bool flags[2] = { false, true }; 459 bool res; 460 461 for (size_t flagi = 0; flagi < nitems(flags); flagi++) { 462 for (size_t opti = 0; opti < nitems(opts); opti++) { 463 s = bind_socket(domain, type, opts[opti], flags[flagi], 464 (struct sockaddr *)&ss); 465 for (size_t optj = 0; optj < nitems(opts); optj++) { 466 int opt; 467 468 opt = opts[optj]; 469 res = child_bind_priv(tc, type, 470 (struct sockaddr *)&ss, opt); 471 /* 472 * Multi-binding is only allowed when both 473 * sockets have SO_REUSEPORT or SO_REUSEPORT_LB 474 * set. 475 */ 476 if (opts[opti] != 0 && 477 opts[opti] != SO_REUSEADDR && opti == optj) 478 ATF_REQUIRE(res); 479 else 480 ATF_REQUIRE(!res); 481 482 res = child_bind_unpriv(tc, type, 483 (struct sockaddr *)&ss, opt); 484 /* 485 * Multi-binding is only allowed when both 486 * sockets have the same owner. 487 */ 488 ATF_REQUIRE(!res); 489 } 490 ATF_REQUIRE(close(s) == 0); 491 } 492 } 493 } 494 495 /* 496 * Try to bind two sockets to the same address/port tuple. Under some 497 * conditions this is permitted. 498 */ 499 ATF_TC(socket_afinet_multibind); 500 ATF_TC_HEAD(socket_afinet_multibind, tc) 501 { 502 atf_tc_set_md_var(tc, "require.user", "root"); 503 atf_tc_set_md_var(tc, "require.config", "unprivileged_user"); 504 } 505 ATF_TC_BODY(socket_afinet_multibind, tc) 506 { 507 multibind_test(tc, AF_INET, SOCK_STREAM); 508 multibind_test(tc, AF_INET, SOCK_DGRAM); 509 multibind_test(tc, AF_INET6, SOCK_STREAM); 510 multibind_test(tc, AF_INET6, SOCK_DGRAM); 511 } 512 513 static void 514 bind_connected_port_test(const atf_tc_t *tc, int domain) 515 { 516 struct sockaddr_in sin; 517 struct sockaddr_in6 sin6; 518 struct sockaddr *sinp; 519 int error, sd[3], tmp; 520 bool res; 521 522 /* 523 * Create a connected socket pair. 524 */ 525 sd[0] = socket(domain, SOCK_STREAM, 0); 526 ATF_REQUIRE_MSG(sd[0] >= 0, "socket failed: %s", strerror(errno)); 527 sd[1] = socket(domain, SOCK_STREAM, 0); 528 ATF_REQUIRE_MSG(sd[1] >= 0, "socket failed: %s", strerror(errno)); 529 if (domain == PF_INET) { 530 memset(&sin, 0, sizeof(sin)); 531 sin.sin_family = AF_INET; 532 sin.sin_len = sizeof(sin); 533 sin.sin_addr.s_addr = htonl(INADDR_ANY); 534 sin.sin_port = htons(0); 535 sinp = (struct sockaddr *)&sin; 536 } else { 537 ATF_REQUIRE(domain == PF_INET6); 538 memset(&sin6, 0, sizeof(sin6)); 539 sin6.sin6_family = AF_INET6; 540 sin6.sin6_len = sizeof(sin6); 541 sin6.sin6_addr = in6addr_any; 542 sin6.sin6_port = htons(0); 543 sinp = (struct sockaddr *)&sin6; 544 } 545 546 error = bind(sd[0], sinp, sinp->sa_len); 547 ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno)); 548 error = listen(sd[0], 1); 549 ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno)); 550 551 error = getsockname(sd[0], sinp, &(socklen_t){ sinp->sa_len }); 552 ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno)); 553 554 error = connect(sd[1], sinp, sinp->sa_len); 555 ATF_REQUIRE_MSG(error == 0, "connect failed: %s", strerror(errno)); 556 tmp = accept(sd[0], NULL, NULL); 557 ATF_REQUIRE_MSG(tmp >= 0, "accept failed: %s", strerror(errno)); 558 ATF_REQUIRE(close(sd[0]) == 0); 559 sd[0] = tmp; 560 561 /* bind() should succeed even from an unprivileged user. */ 562 res = child_bind(tc, SOCK_STREAM, sinp, 0, false); 563 ATF_REQUIRE(!res); 564 res = child_bind(tc, SOCK_STREAM, sinp, 0, true); 565 ATF_REQUIRE(!res); 566 } 567 568 /* 569 * Normally bind() prevents port stealing by a different user, even when 570 * SO_REUSE* are specified. However, if the port is bound by a connected 571 * socket, then it's fair game. 572 */ 573 ATF_TC(socket_afinet_bind_connected_port); 574 ATF_TC_HEAD(socket_afinet_bind_connected_port, tc) 575 { 576 atf_tc_set_md_var(tc, "require.user", "root"); 577 atf_tc_set_md_var(tc, "require.config", "unprivileged_user"); 578 } 579 ATF_TC_BODY(socket_afinet_bind_connected_port, tc) 580 { 581 bind_connected_port_test(tc, AF_INET); 582 bind_connected_port_test(tc, AF_INET6); 583 } 584 585 ATF_TP_ADD_TCS(tp) 586 { 587 ATF_TP_ADD_TC(tp, socket_afinet); 588 ATF_TP_ADD_TC(tp, socket_afinet_bind_zero); 589 ATF_TP_ADD_TC(tp, socket_afinet_bind_ok); 590 ATF_TP_ADD_TC(tp, socket_afinet_poll_no_rdhup); 591 ATF_TP_ADD_TC(tp, socket_afinet_poll_rdhup); 592 ATF_TP_ADD_TC(tp, socket_afinet_stream_reconnect); 593 ATF_TP_ADD_TC(tp, socket_afinet_bindany); 594 ATF_TP_ADD_TC(tp, socket_afinet_multibind); 595 ATF_TP_ADD_TC(tp, socket_afinet_bind_connected_port); 596 597 return atf_no_error(); 598 } 599