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 sd = socket(PF_INET, SOCK_DGRAM, 0); 61 ATF_CHECK(sd >= 0); 62 63 bzero(&sin, sizeof(sin)); 64 /* 65 * For AF_INET we do not check the family in in_pcbbind_setup(9), 66 * sa_len gets set from the syscall argument in getsockaddr(9), 67 * so we bind to 0:0. 68 */ 69 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 70 ATF_CHECK_EQ(0, rc); 71 72 close(sd); 73 } 74 75 ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok); 76 ATF_TC_BODY(socket_afinet_bind_ok, tc) 77 { 78 int sd, rc; 79 struct sockaddr_in sin; 80 81 sd = socket(PF_INET, SOCK_DGRAM, 0); 82 ATF_CHECK(sd >= 0); 83 84 bzero(&sin, sizeof(sin)); 85 sin.sin_family = AF_INET; 86 sin.sin_len = sizeof(sin); 87 sin.sin_port = htons(0); 88 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 89 rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin)); 90 ATF_CHECK_EQ(0, rc); 91 92 close(sd); 93 } 94 95 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup); 96 ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc) 97 { 98 int ss, ss2, cs, rc; 99 struct sockaddr_in sin; 100 socklen_t slen; 101 struct pollfd pfd; 102 int one = 1; 103 104 /* Verify that we don't expose POLLRDHUP if not requested. */ 105 106 /* Server setup. */ 107 ss = socket(PF_INET, SOCK_STREAM, 0); 108 ATF_CHECK(ss >= 0); 109 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 110 ATF_CHECK_EQ(0, rc); 111 bzero(&sin, sizeof(sin)); 112 sin.sin_family = AF_INET; 113 sin.sin_len = sizeof(sin); 114 sin.sin_port = htons(0); 115 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 116 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 117 ATF_CHECK_EQ(0, rc); 118 rc = listen(ss, 1); 119 ATF_CHECK_EQ(0, rc); 120 slen = sizeof(sin); 121 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 122 ATF_CHECK_EQ(0, rc); 123 124 /* Client connects, server accepts. */ 125 cs = socket(PF_INET, SOCK_STREAM, 0); 126 ATF_CHECK(cs >= 0); 127 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 128 ATF_CHECK_EQ(0, rc); 129 ss2 = accept(ss, NULL, NULL); 130 ATF_CHECK(ss2 >= 0); 131 132 /* Server can write, sees only POLLOUT. */ 133 pfd.fd = ss2; 134 pfd.events = POLLIN | POLLOUT; 135 rc = poll(&pfd, 1, 0); 136 ATF_CHECK_EQ(1, rc); 137 ATF_CHECK_EQ(POLLOUT, pfd.revents); 138 139 /* Client closes socket! */ 140 rc = close(cs); 141 ATF_CHECK_EQ(0, rc); 142 143 /* 144 * Server now sees POLLIN, but not POLLRDHUP because we didn't ask. 145 * Need non-zero timeout to wait for the FIN to arrive and trigger the 146 * socket to become readable. 147 */ 148 pfd.fd = ss2; 149 pfd.events = POLLIN; 150 rc = poll(&pfd, 1, 60000); 151 ATF_CHECK_EQ(1, rc); 152 ATF_CHECK_EQ(POLLIN, pfd.revents); 153 154 close(ss2); 155 close(ss); 156 } 157 158 ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup); 159 ATF_TC_BODY(socket_afinet_poll_rdhup, tc) 160 { 161 int ss, ss2, cs, rc; 162 struct sockaddr_in sin; 163 socklen_t slen; 164 struct pollfd pfd; 165 char buffer; 166 int one = 1; 167 168 /* Verify that server sees POLLRDHUP if it asks for it. */ 169 170 /* Server setup. */ 171 ss = socket(PF_INET, SOCK_STREAM, 0); 172 ATF_CHECK(ss >= 0); 173 rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 174 ATF_CHECK_EQ(0, rc); 175 bzero(&sin, sizeof(sin)); 176 sin.sin_family = AF_INET; 177 sin.sin_len = sizeof(sin); 178 sin.sin_port = htons(0); 179 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 180 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 181 ATF_CHECK_EQ(0, rc); 182 rc = listen(ss, 1); 183 ATF_CHECK_EQ(0, rc); 184 slen = sizeof(sin); 185 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 186 ATF_CHECK_EQ(0, rc); 187 188 /* Client connects, server accepts. */ 189 cs = socket(PF_INET, SOCK_STREAM, 0); 190 ATF_CHECK(cs >= 0); 191 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 192 ATF_CHECK_EQ(0, rc); 193 ss2 = accept(ss, NULL, NULL); 194 ATF_CHECK(ss2 >= 0); 195 196 /* Server can write, so sees POLLOUT. */ 197 pfd.fd = ss2; 198 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 199 rc = poll(&pfd, 1, 0); 200 ATF_CHECK_EQ(1, rc); 201 ATF_CHECK_EQ(POLLOUT, pfd.revents); 202 203 /* Client writes two bytes, server reads only one of them. */ 204 rc = write(cs, "xx", 2); 205 ATF_CHECK_EQ(2, rc); 206 rc = read(ss2, &buffer, 1); 207 ATF_CHECK_EQ(1, rc); 208 209 /* Server can read, so sees POLLIN. */ 210 pfd.fd = ss2; 211 pfd.events = POLLIN | POLLOUT | POLLRDHUP; 212 rc = poll(&pfd, 1, 0); 213 ATF_CHECK_EQ(1, rc); 214 ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents); 215 216 /* Client closes socket! */ 217 rc = close(cs); 218 ATF_CHECK_EQ(0, rc); 219 220 /* 221 * Server sees Linux-style POLLRDHUP. Note that this is the case even 222 * though one byte of data remains unread. 223 * 224 * This races against the delivery of FIN caused by the close() above. 225 * Sometimes (more likely when run under truss or if another system 226 * call is added in between) it hits the path where sopoll_generic() 227 * immediately sees SBS_CANTRCVMORE, and sometimes it sleeps with flag 228 * SB_SEL so that it's woken up almost immediately and runs again, 229 * which is why we need a non-zero timeout here. 230 */ 231 pfd.fd = ss2; 232 pfd.events = POLLRDHUP; 233 rc = poll(&pfd, 1, 60000); 234 ATF_CHECK_EQ(1, rc); 235 ATF_CHECK_EQ(POLLRDHUP, pfd.revents); 236 237 close(ss2); 238 close(ss); 239 } 240 241 ATF_TC_WITHOUT_HEAD(socket_afinet_stream_reconnect); 242 ATF_TC_BODY(socket_afinet_stream_reconnect, tc) 243 { 244 struct sockaddr_in sin; 245 socklen_t slen; 246 int ss, cs, rc; 247 248 /* 249 * Make sure that an attempt to connect(2) a connected or disconnected 250 * stream socket fails with EISCONN. 251 */ 252 253 /* Server setup. */ 254 ss = socket(PF_INET, SOCK_STREAM, 0); 255 ATF_CHECK(ss >= 0); 256 bzero(&sin, sizeof(sin)); 257 sin.sin_family = AF_INET; 258 sin.sin_len = sizeof(sin); 259 sin.sin_port = htons(0); 260 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 261 rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin)); 262 ATF_CHECK_EQ(0, rc); 263 rc = listen(ss, 1); 264 ATF_CHECK_EQ(0, rc); 265 slen = sizeof(sin); 266 rc = getsockname(ss, (struct sockaddr *)&sin, &slen); 267 ATF_CHECK_EQ(0, rc); 268 269 /* Client connects, shuts down. */ 270 cs = socket(PF_INET, SOCK_STREAM, 0); 271 ATF_CHECK(cs >= 0); 272 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 273 ATF_CHECK_EQ(0, rc); 274 rc = shutdown(cs, SHUT_RDWR); 275 ATF_CHECK_EQ(0, rc); 276 277 /* A subsequent connect(2) fails with EISCONN. */ 278 rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin)); 279 ATF_CHECK_EQ(-1, rc); 280 ATF_CHECK_EQ(errno, EISCONN); 281 282 rc = close(cs); 283 ATF_CHECK_EQ(0, rc); 284 rc = close(ss); 285 ATF_CHECK_EQ(0, rc); 286 } 287 288 /* 289 * Make sure that unprivileged users can't set the IP_BINDANY or IPV6_BINDANY 290 * socket options. 291 */ 292 ATF_TC(socket_afinet_bindany); 293 ATF_TC_HEAD(socket_afinet_bindany, tc) 294 { 295 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 296 } 297 ATF_TC_BODY(socket_afinet_bindany, tc) 298 { 299 int s; 300 301 s = socket(AF_INET, SOCK_STREAM, 0); 302 ATF_REQUIRE(s >= 0); 303 ATF_REQUIRE_ERRNO(EPERM, 304 setsockopt(s, IPPROTO_IP, IP_BINDANY, &(int){1}, sizeof(int)) == 305 -1); 306 ATF_REQUIRE(close(s) == 0); 307 308 s = socket(AF_INET, SOCK_DGRAM, 0); 309 ATF_REQUIRE(s >= 0); 310 ATF_REQUIRE_ERRNO(EPERM, 311 setsockopt(s, IPPROTO_IP, IP_BINDANY, &(int){1}, sizeof(int)) == 312 -1); 313 ATF_REQUIRE(close(s) == 0); 314 315 s = socket(AF_INET6, SOCK_STREAM, 0); 316 ATF_REQUIRE(s >= 0); 317 ATF_REQUIRE_ERRNO(EPERM, 318 setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, &(int){1}, sizeof(int)) == 319 -1); 320 ATF_REQUIRE(close(s) == 0); 321 322 s = socket(AF_INET6, SOCK_DGRAM, 0); 323 ATF_REQUIRE(s >= 0); 324 ATF_REQUIRE_ERRNO(EPERM, 325 setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY, &(int){1}, sizeof(int)) == 326 -1); 327 ATF_REQUIRE(close(s) == 0); 328 } 329 330 /* 331 * Bind a socket to the specified address, optionally dropping privileges and 332 * setting one of the SO_REUSE* options first. 333 * 334 * Returns true if the bind succeeded, and false if it failed with EADDRINUSE. 335 */ 336 static bool 337 child_bind(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt, 338 bool unpriv) 339 { 340 const char *user; 341 pid_t child; 342 343 if (unpriv) { 344 if (!atf_tc_has_config_var(tc, "unprivileged_user")) 345 atf_tc_skip("unprivileged_user not set"); 346 user = atf_tc_get_config_var(tc, "unprivileged_user"); 347 } else { 348 user = NULL; 349 } 350 351 child = fork(); 352 ATF_REQUIRE(child != -1); 353 if (child == 0) { 354 int s; 355 356 if (user != NULL) { 357 struct passwd *passwd; 358 359 passwd = getpwnam(user); 360 if (seteuid(passwd->pw_uid) != 0) 361 _exit(1); 362 } 363 364 s = socket(sa->sa_family, type, 0); 365 if (s < 0) 366 _exit(2); 367 if (bind(s, sa, sa->sa_len) == 0) 368 _exit(3); 369 if (errno != EADDRINUSE) 370 _exit(4); 371 if (opt != 0) { 372 if (setsockopt(s, SOL_SOCKET, opt, &(int){1}, 373 sizeof(int)) != 0) 374 _exit(5); 375 } 376 if (bind(s, sa, sa->sa_len) == 0) 377 _exit(6); 378 if (errno != EADDRINUSE) 379 _exit(7); 380 _exit(0); 381 } else { 382 int status; 383 384 ATF_REQUIRE_EQ(waitpid(child, &status, 0), child); 385 ATF_REQUIRE(WIFEXITED(status)); 386 status = WEXITSTATUS(status); 387 ATF_REQUIRE_MSG(status == 0 || status == 6, 388 "child exited with %d", status); 389 return (status == 6); 390 } 391 } 392 393 static bool 394 child_bind_priv(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt) 395 { 396 return (child_bind(tc, type, sa, opt, false)); 397 } 398 399 static bool 400 child_bind_unpriv(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt) 401 { 402 return (child_bind(tc, type, sa, opt, true)); 403 } 404 405 static int 406 bind_socket(int domain, int type, int opt, bool unspec, struct sockaddr *sa) 407 { 408 socklen_t slen; 409 int s; 410 411 s = socket(domain, type, 0); 412 ATF_REQUIRE(s >= 0); 413 414 if (domain == AF_INET) { 415 struct sockaddr_in sin; 416 417 bzero(&sin, sizeof(sin)); 418 sin.sin_family = AF_INET; 419 sin.sin_len = sizeof(sin); 420 sin.sin_addr.s_addr = htonl(unspec ? 421 INADDR_ANY : INADDR_LOOPBACK); 422 sin.sin_port = htons(0); 423 ATF_REQUIRE(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0); 424 425 slen = sizeof(sin); 426 } else /* if (domain == AF_INET6) */ { 427 struct sockaddr_in6 sin6; 428 429 bzero(&sin6, sizeof(sin6)); 430 sin6.sin6_family = AF_INET6; 431 sin6.sin6_len = sizeof(sin6); 432 sin6.sin6_addr = unspec ? in6addr_any : in6addr_loopback; 433 sin6.sin6_port = htons(0); 434 ATF_REQUIRE(bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) == 0); 435 436 slen = sizeof(sin6); 437 } 438 439 if (opt != 0) { 440 ATF_REQUIRE(setsockopt(s, SOL_SOCKET, opt, &(int){1}, 441 sizeof(int)) == 0); 442 } 443 444 ATF_REQUIRE(getsockname(s, sa, &slen) == 0); 445 446 return (s); 447 } 448 449 static void 450 multibind_test(const atf_tc_t *tc, int domain, int type) 451 { 452 struct sockaddr_storage ss; 453 int opts[4] = { 0, SO_REUSEADDR, SO_REUSEPORT, SO_REUSEPORT_LB }; 454 int s; 455 bool flags[2] = { false, true }; 456 bool res; 457 458 for (size_t flagi = 0; flagi < nitems(flags); flagi++) { 459 for (size_t opti = 0; opti < nitems(opts); opti++) { 460 s = bind_socket(domain, type, opts[opti], flags[flagi], 461 (struct sockaddr *)&ss); 462 for (size_t optj = 0; optj < nitems(opts); optj++) { 463 int opt; 464 465 opt = opts[optj]; 466 res = child_bind_priv(tc, type, 467 (struct sockaddr *)&ss, opt); 468 /* 469 * Multi-binding is only allowed when both 470 * sockets have SO_REUSEPORT or SO_REUSEPORT_LB 471 * set. 472 */ 473 if (opts[opti] != 0 && 474 opts[opti] != SO_REUSEADDR && opti == optj) 475 ATF_REQUIRE(res); 476 else 477 ATF_REQUIRE(!res); 478 479 res = child_bind_unpriv(tc, type, 480 (struct sockaddr *)&ss, opt); 481 /* 482 * Multi-binding is only allowed when both 483 * sockets have the same owner. 484 */ 485 ATF_REQUIRE(!res); 486 } 487 ATF_REQUIRE(close(s) == 0); 488 } 489 } 490 } 491 492 /* 493 * Try to bind two sockets to the same address/port tuple. Under some 494 * conditions this is permitted. 495 */ 496 ATF_TC(socket_afinet_multibind); 497 ATF_TC_HEAD(socket_afinet_multibind, tc) 498 { 499 atf_tc_set_md_var(tc, "require.user", "root"); 500 atf_tc_set_md_var(tc, "require.config", "unprivileged_user"); 501 } 502 ATF_TC_BODY(socket_afinet_multibind, tc) 503 { 504 multibind_test(tc, AF_INET, SOCK_STREAM); 505 multibind_test(tc, AF_INET, SOCK_DGRAM); 506 multibind_test(tc, AF_INET6, SOCK_STREAM); 507 multibind_test(tc, AF_INET6, SOCK_DGRAM); 508 } 509 510 static void 511 bind_connected_port_test(const atf_tc_t *tc, int domain) 512 { 513 struct sockaddr_in sin; 514 struct sockaddr_in6 sin6; 515 struct sockaddr *sinp; 516 socklen_t slen; 517 int error, sd[3], tmp; 518 bool res; 519 520 /* 521 * Create a connected socket pair. 522 */ 523 sd[0] = socket(domain, SOCK_STREAM, 0); 524 ATF_REQUIRE_MSG(sd[0] >= 0, "socket failed: %s", strerror(errno)); 525 sd[1] = socket(domain, SOCK_STREAM, 0); 526 ATF_REQUIRE_MSG(sd[1] >= 0, "socket failed: %s", strerror(errno)); 527 if (domain == PF_INET) { 528 memset(&sin, 0, sizeof(sin)); 529 sin.sin_family = AF_INET; 530 sin.sin_len = sizeof(sin); 531 sin.sin_addr.s_addr = htonl(INADDR_ANY); 532 sin.sin_port = htons(0); 533 sinp = (struct sockaddr *)&sin; 534 } else { 535 ATF_REQUIRE(domain == PF_INET6); 536 memset(&sin6, 0, sizeof(sin6)); 537 sin6.sin6_family = AF_INET6; 538 sin6.sin6_len = sizeof(sin6); 539 sin6.sin6_addr = in6addr_any; 540 sin6.sin6_port = htons(0); 541 sinp = (struct sockaddr *)&sin6; 542 } 543 544 error = bind(sd[0], sinp, sinp->sa_len); 545 ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno)); 546 error = listen(sd[0], 1); 547 ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno)); 548 549 error = getsockname(sd[0], sinp, &(socklen_t){ sinp->sa_len }); 550 ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno)); 551 if (domain == PF_INET) 552 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 553 else 554 sin6.sin6_addr = in6addr_loopback; 555 error = connect(sd[1], sinp, sinp->sa_len); 556 ATF_REQUIRE_MSG(error == 0, "connect failed: %s", strerror(errno)); 557 slen = sinp->sa_len; 558 tmp = accept(sd[0], sinp, &slen); 559 ATF_REQUIRE_MSG(tmp >= 0, "accept failed: %s", strerror(errno)); 560 561 /* bind() should succeed even from an unprivileged user. */ 562 res = child_bind_priv(tc, SOCK_STREAM, sinp, SO_REUSEADDR); 563 ATF_REQUIRE(res); 564 res = child_bind_unpriv(tc, SOCK_STREAM, sinp, SO_REUSEADDR); 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