]>
Commit | Line | Data |
---|---|---|
f427ee49 A |
1 | #import <darwintest.h> |
2 | #import <darwintest_utils.h> | |
3 | #import <dispatch/dispatch.h> | |
4 | #import <net/pfkeyv2.h> | |
5 | #import <netinet6/ipsec.h> | |
6 | #import <arpa/inet.h> | |
7 | #import <NetworkExtension/NetworkExtensionPrivate.h> | |
8 | #import <System/net/bpf.h> | |
9 | #import <System/netinet/ip.h> | |
10 | #import <System/netinet/ip6.h> | |
11 | ||
12 | T_GLOBAL_META( | |
13 | T_META_NAMESPACE("xnu.ipsec"), | |
14 | T_META_ASROOT(true), | |
15 | T_META_CHECK_LEAKS(false)); | |
16 | ||
17 | typedef enum { | |
18 | TEST_INVALID = 0, | |
19 | TEST_IPSEC_IPv4_ENCAPSULATE_PANIC = 1, | |
20 | TEST_IPSEC_IPv6_ENCAPSULATE_PANIC = 2, | |
21 | } test_identifier; | |
22 | ||
23 | #define TEST_SRC_ADDRESS_IPv4 "10.0.0.2" | |
24 | #define TEST_DST_ADDRESS_IPv4 "10.0.0.3" | |
25 | #define TEST_IPSEC_IPv4_INTERFACE_ADDRESS "192.168.10.10" | |
26 | #define TEST_IPSEC_IPv6_INTERFACE_ADDRESS "fdd3:0f89:9afd:9b9c::1234" | |
27 | #define TEST_DELEGATE_IPSEC_INTERFACE_ADDRESS "192.168.20.10" | |
28 | #define TEST_IPSEC_IPv4_INTERFACE_MASK "255.255.255.255" | |
29 | #define TEST_IPSEC_IPv6_INTERFACE_MASK "ffff:ffff:ffff:ffff::" | |
30 | ||
31 | static test_identifier test_id = TEST_INVALID; | |
32 | static dispatch_source_t pfkey_source = NULL; | |
33 | static NEVirtualInterfaceRef ipsecInterface = NULL; | |
34 | static NEVirtualInterfaceRef delegateIPsecInterface = NULL; | |
35 | static int bpf_fd = -1; | |
36 | ||
37 | static void bpf_write(int fd); | |
38 | static void pfkey_cleanup(void); | |
39 | static void pfkey_process_message_test_encapsulate_panic(uint8_t **mhp, int pfkey_socket); | |
40 | ||
41 | static void(*const process_pfkey_message_tests[])(uint8_t * *mhp, int pfkey_socket) = | |
42 | { | |
43 | NULL, | |
44 | pfkey_process_message_test_encapsulate_panic, // TEST_IPSEC_IPv4_ENCAPSULATE_PANIC | |
45 | pfkey_process_message_test_encapsulate_panic, // TEST_IPSEC_IPv6_ENCAPSULATE_PANIC | |
46 | }; | |
47 | ||
48 | static void | |
49 | send_pkey_add_sa(int pfkey_socket, uint32_t spi, const char *src, const char *dst, int family) | |
50 | { | |
51 | uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); | |
52 | bzero(payload, sizeof(payload)); | |
53 | uint16_t tlen = 0; | |
54 | ||
55 | struct sadb_msg *msg_payload = (struct sadb_msg *)payload; | |
56 | msg_payload->sadb_msg_version = PF_KEY_V2; | |
57 | msg_payload->sadb_msg_type = SADB_ADD; | |
58 | msg_payload->sadb_msg_errno = 0; | |
59 | msg_payload->sadb_msg_satype = SADB_SATYPE_ESP; | |
60 | msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); | |
61 | msg_payload->sadb_msg_reserved = 0; | |
62 | msg_payload->sadb_msg_seq = 0; | |
63 | msg_payload->sadb_msg_pid = (u_int32_t)getpid(); | |
64 | tlen += sizeof(*msg_payload); | |
65 | ||
66 | struct sadb_sa_2 *sa2_payload = (struct sadb_sa_2 *)(void *)(payload + tlen); | |
67 | sa2_payload->sa.sadb_sa_len = PFKEY_UNIT64(sizeof(*sa2_payload)); | |
68 | sa2_payload->sa.sadb_sa_exttype = SADB_EXT_SA; | |
69 | sa2_payload->sa.sadb_sa_spi = htonl(spi); | |
70 | sa2_payload->sa.sadb_sa_replay = 4; | |
71 | sa2_payload->sa.sadb_sa_state = SADB_SASTATE_LARVAL; | |
72 | sa2_payload->sa.sadb_sa_auth = SADB_X_AALG_SHA2_256; | |
73 | sa2_payload->sa.sadb_sa_encrypt = SADB_X_EALG_AESCBC; | |
74 | sa2_payload->sa.sadb_sa_flags |= (SADB_X_EXT_NATT | SADB_X_EXT_NATT_KEEPALIVE); | |
75 | sa2_payload->sadb_sa_natt_src_port = htons(4500); | |
76 | sa2_payload->sadb_sa_natt_port = 4500; | |
77 | sa2_payload->sadb_sa_natt_interval = 20; | |
78 | sa2_payload->sadb_sa_natt_offload_interval = 0; | |
79 | tlen += sizeof(*sa2_payload); | |
80 | ||
81 | struct sadb_x_sa2 *sa2_x_payload = (struct sadb_x_sa2 *)(void *)(payload + tlen); | |
82 | sa2_x_payload->sadb_x_sa2_len = PFKEY_UNIT64(sizeof(*sa2_x_payload)); | |
83 | sa2_x_payload->sadb_x_sa2_exttype = SADB_X_EXT_SA2; | |
84 | sa2_x_payload->sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; | |
85 | sa2_x_payload->sadb_x_sa2_reqid = 0; | |
86 | tlen += sizeof(*sa2_x_payload); | |
87 | ||
88 | uint8_t prefixlen = (family == AF_INET) ? (sizeof(struct in_addr) << 3) : (sizeof(struct in6_addr) << 3); | |
89 | ||
90 | struct sadb_address *src_address_payload = (struct sadb_address *)(void *)(payload + tlen); | |
91 | src_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_SRC & 0xffff; | |
92 | src_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; | |
93 | src_address_payload->sadb_address_prefixlen = prefixlen; | |
94 | src_address_payload->sadb_address_reserved = 0; | |
95 | tlen += sizeof(*src_address_payload); | |
96 | ||
97 | if (family == AF_INET) { | |
98 | struct sockaddr_in *src4 = (struct sockaddr_in *)(void *)(payload + tlen); | |
99 | T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, src, &src4->sin_addr), 1, "src address fail"); | |
100 | src4->sin_family = AF_INET; | |
101 | src4->sin_len = sizeof(*src4); | |
102 | uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src4->sin_len); | |
103 | src_address_payload->sadb_address_len = PFKEY_UNIT64(len); | |
104 | tlen += PFKEY_ALIGN8(src4->sin_len); | |
105 | } else { | |
106 | struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)(void *)(payload + tlen); | |
107 | T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, src, &src6->sin6_addr), 1, "src address fail"); | |
108 | src6->sin6_family = AF_INET6; | |
109 | src6->sin6_len = sizeof(*src6); | |
110 | uint16_t len = sizeof(*src_address_payload) + PFKEY_ALIGN8(src6->sin6_len); | |
111 | src_address_payload->sadb_address_len = PFKEY_UNIT64(len); | |
112 | tlen += PFKEY_ALIGN8(src6->sin6_len); | |
113 | } | |
114 | ||
115 | struct sadb_address *dst_address_payload = (struct sadb_address *)(void *)(payload + tlen); | |
116 | dst_address_payload->sadb_address_exttype = SADB_EXT_ADDRESS_DST & 0xffff; | |
117 | dst_address_payload->sadb_address_proto = IPSEC_ULPROTO_ANY & 0xff; | |
118 | dst_address_payload->sadb_address_prefixlen = prefixlen; | |
119 | dst_address_payload->sadb_address_reserved = 0; | |
120 | tlen += sizeof(*dst_address_payload); | |
121 | ||
122 | if (family == AF_INET) { | |
123 | struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)(payload + tlen); | |
124 | T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET, dst, &dst4->sin_addr), 1, "dst address fail"); | |
125 | dst4->sin_family = AF_INET; | |
126 | dst4->sin_len = sizeof(*dst4); | |
127 | uint16_t len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst4->sin_len); | |
128 | dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); | |
129 | tlen += PFKEY_ALIGN8(dst4->sin_len); | |
130 | } else { | |
131 | struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)(payload + tlen); | |
132 | T_QUIET; T_ASSERT_EQ_INT(inet_pton(AF_INET6, dst, &dst6->sin6_addr), 1, "dst address fail"); | |
133 | dst6->sin6_family = AF_INET6; | |
134 | dst6->sin6_len = sizeof(*dst6); | |
135 | uint16_t len = sizeof(*dst_address_payload) + PFKEY_ALIGN8(dst6->sin6_len); | |
136 | dst_address_payload->sadb_address_len = PFKEY_UNIT64(len); | |
137 | tlen += PFKEY_ALIGN8(dst6->sin6_len); | |
138 | } | |
139 | ||
140 | CFStringRef ipsecIfName = NEVirtualInterfaceCopyName(ipsecInterface); | |
141 | T_QUIET; T_ASSERT_NOTNULL(ipsecIfName, "failed to get ipsec interface name"); | |
142 | char ifname[IFNAMSIZ]; | |
143 | CFStringGetCString(ipsecIfName, ifname, IFNAMSIZ, kCFStringEncodingUTF8); | |
144 | ||
145 | CFStringRef delegateIPsecIfName = NEVirtualInterfaceCopyName(delegateIPsecInterface); | |
146 | T_QUIET; T_ASSERT_NOTNULL(delegateIPsecIfName, "failed to get delegate ipsec interface name"); | |
147 | char delegateIfname[IFNAMSIZ]; | |
148 | CFStringGetCString(delegateIPsecIfName, delegateIfname, IFNAMSIZ, kCFStringEncodingUTF8); | |
149 | ||
150 | struct sadb_x_ipsecif *ipsec_if_payload = (struct sadb_x_ipsecif *)(void *)(payload + tlen); | |
151 | ipsec_if_payload->sadb_x_ipsecif_len = PFKEY_UNIT64(sizeof(*ipsec_if_payload)); | |
152 | ipsec_if_payload->sadb_x_ipsecif_exttype = SADB_X_EXT_IPSECIF; | |
153 | strncpy(ipsec_if_payload->sadb_x_ipsecif_ipsec_if, ifname, strlen(ifname)); | |
154 | strncpy(ipsec_if_payload->sadb_x_ipsecif_outgoing_if, delegateIfname, strlen(delegateIfname)); | |
155 | tlen += sizeof(*ipsec_if_payload); | |
156 | ||
157 | struct sadb_key *encrypt_key_payload = (struct sadb_key *)(void *)(payload + tlen); | |
158 | uint16_t len = sizeof(*encrypt_key_payload) + PFKEY_ALIGN8(32); | |
159 | encrypt_key_payload->sadb_key_len = PFKEY_UNIT64(len); | |
160 | encrypt_key_payload->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; | |
161 | encrypt_key_payload->sadb_key_bits = (uint16_t)(32 << 3); | |
162 | encrypt_key_payload->sadb_key_reserved = 0; | |
163 | tlen += sizeof(*encrypt_key_payload); | |
164 | arc4random_buf(payload + tlen, 32); | |
165 | tlen += PFKEY_ALIGN8(32); | |
166 | ||
167 | struct sadb_key *auth_key_payload = (struct sadb_key *)(void *)(payload + tlen); | |
168 | len = sizeof(*auth_key_payload) + PFKEY_ALIGN8(32); | |
169 | auth_key_payload->sadb_key_len = PFKEY_UNIT64(len); | |
170 | auth_key_payload->sadb_key_exttype = SADB_EXT_KEY_AUTH; | |
171 | auth_key_payload->sadb_key_bits = (uint16_t)(32 << 3); | |
172 | auth_key_payload->sadb_key_reserved = 0; | |
173 | tlen += sizeof(*auth_key_payload); | |
174 | arc4random_buf(payload + tlen, 32); | |
175 | tlen += PFKEY_ALIGN8(32); | |
176 | ||
177 | struct sadb_lifetime *hard_lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); | |
178 | hard_lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*hard_lifetime_payload)); | |
179 | hard_lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; | |
180 | tlen += sizeof(*hard_lifetime_payload); | |
181 | ||
182 | struct sadb_lifetime *soft_lifetime_payload = (struct sadb_lifetime *)(void *)(payload + tlen); | |
183 | soft_lifetime_payload->sadb_lifetime_len = PFKEY_UNIT64(sizeof(*soft_lifetime_payload)); | |
184 | soft_lifetime_payload->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; | |
185 | tlen += sizeof(*soft_lifetime_payload); | |
186 | ||
187 | // Update the total length | |
188 | msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); | |
189 | T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey send update sa"); | |
190 | } | |
191 | ||
192 | static void | |
193 | send_pfkey_flush_sa(int pfkey_socket) | |
194 | { | |
195 | uint8_t payload[MCLBYTES] __attribute__ ((aligned(32))); | |
196 | bzero(payload, sizeof(payload)); | |
197 | uint16_t tlen = 0; | |
198 | ||
199 | struct sadb_msg *msg_payload = (struct sadb_msg *)payload; | |
200 | msg_payload->sadb_msg_version = PF_KEY_V2; | |
201 | msg_payload->sadb_msg_type = SADB_FLUSH; | |
202 | msg_payload->sadb_msg_errno = 0; | |
203 | msg_payload->sadb_msg_satype = SADB_SATYPE_UNSPEC; | |
204 | msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); | |
205 | msg_payload->sadb_msg_reserved = 0; | |
206 | msg_payload->sadb_msg_seq = 0; | |
207 | msg_payload->sadb_msg_pid = (u_int32_t)getpid(); | |
208 | tlen += sizeof(*msg_payload); | |
209 | ||
210 | // Update the total length | |
211 | msg_payload->sadb_msg_len = PFKEY_UNIT64(tlen); | |
212 | T_QUIET; T_ASSERT_POSIX_SUCCESS(send(pfkey_socket, payload, (size_t)PFKEY_UNUNIT64(msg_payload->sadb_msg_len), 0), "pfkey flush sa"); | |
213 | } | |
214 | ||
215 | static void | |
216 | pfkey_cleanup(void) | |
217 | { | |
218 | if (pfkey_source != NULL) { | |
219 | int pfkey_socket = (int)dispatch_source_get_handle(pfkey_source); | |
220 | if (pfkey_socket > 0) { | |
221 | send_pfkey_flush_sa(pfkey_socket); | |
222 | } | |
223 | dispatch_source_cancel(pfkey_source); | |
224 | pfkey_source = NULL; | |
225 | } | |
226 | } | |
227 | ||
228 | static void | |
229 | pfkey_align(struct sadb_msg *msg, uint8_t **mhp) | |
230 | { | |
231 | struct sadb_ext *ext; | |
232 | int i; | |
233 | uint8_t *p; | |
234 | uint8_t *ep; /* XXX should be passed from upper layer */ | |
235 | ||
236 | /* validity check */ | |
237 | T_QUIET; T_ASSERT_NOTNULL(msg, "pfkey align msg"); | |
238 | T_QUIET; T_ASSERT_NOTNULL(mhp, "pfkey align mhp"); | |
239 | ||
240 | /* initialize */ | |
241 | for (i = 0; i < SADB_EXT_MAX + 1; i++) { | |
242 | mhp[i] = NULL; | |
243 | } | |
244 | ||
245 | mhp[0] = (void *)msg; | |
246 | ||
247 | /* initialize */ | |
248 | p = (void *) msg; | |
249 | ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); | |
250 | ||
251 | /* skip base header */ | |
252 | p += sizeof(struct sadb_msg); | |
253 | ||
254 | while (p < ep) { | |
255 | ext = (void *)p; | |
256 | T_QUIET; T_ASSERT_GE_PTR((void *)ep, (void *)(p + sizeof(*ext)), "pfkey extension header beyond end of buffer"); | |
257 | T_QUIET; T_ASSERT_GE_ULONG((unsigned long)PFKEY_EXTLEN(ext), sizeof(*ext), "pfkey extension shorter than extension header"); | |
258 | T_QUIET; T_ASSERT_GE_PTR((void *)ep, (void *)(p + PFKEY_EXTLEN(ext)), "pfkey extension length beyond end of buffer"); | |
259 | ||
260 | T_QUIET; T_EXPECT_NULL(mhp[ext->sadb_ext_type], "duplicate extension type %u payload", ext->sadb_ext_type); | |
261 | ||
262 | /* set pointer */ | |
263 | switch (ext->sadb_ext_type) { | |
264 | case SADB_EXT_SA: | |
265 | case SADB_EXT_LIFETIME_CURRENT: | |
266 | case SADB_EXT_LIFETIME_HARD: | |
267 | case SADB_EXT_LIFETIME_SOFT: | |
268 | case SADB_EXT_ADDRESS_SRC: | |
269 | case SADB_EXT_ADDRESS_DST: | |
270 | case SADB_EXT_ADDRESS_PROXY: | |
271 | case SADB_EXT_KEY_AUTH: | |
272 | /* XXX should to be check weak keys. */ | |
273 | case SADB_EXT_KEY_ENCRYPT: | |
274 | /* XXX should to be check weak keys. */ | |
275 | case SADB_EXT_IDENTITY_SRC: | |
276 | case SADB_EXT_IDENTITY_DST: | |
277 | case SADB_EXT_SENSITIVITY: | |
278 | case SADB_EXT_PROPOSAL: | |
279 | case SADB_EXT_SUPPORTED_AUTH: | |
280 | case SADB_EXT_SUPPORTED_ENCRYPT: | |
281 | case SADB_EXT_SPIRANGE: | |
282 | case SADB_X_EXT_POLICY: | |
283 | case SADB_X_EXT_SA2: | |
284 | case SADB_EXT_SESSION_ID: | |
285 | case SADB_EXT_SASTAT: | |
286 | #ifdef SADB_X_EXT_NAT_T_TYPE | |
287 | case SADB_X_EXT_NAT_T_TYPE: | |
288 | case SADB_X_EXT_NAT_T_SPORT: | |
289 | case SADB_X_EXT_NAT_T_DPORT: | |
290 | case SADB_X_EXT_NAT_T_OA: | |
291 | #endif | |
292 | #ifdef SADB_X_EXT_TAG | |
293 | case SADB_X_EXT_TAG: | |
294 | #endif | |
295 | #ifdef SADB_X_EXT_PACKET | |
296 | case SADB_X_EXT_PACKET: | |
297 | #endif | |
298 | case SADB_X_EXT_IPSECIF: | |
299 | case SADB_X_EXT_ADDR_RANGE_SRC_START: | |
300 | case SADB_X_EXT_ADDR_RANGE_SRC_END: | |
301 | case SADB_X_EXT_ADDR_RANGE_DST_START: | |
302 | case SADB_X_EXT_ADDR_RANGE_DST_END: | |
303 | #ifdef SADB_MIGRATE | |
304 | case SADB_EXT_MIGRATE_ADDRESS_SRC: | |
305 | case SADB_EXT_MIGRATE_ADDRESS_DST: | |
306 | case SADB_X_EXT_MIGRATE_IPSECIF: | |
307 | #endif | |
308 | mhp[ext->sadb_ext_type] = (void *)ext; | |
309 | break; | |
310 | default: | |
311 | T_FAIL("bad extension type %u", ext->sadb_ext_type); | |
312 | T_END; | |
313 | } | |
314 | ||
315 | p += PFKEY_EXTLEN(ext); | |
316 | } | |
317 | ||
318 | T_QUIET; T_EXPECT_EQ_PTR((void *)ep, (void *)p, "invalid pfkey message length"); | |
319 | return; | |
320 | } | |
321 | ||
322 | static void | |
323 | pfkey_process_message_test_encapsulate_panic(uint8_t **mhp, __unused int pfkey_socket) | |
324 | { | |
325 | struct sadb_msg *message = (struct sadb_msg *)(void *)mhp[0]; | |
326 | static uint32_t spi = 0; | |
327 | static uint8_t added_sa_counter = 0; | |
328 | ||
329 | if (message->sadb_msg_pid != (uint32_t)getpid()) { | |
330 | return; | |
331 | } | |
332 | ||
333 | if (message->sadb_msg_errno != 0) { | |
334 | T_FAIL("SADB add SA received error %d", message->sadb_msg_errno); | |
335 | T_END; | |
336 | } | |
337 | ||
338 | switch (message->sadb_msg_type) { | |
339 | case SADB_ADD: | |
340 | { | |
341 | struct sadb_sa *sa_message = (struct sadb_sa *)(void *)mhp[SADB_EXT_SA]; | |
342 | T_QUIET; T_ASSERT_NOTNULL(sa_message, "add sa message is NULL"); | |
343 | spi = ntohl(sa_message->sadb_sa_spi); | |
344 | T_LOG("added sa 0x%x", spi); | |
345 | added_sa_counter++; | |
346 | if (added_sa_counter == 2) { | |
347 | bpf_write(bpf_fd); | |
348 | } | |
349 | break; | |
350 | } | |
351 | case SADB_FLUSH: | |
352 | case SADB_X_SPDFLUSH: | |
353 | break; | |
354 | default: | |
355 | T_FAIL("bad SADB message type %u", message->sadb_msg_type); | |
356 | T_END; | |
357 | } | |
358 | return; | |
359 | } | |
360 | ||
361 | static void | |
362 | recv_pfkey_message(int pfkey_socket) | |
363 | { | |
364 | uint8_t buffer[8192] __attribute__((aligned(4))); | |
365 | struct iovec iovecs[1] = { | |
366 | { buffer, sizeof(buffer) }, | |
367 | }; | |
368 | struct msghdr msg = { | |
369 | NULL, | |
370 | 0, | |
371 | iovecs, | |
372 | sizeof(iovecs) / sizeof(iovecs[0]), | |
373 | NULL, | |
374 | 0, | |
375 | 0, | |
376 | }; | |
377 | ||
378 | do { | |
379 | ssize_t result = -1; | |
380 | memset(buffer, 0, sizeof(buffer)); | |
381 | T_QUIET; T_ASSERT_POSIX_SUCCESS(result = recvmsg(pfkey_socket, &msg, 0), NULL); | |
382 | ||
383 | if (result > 0) { | |
384 | T_QUIET; T_ASSERT_GE_ULONG((size_t)result, sizeof(struct sadb_msg), "Invalid PFKey message size: %zu", result); | |
385 | struct sadb_msg *hdr = (struct sadb_msg *)buffer; | |
386 | uint8_t *mhp[SADB_EXT_MAX + 1]; | |
387 | pfkey_align(hdr, mhp); | |
388 | (*process_pfkey_message_tests[test_id])(mhp, pfkey_socket); | |
389 | } else if (result == 0) { | |
390 | T_LOG("PFKey socket received EOF"); | |
391 | break; | |
392 | } | |
393 | } while (1); | |
394 | } | |
395 | ||
396 | static int | |
397 | pfkey_setup_socket(void) | |
398 | { | |
399 | int pfkey_socket = -1; | |
400 | int bufsiz = 0; | |
401 | const unsigned long newbufk = 1536; | |
402 | unsigned long oldmax; | |
403 | size_t oldmaxsize = sizeof(oldmax); | |
404 | unsigned long newmax = newbufk * (1024 + 128); | |
405 | ||
406 | T_QUIET; T_ASSERT_POSIX_SUCCESS(pfkey_socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2), NULL); | |
407 | ||
408 | if (sysctlbyname("kern.ipc.maxsockbuf", &oldmax, &oldmaxsize, &newmax, sizeof(newmax)) != 0) { | |
409 | bufsiz = 233016; /* Max allowed by default */ | |
410 | } else { | |
411 | bufsiz = newbufk * 1024; | |
412 | } | |
413 | ||
414 | T_QUIET; T_ASSERT_POSIX_SUCCESS(setsockopt(pfkey_socket, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)), "pfkey set snd socket buf failed %d", bufsiz); | |
415 | T_QUIET; T_ASSERT_POSIX_SUCCESS(setsockopt(pfkey_socket, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)), "pfkey set recv socket buf failed %d", bufsiz); | |
416 | ||
417 | pfkey_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)pfkey_socket, 0, dispatch_get_main_queue()); | |
418 | T_QUIET; T_ASSERT_NOTNULL(pfkey_source, "dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ...)"); | |
419 | dispatch_source_set_event_handler(pfkey_source, ^{ | |
420 | recv_pfkey_message(pfkey_socket); | |
421 | }); | |
422 | dispatch_source_set_cancel_handler(pfkey_source, ^{ | |
423 | close(pfkey_socket); | |
424 | }); | |
425 | dispatch_resume(pfkey_source); | |
426 | return pfkey_socket; | |
427 | } | |
428 | ||
429 | static int | |
430 | bpf_new(void) | |
431 | { | |
432 | char bpfdev[256]; | |
433 | int i; | |
434 | int fd = -1; | |
435 | ||
436 | for (i = 0; true; i++) { | |
437 | snprintf(bpfdev, sizeof(bpfdev), "/dev/bpf%d", i); | |
438 | fd = open(bpfdev, O_RDWR, 0); | |
439 | if (fd >= 0) { | |
440 | break; | |
441 | } | |
442 | if (errno != EBUSY) { | |
443 | break; | |
444 | } | |
445 | } | |
446 | return fd; | |
447 | } | |
448 | ||
449 | static int | |
450 | bpf_setif(int fd, const char *en_name) | |
451 | { | |
452 | struct ifreq ifr; | |
453 | ||
454 | strlcpy(ifr.ifr_name, en_name, sizeof(ifr.ifr_name)); | |
455 | return ioctl(fd, BIOCSETIF, &ifr); | |
456 | } | |
457 | ||
458 | static int | |
459 | bpf_sethdr_complete(int fd) | |
460 | { | |
461 | u_int8_t hdr_complete = 1; | |
462 | return ioctl(fd, BIOCSHDRCMPLT, &hdr_complete); | |
463 | } | |
464 | ||
465 | static void | |
466 | bpf_write(int fd) | |
467 | { | |
468 | if (test_id == TEST_IPSEC_IPv4_ENCAPSULATE_PANIC) { | |
469 | char buffer[500]; | |
470 | struct ip *ipheader = (void *)buffer; | |
471 | ipheader->ip_v = IPVERSION; | |
472 | ipheader->ip_hl = (sizeof(struct ip) - 4) >> 2; | |
473 | ipheader->ip_ttl = MAXTTL; | |
474 | ipheader->ip_p = IPPROTO_UDP; | |
475 | T_QUIET; T_ASSERT_POSIX_SUCCESS(write(fd, buffer, 500), "bpf write call failed"); | |
476 | T_PASS("wrote bad ip header successfully"); | |
477 | T_END; | |
478 | } else if (test_id == TEST_IPSEC_IPv6_ENCAPSULATE_PANIC) { | |
479 | struct ip6_hdr ip6 = {0}; | |
480 | ip6.ip6_vfc |= IPV6_VERSION; | |
481 | T_QUIET; T_ASSERT_POSIX_SUCCESS(write(fd, &ip6, sizeof(ip6) - 4), "bpf write call failed"); | |
482 | T_PASS("wrote bad ipv6 header successfully"); | |
483 | T_END; | |
484 | } | |
485 | } | |
486 | ||
487 | static void | |
488 | bpf_socket_setup(void) | |
489 | { | |
490 | int status = -1; | |
491 | ||
492 | bpf_fd = bpf_new(); | |
493 | T_QUIET; T_ASSERT_NE(bpf_fd, -1, "failed to create bpf file descriptor"); | |
494 | ||
495 | CFStringRef ipsecIfName = NEVirtualInterfaceCopyName(ipsecInterface); | |
496 | T_QUIET; T_ASSERT_NOTNULL(ipsecIfName, "failed to get ipsec interface name"); | |
497 | ||
498 | char ifname[IFNAMSIZ]; | |
499 | CFStringGetCString(ipsecIfName, ifname, IFNAMSIZ, kCFStringEncodingUTF8); | |
500 | ||
501 | status = bpf_setif(bpf_fd, ifname); | |
502 | T_QUIET; T_ASSERT_NE(status, -1, "failed to set bpf interface"); | |
503 | ||
504 | status = bpf_sethdr_complete(bpf_fd); | |
505 | T_QUIET; T_ASSERT_NE(status, -1, "failed to set bpf header complete"); | |
506 | } | |
507 | ||
508 | static NEVirtualInterfaceRef | |
509 | ipsec_interface_setup(CFStringRef interfaceAddress, CFStringRef interfaceMask) | |
510 | { | |
511 | Boolean status = FALSE; | |
512 | ||
513 | NEVirtualInterfaceRef interface = NEVirtualInterfaceCreate(NULL, kNEVirtualInterfaceValTypeIPSec, dispatch_get_main_queue(), NULL); | |
514 | T_QUIET; T_ASSERT_NOTNULL(interface, "ipsec interface creation failed"); | |
515 | status = NEVirtualInterfaceSetMTU(interface, 1400); | |
516 | if (status == FALSE) { | |
517 | T_FAIL("Failed to set MTU on ipsec interface"); | |
518 | T_END; | |
519 | } | |
520 | ||
521 | status = NEVirtualInterfaceAddAddress(interface, interfaceAddress, interfaceMask); | |
522 | if (status == FALSE) { | |
523 | T_FAIL("Failed to set address on ipsec interface"); | |
524 | T_END; | |
525 | } | |
526 | ||
527 | CFStringRef ipsecIfName = NEVirtualInterfaceCopyName(interface); | |
528 | T_QUIET; T_ASSERT_NOTNULL(ipsecIfName, "failed to get ipsec interface name"); | |
529 | ||
530 | char ifname[IFNAMSIZ]; | |
531 | CFStringGetCString(ipsecIfName, ifname, IFNAMSIZ, kCFStringEncodingUTF8); | |
532 | ||
533 | T_LOG("%s interface setup", ifname); | |
534 | return interface; | |
535 | } | |
536 | ||
537 | static void | |
538 | ipsec_interface_set_delegate(NEVirtualInterfaceRef interface, CFStringRef delegateInterfaceName) | |
539 | { | |
540 | Boolean status = NEVirtualInterfaceSetDelegateInterface(interface, delegateInterfaceName); | |
541 | if (status == FALSE) { | |
542 | T_FAIL("Failed to set delegate on ipsec interface"); | |
543 | T_END; | |
544 | } | |
545 | ||
546 | return; | |
547 | } | |
548 | ||
549 | static void | |
550 | ipsec_cleanup(void) | |
551 | { | |
552 | pfkey_cleanup(); | |
553 | ||
554 | if (ipsecInterface != NULL) { | |
555 | NEVirtualInterfaceInvalidate(ipsecInterface); | |
556 | ipsecInterface = NULL; | |
557 | } | |
558 | ||
559 | if (delegateIPsecInterface != NULL) { | |
560 | NEVirtualInterfaceInvalidate(delegateIPsecInterface); | |
561 | delegateIPsecInterface = NULL; | |
562 | } | |
563 | ||
564 | if (bpf_fd != -1) { | |
565 | close(bpf_fd); | |
566 | bpf_fd = -1; | |
567 | } | |
568 | } | |
569 | ||
570 | T_DECL(ipsec_ipv4_encapsulate_panic_63139357, "ipsec: outer ip header length less than 20") | |
571 | { | |
572 | test_id = TEST_IPSEC_IPv4_ENCAPSULATE_PANIC; | |
573 | ||
574 | T_ATEND(ipsec_cleanup); | |
575 | ||
576 | ipsecInterface = ipsec_interface_setup(CFSTR(TEST_IPSEC_IPv4_INTERFACE_ADDRESS), CFSTR(TEST_IPSEC_IPv4_INTERFACE_MASK)); | |
577 | delegateIPsecInterface = ipsec_interface_setup(CFSTR(TEST_DELEGATE_IPSEC_INTERFACE_ADDRESS), CFSTR(TEST_IPSEC_IPv4_INTERFACE_MASK)); | |
578 | ||
579 | CFStringRef delegateIPsecIfName = NEVirtualInterfaceCopyName(delegateIPsecInterface); | |
580 | T_QUIET; T_ASSERT_NOTNULL(delegateIPsecIfName, "failed to get ipsec interface name"); | |
581 | ipsec_interface_set_delegate(ipsecInterface, delegateIPsecIfName); | |
582 | ||
583 | bpf_socket_setup(); | |
584 | ||
585 | int pfkey_socket = pfkey_setup_socket(); | |
586 | send_pfkey_flush_sa(pfkey_socket); | |
587 | ||
588 | send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); | |
589 | send_pkey_add_sa(pfkey_socket, 0x23456789, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); | |
590 | ||
591 | dispatch_main(); | |
592 | } | |
593 | ||
594 | T_DECL(ipsec_ipv6_encapsulate_panic_63139357, "ipsec: payload less than IPv6 header") | |
595 | { | |
596 | test_id = TEST_IPSEC_IPv6_ENCAPSULATE_PANIC; | |
597 | ||
598 | T_ATEND(ipsec_cleanup); | |
599 | ||
600 | ipsecInterface = ipsec_interface_setup(CFSTR(TEST_IPSEC_IPv6_INTERFACE_ADDRESS), CFSTR(TEST_IPSEC_IPv6_INTERFACE_MASK)); | |
601 | delegateIPsecInterface = ipsec_interface_setup(CFSTR(TEST_DELEGATE_IPSEC_INTERFACE_ADDRESS), CFSTR(TEST_IPSEC_IPv4_INTERFACE_MASK)); | |
602 | ||
603 | CFStringRef delegateIPsecIfName = NEVirtualInterfaceCopyName(delegateIPsecInterface); | |
604 | T_QUIET; T_ASSERT_NOTNULL(delegateIPsecIfName, "failed to get ipsec interface name"); | |
605 | ipsec_interface_set_delegate(ipsecInterface, delegateIPsecIfName); | |
606 | ||
607 | bpf_socket_setup(); | |
608 | ||
609 | int pfkey_socket = pfkey_setup_socket(); | |
610 | send_pfkey_flush_sa(pfkey_socket); | |
611 | ||
612 | send_pkey_add_sa(pfkey_socket, 0x12345678, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); | |
613 | send_pkey_add_sa(pfkey_socket, 0x23456789, TEST_SRC_ADDRESS_IPv4, TEST_DST_ADDRESS_IPv4, AF_INET); | |
614 | ||
615 | dispatch_main(); | |
616 | } |