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