xref: /freebsd/tests/sys/net/routing/rtsock_common.h (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 
28 #ifndef _NET_ROUTING_RTSOCK_COMMON_H_
29 #define _NET_ROUTING_RTSOCK_COMMON_H_
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <stdbool.h>
37 #include <ctype.h>
38 #include <poll.h>
39 
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <sys/jail.h>
46 #include <sys/linker.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 #include "freebsd_test_suite/macros.h"
66 
67 #include "rtsock_print.h"
68 #include "params.h"
69 
70 void rtsock_update_rtm_len(struct rt_msghdr *rtm);
71 void rtsock_validate_message(char *buffer, ssize_t len);
72 void rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa);
73 
74 void file_append_line(char *fname, char *text);
75 
76 static int _rtm_seq = 42;
77 
78 
79 /*
80  * Checks if the interface cloner module is present for @name.
81  */
82 static int
_check_cloner(char * name)83 _check_cloner(char *name)
84 {
85 	struct if_clonereq ifcr;
86 	char *cp, *buf;
87 	int idx;
88 	int s;
89 	int found = 0;
90 
91 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
92 	if (s == -1)
93 		err(1, "socket(AF_LOCAL,SOCK_DGRAM)");
94 
95 	memset(&ifcr, 0, sizeof(ifcr));
96 
97 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
98 		err(1, "SIOCIFGCLONERS for count");
99 
100 	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
101 	if (buf == NULL)
102 		err(1, "unable to allocate cloner name buffer");
103 
104 	ifcr.ifcr_count = ifcr.ifcr_total;
105 	ifcr.ifcr_buffer = buf;
106 
107 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
108 		err(1, "SIOCIFGCLONERS for names");
109 
110 	/*
111 	 * In case some disappeared in the mean time, clamp it down.
112 	 */
113 	if (ifcr.ifcr_count > ifcr.ifcr_total)
114 		ifcr.ifcr_count = ifcr.ifcr_total;
115 
116 	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
117 		if (!strcmp(cp, name)) {
118 			found = 1;
119 			break;
120 		}
121 	}
122 
123 	free(buf);
124 	close(s);
125 
126 	return (found);
127 }
128 
129 static char *
iface_create(char * ifname_orig)130 iface_create(char *ifname_orig)
131 {
132 	struct ifreq ifr;
133 	int s;
134 	char prefix[IFNAMSIZ], ifname[IFNAMSIZ], *result;
135 
136 	char *src, *dst;
137 	for (src = ifname_orig, dst = prefix; *src && isalpha(*src); src++)
138 		*dst++ = *src;
139 	*dst = '\0';
140 
141 	memset(&ifr, 0, sizeof(struct ifreq));
142 
143 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
144 	strlcpy(ifr.ifr_name, ifname_orig, sizeof(ifr.ifr_name));
145 
146 	RLOG("creating iface %s %s", prefix, ifr.ifr_name);
147 	if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
148 		err(1, "SIOCIFCREATE2");
149 
150 	strlcpy(ifname, ifr.ifr_name, IFNAMSIZ);
151 	RLOG("created interface %s", ifname);
152 
153 	result = strdup(ifname);
154 
155 	file_append_line(IFACES_FNAME, ifname);
156 	if (strstr(ifname, "epair") == ifname) {
157 		/* call returned epairXXXa, need to add epairXXXb */
158 		ifname[strlen(ifname) - 1] = 'b';
159 		file_append_line(IFACES_FNAME, ifname);
160 	}
161 
162 	return (result);
163 }
164 
165 static int
iface_destroy(char * ifname)166 iface_destroy(char *ifname)
167 {
168 	struct ifreq ifr;
169 	int s;
170 
171 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
172 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
173 
174 	RLOG("destroying interface %s", ifname);
175 	if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
176 		return (0);
177 
178 	return (1);
179 }
180 
181 /*
182  * Open tunneling device such as tuntap and returns fd.
183  */
184 int
iface_open(char * ifname)185 iface_open(char *ifname)
186 {
187 	char path[256];
188 
189 	snprintf(path, sizeof(path), "/dev/%s", ifname);
190 
191 	RLOG("opening interface %s", ifname);
192 	int fd = open(path, O_RDWR|O_EXCL);
193 	if (fd == -1) {
194 		RLOG_ERRNO("unable to open interface %s", ifname);
195 		return (-1);
196 	}
197 
198 	return (fd);
199 }
200 
201 /*
202  * Sets primary IPv4 addr.
203  * Returns 0 on success.
204  */
205 static inline int
iface_setup_addr(char * ifname,char * addr,int plen)206 iface_setup_addr(char *ifname, char *addr, int plen)
207 {
208 	char cmd[512];
209 	char *af;
210 
211 	if (strchr(addr, ':'))
212 		af = "inet6";
213 	else
214 		af = "inet";
215 	RLOG("setting af_%s %s/%d on %s", af, addr, plen, ifname);
216 	snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s %s %s/%d", ifname,
217 		af, addr, plen);
218 
219 	return system(cmd);
220 }
221 
222 /*
223  * Removes primary IPv4 prefix.
224  * Returns 0 on success.
225  */
226 static inline int
iface_delete_addr(char * ifname,char * addr)227 iface_delete_addr(char *ifname, char *addr)
228 {
229 	char cmd[512];
230 
231 	if (strchr(addr, ':')) {
232 		RLOG("removing IPv6 %s from %s", addr, ifname);
233 		snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s inet6 %s delete", ifname, addr);
234 	} else {
235 		RLOG("removing IPv4 %s from %s", addr, ifname);
236 		snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s -alias %s", ifname, addr);
237 	}
238 
239 	return system(cmd);
240 }
241 
242 int
iface_turn_up(char * ifname)243 iface_turn_up(char *ifname)
244 {
245 	struct ifreq ifr;
246 	int s;
247 
248 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
249 		RLOG_ERRNO("socket");
250 		return (-1);
251 	}
252 	memset(&ifr, 0, sizeof(struct ifreq));
253 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
254 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
255 		RLOG_ERRNO("ioctl(SIOCGIFFLAGS)");
256 		return (-1);
257 	}
258 	/* Update flags */
259 	if ((ifr.ifr_flags & IFF_UP) == 0) {
260 		ifr.ifr_flags |= IFF_UP;
261 		if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
262 			RLOG_ERRNO("ioctl(SIOSGIFFLAGS)");
263 			return (-1);
264 		}
265 		RLOG("turned interface %s up", ifname);
266 	}
267 
268 	return (0);
269 }
270 
271 /*
272  * Removes ND6_IFF_IFDISABLED from IPv6 interface flags.
273  * Returns 0 on success.
274  */
275 int
iface_enable_ipv6(char * ifname)276 iface_enable_ipv6(char *ifname)
277 {
278 	struct in6_ndireq nd;
279 	int s;
280 
281 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
282 		err(1, "socket");
283 	}
284 	memset(&nd, 0, sizeof(nd));
285 	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
286 	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
287 		RLOG_ERRNO("ioctl(SIOCGIFINFO_IN6)");
288 		return (-1);
289 	}
290 	/* Update flags */
291 	if ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0) {
292 		nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
293 		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
294 			RLOG_ERRNO("ioctl(SIOCSIFINFO_IN6)");
295 			return (-1);
296 		}
297 		RLOG("enabled IPv6 for %s", ifname);
298 	}
299 
300 	return (0);
301 }
302 
303 void
file_append_line(char * fname,char * text)304 file_append_line(char *fname, char *text)
305 {
306 	FILE *f;
307 
308 	f = fopen(fname, "a");
309 	fputs(text, f);
310 	fputs("\n", f);
311 	fclose(f);
312 }
313 
314 static int
vnet_wait_interface(char * vnet_name,char * ifname)315 vnet_wait_interface(char *vnet_name, char *ifname)
316 {
317 	char buf[512], cmd[512], *line, *token;
318 	FILE *fp;
319 	int i;
320 
321 	snprintf(cmd, sizeof(cmd), "/usr/sbin/jexec %s /sbin/ifconfig -l", vnet_name);
322 	for (int i = 0; i < 50; i++) {
323 		fp = popen(cmd, "r");
324 		line = fgets(buf, sizeof(buf), fp);
325 		/* cut last\n */
326 		if (line[0])
327 			line[strlen(line)-1] = '\0';
328 		while ((token = strsep(&line, " ")) != NULL) {
329 			if (strcmp(token, ifname) == 0)
330 				return (1);
331 		}
332 
333 		/* sleep 100ms */
334 		usleep(1000 * 100);
335 	}
336 
337 	return (0);
338 }
339 
340 void
vnet_switch(char * vnet_name,char ** ifnames,int count)341 vnet_switch(char *vnet_name, char **ifnames, int count)
342 {
343 	char buf[512], cmd[512], *line;
344 	FILE *fp;
345 	int jid, len, ret;
346 
347 	RLOG("switching to vnet %s with interface(s) %s", vnet_name, ifnames[0]);
348 	len = snprintf(cmd, sizeof(cmd),
349 	    "/usr/sbin/jail -i -c name=%s persist vnet", vnet_name);
350 	for (int i = 0; i < count && len < sizeof(cmd); i++) {
351 		len += snprintf(&cmd[len], sizeof(cmd) - len,
352 		    " vnet.interface=%s", ifnames[i]);
353 	}
354 	RLOG("jail cmd: \"%s\"\n", cmd);
355 
356 	fp = popen(cmd, "r");
357 	if (fp == NULL)
358 		atf_tc_fail("jail creation failed");
359 	line = fgets(buf, sizeof(buf), fp);
360 	if (line == NULL)
361 		atf_tc_fail("empty output from jail(8)");
362 	jid = strtol(line, NULL, 10);
363 	if (jid <= 0) {
364 		atf_tc_fail("invalid jail output: %s", line);
365 	}
366 
367 	RLOG("created jail jid=%d", jid);
368 	file_append_line(JAILS_FNAME, vnet_name);
369 
370 	/* Wait while interface appearsh inside vnet */
371 	for (int i = 0; i < count; i++) {
372 		if (vnet_wait_interface(vnet_name, ifnames[i]))
373 			continue;
374 		atf_tc_fail("unable to move interface %s to jail %s",
375 		    ifnames[i], vnet_name);
376 	}
377 
378 	if (jail_attach(jid) == -1) {
379 		RLOG_ERRNO("jail %s attach failed: ret=%d", vnet_name, errno);
380 		atf_tc_fail("jail attach failed");
381 	}
382 
383 	RLOG("attached to the jail");
384 }
385 
386 void
vnet_switch_one(char * vnet_name,char * ifname)387 vnet_switch_one(char *vnet_name, char *ifname)
388 {
389 	char *ifnames[1];
390 
391 	ifnames[0] = ifname;
392 	vnet_switch(vnet_name, ifnames, 1);
393 }
394 
395 
396 #define	SA_F_IGNORE_IFNAME	0x01
397 #define	SA_F_IGNORE_IFTYPE	0x02
398 #define	SA_F_IGNORE_MEMCMP	0x04
399 int
sa_equal_msg_flags(const struct sockaddr * a,const struct sockaddr * b,char * msg,size_t sz,int flags)400 sa_equal_msg_flags(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz, int flags)
401 {
402 	char a_s[64], b_s[64];
403 	const struct sockaddr_in *a4, *b4;
404 	const struct sockaddr_in6 *a6, *b6;
405 	const struct sockaddr_dl *al, *bl;
406 
407 	if (a == NULL) {
408 		snprintf(msg, sz, "first sa is NULL");
409 		return 0;
410 	}
411 	if (b == NULL) {
412 		snprintf(msg, sz, "second sa is NULL");
413 		return 0;
414 	}
415 
416 	if (a->sa_family != b->sa_family) {
417 		snprintf(msg, sz, "family: %d vs %d", a->sa_family, b->sa_family);
418 		return 0;
419 	}
420 	if (a->sa_len != b->sa_len) {
421 		snprintf(msg, sz, "len: %d vs %d", a->sa_len, b->sa_len);
422 		return 0;
423 	}
424 
425 	switch (a->sa_family) {
426 	case AF_INET:
427 		a4 = (const struct sockaddr_in *)a;
428 		b4 = (const struct sockaddr_in *)b;
429 		if (a4->sin_addr.s_addr != b4->sin_addr.s_addr) {
430 			inet_ntop(AF_INET, &a4->sin_addr, a_s, sizeof(a_s));
431 			inet_ntop(AF_INET, &b4->sin_addr, b_s, sizeof(b_s));
432 			snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
433 			return 0;
434 		}
435 		if (a4->sin_port != b4->sin_port) {
436 			snprintf(msg, sz, "port diff: %d vs %d",
437 					ntohs(a4->sin_port), ntohs(b4->sin_port));
438 			//return 0;
439 		}
440 		const uint32_t *a32, *b32;
441 		a32 = (const uint32_t *)a4->sin_zero;
442 		b32 = (const uint32_t *)b4->sin_zero;
443 		if ((*a32 != *b32) || (*(a32 + 1) != *(b32 + 1))) {
444 			snprintf(msg, sz, "zero diff: 0x%08X%08X vs 0x%08X%08X",
445 					ntohl(*a32), ntohl(*(a32 + 1)),
446 					ntohl(*b32), ntohl(*(b32 + 1)));
447 			return 0;
448 		}
449 		return 1;
450 	case AF_INET6:
451 		a6 = (const struct sockaddr_in6 *)a;
452 		b6 = (const struct sockaddr_in6 *)b;
453 		if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr)) {
454 			inet_ntop(AF_INET6, &a6->sin6_addr, a_s, sizeof(a_s));
455 			inet_ntop(AF_INET6, &b6->sin6_addr, b_s, sizeof(b_s));
456 			snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
457 			return 0;
458 		}
459 		if (a6->sin6_scope_id != b6->sin6_scope_id) {
460 			snprintf(msg, sz, "scope diff: %u vs %u", a6->sin6_scope_id, b6->sin6_scope_id);
461 			return 0;
462 		}
463 		break;
464 	case AF_LINK:
465 		al = (const struct sockaddr_dl *)a;
466 		bl = (const struct sockaddr_dl *)b;
467 
468 		if (al->sdl_index != bl->sdl_index) {
469 			snprintf(msg, sz, "sdl_index diff: %u vs %u", al->sdl_index, bl->sdl_index);
470 			return 0;
471 		}
472 
473 		if ((al->sdl_alen != bl->sdl_alen) || (memcmp(LLADDR(al), LLADDR(bl), al->sdl_alen) != 0)) {
474 			char abuf[64], bbuf[64];
475 			sa_print_hd(abuf, sizeof(abuf), LLADDR(al), al->sdl_alen);
476 			sa_print_hd(bbuf, sizeof(bbuf), LLADDR(bl), bl->sdl_alen);
477 			snprintf(msg, sz, "sdl_alen diff: {%s} (%d) vs {%s} (%d)",
478 			    abuf, al->sdl_alen, bbuf, bl->sdl_alen);
479 			return 0;
480 		}
481 
482 		if (((flags & SA_F_IGNORE_IFTYPE) == 0) && (al->sdl_type != bl->sdl_type)) {
483 			snprintf(msg, sz, "sdl_type diff: %u vs %u", al->sdl_type, bl->sdl_type);
484 			return 0;
485 		}
486 
487 		if (((flags & SA_F_IGNORE_IFNAME) == 0) && ((al->sdl_nlen != bl->sdl_nlen) ||
488 			    (memcmp(al->sdl_data, bl->sdl_data, al->sdl_nlen) != 0))) {
489 			char abuf[64], bbuf[64];
490 			memcpy(abuf, al->sdl_data, al->sdl_nlen);
491 			abuf[al->sdl_nlen] = '\0';
492 			memcpy(bbuf, bl->sdl_data, bl->sdl_nlen);
493 			abuf[bl->sdl_nlen] = '\0';
494 			snprintf(msg, sz, "sdl_nlen diff: {%s} (%d) vs {%s} (%d)",
495 			    abuf, al->sdl_nlen, bbuf, bl->sdl_nlen);
496 			return 0;
497 		}
498 
499 		if (flags & SA_F_IGNORE_MEMCMP)
500 			return 1;
501 		break;
502 	}
503 
504 	if (memcmp(a, b, a->sa_len)) {
505 		int i;
506 		for (i = 0; i < a->sa_len; i++)
507 			if (((const char *)a)[i] != ((const char *)b)[i])
508 				break;
509 
510 		sa_print(a, 1);
511 		sa_print(b, 1);
512 
513 		snprintf(msg, sz, "overall memcmp() reports diff for af %d offset %d",
514 				a->sa_family, i);
515 		return 0;
516 	}
517 	return 1;
518 }
519 
520 int
sa_equal_msg(const struct sockaddr * a,const struct sockaddr * b,char * msg,size_t sz)521 sa_equal_msg(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz)
522 {
523 
524 	return sa_equal_msg_flags(a, b, msg, sz, 0);
525 }
526 
527 void
sa_fill_mask4(struct sockaddr_in * sin,int plen)528 sa_fill_mask4(struct sockaddr_in *sin, int plen)
529 {
530 
531 	memset(sin, 0, sizeof(struct sockaddr_in));
532 	sin->sin_family = AF_INET;
533 	sin->sin_len = sizeof(struct sockaddr_in);
534 	sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
535 }
536 
537 void
sa_fill_mask6(struct sockaddr_in6 * sin6,uint8_t mask)538 sa_fill_mask6(struct sockaddr_in6 *sin6, uint8_t mask)
539 {
540 	uint32_t *cp;
541 
542 	memset(sin6, 0, sizeof(struct sockaddr_in6));
543 	sin6->sin6_family = AF_INET6;
544 	sin6->sin6_len = sizeof(struct sockaddr_in6);
545 
546 	for (cp = (uint32_t *)&sin6->sin6_addr; mask >= 32; mask -= 32)
547 		*cp++ = 0xFFFFFFFF;
548 	if (mask > 0)
549 		*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
550 }
551 
552 /* 52:54:00:14:e3:10 */
553 #define	ETHER_MAC_MAX_LENGTH	17
554 
555 int
sa_convert_str_to_sa(const char * _addr,struct sockaddr * sa)556 sa_convert_str_to_sa(const char *_addr, struct sockaddr *sa)
557 {
558 	int error;
559 
560 	int af = AF_UNSPEC;
561 
562 	char *addr = strdup(_addr);
563 	int retcode = 0;
564 
565 	/* classify AF by str */
566 	if (strchr(addr, ':')) {
567 		/* inet6 or ether */
568 		char *k;
569 		int delim_cnt = 0;
570 		for (k = addr; *k; k++)
571 			if (*k == ':')
572 				delim_cnt++;
573 		af = AF_INET6;
574 
575 		if (delim_cnt == 5) {
576 			k = strchr(addr, '%');
577 			if (k != NULL && (k - addr) <= ETHER_MAC_MAX_LENGTH)
578 				af = AF_LINK;
579 		}
580 	} else if (strchr(addr, '.'))
581 		af = AF_INET;
582 
583 	/* */
584 	char *delimiter;
585 	int ifindex = 0;
586 	char *ifname = NULL;
587 	if ((delimiter = strchr(addr, '%')) != NULL) {
588 		*delimiter = '\0';
589 		ifname = delimiter + 1;
590 		ifindex = if_nametoindex(ifname);
591 		if (ifindex == 0)
592 			RLOG("unable to find ifindex for '%s'", ifname);
593 		else
594 			RLOG("if %s mapped to %d", ifname, ifindex);
595 	}
596 
597 	if (af == AF_INET6) {
598 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
599 		memset(sin6, 0, sizeof(struct sockaddr_in6));
600 		sin6->sin6_family = AF_INET6;
601 		sin6->sin6_len = sizeof(struct sockaddr_in6);
602 		sin6->sin6_scope_id = ifindex;
603 		error = inet_pton(AF_INET6, addr, &sin6->sin6_addr);
604 		if (error != 1)
605 			RLOG_ERRNO("inet_ntop() failed: ret=%d", error);
606 		else
607 			retcode = 1;
608 	} else if (af == AF_INET) {
609 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
610 		memset(sin, 0, sizeof(struct sockaddr_in));
611 		sin->sin_family = AF_INET;
612 		sin->sin_len = sizeof(struct sockaddr_in);
613 		error = inet_pton(AF_INET, addr, &sin->sin_addr);
614 		if (error != 1)
615 			RLOG("inet_ntop() failed: ret=%d", error);
616 		else
617 			retcode = 1;
618 	} else if (af == AF_LINK) {
619 		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
620 		memset(sdl, 0, sizeof(struct sockaddr_dl));
621 		sdl->sdl_family = AF_LINK;
622 		sdl->sdl_len = sizeof(struct sockaddr_dl);
623 		sdl->sdl_index = ifindex;
624 		sdl->sdl_alen = 6;
625 		struct ether_addr *ea = (struct ether_addr *)LLADDR(sdl);
626 		if (ether_aton_r(addr, ea) == NULL)
627 			RLOG("ether_aton() failed");
628 		else
629 			retcode = 1;
630 	}
631 
632 	return (retcode);
633 }
634 
635 
636 int
rtsock_setup_socket()637 rtsock_setup_socket()
638 {
639 	int fd;
640 	int af = AF_UNSPEC; /* 0 to capture messages from all AFs */
641 	fd = socket(PF_ROUTE, SOCK_RAW, af);
642 
643 	ATF_REQUIRE_MSG(fd != -1, "rtsock open failed: %s", strerror(errno));
644 
645 	/* Listen for our messages */
646 	int on = 1;
647 	if (setsockopt(fd, SOL_SOCKET,SO_USELOOPBACK, &on, sizeof(on)) < 0)
648 		RLOG_ERRNO("setsockopt failed");
649 
650 	return (fd);
651 }
652 
653 ssize_t
rtsock_send_rtm(int fd,struct rt_msghdr * rtm)654 rtsock_send_rtm(int fd, struct rt_msghdr *rtm)
655 {
656 	int my_errno;
657 	ssize_t len;
658 
659 	rtsock_update_rtm_len(rtm);
660 
661 	len = write(fd, rtm, rtm->rtm_msglen);
662 	my_errno = errno;
663 	RTSOCK_ATF_REQUIRE_MSG(rtm, len == rtm->rtm_msglen,
664 	    "rtsock write failed: want %d got %zd (%s)",
665 	    rtm->rtm_msglen, len, strerror(my_errno));
666 
667 	return (len);
668 }
669 
670 struct rt_msghdr *
rtsock_read_rtm(int fd,char * buffer,size_t buflen)671 rtsock_read_rtm(int fd, char *buffer, size_t buflen)
672 {
673 	ssize_t len;
674 	struct pollfd pfd;
675 	int poll_delay = 5 * 1000; /* 5 seconds */
676 
677 	/* Check for the data available to read first */
678 	memset(&pfd, 0, sizeof(pfd));
679 	pfd.fd = fd;
680 	pfd.events = POLLIN;
681 
682 	if (poll(&pfd, 1, poll_delay) == 0)
683 		ATF_REQUIRE_MSG(1 == 0, "rtsock read timed out (%d seconds passed)",
684 		    poll_delay / 1000);
685 
686 	len = read(fd, buffer, buflen);
687 	int my_errno = errno;
688 	ATF_REQUIRE_MSG(len > 0, "rtsock read failed: %s", strerror(my_errno));
689 
690 	rtsock_validate_message(buffer, len);
691 	return ((struct rt_msghdr *)buffer);
692 }
693 
694 struct rt_msghdr *
rtsock_read_rtm_reply(int fd,char * buffer,size_t buflen,int seq)695 rtsock_read_rtm_reply(int fd, char *buffer, size_t buflen, int seq)
696 {
697 	struct rt_msghdr *rtm;
698 	int found = 0;
699 
700 	while (true) {
701 		rtm = rtsock_read_rtm(fd, buffer, buflen);
702 		if (rtm->rtm_pid == getpid() && rtm->rtm_seq == seq)
703 			found = 1;
704 		if (found)
705 			RLOG("--- MATCHED RTSOCK MESSAGE ---");
706 		else
707 			RLOG("--- SKIPPED RTSOCK MESSAGE ---");
708 		rtsock_print_rtm(rtm);
709 		if (found)
710 			return (rtm);
711 	}
712 
713 	/* NOTREACHED */
714 }
715 
716 void
rtsock_prepare_route_message_base(struct rt_msghdr * rtm,int cmd)717 rtsock_prepare_route_message_base(struct rt_msghdr *rtm, int cmd)
718 {
719 
720 	memset(rtm, 0, sizeof(struct rt_msghdr));
721 	rtm->rtm_type = cmd;
722 	rtm->rtm_version = RTM_VERSION;
723 	rtm->rtm_seq = _rtm_seq++;
724 }
725 
726 void
rtsock_prepare_route_message(struct rt_msghdr * rtm,int cmd,struct sockaddr * dst,struct sockaddr * mask,struct sockaddr * gw)727 rtsock_prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
728   struct sockaddr *mask, struct sockaddr *gw)
729 {
730 
731 	rtsock_prepare_route_message_base(rtm, cmd);
732 	if (dst != NULL)
733 		rtsock_add_rtm_sa(rtm, RTA_DST, dst);
734 
735 	if (gw != NULL) {
736 		rtsock_add_rtm_sa(rtm, RTA_GATEWAY, gw);
737 		rtm->rtm_flags |= RTF_GATEWAY;
738 	}
739 
740 	if (mask != NULL)
741 		rtsock_add_rtm_sa(rtm, RTA_NETMASK, mask);
742 }
743 
744 void
rtsock_add_rtm_sa(struct rt_msghdr * rtm,int addr_type,struct sockaddr * sa)745 rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa)
746 {
747 	char *ptr = (char *)(rtm + 1);
748 	for (int i = 0; i < RTAX_MAX; i++) {
749 		if (rtm->rtm_addrs & (1 << i)) {
750 			/* add */
751 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
752 		}
753 	}
754 
755 	rtm->rtm_addrs |= addr_type;
756 	memcpy(ptr, sa, sa->sa_len);
757 }
758 
759 struct sockaddr *
rtsock_find_rtm_sa(struct rt_msghdr * rtm,int addr_type)760 rtsock_find_rtm_sa(struct rt_msghdr *rtm, int addr_type)
761 {
762 	char *ptr = (char *)(rtm + 1);
763 	for (int i = 0; i < RTAX_MAX; i++) {
764 		if (rtm->rtm_addrs & (1 << i)) {
765 			if (addr_type == (1 << i))
766 				return ((struct sockaddr *)ptr);
767 			/* add */
768 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
769 		}
770 	}
771 
772 	return (NULL);
773 }
774 
775 size_t
rtsock_calc_rtm_len(struct rt_msghdr * rtm)776 rtsock_calc_rtm_len(struct rt_msghdr *rtm)
777 {
778 	size_t len = sizeof(struct rt_msghdr);
779 
780 	char *ptr = (char *)(rtm + 1);
781 	for (int i = 0; i < RTAX_MAX; i++) {
782 		if (rtm->rtm_addrs & (1 << i)) {
783 			/* add */
784 			int sa_len = ALIGN(((struct sockaddr *)ptr)->sa_len);
785 			len += sa_len;
786 			ptr += sa_len;
787 		}
788 	}
789 
790 	return len;
791 }
792 
793 void
rtsock_update_rtm_len(struct rt_msghdr * rtm)794 rtsock_update_rtm_len(struct rt_msghdr *rtm)
795 {
796 
797 	rtm->rtm_msglen = rtsock_calc_rtm_len(rtm);
798 }
799 
800 static void
_validate_message_sockaddrs(char * buffer,int rtm_len,size_t offset,int rtm_addrs)801 _validate_message_sockaddrs(char *buffer, int rtm_len, size_t offset, int rtm_addrs)
802 {
803 	struct sockaddr *sa;
804 	size_t parsed_len = offset;
805 
806 	/* Offset denotes initial header size */
807 	sa = (struct sockaddr *)(buffer + offset);
808 
809 	for (int i = 0; i < RTAX_MAX; i++) {
810 		if ((rtm_addrs & (1 << i)) == 0)
811 			continue;
812 		parsed_len += SA_SIZE(sa);
813 		RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len <= rtm_len,
814 		    "SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, rtm_len);
815 		if (sa->sa_family == AF_LINK) {
816 			struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
817 			int data_len = sdl->sdl_nlen + sdl->sdl_alen;
818 			data_len += offsetof(struct sockaddr_dl, sdl_data);
819 
820 			RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer,
821 			    data_len <= rtm_len,
822 			    "AF_LINK data size exceeds total len: %u vs %u, nlen=%d alen=%d",
823 			    data_len, rtm_len, sdl->sdl_nlen, sdl->sdl_alen);
824 		}
825 		sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
826 	}
827 }
828 
829 /*
830  * Raises error if base syntax checks fails.
831  */
832 void
rtsock_validate_message(char * buffer,ssize_t len)833 rtsock_validate_message(char *buffer, ssize_t len)
834 {
835 	struct rt_msghdr *rtm;
836 
837 	ATF_REQUIRE_MSG(len > 0, "read() return %zd, error: %s", len, strerror(errno));
838 
839 	rtm = (struct rt_msghdr *)buffer;
840 	ATF_REQUIRE_MSG(rtm->rtm_version == RTM_VERSION, "unknown RTM_VERSION: expected %d got %d",
841 			RTM_VERSION, rtm->rtm_version);
842 	ATF_REQUIRE_MSG(rtm->rtm_msglen <= len, "wrong message length: expected %d got %d",
843 			(int)len, (int)rtm->rtm_msglen);
844 
845 	switch (rtm->rtm_type) {
846 	case RTM_GET:
847 	case RTM_ADD:
848 	case RTM_DELETE:
849 	case RTM_CHANGE:
850 		_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
851 		    sizeof(struct rt_msghdr), rtm->rtm_addrs);
852 		break;
853 	case RTM_DELADDR:
854 	case RTM_NEWADDR:
855 		_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
856 		    sizeof(struct ifa_msghdr), ((struct ifa_msghdr *)buffer)->ifam_addrs);
857 		break;
858 	}
859 }
860 
861 void
rtsock_validate_pid_ours(struct rt_msghdr * rtm)862 rtsock_validate_pid_ours(struct rt_msghdr *rtm)
863 {
864 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == getpid(), "expected pid %d, got %d",
865 	    getpid(), rtm->rtm_pid);
866 }
867 
868 void
rtsock_validate_pid_user(struct rt_msghdr * rtm)869 rtsock_validate_pid_user(struct rt_msghdr *rtm)
870 {
871 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid, got %d",
872 	    rtm->rtm_pid);
873 }
874 
875 void
rtsock_validate_pid_kernel(struct rt_msghdr * rtm)876 rtsock_validate_pid_kernel(struct rt_msghdr *rtm)
877 {
878 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == 0, "expected zero pid, got %d",
879 	    rtm->rtm_pid);
880 }
881 
882 #endif
883