xref: /illumos-gate/usr/src/test/os-tests/tests/libsocket/inet6_opt.c (revision 2ea71e24ff718fdbfe2a79f10ce89db251e34645)
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
main(void)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