t_ipsec_policy.c revision 1.4 1 1.4 riastrad /* $NetBSD: t_ipsec_policy.c,v 1.4 2026/09/22 15:04:22 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*
4 1.1 riastrad * Copyright (c) 2026 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * Redistribution and use in source and binary forms, with or without
8 1.1 riastrad * modification, are permitted provided that the following conditions
9 1.1 riastrad * are met:
10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
11 1.1 riastrad * notice, this list of conditions and the following disclaimer.
12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
14 1.1 riastrad * documentation and/or other materials provided with the distribution.
15 1.1 riastrad *
16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
27 1.1 riastrad */
28 1.1 riastrad
29 1.1 riastrad #include <sys/cdefs.h>
30 1.4 riastrad __RCSID("$NetBSD: t_ipsec_policy.c,v 1.4 2026/09/22 15:04:22 riastradh Exp $");
31 1.1 riastrad
32 1.1 riastrad #include <sys/socket.h>
33 1.1 riastrad #include <sys/types.h>
34 1.1 riastrad #include <sys/un.h>
35 1.1 riastrad
36 1.1 riastrad #include <arpa/inet.h>
37 1.1 riastrad #include <net/pfkeyv2.h>
38 1.1 riastrad #include <netinet/in.h>
39 1.1 riastrad #include <netipsec/ipsec.h>
40 1.1 riastrad
41 1.1 riastrad #include <atf-c.h>
42 1.1 riastrad #include <stddef.h>
43 1.1 riastrad #include <stdint.h>
44 1.1 riastrad #include <stdio.h>
45 1.1 riastrad
46 1.1 riastrad #include "h_macros.h"
47 1.1 riastrad
48 1.1 riastrad static void
49 1.1 riastrad hexdump(const char *title, const void *buf, size_t len)
50 1.1 riastrad {
51 1.1 riastrad const uint8_t *p = buf;
52 1.1 riastrad size_t i;
53 1.1 riastrad
54 1.4 riastrad fprintf(stderr, "# %s (%zu bytes)\n", title, len);
55 1.1 riastrad for (i = 0; i < len; i++) {
56 1.1 riastrad if ((i % 8) == 0)
57 1.4 riastrad fprintf(stderr, " ");
58 1.4 riastrad fprintf(stderr, " %02hhx", p[i]);
59 1.1 riastrad if ((i % 16) == 15)
60 1.4 riastrad fprintf(stderr, "\n");
61 1.1 riastrad }
62 1.1 riastrad if (i % 16)
63 1.4 riastrad fprintf(stderr, "\n");
64 1.1 riastrad }
65 1.1 riastrad
66 1.1 riastrad static void *
67 1.1 riastrad append(void **bufp, size_t *buflenp, size_t addlen)
68 1.1 riastrad {
69 1.1 riastrad void *p;
70 1.1 riastrad
71 1.1 riastrad if (addlen == 0)
72 1.1 riastrad return NULL;
73 1.1 riastrad
74 1.1 riastrad ATF_REQUIRE(addlen < SIZE_MAX - *buflenp);
75 1.1 riastrad RZ(reallocarr(bufp, *buflenp + addlen, 1));
76 1.1 riastrad p = (char *)*bufp + *buflenp;
77 1.1 riastrad memset(p, 0, addlen);
78 1.1 riastrad *buflenp += addlen;
79 1.1 riastrad return p;
80 1.1 riastrad }
81 1.1 riastrad
82 1.1 riastrad static void
83 1.1 riastrad test_ipsec_policy_roundtrip(int exp_error, uint8_t dir,
84 1.1 riastrad const struct sockaddr *src, const struct sockaddr *dst)
85 1.1 riastrad {
86 1.1 riastrad enum { guardlen = 8 };
87 1.1 riastrad void *buf = NULL;
88 1.1 riastrad size_t len = 0;
89 1.1 riastrad struct sadb_x_policy *xpl, *xpl1;
90 1.1 riastrad size_t xpl_start, xpl1_start;
91 1.1 riastrad size_t reqlen;
92 1.1 riastrad void *copybuf = NULL;
93 1.1 riastrad size_t copylen = 0;
94 1.1 riastrad uint8_t guardbyte[2] = {0x5a, 0x3c};
95 1.1 riastrad size_t guard_start[2];
96 1.1 riastrad socklen_t optlen;
97 1.1 riastrad unsigned i;
98 1.1 riastrad int s;
99 1.1 riastrad
100 1.1 riastrad xpl_start = len;
101 1.1 riastrad xpl = append(&buf, &len, sizeof(*xpl));
102 1.1 riastrad xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
103 1.1 riastrad xpl->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
104 1.1 riastrad xpl->sadb_x_policy_dir = dir;
105 1.1 riastrad xpl = NULL;
106 1.1 riastrad
107 1.1 riastrad for (i = 0; i < 2; i++) {
108 1.1 riastrad const size_t xisr_start = len;
109 1.1 riastrad struct sadb_x_ipsecrequest *xisr;
110 1.1 riastrad
111 1.1 riastrad xisr = append(&buf, &len, sizeof(*xisr));
112 1.1 riastrad xisr->sadb_x_ipsecrequest_proto = IPPROTO_ESP;
113 1.1 riastrad xisr->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
114 1.1 riastrad xisr->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
115 1.1 riastrad xisr->sadb_x_ipsecrequest_reqid = 0;
116 1.1 riastrad xisr = NULL;
117 1.1 riastrad
118 1.1 riastrad memcpy(append(&buf, &len, src->sa_len), src, src->sa_len);
119 1.1 riastrad memcpy(append(&buf, &len, dst->sa_len), dst, dst->sa_len);
120 1.1 riastrad
121 1.1 riastrad /* pad */
122 1.1 riastrad const size_t npad = PFKEY_ALIGN8(len - xisr_start) -
123 1.1 riastrad (len - xisr_start);
124 1.1 riastrad (void)append(&buf, &len, npad);
125 1.1 riastrad
126 1.1 riastrad ATF_REQUIRE(PFKEY_ALIGN8(len - xisr_start) == len - xisr_start);
127 1.1 riastrad xisr = (void *)((char *)buf + xisr_start);
128 1.1 riastrad xisr->sadb_x_ipsecrequest_len = len - xisr_start;
129 1.1 riastrad }
130 1.1 riastrad
131 1.1 riastrad ATF_REQUIRE(PFKEY_ALIGN8(len - xpl_start) == len - xpl_start);
132 1.1 riastrad xpl = (void *)((char *)buf + xpl_start);
133 1.1 riastrad xpl->sadb_x_policy_len = PFKEY_UNIT64(len - xpl_start);
134 1.1 riastrad
135 1.1 riastrad reqlen = len - xpl_start;
136 1.1 riastrad
137 1.1 riastrad RL(s = socket(AF_INET6, SOCK_DGRAM, 0));
138 1.1 riastrad if (exp_error) {
139 1.1 riastrad ATF_CHECK_ERRNO(exp_error,
140 1.1 riastrad setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl, reqlen)
141 1.1 riastrad == -1);
142 1.1 riastrad goto out;
143 1.1 riastrad }
144 1.1 riastrad if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl, reqlen)
145 1.1 riastrad == -1) {
146 1.1 riastrad int error = errno;
147 1.1 riastrad
148 1.1 riastrad atf_tc_fail_nonfatal("setsockopt(IPV6_IPSEC_POLICY): %d (%s)",
149 1.1 riastrad error, strerror(errno));
150 1.1 riastrad goto out;
151 1.1 riastrad }
152 1.1 riastrad
153 1.1 riastrad guard_start[0] = copylen;
154 1.1 riastrad memset(append(©buf, ©len, guardlen), guardbyte[0], guardlen);
155 1.1 riastrad
156 1.1 riastrad xpl1_start = copylen;
157 1.3 kre (void)append(©buf, ©len, reqlen);
158 1.1 riastrad
159 1.1 riastrad guard_start[1] = copylen;
160 1.1 riastrad memset(append(©buf, ©len, guardlen), guardbyte[1], guardlen);
161 1.1 riastrad
162 1.1 riastrad xpl = (void *)((char *)buf + xpl_start);
163 1.1 riastrad xpl1 = (void *)((char *)copybuf + xpl1_start);
164 1.1 riastrad memcpy(xpl1, xpl, reqlen);
165 1.1 riastrad
166 1.1 riastrad optlen = reqlen;
167 1.1 riastrad ATF_CHECK_ERRNO(EINVAL,
168 1.1 riastrad getsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl1, &optlen));
169 1.1 riastrad
170 1.1 riastrad optlen = reqlen;
171 1.1 riastrad if (getsockopt2(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, xpl1, &optlen)
172 1.1 riastrad == -1) {
173 1.1 riastrad int error = errno;
174 1.1 riastrad
175 1.1 riastrad atf_tc_fail_nonfatal("getsockopt2(IPV6_IPSEC_POLICY): %d (%s)",
176 1.1 riastrad error, strerror(errno));
177 1.1 riastrad goto out;
178 1.1 riastrad }
179 1.1 riastrad ATF_CHECK_EQ_MSG(reqlen, optlen, "reqlen=%zu optlen=%zu",
180 1.1 riastrad (size_t)reqlen, (size_t)optlen);
181 1.1 riastrad
182 1.1 riastrad if (reqlen != optlen || memcmp(xpl, xpl1, len) != 0) {
183 1.1 riastrad hexdump("before", xpl, reqlen);
184 1.1 riastrad hexdump("after", xpl1, optlen);
185 1.4 riastrad fflush(stderr);
186 1.1 riastrad atf_tc_fail_nonfatal("mismatch");
187 1.1 riastrad }
188 1.1 riastrad
189 1.1 riastrad for (i = 0; i < __arraycount(guard_start); i++) {
190 1.1 riastrad const char *guard = (char *)copybuf + guard_start[i];
191 1.1 riastrad size_t j;
192 1.1 riastrad
193 1.1 riastrad for (j = 0; j < guardlen; j++) {
194 1.1 riastrad if (guard[j] != guardbyte[i]) {
195 1.1 riastrad char title[8];
196 1.1 riastrad
197 1.1 riastrad snprintf(title, sizeof(title), "guard %u", i);
198 1.1 riastrad hexdump(title, guard, guardlen);
199 1.4 riastrad fflush(stderr);
200 1.1 riastrad atf_tc_fail_nonfatal("guard %u overwritten",
201 1.1 riastrad i);
202 1.1 riastrad break;
203 1.1 riastrad }
204 1.1 riastrad }
205 1.1 riastrad }
206 1.1 riastrad
207 1.1 riastrad out: RL(close(s));
208 1.1 riastrad }
209 1.1 riastrad
210 1.1 riastrad ATF_TC(pr60669);
211 1.1 riastrad ATF_TC_HEAD(pr60669, tc)
212 1.1 riastrad {
213 1.1 riastrad atf_tc_set_md_var(tc, "descr", "Test IPV6_IPSEC_POLICY round-trip with"
214 1.1 riastrad " v4 src and v4 dst");
215 1.1 riastrad }
216 1.1 riastrad ATF_TC_BODY(pr60669, tc)
217 1.1 riastrad {
218 1.1 riastrad union {
219 1.1 riastrad struct sockaddr sa;
220 1.1 riastrad struct sockaddr_in sin;
221 1.1 riastrad } v4[2] = {
222 1.1 riastrad [0] = {
223 1.1 riastrad .sin = {
224 1.1 riastrad .sin_len = sizeof(v4[0].sin),
225 1.1 riastrad .sin_family = AF_INET,
226 1.1 riastrad .sin_port = 0,
227 1.1 riastrad }
228 1.1 riastrad },
229 1.1 riastrad [1] = {
230 1.1 riastrad .sin = {
231 1.1 riastrad .sin_len = sizeof(v4[1].sin),
232 1.1 riastrad .sin_family = AF_INET,
233 1.1 riastrad .sin_port = 0,
234 1.1 riastrad }
235 1.1 riastrad },
236 1.1 riastrad };
237 1.1 riastrad union {
238 1.1 riastrad struct sockaddr sa;
239 1.1 riastrad struct sockaddr_in6 sin6;
240 1.1 riastrad } v6[2] = {
241 1.1 riastrad [0] = {
242 1.1 riastrad .sin6 = {
243 1.1 riastrad .sin6_len = sizeof(v6[0].sin6),
244 1.1 riastrad .sin6_family = AF_INET6,
245 1.1 riastrad .sin6_port = 0,
246 1.1 riastrad }
247 1.1 riastrad },
248 1.1 riastrad [1] = {
249 1.1 riastrad .sin6 = {
250 1.1 riastrad .sin6_len = sizeof(v6[1].sin6),
251 1.1 riastrad .sin6_family = AF_INET6,
252 1.1 riastrad .sin6_port = 0,
253 1.1 riastrad }
254 1.1 riastrad },
255 1.1 riastrad };
256 1.1 riastrad union {
257 1.1 riastrad struct sockaddr sa;
258 1.1 riastrad struct sockaddr_un sun;
259 1.1 riastrad } un[2] = {
260 1.1 riastrad [0] = {
261 1.1 riastrad .sun = {
262 1.1 riastrad .sun_len = -1,
263 1.1 riastrad .sun_family = AF_LOCAL,
264 1.1 riastrad .sun_path = "/socket0",
265 1.1 riastrad }
266 1.1 riastrad },
267 1.1 riastrad [1] = {
268 1.1 riastrad .sun = {
269 1.1 riastrad .sun_len = -1,
270 1.1 riastrad .sun_family = AF_LOCAL,
271 1.1 riastrad .sun_path = "/socket1",
272 1.1 riastrad }
273 1.1 riastrad },
274 1.1 riastrad };
275 1.1 riastrad struct sockaddr sa[2] = {
276 1.1 riastrad [0] = { .sa_len = sizeof(sa[0]), .sa_family = AF_UNSPEC },
277 1.1 riastrad [1] = { .sa_len = sizeof(sa[1]), .sa_family = AF_UNSPEC },
278 1.1 riastrad };
279 1.1 riastrad struct sockaddr sa1[2] = {
280 1.1 riastrad [0] = { .sa_len = 1, .sa_family = AF_UNSPEC },
281 1.1 riastrad [1] = { .sa_len = 1, .sa_family = AF_UNSPEC },
282 1.1 riastrad };
283 1.1 riastrad struct sockaddr sa0[2] = {
284 1.1 riastrad [0] = { .sa_len = 0, .sa_family = AF_UNSPEC },
285 1.1 riastrad [1] = { .sa_len = 0, .sa_family = AF_UNSPEC },
286 1.1 riastrad };
287 1.1 riastrad const struct {
288 1.1 riastrad struct sockaddr *src;
289 1.1 riastrad struct sockaddr *dst;
290 1.1 riastrad int expected_error;
291 1.1 riastrad const char *xfail;
292 1.1 riastrad } C[] = {
293 1.1 riastrad [0] = { &v4[0].sa, &v4[1].sa, 0, NULL },
294 1.2 riastrad [1] = { &v4[0].sa, &v6[1].sa, EINVAL, NULL },
295 1.1 riastrad [2] = { &v4[0].sa, &un[1].sa, EINVAL, NULL },
296 1.2 riastrad [3] = { &v4[0].sa, &sa[1], EINVAL, NULL },
297 1.1 riastrad [4] = { &v4[0].sa, &sa1[1], EINVAL, NULL },
298 1.1 riastrad [5] = { &v4[0].sa, &sa0[1], EINVAL, NULL },
299 1.1 riastrad
300 1.2 riastrad [6] = { &v6[0].sa, &v4[1].sa, EINVAL, NULL },
301 1.1 riastrad [7] = { &v6[0].sa, &v6[1].sa, 0, NULL },
302 1.1 riastrad [8] = { &v6[0].sa, &un[1].sa, EINVAL, NULL },
303 1.2 riastrad [9] = { &v6[0].sa, &sa[1], EINVAL, NULL },
304 1.1 riastrad [10] = { &v6[0].sa, &sa1[1], EINVAL, NULL },
305 1.1 riastrad [11] = { &v6[0].sa, &sa0[1], EINVAL, NULL },
306 1.1 riastrad
307 1.1 riastrad [12] = { &un[0].sa, &v4[1].sa, EINVAL, NULL },
308 1.1 riastrad [13] = { &un[0].sa, &v6[1].sa, EINVAL, NULL },
309 1.1 riastrad [14] = { &un[0].sa, &un[1].sa, EINVAL, NULL },
310 1.1 riastrad [15] = { &un[0].sa, &sa[1], EINVAL, NULL },
311 1.1 riastrad [16] = { &un[0].sa, &sa1[1], EINVAL, NULL },
312 1.1 riastrad [17] = { &un[0].sa, &sa0[1], EINVAL, NULL },
313 1.1 riastrad
314 1.2 riastrad [18] = { &sa[0], &v4[1].sa, EINVAL, NULL },
315 1.2 riastrad [19] = { &sa[0], &v6[1].sa, EINVAL, NULL },
316 1.1 riastrad [20] = { &sa[0], &un[1].sa, EINVAL, NULL },
317 1.2 riastrad [21] = { &sa[0], &sa[1], EINVAL, NULL },
318 1.1 riastrad [22] = { &sa[0], &sa1[1], EINVAL, NULL },
319 1.1 riastrad [23] = { &sa[0], &sa0[1], EINVAL, NULL },
320 1.1 riastrad
321 1.1 riastrad [24] = { &sa1[0], &v4[1].sa, EINVAL, NULL },
322 1.1 riastrad [25] = { &sa1[0], &v6[1].sa, EINVAL, NULL },
323 1.1 riastrad [26] = { &sa1[0], &un[1].sa, EINVAL, NULL },
324 1.1 riastrad [27] = { &sa1[0], &sa[1], EINVAL, NULL },
325 1.1 riastrad [28] = { &sa1[0], &sa1[1], EINVAL, NULL },
326 1.1 riastrad [29] = { &sa1[0], &sa0[1], EINVAL, NULL },
327 1.1 riastrad
328 1.1 riastrad /*
329 1.1 riastrad * sa0 as the src one doesn't even make sense to test,
330 1.1 riastrad * because sa_len won't even advance past it, so it
331 1.1 riastrad * will be the same as testing a nonempty src and sa0
332 1.1 riastrad * dst above.
333 1.1 riastrad */
334 1.1 riastrad };
335 1.1 riastrad unsigned i;
336 1.1 riastrad
337 1.1 riastrad RL(inet_pton(AF_INET, "192.0.2.42", &v4[0].sin.sin_addr));
338 1.1 riastrad RL(inet_pton(AF_INET, "192.51.100.54", &v4[1].sin.sin_addr));
339 1.1 riastrad
340 1.1 riastrad RL(inet_pton(AF_INET6, "2001:db8:1::1", &v6[0].sin6.sin6_addr));
341 1.1 riastrad RL(inet_pton(AF_INET6, "2001:db8:2::1", &v6[1].sin6.sin6_addr));
342 1.1 riastrad
343 1.1 riastrad un[0].sun.sun_len = SUN_LEN(&un[0].sun);
344 1.1 riastrad un[1].sun.sun_len = SUN_LEN(&un[1].sun);
345 1.1 riastrad
346 1.1 riastrad for (i = 0; i < __arraycount(C); i++) {
347 1.1 riastrad const char *const dirname[2] = { "inbound", "outbound" };
348 1.1 riastrad const unsigned dir[2] =
349 1.1 riastrad { IPSEC_DIR_INBOUND, IPSEC_DIR_OUTBOUND };
350 1.1 riastrad unsigned j;
351 1.1 riastrad
352 1.1 riastrad for (j = 0; j < 2; j++) {
353 1.4 riastrad fprintf(stderr, "# case %u %s\n", i, dirname[j]);
354 1.4 riastrad fflush(stderr);
355 1.1 riastrad if (C[i].xfail)
356 1.1 riastrad atf_tc_expect_fail("%s", C[i].xfail);
357 1.1 riastrad test_ipsec_policy_roundtrip(C[i].expected_error,
358 1.1 riastrad dir[j], C[i].src, C[i].dst);
359 1.1 riastrad if (C[i].xfail)
360 1.1 riastrad atf_tc_expect_pass();
361 1.1 riastrad }
362 1.1 riastrad }
363 1.1 riastrad }
364 1.1 riastrad
365 1.1 riastrad ATF_TP_ADD_TCS(tp)
366 1.1 riastrad {
367 1.1 riastrad
368 1.1 riastrad ATF_TP_ADD_TC(tp, pr60669);
369 1.1 riastrad return atf_no_error();
370 1.1 riastrad }
371