xref: /freebsd/tests/sys/net/routing/rtsock_common.h (revision 2f513db7)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Alexander V. Chernikov
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #ifndef _NET_ROUTING_RTSOCK_COMMON_H_
31 #define _NET_ROUTING_RTSOCK_COMMON_H_
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <stdbool.h>
39 #include <ctype.h>
40 #include <poll.h>
41 
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <net/if.h>
48 #include <net/if_dl.h>
49 #include <net/route.h>
50 
51 #include <arpa/inet.h>
52 #include <net/ethernet.h>
53 
54 #include <netinet/in.h>
55 #include <netinet6/in6_var.h>
56 #include <netinet6/nd6.h>
57 
58 #include <ifaddrs.h>
59 
60 #include <errno.h>
61 #include <err.h>
62 #include <sysexits.h>
63 
64 #include <atf-c.h>
65 
66 #include "rtsock_print.h"
67 
68 void rtsock_update_rtm_len(struct rt_msghdr *rtm);
69 void rtsock_validate_message(char *buffer, ssize_t len);
70 void rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa);
71 
72 static int _rtm_seq = 42;
73 
74 
75 /*
76  * Checks if the interface cloner module is present for @name.
77  */
78 static int
79 _check_cloner(char *name)
80 {
81 	struct if_clonereq ifcr;
82 	char *cp, *buf;
83 	int idx;
84 	int s;
85 	int found = 0;
86 
87 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
88 	if (s == -1)
89 		err(1, "socket(AF_LOCAL,SOCK_DGRAM)");
90 
91 	memset(&ifcr, 0, sizeof(ifcr));
92 
93 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
94 		err(1, "SIOCIFGCLONERS for count");
95 
96 	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
97 	if (buf == NULL)
98 		err(1, "unable to allocate cloner name buffer");
99 
100 	ifcr.ifcr_count = ifcr.ifcr_total;
101 	ifcr.ifcr_buffer = buf;
102 
103 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
104 		err(1, "SIOCIFGCLONERS for names");
105 
106 	/*
107 	 * In case some disappeared in the mean time, clamp it down.
108 	 */
109 	if (ifcr.ifcr_count > ifcr.ifcr_total)
110 		ifcr.ifcr_count = ifcr.ifcr_total;
111 
112 	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
113 		if (!strcmp(cp, name)) {
114 			found = 1;
115 			break;
116 		}
117 	}
118 
119 	free(buf);
120 	close(s);
121 
122 	return (found);
123 }
124 
125 /*
126  * Tries to ensure if_tap is loaded.
127  * Checks list of interface cloners first, then tries
128  * to load the module.
129  *
130  * return nonzero on success.
131  */
132 static int
133 _enforce_cloner_loaded(char *cloner_name)
134 {
135 	if (_check_cloner(cloner_name))
136 		return (1);
137 	/* need to load */
138 	RLOG("trying to load %s driver", cloner_name);
139 
140 	char cmd[64];
141 
142 	snprintf(cmd, sizeof(cmd), "/sbin/kldload if_%s", cloner_name);
143 	int ret = system(cmd);
144 	if (ret != 0) {
145 		RLOG("'%s' failed, error %d", cmd, ret);
146 		return (0);
147 	}
148 
149 	return (1);
150 }
151 
152 static int
153 iface_create_cloned(char *ifname_ptr)
154 {
155 	struct ifreq ifr;
156 	int s;
157 	char prefix[IFNAMSIZ];
158 
159 	char *src, *dst;
160 	for (src = ifname_ptr, dst = prefix; *src && isalpha(*src); src++)
161 		*dst++ = *src;
162 	*dst = '\0';
163 
164 	if (_enforce_cloner_loaded(prefix) == 0)
165 		return (0);
166 
167 	memset(&ifr, 0, sizeof(struct ifreq));
168 
169 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
170 	strlcpy(ifr.ifr_name, ifname_ptr, sizeof(ifr.ifr_name));
171 
172 	RLOG("creating iface %s %s", prefix, ifr.ifr_name);
173 	if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
174 		err(1, "SIOCIFCREATE2");
175 
176 	strlcpy(ifname_ptr, ifr.ifr_name, IFNAMSIZ);
177 	RLOG("created interface %s", ifname_ptr);
178 
179 	return (1);
180 }
181 
182 static int
183 iface_destroy(char *ifname)
184 {
185 	struct ifreq ifr;
186 	int s;
187 
188 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
189 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
190 
191 	RLOG("destroying interface %s", ifname);
192 	if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
193 		return (0);
194 
195 	return (1);
196 }
197 
198 /*
199  * Open tunneling device such as tuntap and returns fd.
200  */
201 int
202 iface_open(char *ifname)
203 {
204 	char path[256];
205 
206 	snprintf(path, sizeof(path), "/dev/%s", ifname);
207 
208 	RLOG("opening interface %s", ifname);
209 	int fd = open(path, O_RDWR|O_EXCL);
210 	if (fd == -1) {
211 		RLOG_ERRNO("unable to open interface %s", ifname);
212 		return (-1);
213 	}
214 
215 	return (fd);
216 }
217 
218 /*
219  * Sets primary IPv4 addr.
220  * Returns 0 on success.
221  */
222 inline int
223 iface_setup_addr(char *ifname, char *addr, int plen)
224 {
225 	char cmd[512];
226 	char *af;
227 
228 	if (strchr(addr, ':'))
229 		af = "inet6";
230 	else
231 		af = "inet";
232 	RLOG("setting af_%s %s/%d on %s", af, addr, plen, ifname);
233 	snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s %s %s/%d", ifname,
234 		af, addr, plen);
235 
236 	return system(cmd);
237 }
238 
239 /*
240  * Removes primary IPv4 prefix.
241  * Returns 0 on success.
242  */
243 inline int
244 iface_delete_addr(char *ifname, char *addr)
245 {
246 	char cmd[512];
247 
248 	if (strchr(addr, ':')) {
249 		RLOG("removing IPv6 %s from %s", addr, ifname);
250 		snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s inet6 %s delete", ifname, addr);
251 	} else {
252 		RLOG("removing IPv4 %s from %s", addr, ifname);
253 		snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s -alias %s", ifname, addr);
254 	}
255 
256 	return system(cmd);
257 }
258 
259 int
260 iface_turn_up(char *ifname)
261 {
262 	struct ifreq ifr;
263 	int s;
264 
265 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
266 		RLOG_ERRNO("socket");
267 		return (-1);
268 	}
269 	memset(&ifr, 0, sizeof(struct ifreq));
270 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
271 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
272 		RLOG_ERRNO("ioctl(SIOCGIFFLAGS)");
273 		return (-1);
274 	}
275 	/* Update flags */
276 	if ((ifr.ifr_flags & IFF_UP) == 0) {
277 		ifr.ifr_flags |= IFF_UP;
278 		if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
279 			RLOG_ERRNO("ioctl(SIOSGIFFLAGS)");
280 			return (-1);
281 		}
282 		RLOG("turned interface %s up", ifname);
283 	}
284 
285 	return (0);
286 }
287 
288 /*
289  * Removes ND6_IFF_IFDISABLED from IPv6 interface flags.
290  * Returns 0 on success.
291  */
292 int
293 iface_enable_ipv6(char *ifname)
294 {
295 	struct in6_ndireq nd;
296 	int s;
297 
298 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
299 		err(1, "socket");
300 	}
301 	memset(&nd, 0, sizeof(nd));
302 	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
303 	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
304 		RLOG_ERRNO("ioctl(SIOCGIFINFO_IN6)");
305 		return (-1);
306 	}
307 	/* Update flags */
308 	if ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0) {
309 		nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
310 		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
311 			RLOG_ERRNO("ioctl(SIOCSIFINFO_IN6)");
312 			return (-1);
313 		}
314 		RLOG("enabled IPv6 for %s", ifname);
315 	}
316 
317 	return (0);
318 }
319 
320 #define	SA_F_IGNORE_IFNAME	0x01
321 #define	SA_F_IGNORE_IFTYPE	0x02
322 #define	SA_F_IGNORE_MEMCMP	0x04
323 int
324 sa_equal_msg_flags(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz, int flags)
325 {
326 	char a_s[64], b_s[64];
327 	const struct sockaddr_in *a4, *b4;
328 	const struct sockaddr_in6 *a6, *b6;
329 	const struct sockaddr_dl *al, *bl;
330 
331 	if (a == NULL) {
332 		snprintf(msg, sz, "first sa is NULL");
333 		return 0;
334 	}
335 	if (b == NULL) {
336 		snprintf(msg, sz, "second sa is NULL");
337 		return 0;
338 	}
339 
340 	if (a->sa_family != b->sa_family) {
341 		snprintf(msg, sz, "family: %d vs %d", a->sa_family, b->sa_family);
342 		return 0;
343 	}
344 	if (a->sa_len != b->sa_len) {
345 		snprintf(msg, sz, "len: %d vs %d", a->sa_len, b->sa_len);
346 		return 0;
347 	}
348 
349 	switch (a->sa_family) {
350 	case AF_INET:
351 		a4 = (const struct sockaddr_in *)a;
352 		b4 = (const struct sockaddr_in *)b;
353 		if (a4->sin_addr.s_addr != b4->sin_addr.s_addr) {
354 			inet_ntop(AF_INET, &a4->sin_addr, a_s, sizeof(a_s));
355 			inet_ntop(AF_INET, &b4->sin_addr, b_s, sizeof(b_s));
356 			snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
357 			return 0;
358 		}
359 		if (a4->sin_port != b4->sin_port) {
360 			snprintf(msg, sz, "port diff: %d vs %d",
361 					ntohs(a4->sin_port), ntohs(b4->sin_port));
362 			//return 0;
363 		}
364 		const uint32_t *a32, *b32;
365 		a32 = (const uint32_t *)a4->sin_zero;
366 		b32 = (const uint32_t *)b4->sin_zero;
367 		if ((*a32 != *b32) || (*(a32 + 1) != *(b32 + 1))) {
368 			snprintf(msg, sz, "zero diff: 0x%08X%08X vs 0x%08X%08X",
369 					ntohl(*a32), ntohl(*(a32 + 1)),
370 					ntohl(*b32), ntohl(*(b32 + 1)));
371 			return 0;
372 		}
373 		return 1;
374 	case AF_INET6:
375 		a6 = (const struct sockaddr_in6 *)a;
376 		b6 = (const struct sockaddr_in6 *)b;
377 		if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr)) {
378 			inet_ntop(AF_INET6, &a6->sin6_addr, a_s, sizeof(a_s));
379 			inet_ntop(AF_INET6, &b6->sin6_addr, a_s, sizeof(a_s));
380 			snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
381 			return 0;
382 		}
383 		if (a6->sin6_scope_id != b6->sin6_scope_id) {
384 			snprintf(msg, sz, "scope diff: %u vs %u", a6->sin6_scope_id, b6->sin6_scope_id);
385 			return 0;
386 		}
387 		break;
388 	case AF_LINK:
389 		al = (const struct sockaddr_dl *)a;
390 		bl = (const struct sockaddr_dl *)b;
391 
392 		if (al->sdl_index != bl->sdl_index) {
393 			snprintf(msg, sz, "sdl_index diff: %u vs %u", al->sdl_index, bl->sdl_index);
394 			return 0;
395 		}
396 
397 		if ((al->sdl_alen != bl->sdl_alen) || (memcmp(LLADDR(al), LLADDR(bl), al->sdl_alen) != 0)) {
398 			char abuf[64], bbuf[64];
399 			sa_print_hd(abuf, sizeof(abuf), LLADDR(al), al->sdl_alen);
400 			sa_print_hd(bbuf, sizeof(bbuf), LLADDR(bl), bl->sdl_alen);
401 			snprintf(msg, sz, "sdl_alen diff: {%s} (%d) vs {%s} (%d)",
402 			    abuf, al->sdl_alen, bbuf, bl->sdl_alen);
403 			return 0;
404 		}
405 
406 		if (((flags & SA_F_IGNORE_IFTYPE) == 0) && (al->sdl_type != bl->sdl_type)) {
407 			snprintf(msg, sz, "sdl_type diff: %u vs %u", al->sdl_type, bl->sdl_type);
408 			return 0;
409 		}
410 
411 		if (((flags & SA_F_IGNORE_IFNAME) == 0) && ((al->sdl_nlen != bl->sdl_nlen) ||
412 			    (memcmp(al->sdl_data, bl->sdl_data, al->sdl_nlen) != 0))) {
413 			char abuf[64], bbuf[64];
414 			memcpy(abuf, al->sdl_data, al->sdl_nlen);
415 			abuf[al->sdl_nlen] = '\0';
416 			memcpy(bbuf, bl->sdl_data, bl->sdl_nlen);
417 			abuf[bl->sdl_nlen] = '\0';
418 			snprintf(msg, sz, "sdl_nlen diff: {%s} (%d) vs {%s} (%d)",
419 			    abuf, al->sdl_nlen, bbuf, bl->sdl_nlen);
420 			return 0;
421 		}
422 
423 		if (flags & SA_F_IGNORE_MEMCMP)
424 			return 1;
425 		break;
426 	}
427 
428 	if (memcmp(a, b, a->sa_len)) {
429 		int i;
430 		for (i = 0; i < a->sa_len; i++)
431 			if (((const char *)a)[i] != ((const char *)b)[i])
432 				break;
433 
434 		sa_print(a, 1);
435 		sa_print(b, 1);
436 
437 		snprintf(msg, sz, "overall memcmp() reports diff for af %d offset %d",
438 				a->sa_family, i);
439 		return 0;
440 	}
441 	return 1;
442 }
443 
444 int
445 sa_equal_msg(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz)
446 {
447 
448 	return sa_equal_msg_flags(a, b, msg, sz, 0);
449 }
450 
451 void
452 sa_fill_mask4(struct sockaddr_in *sin, int plen)
453 {
454 
455 	memset(sin, 0, sizeof(struct sockaddr_in));
456 	sin->sin_family = AF_INET;
457 	sin->sin_len = sizeof(struct sockaddr_in);
458 	sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
459 }
460 
461 void
462 sa_fill_mask6(struct sockaddr_in6 *sin6, uint8_t mask)
463 {
464 	uint32_t *cp;
465 
466 	memset(sin6, 0, sizeof(struct sockaddr_in6));
467 	sin6->sin6_family = AF_INET6;
468 	sin6->sin6_len = sizeof(struct sockaddr_in6);
469 
470 	for (cp = (uint32_t *)&sin6->sin6_addr; mask >= 32; mask -= 32)
471 		*cp++ = 0xFFFFFFFF;
472 	if (mask > 0)
473 		*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
474 }
475 
476 /* 52:54:00:14:e3:10 */
477 #define	ETHER_MAC_MAX_LENGTH	17
478 
479 int
480 sa_convert_str_to_sa(const char *_addr, struct sockaddr *sa)
481 {
482 	int error;
483 
484 	int af = AF_UNSPEC;
485 
486 	char *addr = strdup(_addr);
487 	int retcode = 0;
488 
489 	/* classify AF by str */
490 	if (strchr(addr, ':')) {
491 		/* inet6 or ether */
492 		char *k;
493 		int delim_cnt = 0;
494 		for (k = addr; *k; k++)
495 			if (*k == ':')
496 				delim_cnt++;
497 		af = AF_INET6;
498 
499 		if (delim_cnt == 5) {
500 			k = strchr(addr, '%');
501 			if (k != NULL && (k - addr) <= ETHER_MAC_MAX_LENGTH)
502 				af = AF_LINK;
503 		}
504 	} else if (strchr(addr, '.'))
505 		af = AF_INET;
506 
507 	/* */
508 	char *delimiter;
509 	int ifindex = 0;
510 	char *ifname = NULL;
511 	if ((delimiter = strchr(addr, '%')) != NULL) {
512 		*delimiter = '\0';
513 		ifname = delimiter + 1;
514 		ifindex = if_nametoindex(ifname);
515 		if (ifindex == 0)
516 			RLOG("unable to find ifindex for '%s'", ifname);
517 		else
518 			RLOG("if %s mapped to %d", ifname, ifindex);
519 	}
520 
521 	if (af == AF_INET6) {
522 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
523 		memset(sin6, 0, sizeof(struct sockaddr_in6));
524 		sin6->sin6_family = AF_INET6;
525 		sin6->sin6_len = sizeof(struct sockaddr_in6);
526 		sin6->sin6_scope_id = ifindex;
527 		error = inet_pton(AF_INET6, addr, &sin6->sin6_addr);
528 		if (error != 1)
529 			RLOG_ERRNO("inet_ntop() failed: ret=%d", error);
530 		else
531 			retcode = 1;
532 	} else if (af == AF_INET) {
533 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
534 		memset(sin, 0, sizeof(struct sockaddr_in));
535 		sin->sin_family = AF_INET;
536 		sin->sin_len = sizeof(struct sockaddr_in);
537 		error = inet_pton(AF_INET, addr, &sin->sin_addr);
538 		if (error != 1)
539 			RLOG("inet_ntop() failed: ret=%d", error);
540 		else
541 			retcode = 1;
542 	} else if (af == AF_LINK) {
543 		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
544 		memset(sdl, 0, sizeof(struct sockaddr_dl));
545 		sdl->sdl_family = AF_LINK;
546 		sdl->sdl_len = sizeof(struct sockaddr_dl);
547 		sdl->sdl_index = ifindex;
548 		sdl->sdl_alen = 6;
549 		struct ether_addr *ea = (struct ether_addr *)LLADDR(sdl);
550 		if (ether_aton_r(addr, ea) == NULL)
551 			RLOG("ether_aton() failed");
552 		else
553 			retcode = 1;
554 	}
555 
556 	return (retcode);
557 }
558 
559 
560 int
561 rtsock_setup_socket()
562 {
563 	int fd;
564 	int af = AF_UNSPEC; /* 0 to capture messages from all AFs */
565 	fd = socket(PF_ROUTE, SOCK_RAW, af);
566 
567 	ATF_REQUIRE_MSG(fd != -1, "rtsock open failed: %s", strerror(errno));
568 
569 	/* Listen for our messages */
570 	int on = 1;
571 	if (setsockopt(fd, SOL_SOCKET,SO_USELOOPBACK, &on, sizeof(on)) < 0)
572 		RLOG_ERRNO("setsockopt failed");
573 
574 	return (fd);
575 }
576 
577 ssize_t
578 rtsock_send_rtm(int fd, struct rt_msghdr *rtm)
579 {
580 	int my_errno;
581 	ssize_t len;
582 
583 	rtsock_update_rtm_len(rtm);
584 
585 	len = write(fd, rtm, rtm->rtm_msglen);
586 	my_errno = errno;
587 	RTSOCK_ATF_REQUIRE_MSG(rtm, len == rtm->rtm_msglen,
588 	    "rtsock write failed: want %d got %zd (%s)",
589 	    rtm->rtm_msglen, len, strerror(my_errno));
590 
591 	return (len);
592 }
593 
594 struct rt_msghdr *
595 rtsock_read_rtm(int fd, char *buffer, size_t buflen)
596 {
597 	ssize_t len;
598 	struct pollfd pfd;
599 	int poll_delay = 5 * 1000; /* 5 seconds */
600 
601 	/* Check for the data available to read first */
602 	memset(&pfd, 0, sizeof(pfd));
603 	pfd.fd = fd;
604 	pfd.events = POLLIN;
605 
606 	if (poll(&pfd, 1, poll_delay) == 0)
607 		ATF_REQUIRE_MSG(1 == 0, "rtsock read timed out (%d seconds passed)",
608 		    poll_delay / 1000);
609 
610 	len = read(fd, buffer, buflen);
611 	int my_errno = errno;
612 	ATF_REQUIRE_MSG(len > 0, "rtsock read failed: %s", strerror(my_errno));
613 
614 	rtsock_validate_message(buffer, len);
615 	return ((struct rt_msghdr *)buffer);
616 }
617 
618 struct rt_msghdr *
619 rtsock_read_rtm_reply(int fd, char *buffer, size_t buflen, int seq)
620 {
621 	struct rt_msghdr *rtm;
622 
623 	while (true) {
624 		rtm = rtsock_read_rtm(fd, buffer, buflen);
625 		if (rtm->rtm_pid != getpid())
626 			continue;
627 		if (rtm->rtm_seq != seq)
628 			continue;
629 
630 		return (rtm);
631 	}
632 
633 	/* NOTREACHED */
634 }
635 
636 void
637 rtsock_prepare_route_message_base(struct rt_msghdr *rtm, int cmd)
638 {
639 
640 	memset(rtm, 0, sizeof(struct rt_msghdr));
641 	rtm->rtm_type = cmd;
642 	rtm->rtm_version = RTM_VERSION;
643 	rtm->rtm_seq = _rtm_seq++;
644 }
645 
646 void
647 rtsock_prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
648   struct sockaddr *mask, struct sockaddr *gw)
649 {
650 
651 	rtsock_prepare_route_message_base(rtm, cmd);
652 	if (dst != NULL)
653 		rtsock_add_rtm_sa(rtm, RTA_DST, dst);
654 
655 	if (gw != NULL) {
656 		rtsock_add_rtm_sa(rtm, RTA_GATEWAY, gw);
657 		rtm->rtm_flags |= RTF_GATEWAY;
658 	}
659 
660 	if (mask != NULL)
661 		rtsock_add_rtm_sa(rtm, RTA_NETMASK, mask);
662 }
663 
664 void
665 rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa)
666 {
667 	char *ptr = (char *)(rtm + 1);
668 	for (int i = 0; i < RTAX_MAX; i++) {
669 		if (rtm->rtm_addrs & (1 << i)) {
670 			/* add */
671 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
672 		}
673 	}
674 
675 	rtm->rtm_addrs |= addr_type;
676 	memcpy(ptr, sa, sa->sa_len);
677 }
678 
679 struct sockaddr *
680 rtsock_find_rtm_sa(struct rt_msghdr *rtm, int addr_type)
681 {
682 	char *ptr = (char *)(rtm + 1);
683 	for (int i = 0; i < RTAX_MAX; i++) {
684 		if (rtm->rtm_addrs & (1 << i)) {
685 			if (addr_type == (1 << i))
686 				return ((struct sockaddr *)ptr);
687 			/* add */
688 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
689 		}
690 	}
691 
692 	return (NULL);
693 }
694 
695 size_t
696 rtsock_calc_rtm_len(struct rt_msghdr *rtm)
697 {
698 	size_t len = sizeof(struct rt_msghdr);
699 
700 	char *ptr = (char *)(rtm + 1);
701 	for (int i = 0; i < RTAX_MAX; i++) {
702 		if (rtm->rtm_addrs & (1 << i)) {
703 			/* add */
704 			int sa_len = ALIGN(((struct sockaddr *)ptr)->sa_len);
705 			len += sa_len;
706 			ptr += sa_len;
707 		}
708 	}
709 
710 	return len;
711 }
712 
713 void
714 rtsock_update_rtm_len(struct rt_msghdr *rtm)
715 {
716 
717 	rtm->rtm_msglen = rtsock_calc_rtm_len(rtm);
718 }
719 
720 static void
721 _validate_message_sockaddrs(char *buffer, int rtm_len, size_t offset, int rtm_addrs)
722 {
723 	struct sockaddr *sa;
724 	size_t parsed_len = offset;
725 
726 	/* Offset denotes initial header size */
727 	sa = (struct sockaddr *)(buffer + offset);
728 
729 	for (int i = 0; i < RTAX_MAX; i++) {
730 		if ((rtm_addrs & (1 << i)) == 0)
731 			continue;
732 		parsed_len += SA_SIZE(sa);
733 		RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len <= rtm_len,
734 		    "SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, rtm_len);
735 		if (sa->sa_family == AF_LINK) {
736 			struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
737 			int data_len = sdl->sdl_nlen + sdl->sdl_alen;
738 			data_len += offsetof(struct sockaddr_dl, sdl_data);
739 
740 			RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer,
741 			    data_len <= rtm_len,
742 			    "AF_LINK data size exceeds total len: %u vs %u, nlen=%d alen=%d",
743 			    data_len, rtm_len, sdl->sdl_nlen, sdl->sdl_alen);
744 		}
745 		sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
746 	}
747 
748 	RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len == rtm_len,
749 	    "message len != parsed len: expected %d parsed %d",
750 	    rtm_len, (int)parsed_len);
751 }
752 
753 /*
754  * Raises error if base syntax checks fails.
755  */
756 void
757 rtsock_validate_message(char *buffer, ssize_t len)
758 {
759 	struct rt_msghdr *rtm;
760 
761 	ATF_REQUIRE_MSG(len > 0, "read() return %zd, error: %s", len, strerror(errno));
762 
763 	rtm = (struct rt_msghdr *)buffer;
764 	ATF_REQUIRE_MSG(rtm->rtm_version == RTM_VERSION, "unknown RTM_VERSION: expected %d got %d",
765 			RTM_VERSION, rtm->rtm_version);
766 	ATF_REQUIRE_MSG(rtm->rtm_msglen <= len, "wrong message length: expected %d got %d",
767 			(int)len, (int)rtm->rtm_msglen);
768 
769 	switch (rtm->rtm_type) {
770 	case RTM_GET:
771 	case RTM_ADD:
772 	case RTM_DELETE:
773 	case RTM_CHANGE:
774 		_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
775 		    sizeof(struct rt_msghdr), rtm->rtm_addrs);
776 		break;
777 	case RTM_DELADDR:
778 	case RTM_NEWADDR:
779 		_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
780 		    sizeof(struct ifa_msghdr), ((struct ifa_msghdr *)buffer)->ifam_addrs);
781 		break;
782 	}
783 }
784 
785 void
786 rtsock_validate_pid_ours(struct rt_msghdr *rtm)
787 {
788 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == getpid(), "expected pid %d, got %d",
789 	    getpid(), rtm->rtm_pid);
790 }
791 
792 void
793 rtsock_validate_pid_user(struct rt_msghdr *rtm)
794 {
795 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid, got %d",
796 	    rtm->rtm_pid);
797 }
798 
799 void
800 rtsock_validate_pid_kernel(struct rt_msghdr *rtm)
801 {
802 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == 0, "expected zero pid, got %d",
803 	    rtm->rtm_pid);
804 }
805 
806 #endif
807