1 /*
2 * Copyright (c) 2025 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #define __APPLE_USE_RFC_3542 1
30
31 #include <darwintest.h>
32
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37
38 #include "net_test_lib.h"
39
40 T_GLOBAL_META(
41 T_META_NAMESPACE("xnu.net"),
42 T_META_ASROOT(true),
43 T_META_RADAR_COMPONENT_NAME("xnu"),
44 T_META_RADAR_COMPONENT_VERSION("networking"),
45 T_META_CHECK_LEAKS(false));
46
47 static char *ifname1;
48 static char *ifname2;
49
50 #define IPV4_MULTICAST_ADDR_STR "239.1.2.3"
51 #define IPV6_MULTICAST_ADDR_STR "FF12:0:0:0:0:0:0:FC"
52
53 #define TEN_NET 0x0a000000
54 #define TEN_1_NET (TEN_NET | 0x010000)
55 #define TEN_1_BROADCAST (TEN_1_NET | 0xff)
56
57 static network_interface_pair_list_t S_feth_pairs;
58
59
60 static void
get_ipv4_address(u_int unit,u_int addr_index,struct in_addr * ip)61 get_ipv4_address(u_int unit, u_int addr_index, struct in_addr *ip)
62 {
63 /* up to 255 units, 255 addresses */
64 ip->s_addr = htonl(TEN_1_NET | (unit << 8) | addr_index);
65 return;
66 }
67
68 static void
network_interface_assign_address(network_interface_t netif,unsigned int unit,unsigned int address_index)69 network_interface_assign_address(network_interface_t netif,
70 unsigned int unit, unsigned int address_index)
71 {
72 get_ipv4_address(unit, address_index, &netif->ip);
73 ifnet_add_ip_address(netif->if_name, netif->ip,
74 inet_class_c_subnet_mask);
75 route_add_inet_scoped_subnet(netif->if_name, netif->if_index,
76 netif->ip, inet_class_c_subnet_mask);
77 ifnet_start_ipv6(netif->if_name);
78 T_ASSERT_EQ(inet6_get_linklocal_address(netif->if_index, &netif->ip6), 1, NULL);
79 }
80
81 static void
initialize_feth_pairs(u_int n,bool need_address)82 initialize_feth_pairs(u_int n, bool need_address)
83 {
84 network_interface_pair_t scan;
85
86 S_feth_pairs = network_interface_pair_list_alloc(n);
87 scan = S_feth_pairs->list;
88 for (unsigned int i = 0; i < n; i++, scan++) {
89 network_interface_create(&scan->one, FETH_NAME);
90 network_interface_create(&scan->two, FETH_NAME);
91 if (need_address) {
92 network_interface_assign_address(&scan->one, i, 1);
93 network_interface_assign_address(&scan->two, i, 2);
94 }
95 fake_set_peer(scan->one.if_name, scan->two.if_name);
96 }
97
98 ifname1 = S_feth_pairs->list->one.if_name;
99 ifname2 = S_feth_pairs->list->two.if_name;
100 }
101
102 static void
cleanup(void)103 cleanup(void)
104 {
105 network_interface_pair_list_destroy(S_feth_pairs);
106 }
107
108 static void
init(void)109 init(void)
110 {
111 T_ATEND(cleanup);
112
113 initialize_feth_pairs(1, true);
114 }
115
116 T_DECL(ip_recv_link_addr_type, "IP_RECV_LINK_ADDR_TYPE")
117 {
118 int receive_fd;
119 int sender_fd;
120 socklen_t solen;
121 int optval;
122 struct ip_mreq mreq = {};
123 struct sockaddr_in sin = {};
124 struct in_addr addr;
125 char *str;
126 ssize_t retval;
127 in_port_t port;
128
129 init();
130
131 /*
132 * Setup receiver bound to ifname1
133 */
134 T_ASSERT_POSIX_SUCCESS(receive_fd = socket(AF_INET, SOCK_DGRAM, 0), NULL);
135
136 solen = strlen(ifname1);
137 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname1, solen), NULL);
138
139 /*
140 * Verify the IP_RECV_LINK_ADDR_TYPE option is setable
141 */
142 solen = sizeof(int);
143
144 T_ASSERT_POSIX_SUCCESS(getsockopt(receive_fd, IPPROTO_IP, IP_RECV_LINK_ADDR_TYPE, &optval, &solen), NULL);
145 T_LOG("IP_RECV_LINK_ADDR_TYPE default: %d", optval);
146
147 optval = 1;
148 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IP, IP_RECV_LINK_ADDR_TYPE, &optval, solen), NULL);
149
150 T_ASSERT_POSIX_SUCCESS(getsockopt(receive_fd, IPPROTO_IP, IP_RECV_LINK_ADDR_TYPE, &optval, &solen), NULL);
151 T_LOG("IP_RECV_LINK_ADDR_TYPE enabled: %d", optval);
152
153 /*
154 * Join multicast group on ifname1
155 */
156 inet_aton(IPV4_MULTICAST_ADDR_STR, &mreq.imr_multiaddr);
157 mreq.imr_interface = S_feth_pairs->list->one.ip;
158 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)), NULL);
159
160 struct timeval timeo = { .tv_sec = 1, .tv_usec = 0 };
161 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)), NULL);
162
163 optval = 1;
164 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IP, IP_RECVDSTADDR, &optval, sizeof(optval)), NULL);
165
166 /*
167 * Bind to an ephemeral port
168 */
169 sin.sin_family = AF_INET;
170 sin.sin_len = sizeof(struct sockaddr_in);
171 T_ASSERT_POSIX_SUCCESS(bind(receive_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)), NULL);
172
173 solen = sizeof(struct sockaddr_in);
174 T_ASSERT_POSIX_SUCCESS(getsockname(receive_fd, (struct sockaddr *)&sin, &solen), NULL);
175
176 port = sin.sin_port;
177 T_LOG("receiver bound to port %u", ntohs(port));
178
179
180 /*
181 * Setup receiver bound to ifname2
182 */
183 T_ASSERT_POSIX_SUCCESS(sender_fd = socket(AF_INET, SOCK_DGRAM, 0), NULL);
184
185 solen = strlen(ifname2);
186 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname2, solen), NULL);
187
188 addr = S_feth_pairs->list->two.ip;
189 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr)), NULL);
190
191 u_char ttl = 255;
192 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)), NULL);
193
194 optval = 1;
195 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)), NULL);
196
197 /*
198 * Send unicast, broadcast and multicast a few times to allow for ARP to do its job
199 */
200 for (int i = 0; i < 3; i++) {
201 str = "unicast";
202 sin.sin_family = AF_INET;
203 sin.sin_len = sizeof(struct sockaddr_in);
204 sin.sin_addr = S_feth_pairs->list->one.ip;
205 sin.sin_port = port;
206 T_ASSERT_POSIX_SUCCESS(retval = sendto(sender_fd, str, strlen(str) + 1, 0, (struct sockaddr *)&sin, sin.sin_len), NULL);
207
208 str = "broadcast";
209 sin.sin_family = AF_INET;
210 sin.sin_len = sizeof(struct sockaddr_in);
211 sin.sin_addr.s_addr = htonl(TEN_1_BROADCAST);
212 sin.sin_port = port;
213 T_ASSERT_POSIX_SUCCESS(retval = sendto(sender_fd, str, strlen(str) + 1, 0, (struct sockaddr *)&sin, sin.sin_len), NULL);
214
215 str = "multicast";
216 sin.sin_family = AF_INET;
217 sin.sin_len = sizeof(struct sockaddr_in);
218 inet_aton(IPV4_MULTICAST_ADDR_STR, &sin.sin_addr);
219 sin.sin_port = port;
220 T_ASSERT_POSIX_SUCCESS(retval = sendto(sender_fd, str, strlen(str) + 1, 0, (struct sockaddr *)&sin, sin.sin_len), NULL);
221
222 usleep(50);
223 }
224
225 while (true) {
226 char control_space[CMSG_SPACE(8192)] = {};
227 struct msghdr recvmsghdr = {};
228 char packet_space[1500] = {};
229 struct cmsghdr *cmsg;
230 int addr_type = -1;
231
232 struct iovec recv_iov;
233 recv_iov.iov_len = sizeof(packet_space);
234 recv_iov.iov_base = &packet_space;
235
236 recvmsghdr.msg_iov = &recv_iov;
237 recvmsghdr.msg_iovlen = 1;
238 recvmsghdr.msg_control = &control_space;
239 recvmsghdr.msg_controllen = sizeof(control_space);
240 recvmsghdr.msg_flags = 0;
241
242 retval = recvmsg(receive_fd, &recvmsghdr, 0);
243 if (retval < 0) {
244 break;
245 }
246
247 for (cmsg = CMSG_FIRSTHDR(&recvmsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&recvmsghdr, cmsg)) {
248 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
249 addr.s_addr = *(in_addr_t *)CMSG_DATA(cmsg);
250 }
251 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECV_LINK_ADDR_TYPE) {
252 addr_type = *(int *)CMSG_DATA(cmsg);
253 }
254 }
255 T_LOG("received packet to: %s address type: %d", inet_ntoa(addr), addr_type);
256
257 if (IN_MULTICAST(ntohl(addr.s_addr))) {
258 T_ASSERT_EQ(addr_type, IP_RECV_LINK_ADDR_MULTICAST, "multicast");
259 } else if ((ntohl(addr.s_addr) & 0x000000ff) == 0x000000ff) {
260 T_ASSERT_EQ(addr_type, IP_RECV_LINK_ADDR_BROADCAST, "broadcast");
261 } else {
262 T_ASSERT_EQ(addr_type, IP_RECV_LINK_ADDR_UNICAST, "unicast");
263 }
264 }
265 }
266
267 T_DECL(ipv6_recv_link_addr_type, "IPV6_RECV_LINK_ADDR_TYPE")
268 {
269 int receive_fd;
270 int sender_fd;
271 socklen_t solen;
272 int optval;
273 struct ipv6_mreq mreq = {};
274 struct sockaddr_in6 sin6 = {};
275 char *str;
276 ssize_t retval;
277 in_port_t port;
278 char addrstr[INET6_ADDRSTRLEN];
279
280 init();
281
282 inet_ntop(AF_INET6, &S_feth_pairs->list->one.ip6, addrstr, sizeof(addrstr));
283 T_LOG("feth one: %s index: %u ip: %s ip6: %s",
284 S_feth_pairs->list->one.if_name,
285 S_feth_pairs->list->one.if_index,
286 inet_ntoa(S_feth_pairs->list->one.ip),
287 addrstr);
288
289 inet_ntop(AF_INET6, &S_feth_pairs->list->two.ip6, addrstr, sizeof(addrstr));
290 T_LOG("feth one: %s index: %u ip: %s ip6: %s",
291 S_feth_pairs->list->two.if_name,
292 S_feth_pairs->list->two.if_index,
293 inet_ntoa(S_feth_pairs->list->two.ip),
294 addrstr);
295
296
297 /*
298 * Setup receiver bound to ifname1
299 */
300 T_ASSERT_POSIX_SUCCESS(receive_fd = socket(AF_INET6, SOCK_DGRAM, 0), NULL);
301
302 solen = strlen(ifname1);
303 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname1, solen), NULL);
304
305 optval = 1;
306 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)), NULL);
307
308 /*
309 * Verify the IP_RECV_LINK_ADDR_TYPE option is setable
310 */
311 solen = sizeof(int);
312
313 T_ASSERT_POSIX_SUCCESS(getsockopt(receive_fd, IPPROTO_IPV6, IPV6_RECV_LINK_ADDR_TYPE, &optval, &solen), NULL);
314 T_LOG("IPV6_RECV_LINK_ADDR_TYPE default: %d", optval);
315
316 optval = 1;
317 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IPV6, IPV6_RECV_LINK_ADDR_TYPE, &optval, solen), NULL);
318
319 T_ASSERT_POSIX_SUCCESS(getsockopt(receive_fd, IPPROTO_IPV6, IPV6_RECV_LINK_ADDR_TYPE, &optval, &solen), NULL);
320 T_LOG("IPV6_RECV_LINK_ADDR_TYPE enabled: %d", optval);
321
322 /*
323 * Join multicast group on ifname1
324 */
325 inet_pton(AF_INET6, IPV6_MULTICAST_ADDR_STR, &mreq.ipv6mr_multiaddr);
326 mreq.ipv6mr_interface = S_feth_pairs->list->one.if_index;
327 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)), NULL);
328
329 struct timeval timeo = { .tv_sec = 1, .tv_usec = 0 };
330 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)), NULL);
331
332 optval = 1;
333 T_ASSERT_POSIX_SUCCESS(setsockopt(receive_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, sizeof(optval)), NULL);
334
335 /*
336 * Bind to an ephemeral port
337 */
338 sin6.sin6_family = AF_INET6;
339 sin6.sin6_len = sizeof(struct sockaddr_in6);
340 T_ASSERT_POSIX_SUCCESS(bind(receive_fd, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6)), NULL);
341
342 solen = sizeof(struct sockaddr_in6);
343 T_ASSERT_POSIX_SUCCESS(getsockname(receive_fd, (struct sockaddr *)&sin6, &solen), NULL);
344
345 port = sin6.sin6_port;
346 T_LOG("receiver bound to port %u", ntohs(port));
347
348
349 /*
350 * Setup receiver bound to ifname2
351 */
352 T_ASSERT_POSIX_SUCCESS(sender_fd = socket(AF_INET6, SOCK_DGRAM, 0), NULL);
353
354 solen = strlen(ifname2);
355 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname2, solen), NULL);
356
357 optval = S_feth_pairs->list->two.if_index;
358 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &optval, sizeof(optval)), NULL);
359
360 optval = IPV6_DEFHLIM;
361 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &optval, sizeof(optval)), NULL);
362
363 optval = 1;
364 T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)), NULL);
365
366 /*
367 * Send unicast, broadcast and multicast a few times to allow for ND to do its job
368 */
369 for (int i = 0; i < 3; i++) {
370 str = "unicast";
371 sin6.sin6_family = AF_INET6;
372 sin6.sin6_len = sizeof(struct sockaddr_in6);
373 sin6.sin6_addr = S_feth_pairs->list->one.ip6;
374 sin6.sin6_port = port;
375 sin6.sin6_scope_id = S_feth_pairs->list->two.if_index;
376 T_ASSERT_POSIX_SUCCESS(retval = sendto(sender_fd, str, strlen(str) + 1, 0, (struct sockaddr *)&sin6, sin6.sin6_len), NULL);
377
378 str = "multicast";
379 sin6.sin6_family = AF_INET6;
380 sin6.sin6_len = sizeof(struct sockaddr_in6);
381 inet_pton(AF_INET6, IPV6_MULTICAST_ADDR_STR, &sin6.sin6_addr);
382 sin6.sin6_port = port;
383 T_ASSERT_POSIX_SUCCESS(retval = sendto(sender_fd, str, strlen(str) + 1, 0, (struct sockaddr *)&sin6, sin6.sin6_len), NULL);
384
385 usleep(50);
386 }
387
388 while (true) {
389 char control_space[CMSG_SPACE(8192)] = {};
390 struct msghdr recvmsghdr = {};
391 char packet_space[1500] = {};
392 struct cmsghdr *cmsg;
393 int addr_type = -1;
394 struct in6_pktinfo pktinfo = {};
395
396 struct iovec recv_iov;
397 recv_iov.iov_len = sizeof(packet_space);
398 recv_iov.iov_base = &packet_space;
399
400 recvmsghdr.msg_iov = &recv_iov;
401 recvmsghdr.msg_iovlen = 1;
402 recvmsghdr.msg_control = &control_space;
403 recvmsghdr.msg_controllen = sizeof(control_space);
404 recvmsghdr.msg_flags = 0;
405
406 retval = recvmsg(receive_fd, &recvmsghdr, 0);
407 if (retval < 0) {
408 break;
409 }
410
411 for (cmsg = CMSG_FIRSTHDR(&recvmsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&recvmsghdr, cmsg)) {
412 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
413 pktinfo = *(struct in6_pktinfo *)CMSG_DATA(cmsg);
414 }
415 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_RECV_LINK_ADDR_TYPE) {
416 addr_type = *(int *)CMSG_DATA(cmsg);
417 }
418 }
419 inet_ntop(AF_INET6, &pktinfo.ipi6_addr, addrstr, sizeof(addrstr));
420 T_LOG("received packet to: %s address type: %d", addrstr, addr_type);
421
422 if (IN6_IS_ADDR_MULTICAST(&pktinfo.ipi6_addr)) {
423 T_ASSERT_EQ(addr_type, IP_RECV_LINK_ADDR_MULTICAST, "multicast");
424 } else {
425 T_ASSERT_EQ(addr_type, IP_RECV_LINK_ADDR_UNICAST, "unicast");
426 }
427 }
428 }
429