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 tests to verify that SO_PROTOCOL, SO_DOMAIN, and SO_TYPE perform as we
18 * expect.
19 */
20
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <stdio.h>
26 #include <err.h>
27 #include <unistd.h>
28 #include <sys/sysmacros.h>
29 #include <sys/debug.h>
30 #include <net/pfkeyv2.h>
31 #include <net/pfpolicy.h>
32
33 typedef struct {
34 const char *sp_desc;
35 int sp_dom;
36 int sp_type;
37 int sp_prot;
38 int sp_expprot;
39 bool sp_noproto;
40 } so_prot_test_t;
41
42 static const so_prot_test_t so_prot_tests[] = { {
43 .sp_desc = "IPv4 TCP (prot=0)",
44 .sp_dom = PF_INET,
45 .sp_type = SOCK_STREAM,
46 .sp_prot = 0,
47 .sp_expprot = IPPROTO_TCP
48 }, {
49 .sp_desc = "IPv4 TCP (prot=TCP)",
50 .sp_dom = PF_INET,
51 .sp_type = SOCK_STREAM,
52 .sp_prot = IPPROTO_TCP,
53 .sp_expprot = IPPROTO_TCP
54 }, {
55 .sp_desc = "IPv4 UDP (prot=0)",
56 .sp_dom = PF_INET,
57 .sp_type = SOCK_DGRAM,
58 .sp_prot = 0,
59 .sp_expprot = IPPROTO_UDP
60 }, {
61 .sp_desc = "IPv4 UDP (prot=UDP)",
62 .sp_dom = PF_INET,
63 .sp_type = SOCK_DGRAM,
64 .sp_prot = IPPROTO_UDP,
65 .sp_expprot = IPPROTO_UDP
66 }, {
67 .sp_desc = "IPv4 SCTP (type=STREAM)",
68 .sp_dom = PF_INET,
69 .sp_type = SOCK_STREAM,
70 .sp_prot = IPPROTO_SCTP,
71 .sp_expprot = IPPROTO_SCTP
72 }, {
73 .sp_desc = "IPv4 SCTP (type=SEQPACKET)",
74 .sp_dom = PF_INET,
75 .sp_type = SOCK_SEQPACKET,
76 .sp_prot = IPPROTO_SCTP,
77 .sp_expprot = IPPROTO_SCTP
78 }, {
79 .sp_desc = "IPv6 TCP (prot=0)",
80 .sp_dom = PF_INET6,
81 .sp_type = SOCK_STREAM,
82 .sp_prot = 0,
83 .sp_expprot = IPPROTO_TCP
84 }, {
85 .sp_desc = "IPv6 TCP (prot=TCP)",
86 .sp_dom = PF_INET6,
87 .sp_type = SOCK_STREAM,
88 .sp_prot = IPPROTO_TCP,
89 .sp_expprot = IPPROTO_TCP
90 }, {
91 .sp_desc = "IPv6 UDP (prot=0)",
92 .sp_dom = PF_INET6,
93 .sp_type = SOCK_DGRAM,
94 .sp_prot = 0,
95 .sp_expprot = IPPROTO_UDP
96 }, {
97 .sp_desc = "IPv6 UDP (prot=UDP)",
98 .sp_dom = PF_INET6,
99 .sp_type = SOCK_DGRAM,
100 .sp_prot = IPPROTO_UDP,
101 .sp_expprot = IPPROTO_UDP
102 }, {
103 .sp_desc = "IPv6 SCTP (type=STREAM)",
104 .sp_dom = PF_INET6,
105 .sp_type = SOCK_STREAM,
106 .sp_prot = IPPROTO_SCTP,
107 .sp_expprot = IPPROTO_SCTP
108 }, {
109 .sp_desc = "IPv6 SCTP (type=SEQPACKET)",
110 .sp_dom = PF_INET6,
111 .sp_type = SOCK_SEQPACKET,
112 .sp_prot = IPPROTO_SCTP,
113 .sp_expprot = IPPROTO_SCTP
114 }, {
115 .sp_desc = "UDS (type=STREAM)",
116 .sp_dom = PF_UNIX,
117 .sp_type = SOCK_STREAM,
118 .sp_prot = 0,
119 .sp_expprot = 0
120 }, {
121 .sp_desc = "UDS (type=DGRAM)",
122 .sp_dom = PF_UNIX,
123 .sp_type = SOCK_DGRAM,
124 .sp_prot = 0,
125 .sp_expprot = 0
126 }, {
127 .sp_desc = "UDS (type=SEQPACKET)",
128 .sp_dom = PF_UNIX,
129 .sp_type = SOCK_SEQPACKET,
130 .sp_prot = 0,
131 .sp_expprot = 0
132 }, {
133 .sp_desc = "PF_KEY",
134 .sp_dom = PF_KEY,
135 .sp_type = SOCK_RAW,
136 .sp_prot = PF_KEY_V2,
137 .sp_expprot = PF_KEY_V2
138 }, {
139 .sp_desc = "PF_POLICY",
140 .sp_dom = PF_POLICY,
141 .sp_type = SOCK_RAW,
142 .sp_prot = PF_POLICY_V1,
143 .sp_expprot = PF_POLICY_V1
144 }, {
145 .sp_desc = "ICMP",
146 .sp_dom = PF_INET,
147 .sp_type = SOCK_RAW,
148 .sp_prot = IPPROTO_ICMP,
149 .sp_expprot = IPPROTO_ICMP
150 }, {
151 .sp_desc = "ICMPv6",
152 .sp_dom = PF_INET6,
153 .sp_type = SOCK_RAW,
154 .sp_prot = IPPROTO_ICMPV6,
155 .sp_expprot = IPPROTO_ICMPV6
156 }, {
157 .sp_desc = "PF_ROUTE (IPv4)",
158 .sp_dom = PF_ROUTE,
159 .sp_type = SOCK_RAW,
160 .sp_prot = AF_INET,
161 .sp_expprot = AF_INET
162 }, {
163 .sp_desc = "PF_ROUTE (IPv6)",
164 .sp_dom = PF_ROUTE,
165 .sp_type = SOCK_RAW,
166 .sp_prot = AF_INET6,
167 .sp_expprot = AF_INET6
168 }, {
169 .sp_desc = "PF_ROUTE (IPv4+IPv6)",
170 .sp_dom = PF_ROUTE,
171 .sp_type = SOCK_RAW,
172 .sp_prot = 0,
173 .sp_expprot = 0
174 }, {
175 .sp_desc = "Trill",
176 .sp_dom = PF_TRILL,
177 .sp_type = SOCK_DGRAM,
178 .sp_prot = 0,
179 .sp_expprot = 0
180 } };
181
182 static bool
so_test_one(const so_prot_test_t * test)183 so_test_one(const so_prot_test_t *test)
184 {
185 int s, opt;
186 socklen_t len;
187 bool ret = true;
188
189 s = socket(test->sp_dom, test->sp_type, test->sp_prot);
190 if (s < 0) {
191 warn("TEST FAILED: %s: failed to create socket with "
192 "domain/type/protocol 0x%x/0x%x/0x%x", test->sp_desc,
193 test->sp_dom, test->sp_type, test->sp_prot);
194 return (false);
195 }
196
197 len = sizeof (opt);
198 if (getsockopt(s, SOL_SOCKET, SO_DOMAIN, &opt, &len) != 0) {
199 warn("TEST FAILED: %s: failed to get SO_DOMAIN", test->sp_desc);
200 ret = false;
201 } else if (opt != test->sp_dom) {
202 warnx("TEST FAILED: %s: expected domain 0x%x, but found 0x%x",
203 test->sp_desc, test->sp_dom, opt);
204 ret = false;
205 } else {
206 (void) printf("TEST PASSED: %s: received correct domain\n",
207 test->sp_desc);
208 }
209
210 len = sizeof (opt);
211 if (getsockopt(s, SOL_SOCKET, SO_TYPE, &opt, &len) != 0) {
212 warn("TEST FAILED: %s: failed to get SO_TYPE", test->sp_desc);
213 ret = false;
214 } else if (opt != test->sp_type) {
215 warnx("TEST FAILED: %s: expected type 0x%x, but found 0x%x",
216 test->sp_desc, test->sp_type, opt);
217 ret = false;
218 } else {
219 (void) printf("TEST PASSED: %s: received correct type\n",
220 test->sp_desc);
221 }
222
223 len = sizeof (opt);
224 if (getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &opt, &len) != 0) {
225 warn("TEST FAILED: %s: failed to get SO_PROTOCOL",
226 test->sp_desc);
227 ret = false;
228 } else if (opt != test->sp_expprot) {
229 warnx("TEST FAILED: %s: expected protocol 0x%x, but found 0x%x",
230 test->sp_desc, test->sp_expprot, opt);
231 ret = false;
232 } else {
233 (void) printf("TEST PASSED: %s: received correct protocol\n",
234 test->sp_desc);
235 }
236
237 VERIFY0(close(s));
238 return (ret);
239 }
240
241 int
main(void)242 main(void)
243 {
244 int ret = EXIT_SUCCESS;
245
246 for (size_t i = 0; i < ARRAY_SIZE(so_prot_tests); i++) {
247 if (!so_test_one(&so_prot_tests[i]))
248 ret = EXIT_FAILURE;
249 }
250
251 if (ret == EXIT_SUCCESS)
252 (void) printf("All tests passed successfully\n");
253 return (ret);
254 }
255