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