xref: /xnu-12377.81.4/tests/recv_link_addr_type.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796) !
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