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