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 IP_MINTTL and IPV6_MINHOPCOUNT. The main design of 18 * this is to spin up connections on localhost that walk through different 19 * socket types and confirm that we can use the corresponding socket option and 20 * that we receive traffic when the TTL is set and not otherwise. 21 */ 22 23 #include <err.h> 24 #include <port.h> 25 #include <stdlib.h> 26 #include <sys/types.h> 27 #include <sys/socket.h> 28 #include <netinet/in.h> 29 #include <netinet/sctp.h> 30 #include <arpa/inet.h> 31 #include <sys/sysmacros.h> 32 #include <stdbool.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <sys/debug.h> 37 38 /* 39 * The IP protocols 0xfd-0xfe are reserved for experiments. This is the safest 40 * IP protocol for us to use then in our testing for raw sockets. 41 */ 42 #define TTL_IPPROTO_EXP 0xfd 43 44 static hrtime_t tt_sock_to = MSEC2NSEC(100); /* ms in ns */ 45 static const uint32_t tt_msg = 0x7777; 46 47 typedef enum { 48 TTL_SENDRECV, 49 TTL_NOCONNECT, 50 TTL_NODATA 51 } ttl_pass_t; 52 53 typedef struct { 54 const char *tt_desc; 55 int tt_domain; 56 int tt_type; 57 int tt_ttl; 58 int tt_proto; 59 int tt_minttl; 60 ttl_pass_t tt_pass; 61 } ttl_test_t; 62 63 static const ttl_test_t ttl_tests[] = { 64 { 65 .tt_desc = "IPv4 TCP TTL/MIN: unset/0", 66 .tt_domain = PF_INET, 67 .tt_type = SOCK_STREAM, 68 .tt_ttl = 0, 69 .tt_minttl = 0, 70 .tt_pass = TTL_SENDRECV 71 }, { 72 .tt_desc = "IPv4 TCP TTL/MIN: 200/100", 73 .tt_domain = PF_INET, 74 .tt_type = SOCK_STREAM, 75 .tt_ttl = 200, 76 .tt_minttl = 100, 77 .tt_pass = TTL_SENDRECV 78 }, { 79 .tt_desc = "IPv4 TCP TTL/MIN: 255/255", 80 .tt_domain = PF_INET, 81 .tt_type = SOCK_STREAM, 82 .tt_ttl = 255, 83 .tt_minttl = 255, 84 .tt_pass = TTL_SENDRECV 85 }, { 86 .tt_desc = "IPv4 TCP TTL/MIN: 23/169", 87 .tt_domain = PF_INET, 88 .tt_type = SOCK_STREAM, 89 .tt_ttl = 23, 90 .tt_minttl = 169, 91 .tt_pass = TTL_NOCONNECT 92 }, { 93 .tt_desc = "IPv4 TCP TTL/MIN: 254/255", 94 .tt_domain = PF_INET, 95 .tt_type = SOCK_STREAM, 96 .tt_ttl = 254, 97 .tt_minttl = 255, 98 .tt_pass = TTL_NOCONNECT 99 }, { 100 .tt_desc = "IPv4 UDP TTL/MIN: unset/0", 101 .tt_domain = PF_INET, 102 .tt_type = SOCK_DGRAM, 103 .tt_ttl = 0, 104 .tt_minttl = 0, 105 .tt_pass = TTL_SENDRECV 106 }, { 107 .tt_desc = "IPv4 UDP TTL/MIN: 200/100", 108 .tt_domain = PF_INET, 109 .tt_type = SOCK_DGRAM, 110 .tt_ttl = 200, 111 .tt_minttl = 100, 112 .tt_pass = TTL_SENDRECV 113 }, { 114 .tt_desc = "IPv4 UDP TTL/MIN: 255/255", 115 .tt_domain = PF_INET, 116 .tt_type = SOCK_DGRAM, 117 .tt_ttl = 255, 118 .tt_minttl = 255, 119 .tt_pass = TTL_SENDRECV 120 }, { 121 .tt_desc = "IPv4 UDP TTL/MIN: 23/169", 122 .tt_domain = PF_INET, 123 .tt_type = SOCK_DGRAM, 124 .tt_ttl = 23, 125 .tt_minttl = 169, 126 .tt_pass = TTL_NODATA 127 }, { 128 .tt_desc = "IPv4 UDP TTL/MIN: 254/255", 129 .tt_domain = PF_INET, 130 .tt_type = SOCK_DGRAM, 131 .tt_ttl = 254, 132 .tt_minttl = 255, 133 .tt_pass = TTL_NODATA 134 }, { 135 .tt_desc = "IPv4 SCTP TTL/MIN: unset/0", 136 .tt_domain = PF_INET, 137 .tt_type = SOCK_STREAM, 138 .tt_proto = IPPROTO_SCTP, 139 .tt_ttl = 0, 140 .tt_minttl = 0, 141 .tt_pass = TTL_SENDRECV 142 }, { 143 .tt_desc = "IPv4 SCTP TTL/MIN: 200/100", 144 .tt_domain = PF_INET, 145 .tt_type = SOCK_STREAM, 146 .tt_proto = IPPROTO_SCTP, 147 .tt_ttl = 200, 148 .tt_minttl = 100, 149 .tt_pass = TTL_SENDRECV 150 }, { 151 .tt_desc = "IPv4 SCTP TTL/MIN: 255/255", 152 .tt_domain = PF_INET, 153 .tt_type = SOCK_STREAM, 154 .tt_proto = IPPROTO_SCTP, 155 .tt_ttl = 255, 156 .tt_minttl = 255, 157 .tt_pass = TTL_SENDRECV 158 }, { 159 .tt_desc = "IPv4 SCTP TTL/MIN: 23/169", 160 .tt_domain = PF_INET, 161 .tt_type = SOCK_STREAM, 162 .tt_proto = IPPROTO_SCTP, 163 .tt_ttl = 23, 164 .tt_minttl = 169, 165 .tt_pass = TTL_NOCONNECT 166 }, { 167 .tt_desc = "IPv4 SCTP TTL/MIN: 254/255", 168 .tt_domain = PF_INET, 169 .tt_type = SOCK_STREAM, 170 .tt_proto = IPPROTO_SCTP, 171 .tt_ttl = 254, 172 .tt_minttl = 255, 173 .tt_pass = TTL_NOCONNECT 174 }, { 175 .tt_desc = "IPv4 RAW (0xfd) TTL/MIN: unset/0", 176 .tt_domain = PF_INET, 177 .tt_type = SOCK_RAW, 178 .tt_proto = TTL_IPPROTO_EXP, 179 .tt_ttl = 0, 180 .tt_minttl = 0, 181 .tt_pass = TTL_SENDRECV 182 }, { 183 .tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 200/100", 184 .tt_domain = PF_INET, 185 .tt_type = SOCK_RAW, 186 .tt_proto = TTL_IPPROTO_EXP, 187 .tt_ttl = 200, 188 .tt_minttl = 100, 189 .tt_pass = TTL_SENDRECV 190 }, { 191 .tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 255/255", 192 .tt_domain = PF_INET, 193 .tt_type = SOCK_RAW, 194 .tt_proto = TTL_IPPROTO_EXP, 195 .tt_ttl = 255, 196 .tt_minttl = 255, 197 .tt_pass = TTL_SENDRECV 198 }, { 199 .tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 23/169", 200 .tt_domain = PF_INET, 201 .tt_type = SOCK_RAW, 202 .tt_proto = TTL_IPPROTO_EXP, 203 .tt_ttl = 23, 204 .tt_minttl = 169, 205 .tt_pass = TTL_NODATA 206 }, { 207 .tt_desc = "IPv4 RAW (0xfd) TTL/MIN: 254/255", 208 .tt_domain = PF_INET, 209 .tt_type = SOCK_RAW, 210 .tt_proto = TTL_IPPROTO_EXP, 211 .tt_ttl = 254, 212 .tt_minttl = 255, 213 .tt_pass = TTL_NODATA 214 }, { 215 .tt_desc = "IPv6 TCP TTL/MIN: unset/0", 216 .tt_domain = PF_INET6, 217 .tt_type = SOCK_STREAM, 218 .tt_ttl = 0, 219 .tt_minttl = 0, 220 .tt_pass = TTL_SENDRECV 221 }, { 222 .tt_desc = "IPv6 TCP TTL/MIN: 200/100", 223 .tt_domain = PF_INET6, 224 .tt_type = SOCK_STREAM, 225 .tt_ttl = 200, 226 .tt_minttl = 100, 227 .tt_pass = TTL_SENDRECV 228 }, { 229 .tt_desc = "IPv6 TCP TTL/MIN: 255/255", 230 .tt_domain = PF_INET6, 231 .tt_type = SOCK_STREAM, 232 .tt_ttl = 255, 233 .tt_minttl = 255, 234 .tt_pass = TTL_SENDRECV 235 }, { 236 .tt_desc = "IPv6 CTP TTL/MIN: 23/169", 237 .tt_domain = PF_INET6, 238 .tt_type = SOCK_STREAM, 239 .tt_ttl = 23, 240 .tt_minttl = 169, 241 .tt_pass = TTL_NOCONNECT 242 }, { 243 .tt_desc = "IPv6 CTP TTL/MIN: 254/255", 244 .tt_domain = PF_INET6, 245 .tt_type = SOCK_STREAM, 246 .tt_ttl = 254, 247 .tt_minttl = 255, 248 .tt_pass = TTL_NOCONNECT 249 }, { 250 .tt_desc = "IPv6 UDP TTL/MIN: unset/0", 251 .tt_domain = PF_INET6, 252 .tt_type = SOCK_DGRAM, 253 .tt_ttl = 0, 254 .tt_minttl = 0, 255 .tt_pass = TTL_SENDRECV 256 }, { 257 .tt_desc = "IPv6 UDP TTL/MIN: 200/100", 258 .tt_domain = PF_INET6, 259 .tt_type = SOCK_DGRAM, 260 .tt_ttl = 200, 261 .tt_minttl = 100, 262 .tt_pass = TTL_SENDRECV 263 }, { 264 .tt_desc = "IPv6 UDP TTL/MIN: 255/255", 265 .tt_domain = PF_INET6, 266 .tt_type = SOCK_DGRAM, 267 .tt_ttl = 255, 268 .tt_minttl = 255, 269 .tt_pass = TTL_SENDRECV 270 }, { 271 .tt_desc = "IPv6 UDP TTL/MIN: 23/169", 272 .tt_domain = PF_INET6, 273 .tt_type = SOCK_DGRAM, 274 .tt_ttl = 23, 275 .tt_minttl = 169, 276 .tt_pass = TTL_NODATA 277 }, { 278 .tt_desc = "IPv6 UDP TTL/MIN: 254/255", 279 .tt_domain = PF_INET6, 280 .tt_type = SOCK_DGRAM, 281 .tt_ttl = 254, 282 .tt_minttl = 255, 283 .tt_pass = TTL_NODATA 284 }, { 285 .tt_desc = "IPv6 SCTP TTL/MIN: unset/0", 286 .tt_domain = PF_INET6, 287 .tt_type = SOCK_STREAM, 288 .tt_proto = IPPROTO_SCTP, 289 .tt_ttl = 0, 290 .tt_minttl = 0, 291 .tt_pass = TTL_SENDRECV 292 }, { 293 .tt_desc = "IPv6 SCTP TTL/MIN: 200/100", 294 .tt_domain = PF_INET6, 295 .tt_type = SOCK_STREAM, 296 .tt_proto = IPPROTO_SCTP, 297 .tt_ttl = 200, 298 .tt_minttl = 100, 299 .tt_pass = TTL_SENDRECV 300 }, { 301 .tt_desc = "IPv6 SCTP TTL/MIN: 255/255", 302 .tt_domain = PF_INET6, 303 .tt_type = SOCK_STREAM, 304 .tt_proto = IPPROTO_SCTP, 305 .tt_ttl = 255, 306 .tt_minttl = 255, 307 .tt_pass = TTL_SENDRECV 308 }, { 309 .tt_desc = "IPv6 SCTP TTL/MIN: 23/169", 310 .tt_domain = PF_INET6, 311 .tt_type = SOCK_STREAM, 312 .tt_proto = IPPROTO_SCTP, 313 .tt_ttl = 23, 314 .tt_minttl = 169, 315 .tt_pass = TTL_NOCONNECT 316 }, { 317 .tt_desc = "IPv6 SCTP TTL/MIN: 254/255", 318 .tt_domain = PF_INET6, 319 .tt_type = SOCK_STREAM, 320 .tt_proto = IPPROTO_SCTP, 321 .tt_ttl = 254, 322 .tt_minttl = 255, 323 .tt_pass = TTL_NOCONNECT 324 }, { 325 .tt_desc = "IPv6 RAW (0xfd) TTL/MIN: unset/0", 326 .tt_domain = PF_INET6, 327 .tt_type = SOCK_RAW, 328 .tt_proto = TTL_IPPROTO_EXP, 329 .tt_ttl = 0, 330 .tt_minttl = 0, 331 .tt_pass = TTL_SENDRECV 332 }, { 333 .tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 200/100", 334 .tt_domain = PF_INET6, 335 .tt_type = SOCK_RAW, 336 .tt_proto = TTL_IPPROTO_EXP, 337 .tt_ttl = 200, 338 .tt_minttl = 100, 339 .tt_pass = TTL_SENDRECV 340 }, { 341 .tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 255/255", 342 .tt_domain = PF_INET6, 343 .tt_type = SOCK_RAW, 344 .tt_proto = TTL_IPPROTO_EXP, 345 .tt_ttl = 255, 346 .tt_minttl = 255, 347 .tt_pass = TTL_SENDRECV 348 }, { 349 .tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 23/169", 350 .tt_domain = PF_INET6, 351 .tt_type = SOCK_RAW, 352 .tt_proto = TTL_IPPROTO_EXP, 353 .tt_ttl = 23, 354 .tt_minttl = 169, 355 .tt_pass = TTL_NODATA 356 }, { 357 .tt_desc = "IPv6 RAW (0xfd) TTL/MIN: 254/255", 358 .tt_domain = PF_INET6, 359 .tt_type = SOCK_RAW, 360 .tt_proto = TTL_IPPROTO_EXP, 361 .tt_ttl = 254, 362 .tt_minttl = 255, 363 .tt_pass = TTL_NODATA 364 } 365 }; 366 367 static bool 368 ttl_bind_dest(const ttl_test_t *test, int sock, struct sockaddr_storage *dst) 369 { 370 socklen_t len; 371 struct sockaddr_storage addr; 372 373 (void) memset(&addr, 0, sizeof (struct sockaddr_storage)); 374 375 if (test->tt_domain == PF_INET) { 376 struct sockaddr_in *in = (struct sockaddr_in *)&addr; 377 in->sin_family = AF_INET; 378 in->sin_port = htons(0); 379 if (inet_pton(AF_INET, "127.0.0.1", &in->sin_addr) != 1) { 380 warnx("TEST FAILED: %s: failed to convert 127.0.0.1 " 381 "to an IPv4 address", test->tt_desc); 382 return (false); 383 } 384 len = sizeof (struct sockaddr_in); 385 } else { 386 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; 387 in6->sin6_family = AF_INET6; 388 in6->sin6_port = htons(0); 389 if (inet_pton(AF_INET6, "::1", &in6->sin6_addr) != 1) { 390 warnx("TEST FAILED: %s: failed to convert ::1 " 391 "to an IPv6 address", test->tt_desc); 392 return (false); 393 } 394 len = sizeof (struct sockaddr_in6); 395 } 396 397 if (bind(sock, (struct sockaddr *)&addr, len) != 0) { 398 warn("TEST FAILED: %s: failed to bind listen socket", 399 test->tt_desc); 400 return (false); 401 } 402 403 len = sizeof (struct sockaddr_storage); 404 if (getsockname(sock, (struct sockaddr *)dst, &len) != 0) { 405 warn("TEST FAILED: %s: failed to retrieve socket address ", 406 test->tt_desc); 407 return (false); 408 } 409 410 return (true); 411 } 412 413 /* 414 * Our job is to attempt to connect to the other end with our current settings. 415 * This may not work, so we use our port to get things ready just in case. 416 */ 417 static bool 418 ttl_connect(const ttl_test_t *test, int port, int src, int dst, int *cfd, 419 const struct sockaddr *addr) 420 { 421 struct timespec to = { .tv_nsec = tt_sock_to }; 422 int namelen = test->tt_domain == PF_INET ? sizeof (struct sockaddr_in) : 423 sizeof (struct sockaddr_in6); 424 int conn; 425 port_event_t pe; 426 427 if (listen(dst, 5) != 0) { 428 warn("TEST FAILED: %s: failed to listen", test->tt_desc); 429 return (false); 430 } 431 432 if (connect(src, addr, namelen) != 0 && errno != EINPROGRESS) { 433 warn("TEST FAILED: %s: failed to connect", test->tt_desc); 434 return (false); 435 } 436 437 if (port_associate(port, PORT_SOURCE_FD, src, POLLOUT, NULL) != 0) { 438 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port " 439 "associate to watch connect", test->tt_desc); 440 } 441 442 if (port_get(port, &pe, &to) != 0) { 443 if (test->tt_pass == TTL_NOCONNECT) { 444 (void) printf("TEST PASSED: %s: correctly failed to " 445 "connect\n", test->tt_desc); 446 return (true); 447 } else { 448 warn("TEST FAILED: %s: timed out waiting to connect", 449 test->tt_desc); 450 return (false); 451 } 452 } 453 454 if ((pe.portev_events & POLLOUT) == 0) { 455 warnx("TEST FAILED: %s: connect port event doesn't contain " 456 "POLLOUT, found 0x%x", test->tt_desc, pe.portev_events); 457 return (false); 458 } 459 460 /* 461 * Now make sure the listen socket is ready. 462 */ 463 if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) { 464 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port " 465 "associate to watch accept", test->tt_desc); 466 } 467 468 if (port_get(port, &pe, &to) != 0) { 469 warn("TEST FAILED: %s: timed out waiting to accept", 470 test->tt_desc); 471 return (false); 472 } 473 474 if ((pe.portev_events & POLLIN) == 0) { 475 warnx("TEST FAILED: %s: accept port event doesn't contain " 476 "POLLIN, found 0x%x", test->tt_desc, pe.portev_events); 477 return (false); 478 } 479 480 conn = accept4(dst, NULL, NULL, SOCK_NONBLOCK); 481 if (conn < 0) { 482 warn("TEST FAILED: %s: failed to get client connection", 483 test->tt_desc); 484 return (false); 485 } 486 487 if (test->tt_pass != TTL_SENDRECV) { 488 warnx("TEST FAILED: %s: expected connect to fail, but passed", 489 test->tt_desc); 490 return (false); 491 } 492 493 *cfd = conn; 494 return (true); 495 } 496 497 static bool 498 ttl_check_ancil(const ttl_test_t *test, const struct msghdr *msg) 499 { 500 int level, ttlopt; 501 502 if (test->tt_domain == PF_INET) { 503 level = IPPROTO_IP; 504 ttlopt = IP_RECVTTL; 505 } else { 506 level = IPPROTO_IPV6; 507 ttlopt = IPV6_HOPLIMIT; 508 } 509 510 if (msg->msg_controllen != CMSG_SPACE(sizeof (int))) { 511 warnx("TEST FAILED: %s: expected %u bytes of ancillary " 512 "data, found %u", test->tt_desc, CMSG_SPACE(sizeof (int)), 513 msg->msg_controllen); 514 return (false); 515 } 516 517 for (const struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 518 cmsg = CMSG_NXTHDR(msg, cmsg)) { 519 int val; 520 521 if (cmsg->cmsg_level != level || cmsg->cmsg_type != ttlopt) 522 continue; 523 (void) memcpy(&val, CMSG_DATA(cmsg), sizeof (int)); 524 if (test->tt_ttl != 0 && val != test->tt_ttl) { 525 warnx("TEST FAILED: %s: TTL/HLIM mismatch: expected " 526 "0x%x, found 0x%x", test->tt_desc, test->tt_ttl, 527 val); 528 return (false); 529 } 530 531 (void) printf("TEST PASSED: %s: TTL/HLIM is correct\n", 532 test->tt_desc); 533 return (true); 534 } 535 536 warnx("TEST FAILED: %s: failed to find TTL/HLIM in ancillary options", 537 test->tt_desc); 538 return (false); 539 } 540 541 /* 542 * Attempt to send data with the TTLs set up appropriately. This might fail, 543 * hence our port_associate dance and unfortunately regrettable timeout. 544 */ 545 static bool 546 ttl_sendrecv(const ttl_test_t *test, int port, int src, int dst, 547 struct sockaddr *addr) 548 { 549 struct timespec to = { .tv_nsec = tt_sock_to }; 550 int namelen = test->tt_domain == PF_INET ? sizeof (struct sockaddr_in) : 551 sizeof (struct sockaddr_in6); 552 uint8_t ancil[CMSG_SPACE(sizeof (int)) * 2]; 553 port_event_t pe; 554 struct msghdr msg; 555 uint32_t data; 556 struct iovec iov; 557 ssize_t sret; 558 559 if (sendto(src, &tt_msg, sizeof (tt_msg), MSG_NOSIGNAL, addr, 560 namelen) != sizeof (tt_msg)) { 561 warn("TEST FAILED: %s: failed to write message to socket", 562 test->tt_desc); 563 } 564 565 if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) { 566 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port " 567 "associate to watch recv", test->tt_desc); 568 } 569 570 if (port_get(port, &pe, &to) != 0) { 571 if (test->tt_pass == TTL_NODATA) { 572 (void) printf("TEST PASSED: %s: timed out waiting " 573 "for data\n", test->tt_desc); 574 return (true); 575 } else { 576 warn("TEST FAILED: %s: timed out waiting to recv", 577 test->tt_desc); 578 return (false); 579 } 580 } 581 582 if ((pe.portev_events & POLLIN) == 0) { 583 warnx("TEST FAILED: %s: receive port event doesn't contain " 584 "POLLIN, found 0x%x", test->tt_desc, pe.portev_events); 585 return (false); 586 } 587 588 (void) memset(&msg, 0, sizeof (msg)); 589 iov.iov_base = (void *)&data; 590 iov.iov_len = sizeof (data); 591 msg.msg_iov = &iov; 592 msg.msg_iovlen = 1; 593 msg.msg_control = ancil; 594 msg.msg_controllen = sizeof (ancil); 595 596 sret = recvmsg(dst, &msg, MSG_DONTWAIT); 597 if (sret != (ssize_t)sizeof (data)) { 598 warnx("TEST FAILED: %s: failed to receive data: %zx", 599 test->tt_desc, sret); 600 return (false); 601 } 602 603 if (test->tt_pass != TTL_SENDRECV) { 604 warnx("TEST FAILED: %s: found data, despite expecting not to", 605 test->tt_desc); 606 return (false); 607 } 608 609 /* 610 * We skip testing the data on raw sockets so we can ignore having to 611 * parse the IPv4 or IPv6 headers. 612 */ 613 if (data != tt_msg && test->tt_type != SOCK_RAW) { 614 warnx("TEST FAILED: %s: data mismatch: expected 0x%x, found " 615 "0x%x", test->tt_desc, tt_msg, data); 616 return (false); 617 } 618 619 if (test->tt_type == SOCK_DGRAM && !ttl_check_ancil(test, &msg)) { 620 return (false); 621 } 622 623 (void) printf("TEST PASSED: %s: Successfully received data\n", 624 test->tt_desc); 625 return (true); 626 } 627 628 static bool 629 ttl_test_one(const ttl_test_t *test) 630 { 631 int src = -1, dst = -1, cfd = -1, port = -1, tdst; 632 int level, ttlopt, minttlopt, recvopt, en = 1; 633 bool ret = true; 634 struct sockaddr_storage dst_addr; 635 636 if ((port = port_create()) < 0) { 637 err(EXIT_FAILURE, "TEST FAILED: failed to create event port"); 638 } 639 640 src = socket(test->tt_domain, test->tt_type | SOCK_NONBLOCK, 641 test->tt_proto); 642 if (src < 0) { 643 warn("TEST FAILED: %s: failed to create source socket", 644 test->tt_desc); 645 ret = false; 646 goto cleanup; 647 } 648 649 dst = socket(test->tt_domain, test->tt_type | SOCK_NONBLOCK, 650 test->tt_proto); 651 if (dst < 0) { 652 warn("TEST FAILED: %s: failed to create destination socket", 653 test->tt_desc); 654 ret = false; 655 goto cleanup; 656 } 657 658 if (!ttl_bind_dest(test, dst, &dst_addr)) { 659 ret = false; 660 goto cleanup; 661 } 662 663 if (test->tt_domain == PF_INET) { 664 level = IPPROTO_IP; 665 ttlopt = IP_TTL; 666 minttlopt = IP_MINTTL; 667 recvopt = IP_RECVTTL; 668 } else { 669 level = IPPROTO_IPV6; 670 ttlopt = IPV6_UNICAST_HOPS; 671 minttlopt = IPV6_MINHOPCOUNT; 672 recvopt = IPV6_RECVHOPLIMIT; 673 } 674 675 if (test->tt_ttl > 0 && setsockopt(src, level, ttlopt, &test->tt_ttl, 676 sizeof (int)) != 0) { 677 warn("TEST FAILED: %s: failed to set TTL/HLIM to %d", 678 test->tt_desc, test->tt_ttl); 679 ret = false; 680 goto cleanup; 681 } 682 683 if (setsockopt(dst, level, minttlopt, &test->tt_minttl, 684 sizeof (int)) != 0) { 685 warn("TEST FAILED: %s: failed to set min TTL/HLIM to %d", 686 test->tt_desc, test->tt_minttl); 687 ret = false; 688 goto cleanup; 689 } 690 691 if (test->tt_type == SOCK_DGRAM && setsockopt(dst, level, recvopt, &en, 692 sizeof (int)) != 0) { 693 warn("TEST FAILED: %s failed to enable receiving the TTL", 694 test->tt_desc); 695 ret = false; 696 goto cleanup; 697 } 698 699 if (test->tt_type != SOCK_DGRAM && test->tt_type != SOCK_RAW) { 700 if (!ttl_connect(test, port, src, dst, &cfd, 701 (struct sockaddr *)&dst_addr)) { 702 ret = false; 703 goto cleanup; 704 } 705 if (test->tt_pass != TTL_SENDRECV) { 706 goto cleanup; 707 } 708 tdst = cfd; 709 } else { 710 tdst = dst; 711 } 712 713 if (!ttl_sendrecv(test, port, src, tdst, 714 (struct sockaddr *)&dst_addr)) { 715 ret = false; 716 goto cleanup; 717 } 718 719 cleanup: 720 if (port > -1) 721 (void) close(port); 722 if (src > -1) 723 (void) close(src); 724 if (dst > -1) 725 (void) close(dst); 726 if (cfd > -1) 727 (void) close(cfd); 728 return (ret); 729 } 730 731 int 732 main(void) 733 { 734 int ret = EXIT_SUCCESS; 735 736 for (size_t i = 0; i < ARRAY_SIZE(ttl_tests); i++) { 737 if (!ttl_test_one(&ttl_tests[i])) { 738 ret = EXIT_FAILURE; 739 } 740 } 741 742 if (ret == EXIT_SUCCESS) { 743 (void) printf("All tests passed successfully\n"); 744 } 745 746 return (ret); 747 } 748