1/*	$OpenBSD: vroute.c,v 1.19 2023/06/13 12:34:12 tb 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
43int vroute_setroute(struct iked *, uint32_t, struct sockaddr *, uint8_t,
44    struct sockaddr *, int);
45int vroute_doroute(struct iked *, int, int, int, uint8_t, struct sockaddr *,
46    struct sockaddr *, struct sockaddr *, int *);
47int vroute_doaddr(struct iked *, char *, struct sockaddr *, struct sockaddr *, int);
48int vroute_dodns(struct iked *, struct sockaddr *, int, unsigned int);
49void vroute_cleanup(struct iked *);
50void vroute_rtmsg_cb(int, short, void *);
51
52void vroute_insertaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
53void vroute_removeaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
54void vroute_insertdns(struct iked *, int, struct sockaddr *);
55void vroute_removedns(struct iked *, int, struct sockaddr *);
56void vroute_insertroute(struct iked *, int, struct sockaddr *, struct sockaddr *);
57void vroute_removeroute(struct iked *, int, struct sockaddr *, struct sockaddr *);
58
59struct 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};
65TAILQ_HEAD(vroute_addrs, vroute_addr);
66
67struct 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};
74TAILQ_HEAD(vroute_routes, vroute_route);
75
76struct vroute_dns {
77	struct	sockaddr_storage	vd_addr;
78	int				vd_ifidx;
79	TAILQ_ENTRY(vroute_dns)		vd_entry;
80};
81TAILQ_HEAD(vroute_dnss, vroute_dns);
82
83struct 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
95struct vroute_msg {
96	struct rt_msghdr	 vm_rtm;
97	uint8_t			 vm_space[512];
98};
99
100int vroute_process(struct iked *, int msglen, struct vroute_msg *,
101    struct sockaddr *, struct sockaddr *, struct sockaddr *, int *);
102
103void
104vroute_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
153void
154vroute_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
190void
191vroute_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
226int
227vroute_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
273int
274vroute_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
325int
326vroute_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
341int
342vroute_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
378void
379vroute_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
402void
403vroute_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
424void
425vroute_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
440void
441vroute_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
457void
458vroute_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
475void
476vroute_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
494int
495vroute_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
502int
503vroute_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
510int
511vroute_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
518int
519vroute_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
573int
574vroute_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	}
635
636	if (type == RTM_ADD)
637		vroute_insertroute(env, rdomain, dest, mask);
638	else
639		vroute_removeroute(env, rdomain, dest, mask);
640	return (vroute_doroute(env, flags, addrs, rdomain, type,
641	    dest, mask, gateway, NULL));
642}
643
644int
645vroute_getcloneroute(struct iked *env, struct imsg *imsg)
646{
647	struct sockaddr		*dst;
648	struct sockaddr_storage	 dest;
649	struct sockaddr_storage	 mask;
650	struct sockaddr_storage	 addr;
651	uint8_t			*ptr;
652	size_t			 left;
653	uint32_t		 rdomain;
654	int			 flags;
655	int			 addrs;
656	int			 need_gw;
657
658	ptr = (uint8_t *)imsg->data;
659	left = IMSG_DATA_SIZE(imsg);
660
661	if (left < sizeof(rdomain))
662		return (-1);
663	rdomain = *ptr;
664	ptr += sizeof(rdomain);
665	left -= sizeof(rdomain);
666
667	bzero(&dest, sizeof(dest));
668	bzero(&mask, sizeof(mask));
669	bzero(&addr, sizeof(addr));
670
671	if (left < sizeof(struct sockaddr))
672		return (-1);
673	dst = (struct sockaddr *)ptr;
674	if (left < dst->sa_len)
675		return (-1);
676	memcpy(&dest, dst, dst->sa_len);
677	ptr += dst->sa_len;
678	left -= dst->sa_len;
679
680	/* Get route to peer */
681	flags = RTF_UP | RTF_HOST | RTF_STATIC;
682	if (vroute_doroute(env, flags, RTA_DST, rdomain, RTM_GET,
683	    (struct sockaddr *)&dest, (struct sockaddr *)&mask,
684	    (struct sockaddr *)&addr, &need_gw))
685		return (-1);
686
687	if (need_gw)
688		flags |= RTF_GATEWAY;
689
690	memcpy(&dest, dst, dst->sa_len);
691	socket_setport((struct sockaddr *)&dest, 0);
692	vroute_insertroute(env, rdomain, (struct sockaddr *)&dest, NULL);
693
694	/* Set explicit route to peer with gateway addr*/
695	addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
696	return (vroute_doroute(env, flags, addrs, rdomain, RTM_ADD,
697	    (struct sockaddr *)&dest, (struct sockaddr *)&mask,
698	    (struct sockaddr *)&addr, NULL));
699}
700
701int
702vroute_dodns(struct iked *env, struct sockaddr *dns, int add,
703    unsigned int ifidx)
704{
705	struct vroute_msg	 m_rtmsg;
706	struct sockaddr_in	 *in;
707	struct sockaddr_in6	 *in6;
708	struct sockaddr_rtdns	 rtdns;
709	struct iked_vroute_sc	*ivr = env->sc_vroute;
710	struct iovec		 iov[3];
711	int			 i;
712	long			 pad = 0;
713	int			 iovcnt = 0, padlen;
714
715	bzero(&m_rtmsg, sizeof(m_rtmsg));
716#define rtm m_rtmsg.vm_rtm
717	rtm.rtm_version = RTM_VERSION;
718	rtm.rtm_type = RTM_PROPOSAL;
719	rtm.rtm_seq = ++ivr->ivr_rtseq;
720	rtm.rtm_priority = RTP_PROPOSAL_STATIC;
721	rtm.rtm_flags = RTF_UP;
722	rtm.rtm_addrs = RTA_DNS;
723	rtm.rtm_index = ifidx;
724
725	iov[iovcnt].iov_base = &rtm;
726	iov[iovcnt].iov_len = sizeof(rtm);
727	iovcnt++;
728
729	bzero(&rtdns, sizeof(rtdns));
730	rtdns.sr_family = dns->sa_family;
731	rtdns.sr_len = 2;
732	if (add) {
733		switch(dns->sa_family) {
734		case AF_INET:
735			rtdns.sr_family = AF_INET;
736			rtdns.sr_len += sizeof(struct in_addr);
737			in = (struct sockaddr_in *)dns;
738			memcpy(rtdns.sr_dns, &in->sin_addr, sizeof(struct in_addr));
739			break;
740		case AF_INET6:
741			rtdns.sr_family = AF_INET6;
742			rtdns.sr_len += sizeof(struct in6_addr);
743			in6 = (struct sockaddr_in6 *)dns;
744			memcpy(rtdns.sr_dns, &in6->sin6_addr, sizeof(struct in6_addr));
745			break;
746		default:
747			return (-1);
748		}
749	}
750	iov[iovcnt].iov_base = &rtdns;
751	iov[iovcnt++].iov_len = sizeof(rtdns);
752	padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns);
753	if (padlen > 0) {
754		iov[iovcnt].iov_base = &pad;
755		iov[iovcnt++].iov_len = padlen;
756	}
757
758	for (i = 0; i < iovcnt; i++)
759		rtm.rtm_msglen += iov[i].iov_len;
760#undef rtm
761
762	if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1)
763		log_warn("failed to send route message");
764
765	return (0);
766}
767
768int
769vroute_doroute(struct iked *env, int flags, int addrs, int rdomain, uint8_t type,
770    struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw)
771{
772	struct vroute_msg	 m_rtmsg;
773	struct iovec		 iov[7];
774	struct iked_vroute_sc	*ivr = env->sc_vroute;
775	ssize_t			 len;
776	int			 iovcnt = 0;
777	int			 i;
778	long			 pad = 0;
779	size_t			 padlen;
780
781	bzero(&m_rtmsg, sizeof(m_rtmsg));
782#define rtm m_rtmsg.vm_rtm
783	rtm.rtm_version = RTM_VERSION;
784	rtm.rtm_tableid = rdomain;
785	rtm.rtm_type = type;
786	rtm.rtm_seq = ++ivr->ivr_rtseq;
787	if (type != RTM_GET)
788		rtm.rtm_priority = IKED_VROUTE_PRIO;
789	rtm.rtm_flags = flags;
790	rtm.rtm_addrs = addrs;
791
792	iov[iovcnt].iov_base = &rtm;
793	iov[iovcnt].iov_len = sizeof(rtm);
794	iovcnt++;
795
796	if (rtm.rtm_addrs & RTA_DST) {
797		iov[iovcnt].iov_base = dest;
798		iov[iovcnt].iov_len = dest->sa_len;
799		iovcnt++;
800		padlen = ROUNDUP(dest->sa_len) - dest->sa_len;
801		if (padlen > 0) {
802			iov[iovcnt].iov_base = &pad;
803			iov[iovcnt].iov_len = padlen;
804			iovcnt++;
805		}
806	}
807
808	if (rtm.rtm_addrs & RTA_GATEWAY) {
809		iov[iovcnt].iov_base = addr;
810		iov[iovcnt].iov_len = addr->sa_len;
811		iovcnt++;
812		padlen = ROUNDUP(addr->sa_len) - addr->sa_len;
813		if (padlen > 0) {
814			iov[iovcnt].iov_base = &pad;
815			iov[iovcnt].iov_len = padlen;
816			iovcnt++;
817		}
818	}
819
820	if (rtm.rtm_addrs & RTA_NETMASK) {
821		iov[iovcnt].iov_base = mask;
822		iov[iovcnt].iov_len = mask->sa_len;
823		iovcnt++;
824		padlen = ROUNDUP(mask->sa_len) - mask->sa_len;
825		if (padlen > 0) {
826			iov[iovcnt].iov_base = &pad;
827			iov[iovcnt].iov_len = padlen;
828			iovcnt++;
829		}
830	}
831
832	for (i = 0; i < iovcnt; i++)
833		rtm.rtm_msglen += iov[i].iov_len;
834
835	log_debug("%s: len: %u type: %s rdomain: %d flags %x (%s%s)"
836	    " addrs %x (dst %s mask %s gw %s)", __func__, rtm.rtm_msglen,
837	    type == RTM_ADD ? "RTM_ADD" : type == RTM_DELETE ? "RTM_DELETE" :
838	    type == RTM_GET ? "RTM_GET" : "unknown", rdomain,
839	    flags,
840	    flags & RTF_HOST ? "H" : "",
841	    flags & RTF_GATEWAY ? "G" : "",
842	    addrs,
843	    addrs & RTA_DST ? print_addr(dest) : "<>",
844	    addrs & RTA_NETMASK ? print_addr(mask) : "<>",
845	    addrs & RTA_GATEWAY ? print_addr(addr) : "<>");
846
847	if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1) {
848		if ((type == RTM_ADD && errno != EEXIST) ||
849		    (type == RTM_DELETE && errno != ESRCH)) {
850			log_warn("%s: write %d", __func__, rtm.rtm_errno);
851			return (0);
852		}
853	}
854
855	if (type == RTM_GET) {
856		do {
857			len = read(ivr->ivr_rtsock, &m_rtmsg, sizeof(m_rtmsg));
858		} while(len > 0 && (rtm.rtm_version != RTM_VERSION ||
859		    rtm.rtm_seq != ivr->ivr_rtseq || rtm.rtm_pid != ivr->ivr_pid));
860		return (vroute_process(env, len, &m_rtmsg, dest, mask, addr, need_gw));
861	}
862#undef rtm
863
864	return (0);
865}
866
867int
868vroute_process(struct iked *env, int msglen, struct vroute_msg *m_rtmsg,
869    struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw)
870{
871	struct sockaddr *sa;
872	char *cp;
873	int i;
874
875#define rtm m_rtmsg->vm_rtm
876	if (rtm.rtm_version != RTM_VERSION) {
877		warnx("routing message version %u not understood",
878		    rtm.rtm_version);
879		return (-1);
880	}
881	if (rtm.rtm_msglen > msglen) {
882		warnx("message length mismatch, in packet %u, returned %d",
883		    rtm.rtm_msglen, msglen);
884		return (-1);
885	}
886	if (rtm.rtm_errno) {
887		warnx("RTM_GET: %s (errno %d)",
888		    strerror(rtm.rtm_errno), rtm.rtm_errno);
889		return (-1);
890	}
891	cp = m_rtmsg->vm_space;
892	*need_gw = rtm.rtm_flags & RTF_GATEWAY;
893	if(rtm.rtm_addrs) {
894		for (i = 1; i; i <<= 1) {
895			if (i & rtm.rtm_addrs) {
896				sa = (struct sockaddr *)cp;
897				switch(i) {
898				case RTA_DST:
899					memcpy(dest, cp, sa->sa_len);
900					break;
901				case RTA_NETMASK:
902					memcpy(mask, cp, sa->sa_len);
903					break;
904				case RTA_GATEWAY:
905					memcpy(addr, cp, sa->sa_len);
906					break;
907				}
908				cp += ROUNDUP(sa->sa_len);
909			}
910		}
911	}
912#undef rtm
913	return (0);
914}
915
916int
917vroute_doaddr(struct iked *env, char *ifname, struct sockaddr *addr,
918    struct sockaddr *mask, int add)
919{
920	struct iked_vroute_sc	*ivr = env->sc_vroute;
921	struct ifaliasreq	 req;
922	struct in6_aliasreq	 req6;
923	unsigned long		 ioreq;
924	int			 af;
925
926	af = addr->sa_family;
927	switch (af) {
928	case AF_INET:
929		bzero(&req, sizeof(req));
930		strncpy(req.ifra_name, ifname, sizeof(req.ifra_name));
931		memcpy(&req.ifra_addr, addr, sizeof(req.ifra_addr));
932		if (add)
933			memcpy(&req.ifra_mask, mask, sizeof(req.ifra_addr));
934
935		log_debug("%s: %s inet %s netmask %s", __func__,
936		    add ? "add" : "del", print_addr(addr), print_addr(mask));
937
938		ioreq = add ? SIOCAIFADDR : SIOCDIFADDR;
939		if (ioctl(ivr->ivr_iosock, ioreq, &req) == -1) {
940			log_warn("%s: req: %lu", __func__, ioreq);
941			return (-1);
942		}
943		break;
944	case AF_INET6:
945		bzero(&req6, sizeof(req6));
946		strncpy(req6.ifra_name, ifname, sizeof(req6.ifra_name));
947		req6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
948		req6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
949
950		memcpy(&req6.ifra_addr, addr, sizeof(req6.ifra_addr));
951		if (add)
952			memcpy(&req6.ifra_prefixmask, mask,
953			    sizeof(req6.ifra_prefixmask));
954
955		log_debug("%s: %s inet6 %s netmask %s", __func__,
956		    add ? "add" : "del", print_addr(addr), print_addr(mask));
957
958		ioreq = add ? SIOCAIFADDR_IN6 : SIOCDIFADDR_IN6;
959		if (ioctl(ivr->ivr_iosock6, ioreq, &req6) == -1) {
960			log_warn("%s: req: %lu", __func__, ioreq);
961			return (-1);
962		}
963		break;
964	default:
965		return (-1);
966	}
967
968	return (0);
969}
970