xref: /xnu-10063.141.1/tests/net_test_lib.c (revision d8b80295118ef25ac3a784134bcf95cd8e88109f)
1 /*
2  * Copyright (c) 2019-2023 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 
34 bool S_debug;
35 
36 int
inet_dgram_socket(void)37 inet_dgram_socket(void)
38 {
39 	int     s;
40 
41 	s = socket(AF_INET, SOCK_DGRAM, 0);
42 	T_QUIET;
43 	T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET, SOCK_DGRAM, 0)");
44 	return s;
45 }
46 
47 int
inet6_dgram_socket(void)48 inet6_dgram_socket(void)
49 {
50 	int     s;
51 
52 	s = socket(AF_INET6, SOCK_DGRAM, 0);
53 	T_QUIET;
54 	T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET6, SOCK_DGRAM, 0)");
55 	return s;
56 }
57 
58 int
routing_socket(void)59 routing_socket(void)
60 {
61 	int     s;
62 
63 	s = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE);
64 	T_QUIET;
65 	T_ASSERT_POSIX_SUCCESS(s, "socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)");
66 	return s;
67 }
68 
69 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)70 ethernet_udp4_frame_populate(void * buf, size_t buf_len,
71     const ether_addr_t * src,
72     struct in_addr src_ip,
73     uint16_t src_port,
74     const ether_addr_t * dst,
75     struct in_addr dst_ip,
76     uint16_t dst_port,
77     const void * data, u_int data_len)
78 {
79 	ether_header_t *        eh_p;
80 	u_int                   frame_length;
81 	static int              ip_id;
82 	ip_udp_header_t *       ip_udp;
83 	char *                  payload;
84 	udp_pseudo_hdr_t *      udp_pseudo;
85 
86 	frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)) + data_len;
87 	if (buf_len < frame_length) {
88 		return 0;
89 	}
90 
91 	/* determine frame offsets */
92 	eh_p = (ether_header_t *)buf;
93 	ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
94 	udp_pseudo = (udp_pseudo_hdr_t *)(void *)
95 	    (((char *)&ip_udp->udp) - sizeof(*udp_pseudo));
96 	payload = (char *)(eh_p + 1) + sizeof(*ip_udp);
97 
98 	/* ethernet_header */
99 	bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
100 	bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
101 	eh_p->ether_type = htons(ETHERTYPE_IP);
102 
103 	/* copy the data */
104 	bcopy(data, payload, data_len);
105 
106 	/* fill in UDP pseudo header (gets overwritten by IP header below) */
107 	bcopy(&src_ip, &udp_pseudo->src_ip, sizeof(src_ip));
108 	bcopy(&dst_ip, &udp_pseudo->dst_ip, sizeof(dst_ip));
109 	udp_pseudo->zero = 0;
110 	udp_pseudo->proto = IPPROTO_UDP;
111 	udp_pseudo->length = htons(sizeof(ip_udp->udp) + data_len);
112 
113 	/* fill in UDP header */
114 	ip_udp->udp.uh_sport = htons(src_port);
115 	ip_udp->udp.uh_dport = htons(dst_port);
116 	ip_udp->udp.uh_ulen = htons(sizeof(ip_udp->udp) + data_len);
117 	ip_udp->udp.uh_sum = 0;
118 	ip_udp->udp.uh_sum = in_cksum(udp_pseudo, (int)(sizeof(*udp_pseudo)
119 	    + sizeof(ip_udp->udp) + data_len));
120 
121 	/* fill in IP header */
122 	bzero(ip_udp, sizeof(ip_udp->ip));
123 	ip_udp->ip.ip_v = IPVERSION;
124 	ip_udp->ip.ip_hl = sizeof(struct ip) >> 2;
125 	ip_udp->ip.ip_ttl = MAXTTL;
126 	ip_udp->ip.ip_p = IPPROTO_UDP;
127 	bcopy(&src_ip, &ip_udp->ip.ip_src, sizeof(src_ip));
128 	bcopy(&dst_ip, &ip_udp->ip.ip_dst, sizeof(dst_ip));
129 	ip_udp->ip.ip_len = htons(sizeof(*ip_udp) + data_len);
130 	ip_udp->ip.ip_id = htons(ip_id++);
131 
132 	/* compute the IP checksum */
133 	ip_udp->ip.ip_sum = 0; /* needs to be zero for checksum */
134 	ip_udp->ip.ip_sum = in_cksum(&ip_udp->ip, sizeof(ip_udp->ip));
135 
136 	return frame_length;
137 }
138 
139 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)140 ethernet_udp6_frame_populate(void * buf, size_t buf_len,
141     const ether_addr_t * src,
142     struct in6_addr *src_ip,
143     uint16_t src_port,
144     const ether_addr_t * dst,
145     struct in6_addr * dst_ip,
146     uint16_t dst_port,
147     const void * data, u_int data_len)
148 {
149 	ether_header_t *        eh_p;
150 	u_int                   frame_length;
151 	ip6_udp_header_t *      ip6_udp;
152 	char *                  payload;
153 	udp6_pseudo_hdr_t *     udp6_pseudo;
154 
155 	frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)) + data_len;
156 	if (buf_len < frame_length) {
157 		return 0;
158 	}
159 
160 	/* determine frame offsets */
161 	eh_p = (ether_header_t *)buf;
162 	ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
163 	udp6_pseudo = (udp6_pseudo_hdr_t *)(void *)
164 	    (((char *)&ip6_udp->udp) - sizeof(*udp6_pseudo));
165 	payload = (char *)(eh_p + 1) + sizeof(*ip6_udp);
166 
167 	/* ethernet_header */
168 	bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
169 	bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
170 	eh_p->ether_type = htons(ETHERTYPE_IPV6);
171 
172 	/* copy the data */
173 	bcopy(data, payload, data_len);
174 
175 	/* fill in UDP pseudo header (gets overwritten by IP header below) */
176 	bcopy(src_ip, &udp6_pseudo->src_ip, sizeof(*src_ip));
177 	bcopy(dst_ip, &udp6_pseudo->dst_ip, sizeof(*dst_ip));
178 	udp6_pseudo->zero = 0;
179 	udp6_pseudo->proto = IPPROTO_UDP;
180 	udp6_pseudo->length = htons(sizeof(ip6_udp->udp) + data_len);
181 
182 	/* fill in UDP header */
183 	ip6_udp->udp.uh_sport = htons(src_port);
184 	ip6_udp->udp.uh_dport = htons(dst_port);
185 	ip6_udp->udp.uh_ulen = htons(sizeof(ip6_udp->udp) + data_len);
186 	ip6_udp->udp.uh_sum = 0;
187 	ip6_udp->udp.uh_sum = in_cksum(udp6_pseudo, (int)(sizeof(*udp6_pseudo)
188 	    + sizeof(ip6_udp->udp) + data_len));
189 
190 	/* fill in IP header */
191 	bzero(&ip6_udp->ip6, sizeof(ip6_udp->ip6));
192 	ip6_udp->ip6.ip6_vfc = IPV6_VERSION;
193 	ip6_udp->ip6.ip6_nxt = IPPROTO_UDP;
194 	bcopy(src_ip, &ip6_udp->ip6.ip6_src, sizeof(*src_ip));
195 	bcopy(dst_ip, &ip6_udp->ip6.ip6_dst, sizeof(*dst_ip));
196 	ip6_udp->ip6.ip6_plen = htons(sizeof(struct udphdr) + data_len);
197 	/* ip6_udp->ip6.ip6_flow = ? */
198 	return frame_length;
199 }
200 
201 /**
202 ** interface management
203 **/
204 
205 void
ifnet_get_lladdr(int s,const char * ifname,ether_addr_t * eaddr)206 ifnet_get_lladdr(int s, const char * ifname, ether_addr_t * eaddr)
207 {
208 	int err;
209 	struct ifreq ifr;
210 
211 	bzero(&ifr, sizeof(ifr));
212 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
213 	ifr.ifr_addr.sa_family = AF_LINK;
214 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
215 	err = ioctl(s, SIOCGIFLLADDR, &ifr);
216 	T_QUIET;
217 	T_ASSERT_POSIX_SUCCESS(err, "SIOCGIFLLADDR %s", ifname);
218 	bcopy(ifr.ifr_addr.sa_data, eaddr->octet, ETHER_ADDR_LEN);
219 	return;
220 }
221 
222 
223 int
ifnet_attach_ip(int s,char * name)224 ifnet_attach_ip(int s, char * name)
225 {
226 	int                     err;
227 	struct ifreq    ifr;
228 
229 	bzero(&ifr, sizeof(ifr));
230 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
231 	err = ioctl(s, SIOCPROTOATTACH, &ifr);
232 	T_QUIET;
233 	T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTOATTACH %s", ifr.ifr_name);
234 	return err;
235 }
236 
237 int
ifnet_destroy(int s,const char * ifname,bool fail_on_error)238 ifnet_destroy(int s, const char * ifname, bool fail_on_error)
239 {
240 	int             err;
241 	struct ifreq    ifr;
242 
243 	bzero(&ifr, sizeof(ifr));
244 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
245 	err = ioctl(s, SIOCIFDESTROY, &ifr);
246 	if (fail_on_error) {
247 		T_QUIET;
248 		T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
249 	}
250 	if (err < 0) {
251 		T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
252 	}
253 	return err;
254 }
255 
256 int
ifnet_set_flags(int s,const char * ifname,uint16_t flags_set,uint16_t flags_clear)257 ifnet_set_flags(int s, const char * ifname,
258     uint16_t flags_set, uint16_t flags_clear)
259 {
260 	uint16_t        flags_after;
261 	uint16_t        flags_before;
262 	struct ifreq    ifr;
263 	int             ret;
264 
265 	bzero(&ifr, sizeof(ifr));
266 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
267 	ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
268 	if (ret != 0) {
269 		T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
270 		return ret;
271 	}
272 	flags_before = (uint16_t)ifr.ifr_flags;
273 	ifr.ifr_flags |= flags_set;
274 	ifr.ifr_flags &= ~(flags_clear);
275 	flags_after = (uint16_t)ifr.ifr_flags;
276 	if (flags_before == flags_after) {
277 		/* nothing to do */
278 		ret = 0;
279 	} else {
280 		/* issue the ioctl */
281 		T_QUIET;
282 		T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
283 		    "SIOCSIFFLAGS %s 0x%x",
284 		    ifr.ifr_name, (uint16_t)ifr.ifr_flags);
285 		if (S_debug) {
286 			T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
287 			    ifr.ifr_name, flags_set, flags_clear,
288 			    flags_before, flags_after);
289 		}
290 	}
291 	return ret;
292 }
293 
294 #define FETH_NAME       "feth"
295 
296 /* On some platforms with DEBUG kernel, we need to wait a while */
297 #define SIFCREATE_RETRY 600
298 
299 static int
ifnet_create_common(int s,const char * ifname,char * ifname_out,size_t ifname_out_len)300 ifnet_create_common(int s, const char * ifname, char *ifname_out, size_t ifname_out_len)
301 {
302 	int             error = 0;
303 	struct ifreq    ifr;
304 
305 	bzero(&ifr, sizeof(ifr));
306 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
307 
308 	for (int i = 0; i < SIFCREATE_RETRY; i++) {
309 		if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
310 			error = errno;
311 			T_LOG("SIOCSIFCREATE %s: %s", ifname,
312 			    strerror(error));
313 			if (error == EBUSY) {
314 				/* interface is tearing down, try again */
315 				usleep(10000);
316 			} else if (error == EEXIST) {
317 				/* interface exists, try destroying it */
318 				(void)ifnet_destroy(s, ifname, false);
319 			} else {
320 				/* unexpected failure */
321 				break;
322 			}
323 		} else {
324 			if (ifname_out != NULL) {
325 				strlcpy(ifname_out, ifr.ifr_name, ifname_out_len);
326 			}
327 			error = 0;
328 			break;
329 		}
330 	}
331 	if (error == 0) {
332 		error = ifnet_set_flags(s, ifname, IFF_UP, 0);
333 	}
334 	return error;
335 }
336 
337 int
ifnet_create(int s,const char * ifname)338 ifnet_create(int s, const char * ifname)
339 {
340 	return ifnet_create_common(s, ifname, NULL, 0);
341 }
342 
343 int
ifnet_create_2(int s,char * ifname,size_t len)344 ifnet_create_2(int s, char * ifname, size_t len)
345 {
346 	return ifnet_create_common(s, ifname, ifname, len);
347 }
348 
349 int
siocdrvspec(int s,const char * ifname,u_long op,void * arg,size_t argsize,bool set)350 siocdrvspec(int s, const char * ifname,
351     u_long op, void *arg, size_t argsize, bool set)
352 {
353 	struct ifdrv    ifd;
354 
355 	memset(&ifd, 0, sizeof(ifd));
356 	strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
357 	ifd.ifd_cmd = op;
358 	ifd.ifd_len = argsize;
359 	ifd.ifd_data = arg;
360 	return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
361 }
362 
363 int
fake_set_peer(int s,const char * feth,const char * feth_peer)364 fake_set_peer(int s, const char * feth, const char * feth_peer)
365 {
366 	struct if_fake_request  iffr;
367 	int                     ret;
368 
369 	bzero((char *)&iffr, sizeof(iffr));
370 	if (feth_peer != NULL) {
371 		strlcpy(iffr.iffr_peer_name, feth_peer,
372 		    sizeof(iffr.iffr_peer_name));
373 	}
374 	ret = siocdrvspec(s, feth, IF_FAKE_S_CMD_SET_PEER,
375 	    &iffr, sizeof(iffr), true);
376 	T_QUIET;
377 	T_ASSERT_POSIX_SUCCESS(ret,
378 	    "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
379 	    feth, (feth_peer != NULL) ? feth_peer : "<none>");
380 	return ret;
381 }
382 
383 u_int
make_dhcp_payload(dhcp_min_payload_t payload,ether_addr_t * eaddr)384 make_dhcp_payload(dhcp_min_payload_t payload, ether_addr_t *eaddr)
385 {
386 	struct bootp *  dhcp;
387 	u_int           payload_length;
388 
389 	/* create a minimal BOOTP packet */
390 	payload_length = sizeof(*payload);
391 	dhcp = (struct bootp *)payload;
392 	bzero(dhcp, payload_length);
393 	dhcp->bp_op = BOOTREQUEST;
394 	dhcp->bp_htype = ARPHRD_ETHER;
395 	dhcp->bp_hlen = sizeof(*eaddr);
396 	bcopy(eaddr->octet, dhcp->bp_chaddr, sizeof(eaddr->octet));
397 	return payload_length;
398 }
399