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