xref: /xnu-11215/tests/net_test_lib.c (revision 8d741a5d)
1 /*
2  * Copyright (c) 2019-2024 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 #include "net_test_lib.h"
30 #include "inet_transfer.h"
31 #include "bpflib.h"
32 #include "in_cksum.h"
33 #include <net/if_fake_var.h>
34 #include <net/if_vlan_var.h>
35 #include <net/if_bridgevar.h>
36 
37 #define RTM_BUFLEN (sizeof(struct rt_msghdr) + 6 * SOCK_MAXADDRLEN)
38 
39 #define ROUNDUP(a) \
40 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
41 
42 bool G_debug;
43 
44 struct in_addr inet_class_c_subnet_mask = {
45 	.s_addr = htonl(IN_CLASSC_NET)
46 };
47 
48 ether_addr_t ether_broadcast = {
49 	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
50 };
51 
52 /*
53  * local utility functions
54  */
55 static void
siocll_start(int s,const char * ifname)56 siocll_start(int s, const char * ifname)
57 {
58 	struct in6_aliasreq     ifra_in6;
59 	int                     result;
60 
61 	bzero(&ifra_in6, sizeof(ifra_in6));
62 	strncpy(ifra_in6.ifra_name, ifname, sizeof(ifra_in6.ifra_name));
63 	result = ioctl(s, SIOCLL_START, &ifra_in6);
64 	T_QUIET;
65 	T_ASSERT_POSIX_SUCCESS(result, "SIOCLL_START %s", ifname);
66 	return;
67 }
68 
69 static void
nd_flags_set(int s,const char * if_name,uint32_t set_flags,uint32_t clear_flags)70 nd_flags_set(int s, const char * if_name,
71     uint32_t set_flags, uint32_t clear_flags)
72 {
73 	uint32_t                new_flags;
74 	struct in6_ndireq       nd;
75 	int                     result;
76 
77 	bzero(&nd, sizeof(nd));
78 	strncpy(nd.ifname, if_name, sizeof(nd.ifname));
79 	result = ioctl(s, SIOCGIFINFO_IN6, &nd);
80 	T_ASSERT_POSIX_SUCCESS(result, "SIOCGIFINFO_IN6(%s)", if_name);
81 	new_flags = nd.ndi.flags;
82 	if (set_flags) {
83 		new_flags |= set_flags;
84 	}
85 	if (clear_flags) {
86 		new_flags &= ~clear_flags;
87 	}
88 	if (new_flags != nd.ndi.flags) {
89 		nd.ndi.flags = new_flags;
90 		result = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
91 		T_ASSERT_POSIX_SUCCESS(result,
92 		    "SIOCSIFINFO_FLAGS(%s) 0x%x",
93 		    if_name, nd.ndi.flags);
94 	}
95 	return;
96 }
97 
98 
99 static void
siocprotoattach_in6(int s,const char * name)100 siocprotoattach_in6(int s, const char * name)
101 {
102 	struct in6_aliasreq ifra;
103 	int                 result;
104 
105 	bzero(&ifra, sizeof(ifra));
106 	strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
107 	result = ioctl(s, SIOCPROTOATTACH_IN6, &ifra);
108 	T_ASSERT_POSIX_SUCCESS(result, "SIOCPROTOATTACH_IN6(%s)", name);
109 	return;
110 }
111 
112 static void
siocaifaddr(int s,char * ifname,struct in_addr addr,struct in_addr mask)113 siocaifaddr(int s, char *ifname, struct in_addr addr, struct in_addr mask)
114 {
115 	struct ifaliasreq       ifra;
116 	char                    ntopbuf_ip[INET_ADDRSTRLEN];
117 	char                    ntopbuf_mask[INET_ADDRSTRLEN];
118 	int                     ret;
119 	struct sockaddr_in *    sin;
120 
121 	bzero(&ifra, sizeof(ifra));
122 	strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
123 
124 	sin = (struct sockaddr_in *)(void *)&ifra.ifra_addr;
125 	sin->sin_len = sizeof(*sin);
126 	sin->sin_family = AF_INET;
127 	sin->sin_addr = addr;
128 
129 	sin = (struct sockaddr_in *)(void *)&ifra.ifra_mask;
130 	sin->sin_len = sizeof(*sin);
131 	sin->sin_family = AF_INET;
132 	sin->sin_addr = mask;
133 
134 	ret = ioctl(s, SIOCAIFADDR, &ifra);
135 	inet_ntop(AF_INET, &addr, ntopbuf_ip, sizeof(ntopbuf_ip));
136 	inet_ntop(AF_INET, &sin->sin_addr, ntopbuf_mask, sizeof(ntopbuf_mask));
137 	T_ASSERT_POSIX_SUCCESS(ret, "SIOCAIFADDR %s %s %s",
138 	    ifname, ntopbuf_ip, ntopbuf_mask);
139 	return;
140 }
141 
142 
143 /*
144  * utility functions
145  */
146 
147 #define NO_SOCKET       (-1)
148 
149 static int
_dgram_socket_get(int * sock_p,int af)150 _dgram_socket_get(int * sock_p, int af)
151 {
152 	int     sock = *sock_p;
153 
154 	if (sock != NO_SOCKET) {
155 		goto done;
156 	}
157 	sock = *sock_p = socket(af, SOCK_DGRAM, 0);
158 	T_QUIET;
159 	T_ASSERT_POSIX_SUCCESS(sock,
160 	    "socket(SOCK_DGRAM, %s, 0)",
161 	    af == AF_INET ? "AF_INET" : "AF_INET6");
162 done:
163 	return sock;
164 }
165 
166 static void
_socket_close(int * sock_p)167 _socket_close(int * sock_p)
168 {
169 	int sock = *sock_p;
170 
171 	if (sock != NO_SOCKET) {
172 		close(sock);
173 		*sock_p = NO_SOCKET;
174 	}
175 }
176 
177 static int inet_dgram_socket = NO_SOCKET;
178 
179 int
inet_dgram_socket_get(void)180 inet_dgram_socket_get(void)
181 {
182 	return _dgram_socket_get(&inet_dgram_socket, AF_INET);
183 }
184 
185 void
inet_dgram_socket_close(void)186 inet_dgram_socket_close(void)
187 {
188 	_socket_close(&inet_dgram_socket);
189 }
190 
191 
192 static int inet6_dgram_socket = NO_SOCKET;
193 
194 int
inet6_dgram_socket_get(void)195 inet6_dgram_socket_get(void)
196 {
197 	return _dgram_socket_get(&inet6_dgram_socket, AF_INET6);
198 }
199 
200 void
inet6_dgram_socket_close(void)201 inet6_dgram_socket_close(void)
202 {
203 	_socket_close(&inet6_dgram_socket);
204 }
205 
206 u_int
ethernet_udp4_frame_populate(void * buf,size_t buf_len,const ether_addr_t * src,struct in_addr src_ip,uint16_t src_port,const ether_addr_t * dst,struct in_addr dst_ip,uint16_t dst_port,const void * data,u_int data_len)207 ethernet_udp4_frame_populate(void * buf, size_t buf_len,
208     const ether_addr_t * src,
209     struct in_addr src_ip,
210     uint16_t src_port,
211     const ether_addr_t * dst,
212     struct in_addr dst_ip,
213     uint16_t dst_port,
214     const void * data, u_int data_len)
215 {
216 	ether_header_t *        eh_p;
217 	u_int                   frame_length;
218 	static int              ip_id;
219 	ip_udp_header_t *       ip_udp;
220 	char *                  payload;
221 	udp_pseudo_hdr_t *      udp_pseudo;
222 
223 	frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)) + data_len;
224 	if (buf_len < frame_length) {
225 		return 0;
226 	}
227 
228 	/* determine frame offsets */
229 	eh_p = (ether_header_t *)buf;
230 	ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
231 	udp_pseudo = (udp_pseudo_hdr_t *)(void *)
232 	    (((char *)&ip_udp->udp) - sizeof(*udp_pseudo));
233 	payload = (char *)(eh_p + 1) + sizeof(*ip_udp);
234 
235 	/* ethernet_header */
236 	bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
237 	bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
238 	eh_p->ether_type = htons(ETHERTYPE_IP);
239 
240 	/* copy the data */
241 	bcopy(data, payload, data_len);
242 
243 	/* fill in UDP pseudo header (gets overwritten by IP header below) */
244 	bcopy(&src_ip, &udp_pseudo->src_ip, sizeof(src_ip));
245 	bcopy(&dst_ip, &udp_pseudo->dst_ip, sizeof(dst_ip));
246 	udp_pseudo->zero = 0;
247 	udp_pseudo->proto = IPPROTO_UDP;
248 	udp_pseudo->length = htons(sizeof(ip_udp->udp) + data_len);
249 
250 	/* fill in UDP header */
251 	ip_udp->udp.uh_sport = htons(src_port);
252 	ip_udp->udp.uh_dport = htons(dst_port);
253 	ip_udp->udp.uh_ulen = htons(sizeof(ip_udp->udp) + data_len);
254 	ip_udp->udp.uh_sum = 0;
255 	ip_udp->udp.uh_sum = in_cksum(udp_pseudo, (int)(sizeof(*udp_pseudo)
256 	    + sizeof(ip_udp->udp) + data_len));
257 
258 	/* fill in IP header */
259 	bzero(ip_udp, sizeof(ip_udp->ip));
260 	ip_udp->ip.ip_v = IPVERSION;
261 	ip_udp->ip.ip_hl = sizeof(struct ip) >> 2;
262 	ip_udp->ip.ip_ttl = MAXTTL;
263 	ip_udp->ip.ip_p = IPPROTO_UDP;
264 	bcopy(&src_ip, &ip_udp->ip.ip_src, sizeof(src_ip));
265 	bcopy(&dst_ip, &ip_udp->ip.ip_dst, sizeof(dst_ip));
266 	ip_udp->ip.ip_len = htons(sizeof(*ip_udp) + data_len);
267 	ip_udp->ip.ip_id = htons(ip_id++);
268 
269 	/* compute the IP checksum */
270 	ip_udp->ip.ip_sum = 0; /* needs to be zero for checksum */
271 	ip_udp->ip.ip_sum = in_cksum(&ip_udp->ip, sizeof(ip_udp->ip));
272 
273 	return frame_length;
274 }
275 
276 u_int
ethernet_udp6_frame_populate(void * buf,size_t buf_len,const ether_addr_t * src,struct in6_addr * src_ip,uint16_t src_port,const ether_addr_t * dst,struct in6_addr * dst_ip,uint16_t dst_port,const void * data,u_int data_len)277 ethernet_udp6_frame_populate(void * buf, size_t buf_len,
278     const ether_addr_t * src,
279     struct in6_addr *src_ip,
280     uint16_t src_port,
281     const ether_addr_t * dst,
282     struct in6_addr * dst_ip,
283     uint16_t dst_port,
284     const void * data, u_int data_len)
285 {
286 	ether_header_t *        eh_p;
287 	u_int                   frame_length;
288 	ip6_udp_header_t *      ip6_udp;
289 	char *                  payload;
290 	udp6_pseudo_hdr_t *     udp6_pseudo;
291 
292 	frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)) + data_len;
293 	if (buf_len < frame_length) {
294 		return 0;
295 	}
296 
297 	/* determine frame offsets */
298 	eh_p = (ether_header_t *)buf;
299 	ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
300 	udp6_pseudo = (udp6_pseudo_hdr_t *)(void *)
301 	    (((char *)&ip6_udp->udp) - sizeof(*udp6_pseudo));
302 	payload = (char *)(eh_p + 1) + sizeof(*ip6_udp);
303 
304 	/* ethernet_header */
305 	bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
306 	bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
307 	eh_p->ether_type = htons(ETHERTYPE_IPV6);
308 
309 	/* copy the data */
310 	bcopy(data, payload, data_len);
311 
312 	/* fill in UDP pseudo header (gets overwritten by IP header below) */
313 	bcopy(src_ip, &udp6_pseudo->src_ip, sizeof(*src_ip));
314 	bcopy(dst_ip, &udp6_pseudo->dst_ip, sizeof(*dst_ip));
315 	udp6_pseudo->zero = 0;
316 	udp6_pseudo->proto = IPPROTO_UDP;
317 	udp6_pseudo->length = htons(sizeof(ip6_udp->udp) + data_len);
318 
319 	/* fill in UDP header */
320 	ip6_udp->udp.uh_sport = htons(src_port);
321 	ip6_udp->udp.uh_dport = htons(dst_port);
322 	ip6_udp->udp.uh_ulen = htons(sizeof(ip6_udp->udp) + data_len);
323 	ip6_udp->udp.uh_sum = 0;
324 	ip6_udp->udp.uh_sum = in_cksum(udp6_pseudo, (int)(sizeof(*udp6_pseudo)
325 	    + sizeof(ip6_udp->udp) + data_len));
326 
327 	/* fill in IP header */
328 	bzero(&ip6_udp->ip6, sizeof(ip6_udp->ip6));
329 	ip6_udp->ip6.ip6_vfc = IPV6_VERSION;
330 	ip6_udp->ip6.ip6_nxt = IPPROTO_UDP;
331 	bcopy(src_ip, &ip6_udp->ip6.ip6_src, sizeof(*src_ip));
332 	bcopy(dst_ip, &ip6_udp->ip6.ip6_dst, sizeof(*dst_ip));
333 	ip6_udp->ip6.ip6_plen = htons(sizeof(struct udphdr) + data_len);
334 	/* ip6_udp->ip6.ip6_flow = ? */
335 	return frame_length;
336 }
337 
338 /**
339 ** interface management
340 **/
341 
342 void
ifnet_get_lladdr(const char * ifname,ether_addr_t * eaddr)343 ifnet_get_lladdr(const char * ifname, ether_addr_t * eaddr)
344 {
345 	int err;
346 	struct ifreq ifr;
347 	int s = inet_dgram_socket_get();
348 
349 	bzero(&ifr, sizeof(ifr));
350 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
351 	ifr.ifr_addr.sa_family = AF_LINK;
352 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
353 	err = ioctl(s, SIOCGIFLLADDR, &ifr);
354 	T_QUIET;
355 	T_ASSERT_POSIX_SUCCESS(err, "SIOCGIFLLADDR %s", ifname);
356 	bcopy(ifr.ifr_addr.sa_data, eaddr->octet, ETHER_ADDR_LEN);
357 	return;
358 }
359 
360 int
ifnet_set_lladdr(const char * ifname,ether_addr_t * eaddr)361 ifnet_set_lladdr(const char * ifname, ether_addr_t * eaddr)
362 {
363 	int err;
364 	int this_errno = 0;
365 	struct ifreq ifr;
366 	int s = inet_dgram_socket_get();
367 
368 	bzero(&ifr, sizeof(ifr));
369 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
370 	ifr.ifr_addr.sa_family = AF_LINK;
371 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
372 	bcopy(eaddr->octet, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
373 	err = ioctl(s, SIOCSIFLLADDR, &ifr);
374 	if (err != 0) {
375 		this_errno = errno;
376 		T_LOG("SIOCSIFLLADDR %s %s (%d)", ifname,
377 		    strerror(this_errno), this_errno);
378 	} else {
379 		T_LOG("SIOCSIFLLADDR %s success", ifname);
380 	}
381 	return err;
382 }
383 
384 
385 void
ifnet_attach_ip(char * name)386 ifnet_attach_ip(char * name)
387 {
388 	int             err;
389 	struct ifreq    ifr;
390 	int             s = inet_dgram_socket_get();
391 
392 	bzero(&ifr, sizeof(ifr));
393 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
394 	err = ioctl(s, SIOCPROTOATTACH, &ifr);
395 	T_QUIET;
396 	T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTOATTACH %s", ifr.ifr_name);
397 	return;
398 }
399 
400 void
ifnet_start_ipv6(const char * ifname)401 ifnet_start_ipv6(const char * ifname)
402 {
403 	int             s6 = inet6_dgram_socket_get();
404 
405 	/* attach IPv6 */
406 	siocprotoattach_in6(s6, ifname);
407 
408 	/* disable DAD to avoid 1 second delay (rdar://problem/73270401) */
409 	nd_flags_set(s6, ifname, 0, ND6_IFF_DAD);
410 
411 	/* start IPv6LL */
412 	siocll_start(s6, ifname);
413 
414 	return;
415 }
416 
417 int
ifnet_destroy(const char * ifname,bool fail_on_error)418 ifnet_destroy(const char * ifname, bool fail_on_error)
419 {
420 	int             err;
421 	struct ifreq    ifr;
422 	int             s = inet_dgram_socket_get();
423 
424 	bzero(&ifr, sizeof(ifr));
425 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
426 	err = ioctl(s, SIOCIFDESTROY, &ifr);
427 	if (fail_on_error) {
428 		T_QUIET;
429 		T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
430 	}
431 	if (err < 0) {
432 		T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
433 	}
434 	return err;
435 }
436 
437 int
ifnet_set_flags(const char * ifname,uint16_t flags_set,uint16_t flags_clear)438 ifnet_set_flags(const char * ifname, uint16_t flags_set, uint16_t flags_clear)
439 {
440 	uint16_t        flags_after;
441 	uint16_t        flags_before;
442 	struct ifreq    ifr;
443 	int             ret;
444 	int             s = inet_dgram_socket_get();
445 
446 	bzero(&ifr, sizeof(ifr));
447 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
448 	ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
449 	if (ret != 0) {
450 		T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
451 		return ret;
452 	}
453 	flags_before = (uint16_t)ifr.ifr_flags;
454 	ifr.ifr_flags |= flags_set;
455 	ifr.ifr_flags &= ~(flags_clear);
456 	flags_after = (uint16_t)ifr.ifr_flags;
457 	if (flags_before == flags_after) {
458 		/* nothing to do */
459 		ret = 0;
460 	} else {
461 		/* issue the ioctl */
462 		T_QUIET;
463 		T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
464 		    "SIOCSIFFLAGS %s 0x%x",
465 		    ifr.ifr_name, (uint16_t)ifr.ifr_flags);
466 		if (G_debug) {
467 			T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
468 			    ifr.ifr_name, flags_set, flags_clear,
469 			    flags_before, flags_after);
470 		}
471 	}
472 	return ret;
473 }
474 
475 /* On some platforms with DEBUG kernel, we need to wait a while */
476 #define SIFCREATE_RETRY 600
477 
478 static int
ifnet_create_common(const char * ifname,char * ifname_out,size_t ifname_out_len)479 ifnet_create_common(const char * ifname, char *ifname_out, size_t ifname_out_len)
480 {
481 	int             error = 0;
482 	struct ifreq    ifr;
483 	int             s = inet_dgram_socket_get();
484 
485 	bzero(&ifr, sizeof(ifr));
486 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
487 
488 	for (int i = 0; i < SIFCREATE_RETRY; i++) {
489 		if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
490 			error = errno;
491 			T_LOG("SIOCSIFCREATE %s: %s", ifname,
492 			    strerror(error));
493 			if (error == EBUSY) {
494 				/* interface is tearing down, try again */
495 				usleep(10000);
496 			} else if (error == EEXIST) {
497 				/* interface exists, try destroying it */
498 				(void)ifnet_destroy(ifname, false);
499 			} else {
500 				/* unexpected failure */
501 				break;
502 			}
503 		} else {
504 			if (ifname_out != NULL) {
505 				strlcpy(ifname_out, ifr.ifr_name, ifname_out_len);
506 			}
507 			error = 0;
508 			break;
509 		}
510 	}
511 	if (error == 0) {
512 		error = ifnet_set_flags(ifname, IFF_UP, 0);
513 	}
514 	return error;
515 }
516 
517 int
ifnet_create(const char * ifname)518 ifnet_create(const char * ifname)
519 {
520 	return ifnet_create_common(ifname, NULL, 0);
521 }
522 
523 int
ifnet_create_2(char * ifname,size_t len)524 ifnet_create_2(char * ifname, size_t len)
525 {
526 	return ifnet_create_common(ifname, ifname, len);
527 }
528 
529 void
ifnet_add_ip_address(char * ifname,struct in_addr addr,struct in_addr mask)530 ifnet_add_ip_address(char *ifname, struct in_addr addr, struct in_addr mask)
531 {
532 	int             s = inet_dgram_socket_get();
533 
534 	siocaifaddr(s, ifname, addr, mask);
535 }
536 
537 int
ifnet_set_mtu(const char * ifname,int mtu)538 ifnet_set_mtu(const char *ifname, int mtu)
539 {
540 	int error = 0;
541 	struct ifreq ifr = { 0 };
542 	int s = inet_dgram_socket_get();
543 
544 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
545 	ifr.ifr_mtu = mtu;
546 
547 	T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFMTU, (caddr_t)&ifr), "set MTU");
548 
549 	return error;
550 }
551 
552 int
siocdrvspec(const char * ifname,u_long op,void * arg,size_t argsize,bool set)553 siocdrvspec(const char * ifname, u_long op, void *arg, size_t argsize, bool set)
554 {
555 	struct ifdrv    ifd;
556 	int             s = inet_dgram_socket_get();
557 
558 	memset(&ifd, 0, sizeof(ifd));
559 	strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
560 	ifd.ifd_cmd = op;
561 	ifd.ifd_len = argsize;
562 	ifd.ifd_data = arg;
563 	return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
564 }
565 
566 void
fake_set_peer(const char * feth,const char * feth_peer)567 fake_set_peer(const char * feth, const char * feth_peer)
568 {
569 	struct if_fake_request  iffr;
570 	int                     ret;
571 
572 	bzero((char *)&iffr, sizeof(iffr));
573 	if (feth_peer != NULL) {
574 		strlcpy(iffr.iffr_peer_name, feth_peer,
575 		    sizeof(iffr.iffr_peer_name));
576 	}
577 	ret = siocdrvspec(feth, IF_FAKE_S_CMD_SET_PEER,
578 	    &iffr, sizeof(iffr), true);
579 	T_QUIET;
580 	T_ASSERT_POSIX_SUCCESS(ret,
581 	    "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
582 	    feth, (feth_peer != NULL) ? feth_peer : "<none>");
583 	T_LOG("%s peer %s\n", feth, feth_peer);
584 	return;
585 }
586 
587 void
siocsifvlan(const char * vlan,const char * phys,uint16_t tag)588 siocsifvlan(const char * vlan, const char * phys, uint16_t tag)
589 {
590 	int             result;
591 	struct ifreq    ifr;
592 	int             s = inet_dgram_socket_get();
593 	struct vlanreq  vlr;
594 
595 	bzero(&ifr, sizeof(ifr));
596 	strlcpy(ifr.ifr_name, vlan, sizeof(ifr.ifr_name));
597 	ifr.ifr_data = (caddr_t)&vlr;
598 	strlcpy(vlr.vlr_parent, phys, sizeof(vlr.vlr_parent));
599 	vlr.vlr_tag = tag;
600 	result = ioctl(s, SIOCSIFVLAN, &ifr);
601 	T_ASSERT_POSIX_SUCCESS(result, "SIOCSIFVLAN(%s) %s %d",
602 	    vlan, phys, tag);
603 }
604 
605 u_int
make_dhcp_payload(dhcp_min_payload_t payload,ether_addr_t * eaddr)606 make_dhcp_payload(dhcp_min_payload_t payload, ether_addr_t *eaddr)
607 {
608 	struct bootp *  dhcp;
609 	u_int           payload_length;
610 
611 	/* create a minimal BOOTP packet */
612 	payload_length = sizeof(*payload);
613 	dhcp = (struct bootp *)payload;
614 	bzero(dhcp, payload_length);
615 	dhcp->bp_op = BOOTREQUEST;
616 	dhcp->bp_htype = ARPHRD_ETHER;
617 	dhcp->bp_hlen = sizeof(*eaddr);
618 	bcopy(eaddr->octet, dhcp->bp_chaddr, sizeof(eaddr->octet));
619 	return payload_length;
620 }
621 
622 
623 
624 /*
625  * routing table
626  */
627 
628 /*
629  * Stolen/modified from IPMonitor/ip_plugin.c
630  */
631 /*
632  * Define: ROUTE_MSG_ADDRS_SPACE
633  * Purpose:
634  *   Since sizeof(sockaddr_dl) > sizeof(sockaddr_in), we need space for
635  *   3 sockaddr_in's and 2 sockaddr_dl's, but pad it just in case
636  *   someone changes the code and doesn't think to modify this.
637  */
638 #define ROUTE_MSG_ADDRS_SPACE   (3 * sizeof(struct sockaddr_in) \
639 	                         + 2 * sizeof(struct sockaddr_dl) \
640 	                         + 128)
641 typedef struct {
642 	struct rt_msghdr    hdr;
643 	char                addrs[ROUTE_MSG_ADDRS_SPACE];
644 } route_msg;
645 
646 typedef unsigned short  IFIndex;
647 
648 typedef enum {
649 	kRouteFlagsIsScoped         = 0x0001,
650 	kRouteFlagsHasGateway       = 0x0002,
651 	kRouteFlagsIsHost           = 0x0004,
652 } RouteFlags;
653 
654 typedef struct {
655 	IFIndex         ifindex;
656 	RouteFlags      flags;
657 	struct in_addr  dest;
658 	struct in_addr  mask;
659 	struct in_addr  gateway;
660 	struct in_addr  ifa;
661 } IPv4Route, * IPv4RouteRef;
662 
663 /*
664  * Function: IPv4RouteApply
665  * Purpose:
666  *   Add or remove the specified route to/from the kernel routing table.
667  */
668 static int
IPv4RouteApply(IPv4RouteRef route,uint8_t cmd,int s)669 IPv4RouteApply(IPv4RouteRef route, uint8_t cmd, int s)
670 {
671 	size_t          len;
672 	int             ret = 0;
673 	route_msg       rtmsg;
674 	union {
675 		struct sockaddr_in *    in_p;
676 		struct sockaddr_dl *    dl_p;
677 		char *                  ptr;
678 	} rtaddr;
679 	static int      rtm_seq;
680 	static bool     rtm_seq_inited;
681 
682 	if (!rtm_seq_inited) {
683 		rtm_seq_inited = true;
684 		rtm_seq = (int)arc4random();
685 	}
686 	if (route->ifindex == 0) {
687 		T_LOG("no interface specified, ignoring %s",
688 		    inet_ntoa(route->dest));
689 		return ENXIO;
690 	}
691 	if (s < 0) {
692 		T_LOG("invalid routing socket");
693 		return EBADF;
694 	}
695 	memset(&rtmsg, 0, sizeof(rtmsg));
696 	rtmsg.hdr.rtm_type = cmd;
697 	rtmsg.hdr.rtm_version = RTM_VERSION;
698 	rtmsg.hdr.rtm_seq = rtm_seq++;
699 	rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP;
700 	if (route->ifa.s_addr != 0) {
701 		rtmsg.hdr.rtm_addrs |= RTA_IFA;
702 	}
703 	rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
704 	if ((route->flags & kRouteFlagsIsHost) != 0) {
705 		rtmsg.hdr.rtm_flags |= RTF_HOST;
706 	} else {
707 		rtmsg.hdr.rtm_addrs |= RTA_NETMASK;
708 		if ((route->flags & kRouteFlagsHasGateway) == 0) {
709 			rtmsg.hdr.rtm_flags |= RTF_CLONING;
710 		}
711 	}
712 	if ((route->flags & kRouteFlagsHasGateway) != 0) {
713 		rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
714 	}
715 	if ((route->flags & kRouteFlagsIsScoped) != 0) {
716 		rtmsg.hdr.rtm_index = route->ifindex;
717 		rtmsg.hdr.rtm_flags |= RTF_IFSCOPE;
718 	}
719 
720 	rtaddr.ptr = rtmsg.addrs;
721 
722 	/* dest */
723 	rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
724 	rtaddr.in_p->sin_family = AF_INET;
725 	rtaddr.in_p->sin_addr = route->dest;
726 	rtaddr.ptr += sizeof(*rtaddr.in_p);
727 
728 	/* gateway */
729 	if ((rtmsg.hdr.rtm_flags & RTF_GATEWAY) != 0) {
730 		/* gateway is an IP address */
731 		rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
732 		rtaddr.in_p->sin_family = AF_INET;
733 		rtaddr.in_p->sin_addr = route->gateway;
734 		rtaddr.ptr += sizeof(*rtaddr.in_p);
735 	} else {
736 		/* gateway is the interface itself */
737 		rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
738 		rtaddr.dl_p->sdl_family = AF_LINK;
739 		rtaddr.dl_p->sdl_index = route->ifindex;
740 		rtaddr.ptr += sizeof(*rtaddr.dl_p);
741 	}
742 
743 	/* mask */
744 	if ((rtmsg.hdr.rtm_addrs & RTA_NETMASK) != 0) {
745 		rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
746 		rtaddr.in_p->sin_family = AF_INET;
747 		rtaddr.in_p->sin_addr = route->mask;
748 		rtaddr.ptr += sizeof(*rtaddr.in_p);
749 	}
750 
751 	/* interface */
752 	if ((rtmsg.hdr.rtm_addrs & RTA_IFP) != 0) {
753 		rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
754 		rtaddr.dl_p->sdl_family = AF_LINK;
755 		rtaddr.dl_p->sdl_index = route->ifindex;
756 		rtaddr.ptr += sizeof(*rtaddr.dl_p);
757 	}
758 	/* interface address */
759 	if ((rtmsg.hdr.rtm_addrs & RTA_IFA) != 0) {
760 		rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
761 		rtaddr.in_p->sin_family = AF_INET;
762 		rtaddr.in_p->sin_addr = route->ifa;
763 		rtaddr.ptr += sizeof(*rtaddr.in_p);
764 	}
765 
766 	/* apply the route */
767 	len = (sizeof(rtmsg.hdr)
768 	    + (unsigned long)(rtaddr.ptr - (char *)rtmsg.addrs));
769 	rtmsg.hdr.rtm_msglen = (u_short)len;
770 	if (write(s, &rtmsg, len) == -1) {
771 		ret = errno;
772 		T_LOG("write routing socket failed, (%d) %s",
773 		    errno, strerror(errno));
774 	}
775 	return ret;
776 }
777 
778 static int routing_socket = -1;
779 
780 static int
routing_socket_get(void)781 routing_socket_get(void)
782 {
783 	if (routing_socket != NO_SOCKET) {
784 		goto done;
785 	}
786 	routing_socket = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE);
787 	T_QUIET;
788 	T_ASSERT_POSIX_SUCCESS(routing_socket,
789 	    "socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)");
790 done:
791 	return routing_socket;
792 }
793 
794 void
route_add_inet_scoped_subnet(char * ifname,u_short if_index,struct in_addr ifa,struct in_addr mask)795 route_add_inet_scoped_subnet(char * ifname, u_short if_index,
796     struct in_addr ifa, struct in_addr mask)
797 {
798 	int             error;
799 	IPv4Route       route;
800 	int             rs = routing_socket_get();
801 
802 	bzero(&route, sizeof(route));
803 	route.flags |= kRouteFlagsIsScoped;
804 	route.ifa = ifa;
805 	route.ifindex = if_index;
806 	route.mask = mask;
807 	route.dest.s_addr = route.ifa.s_addr & route.mask.s_addr;
808 	T_QUIET;
809 	T_ASSERT_NE((int)route.ifindex, 0, "if_nametoindex(%s)", ifname);
810 	error = IPv4RouteApply(&route, RTM_ADD, rs);
811 	T_ASSERT_EQ(error, 0, "add scoped subnet route %s %s/24", ifname,
812 	    inet_ntoa(route.dest));
813 	return;
814 }
815 
816 /**
817 ** network_interface
818 **/
819 
820 void
network_interface_create(network_interface_t if_p,const if_name_t name)821 network_interface_create(network_interface_t if_p, const if_name_t name)
822 {
823 	int             error;
824 	size_t          len = sizeof(if_p->if_name);
825 
826 	strlcpy(if_p->if_name, name, len);
827 	error = ifnet_create_2(if_p->if_name, len);
828 	T_ASSERT_POSIX_SUCCESS(error, "ifnet_create_2 %s", if_p->if_name);
829 
830 	if_p->if_index = (u_short)if_nametoindex(if_p->if_name);
831 	T_QUIET;
832 	T_ASSERT_TRUE(if_p->if_index != 0, NULL);
833 	T_LOG("%s: created %s index %d\n",
834 	    __func__, if_p->if_name, if_p->if_index);
835 }
836 
837 void
network_interface_destroy(network_interface_t if_p)838 network_interface_destroy(network_interface_t if_p)
839 {
840 	if (if_p->if_index != 0) {
841 		ifnet_destroy(if_p->if_name, false);
842 		T_LOG("%s: destroyed %s\n", __func__, if_p->if_name);
843 	}
844 }
845 
846 static inline size_t
network_interface_pair_list_size(size_t count)847 network_interface_pair_list_size(size_t count)
848 {
849 	return offsetof(network_interface_pair_list, list[count]);
850 }
851 
852 network_interface_pair_list_t
network_interface_pair_list_alloc(u_int n)853 network_interface_pair_list_alloc(u_int n)
854 {
855 	network_interface_pair_list_t   list;
856 
857 	list = (network_interface_pair_list_t)
858 	    calloc(1, network_interface_pair_list_size(n));
859 	list->count = n;
860 	return list;
861 }
862 
863 void
network_interface_pair_list_destroy(network_interface_pair_list_t list)864 network_interface_pair_list_destroy(network_interface_pair_list_t list)
865 {
866 	network_interface_pair_t        scan;
867 
868 	if (list == NULL) {
869 		return;
870 	}
871 	scan = list->list;
872 	for (size_t i = 0; i < list->count; i++, scan++) {
873 		network_interface_destroy(&scan->one);
874 		network_interface_destroy(&scan->two);
875 	}
876 }
877 
878 bool
has_ipv4_default_route(void)879 has_ipv4_default_route(void)
880 {
881 	bool result = false;
882 	struct rt_msghdr *rtm = NULL;
883 	struct sockaddr_in sin = { 0 };
884 
885 	sin.sin_len = sizeof(struct sockaddr_in);
886 	sin.sin_family = AF_INET;
887 	sin.sin_addr.s_addr = INADDR_ANY;
888 
889 	T_QUIET; T_ASSERT_NOTNULL(rtm = (struct rt_msghdr *)calloc(1, RTM_BUFLEN), NULL);
890 
891 	rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
892 	rtm->rtm_version = RTM_VERSION;
893 	rtm->rtm_type = RTM_GET;
894 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY | RTF_HOST;
895 	rtm->rtm_addrs = RTA_DST;
896 	rtm->rtm_pid = getpid();
897 	rtm->rtm_seq = 1;
898 
899 	uint8_t *cp = (unsigned char *)(rtm + 1);
900 
901 	bcopy(&sin, cp, sin.sin_len);
902 	cp += ROUNDUP(sin.sin_len);
903 
904 	u_short len = (u_short)(cp - (uint8_t *)rtm);
905 
906 	rtm->rtm_msglen = len;
907 
908 	int fd;
909 	T_QUIET; T_ASSERT_POSIX_SUCCESS(fd = socket(PF_ROUTE, SOCK_RAW, 0), NULL);
910 
911 	ssize_t sent = send(fd, rtm, len, 0);
912 	if (sent == len) {
913 		result = true;
914 	} else {
915 		result = false;
916 	}
917 
918 	(void) close(fd);
919 	free(rtm);
920 
921 	return result;
922 }
923 
924 bool
has_ipv6_default_route(void)925 has_ipv6_default_route(void)
926 {
927 	bool result = false;
928 	struct rt_msghdr *rtm = NULL;
929 	struct sockaddr_in6 sin6 = { 0 };
930 
931 	sin6.sin6_len = sizeof(struct sockaddr_in6);
932 	sin6.sin6_family = AF_INET6;
933 
934 	T_QUIET; T_ASSERT_NOTNULL(rtm = (struct rt_msghdr *)calloc(1, RTM_BUFLEN), NULL);
935 
936 	rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
937 	rtm->rtm_version = RTM_VERSION;
938 	rtm->rtm_type = RTM_GET;
939 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY | RTF_HOST;
940 	rtm->rtm_addrs = RTA_DST;
941 	rtm->rtm_pid = getpid();
942 	rtm->rtm_seq = 1;
943 
944 	uint8_t *cp = (unsigned char *)(rtm + 1);
945 
946 	bcopy(&sin6, cp, sin6.sin6_len);
947 	cp += ROUNDUP(sin6.sin6_len);
948 
949 	u_short len = (u_short)(cp - (uint8_t *)rtm);
950 
951 	rtm->rtm_msglen = len;
952 
953 	int fd;
954 	T_QUIET; T_ASSERT_POSIX_SUCCESS(fd = socket(PF_ROUTE, SOCK_RAW, 0), NULL);
955 
956 	ssize_t sent = send(fd, rtm, len, 0);
957 	if (sent == len) {
958 		result = true;
959 	} else {
960 		result = false;
961 	}
962 
963 	(void) close(fd);
964 	free(rtm);
965 
966 	return result;
967 }
968 
969 /*
970  * Bridge management
971  */
972 int
bridge_add_member(const char * bridge,const char * member)973 bridge_add_member(const char * bridge, const char * member)
974 {
975 	struct ifbreq           req;
976 	int                     ret;
977 
978 	memset(&req, 0, sizeof(req));
979 	strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
980 	ret = siocdrvspec(bridge, BRDGADD, &req, sizeof(req), true);
981 	T_QUIET;
982 	T_ASSERT_POSIX_SUCCESS(ret, "%s %s %s", __func__, bridge, member);
983 	return ret;
984 }
985