1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 /* 17 * Basic set of tests for TCP_MD5SIG. The main design of this is to spin up 18 * connections on localhost that walk through different options and confirm 19 * that traffic either flows or is dropped according to the configuration. 20 */ 21 22 #include <err.h> 23 #include <port.h> 24 #include <stdlib.h> 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <netinet/in.h> 28 #include <netinet/tcp.h> 29 #include <arpa/inet.h> 30 #include <sys/sysmacros.h> 31 #include <stdbool.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <sys/debug.h> 36 37 static hrtime_t sock_to = MSEC2NSEC(100); /* ms in ns */ 38 static const uint32_t msgdata = 0x7777; 39 40 /* 41 * Port setup - see tcpsig_init 42 */ 43 44 /* No SAs are configured */ 45 #define PORT_NOSA 24134 46 /* SAs exist in both directions, and the authentication keys match */ 47 #define PORT_BIDIR 24135 48 /* SAs exist in both directions, but the authentication keys don't match */ 49 #define PORT_MISMATCH 24136 50 /* A single SA exists in the outbound direction, none for inbound */ 51 #define PORT_OBSA 24137 52 /* A single SA exists in the inbound direction, none for outbound */ 53 #define PORT_IBSA 24138 54 55 typedef enum { 56 TCPSIG_SENDRECV, 57 TCPSIG_NOCONNECT, 58 TCPSIG_CONNREFUSED, 59 TCPSIG_NODATA 60 } tcpsig_pass_t; 61 62 typedef struct { 63 const char *tt_desc; 64 const int tt_domain; 65 const uint16_t tt_port; 66 const bool tt_enable_src; 67 const bool tt_enable_dst; 68 const tcpsig_pass_t tt_pass; 69 } tcpsig_test_t; 70 71 static const tcpsig_test_t tcpsig_tests[] = { 72 /* Tests using the port that (hopefully) has no SAs configured */ 73 { 74 .tt_desc = "IPv4 NOSA with MD5 enabled on both sides", 75 .tt_domain = PF_INET, 76 .tt_port = PORT_NOSA, 77 .tt_enable_src = true, 78 .tt_enable_dst = true, 79 .tt_pass = TCPSIG_CONNREFUSED 80 }, { 81 .tt_desc = "IPv4 NOSA with MD5 disabled on both sides", 82 .tt_domain = PF_INET, 83 .tt_port = PORT_NOSA, 84 .tt_enable_src = false, 85 .tt_enable_dst = false, 86 .tt_pass = TCPSIG_SENDRECV 87 }, { 88 .tt_desc = "IPv4 NOSA with MD5 enabled on src only", 89 .tt_domain = PF_INET, 90 .tt_port = PORT_NOSA, 91 .tt_enable_src = true, 92 .tt_enable_dst = false, 93 .tt_pass = TCPSIG_CONNREFUSED 94 }, { 95 .tt_desc = "IPv4 NOSA with MD5 enabled on dst only", 96 .tt_domain = PF_INET, 97 .tt_port = PORT_NOSA, 98 .tt_enable_src = false, 99 .tt_enable_dst = true, 100 .tt_pass = TCPSIG_SENDRECV 101 }, 102 { 103 .tt_desc = "IPv6 NOSA with MD5 enabled on both sides", 104 .tt_domain = PF_INET6, 105 .tt_port = PORT_NOSA, 106 .tt_enable_src = true, 107 .tt_enable_dst = true, 108 .tt_pass = TCPSIG_CONNREFUSED 109 }, { 110 .tt_desc = "IPv6 NOSA with MD5 disabled on both sides", 111 .tt_domain = PF_INET6, 112 .tt_port = PORT_NOSA, 113 .tt_enable_src = false, 114 .tt_enable_dst = false, 115 .tt_pass = TCPSIG_SENDRECV 116 }, { 117 .tt_desc = "IPv6 NOSA with MD5 enabled on src only", 118 .tt_domain = PF_INET6, 119 .tt_port = PORT_NOSA, 120 .tt_enable_src = true, 121 .tt_enable_dst = false, 122 .tt_pass = TCPSIG_CONNREFUSED 123 }, { 124 .tt_desc = "IPv6 NOSA with MD5 enabled on dst only", 125 .tt_domain = PF_INET6, 126 .tt_port = PORT_NOSA, 127 .tt_enable_src = false, 128 .tt_enable_dst = true, 129 .tt_pass = TCPSIG_SENDRECV 130 }, 131 /* Tests using the port that has bi-directional SAs configured */ 132 { 133 .tt_desc = "IPv4 BIDIR with MD5 enabled on both sides", 134 .tt_domain = PF_INET, 135 .tt_port = PORT_BIDIR, 136 .tt_enable_src = true, 137 .tt_enable_dst = true, 138 .tt_pass = TCPSIG_SENDRECV 139 }, { 140 .tt_desc = "IPv4 BIDIR with MD5 disabled on both sides", 141 .tt_domain = PF_INET, 142 .tt_port = PORT_BIDIR, 143 .tt_enable_src = false, 144 .tt_enable_dst = false, 145 .tt_pass = TCPSIG_SENDRECV 146 }, { 147 .tt_desc = "IPv4 BIDIR with MD5 enabled on src only", 148 .tt_domain = PF_INET, 149 .tt_port = PORT_BIDIR, 150 .tt_enable_src = true, 151 .tt_enable_dst = false, 152 .tt_pass = TCPSIG_NOCONNECT 153 }, { 154 .tt_desc = "IPv4 BIDIR with MD5 enabled on dst only", 155 .tt_domain = PF_INET, 156 .tt_port = PORT_BIDIR, 157 .tt_enable_src = false, 158 .tt_enable_dst = true, 159 .tt_pass = TCPSIG_NOCONNECT 160 }, { 161 .tt_desc = "IPv6 BIDIR with MD5 enabled on both sides", 162 .tt_domain = PF_INET6, 163 .tt_port = PORT_BIDIR, 164 .tt_enable_src = true, 165 .tt_enable_dst = true, 166 .tt_pass = TCPSIG_SENDRECV 167 }, { 168 .tt_desc = "IPv6 BIDIR with MD5 disabled on both sides", 169 .tt_domain = PF_INET6, 170 .tt_port = PORT_BIDIR, 171 .tt_enable_src = false, 172 .tt_enable_dst = false, 173 .tt_pass = TCPSIG_SENDRECV 174 }, { 175 .tt_desc = "IPv6 BIDIR with MD5 enabled on src only", 176 .tt_domain = PF_INET6, 177 .tt_port = PORT_BIDIR, 178 .tt_enable_src = true, 179 .tt_enable_dst = false, 180 .tt_pass = TCPSIG_NOCONNECT 181 }, { 182 .tt_desc = "IPv6 BIDIR with MD5 enabled on dst only", 183 .tt_domain = PF_INET6, 184 .tt_port = PORT_BIDIR, 185 .tt_enable_src = false, 186 .tt_enable_dst = true, 187 .tt_pass = TCPSIG_NOCONNECT 188 }, 189 /* Tests using the port with mismatching SA keys */ 190 { 191 /* 192 * Both sides of the connection have access to the two 193 * SAs and will use the correct key depending on the direction 194 * of the traffic. We therefore expect this to succeed. 195 * `tcpdump -M` can be used to verify that a different key is 196 * being used in each direction. 197 */ 198 .tt_desc = "IPv4 MISMATCH with MD5 enabled on both sides", 199 .tt_domain = PF_INET, 200 .tt_port = PORT_MISMATCH, 201 .tt_enable_src = true, 202 .tt_enable_dst = true, 203 .tt_pass = TCPSIG_SENDRECV 204 }, { 205 .tt_desc = "IPv4 MISMATCH with MD5 disabled on both sides", 206 .tt_domain = PF_INET, 207 .tt_port = PORT_MISMATCH, 208 .tt_enable_src = false, 209 .tt_enable_dst = false, 210 .tt_pass = TCPSIG_SENDRECV 211 }, { 212 .tt_desc = "IPv4 MISMATCH with MD5 enabled on src only", 213 .tt_domain = PF_INET, 214 .tt_port = PORT_MISMATCH, 215 .tt_enable_src = true, 216 .tt_enable_dst = false, 217 .tt_pass = TCPSIG_NOCONNECT 218 }, { 219 .tt_desc = "IPv4 MISMATCH with MD5 enabled on dst only", 220 .tt_domain = PF_INET, 221 .tt_port = PORT_MISMATCH, 222 .tt_enable_src = false, 223 .tt_enable_dst = true, 224 .tt_pass = TCPSIG_NOCONNECT 225 }, { 226 .tt_desc = "IPv6 MISMATCH with MD5 enabled on both sides", 227 .tt_domain = PF_INET6, 228 .tt_port = PORT_MISMATCH, 229 .tt_enable_src = true, 230 .tt_enable_dst = true, 231 .tt_pass = TCPSIG_SENDRECV 232 }, { 233 .tt_desc = "IPv6 MISMATCH with MD5 disabled on both sides", 234 .tt_domain = PF_INET6, 235 .tt_port = PORT_MISMATCH, 236 .tt_enable_src = false, 237 .tt_enable_dst = false, 238 .tt_pass = TCPSIG_SENDRECV 239 }, { 240 .tt_desc = "IPv6 MISMATCH with MD5 enabled on src only", 241 .tt_domain = PF_INET6, 242 .tt_port = PORT_MISMATCH, 243 .tt_enable_src = true, 244 .tt_enable_dst = false, 245 .tt_pass = TCPSIG_NOCONNECT 246 }, { 247 .tt_desc = "IPv6 MISMATCH with MD5 enabled on dst only", 248 .tt_domain = PF_INET6, 249 .tt_port = PORT_MISMATCH, 250 .tt_enable_src = false, 251 .tt_enable_dst = true, 252 .tt_pass = TCPSIG_NOCONNECT 253 }, 254 /* Tests using the port with only an outbound SA */ 255 { 256 .tt_desc = "IPv4 OBSA with MD5 enabled on both sides", 257 .tt_domain = PF_INET, 258 .tt_port = PORT_OBSA, 259 .tt_enable_src = true, 260 .tt_enable_dst = true, 261 .tt_pass = TCPSIG_NOCONNECT 262 }, { 263 .tt_desc = "IPv4 OBSA with MD5 disabled on both sides", 264 .tt_domain = PF_INET, 265 .tt_port = PORT_OBSA, 266 .tt_enable_src = false, 267 .tt_enable_dst = false, 268 .tt_pass = TCPSIG_SENDRECV 269 }, { 270 .tt_desc = "IPv4 OBSA with MD5 enabled on src only", 271 .tt_domain = PF_INET, 272 .tt_port = PORT_OBSA, 273 .tt_enable_src = true, 274 .tt_enable_dst = false, 275 .tt_pass = TCPSIG_NOCONNECT 276 }, { 277 .tt_desc = "IPv4 OBSA with MD5 enabled on dst only", 278 .tt_domain = PF_INET, 279 .tt_port = PORT_OBSA, 280 .tt_enable_src = false, 281 .tt_enable_dst = true, 282 .tt_pass = TCPSIG_NOCONNECT 283 }, { 284 .tt_desc = "IPv6 OBSA with MD5 enabled on both sides", 285 .tt_domain = PF_INET6, 286 .tt_port = PORT_OBSA, 287 .tt_enable_src = true, 288 .tt_enable_dst = true, 289 .tt_pass = TCPSIG_NOCONNECT 290 }, { 291 .tt_desc = "IPv6 OBSA with MD5 disabled on both sides", 292 .tt_domain = PF_INET6, 293 .tt_port = PORT_OBSA, 294 .tt_enable_src = false, 295 .tt_enable_dst = false, 296 .tt_pass = TCPSIG_SENDRECV 297 }, { 298 .tt_desc = "IPv6 OBSA with MD5 enabled on src only", 299 .tt_domain = PF_INET6, 300 .tt_port = PORT_OBSA, 301 .tt_enable_src = true, 302 .tt_enable_dst = false, 303 .tt_pass = TCPSIG_NOCONNECT 304 }, { 305 .tt_desc = "IPv6 OBSA with MD5 enabled on dst only", 306 .tt_domain = PF_INET6, 307 .tt_port = PORT_OBSA, 308 .tt_enable_src = false, 309 .tt_enable_dst = true, 310 .tt_pass = TCPSIG_NOCONNECT 311 }, 312 /* Tests using the port with only an inbound SA */ 313 { 314 .tt_desc = "IPv4 IBSA with MD5 enabled on both sides", 315 .tt_domain = PF_INET, 316 .tt_port = PORT_IBSA, 317 .tt_enable_src = true, 318 .tt_enable_dst = true, 319 .tt_pass = TCPSIG_CONNREFUSED 320 }, { 321 .tt_desc = "IPv4 IBSA with MD5 disabled on both sides", 322 .tt_domain = PF_INET, 323 .tt_port = PORT_IBSA, 324 .tt_enable_src = false, 325 .tt_enable_dst = false, 326 .tt_pass = TCPSIG_SENDRECV 327 }, { 328 .tt_desc = "IPv4 IBSA with MD5 enabled on src only", 329 .tt_domain = PF_INET, 330 .tt_port = PORT_IBSA, 331 .tt_enable_src = true, 332 .tt_enable_dst = false, 333 .tt_pass = TCPSIG_CONNREFUSED 334 }, { 335 .tt_desc = "IPv4 IBSA with MD5 enabled on dst only", 336 .tt_domain = PF_INET, 337 .tt_port = PORT_IBSA, 338 .tt_enable_src = false, 339 .tt_enable_dst = true, 340 .tt_pass = TCPSIG_SENDRECV 341 }, { 342 .tt_desc = "IPv6 IBSA with MD5 enabled on both sides", 343 .tt_domain = PF_INET6, 344 .tt_port = PORT_IBSA, 345 .tt_enable_src = true, 346 .tt_enable_dst = true, 347 .tt_pass = TCPSIG_CONNREFUSED 348 }, { 349 .tt_desc = "IPv6 IBSA with MD5 disabled on both sides", 350 .tt_domain = PF_INET6, 351 .tt_port = PORT_IBSA, 352 .tt_enable_src = false, 353 .tt_enable_dst = false, 354 .tt_pass = TCPSIG_SENDRECV 355 }, { 356 .tt_desc = "IPv6 IBSA with MD5 enabled on src only", 357 .tt_domain = PF_INET6, 358 .tt_port = PORT_IBSA, 359 .tt_enable_src = true, 360 .tt_enable_dst = false, 361 .tt_pass = TCPSIG_CONNREFUSED 362 }, { 363 .tt_desc = "IPv6 IBSA with MD5 enabled on dst only", 364 .tt_domain = PF_INET6, 365 .tt_port = PORT_IBSA, 366 .tt_enable_src = false, 367 .tt_enable_dst = true, 368 .tt_pass = TCPSIG_SENDRECV 369 } 370 }; 371 372 static bool 373 tcpsig_bind_dest(const tcpsig_test_t *test, int sock, 374 struct sockaddr_storage *dst) 375 { 376 socklen_t len; 377 struct sockaddr_storage addr; 378 379 (void) memset(&addr, 0, sizeof (struct sockaddr_storage)); 380 381 if (test->tt_domain == PF_INET) { 382 struct sockaddr_in *in = (struct sockaddr_in *)&addr; 383 in->sin_family = AF_INET; 384 in->sin_port = htons(test->tt_port); 385 if (inet_pton(AF_INET, "127.0.0.1", &in->sin_addr) != 1) { 386 warnx("TEST FAILED: %s: failed to convert 127.0.0.1 " 387 "to an IPv4 address", test->tt_desc); 388 return (false); 389 } 390 len = sizeof (struct sockaddr_in); 391 } else { 392 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; 393 in6->sin6_family = AF_INET6; 394 in6->sin6_port = htons(test->tt_port); 395 if (inet_pton(AF_INET6, "::1", &in6->sin6_addr) != 1) { 396 warnx("TEST FAILED: %s: failed to convert ::1 " 397 "to an IPv6 address", test->tt_desc); 398 return (false); 399 } 400 len = sizeof (struct sockaddr_in6); 401 } 402 403 if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 404 warn("TEST FAILED: %s: failed to bind listen socket", 405 test->tt_desc); 406 return (false); 407 } 408 409 len = sizeof (struct sockaddr_storage); 410 if (getsockname(sock, (struct sockaddr *)dst, &len) != 0) { 411 warn("TEST FAILED: %s: failed to retrieve socket address ", 412 test->tt_desc); 413 return (false); 414 } 415 416 return (true); 417 } 418 419 /* 420 * Our job is to attempt to connect to the other end with our current settings. 421 * This may not work, so we use our port to get things ready just in case. 422 */ 423 static bool 424 tcpsig_connect(const tcpsig_test_t *test, int port, int src, int dst, int *cfd, 425 const struct sockaddr *addr) 426 { 427 struct timespec to = { .tv_nsec = sock_to }; 428 int namelen = test->tt_domain == PF_INET ? sizeof (struct sockaddr_in) : 429 sizeof (struct sockaddr_in6); 430 int conn, opt; 431 unsigned int optlen; 432 port_event_t pe; 433 434 if (listen(dst, 5) != 0) { 435 warn("TEST FAILED: %s: failed to listen", test->tt_desc); 436 return (false); 437 } 438 439 if (connect(src, addr, namelen) != 0 && errno != EINPROGRESS) { 440 if (errno == ECONNREFUSED && 441 test->tt_pass == TCPSIG_CONNREFUSED) { 442 (void) printf("TEST PASSED: %s: connection refused\n", 443 test->tt_desc); 444 return (true); 445 } 446 warn("TEST FAILED: %s: failed to connect", test->tt_desc); 447 return (false); 448 } 449 450 if (port_associate(port, PORT_SOURCE_FD, src, POLLOUT, NULL) != 0) { 451 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port " 452 "associate to watch connect", test->tt_desc); 453 } 454 455 if (port_get(port, &pe, &to) != 0) { 456 if (test->tt_pass == TCPSIG_NOCONNECT) { 457 (void) printf( 458 "TEST PASSED: %s: correctly failed to connect\n", 459 test->tt_desc); 460 return (true); 461 } else { 462 warn("TEST FAILED: %s: timed out waiting to connect", 463 test->tt_desc); 464 return (false); 465 } 466 } 467 468 if ((pe.portev_events & POLLOUT) == 0) { 469 warnx("TEST FAILED: %s: connect port event doesn't contain " 470 "POLLOUT, found 0x%x", test->tt_desc, pe.portev_events); 471 return (false); 472 } 473 474 /* 475 * Now make sure the listen socket is ready. 476 */ 477 if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) { 478 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port " 479 "associate to watch accept", test->tt_desc); 480 } 481 482 if (port_get(port, &pe, &to) != 0) { 483 warn("TEST FAILED: %s: timed out waiting to accept", 484 test->tt_desc); 485 return (false); 486 } 487 488 if ((pe.portev_events & POLLIN) == 0) { 489 warnx("TEST FAILED: %s: accept port event doesn't contain " 490 "POLLIN, found 0x%x", test->tt_desc, pe.portev_events); 491 return (false); 492 } 493 494 conn = accept4(dst, NULL, NULL, SOCK_NONBLOCK); 495 if (conn < 0) { 496 warn("TEST FAILED: %s: failed to get client connection", 497 test->tt_desc); 498 return (false); 499 } 500 501 optlen = sizeof (opt); 502 if (getsockopt(conn, IPPROTO_TCP, TCP_MD5SIG, &opt, &optlen) != 0) { 503 warn("TEST FAILED: %s: failed to retrieve accepted socket " 504 "TCP_MD5SIG option", test->tt_desc); 505 return (false); 506 } 507 508 if (optlen != sizeof (opt)) { 509 warn("TEST FAILED: %s: TCP_MD5SIG option has wrong length %d " 510 "(expected %ld).", test->tt_desc, optlen, sizeof (opt)); 511 return (false); 512 } 513 514 /* 515 * For tests where the TCP MD5 option is not enabled on the source, but 516 * is on the destination, and where we expect the connection to 517 * succeed, we also expect that the socket option has been disabled on 518 * accept(). Check. 519 */ 520 if (test->tt_enable_dst && !test->tt_enable_src && 521 test->tt_pass == TCPSIG_SENDRECV && opt != 0) { 522 warnx("TEST FAILED: %s: TCP_MD5SIG is set and should not be", 523 test->tt_desc); 524 return (false); 525 } else if (test->tt_enable_src && opt == 0) { 526 warnx("TEST FAILED: %s: TCP_MD5SIG is not set and should be", 527 test->tt_desc); 528 return (false); 529 } 530 531 if (test->tt_pass != TCPSIG_SENDRECV && 532 test->tt_pass != TCPSIG_NODATA) { 533 warnx("TEST FAILED: %s: expected connect to fail, but passed", 534 test->tt_desc); 535 return (false); 536 } 537 538 *cfd = conn; 539 return (true); 540 } 541 542 /* 543 * Attempt to send data with the tcpsigs set up appropriately. This might fail, 544 * hence our port_associate dance and unfortunately regrettable timeout. 545 */ 546 static bool 547 tcpsig_sendrecv(const tcpsig_test_t *test, int port, int src, int dst) 548 { 549 struct timespec to = { .tv_nsec = sock_to }; 550 port_event_t pe; 551 uint32_t data; 552 ssize_t sret; 553 554 if (send(src, &msgdata, sizeof (msgdata), MSG_NOSIGNAL) != 555 sizeof (msgdata)) { 556 warn("TEST FAILED: %s: failed to write message to socket", 557 test->tt_desc); 558 } 559 560 if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) { 561 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port " 562 "associate to watch recv", test->tt_desc); 563 } 564 565 if (port_get(port, &pe, &to) != 0) { 566 if (test->tt_pass == TCPSIG_NODATA) { 567 (void) printf("TEST PASSED: %s: timed out waiting " 568 "for data\n", test->tt_desc); 569 return (true); 570 } else { 571 warn("TEST FAILED: %s: timed out waiting to recv", 572 test->tt_desc); 573 return (false); 574 } 575 } 576 577 if ((pe.portev_events & POLLIN) == 0) { 578 warnx("TEST FAILED: %s: receive port event doesn't contain " 579 "POLLIN, found 0x%x", test->tt_desc, pe.portev_events); 580 return (false); 581 } 582 583 sret = recv(dst, &data, sizeof (data), MSG_DONTWAIT); 584 if (sret != (ssize_t)sizeof (data)) { 585 warnx("TEST FAILED: %s: failed to receive data: %zx", 586 test->tt_desc, sret); 587 return (false); 588 } 589 590 if (test->tt_pass != TCPSIG_SENDRECV) { 591 warnx("TEST FAILED: %s: found data, despite expecting not to", 592 test->tt_desc); 593 return (false); 594 } 595 596 if (data != msgdata) { 597 warnx("TEST FAILED: %s: data mismatch: expected 0x%x, found " 598 "0x%x", test->tt_desc, msgdata, data); 599 return (false); 600 } 601 602 (void) printf("TEST PASSED: %s: successfully received data\n", 603 test->tt_desc); 604 return (true); 605 } 606 607 static bool 608 tcpsig_test_one(const tcpsig_test_t *test) 609 { 610 int src = -1, dst = -1, cfd = -1, port = -1, tdst; 611 int x; 612 bool ret = true; 613 struct sockaddr_storage dst_addr; 614 615 if ((port = port_create()) < 0) 616 err(EXIT_FAILURE, "TEST FAILED: failed to create event port"); 617 618 src = socket(test->tt_domain, SOCK_STREAM | SOCK_NONBLOCK, 0); 619 if (src < 0) { 620 warn("TEST FAILED: %s: failed to create source socket", 621 test->tt_desc); 622 ret = false; 623 goto cleanup; 624 } 625 626 x = test->tt_enable_src ? 1 : 0; 627 if (setsockopt(src, IPPROTO_TCP, TCP_MD5SIG, &x, sizeof (x)) != 0) { 628 warn("TEST FAILED: %s: failed to configure src MD5SIG option", 629 test->tt_desc); 630 ret = false; 631 goto cleanup; 632 } 633 634 dst = socket(test->tt_domain, SOCK_STREAM | SOCK_NONBLOCK, 0); 635 if (dst < 0) { 636 warn("TEST FAILED: %s: failed to create destination socket", 637 test->tt_desc); 638 ret = false; 639 goto cleanup; 640 } 641 642 x = test->tt_enable_dst ? 1 : 0; 643 if (setsockopt(dst, IPPROTO_TCP, TCP_MD5SIG, &x, sizeof (x)) != 0) { 644 warn("TEST FAILED: %s: failed to configure dst MD5SIG option", 645 test->tt_desc); 646 ret = false; 647 goto cleanup; 648 } 649 650 if (!tcpsig_bind_dest(test, dst, &dst_addr)) { 651 ret = false; 652 goto cleanup; 653 } 654 655 if (!tcpsig_connect(test, port, src, dst, &cfd, 656 (struct sockaddr *)&dst_addr)) { 657 ret = false; 658 goto cleanup; 659 } 660 661 if (test->tt_pass != TCPSIG_SENDRECV && test->tt_pass != TCPSIG_NODATA) 662 goto cleanup; 663 664 tdst = cfd; 665 666 if (!tcpsig_sendrecv(test, port, src, tdst)) { 667 ret = false; 668 goto cleanup; 669 } 670 671 cleanup: 672 if (port > -1) 673 (void) close(port); 674 if (src > -1) { 675 (void) shutdown(src, SHUT_RDWR); 676 (void) close(src); 677 } 678 if (dst > -1) 679 (void) close(dst); 680 if (cfd > -1) 681 (void) close(cfd); 682 return (ret); 683 } 684 685 int 686 main(int argc, char **argv) 687 { 688 size_t max = ARRAY_SIZE(tcpsig_tests) - 1; 689 int ret = EXIT_SUCCESS; 690 691 if (argc == 2) { 692 const char *errstr; 693 size_t idx; 694 695 idx = (size_t)strtonumx(argv[1], 0, max, &errstr, 0); 696 if (errstr != NULL) { 697 (void) fprintf(stderr, "Syntax: %s [test number]\n", 698 getprogname()); 699 (void) fprintf(stderr, 700 "Test number is in the range [0-%u]\n", max); 701 (void) fprintf(stderr, "\nAvailable tests:\n"); 702 for (size_t i = 0; i <= max; i++) { 703 (void) fprintf(stderr, " %5d - %s\n", i, 704 tcpsig_tests[i].tt_desc); 705 } 706 return (EXIT_FAILURE); 707 } 708 709 if (!tcpsig_test_one(&tcpsig_tests[idx])) 710 ret = EXIT_FAILURE; 711 } else { 712 for (size_t i = 0; i <= max; i++) { 713 if (!tcpsig_test_one(&tcpsig_tests[i])) 714 ret = EXIT_FAILURE; 715 } 716 if (ret == EXIT_SUCCESS) 717 (void) printf("All tests passed successfully\n"); 718 } 719 720 return (ret); 721 } 722