xref: /freebsd/tests/sys/net/routing/rtsock_common.h (revision b3e76948)
1775dc861SAlexander V. Chernikov /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3775dc861SAlexander V. Chernikov  *
4775dc861SAlexander V. Chernikov  * Copyright (c) 2019 Alexander V. Chernikov
5775dc861SAlexander V. Chernikov  *
6775dc861SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
7775dc861SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
8775dc861SAlexander V. Chernikov  * are met:
9775dc861SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
10775dc861SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
11775dc861SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
12775dc861SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
13775dc861SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
14775dc861SAlexander V. Chernikov  *
15775dc861SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16775dc861SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17775dc861SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18775dc861SAlexander V. Chernikov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19775dc861SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20775dc861SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21775dc861SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22775dc861SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23775dc861SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24775dc861SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25775dc861SAlexander V. Chernikov  * SUCH DAMAGE.
26775dc861SAlexander V. Chernikov  */
27775dc861SAlexander V. Chernikov 
28775dc861SAlexander V. Chernikov #ifndef _NET_ROUTING_RTSOCK_COMMON_H_
29775dc861SAlexander V. Chernikov #define _NET_ROUTING_RTSOCK_COMMON_H_
30775dc861SAlexander V. Chernikov 
31775dc861SAlexander V. Chernikov #include <stdio.h>
32775dc861SAlexander V. Chernikov #include <stdlib.h>
33775dc861SAlexander V. Chernikov #include <string.h>
34775dc861SAlexander V. Chernikov #include <unistd.h>
35775dc861SAlexander V. Chernikov #include <fcntl.h>
36775dc861SAlexander V. Chernikov #include <stdbool.h>
37775dc861SAlexander V. Chernikov #include <ctype.h>
38e02d3fe7SAlexander V. Chernikov #include <poll.h>
39775dc861SAlexander V. Chernikov 
40775dc861SAlexander V. Chernikov #include <sys/types.h>
41775dc861SAlexander V. Chernikov #include <sys/time.h>
42775dc861SAlexander V. Chernikov #include <sys/param.h>
43775dc861SAlexander V. Chernikov #include <sys/socket.h>
44775dc861SAlexander V. Chernikov #include <sys/ioctl.h>
45ddc75076SAlexander V. Chernikov #include <sys/jail.h>
4686686423SOlivier Cochard #include <sys/linker.h>
47775dc861SAlexander V. Chernikov #include <net/if.h>
48775dc861SAlexander V. Chernikov #include <net/if_dl.h>
49775dc861SAlexander V. Chernikov #include <net/route.h>
50775dc861SAlexander V. Chernikov 
51775dc861SAlexander V. Chernikov #include <arpa/inet.h>
52775dc861SAlexander V. Chernikov #include <net/ethernet.h>
53775dc861SAlexander V. Chernikov 
54775dc861SAlexander V. Chernikov #include <netinet/in.h>
55775dc861SAlexander V. Chernikov #include <netinet6/in6_var.h>
56775dc861SAlexander V. Chernikov #include <netinet6/nd6.h>
57775dc861SAlexander V. Chernikov 
58775dc861SAlexander V. Chernikov #include <ifaddrs.h>
59775dc861SAlexander V. Chernikov 
60775dc861SAlexander V. Chernikov #include <errno.h>
61775dc861SAlexander V. Chernikov #include <err.h>
62775dc861SAlexander V. Chernikov #include <sysexits.h>
63775dc861SAlexander V. Chernikov 
64775dc861SAlexander V. Chernikov #include <atf-c.h>
6586686423SOlivier Cochard #include "freebsd_test_suite/macros.h"
66775dc861SAlexander V. Chernikov 
67775dc861SAlexander V. Chernikov #include "rtsock_print.h"
68ddc75076SAlexander V. Chernikov #include "params.h"
69775dc861SAlexander V. Chernikov 
70775dc861SAlexander V. Chernikov void rtsock_update_rtm_len(struct rt_msghdr *rtm);
71775dc861SAlexander V. Chernikov void rtsock_validate_message(char *buffer, ssize_t len);
72775dc861SAlexander V. Chernikov void rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa);
73775dc861SAlexander V. Chernikov 
74272bd698SAlexander V. Chernikov void file_append_line(char *fname, char *text);
75272bd698SAlexander V. Chernikov 
76775dc861SAlexander V. Chernikov static int _rtm_seq = 42;
77775dc861SAlexander V. Chernikov 
78775dc861SAlexander V. Chernikov 
79775dc861SAlexander V. Chernikov /*
80775dc861SAlexander V. Chernikov  * Checks if the interface cloner module is present for @name.
81775dc861SAlexander V. Chernikov  */
82775dc861SAlexander V. Chernikov static int
_check_cloner(char * name)83775dc861SAlexander V. Chernikov _check_cloner(char *name)
84775dc861SAlexander V. Chernikov {
85775dc861SAlexander V. Chernikov 	struct if_clonereq ifcr;
86775dc861SAlexander V. Chernikov 	char *cp, *buf;
87775dc861SAlexander V. Chernikov 	int idx;
88775dc861SAlexander V. Chernikov 	int s;
89775dc861SAlexander V. Chernikov 	int found = 0;
90775dc861SAlexander V. Chernikov 
91775dc861SAlexander V. Chernikov 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
92775dc861SAlexander V. Chernikov 	if (s == -1)
93775dc861SAlexander V. Chernikov 		err(1, "socket(AF_LOCAL,SOCK_DGRAM)");
94775dc861SAlexander V. Chernikov 
95775dc861SAlexander V. Chernikov 	memset(&ifcr, 0, sizeof(ifcr));
96775dc861SAlexander V. Chernikov 
97775dc861SAlexander V. Chernikov 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
98775dc861SAlexander V. Chernikov 		err(1, "SIOCIFGCLONERS for count");
99775dc861SAlexander V. Chernikov 
100775dc861SAlexander V. Chernikov 	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
101775dc861SAlexander V. Chernikov 	if (buf == NULL)
102775dc861SAlexander V. Chernikov 		err(1, "unable to allocate cloner name buffer");
103775dc861SAlexander V. Chernikov 
104775dc861SAlexander V. Chernikov 	ifcr.ifcr_count = ifcr.ifcr_total;
105775dc861SAlexander V. Chernikov 	ifcr.ifcr_buffer = buf;
106775dc861SAlexander V. Chernikov 
107775dc861SAlexander V. Chernikov 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
108775dc861SAlexander V. Chernikov 		err(1, "SIOCIFGCLONERS for names");
109775dc861SAlexander V. Chernikov 
110775dc861SAlexander V. Chernikov 	/*
111775dc861SAlexander V. Chernikov 	 * In case some disappeared in the mean time, clamp it down.
112775dc861SAlexander V. Chernikov 	 */
113775dc861SAlexander V. Chernikov 	if (ifcr.ifcr_count > ifcr.ifcr_total)
114775dc861SAlexander V. Chernikov 		ifcr.ifcr_count = ifcr.ifcr_total;
115775dc861SAlexander V. Chernikov 
116775dc861SAlexander V. Chernikov 	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
117775dc861SAlexander V. Chernikov 		if (!strcmp(cp, name)) {
118775dc861SAlexander V. Chernikov 			found = 1;
119775dc861SAlexander V. Chernikov 			break;
120775dc861SAlexander V. Chernikov 		}
121775dc861SAlexander V. Chernikov 	}
122775dc861SAlexander V. Chernikov 
123775dc861SAlexander V. Chernikov 	free(buf);
124775dc861SAlexander V. Chernikov 	close(s);
125775dc861SAlexander V. Chernikov 
126775dc861SAlexander V. Chernikov 	return (found);
127775dc861SAlexander V. Chernikov }
128775dc861SAlexander V. Chernikov 
129272bd698SAlexander V. Chernikov static char *
iface_create(char * ifname_orig)130272bd698SAlexander V. Chernikov iface_create(char *ifname_orig)
131775dc861SAlexander V. Chernikov {
132775dc861SAlexander V. Chernikov 	struct ifreq ifr;
133775dc861SAlexander V. Chernikov 	int s;
134272bd698SAlexander V. Chernikov 	char prefix[IFNAMSIZ], ifname[IFNAMSIZ], *result;
135775dc861SAlexander V. Chernikov 
136775dc861SAlexander V. Chernikov 	char *src, *dst;
137272bd698SAlexander V. Chernikov 	for (src = ifname_orig, dst = prefix; *src && isalpha(*src); src++)
138775dc861SAlexander V. Chernikov 		*dst++ = *src;
139775dc861SAlexander V. Chernikov 	*dst = '\0';
140775dc861SAlexander V. Chernikov 
141775dc861SAlexander V. Chernikov 	memset(&ifr, 0, sizeof(struct ifreq));
142775dc861SAlexander V. Chernikov 
143775dc861SAlexander V. Chernikov 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
144272bd698SAlexander V. Chernikov 	strlcpy(ifr.ifr_name, ifname_orig, sizeof(ifr.ifr_name));
145775dc861SAlexander V. Chernikov 
146775dc861SAlexander V. Chernikov 	RLOG("creating iface %s %s", prefix, ifr.ifr_name);
147775dc861SAlexander V. Chernikov 	if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
148775dc861SAlexander V. Chernikov 		err(1, "SIOCIFCREATE2");
149775dc861SAlexander V. Chernikov 
150272bd698SAlexander V. Chernikov 	strlcpy(ifname, ifr.ifr_name, IFNAMSIZ);
151272bd698SAlexander V. Chernikov 	RLOG("created interface %s", ifname);
152775dc861SAlexander V. Chernikov 
153272bd698SAlexander V. Chernikov 	result = strdup(ifname);
154272bd698SAlexander V. Chernikov 
155272bd698SAlexander V. Chernikov 	file_append_line(IFACES_FNAME, ifname);
156272bd698SAlexander V. Chernikov 	if (strstr(ifname, "epair") == ifname) {
157272bd698SAlexander V. Chernikov 		/* call returned epairXXXa, need to add epairXXXb */
158272bd698SAlexander V. Chernikov 		ifname[strlen(ifname) - 1] = 'b';
159272bd698SAlexander V. Chernikov 		file_append_line(IFACES_FNAME, ifname);
160272bd698SAlexander V. Chernikov 	}
161272bd698SAlexander V. Chernikov 
162272bd698SAlexander V. Chernikov 	return (result);
163775dc861SAlexander V. Chernikov }
164775dc861SAlexander V. Chernikov 
165775dc861SAlexander V. Chernikov static int
iface_destroy(char * ifname)166775dc861SAlexander V. Chernikov iface_destroy(char *ifname)
167775dc861SAlexander V. Chernikov {
168775dc861SAlexander V. Chernikov 	struct ifreq ifr;
169775dc861SAlexander V. Chernikov 	int s;
170775dc861SAlexander V. Chernikov 
171775dc861SAlexander V. Chernikov 	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
172775dc861SAlexander V. Chernikov 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
173775dc861SAlexander V. Chernikov 
174775dc861SAlexander V. Chernikov 	RLOG("destroying interface %s", ifname);
175775dc861SAlexander V. Chernikov 	if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
176775dc861SAlexander V. Chernikov 		return (0);
177775dc861SAlexander V. Chernikov 
178775dc861SAlexander V. Chernikov 	return (1);
179775dc861SAlexander V. Chernikov }
180775dc861SAlexander V. Chernikov 
181775dc861SAlexander V. Chernikov /*
182775dc861SAlexander V. Chernikov  * Open tunneling device such as tuntap and returns fd.
183775dc861SAlexander V. Chernikov  */
184775dc861SAlexander V. Chernikov int
iface_open(char * ifname)185775dc861SAlexander V. Chernikov iface_open(char *ifname)
186775dc861SAlexander V. Chernikov {
187775dc861SAlexander V. Chernikov 	char path[256];
188775dc861SAlexander V. Chernikov 
189775dc861SAlexander V. Chernikov 	snprintf(path, sizeof(path), "/dev/%s", ifname);
190775dc861SAlexander V. Chernikov 
191775dc861SAlexander V. Chernikov 	RLOG("opening interface %s", ifname);
192775dc861SAlexander V. Chernikov 	int fd = open(path, O_RDWR|O_EXCL);
193775dc861SAlexander V. Chernikov 	if (fd == -1) {
194775dc861SAlexander V. Chernikov 		RLOG_ERRNO("unable to open interface %s", ifname);
195775dc861SAlexander V. Chernikov 		return (-1);
196775dc861SAlexander V. Chernikov 	}
197775dc861SAlexander V. Chernikov 
198775dc861SAlexander V. Chernikov 	return (fd);
199775dc861SAlexander V. Chernikov }
200775dc861SAlexander V. Chernikov 
201775dc861SAlexander V. Chernikov /*
202775dc861SAlexander V. Chernikov  * Sets primary IPv4 addr.
203775dc861SAlexander V. Chernikov  * Returns 0 on success.
204775dc861SAlexander V. Chernikov  */
205967348a9SDimitry Andric static inline int
iface_setup_addr(char * ifname,char * addr,int plen)206775dc861SAlexander V. Chernikov iface_setup_addr(char *ifname, char *addr, int plen)
207775dc861SAlexander V. Chernikov {
208775dc861SAlexander V. Chernikov 	char cmd[512];
209775dc861SAlexander V. Chernikov 	char *af;
210775dc861SAlexander V. Chernikov 
211775dc861SAlexander V. Chernikov 	if (strchr(addr, ':'))
212775dc861SAlexander V. Chernikov 		af = "inet6";
213775dc861SAlexander V. Chernikov 	else
214775dc861SAlexander V. Chernikov 		af = "inet";
215775dc861SAlexander V. Chernikov 	RLOG("setting af_%s %s/%d on %s", af, addr, plen, ifname);
216775dc861SAlexander V. Chernikov 	snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s %s %s/%d", ifname,
217775dc861SAlexander V. Chernikov 		af, addr, plen);
218775dc861SAlexander V. Chernikov 
219775dc861SAlexander V. Chernikov 	return system(cmd);
220775dc861SAlexander V. Chernikov }
221775dc861SAlexander V. Chernikov 
222775dc861SAlexander V. Chernikov /*
223775dc861SAlexander V. Chernikov  * Removes primary IPv4 prefix.
224775dc861SAlexander V. Chernikov  * Returns 0 on success.
225775dc861SAlexander V. Chernikov  */
226967348a9SDimitry Andric static inline int
iface_delete_addr(char * ifname,char * addr)227775dc861SAlexander V. Chernikov iface_delete_addr(char *ifname, char *addr)
228775dc861SAlexander V. Chernikov {
229775dc861SAlexander V. Chernikov 	char cmd[512];
230775dc861SAlexander V. Chernikov 
231775dc861SAlexander V. Chernikov 	if (strchr(addr, ':')) {
232775dc861SAlexander V. Chernikov 		RLOG("removing IPv6 %s from %s", addr, ifname);
233775dc861SAlexander V. Chernikov 		snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s inet6 %s delete", ifname, addr);
234775dc861SAlexander V. Chernikov 	} else {
235775dc861SAlexander V. Chernikov 		RLOG("removing IPv4 %s from %s", addr, ifname);
236775dc861SAlexander V. Chernikov 		snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s -alias %s", ifname, addr);
237775dc861SAlexander V. Chernikov 	}
238775dc861SAlexander V. Chernikov 
239775dc861SAlexander V. Chernikov 	return system(cmd);
240775dc861SAlexander V. Chernikov }
241775dc861SAlexander V. Chernikov 
242775dc861SAlexander V. Chernikov int
iface_turn_up(char * ifname)243775dc861SAlexander V. Chernikov iface_turn_up(char *ifname)
244775dc861SAlexander V. Chernikov {
245775dc861SAlexander V. Chernikov 	struct ifreq ifr;
246775dc861SAlexander V. Chernikov 	int s;
247775dc861SAlexander V. Chernikov 
248775dc861SAlexander V. Chernikov 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
249775dc861SAlexander V. Chernikov 		RLOG_ERRNO("socket");
250775dc861SAlexander V. Chernikov 		return (-1);
251775dc861SAlexander V. Chernikov 	}
252775dc861SAlexander V. Chernikov 	memset(&ifr, 0, sizeof(struct ifreq));
253775dc861SAlexander V. Chernikov 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
254775dc861SAlexander V. Chernikov 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
255775dc861SAlexander V. Chernikov 		RLOG_ERRNO("ioctl(SIOCGIFFLAGS)");
256775dc861SAlexander V. Chernikov 		return (-1);
257775dc861SAlexander V. Chernikov 	}
258775dc861SAlexander V. Chernikov 	/* Update flags */
259775dc861SAlexander V. Chernikov 	if ((ifr.ifr_flags & IFF_UP) == 0) {
260775dc861SAlexander V. Chernikov 		ifr.ifr_flags |= IFF_UP;
261775dc861SAlexander V. Chernikov 		if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
262775dc861SAlexander V. Chernikov 			RLOG_ERRNO("ioctl(SIOSGIFFLAGS)");
263775dc861SAlexander V. Chernikov 			return (-1);
264775dc861SAlexander V. Chernikov 		}
265775dc861SAlexander V. Chernikov 		RLOG("turned interface %s up", ifname);
266775dc861SAlexander V. Chernikov 	}
267775dc861SAlexander V. Chernikov 
268775dc861SAlexander V. Chernikov 	return (0);
269775dc861SAlexander V. Chernikov }
270775dc861SAlexander V. Chernikov 
271775dc861SAlexander V. Chernikov /*
272775dc861SAlexander V. Chernikov  * Removes ND6_IFF_IFDISABLED from IPv6 interface flags.
273775dc861SAlexander V. Chernikov  * Returns 0 on success.
274775dc861SAlexander V. Chernikov  */
275775dc861SAlexander V. Chernikov int
iface_enable_ipv6(char * ifname)276775dc861SAlexander V. Chernikov iface_enable_ipv6(char *ifname)
277775dc861SAlexander V. Chernikov {
278775dc861SAlexander V. Chernikov 	struct in6_ndireq nd;
279775dc861SAlexander V. Chernikov 	int s;
280775dc861SAlexander V. Chernikov 
281775dc861SAlexander V. Chernikov 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
282775dc861SAlexander V. Chernikov 		err(1, "socket");
283775dc861SAlexander V. Chernikov 	}
284775dc861SAlexander V. Chernikov 	memset(&nd, 0, sizeof(nd));
285775dc861SAlexander V. Chernikov 	strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
286775dc861SAlexander V. Chernikov 	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
287775dc861SAlexander V. Chernikov 		RLOG_ERRNO("ioctl(SIOCGIFINFO_IN6)");
288775dc861SAlexander V. Chernikov 		return (-1);
289775dc861SAlexander V. Chernikov 	}
290775dc861SAlexander V. Chernikov 	/* Update flags */
291775dc861SAlexander V. Chernikov 	if ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0) {
292775dc861SAlexander V. Chernikov 		nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
293775dc861SAlexander V. Chernikov 		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
294775dc861SAlexander V. Chernikov 			RLOG_ERRNO("ioctl(SIOCSIFINFO_IN6)");
295775dc861SAlexander V. Chernikov 			return (-1);
296775dc861SAlexander V. Chernikov 		}
297775dc861SAlexander V. Chernikov 		RLOG("enabled IPv6 for %s", ifname);
298775dc861SAlexander V. Chernikov 	}
299775dc861SAlexander V. Chernikov 
300775dc861SAlexander V. Chernikov 	return (0);
301775dc861SAlexander V. Chernikov }
302775dc861SAlexander V. Chernikov 
303ddc75076SAlexander V. Chernikov void
file_append_line(char * fname,char * text)304ddc75076SAlexander V. Chernikov file_append_line(char *fname, char *text)
305ddc75076SAlexander V. Chernikov {
306ddc75076SAlexander V. Chernikov 	FILE *f;
307ddc75076SAlexander V. Chernikov 
308ddc75076SAlexander V. Chernikov 	f = fopen(fname, "a");
309ddc75076SAlexander V. Chernikov 	fputs(text, f);
310ddc75076SAlexander V. Chernikov 	fputs("\n", f);
311ddc75076SAlexander V. Chernikov 	fclose(f);
312ddc75076SAlexander V. Chernikov }
313ddc75076SAlexander V. Chernikov 
314ddc75076SAlexander V. Chernikov static int
vnet_wait_interface(char * vnet_name,char * ifname)315ddc75076SAlexander V. Chernikov vnet_wait_interface(char *vnet_name, char *ifname)
316ddc75076SAlexander V. Chernikov {
317ddc75076SAlexander V. Chernikov 	char buf[512], cmd[512], *line, *token;
318ddc75076SAlexander V. Chernikov 	FILE *fp;
319ddc75076SAlexander V. Chernikov 	int i;
320ddc75076SAlexander V. Chernikov 
321ddc75076SAlexander V. Chernikov 	snprintf(cmd, sizeof(cmd), "/usr/sbin/jexec %s /sbin/ifconfig -l", vnet_name);
322ddc75076SAlexander V. Chernikov 	for (int i = 0; i < 50; i++) {
323ddc75076SAlexander V. Chernikov 		fp = popen(cmd, "r");
324ddc75076SAlexander V. Chernikov 		line = fgets(buf, sizeof(buf), fp);
325ddc75076SAlexander V. Chernikov 		/* cut last\n */
326ddc75076SAlexander V. Chernikov 		if (line[0])
327ddc75076SAlexander V. Chernikov 			line[strlen(line)-1] = '\0';
328ddc75076SAlexander V. Chernikov 		while ((token = strsep(&line, " ")) != NULL) {
329ddc75076SAlexander V. Chernikov 			if (strcmp(token, ifname) == 0)
330ddc75076SAlexander V. Chernikov 				return (1);
331ddc75076SAlexander V. Chernikov 		}
332ddc75076SAlexander V. Chernikov 
333ddc75076SAlexander V. Chernikov 		/* sleep 100ms */
334ddc75076SAlexander V. Chernikov 		usleep(1000 * 100);
335ddc75076SAlexander V. Chernikov 	}
336ddc75076SAlexander V. Chernikov 
337ddc75076SAlexander V. Chernikov 	return (0);
338ddc75076SAlexander V. Chernikov }
339ddc75076SAlexander V. Chernikov 
340ddc75076SAlexander V. Chernikov void
vnet_switch(char * vnet_name,char ** ifnames,int count)341272bd698SAlexander V. Chernikov vnet_switch(char *vnet_name, char **ifnames, int count)
342ddc75076SAlexander V. Chernikov {
343ddc75076SAlexander V. Chernikov 	char buf[512], cmd[512], *line;
344ddc75076SAlexander V. Chernikov 	FILE *fp;
345272bd698SAlexander V. Chernikov 	int jid, len, ret;
346ddc75076SAlexander V. Chernikov 
347272bd698SAlexander V. Chernikov 	RLOG("switching to vnet %s with interface(s) %s", vnet_name, ifnames[0]);
348272bd698SAlexander V. Chernikov 	len = snprintf(cmd, sizeof(cmd),
349272bd698SAlexander V. Chernikov 	    "/usr/sbin/jail -i -c name=%s persist vnet", vnet_name);
350272bd698SAlexander V. Chernikov 	for (int i = 0; i < count && len < sizeof(cmd); i++) {
351272bd698SAlexander V. Chernikov 		len += snprintf(&cmd[len], sizeof(cmd) - len,
352272bd698SAlexander V. Chernikov 		    " vnet.interface=%s", ifnames[i]);
353272bd698SAlexander V. Chernikov 	}
354ddc75076SAlexander V. Chernikov 	RLOG("jail cmd: \"%s\"\n", cmd);
355ddc75076SAlexander V. Chernikov 
356ddc75076SAlexander V. Chernikov 	fp = popen(cmd, "r");
357ddc75076SAlexander V. Chernikov 	if (fp == NULL)
358ddc75076SAlexander V. Chernikov 		atf_tc_fail("jail creation failed");
359ddc75076SAlexander V. Chernikov 	line = fgets(buf, sizeof(buf), fp);
360ddc75076SAlexander V. Chernikov 	if (line == NULL)
361ddc75076SAlexander V. Chernikov 		atf_tc_fail("empty output from jail(8)");
362ddc75076SAlexander V. Chernikov 	jid = strtol(line, NULL, 10);
363ddc75076SAlexander V. Chernikov 	if (jid <= 0) {
364ddc75076SAlexander V. Chernikov 		atf_tc_fail("invalid jail output: %s", line);
365ddc75076SAlexander V. Chernikov 	}
366ddc75076SAlexander V. Chernikov 
367ddc75076SAlexander V. Chernikov 	RLOG("created jail jid=%d", jid);
368ddc75076SAlexander V. Chernikov 	file_append_line(JAILS_FNAME, vnet_name);
369ddc75076SAlexander V. Chernikov 
370ddc75076SAlexander V. Chernikov 	/* Wait while interface appearsh inside vnet */
371272bd698SAlexander V. Chernikov 	for (int i = 0; i < count; i++) {
372272bd698SAlexander V. Chernikov 		if (vnet_wait_interface(vnet_name, ifnames[i]))
373272bd698SAlexander V. Chernikov 			continue;
374272bd698SAlexander V. Chernikov 		atf_tc_fail("unable to move interface %s to jail %s",
375272bd698SAlexander V. Chernikov 		    ifnames[i], vnet_name);
376ddc75076SAlexander V. Chernikov 	}
377ddc75076SAlexander V. Chernikov 
378ddc75076SAlexander V. Chernikov 	if (jail_attach(jid) == -1) {
379ddc75076SAlexander V. Chernikov 		RLOG_ERRNO("jail %s attach failed: ret=%d", vnet_name, errno);
380ddc75076SAlexander V. Chernikov 		atf_tc_fail("jail attach failed");
381ddc75076SAlexander V. Chernikov 	}
382ddc75076SAlexander V. Chernikov 
383ddc75076SAlexander V. Chernikov 	RLOG("attached to the jail");
384ddc75076SAlexander V. Chernikov }
385ddc75076SAlexander V. Chernikov 
386272bd698SAlexander V. Chernikov void
vnet_switch_one(char * vnet_name,char * ifname)387272bd698SAlexander V. Chernikov vnet_switch_one(char *vnet_name, char *ifname)
388272bd698SAlexander V. Chernikov {
389272bd698SAlexander V. Chernikov 	char *ifnames[1];
390272bd698SAlexander V. Chernikov 
391272bd698SAlexander V. Chernikov 	ifnames[0] = ifname;
392272bd698SAlexander V. Chernikov 	vnet_switch(vnet_name, ifnames, 1);
393272bd698SAlexander V. Chernikov }
394272bd698SAlexander V. Chernikov 
395ddc75076SAlexander V. Chernikov 
396775dc861SAlexander V. Chernikov #define	SA_F_IGNORE_IFNAME	0x01
397775dc861SAlexander V. Chernikov #define	SA_F_IGNORE_IFTYPE	0x02
398775dc861SAlexander V. Chernikov #define	SA_F_IGNORE_MEMCMP	0x04
399775dc861SAlexander V. Chernikov int
sa_equal_msg_flags(const struct sockaddr * a,const struct sockaddr * b,char * msg,size_t sz,int flags)400775dc861SAlexander V. Chernikov sa_equal_msg_flags(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz, int flags)
401775dc861SAlexander V. Chernikov {
402775dc861SAlexander V. Chernikov 	char a_s[64], b_s[64];
403775dc861SAlexander V. Chernikov 	const struct sockaddr_in *a4, *b4;
404775dc861SAlexander V. Chernikov 	const struct sockaddr_in6 *a6, *b6;
405775dc861SAlexander V. Chernikov 	const struct sockaddr_dl *al, *bl;
406775dc861SAlexander V. Chernikov 
407775dc861SAlexander V. Chernikov 	if (a == NULL) {
408775dc861SAlexander V. Chernikov 		snprintf(msg, sz, "first sa is NULL");
409775dc861SAlexander V. Chernikov 		return 0;
410775dc861SAlexander V. Chernikov 	}
411775dc861SAlexander V. Chernikov 	if (b == NULL) {
412775dc861SAlexander V. Chernikov 		snprintf(msg, sz, "second sa is NULL");
413775dc861SAlexander V. Chernikov 		return 0;
414775dc861SAlexander V. Chernikov 	}
415775dc861SAlexander V. Chernikov 
416775dc861SAlexander V. Chernikov 	if (a->sa_family != b->sa_family) {
417775dc861SAlexander V. Chernikov 		snprintf(msg, sz, "family: %d vs %d", a->sa_family, b->sa_family);
418775dc861SAlexander V. Chernikov 		return 0;
419775dc861SAlexander V. Chernikov 	}
420775dc861SAlexander V. Chernikov 	if (a->sa_len != b->sa_len) {
421775dc861SAlexander V. Chernikov 		snprintf(msg, sz, "len: %d vs %d", a->sa_len, b->sa_len);
422775dc861SAlexander V. Chernikov 		return 0;
423775dc861SAlexander V. Chernikov 	}
424775dc861SAlexander V. Chernikov 
425775dc861SAlexander V. Chernikov 	switch (a->sa_family) {
426775dc861SAlexander V. Chernikov 	case AF_INET:
427775dc861SAlexander V. Chernikov 		a4 = (const struct sockaddr_in *)a;
428775dc861SAlexander V. Chernikov 		b4 = (const struct sockaddr_in *)b;
429775dc861SAlexander V. Chernikov 		if (a4->sin_addr.s_addr != b4->sin_addr.s_addr) {
430775dc861SAlexander V. Chernikov 			inet_ntop(AF_INET, &a4->sin_addr, a_s, sizeof(a_s));
431775dc861SAlexander V. Chernikov 			inet_ntop(AF_INET, &b4->sin_addr, b_s, sizeof(b_s));
432775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
433775dc861SAlexander V. Chernikov 			return 0;
434775dc861SAlexander V. Chernikov 		}
435775dc861SAlexander V. Chernikov 		if (a4->sin_port != b4->sin_port) {
436775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "port diff: %d vs %d",
437775dc861SAlexander V. Chernikov 					ntohs(a4->sin_port), ntohs(b4->sin_port));
438775dc861SAlexander V. Chernikov 			//return 0;
439775dc861SAlexander V. Chernikov 		}
440775dc861SAlexander V. Chernikov 		const uint32_t *a32, *b32;
441775dc861SAlexander V. Chernikov 		a32 = (const uint32_t *)a4->sin_zero;
442775dc861SAlexander V. Chernikov 		b32 = (const uint32_t *)b4->sin_zero;
443775dc861SAlexander V. Chernikov 		if ((*a32 != *b32) || (*(a32 + 1) != *(b32 + 1))) {
444775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "zero diff: 0x%08X%08X vs 0x%08X%08X",
445775dc861SAlexander V. Chernikov 					ntohl(*a32), ntohl(*(a32 + 1)),
446775dc861SAlexander V. Chernikov 					ntohl(*b32), ntohl(*(b32 + 1)));
447775dc861SAlexander V. Chernikov 			return 0;
448775dc861SAlexander V. Chernikov 		}
449775dc861SAlexander V. Chernikov 		return 1;
450775dc861SAlexander V. Chernikov 	case AF_INET6:
451775dc861SAlexander V. Chernikov 		a6 = (const struct sockaddr_in6 *)a;
452775dc861SAlexander V. Chernikov 		b6 = (const struct sockaddr_in6 *)b;
453775dc861SAlexander V. Chernikov 		if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr)) {
454775dc861SAlexander V. Chernikov 			inet_ntop(AF_INET6, &a6->sin6_addr, a_s, sizeof(a_s));
45537c0f4a2SAlexander V. Chernikov 			inet_ntop(AF_INET6, &b6->sin6_addr, b_s, sizeof(b_s));
456775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
457775dc861SAlexander V. Chernikov 			return 0;
458775dc861SAlexander V. Chernikov 		}
459775dc861SAlexander V. Chernikov 		if (a6->sin6_scope_id != b6->sin6_scope_id) {
460775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "scope diff: %u vs %u", a6->sin6_scope_id, b6->sin6_scope_id);
461775dc861SAlexander V. Chernikov 			return 0;
462775dc861SAlexander V. Chernikov 		}
463775dc861SAlexander V. Chernikov 		break;
464775dc861SAlexander V. Chernikov 	case AF_LINK:
465775dc861SAlexander V. Chernikov 		al = (const struct sockaddr_dl *)a;
466775dc861SAlexander V. Chernikov 		bl = (const struct sockaddr_dl *)b;
467775dc861SAlexander V. Chernikov 
468775dc861SAlexander V. Chernikov 		if (al->sdl_index != bl->sdl_index) {
469775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "sdl_index diff: %u vs %u", al->sdl_index, bl->sdl_index);
470775dc861SAlexander V. Chernikov 			return 0;
471775dc861SAlexander V. Chernikov 		}
472775dc861SAlexander V. Chernikov 
473775dc861SAlexander V. Chernikov 		if ((al->sdl_alen != bl->sdl_alen) || (memcmp(LLADDR(al), LLADDR(bl), al->sdl_alen) != 0)) {
474775dc861SAlexander V. Chernikov 			char abuf[64], bbuf[64];
475775dc861SAlexander V. Chernikov 			sa_print_hd(abuf, sizeof(abuf), LLADDR(al), al->sdl_alen);
476775dc861SAlexander V. Chernikov 			sa_print_hd(bbuf, sizeof(bbuf), LLADDR(bl), bl->sdl_alen);
477775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "sdl_alen diff: {%s} (%d) vs {%s} (%d)",
478775dc861SAlexander V. Chernikov 			    abuf, al->sdl_alen, bbuf, bl->sdl_alen);
479775dc861SAlexander V. Chernikov 			return 0;
480775dc861SAlexander V. Chernikov 		}
481775dc861SAlexander V. Chernikov 
482775dc861SAlexander V. Chernikov 		if (((flags & SA_F_IGNORE_IFTYPE) == 0) && (al->sdl_type != bl->sdl_type)) {
483775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "sdl_type diff: %u vs %u", al->sdl_type, bl->sdl_type);
484775dc861SAlexander V. Chernikov 			return 0;
485775dc861SAlexander V. Chernikov 		}
486775dc861SAlexander V. Chernikov 
487775dc861SAlexander V. Chernikov 		if (((flags & SA_F_IGNORE_IFNAME) == 0) && ((al->sdl_nlen != bl->sdl_nlen) ||
488775dc861SAlexander V. Chernikov 			    (memcmp(al->sdl_data, bl->sdl_data, al->sdl_nlen) != 0))) {
489775dc861SAlexander V. Chernikov 			char abuf[64], bbuf[64];
490775dc861SAlexander V. Chernikov 			memcpy(abuf, al->sdl_data, al->sdl_nlen);
491775dc861SAlexander V. Chernikov 			abuf[al->sdl_nlen] = '\0';
492775dc861SAlexander V. Chernikov 			memcpy(bbuf, bl->sdl_data, bl->sdl_nlen);
493775dc861SAlexander V. Chernikov 			abuf[bl->sdl_nlen] = '\0';
494775dc861SAlexander V. Chernikov 			snprintf(msg, sz, "sdl_nlen diff: {%s} (%d) vs {%s} (%d)",
495775dc861SAlexander V. Chernikov 			    abuf, al->sdl_nlen, bbuf, bl->sdl_nlen);
496775dc861SAlexander V. Chernikov 			return 0;
497775dc861SAlexander V. Chernikov 		}
498775dc861SAlexander V. Chernikov 
499775dc861SAlexander V. Chernikov 		if (flags & SA_F_IGNORE_MEMCMP)
500775dc861SAlexander V. Chernikov 			return 1;
501775dc861SAlexander V. Chernikov 		break;
502775dc861SAlexander V. Chernikov 	}
503775dc861SAlexander V. Chernikov 
504775dc861SAlexander V. Chernikov 	if (memcmp(a, b, a->sa_len)) {
505775dc861SAlexander V. Chernikov 		int i;
506775dc861SAlexander V. Chernikov 		for (i = 0; i < a->sa_len; i++)
507775dc861SAlexander V. Chernikov 			if (((const char *)a)[i] != ((const char *)b)[i])
508775dc861SAlexander V. Chernikov 				break;
509775dc861SAlexander V. Chernikov 
510775dc861SAlexander V. Chernikov 		sa_print(a, 1);
511775dc861SAlexander V. Chernikov 		sa_print(b, 1);
512775dc861SAlexander V. Chernikov 
513775dc861SAlexander V. Chernikov 		snprintf(msg, sz, "overall memcmp() reports diff for af %d offset %d",
514775dc861SAlexander V. Chernikov 				a->sa_family, i);
515775dc861SAlexander V. Chernikov 		return 0;
516775dc861SAlexander V. Chernikov 	}
517775dc861SAlexander V. Chernikov 	return 1;
518775dc861SAlexander V. Chernikov }
519775dc861SAlexander V. Chernikov 
520775dc861SAlexander V. Chernikov int
sa_equal_msg(const struct sockaddr * a,const struct sockaddr * b,char * msg,size_t sz)521775dc861SAlexander V. Chernikov sa_equal_msg(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz)
522775dc861SAlexander V. Chernikov {
523775dc861SAlexander V. Chernikov 
524775dc861SAlexander V. Chernikov 	return sa_equal_msg_flags(a, b, msg, sz, 0);
525775dc861SAlexander V. Chernikov }
526775dc861SAlexander V. Chernikov 
527775dc861SAlexander V. Chernikov void
sa_fill_mask4(struct sockaddr_in * sin,int plen)528775dc861SAlexander V. Chernikov sa_fill_mask4(struct sockaddr_in *sin, int plen)
529775dc861SAlexander V. Chernikov {
530775dc861SAlexander V. Chernikov 
531775dc861SAlexander V. Chernikov 	memset(sin, 0, sizeof(struct sockaddr_in));
532775dc861SAlexander V. Chernikov 	sin->sin_family = AF_INET;
533775dc861SAlexander V. Chernikov 	sin->sin_len = sizeof(struct sockaddr_in);
534775dc861SAlexander V. Chernikov 	sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
535775dc861SAlexander V. Chernikov }
536775dc861SAlexander V. Chernikov 
537775dc861SAlexander V. Chernikov void
sa_fill_mask6(struct sockaddr_in6 * sin6,uint8_t mask)538775dc861SAlexander V. Chernikov sa_fill_mask6(struct sockaddr_in6 *sin6, uint8_t mask)
539775dc861SAlexander V. Chernikov {
540775dc861SAlexander V. Chernikov 	uint32_t *cp;
541775dc861SAlexander V. Chernikov 
542775dc861SAlexander V. Chernikov 	memset(sin6, 0, sizeof(struct sockaddr_in6));
543775dc861SAlexander V. Chernikov 	sin6->sin6_family = AF_INET6;
544775dc861SAlexander V. Chernikov 	sin6->sin6_len = sizeof(struct sockaddr_in6);
545775dc861SAlexander V. Chernikov 
546775dc861SAlexander V. Chernikov 	for (cp = (uint32_t *)&sin6->sin6_addr; mask >= 32; mask -= 32)
547775dc861SAlexander V. Chernikov 		*cp++ = 0xFFFFFFFF;
548775dc861SAlexander V. Chernikov 	if (mask > 0)
549775dc861SAlexander V. Chernikov 		*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
550775dc861SAlexander V. Chernikov }
551775dc861SAlexander V. Chernikov 
552775dc861SAlexander V. Chernikov /* 52:54:00:14:e3:10 */
553775dc861SAlexander V. Chernikov #define	ETHER_MAC_MAX_LENGTH	17
554775dc861SAlexander V. Chernikov 
555775dc861SAlexander V. Chernikov int
sa_convert_str_to_sa(const char * _addr,struct sockaddr * sa)556775dc861SAlexander V. Chernikov sa_convert_str_to_sa(const char *_addr, struct sockaddr *sa)
557775dc861SAlexander V. Chernikov {
558775dc861SAlexander V. Chernikov 	int error;
559775dc861SAlexander V. Chernikov 
560775dc861SAlexander V. Chernikov 	int af = AF_UNSPEC;
561775dc861SAlexander V. Chernikov 
562775dc861SAlexander V. Chernikov 	char *addr = strdup(_addr);
563775dc861SAlexander V. Chernikov 	int retcode = 0;
564775dc861SAlexander V. Chernikov 
565775dc861SAlexander V. Chernikov 	/* classify AF by str */
566775dc861SAlexander V. Chernikov 	if (strchr(addr, ':')) {
567775dc861SAlexander V. Chernikov 		/* inet6 or ether */
568775dc861SAlexander V. Chernikov 		char *k;
569775dc861SAlexander V. Chernikov 		int delim_cnt = 0;
570775dc861SAlexander V. Chernikov 		for (k = addr; *k; k++)
571775dc861SAlexander V. Chernikov 			if (*k == ':')
572775dc861SAlexander V. Chernikov 				delim_cnt++;
573775dc861SAlexander V. Chernikov 		af = AF_INET6;
574775dc861SAlexander V. Chernikov 
575775dc861SAlexander V. Chernikov 		if (delim_cnt == 5) {
576775dc861SAlexander V. Chernikov 			k = strchr(addr, '%');
577775dc861SAlexander V. Chernikov 			if (k != NULL && (k - addr) <= ETHER_MAC_MAX_LENGTH)
578775dc861SAlexander V. Chernikov 				af = AF_LINK;
579775dc861SAlexander V. Chernikov 		}
580775dc861SAlexander V. Chernikov 	} else if (strchr(addr, '.'))
581775dc861SAlexander V. Chernikov 		af = AF_INET;
582775dc861SAlexander V. Chernikov 
583775dc861SAlexander V. Chernikov 	/* */
584775dc861SAlexander V. Chernikov 	char *delimiter;
585775dc861SAlexander V. Chernikov 	int ifindex = 0;
586775dc861SAlexander V. Chernikov 	char *ifname = NULL;
587775dc861SAlexander V. Chernikov 	if ((delimiter = strchr(addr, '%')) != NULL) {
588775dc861SAlexander V. Chernikov 		*delimiter = '\0';
589775dc861SAlexander V. Chernikov 		ifname = delimiter + 1;
590775dc861SAlexander V. Chernikov 		ifindex = if_nametoindex(ifname);
591775dc861SAlexander V. Chernikov 		if (ifindex == 0)
592775dc861SAlexander V. Chernikov 			RLOG("unable to find ifindex for '%s'", ifname);
593775dc861SAlexander V. Chernikov 		else
594775dc861SAlexander V. Chernikov 			RLOG("if %s mapped to %d", ifname, ifindex);
595775dc861SAlexander V. Chernikov 	}
596775dc861SAlexander V. Chernikov 
597775dc861SAlexander V. Chernikov 	if (af == AF_INET6) {
598775dc861SAlexander V. Chernikov 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
599775dc861SAlexander V. Chernikov 		memset(sin6, 0, sizeof(struct sockaddr_in6));
600775dc861SAlexander V. Chernikov 		sin6->sin6_family = AF_INET6;
601775dc861SAlexander V. Chernikov 		sin6->sin6_len = sizeof(struct sockaddr_in6);
602775dc861SAlexander V. Chernikov 		sin6->sin6_scope_id = ifindex;
603775dc861SAlexander V. Chernikov 		error = inet_pton(AF_INET6, addr, &sin6->sin6_addr);
604775dc861SAlexander V. Chernikov 		if (error != 1)
605775dc861SAlexander V. Chernikov 			RLOG_ERRNO("inet_ntop() failed: ret=%d", error);
606775dc861SAlexander V. Chernikov 		else
607775dc861SAlexander V. Chernikov 			retcode = 1;
608775dc861SAlexander V. Chernikov 	} else if (af == AF_INET) {
609775dc861SAlexander V. Chernikov 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
610775dc861SAlexander V. Chernikov 		memset(sin, 0, sizeof(struct sockaddr_in));
611775dc861SAlexander V. Chernikov 		sin->sin_family = AF_INET;
612775dc861SAlexander V. Chernikov 		sin->sin_len = sizeof(struct sockaddr_in);
613775dc861SAlexander V. Chernikov 		error = inet_pton(AF_INET, addr, &sin->sin_addr);
614775dc861SAlexander V. Chernikov 		if (error != 1)
615775dc861SAlexander V. Chernikov 			RLOG("inet_ntop() failed: ret=%d", error);
616775dc861SAlexander V. Chernikov 		else
617775dc861SAlexander V. Chernikov 			retcode = 1;
618775dc861SAlexander V. Chernikov 	} else if (af == AF_LINK) {
619775dc861SAlexander V. Chernikov 		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
620775dc861SAlexander V. Chernikov 		memset(sdl, 0, sizeof(struct sockaddr_dl));
621775dc861SAlexander V. Chernikov 		sdl->sdl_family = AF_LINK;
622775dc861SAlexander V. Chernikov 		sdl->sdl_len = sizeof(struct sockaddr_dl);
623775dc861SAlexander V. Chernikov 		sdl->sdl_index = ifindex;
624775dc861SAlexander V. Chernikov 		sdl->sdl_alen = 6;
625775dc861SAlexander V. Chernikov 		struct ether_addr *ea = (struct ether_addr *)LLADDR(sdl);
626775dc861SAlexander V. Chernikov 		if (ether_aton_r(addr, ea) == NULL)
627775dc861SAlexander V. Chernikov 			RLOG("ether_aton() failed");
628775dc861SAlexander V. Chernikov 		else
629775dc861SAlexander V. Chernikov 			retcode = 1;
630775dc861SAlexander V. Chernikov 	}
631775dc861SAlexander V. Chernikov 
632775dc861SAlexander V. Chernikov 	return (retcode);
633775dc861SAlexander V. Chernikov }
634775dc861SAlexander V. Chernikov 
635775dc861SAlexander V. Chernikov 
636775dc861SAlexander V. Chernikov int
rtsock_setup_socket()637775dc861SAlexander V. Chernikov rtsock_setup_socket()
638775dc861SAlexander V. Chernikov {
639775dc861SAlexander V. Chernikov 	int fd;
640775dc861SAlexander V. Chernikov 	int af = AF_UNSPEC; /* 0 to capture messages from all AFs */
641775dc861SAlexander V. Chernikov 	fd = socket(PF_ROUTE, SOCK_RAW, af);
642775dc861SAlexander V. Chernikov 
643775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(fd != -1, "rtsock open failed: %s", strerror(errno));
644775dc861SAlexander V. Chernikov 
645775dc861SAlexander V. Chernikov 	/* Listen for our messages */
646775dc861SAlexander V. Chernikov 	int on = 1;
647775dc861SAlexander V. Chernikov 	if (setsockopt(fd, SOL_SOCKET,SO_USELOOPBACK, &on, sizeof(on)) < 0)
648775dc861SAlexander V. Chernikov 		RLOG_ERRNO("setsockopt failed");
649775dc861SAlexander V. Chernikov 
650775dc861SAlexander V. Chernikov 	return (fd);
651775dc861SAlexander V. Chernikov }
652775dc861SAlexander V. Chernikov 
653775dc861SAlexander V. Chernikov ssize_t
rtsock_send_rtm(int fd,struct rt_msghdr * rtm)654775dc861SAlexander V. Chernikov rtsock_send_rtm(int fd, struct rt_msghdr *rtm)
655775dc861SAlexander V. Chernikov {
656775dc861SAlexander V. Chernikov 	int my_errno;
657775dc861SAlexander V. Chernikov 	ssize_t len;
658775dc861SAlexander V. Chernikov 
659775dc861SAlexander V. Chernikov 	rtsock_update_rtm_len(rtm);
660775dc861SAlexander V. Chernikov 
661775dc861SAlexander V. Chernikov 	len = write(fd, rtm, rtm->rtm_msglen);
662775dc861SAlexander V. Chernikov 	my_errno = errno;
663775dc861SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, len == rtm->rtm_msglen,
664775dc861SAlexander V. Chernikov 	    "rtsock write failed: want %d got %zd (%s)",
665775dc861SAlexander V. Chernikov 	    rtm->rtm_msglen, len, strerror(my_errno));
666775dc861SAlexander V. Chernikov 
667775dc861SAlexander V. Chernikov 	return (len);
668775dc861SAlexander V. Chernikov }
669775dc861SAlexander V. Chernikov 
670775dc861SAlexander V. Chernikov struct rt_msghdr *
rtsock_read_rtm(int fd,char * buffer,size_t buflen)671775dc861SAlexander V. Chernikov rtsock_read_rtm(int fd, char *buffer, size_t buflen)
672775dc861SAlexander V. Chernikov {
673775dc861SAlexander V. Chernikov 	ssize_t len;
674e02d3fe7SAlexander V. Chernikov 	struct pollfd pfd;
675e02d3fe7SAlexander V. Chernikov 	int poll_delay = 5 * 1000; /* 5 seconds */
676e02d3fe7SAlexander V. Chernikov 
677e02d3fe7SAlexander V. Chernikov 	/* Check for the data available to read first */
678e02d3fe7SAlexander V. Chernikov 	memset(&pfd, 0, sizeof(pfd));
679e02d3fe7SAlexander V. Chernikov 	pfd.fd = fd;
680e02d3fe7SAlexander V. Chernikov 	pfd.events = POLLIN;
681e02d3fe7SAlexander V. Chernikov 
682e02d3fe7SAlexander V. Chernikov 	if (poll(&pfd, 1, poll_delay) == 0)
683e02d3fe7SAlexander V. Chernikov 		ATF_REQUIRE_MSG(1 == 0, "rtsock read timed out (%d seconds passed)",
684e02d3fe7SAlexander V. Chernikov 		    poll_delay / 1000);
685775dc861SAlexander V. Chernikov 
686775dc861SAlexander V. Chernikov 	len = read(fd, buffer, buflen);
687775dc861SAlexander V. Chernikov 	int my_errno = errno;
688775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(len > 0, "rtsock read failed: %s", strerror(my_errno));
689775dc861SAlexander V. Chernikov 
690775dc861SAlexander V. Chernikov 	rtsock_validate_message(buffer, len);
691775dc861SAlexander V. Chernikov 	return ((struct rt_msghdr *)buffer);
692775dc861SAlexander V. Chernikov }
693775dc861SAlexander V. Chernikov 
694775dc861SAlexander V. Chernikov struct rt_msghdr *
rtsock_read_rtm_reply(int fd,char * buffer,size_t buflen,int seq)695775dc861SAlexander V. Chernikov rtsock_read_rtm_reply(int fd, char *buffer, size_t buflen, int seq)
696775dc861SAlexander V. Chernikov {
697775dc861SAlexander V. Chernikov 	struct rt_msghdr *rtm;
698272bd698SAlexander V. Chernikov 	int found = 0;
699775dc861SAlexander V. Chernikov 
700775dc861SAlexander V. Chernikov 	while (true) {
701775dc861SAlexander V. Chernikov 		rtm = rtsock_read_rtm(fd, buffer, buflen);
702272bd698SAlexander V. Chernikov 		if (rtm->rtm_pid == getpid() && rtm->rtm_seq == seq)
703272bd698SAlexander V. Chernikov 			found = 1;
704272bd698SAlexander V. Chernikov 		if (found)
705272bd698SAlexander V. Chernikov 			RLOG("--- MATCHED RTSOCK MESSAGE ---");
706272bd698SAlexander V. Chernikov 		else
707272bd698SAlexander V. Chernikov 			RLOG("--- SKIPPED RTSOCK MESSAGE ---");
708272bd698SAlexander V. Chernikov 		rtsock_print_rtm(rtm);
709272bd698SAlexander V. Chernikov 		if (found)
710775dc861SAlexander V. Chernikov 			return (rtm);
711775dc861SAlexander V. Chernikov 	}
712775dc861SAlexander V. Chernikov 
713775dc861SAlexander V. Chernikov 	/* NOTREACHED */
714775dc861SAlexander V. Chernikov }
715775dc861SAlexander V. Chernikov 
716775dc861SAlexander V. Chernikov void
rtsock_prepare_route_message_base(struct rt_msghdr * rtm,int cmd)717775dc861SAlexander V. Chernikov rtsock_prepare_route_message_base(struct rt_msghdr *rtm, int cmd)
718775dc861SAlexander V. Chernikov {
719775dc861SAlexander V. Chernikov 
720775dc861SAlexander V. Chernikov 	memset(rtm, 0, sizeof(struct rt_msghdr));
721775dc861SAlexander V. Chernikov 	rtm->rtm_type = cmd;
722775dc861SAlexander V. Chernikov 	rtm->rtm_version = RTM_VERSION;
723775dc861SAlexander V. Chernikov 	rtm->rtm_seq = _rtm_seq++;
724775dc861SAlexander V. Chernikov }
725775dc861SAlexander V. Chernikov 
726775dc861SAlexander V. Chernikov void
rtsock_prepare_route_message(struct rt_msghdr * rtm,int cmd,struct sockaddr * dst,struct sockaddr * mask,struct sockaddr * gw)727775dc861SAlexander V. Chernikov rtsock_prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
728775dc861SAlexander V. Chernikov   struct sockaddr *mask, struct sockaddr *gw)
729775dc861SAlexander V. Chernikov {
730775dc861SAlexander V. Chernikov 
731775dc861SAlexander V. Chernikov 	rtsock_prepare_route_message_base(rtm, cmd);
732775dc861SAlexander V. Chernikov 	if (dst != NULL)
733775dc861SAlexander V. Chernikov 		rtsock_add_rtm_sa(rtm, RTA_DST, dst);
734775dc861SAlexander V. Chernikov 
735775dc861SAlexander V. Chernikov 	if (gw != NULL) {
736775dc861SAlexander V. Chernikov 		rtsock_add_rtm_sa(rtm, RTA_GATEWAY, gw);
737775dc861SAlexander V. Chernikov 		rtm->rtm_flags |= RTF_GATEWAY;
738775dc861SAlexander V. Chernikov 	}
739775dc861SAlexander V. Chernikov 
740775dc861SAlexander V. Chernikov 	if (mask != NULL)
741775dc861SAlexander V. Chernikov 		rtsock_add_rtm_sa(rtm, RTA_NETMASK, mask);
742775dc861SAlexander V. Chernikov }
743775dc861SAlexander V. Chernikov 
744775dc861SAlexander V. Chernikov void
rtsock_add_rtm_sa(struct rt_msghdr * rtm,int addr_type,struct sockaddr * sa)745775dc861SAlexander V. Chernikov rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa)
746775dc861SAlexander V. Chernikov {
747775dc861SAlexander V. Chernikov 	char *ptr = (char *)(rtm + 1);
748775dc861SAlexander V. Chernikov 	for (int i = 0; i < RTAX_MAX; i++) {
749775dc861SAlexander V. Chernikov 		if (rtm->rtm_addrs & (1 << i)) {
750775dc861SAlexander V. Chernikov 			/* add */
751775dc861SAlexander V. Chernikov 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
752775dc861SAlexander V. Chernikov 		}
753775dc861SAlexander V. Chernikov 	}
754775dc861SAlexander V. Chernikov 
755775dc861SAlexander V. Chernikov 	rtm->rtm_addrs |= addr_type;
756775dc861SAlexander V. Chernikov 	memcpy(ptr, sa, sa->sa_len);
757775dc861SAlexander V. Chernikov }
758775dc861SAlexander V. Chernikov 
759775dc861SAlexander V. Chernikov struct sockaddr *
rtsock_find_rtm_sa(struct rt_msghdr * rtm,int addr_type)760775dc861SAlexander V. Chernikov rtsock_find_rtm_sa(struct rt_msghdr *rtm, int addr_type)
761775dc861SAlexander V. Chernikov {
762775dc861SAlexander V. Chernikov 	char *ptr = (char *)(rtm + 1);
763775dc861SAlexander V. Chernikov 	for (int i = 0; i < RTAX_MAX; i++) {
764775dc861SAlexander V. Chernikov 		if (rtm->rtm_addrs & (1 << i)) {
765775dc861SAlexander V. Chernikov 			if (addr_type == (1 << i))
766775dc861SAlexander V. Chernikov 				return ((struct sockaddr *)ptr);
767775dc861SAlexander V. Chernikov 			/* add */
768775dc861SAlexander V. Chernikov 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
769775dc861SAlexander V. Chernikov 		}
770775dc861SAlexander V. Chernikov 	}
771775dc861SAlexander V. Chernikov 
772775dc861SAlexander V. Chernikov 	return (NULL);
773775dc861SAlexander V. Chernikov }
774775dc861SAlexander V. Chernikov 
775775dc861SAlexander V. Chernikov size_t
rtsock_calc_rtm_len(struct rt_msghdr * rtm)776775dc861SAlexander V. Chernikov rtsock_calc_rtm_len(struct rt_msghdr *rtm)
777775dc861SAlexander V. Chernikov {
778775dc861SAlexander V. Chernikov 	size_t len = sizeof(struct rt_msghdr);
779775dc861SAlexander V. Chernikov 
780775dc861SAlexander V. Chernikov 	char *ptr = (char *)(rtm + 1);
781775dc861SAlexander V. Chernikov 	for (int i = 0; i < RTAX_MAX; i++) {
782775dc861SAlexander V. Chernikov 		if (rtm->rtm_addrs & (1 << i)) {
783775dc861SAlexander V. Chernikov 			/* add */
784775dc861SAlexander V. Chernikov 			int sa_len = ALIGN(((struct sockaddr *)ptr)->sa_len);
785775dc861SAlexander V. Chernikov 			len += sa_len;
786775dc861SAlexander V. Chernikov 			ptr += sa_len;
787775dc861SAlexander V. Chernikov 		}
788775dc861SAlexander V. Chernikov 	}
789775dc861SAlexander V. Chernikov 
790775dc861SAlexander V. Chernikov 	return len;
791775dc861SAlexander V. Chernikov }
792775dc861SAlexander V. Chernikov 
793775dc861SAlexander V. Chernikov void
rtsock_update_rtm_len(struct rt_msghdr * rtm)794775dc861SAlexander V. Chernikov rtsock_update_rtm_len(struct rt_msghdr *rtm)
795775dc861SAlexander V. Chernikov {
796775dc861SAlexander V. Chernikov 
797775dc861SAlexander V. Chernikov 	rtm->rtm_msglen = rtsock_calc_rtm_len(rtm);
798775dc861SAlexander V. Chernikov }
799775dc861SAlexander V. Chernikov 
800775dc861SAlexander V. Chernikov static void
_validate_message_sockaddrs(char * buffer,int rtm_len,size_t offset,int rtm_addrs)801e02d3fe7SAlexander V. Chernikov _validate_message_sockaddrs(char *buffer, int rtm_len, size_t offset, int rtm_addrs)
802775dc861SAlexander V. Chernikov {
803775dc861SAlexander V. Chernikov 	struct sockaddr *sa;
804e02d3fe7SAlexander V. Chernikov 	size_t parsed_len = offset;
805775dc861SAlexander V. Chernikov 
806e02d3fe7SAlexander V. Chernikov 	/* Offset denotes initial header size */
807e02d3fe7SAlexander V. Chernikov 	sa = (struct sockaddr *)(buffer + offset);
808775dc861SAlexander V. Chernikov 
809775dc861SAlexander V. Chernikov 	for (int i = 0; i < RTAX_MAX; i++) {
810e02d3fe7SAlexander V. Chernikov 		if ((rtm_addrs & (1 << i)) == 0)
811775dc861SAlexander V. Chernikov 			continue;
812775dc861SAlexander V. Chernikov 		parsed_len += SA_SIZE(sa);
813e02d3fe7SAlexander V. Chernikov 		RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len <= rtm_len,
814e02d3fe7SAlexander V. Chernikov 		    "SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, rtm_len);
815775dc861SAlexander V. Chernikov 		if (sa->sa_family == AF_LINK) {
816775dc861SAlexander V. Chernikov 			struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
817775dc861SAlexander V. Chernikov 			int data_len = sdl->sdl_nlen + sdl->sdl_alen;
818775dc861SAlexander V. Chernikov 			data_len += offsetof(struct sockaddr_dl, sdl_data);
819775dc861SAlexander V. Chernikov 
820e02d3fe7SAlexander V. Chernikov 			RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer,
821e02d3fe7SAlexander V. Chernikov 			    data_len <= rtm_len,
822e02d3fe7SAlexander V. Chernikov 			    "AF_LINK data size exceeds total len: %u vs %u, nlen=%d alen=%d",
823e02d3fe7SAlexander V. Chernikov 			    data_len, rtm_len, sdl->sdl_nlen, sdl->sdl_alen);
824775dc861SAlexander V. Chernikov 		}
825775dc861SAlexander V. Chernikov 		sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
826775dc861SAlexander V. Chernikov 	}
827775dc861SAlexander V. Chernikov }
828775dc861SAlexander V. Chernikov 
829775dc861SAlexander V. Chernikov /*
830775dc861SAlexander V. Chernikov  * Raises error if base syntax checks fails.
831775dc861SAlexander V. Chernikov  */
832775dc861SAlexander V. Chernikov void
rtsock_validate_message(char * buffer,ssize_t len)833775dc861SAlexander V. Chernikov rtsock_validate_message(char *buffer, ssize_t len)
834775dc861SAlexander V. Chernikov {
835775dc861SAlexander V. Chernikov 	struct rt_msghdr *rtm;
836775dc861SAlexander V. Chernikov 
837775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(len > 0, "read() return %zd, error: %s", len, strerror(errno));
838775dc861SAlexander V. Chernikov 
839775dc861SAlexander V. Chernikov 	rtm = (struct rt_msghdr *)buffer;
840775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(rtm->rtm_version == RTM_VERSION, "unknown RTM_VERSION: expected %d got %d",
841775dc861SAlexander V. Chernikov 			RTM_VERSION, rtm->rtm_version);
842775dc861SAlexander V. Chernikov 	ATF_REQUIRE_MSG(rtm->rtm_msglen <= len, "wrong message length: expected %d got %d",
843775dc861SAlexander V. Chernikov 			(int)len, (int)rtm->rtm_msglen);
844775dc861SAlexander V. Chernikov 
845775dc861SAlexander V. Chernikov 	switch (rtm->rtm_type) {
846775dc861SAlexander V. Chernikov 	case RTM_GET:
847775dc861SAlexander V. Chernikov 	case RTM_ADD:
848775dc861SAlexander V. Chernikov 	case RTM_DELETE:
849775dc861SAlexander V. Chernikov 	case RTM_CHANGE:
850e02d3fe7SAlexander V. Chernikov 		_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
851e02d3fe7SAlexander V. Chernikov 		    sizeof(struct rt_msghdr), rtm->rtm_addrs);
852e02d3fe7SAlexander V. Chernikov 		break;
853e02d3fe7SAlexander V. Chernikov 	case RTM_DELADDR:
854e02d3fe7SAlexander V. Chernikov 	case RTM_NEWADDR:
855e02d3fe7SAlexander V. Chernikov 		_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
856e02d3fe7SAlexander V. Chernikov 		    sizeof(struct ifa_msghdr), ((struct ifa_msghdr *)buffer)->ifam_addrs);
857775dc861SAlexander V. Chernikov 		break;
858775dc861SAlexander V. Chernikov 	}
859775dc861SAlexander V. Chernikov }
860775dc861SAlexander V. Chernikov 
861e02d3fe7SAlexander V. Chernikov void
rtsock_validate_pid_ours(struct rt_msghdr * rtm)862e02d3fe7SAlexander V. Chernikov rtsock_validate_pid_ours(struct rt_msghdr *rtm)
863e02d3fe7SAlexander V. Chernikov {
864e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == getpid(), "expected pid %d, got %d",
865e02d3fe7SAlexander V. Chernikov 	    getpid(), rtm->rtm_pid);
866e02d3fe7SAlexander V. Chernikov }
867e02d3fe7SAlexander V. Chernikov 
868e02d3fe7SAlexander V. Chernikov void
rtsock_validate_pid_user(struct rt_msghdr * rtm)869e02d3fe7SAlexander V. Chernikov rtsock_validate_pid_user(struct rt_msghdr *rtm)
870e02d3fe7SAlexander V. Chernikov {
871e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid, got %d",
872e02d3fe7SAlexander V. Chernikov 	    rtm->rtm_pid);
873e02d3fe7SAlexander V. Chernikov }
874e02d3fe7SAlexander V. Chernikov 
875e02d3fe7SAlexander V. Chernikov void
rtsock_validate_pid_kernel(struct rt_msghdr * rtm)876e02d3fe7SAlexander V. Chernikov rtsock_validate_pid_kernel(struct rt_msghdr *rtm)
877e02d3fe7SAlexander V. Chernikov {
878e02d3fe7SAlexander V. Chernikov 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == 0, "expected zero pid, got %d",
879e02d3fe7SAlexander V. Chernikov 	    rtm->rtm_pid);
880e02d3fe7SAlexander V. Chernikov }
881e02d3fe7SAlexander V. Chernikov 
882775dc861SAlexander V. Chernikov #endif
883