xref: /openbsd/sbin/iked/vroute.c (revision f294d01e)
1 /*	$OpenBSD: vroute.c,v 1.20 2024/07/14 13:13:33 tobhe Exp $	*/
2 
3 /*
4  * Copyright (c) 2021 Tobias Heider <tobhe@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/ioctl.h>
20 
21 #include <net/if.h>
22 #include <net/route.h>
23 #include <netinet/in.h>
24 #include <netinet6/in6_var.h>
25 #include <netinet6/nd6.h>
26 
27 #include <event.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <poll.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <netdb.h>
35 
36 #include <iked.h>
37 
38 #define ROUTE_SOCKET_BUF_SIZE	16384
39 #define IKED_VROUTE_PRIO	6
40 
41 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
42 
43 int vroute_setroute(struct iked *, uint32_t, struct sockaddr *, uint8_t,
44     struct sockaddr *, int);
45 int vroute_doroute(struct iked *, int, int, int, uint8_t, struct sockaddr *,
46     struct sockaddr *, struct sockaddr *, int *);
47 int vroute_doaddr(struct iked *, char *, struct sockaddr *, struct sockaddr *, int);
48 int vroute_dodns(struct iked *, struct sockaddr *, int, unsigned int);
49 void vroute_cleanup(struct iked *);
50 void vroute_rtmsg_cb(int, short, void *);
51 
52 void vroute_insertaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
53 void vroute_removeaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
54 void vroute_insertdns(struct iked *, int, struct sockaddr *);
55 void vroute_removedns(struct iked *, int, struct sockaddr *);
56 void vroute_insertroute(struct iked *, int, struct sockaddr *, struct sockaddr *);
57 void vroute_removeroute(struct iked *, int, struct sockaddr *, struct sockaddr *);
58 
59 struct vroute_addr {
60 	int				va_ifidx;
61 	struct	sockaddr_storage	va_addr;
62 	struct	sockaddr_storage	va_mask;
63 	TAILQ_ENTRY(vroute_addr)	va_entry;
64 };
65 TAILQ_HEAD(vroute_addrs, vroute_addr);
66 
67 struct vroute_route {
68 	int				vr_rdomain;
69 	int				vr_flags;
70 	struct	sockaddr_storage	vr_dest;
71 	struct	sockaddr_storage	vr_mask;
72 	TAILQ_ENTRY(vroute_route)	vr_entry;
73 };
74 TAILQ_HEAD(vroute_routes, vroute_route);
75 
76 struct vroute_dns {
77 	struct	sockaddr_storage	vd_addr;
78 	int				vd_ifidx;
79 	TAILQ_ENTRY(vroute_dns)		vd_entry;
80 };
81 TAILQ_HEAD(vroute_dnss, vroute_dns);
82 
83 struct iked_vroute_sc {
84 	struct vroute_addrs	 ivr_addrs;
85 	struct vroute_routes	 ivr_routes;
86 	struct vroute_dnss	 ivr_dnss;
87 	struct event		 ivr_routeev;
88 	int			 ivr_iosock;
89 	int			 ivr_iosock6;
90 	int			 ivr_rtsock;
91 	int			 ivr_rtseq;
92 	pid_t			 ivr_pid;
93 };
94 
95 struct vroute_msg {
96 	struct rt_msghdr	 vm_rtm;
97 	uint8_t			 vm_space[512];
98 };
99 
100 int vroute_process(struct iked *, int msglen, struct vroute_msg *,
101     struct sockaddr *, struct sockaddr *, struct sockaddr *, int *);
102 
103 void
vroute_rtmsg_cb(int fd,short events,void * arg)104 vroute_rtmsg_cb(int fd, short events, void *arg)
105 {
106 	struct iked		*env = (struct iked *) arg;
107 	struct iked_vroute_sc	*ivr = env->sc_vroute;
108 	struct vroute_dns	*dns;
109 	static uint8_t		*buf;
110 	struct rt_msghdr	*rtm;
111 	ssize_t			 n;
112 
113 	if (buf == NULL) {
114 		buf = malloc(ROUTE_SOCKET_BUF_SIZE);
115 		if (buf == NULL)
116 			fatal("malloc");
117 	}
118 	rtm = (struct rt_msghdr *)buf;
119 	if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
120 		if (errno == EAGAIN || errno == EINTR)
121 			return;
122 		log_warn("%s: read error", __func__);
123 		return;
124 	}
125 
126 	if (n == 0)
127 		fatal("routing socket closed");
128 
129 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
130 		log_warnx("partial rtm of %zd in buffer", n);
131 		return;
132 	}
133 
134 	if (rtm->rtm_version != RTM_VERSION)
135 		return;
136 
137 	switch(rtm->rtm_type) {
138 	case RTM_PROPOSAL:
139 		if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) {
140 			TAILQ_FOREACH(dns, &ivr->ivr_dnss, vd_entry) {
141 				log_debug("%s: got solicit", __func__);
142 				vroute_dodns(env, (struct sockaddr *) &dns->vd_addr,
143 				    1, dns->vd_ifidx);
144 			}
145 		}
146 		break;
147 	default:
148 		log_debug("%s: unexpected RTM: %d", __func__, rtm->rtm_type);
149 		break;
150 	}
151 }
152 
153 void
vroute_init(struct iked * env)154 vroute_init(struct iked *env)
155 {
156 	struct iked_vroute_sc	*ivr;
157 	int			 rtfilter;
158 
159 	ivr = calloc(1, sizeof(*ivr));
160 	if (ivr == NULL)
161 		fatal("%s: calloc.", __func__);
162 
163 	if ((ivr->ivr_iosock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
164 		fatal("%s: failed to create ioctl socket", __func__);
165 
166 	if ((ivr->ivr_iosock6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
167 		fatal("%s: failed to create ioctl socket", __func__);
168 
169 	if ((ivr->ivr_rtsock = socket(AF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1)
170 		fatal("%s: failed to create routing socket", __func__);
171 
172 	rtfilter = ROUTE_FILTER(RTM_GET) | ROUTE_FILTER(RTM_PROPOSAL);
173 	if (setsockopt(ivr->ivr_rtsock, AF_ROUTE, ROUTE_MSGFILTER, &rtfilter,
174 	    sizeof(rtfilter)) == -1)
175 		fatal("%s: setsockopt(ROUTE_MSGFILTER)", __func__);
176 
177 	TAILQ_INIT(&ivr->ivr_addrs);
178 	TAILQ_INIT(&ivr->ivr_dnss);
179 	TAILQ_INIT(&ivr->ivr_routes);
180 
181 	ivr->ivr_pid = getpid();
182 
183 	env->sc_vroute = ivr;
184 
185 	event_set(&ivr->ivr_routeev, ivr->ivr_rtsock, EV_READ | EV_PERSIST,
186 	    vroute_rtmsg_cb, env);
187 	event_add(&ivr->ivr_routeev, NULL);
188 }
189 
190 void
vroute_cleanup(struct iked * env)191 vroute_cleanup(struct iked *env)
192 {
193 	char			 ifname[IF_NAMESIZE];
194 	struct iked_vroute_sc	*ivr = env->sc_vroute;
195 	struct vroute_addr	*addr;
196 	struct vroute_route	*route;
197 	struct vroute_dns	*dns;
198 
199 	while ((addr = TAILQ_FIRST(&ivr->ivr_addrs))) {
200 		if_indextoname(addr->va_ifidx, ifname);
201 		vroute_doaddr(env, ifname,
202 		    (struct sockaddr *)&addr->va_addr,
203 		    (struct sockaddr *)&addr->va_mask, 0);
204 		TAILQ_REMOVE(&ivr->ivr_addrs, addr, va_entry);
205 		free(addr);
206 	}
207 
208 	while ((route = TAILQ_FIRST(&ivr->ivr_routes))) {
209 		vroute_doroute(env, RTF_UP | RTF_GATEWAY | RTF_STATIC,
210 		    route->vr_flags, route->vr_rdomain, RTM_DELETE,
211 		    (struct sockaddr *)&route->vr_dest,
212 		    (struct sockaddr *)&route->vr_mask,
213 		    NULL, NULL);
214 		TAILQ_REMOVE(&ivr->ivr_routes, route, vr_entry);
215 		free(route);
216 	}
217 
218 	while ((dns = TAILQ_FIRST(&ivr->ivr_dnss))) {
219 		vroute_dodns(env, (struct sockaddr *)&dns->vd_addr, 0,
220 		    dns->vd_ifidx);
221 		TAILQ_REMOVE(&ivr->ivr_dnss, dns, vd_entry);
222 		free(dns);
223 	}
224 }
225 
226 int
vroute_setaddr(struct iked * env,int add,struct sockaddr * addr,int mask,unsigned int ifidx)227 vroute_setaddr(struct iked *env, int add, struct sockaddr *addr,
228     int mask, unsigned int ifidx)
229 {
230 	struct iovec		 iov[4];
231 	int			 iovcnt;
232 	struct sockaddr_in	 mask4;
233 	struct sockaddr_in6	 mask6;
234 
235 	iovcnt = 0;
236 	iov[0].iov_base = addr;
237 	iov[0].iov_len = addr->sa_len;
238 	iovcnt++;
239 
240 	switch(addr->sa_family) {
241 	case AF_INET:
242 		bzero(&mask, sizeof(mask));
243 		mask4.sin_addr.s_addr = prefixlen2mask(mask ? mask : 32);
244 		mask4.sin_family = AF_INET;
245 		mask4.sin_len = sizeof(mask4);
246 
247 		iov[1].iov_base = &mask4;
248 		iov[1].iov_len = sizeof(mask4);
249 		iovcnt++;
250 		break;
251 	case AF_INET6:
252 		bzero(&mask6, sizeof(mask6));
253 		prefixlen2mask6(mask ? mask : 128,
254 		    (uint32_t *)&mask6.sin6_addr.s6_addr);
255 		mask6.sin6_family = AF_INET6;
256 		mask6.sin6_len = sizeof(mask6);
257 		iov[1].iov_base = &mask6;
258 		iov[1].iov_len = sizeof(mask6);
259 		iovcnt++;
260 		break;
261 	default:
262 		return -1;
263 	}
264 
265 	iov[2].iov_base = &ifidx;
266 	iov[2].iov_len = sizeof(ifidx);
267 	iovcnt++;
268 
269 	return (proc_composev(&env->sc_ps, PROC_PARENT,
270 	    add ? IMSG_IF_ADDADDR : IMSG_IF_DELADDR, iov, iovcnt));
271 }
272 
273 int
vroute_getaddr(struct iked * env,struct imsg * imsg)274 vroute_getaddr(struct iked *env, struct imsg *imsg)
275 {
276 	char			 ifname[IF_NAMESIZE];
277 	struct sockaddr	*addr, *mask;
278 	uint8_t			*ptr;
279 	size_t			 left;
280 	int			 af, add;
281 	unsigned int		 ifidx;
282 
283 	ptr = imsg->data;
284 	left = IMSG_DATA_SIZE(imsg);
285 
286 	if (left < sizeof(*addr))
287 		fatalx("bad length imsg received");
288 
289 	addr = (struct sockaddr *) ptr;
290 	af = addr->sa_family;
291 
292 	if (left < addr->sa_len)
293 		fatalx("bad length imsg received");
294 	ptr += addr->sa_len;
295 	left -= addr->sa_len;
296 
297 	if (left < sizeof(*mask))
298 		fatalx("bad length imsg received");
299 	mask = (struct sockaddr *) ptr;
300 	if (mask->sa_family != af)
301 		return (-1);
302 
303 	if (left < mask->sa_len)
304 		fatalx("bad length imsg received");
305 	ptr += mask->sa_len;
306 	left -= mask->sa_len;
307 
308 	if (left != sizeof(ifidx))
309 		fatalx("bad length imsg received");
310 	memcpy(&ifidx, ptr, sizeof(ifidx));
311 	ptr += sizeof(ifidx);
312 	left -= sizeof(ifidx);
313 
314 	add = (imsg->hdr.type == IMSG_IF_ADDADDR);
315 	/* Store address for cleanup */
316 	if (add)
317 		vroute_insertaddr(env, ifidx, addr, mask);
318 	else
319 		vroute_removeaddr(env, ifidx, addr, mask);
320 
321 	if_indextoname(ifidx, ifname);
322 	return (vroute_doaddr(env, ifname, addr, mask, add));
323 }
324 
325 int
vroute_setdns(struct iked * env,int add,struct sockaddr * addr,unsigned int ifidx)326 vroute_setdns(struct iked *env, int add, struct sockaddr *addr,
327     unsigned int ifidx)
328 {
329 	struct iovec		 iov[2];
330 
331 	iov[0].iov_base = addr;
332 	iov[0].iov_len = addr->sa_len;
333 
334 	iov[1].iov_base = &ifidx;
335 	iov[1].iov_len = sizeof(ifidx);
336 
337 	return (proc_composev(&env->sc_ps, PROC_PARENT,
338 	    add ? IMSG_VDNS_ADD: IMSG_VDNS_DEL, iov, 2));
339 }
340 
341 int
vroute_getdns(struct iked * env,struct imsg * imsg)342 vroute_getdns(struct iked *env, struct imsg *imsg)
343 {
344 	struct sockaddr		*dns;
345 	uint8_t			*ptr;
346 	size_t			 left;
347 	int			 add;
348 	unsigned int		 ifidx;
349 
350 	ptr = imsg->data;
351 	left = IMSG_DATA_SIZE(imsg);
352 
353 	if (left < sizeof(*dns))
354 		fatalx("bad length imsg received");
355 
356 	dns = (struct sockaddr *) ptr;
357 	if (left < dns->sa_len)
358 		fatalx("bad length imsg received");
359 	ptr += dns->sa_len;
360 	left -= dns->sa_len;
361 
362 	if (left != sizeof(ifidx))
363 		fatalx("bad length imsg received");
364 	memcpy(&ifidx, ptr, sizeof(ifidx));
365 	ptr += sizeof(ifidx);
366 	left -= sizeof(ifidx);
367 
368 	add = (imsg->hdr.type == IMSG_VDNS_ADD);
369 	if (add) {
370 		vroute_insertdns(env, ifidx, dns);
371 	} else {
372 		vroute_removedns(env, ifidx, dns);
373 	}
374 
375 	return (vroute_dodns(env, dns, add, ifidx));
376 }
377 
378 void
vroute_insertroute(struct iked * env,int rdomain,struct sockaddr * dest,struct sockaddr * mask)379 vroute_insertroute(struct iked *env, int rdomain, struct sockaddr *dest,
380     struct sockaddr *mask)
381 {
382 	struct iked_vroute_sc	*ivr = env->sc_vroute;
383 	struct vroute_route	*route;
384 
385 	route = calloc(1, sizeof(*route));
386 	if (route == NULL)
387 		fatalx("%s: calloc.", __func__);
388 
389 	if (dest != NULL) {
390 		route->vr_flags |= RTA_DST;
391 		memcpy(&route->vr_dest, dest, dest->sa_len);
392 	}
393 	if (mask != NULL) {
394 		route->vr_flags |= RTA_NETMASK;
395 		memcpy(&route->vr_mask, mask, mask->sa_len);
396 	}
397 	route->vr_rdomain = rdomain;
398 
399 	TAILQ_INSERT_TAIL(&ivr->ivr_routes, route, vr_entry);
400 }
401 
402 void
vroute_removeroute(struct iked * env,int rdomain,struct sockaddr * dest,struct sockaddr * mask)403 vroute_removeroute(struct iked *env, int rdomain, struct sockaddr *dest,
404     struct sockaddr *mask)
405 {
406 	struct iked_vroute_sc	*ivr = env->sc_vroute;
407 	struct vroute_route	*route, *troute;
408 
409 	TAILQ_FOREACH_SAFE(route, &ivr->ivr_routes, vr_entry, troute) {
410 		if (sockaddr_cmp(dest, (struct sockaddr *)&route->vr_dest, -1))
411 			continue;
412 		if (mask && !(route->vr_flags & RTA_NETMASK))
413 			continue;
414 		if (mask &&
415 		    sockaddr_cmp(mask, (struct sockaddr *)&route->vr_mask, -1))
416 			continue;
417 		if (rdomain != route->vr_rdomain)
418 			continue;
419 		TAILQ_REMOVE(&ivr->ivr_routes, route, vr_entry);
420 		free(route);
421 	}
422 }
423 
424 void
vroute_insertdns(struct iked * env,int ifidx,struct sockaddr * addr)425 vroute_insertdns(struct iked *env, int ifidx, struct sockaddr *addr)
426 {
427 	struct iked_vroute_sc	*ivr = env->sc_vroute;
428 	struct vroute_dns	*dns;
429 
430 	dns = calloc(1, sizeof(*dns));
431 	if (dns == NULL)
432 		fatalx("%s: calloc.", __func__);
433 
434 	memcpy(&dns->vd_addr, addr, addr->sa_len);
435 	dns->vd_ifidx = ifidx;
436 
437 	TAILQ_INSERT_TAIL(&ivr->ivr_dnss, dns, vd_entry);
438 }
439 
440 void
vroute_removedns(struct iked * env,int ifidx,struct sockaddr * addr)441 vroute_removedns(struct iked *env, int ifidx, struct sockaddr *addr)
442 {
443 	struct iked_vroute_sc	*ivr = env->sc_vroute;
444 	struct vroute_dns	*dns, *tdns;
445 
446 	TAILQ_FOREACH_SAFE(dns, &ivr->ivr_dnss, vd_entry, tdns) {
447 		if (ifidx != dns->vd_ifidx)
448 			continue;
449 		if (sockaddr_cmp(addr, (struct sockaddr *) &dns->vd_addr, -1))
450 			continue;
451 
452 		TAILQ_REMOVE(&ivr->ivr_dnss, dns, vd_entry);
453 		free(dns);
454 	}
455 }
456 
457 void
vroute_insertaddr(struct iked * env,int ifidx,struct sockaddr * addr,struct sockaddr * mask)458 vroute_insertaddr(struct iked *env, int ifidx, struct sockaddr *addr,
459     struct sockaddr *mask)
460 {
461 	struct iked_vroute_sc	*ivr = env->sc_vroute;
462 	struct vroute_addr	*vaddr;
463 
464 	vaddr = calloc(1, sizeof(*vaddr));
465 	if (vaddr == NULL)
466 		fatalx("%s: calloc.", __func__);
467 
468 	memcpy(&vaddr->va_addr, addr, addr->sa_len);
469 	memcpy(&vaddr->va_mask, mask, mask->sa_len);
470 	vaddr->va_ifidx = ifidx;
471 
472 	TAILQ_INSERT_TAIL(&ivr->ivr_addrs, vaddr, va_entry);
473 }
474 
475 void
vroute_removeaddr(struct iked * env,int ifidx,struct sockaddr * addr,struct sockaddr * mask)476 vroute_removeaddr(struct iked *env, int ifidx, struct sockaddr *addr,
477     struct sockaddr *mask)
478 {
479 	struct iked_vroute_sc	*ivr = env->sc_vroute;
480 	struct vroute_addr	*vaddr, *tvaddr;
481 
482 	TAILQ_FOREACH_SAFE(vaddr, &ivr->ivr_addrs, va_entry, tvaddr) {
483 		if (sockaddr_cmp(addr, (struct sockaddr *)&vaddr->va_addr, -1))
484 			continue;
485 		if (sockaddr_cmp(mask, (struct sockaddr *)&vaddr->va_mask, -1))
486 			continue;
487 		if (ifidx != vaddr->va_ifidx)
488 			continue;
489 		TAILQ_REMOVE(&ivr->ivr_addrs, vaddr, va_entry);
490 		free(vaddr);
491 	}
492 }
493 
494 int
vroute_setaddroute(struct iked * env,uint8_t rdomain,struct sockaddr * dst,uint8_t mask,struct sockaddr * ifa)495 vroute_setaddroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
496     uint8_t mask, struct sockaddr *ifa)
497 {
498 	return (vroute_setroute(env, rdomain, dst, mask, ifa,
499 	    IMSG_VROUTE_ADD));
500 }
501 
502 int
vroute_setcloneroute(struct iked * env,uint8_t rdomain,struct sockaddr * dst,uint8_t mask,struct sockaddr * addr)503 vroute_setcloneroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
504     uint8_t mask, struct sockaddr *addr)
505 {
506 	return (vroute_setroute(env, rdomain, dst, mask, addr,
507 	    IMSG_VROUTE_CLONE));
508 }
509 
510 int
vroute_setdelroute(struct iked * env,uint8_t rdomain,struct sockaddr * dst,uint8_t mask,struct sockaddr * addr)511 vroute_setdelroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
512     uint8_t mask, struct sockaddr *addr)
513 {
514 	return (vroute_setroute(env, rdomain, dst, mask, addr,
515 	    IMSG_VROUTE_DEL));
516 }
517 
518 int
vroute_setroute(struct iked * env,uint32_t rdomain,struct sockaddr * dst,uint8_t mask,struct sockaddr * addr,int type)519 vroute_setroute(struct iked *env, uint32_t rdomain, struct sockaddr *dst,
520     uint8_t mask, struct sockaddr *addr, int type)
521 {
522 	struct sockaddr_storage	 sa;
523 	struct sockaddr_in	*in;
524 	struct sockaddr_in6	*in6;
525 	struct iovec		 iov[5];
526 	int			 iovcnt = 0;
527 	uint8_t			 af;
528 
529 	if (addr && dst->sa_family != addr->sa_family)
530 		return (-1);
531 	af = dst->sa_family;
532 
533 	iov[iovcnt].iov_base = &rdomain;
534 	iov[iovcnt].iov_len = sizeof(rdomain);
535 	iovcnt++;
536 
537 	iov[iovcnt].iov_base = dst;
538 	iov[iovcnt].iov_len = dst->sa_len;
539 	iovcnt++;
540 
541 	if (type != IMSG_VROUTE_CLONE && addr) {
542 		bzero(&sa, sizeof(sa));
543 		switch(af) {
544 		case AF_INET:
545 			in = (struct sockaddr_in *)&sa;
546 			in->sin_addr.s_addr = prefixlen2mask(mask);
547 			in->sin_family = af;
548 			in->sin_len = sizeof(*in);
549 			iov[iovcnt].iov_base = in;
550 			iov[iovcnt].iov_len = sizeof(*in);
551 			iovcnt++;
552 			break;
553 		case AF_INET6:
554 			in6 = (struct sockaddr_in6 *)&sa;
555 			prefixlen2mask6(mask,
556 			    (uint32_t *)in6->sin6_addr.s6_addr);
557 			in6->sin6_family = af;
558 			in6->sin6_len = sizeof(*in6);
559 			iov[iovcnt].iov_base = in6;
560 			iov[iovcnt].iov_len = sizeof(*in6);
561 			iovcnt++;
562 			break;
563 		}
564 
565 		iov[iovcnt].iov_base = addr;
566 		iov[iovcnt].iov_len = addr->sa_len;
567 		iovcnt++;
568 	}
569 
570 	return (proc_composev(&env->sc_ps, PROC_PARENT, type, iov, iovcnt));
571 }
572 
573 int
vroute_getroute(struct iked * env,struct imsg * imsg)574 vroute_getroute(struct iked *env, struct imsg *imsg)
575 {
576 	struct sockaddr		*dest, *mask = NULL, *gateway = NULL;
577 	uint8_t			*ptr;
578 	size_t			 left;
579 	int			 addrs = 0;
580 	int			 type, flags;
581 	uint32_t		 rdomain;
582 
583 	ptr = (uint8_t *)imsg->data;
584 	left = IMSG_DATA_SIZE(imsg);
585 
586 	if (left < sizeof(rdomain))
587 		return (-1);
588 	rdomain = *ptr;
589 	ptr += sizeof(rdomain);
590 	left -= sizeof(rdomain);
591 
592 	if (left < sizeof(struct sockaddr))
593 		return (-1);
594 	dest = (struct sockaddr *)ptr;
595 	if (left < dest->sa_len)
596 		return (-1);
597 	socket_setport(dest, 0);
598 	ptr += dest->sa_len;
599 	left -= dest->sa_len;
600 	addrs |= RTA_DST;
601 
602 	flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
603 	if (left != 0) {
604 		if (left < sizeof(struct sockaddr))
605 			return (-1);
606 		mask = (struct sockaddr *)ptr;
607 		if (left < mask->sa_len)
608 			return (-1);
609 		socket_setport(mask, 0);
610 		ptr += mask->sa_len;
611 		left -= mask->sa_len;
612 		addrs |= RTA_NETMASK;
613 
614 		if (left < sizeof(struct sockaddr))
615 			return (-1);
616 		gateway = (struct sockaddr *)ptr;
617 		if (left < gateway->sa_len)
618 			return (-1);
619 		socket_setport(gateway, 0);
620 		ptr += gateway->sa_len;
621 		left -= gateway->sa_len;
622 		addrs |= RTA_GATEWAY;
623 	} else {
624 		flags |= RTF_HOST;
625 	}
626 
627 	switch(imsg->hdr.type) {
628 	case IMSG_VROUTE_ADD:
629 		type = RTM_ADD;
630 		break;
631 	case IMSG_VROUTE_DEL:
632 		type = RTM_DELETE;
633 		break;
634 	default:
635 		return (-1);
636 	}
637 
638 	if (type == RTM_ADD)
639 		vroute_insertroute(env, rdomain, dest, mask);
640 	else
641 		vroute_removeroute(env, rdomain, dest, mask);
642 	return (vroute_doroute(env, flags, addrs, rdomain, type,
643 	    dest, mask, gateway, NULL));
644 }
645 
646 int
vroute_getcloneroute(struct iked * env,struct imsg * imsg)647 vroute_getcloneroute(struct iked *env, struct imsg *imsg)
648 {
649 	struct sockaddr		*dst;
650 	struct sockaddr_storage	 dest;
651 	struct sockaddr_storage	 mask;
652 	struct sockaddr_storage	 addr;
653 	uint8_t			*ptr;
654 	size_t			 left;
655 	uint32_t		 rdomain;
656 	int			 flags;
657 	int			 addrs;
658 	int			 need_gw;
659 
660 	ptr = (uint8_t *)imsg->data;
661 	left = IMSG_DATA_SIZE(imsg);
662 
663 	if (left < sizeof(rdomain))
664 		return (-1);
665 	rdomain = *ptr;
666 	ptr += sizeof(rdomain);
667 	left -= sizeof(rdomain);
668 
669 	bzero(&dest, sizeof(dest));
670 	bzero(&mask, sizeof(mask));
671 	bzero(&addr, sizeof(addr));
672 
673 	if (left < sizeof(struct sockaddr))
674 		return (-1);
675 	dst = (struct sockaddr *)ptr;
676 	if (left < dst->sa_len)
677 		return (-1);
678 	memcpy(&dest, dst, dst->sa_len);
679 	ptr += dst->sa_len;
680 	left -= dst->sa_len;
681 
682 	/* Get route to peer */
683 	flags = RTF_UP | RTF_HOST | RTF_STATIC;
684 	if (vroute_doroute(env, flags, RTA_DST, rdomain, RTM_GET,
685 	    (struct sockaddr *)&dest, (struct sockaddr *)&mask,
686 	    (struct sockaddr *)&addr, &need_gw))
687 		return (-1);
688 
689 	if (need_gw)
690 		flags |= RTF_GATEWAY;
691 
692 	memcpy(&dest, dst, dst->sa_len);
693 	socket_setport((struct sockaddr *)&dest, 0);
694 	vroute_insertroute(env, rdomain, (struct sockaddr *)&dest, NULL);
695 
696 	/* Set explicit route to peer with gateway addr*/
697 	addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
698 	return (vroute_doroute(env, flags, addrs, rdomain, RTM_ADD,
699 	    (struct sockaddr *)&dest, (struct sockaddr *)&mask,
700 	    (struct sockaddr *)&addr, NULL));
701 }
702 
703 int
vroute_dodns(struct iked * env,struct sockaddr * dns,int add,unsigned int ifidx)704 vroute_dodns(struct iked *env, struct sockaddr *dns, int add,
705     unsigned int ifidx)
706 {
707 	struct vroute_msg	 m_rtmsg;
708 	struct sockaddr_in	 *in;
709 	struct sockaddr_in6	 *in6;
710 	struct sockaddr_rtdns	 rtdns;
711 	struct iked_vroute_sc	*ivr = env->sc_vroute;
712 	struct iovec		 iov[3];
713 	int			 i;
714 	long			 pad = 0;
715 	int			 iovcnt = 0, padlen;
716 
717 	bzero(&m_rtmsg, sizeof(m_rtmsg));
718 #define rtm m_rtmsg.vm_rtm
719 	rtm.rtm_version = RTM_VERSION;
720 	rtm.rtm_type = RTM_PROPOSAL;
721 	rtm.rtm_seq = ++ivr->ivr_rtseq;
722 	rtm.rtm_priority = RTP_PROPOSAL_STATIC;
723 	rtm.rtm_flags = RTF_UP;
724 	rtm.rtm_addrs = RTA_DNS;
725 	rtm.rtm_index = ifidx;
726 
727 	iov[iovcnt].iov_base = &rtm;
728 	iov[iovcnt].iov_len = sizeof(rtm);
729 	iovcnt++;
730 
731 	bzero(&rtdns, sizeof(rtdns));
732 	rtdns.sr_family = dns->sa_family;
733 	rtdns.sr_len = 2;
734 	if (add) {
735 		switch(dns->sa_family) {
736 		case AF_INET:
737 			rtdns.sr_family = AF_INET;
738 			rtdns.sr_len += sizeof(struct in_addr);
739 			in = (struct sockaddr_in *)dns;
740 			memcpy(rtdns.sr_dns, &in->sin_addr, sizeof(struct in_addr));
741 			break;
742 		case AF_INET6:
743 			rtdns.sr_family = AF_INET6;
744 			rtdns.sr_len += sizeof(struct in6_addr);
745 			in6 = (struct sockaddr_in6 *)dns;
746 			memcpy(rtdns.sr_dns, &in6->sin6_addr, sizeof(struct in6_addr));
747 			break;
748 		default:
749 			return (-1);
750 		}
751 	}
752 	iov[iovcnt].iov_base = &rtdns;
753 	iov[iovcnt++].iov_len = sizeof(rtdns);
754 	padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns);
755 	if (padlen > 0) {
756 		iov[iovcnt].iov_base = &pad;
757 		iov[iovcnt++].iov_len = padlen;
758 	}
759 
760 	for (i = 0; i < iovcnt; i++)
761 		rtm.rtm_msglen += iov[i].iov_len;
762 #undef rtm
763 
764 	if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1)
765 		log_warn("failed to send route message");
766 
767 	return (0);
768 }
769 
770 int
vroute_doroute(struct iked * env,int flags,int addrs,int rdomain,uint8_t type,struct sockaddr * dest,struct sockaddr * mask,struct sockaddr * addr,int * need_gw)771 vroute_doroute(struct iked *env, int flags, int addrs, int rdomain, uint8_t type,
772     struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw)
773 {
774 	struct vroute_msg	 m_rtmsg;
775 	struct iovec		 iov[7];
776 	struct iked_vroute_sc	*ivr = env->sc_vroute;
777 	ssize_t			 len;
778 	int			 iovcnt = 0;
779 	int			 i;
780 	long			 pad = 0;
781 	size_t			 padlen;
782 
783 	bzero(&m_rtmsg, sizeof(m_rtmsg));
784 #define rtm m_rtmsg.vm_rtm
785 	rtm.rtm_version = RTM_VERSION;
786 	rtm.rtm_tableid = rdomain;
787 	rtm.rtm_type = type;
788 	rtm.rtm_seq = ++ivr->ivr_rtseq;
789 	if (type != RTM_GET)
790 		rtm.rtm_priority = IKED_VROUTE_PRIO;
791 	rtm.rtm_flags = flags;
792 	rtm.rtm_addrs = addrs;
793 
794 	iov[iovcnt].iov_base = &rtm;
795 	iov[iovcnt].iov_len = sizeof(rtm);
796 	iovcnt++;
797 
798 	if (rtm.rtm_addrs & RTA_DST) {
799 		iov[iovcnt].iov_base = dest;
800 		iov[iovcnt].iov_len = dest->sa_len;
801 		iovcnt++;
802 		padlen = ROUNDUP(dest->sa_len) - dest->sa_len;
803 		if (padlen > 0) {
804 			iov[iovcnt].iov_base = &pad;
805 			iov[iovcnt].iov_len = padlen;
806 			iovcnt++;
807 		}
808 	}
809 
810 	if (rtm.rtm_addrs & RTA_GATEWAY) {
811 		iov[iovcnt].iov_base = addr;
812 		iov[iovcnt].iov_len = addr->sa_len;
813 		iovcnt++;
814 		padlen = ROUNDUP(addr->sa_len) - addr->sa_len;
815 		if (padlen > 0) {
816 			iov[iovcnt].iov_base = &pad;
817 			iov[iovcnt].iov_len = padlen;
818 			iovcnt++;
819 		}
820 	}
821 
822 	if (rtm.rtm_addrs & RTA_NETMASK) {
823 		iov[iovcnt].iov_base = mask;
824 		iov[iovcnt].iov_len = mask->sa_len;
825 		iovcnt++;
826 		padlen = ROUNDUP(mask->sa_len) - mask->sa_len;
827 		if (padlen > 0) {
828 			iov[iovcnt].iov_base = &pad;
829 			iov[iovcnt].iov_len = padlen;
830 			iovcnt++;
831 		}
832 	}
833 
834 	for (i = 0; i < iovcnt; i++)
835 		rtm.rtm_msglen += iov[i].iov_len;
836 
837 	log_debug("%s: len: %u type: %s rdomain: %d flags %x (%s%s)"
838 	    " addrs %x (dst %s mask %s gw %s)", __func__, rtm.rtm_msglen,
839 	    type == RTM_ADD ? "RTM_ADD" : type == RTM_DELETE ? "RTM_DELETE" :
840 	    type == RTM_GET ? "RTM_GET" : "unknown", rdomain,
841 	    flags,
842 	    flags & RTF_HOST ? "H" : "",
843 	    flags & RTF_GATEWAY ? "G" : "",
844 	    addrs,
845 	    addrs & RTA_DST ? print_addr(dest) : "<>",
846 	    addrs & RTA_NETMASK ? print_addr(mask) : "<>",
847 	    addrs & RTA_GATEWAY ? print_addr(addr) : "<>");
848 
849 	if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1) {
850 		if ((type == RTM_ADD && errno != EEXIST) ||
851 		    (type == RTM_DELETE && errno != ESRCH)) {
852 			log_warn("%s: write %d", __func__, rtm.rtm_errno);
853 			return (0);
854 		}
855 	}
856 
857 	if (type == RTM_GET) {
858 		do {
859 			len = read(ivr->ivr_rtsock, &m_rtmsg, sizeof(m_rtmsg));
860 		} while(len > 0 && (rtm.rtm_version != RTM_VERSION ||
861 		    rtm.rtm_seq != ivr->ivr_rtseq || rtm.rtm_pid != ivr->ivr_pid));
862 		return (vroute_process(env, len, &m_rtmsg, dest, mask, addr, need_gw));
863 	}
864 #undef rtm
865 
866 	return (0);
867 }
868 
869 int
vroute_process(struct iked * env,int msglen,struct vroute_msg * m_rtmsg,struct sockaddr * dest,struct sockaddr * mask,struct sockaddr * addr,int * need_gw)870 vroute_process(struct iked *env, int msglen, struct vroute_msg *m_rtmsg,
871     struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw)
872 {
873 	struct sockaddr *sa;
874 	char *cp;
875 	int i;
876 
877 #define rtm m_rtmsg->vm_rtm
878 	if (rtm.rtm_version != RTM_VERSION) {
879 		warnx("routing message version %u not understood",
880 		    rtm.rtm_version);
881 		return (-1);
882 	}
883 	if (rtm.rtm_msglen > msglen) {
884 		warnx("message length mismatch, in packet %u, returned %d",
885 		    rtm.rtm_msglen, msglen);
886 		return (-1);
887 	}
888 	if (rtm.rtm_errno) {
889 		warnx("RTM_GET: %s (errno %d)",
890 		    strerror(rtm.rtm_errno), rtm.rtm_errno);
891 		return (-1);
892 	}
893 	cp = m_rtmsg->vm_space;
894 	*need_gw = rtm.rtm_flags & RTF_GATEWAY;
895 	if(rtm.rtm_addrs) {
896 		for (i = 1; i; i <<= 1) {
897 			if (i & rtm.rtm_addrs) {
898 				sa = (struct sockaddr *)cp;
899 				switch(i) {
900 				case RTA_DST:
901 					memcpy(dest, cp, sa->sa_len);
902 					break;
903 				case RTA_NETMASK:
904 					memcpy(mask, cp, sa->sa_len);
905 					break;
906 				case RTA_GATEWAY:
907 					memcpy(addr, cp, sa->sa_len);
908 					break;
909 				}
910 				cp += ROUNDUP(sa->sa_len);
911 			}
912 		}
913 	}
914 #undef rtm
915 	return (0);
916 }
917 
918 int
vroute_doaddr(struct iked * env,char * ifname,struct sockaddr * addr,struct sockaddr * mask,int add)919 vroute_doaddr(struct iked *env, char *ifname, struct sockaddr *addr,
920     struct sockaddr *mask, int add)
921 {
922 	struct iked_vroute_sc	*ivr = env->sc_vroute;
923 	struct ifaliasreq	 req;
924 	struct in6_aliasreq	 req6;
925 	unsigned long		 ioreq;
926 	int			 af;
927 
928 	af = addr->sa_family;
929 	switch (af) {
930 	case AF_INET:
931 		bzero(&req, sizeof(req));
932 		strncpy(req.ifra_name, ifname, sizeof(req.ifra_name));
933 		memcpy(&req.ifra_addr, addr, sizeof(req.ifra_addr));
934 		if (add)
935 			memcpy(&req.ifra_mask, mask, sizeof(req.ifra_addr));
936 
937 		log_debug("%s: %s inet %s netmask %s", __func__,
938 		    add ? "add" : "del", print_addr(addr), print_addr(mask));
939 
940 		ioreq = add ? SIOCAIFADDR : SIOCDIFADDR;
941 		if (ioctl(ivr->ivr_iosock, ioreq, &req) == -1) {
942 			log_warn("%s: req: %lu", __func__, ioreq);
943 			return (-1);
944 		}
945 		break;
946 	case AF_INET6:
947 		bzero(&req6, sizeof(req6));
948 		strncpy(req6.ifra_name, ifname, sizeof(req6.ifra_name));
949 		req6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
950 		req6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
951 
952 		memcpy(&req6.ifra_addr, addr, sizeof(req6.ifra_addr));
953 		if (add)
954 			memcpy(&req6.ifra_prefixmask, mask,
955 			    sizeof(req6.ifra_prefixmask));
956 
957 		log_debug("%s: %s inet6 %s netmask %s", __func__,
958 		    add ? "add" : "del", print_addr(addr), print_addr(mask));
959 
960 		ioreq = add ? SIOCAIFADDR_IN6 : SIOCDIFADDR_IN6;
961 		if (ioctl(ivr->ivr_iosock6, ioreq, &req6) == -1) {
962 			log_warn("%s: req: %lu", __func__, ioreq);
963 			return (-1);
964 		}
965 		break;
966 	default:
967 		return (-1);
968 	}
969 
970 	return (0);
971 }
972