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