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 2026 Oxide Computer Company 14 */ 15 16 /* 17 * Test a few aspects of inet6_opt(3C), particularly around error cases. 18 */ 19 20 #include <stdlib.h> 21 #include <err.h> 22 #include <netinet/in.h> 23 #include <netinet/ip6.h> 24 #include <sys/sysmacros.h> 25 26 typedef struct { 27 const char *i6a_desc; 28 int i6a_ret; 29 int i6a_off; 30 uint8_t i6a_type; 31 socklen_t i6a_len; 32 uint_t i6a_align; 33 } inet6_append_t; 34 35 static const inet6_append_t inet6_append_tests[] = { 36 { "no offset, 1-byte align", 6, 0, IP6OPT_JUMBO, 4, 1 }, 37 { "no offset, 2-byte align", 6, 0, IP6OPT_JUMBO, 4, 2 }, 38 { "no offset, 2-byte align (2)", 8, 0, IP6OPT_JUMBO, 5, 2 }, 39 { "no offset, 4-byte align (1)", 8, 0, IP6OPT_JUMBO, 4, 4 }, 40 { "no offset, 4-byte align (2)", 8, 0, IP6OPT_JUMBO, 6, 4 }, 41 { "no offset, 8-byte align (1)", 16, 0, IP6OPT_JUMBO, 8, 8 }, 42 { "no offset, 8-byte align (2)", 24, 0, IP6OPT_JUMBO, 22, 8 }, 43 { "offset, 1-byte align (1)", 23, 20, IP6OPT_JUMBO, 1, 1 }, 44 { "offset, 2-byte align (1)", 14, 8, IP6OPT_JUMBO, 3, 2 }, 45 { "offset, 2-byte align (2)", 14, 8, IP6OPT_JUMBO, 4, 2 }, 46 { "offset, 4-byte align (1)", 20, 10, IP6OPT_JUMBO, 7, 4 }, 47 { "offset, 4-byte align (2)", 20, 10, IP6OPT_JUMBO, 8, 4 }, 48 { "offset, 4-byte align (3)", 24, 10, IP6OPT_JUMBO, 9, 4 }, 49 { "invalid align (1)", -1, 0, IP6OPT_JUMBO, 4, 3 }, 50 { "invalid align (2)", -1, 0, IP6OPT_JUMBO, 22, 5 }, 51 { "invalid align (3)", -1, 0, IP6OPT_JUMBO, 22, 7 }, 52 { "invalid align (4)", -1, 0, IP6OPT_JUMBO, 22, 10 }, 53 { "align > len (1)", -1, 0, IP6OPT_JUMBO, 2, 4 }, 54 { "align > len (2)", -1, 0, IP6OPT_JUMBO, 7, 8 }, 55 { "invalid type (1)", -1, 0, IP6OPT_PAD1, 4, 1 }, 56 { "invalid type (2)", -1, 0, IP6OPT_PADN, 4, 1 }, 57 { "invalid length (1)", -1, 0, IP6OPT_PADN, 256, 1 }, 58 { "invalid length (2)", -1, 0, IP6OPT_PADN, 7777, 1 } 59 }; 60 61 int 62 main(void) 63 { 64 uint8_t buf[128]; 65 int ret = EXIT_SUCCESS; 66 67 /* 68 * First verify several invalid sizes for the buffer allocation. We use 69 * a token buffer for this. 70 */ 71 const socklen_t inv_lens[] = { 0, 1, 7, 23, 169, UINT32_MAX }; 72 for (size_t i = 0; i < ARRAY_SIZE(inv_lens); i++) { 73 if (inet6_opt_init(buf, inv_lens[i]) != -1) { 74 warnx("TEST FAILED: inet6_opt_init passed with invalid " 75 "length 0x%x", inv_lens[i]); 76 ret = EXIT_FAILURE; 77 } else { 78 (void) printf("TEST PASSED: inet6_opt_init rejected " 79 "invalid length 0x%x\n", inv_lens[i]); 80 } 81 } 82 83 /* 84 * Next, valid and invalid append operations without data. 85 */ 86 for (size_t i = 0; i < ARRAY_SIZE(inet6_append_tests); i++) { 87 const inet6_append_t *t = &inet6_append_tests[i]; 88 int rval = inet6_opt_append(NULL, 0, t->i6a_off, t->i6a_type, 89 t->i6a_len, t->i6a_align, NULL); 90 if (rval != t->i6a_ret) { 91 warnx("TEST FAILED: %s: inet6_opt_append returned %d, " 92 "but expected %d\n", t->i6a_desc, rval, t->i6a_ret); 93 ret = EXIT_FAILURE; 94 } else { 95 (void) printf("TEST PASSED: %s: inet6_opt_append " 96 "returned %d\n", t->i6a_desc, t->i6a_ret); 97 } 98 } 99 100 /* 101 * Now go through and test a few cases that would cause us to exceed the 102 * buffer capacity and make sure that we always catch those. 103 */ 104 if (inet6_opt_append(buf, sizeof (buf), 120, IP6OPT_NSAP_ADDR, 10, 1, 105 NULL) != -1) { 106 warnx("TEST FAILED: didn't fail inet6_opt_append overflow"); 107 ret = EXIT_FAILURE; 108 } else { 109 (void) printf("TEST PASSED: caught inet6_opt_append " 110 "overflow\n"); 111 } 112 113 buf[0] = 2; 114 if (inet6_opt_finish(buf, 2, 24) != -1) { 115 warnx("TEST FAILED: didn't fail inet6_opt_finish overflow"); 116 ret = EXIT_FAILURE; 117 } else { 118 (void) printf("TEST PASSED: caught inet6_opt_finish " 119 "overflow\n"); 120 } 121 122 if (ret == EXIT_SUCCESS) { 123 (void) printf("All tests passed successfully\n"); 124 } 125 return (ret); 126 } 127