1 /* $OpenBSD: kroute.c,v 1.67 2023/03/08 04:43:14 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <sys/sysctl.h> 23 #include <sys/tree.h> 24 #include <sys/uio.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <net/if.h> 28 #include <net/if_dl.h> 29 #include <net/if_types.h> 30 #include <net/route.h> 31 #include <err.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <limits.h> 39 40 #include "ospf6d.h" 41 #include "ospfe.h" 42 #include "log.h" 43 44 struct { 45 u_int32_t rtseq; 46 pid_t pid; 47 int fib_sync; 48 u_int8_t fib_prio; 49 int fd; 50 struct event ev; 51 u_int rdomain; 52 } kr_state; 53 54 struct kroute_node { 55 RB_ENTRY(kroute_node) entry; 56 struct kroute_node *next; 57 struct kroute r; 58 }; 59 60 void kr_redist_remove(struct kroute_node *, struct kroute_node *); 61 int kr_redist_eval(struct kroute *, struct kroute *); 62 void kr_redistribute(struct kroute_node *); 63 int kroute_compare(struct kroute_node *, struct kroute_node *); 64 int kr_change_fib(struct kroute_node *, struct kroute *, int, int); 65 int kr_delete_fib(struct kroute_node *); 66 67 struct kroute_node *kroute_find(const struct in6_addr *, u_int8_t, 68 u_int8_t); 69 struct kroute_node *kroute_matchgw(struct kroute_node *, 70 struct in6_addr *, unsigned int); 71 int kroute_insert(struct kroute_node *); 72 int kroute_remove(struct kroute_node *); 73 void kroute_clear(void); 74 75 struct iface *kif_update(u_short, int, struct if_data *, 76 struct sockaddr_dl *); 77 int kif_validate(u_short); 78 79 struct kroute_node *kroute_match(struct in6_addr *); 80 81 int protect_lo(void); 82 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 83 void if_change(u_short, int, struct if_data *, struct sockaddr_dl *); 84 void if_newaddr(u_short, struct sockaddr_in6 *, 85 struct sockaddr_in6 *, struct sockaddr_in6 *); 86 void if_deladdr(u_short, struct sockaddr_in6 *, 87 struct sockaddr_in6 *, struct sockaddr_in6 *); 88 void if_announce(void *); 89 90 int send_rtmsg(int, int, struct kroute *); 91 int dispatch_rtmsg(void); 92 int fetchtable(void); 93 int rtmsg_process(char *, size_t); 94 95 RB_HEAD(kroute_tree, kroute_node) krt; 96 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare) 97 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare) 98 99 int 100 kr_init(int fs, u_int rdomain, int redis_label_or_prefix, u_int8_t fib_prio) 101 { 102 int opt = 0, rcvbuf, default_rcvbuf; 103 socklen_t optlen; 104 int filter_prio = fib_prio; 105 int filter_flags = RTF_LLINFO | RTF_BROADCAST; 106 107 kr_state.fib_sync = fs; 108 kr_state.rdomain = rdomain; 109 kr_state.fib_prio = fib_prio; 110 111 if ((kr_state.fd = socket(AF_ROUTE, 112 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, AF_INET6)) == -1) { 113 log_warn("kr_init: socket"); 114 return (-1); 115 } 116 117 /* not interested in my own messages */ 118 if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK, 119 &opt, sizeof(opt)) == -1) 120 log_warn("kr_init: setsockopt"); /* not fatal */ 121 122 if (redis_label_or_prefix) { 123 filter_prio = 0; 124 log_info("%s: priority filter disabled", __func__); 125 } else 126 log_debug("%s: priority filter enabled", __func__); 127 128 if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_PRIOFILTER, &filter_prio, 129 sizeof(filter_prio)) == -1) { 130 log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__); 131 /* not fatal */ 132 } 133 134 if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_FLAGFILTER, &filter_flags, 135 sizeof(filter_flags)) == -1) { 136 log_warn("%s: setsockopt AF_ROUTE ROUTE_FLAGFILTER", __func__); 137 /* not fatal */ 138 } 139 140 /* grow receive buffer, don't wanna miss messages */ 141 optlen = sizeof(default_rcvbuf); 142 if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, 143 &default_rcvbuf, &optlen) == -1) 144 log_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF"); 145 else 146 for (rcvbuf = MAX_RTSOCK_BUF; 147 rcvbuf > default_rcvbuf && 148 setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, 149 &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS; 150 rcvbuf /= 2) 151 ; /* nothing */ 152 153 kr_state.pid = getpid(); 154 kr_state.rtseq = 1; 155 156 RB_INIT(&krt); 157 158 if (fetchtable() == -1) 159 return (-1); 160 161 if (protect_lo() == -1) 162 return (-1); 163 164 event_set(&kr_state.ev, kr_state.fd, EV_READ | EV_PERSIST, 165 kr_dispatch_msg, NULL); 166 event_add(&kr_state.ev, NULL); 167 168 return (0); 169 } 170 171 int 172 kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int krcount, 173 int action) 174 { 175 int i; 176 struct kroute_node *kn, *nkn; 177 178 if (action == RTM_ADD) { 179 /* 180 * First remove all stale multipath routes. 181 * This step must be skipped when the action is RTM_CHANGE 182 * because it is already a single path route that will be 183 * changed. 184 */ 185 for (kn = kr; kn != NULL; kn = nkn) { 186 for (i = 0; i < krcount; i++) { 187 if (kn->r.scope == kroute[i].scope && 188 IN6_ARE_ADDR_EQUAL(&kn->r.nexthop, 189 &kroute[i].nexthop)) 190 break; 191 } 192 nkn = kn->next; 193 if (i == krcount) { 194 /* stale route */ 195 if (kr_delete_fib(kn) == -1) 196 log_warnx("kr_delete_fib failed"); 197 /* 198 * if head element was removed we need to adjust 199 * the head 200 */ 201 if (kr == kn) 202 kr = nkn; 203 } 204 } 205 } 206 207 /* 208 * now add or change the route 209 */ 210 for (i = 0; i < krcount; i++) { 211 /* nexthop ::1 -> ignore silently */ 212 if (IN6_IS_ADDR_LOOPBACK(&kroute[i].nexthop)) 213 continue; 214 215 if (action == RTM_ADD && kr) { 216 for (kn = kr; kn != NULL; kn = kn->next) { 217 if (kn->r.scope == kroute[i].scope && 218 IN6_ARE_ADDR_EQUAL(&kn->r.nexthop, 219 &kroute[i].nexthop)) 220 break; 221 } 222 223 if (kn != NULL) 224 /* nexthop already present, skip it */ 225 continue; 226 } else 227 /* modify first entry */ 228 kn = kr; 229 230 /* send update */ 231 if (send_rtmsg(kr_state.fd, action, &kroute[i]) == -1) 232 return (-1); 233 234 /* create new entry unless we are changing the first entry */ 235 if (action == RTM_ADD) 236 if ((kn = calloc(1, sizeof(*kn))) == NULL) 237 fatal(NULL); 238 239 kn->r.prefix = kroute[i].prefix; 240 kn->r.prefixlen = kroute[i].prefixlen; 241 kn->r.nexthop = kroute[i].nexthop; 242 kn->r.scope = kroute[i].scope; 243 kn->r.flags = kroute[i].flags | F_OSPFD_INSERTED; 244 kn->r.priority = kr_state.fib_prio; 245 kn->r.ext_tag = kroute[i].ext_tag; 246 rtlabel_unref(kn->r.rtlabel); /* for RTM_CHANGE */ 247 kn->r.rtlabel = kroute[i].rtlabel; 248 249 if (action == RTM_ADD) 250 if (kroute_insert(kn) == -1) { 251 log_debug("kr_update_fib: cannot insert %s", 252 log_in6addr(&kn->r.nexthop)); 253 free(kn); 254 } 255 action = RTM_ADD; 256 } 257 return (0); 258 } 259 260 int 261 kr_change(struct kroute *kroute, int krcount) 262 { 263 struct kroute_node *kr; 264 int action = RTM_ADD; 265 266 kroute->rtlabel = rtlabel_tag2id(kroute->ext_tag); 267 268 kr = kroute_find(&kroute->prefix, kroute->prefixlen, kr_state.fib_prio); 269 if (kr != NULL && kr->next == NULL && krcount == 1) { 270 /* 271 * single path OSPF route. 272 * The kernel does not allow to change a gateway route to a 273 * cloning route or contrary. In this case remove and add the 274 * route, otherwise change the existing one. 275 */ 276 if ((IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop) && 277 !IN6_IS_ADDR_UNSPECIFIED(&kr->r.nexthop)) || 278 (!IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop) && 279 IN6_IS_ADDR_UNSPECIFIED(&kr->r.nexthop))) { 280 if (kr_delete_fib(kr) == 0) 281 kr = NULL; 282 else { 283 log_warn("kr_change: failed to remove route: " 284 "%s/%d", log_in6addr(&kr->r.prefix), 285 kr->r.prefixlen); 286 return (-1); 287 } 288 } else 289 action = RTM_CHANGE; 290 } 291 292 return (kr_change_fib(kr, kroute, krcount, action)); 293 } 294 295 int 296 kr_delete_fib(struct kroute_node *kr) 297 { 298 if (kr->r.priority != kr_state.fib_prio) 299 log_warn("kr_delete_fib: %s/%d has wrong priority %d", 300 log_in6addr(&kr->r.prefix), kr->r.prefixlen, 301 kr->r.priority); 302 303 if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r) == -1) 304 return (-1); 305 306 if (kroute_remove(kr) == -1) 307 return (-1); 308 309 return (0); 310 } 311 312 int 313 kr_delete(struct kroute *kroute) 314 { 315 struct kroute_node *kr, *nkr; 316 317 if ((kr = kroute_find(&kroute->prefix, kroute->prefixlen, 318 kr_state.fib_prio)) == NULL) 319 return (0); 320 321 while (kr != NULL) { 322 nkr = kr->next; 323 if (kr_delete_fib(kr) == -1) 324 return (-1); 325 kr = nkr; 326 } 327 328 return (0); 329 } 330 331 void 332 kr_shutdown(void) 333 { 334 kr_fib_decouple(); 335 kroute_clear(); 336 } 337 338 void 339 kr_fib_couple(void) 340 { 341 struct kroute_node *kr; 342 struct kroute_node *kn; 343 344 if (kr_state.fib_sync == 1) /* already coupled */ 345 return; 346 347 kr_state.fib_sync = 1; 348 349 RB_FOREACH(kr, kroute_tree, &krt) 350 if (kr->r.priority == kr_state.fib_prio) 351 for (kn = kr; kn != NULL; kn = kn->next) 352 send_rtmsg(kr_state.fd, RTM_ADD, &kn->r); 353 354 log_info("kernel routing table coupled"); 355 } 356 357 void 358 kr_fib_decouple(void) 359 { 360 struct kroute_node *kr; 361 struct kroute_node *kn; 362 363 if (kr_state.fib_sync == 0) /* already decoupled */ 364 return; 365 366 RB_FOREACH(kr, kroute_tree, &krt) 367 if (kr->r.priority == kr_state.fib_prio) 368 for (kn = kr; kn != NULL; kn = kn->next) 369 send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r); 370 371 kr_state.fib_sync = 0; 372 373 log_info("kernel routing table decoupled"); 374 } 375 376 void 377 kr_fib_update_prio(u_int8_t fib_prio) 378 { 379 struct kroute_node *kr; 380 381 RB_FOREACH(kr, kroute_tree, &krt) 382 if ((kr->r.flags & F_OSPFD_INSERTED)) 383 kr->r.priority = fib_prio; 384 385 log_info("fib priority changed from %hhu to %hhu", kr_state.fib_prio, 386 fib_prio); 387 388 kr_state.fib_prio = fib_prio; 389 } 390 391 void 392 kr_dispatch_msg(int fd, short event, void *bula) 393 { 394 /* XXX this is stupid */ 395 dispatch_rtmsg(); 396 } 397 398 void 399 kr_show_route(struct imsg *imsg) 400 { 401 struct kroute_node *kr; 402 struct kroute_node *kn; 403 int flags; 404 struct in6_addr addr; 405 406 switch (imsg->hdr.type) { 407 case IMSG_CTL_KROUTE: 408 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags)) { 409 log_warnx("kr_show_route: wrong imsg len"); 410 return; 411 } 412 memcpy(&flags, imsg->data, sizeof(flags)); 413 RB_FOREACH(kr, kroute_tree, &krt) 414 if (!flags || kr->r.flags & flags) { 415 kn = kr; 416 do { 417 main_imsg_compose_ospfe(IMSG_CTL_KROUTE, 418 imsg->hdr.pid, 419 &kn->r, sizeof(kn->r)); 420 } while ((kn = kn->next) != NULL); 421 } 422 break; 423 case IMSG_CTL_KROUTE_ADDR: 424 if (imsg->hdr.len != IMSG_HEADER_SIZE + 425 sizeof(struct in6_addr)) { 426 log_warnx("kr_show_route: wrong imsg len"); 427 return; 428 } 429 memcpy(&addr, imsg->data, sizeof(addr)); 430 kr = kroute_match(&addr); 431 if (kr != NULL) 432 main_imsg_compose_ospfe(IMSG_CTL_KROUTE, imsg->hdr.pid, 433 &kr->r, sizeof(kr->r)); 434 break; 435 default: 436 log_debug("kr_show_route: error handling imsg"); 437 break; 438 } 439 440 main_imsg_compose_ospfe(IMSG_CTL_END, imsg->hdr.pid, NULL, 0); 441 } 442 443 void 444 kr_redist_remove(struct kroute_node *kh, struct kroute_node *kn) 445 { 446 struct kroute *kr; 447 448 /* was the route redistributed? */ 449 if ((kn->r.flags & F_REDISTRIBUTED) == 0) 450 return; 451 452 /* remove redistributed flag */ 453 kn->r.flags &= ~F_REDISTRIBUTED; 454 kr = &kn->r; 455 456 /* probably inform the RDE (check if no other path is redistributed) */ 457 for (kn = kh; kn; kn = kn->next) 458 if (kn->r.flags & F_REDISTRIBUTED) 459 break; 460 461 if (kn == NULL) 462 main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, kr, 463 sizeof(struct kroute)); 464 } 465 466 int 467 kr_redist_eval(struct kroute *kr, struct kroute *new_kr) 468 { 469 u_int32_t metric = 0; 470 471 /* Only non-ospfd routes are considered for redistribution. */ 472 if (!(kr->flags & F_KERNEL)) 473 goto dont_redistribute; 474 475 /* Dynamic routes are not redistributable. */ 476 if (kr->flags & F_DYNAMIC) 477 goto dont_redistribute; 478 479 /* interface is not up and running so don't announce */ 480 if (kr->flags & F_DOWN) 481 goto dont_redistribute; 482 483 /* 484 * We consider loopback, multicast, link- and site-local, 485 * IPv4 mapped and IPv4 compatible addresses as not redistributable. 486 */ 487 if (IN6_IS_ADDR_LOOPBACK(&kr->prefix) || 488 IN6_IS_ADDR_MULTICAST(&kr->prefix) || 489 IN6_IS_ADDR_LINKLOCAL(&kr->prefix) || 490 IN6_IS_ADDR_SITELOCAL(&kr->prefix) || 491 IN6_IS_ADDR_V4MAPPED(&kr->prefix) || 492 IN6_IS_ADDR_V4COMPAT(&kr->prefix)) 493 goto dont_redistribute; 494 /* 495 * Consider networks with nexthop loopback as not redistributable 496 * unless it is a reject or blackhole route. 497 */ 498 if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop) && 499 !(kr->flags & (F_BLACKHOLE|F_REJECT))) 500 goto dont_redistribute; 501 502 /* Should we redistribute this route? */ 503 if (!ospf_redistribute(kr, &metric)) 504 goto dont_redistribute; 505 506 /* prefix should be redistributed */ 507 kr->flags |= F_REDISTRIBUTED; 508 /* 509 * only one of all multipath routes can be redistributed so 510 * redistribute the best one. 511 */ 512 if (new_kr->metric > metric) { 513 *new_kr = *kr; 514 new_kr->metric = metric; 515 } 516 517 return (1); 518 519 dont_redistribute: 520 /* was the route redistributed? */ 521 if ((kr->flags & F_REDISTRIBUTED) == 0) 522 return (0); 523 524 kr->flags &= ~F_REDISTRIBUTED; 525 return (1); 526 } 527 528 void 529 kr_redistribute(struct kroute_node *kh) 530 { 531 struct kroute_node *kn; 532 struct kroute kr; 533 int redistribute = 0; 534 535 /* only the highest prio route can be redistributed */ 536 if (kroute_find(&kh->r.prefix, kh->r.prefixlen, RTP_ANY) != kh) 537 return; 538 539 bzero(&kr, sizeof(kr)); 540 kr.metric = UINT_MAX; 541 for (kn = kh; kn; kn = kn->next) 542 if (kr_redist_eval(&kn->r, &kr)) 543 redistribute = 1; 544 545 if (!redistribute) 546 return; 547 548 if (kr.flags & F_REDISTRIBUTED) { 549 main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, &kr, 550 sizeof(struct kroute)); 551 } else { 552 kr = kh->r; 553 main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &kr, 554 sizeof(struct kroute)); 555 } 556 } 557 558 void 559 kr_reload(int redis_label_or_prefix) 560 { 561 struct kroute_node *kr, *kn; 562 u_int32_t dummy; 563 int r; 564 int filter_prio = kr_state.fib_prio; 565 566 /* update the priority filter */ 567 if (redis_label_or_prefix) { 568 filter_prio = 0; 569 log_info("%s: priority filter disabled", __func__); 570 } else 571 log_debug("%s: priority filter enabled", __func__); 572 573 if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_PRIOFILTER, &filter_prio, 574 sizeof(filter_prio)) == -1) { 575 log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__); 576 /* not fatal */ 577 } 578 579 RB_FOREACH(kr, kroute_tree, &krt) { 580 for (kn = kr; kn; kn = kn->next) { 581 r = ospf_redistribute(&kn->r, &dummy); 582 /* 583 * if it is redistributed, redistribute again metric 584 * may have changed. 585 */ 586 if ((kn->r.flags & F_REDISTRIBUTED && !r) || r) 587 break; 588 } 589 if (kn) { 590 /* 591 * kr_redistribute copes with removes and RDE with 592 * duplicates 593 */ 594 kr_redistribute(kr); 595 } 596 } 597 } 598 599 /* rb-tree compare */ 600 int 601 kroute_compare(struct kroute_node *a, struct kroute_node *b) 602 { 603 int i; 604 605 /* XXX maybe switch a & b */ 606 i = memcmp(&a->r.prefix, &b->r.prefix, sizeof(a->r.prefix)); 607 if (i) 608 return (i); 609 if (a->r.prefixlen < b->r.prefixlen) 610 return (-1); 611 if (a->r.prefixlen > b->r.prefixlen) 612 return (1); 613 614 /* if the priority is RTP_ANY finish on the first address hit */ 615 if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY) 616 return (0); 617 if (a->r.priority < b->r.priority) 618 return (-1); 619 if (a->r.priority > b->r.priority) 620 return (1); 621 return (0); 622 } 623 624 /* tree management */ 625 struct kroute_node * 626 kroute_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio) 627 { 628 struct kroute_node s; 629 struct kroute_node *kn, *tmp; 630 631 s.r.prefix = *prefix; 632 s.r.prefixlen = prefixlen; 633 s.r.priority = prio; 634 635 kn = RB_FIND(kroute_tree, &krt, &s); 636 if (kn && prio == RTP_ANY) { 637 tmp = RB_PREV(kroute_tree, &krt, kn); 638 while (tmp) { 639 if (kroute_compare(&s, tmp) == 0) 640 kn = tmp; 641 else 642 break; 643 tmp = RB_PREV(kroute_tree, &krt, kn); 644 } 645 } 646 return (kn); 647 } 648 649 struct kroute_node * 650 kroute_matchgw(struct kroute_node *kr, struct in6_addr *nh, unsigned int scope) 651 { 652 while (kr) { 653 if (scope == kr->r.scope && 654 IN6_ARE_ADDR_EQUAL(&kr->r.nexthop, nh)) 655 return (kr); 656 kr = kr->next; 657 } 658 659 return (NULL); 660 } 661 662 int 663 kroute_insert(struct kroute_node *kr) 664 { 665 struct kroute_node *krm, *krh; 666 667 if ((krh = RB_INSERT(kroute_tree, &krt, kr)) != NULL) { 668 /* 669 * Multipath route, add at end of list. 670 */ 671 krm = krh; 672 while (krm->next != NULL) 673 krm = krm->next; 674 krm->next = kr; 675 kr->next = NULL; /* to be sure */ 676 } else 677 krh = kr; 678 679 if (!(kr->r.flags & F_KERNEL)) { 680 /* don't validate or redistribute ospf route */ 681 kr->r.flags &= ~F_DOWN; 682 return (0); 683 } 684 685 if (kif_validate(kr->r.ifindex)) 686 kr->r.flags &= ~F_DOWN; 687 else 688 kr->r.flags |= F_DOWN; 689 690 kr_redistribute(krh); 691 return (0); 692 } 693 694 int 695 kroute_remove(struct kroute_node *kr) 696 { 697 struct kroute_node *krm; 698 699 if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) { 700 log_warnx("kroute_remove failed to find %s/%u", 701 log_in6addr(&kr->r.prefix), kr->r.prefixlen); 702 return (-1); 703 } 704 705 if (krm == kr) { 706 /* head element */ 707 if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) { 708 log_warnx("kroute_remove failed for %s/%u", 709 log_in6addr(&kr->r.prefix), kr->r.prefixlen); 710 return (-1); 711 } 712 if (kr->next != NULL) { 713 if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) { 714 log_warnx("kroute_remove failed to add %s/%u", 715 log_in6addr(&kr->r.prefix), 716 kr->r.prefixlen); 717 return (-1); 718 } 719 } 720 } else { 721 /* somewhere in the list */ 722 while (krm->next != kr && krm->next != NULL) 723 krm = krm->next; 724 if (krm->next == NULL) { 725 log_warnx("kroute_remove multipath list corrupted " 726 "for %s/%u", log_in6addr(&kr->r.prefix), 727 kr->r.prefixlen); 728 return (-1); 729 } 730 krm->next = kr->next; 731 } 732 733 kr_redist_remove(krm, kr); 734 rtlabel_unref(kr->r.rtlabel); 735 736 free(kr); 737 return (0); 738 } 739 740 void 741 kroute_clear(void) 742 { 743 struct kroute_node *kr; 744 745 while ((kr = RB_MIN(kroute_tree, &krt)) != NULL) 746 kroute_remove(kr); 747 } 748 749 struct iface * 750 kif_update(u_short ifindex, int flags, struct if_data *ifd, 751 struct sockaddr_dl *sdl) 752 { 753 struct iface *iface; 754 char ifname[IF_NAMESIZE]; 755 756 if ((iface = if_find(ifindex)) == NULL) { 757 bzero(ifname, sizeof(ifname)); 758 if (sdl && sdl->sdl_family == AF_LINK) { 759 if (sdl->sdl_nlen >= sizeof(ifname)) 760 memcpy(ifname, sdl->sdl_data, 761 sizeof(ifname) - 1); 762 else if (sdl->sdl_nlen > 0) 763 memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen); 764 else 765 return (NULL); 766 } else 767 return (NULL); 768 if ((iface = if_new(ifindex, ifname)) == NULL) 769 return (NULL); 770 } 771 772 if_update(iface, ifd->ifi_mtu, flags, ifd->ifi_type, 773 ifd->ifi_link_state, ifd->ifi_baudrate, ifd->ifi_rdomain); 774 775 return (iface); 776 } 777 778 int 779 kif_validate(u_short ifindex) 780 { 781 struct iface *iface; 782 783 if ((iface = if_find(ifindex)) == NULL) { 784 log_warnx("interface with index %u not found", ifindex); 785 return (-1); 786 } 787 788 return ((iface->flags & IFF_UP) && LINK_STATE_IS_UP(iface->linkstate)); 789 } 790 791 struct kroute_node * 792 kroute_match(struct in6_addr *key) 793 { 794 int i; 795 struct kroute_node *kr; 796 struct in6_addr ina; 797 798 /* we will never match the default route */ 799 for (i = 128; i > 0; i--) { 800 inet6applymask(&ina, key, i); 801 if ((kr = kroute_find(&ina, i, RTP_ANY)) != NULL) 802 return (kr); 803 } 804 805 /* if we don't have a match yet, try to find a default route */ 806 if ((kr = kroute_find(&in6addr_any, 0, RTP_ANY)) != NULL) 807 return (kr); 808 809 return (NULL); 810 } 811 812 /* misc */ 813 int 814 protect_lo(void) 815 { 816 struct kroute_node *kr; 817 818 /* special protection for loopback */ 819 if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { 820 log_warn("protect_lo"); 821 return (-1); 822 } 823 memcpy(&kr->r.prefix, &in6addr_loopback, sizeof(kr->r.prefix)); 824 kr->r.prefixlen = 128; 825 kr->r.flags = F_KERNEL|F_CONNECTED; 826 827 if (RB_INSERT(kroute_tree, &krt, kr) != NULL) 828 free(kr); /* kernel route already there, no problem */ 829 830 return (0); 831 } 832 833 #define ROUNDUP(a) \ 834 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 835 836 void 837 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 838 { 839 int i; 840 841 for (i = 0; i < RTAX_MAX; i++) { 842 if (addrs & (1 << i)) { 843 rti_info[i] = sa; 844 sa = (struct sockaddr *)((char *)(sa) + 845 ROUNDUP(sa->sa_len)); 846 } else 847 rti_info[i] = NULL; 848 } 849 } 850 851 void 852 if_change(u_short ifindex, int flags, struct if_data *ifd, 853 struct sockaddr_dl *sdl) 854 { 855 struct kroute_node *kr, *tkr; 856 struct iface *iface; 857 u_int8_t wasvalid, isvalid; 858 859 wasvalid = kif_validate(ifindex); 860 861 if ((iface = kif_update(ifindex, flags, ifd, sdl)) == NULL) { 862 log_warn("if_change: kif_update(%u)", ifindex); 863 return; 864 } 865 866 /* inform engine and rde about state change */ 867 main_imsg_compose_rde(IMSG_IFINFO, 0, iface, sizeof(struct iface)); 868 main_imsg_compose_ospfe(IMSG_IFINFO, 0, iface, sizeof(struct iface)); 869 870 isvalid = (iface->flags & IFF_UP) && 871 LINK_STATE_IS_UP(iface->linkstate); 872 873 if (wasvalid == isvalid) 874 return; /* nothing changed wrt validity */ 875 876 /* update redistribute list */ 877 RB_FOREACH(kr, kroute_tree, &krt) { 878 for (tkr = kr; tkr != NULL; tkr = tkr->next) { 879 if (tkr->r.ifindex == ifindex) { 880 if (isvalid) 881 tkr->r.flags &= ~F_DOWN; 882 else 883 tkr->r.flags |= F_DOWN; 884 885 } 886 } 887 kr_redistribute(kr); 888 } 889 } 890 891 void 892 if_newaddr(u_short ifindex, struct sockaddr_in6 *ifa, struct sockaddr_in6 *mask, 893 struct sockaddr_in6 *brd) 894 { 895 struct iface *iface; 896 struct iface_addr *ia; 897 struct ifaddrchange ifc; 898 899 if (ifa == NULL || ifa->sin6_family != AF_INET6) 900 return; 901 if ((iface = if_find(ifindex)) == NULL) { 902 log_warnx("if_newaddr: corresponding if %d not found", ifindex); 903 return; 904 } 905 906 /* We only care about link-local and global-scope. */ 907 if (IN6_IS_ADDR_UNSPECIFIED(&ifa->sin6_addr) || 908 IN6_IS_ADDR_LOOPBACK(&ifa->sin6_addr) || 909 IN6_IS_ADDR_MULTICAST(&ifa->sin6_addr) || 910 IN6_IS_ADDR_SITELOCAL(&ifa->sin6_addr) || 911 IN6_IS_ADDR_V4MAPPED(&ifa->sin6_addr) || 912 IN6_IS_ADDR_V4COMPAT(&ifa->sin6_addr)) 913 return; 914 915 clearscope(&ifa->sin6_addr); 916 917 if (IN6_IS_ADDR_LINKLOCAL(&ifa->sin6_addr) || 918 iface->flags & IFF_LOOPBACK) 919 iface->addr = ifa->sin6_addr; 920 921 if ((ia = calloc(1, sizeof(struct iface_addr))) == NULL) 922 fatal("if_newaddr"); 923 924 ia->addr = ifa->sin6_addr; 925 926 if (mask) 927 ia->prefixlen = mask2prefixlen(mask); 928 else 929 ia->prefixlen = 0; 930 if (brd && brd->sin6_family == AF_INET6) 931 ia->dstbrd = brd->sin6_addr; 932 else 933 bzero(&ia->dstbrd, sizeof(ia->dstbrd)); 934 935 switch (iface->type) { 936 case IF_TYPE_BROADCAST: 937 case IF_TYPE_NBMA: 938 log_debug("if_newaddr: ifindex %u, addr %s/%d", 939 ifindex, log_in6addr(&ia->addr), ia->prefixlen); 940 break; 941 case IF_TYPE_VIRTUALLINK: /* FIXME */ 942 break; 943 case IF_TYPE_POINTOPOINT: 944 case IF_TYPE_POINTOMULTIPOINT: 945 log_debug("if_newaddr: ifindex %u, addr %s/%d, " 946 "dest %s", ifindex, log_in6addr(&ia->addr), 947 ia->prefixlen, log_in6addr(&ia->dstbrd)); 948 break; 949 default: 950 fatalx("if_newaddr: unknown interface type"); 951 } 952 953 TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry); 954 /* inform engine and rde if interface is used */ 955 if (iface->cflags & F_IFACE_CONFIGURED) { 956 ifc.addr = ia->addr; 957 ifc.dstbrd = ia->dstbrd; 958 ifc.prefixlen = ia->prefixlen; 959 ifc.ifindex = ifindex; 960 main_imsg_compose_ospfe(IMSG_IFADDRNEW, 0, &ifc, sizeof(ifc)); 961 main_imsg_compose_rde(IMSG_IFADDRNEW, 0, &ifc, sizeof(ifc)); 962 } 963 } 964 965 void 966 if_deladdr(u_short ifindex, struct sockaddr_in6 *ifa, struct sockaddr_in6 *mask, 967 struct sockaddr_in6 *brd) 968 { 969 struct iface *iface; 970 struct iface_addr *ia, *nia; 971 struct ifaddrchange ifc; 972 973 if (ifa == NULL || ifa->sin6_family != AF_INET6) 974 return; 975 if ((iface = if_find(ifindex)) == NULL) { 976 log_warnx("if_deladdr: corresponding if %d not found", ifindex); 977 return; 978 } 979 980 /* We only care about link-local and global-scope. */ 981 if (IN6_IS_ADDR_UNSPECIFIED(&ifa->sin6_addr) || 982 IN6_IS_ADDR_LOOPBACK(&ifa->sin6_addr) || 983 IN6_IS_ADDR_MULTICAST(&ifa->sin6_addr) || 984 IN6_IS_ADDR_SITELOCAL(&ifa->sin6_addr) || 985 IN6_IS_ADDR_V4MAPPED(&ifa->sin6_addr) || 986 IN6_IS_ADDR_V4COMPAT(&ifa->sin6_addr)) 987 return; 988 989 clearscope(&ifa->sin6_addr); 990 991 for (ia = TAILQ_FIRST(&iface->ifa_list); ia != NULL; ia = nia) { 992 nia = TAILQ_NEXT(ia, entry); 993 994 if (IN6_ARE_ADDR_EQUAL(&ia->addr, &ifa->sin6_addr)) { 995 log_debug("if_deladdr: ifindex %u, addr %s/%d", 996 ifindex, log_in6addr(&ia->addr), ia->prefixlen); 997 TAILQ_REMOVE(&iface->ifa_list, ia, entry); 998 /* inform engine and rde if interface is used */ 999 if (iface->cflags & F_IFACE_CONFIGURED) { 1000 ifc.addr = ia->addr; 1001 ifc.dstbrd = ia->dstbrd; 1002 ifc.prefixlen = ia->prefixlen; 1003 ifc.ifindex = ifindex; 1004 main_imsg_compose_ospfe(IMSG_IFADDRDEL, 0, &ifc, 1005 sizeof(ifc)); 1006 main_imsg_compose_rde(IMSG_IFADDRDEL, 0, &ifc, 1007 sizeof(ifc)); 1008 } 1009 free(ia); 1010 return; 1011 } 1012 } 1013 } 1014 1015 void 1016 if_announce(void *msg) 1017 { 1018 struct if_announcemsghdr *ifan; 1019 struct iface *iface; 1020 1021 ifan = msg; 1022 1023 switch (ifan->ifan_what) { 1024 case IFAN_ARRIVAL: 1025 if ((iface = if_new(ifan->ifan_index, ifan->ifan_name)) == NULL) 1026 fatal("if_announce failed"); 1027 break; 1028 case IFAN_DEPARTURE: 1029 iface = if_find(ifan->ifan_index); 1030 if_del(iface); 1031 break; 1032 } 1033 } 1034 1035 /* rtsock */ 1036 int 1037 send_rtmsg(int fd, int action, struct kroute *kroute) 1038 { 1039 struct iovec iov[5]; 1040 struct rt_msghdr hdr; 1041 struct pad { 1042 struct sockaddr_in6 addr; 1043 char pad[sizeof(long)]; /* thank you IPv6 */ 1044 } prefix, nexthop, mask; 1045 struct { 1046 struct sockaddr_dl addr; 1047 char pad[sizeof(long)]; 1048 } ifp; 1049 struct sockaddr_rtlabel sa_rl; 1050 int iovcnt = 0; 1051 const char *label; 1052 1053 if (kr_state.fib_sync == 0) 1054 return (0); 1055 1056 /* initialize header */ 1057 bzero(&hdr, sizeof(hdr)); 1058 hdr.rtm_version = RTM_VERSION; 1059 hdr.rtm_type = action; 1060 hdr.rtm_priority = kr_state.fib_prio; 1061 hdr.rtm_tableid = kr_state.rdomain; /* rtableid */ 1062 if (action == RTM_CHANGE) 1063 hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE; 1064 else 1065 hdr.rtm_flags = RTF_MPATH; 1066 hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */ 1067 hdr.rtm_hdrlen = sizeof(hdr); 1068 hdr.rtm_msglen = sizeof(hdr); 1069 /* adjust iovec */ 1070 iov[iovcnt].iov_base = &hdr; 1071 iov[iovcnt++].iov_len = sizeof(hdr); 1072 1073 bzero(&prefix, sizeof(prefix)); 1074 prefix.addr.sin6_len = sizeof(struct sockaddr_in6); 1075 prefix.addr.sin6_family = AF_INET6; 1076 prefix.addr.sin6_addr = kroute->prefix; 1077 /* adjust header */ 1078 hdr.rtm_addrs |= RTA_DST; 1079 hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); 1080 /* adjust iovec */ 1081 iov[iovcnt].iov_base = &prefix; 1082 iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6)); 1083 1084 if (!IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop)) { 1085 bzero(&nexthop, sizeof(nexthop)); 1086 nexthop.addr.sin6_len = sizeof(struct sockaddr_in6); 1087 nexthop.addr.sin6_family = AF_INET6; 1088 nexthop.addr.sin6_addr = kroute->nexthop; 1089 nexthop.addr.sin6_scope_id = kroute->scope; 1090 /* 1091 * XXX we should set the sin6_scope_id but the kernel 1092 * XXX does not expect it that way. It must be fiddled 1093 * XXX into the sin6_addr. Welcome to the typical 1094 * XXX IPv6 insanity and all without wine bottles. 1095 */ 1096 embedscope(&nexthop.addr); 1097 1098 /* adjust header */ 1099 hdr.rtm_flags |= RTF_GATEWAY; 1100 hdr.rtm_addrs |= RTA_GATEWAY; 1101 hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); 1102 /* adjust iovec */ 1103 iov[iovcnt].iov_base = &nexthop; 1104 iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6)); 1105 } else if (kroute->ifindex) { 1106 /* 1107 * We don't have an interface address in that network, 1108 * so we install a cloning route. The kernel will then 1109 * do neighbor discovery. 1110 */ 1111 bzero(&ifp, sizeof(ifp)); 1112 ifp.addr.sdl_len = sizeof(struct sockaddr_dl); 1113 ifp.addr.sdl_family = AF_LINK; 1114 1115 ifp.addr.sdl_index = kroute->ifindex; 1116 /* adjust header */ 1117 hdr.rtm_flags |= RTF_CLONING; 1118 hdr.rtm_addrs |= RTA_GATEWAY; 1119 hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl)); 1120 /* adjust iovec */ 1121 iov[iovcnt].iov_base = &ifp; 1122 iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl)); 1123 } 1124 1125 bzero(&mask, sizeof(mask)); 1126 mask.addr.sin6_len = sizeof(struct sockaddr_in6); 1127 mask.addr.sin6_family = AF_INET6; 1128 mask.addr.sin6_addr = *prefixlen2mask(kroute->prefixlen); 1129 /* adjust header */ 1130 if (kroute->prefixlen == 128) 1131 hdr.rtm_flags |= RTF_HOST; 1132 hdr.rtm_addrs |= RTA_NETMASK; 1133 hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); 1134 /* adjust iovec */ 1135 iov[iovcnt].iov_base = &mask; 1136 iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6)); 1137 1138 if (kroute->rtlabel != 0) { 1139 sa_rl.sr_len = sizeof(sa_rl); 1140 sa_rl.sr_family = AF_UNSPEC; 1141 label = rtlabel_id2name(kroute->rtlabel); 1142 if (strlcpy(sa_rl.sr_label, label, 1143 sizeof(sa_rl.sr_label)) >= sizeof(sa_rl.sr_label)) { 1144 log_warnx("send_rtmsg: invalid rtlabel"); 1145 return (-1); 1146 } 1147 /* adjust header */ 1148 hdr.rtm_addrs |= RTA_LABEL; 1149 hdr.rtm_msglen += sizeof(sa_rl); 1150 /* adjust iovec */ 1151 iov[iovcnt].iov_base = &sa_rl; 1152 iov[iovcnt++].iov_len = sizeof(sa_rl); 1153 } 1154 1155 retry: 1156 if (writev(fd, iov, iovcnt) == -1) { 1157 if (errno == ESRCH) { 1158 if (hdr.rtm_type == RTM_CHANGE) { 1159 hdr.rtm_type = RTM_ADD; 1160 goto retry; 1161 } else if (hdr.rtm_type == RTM_DELETE) { 1162 log_info("route %s/%u vanished before delete", 1163 log_sockaddr(&prefix), kroute->prefixlen); 1164 return (0); 1165 } 1166 } 1167 log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type, 1168 log_sockaddr(&prefix), kroute->prefixlen); 1169 return (0); 1170 } 1171 1172 return (0); 1173 } 1174 1175 int 1176 fetchtable(void) 1177 { 1178 size_t len; 1179 int mib[7]; 1180 char *buf; 1181 int rv; 1182 1183 mib[0] = CTL_NET; 1184 mib[1] = PF_ROUTE; 1185 mib[2] = 0; 1186 mib[3] = AF_INET6; 1187 mib[4] = NET_RT_DUMP; 1188 mib[5] = 0; 1189 mib[6] = kr_state.rdomain; /* rtableid */ 1190 1191 if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) { 1192 log_warn("sysctl"); 1193 return (-1); 1194 } 1195 if ((buf = malloc(len)) == NULL) { 1196 log_warn("fetchtable"); 1197 return (-1); 1198 } 1199 if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) { 1200 log_warn("sysctl"); 1201 free(buf); 1202 return (-1); 1203 } 1204 1205 rv = rtmsg_process(buf, len); 1206 free(buf); 1207 1208 return (rv); 1209 } 1210 1211 int 1212 fetchifs(u_short ifindex) 1213 { 1214 size_t len; 1215 int mib[6]; 1216 char *buf; 1217 int rv; 1218 1219 mib[0] = CTL_NET; 1220 mib[1] = PF_ROUTE; 1221 mib[2] = 0; 1222 mib[3] = AF_INET6; 1223 mib[4] = NET_RT_IFLIST; 1224 mib[5] = ifindex; 1225 1226 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) { 1227 log_warn("sysctl"); 1228 return (-1); 1229 } 1230 if ((buf = malloc(len)) == NULL) { 1231 log_warn("fetchifs"); 1232 return (-1); 1233 } 1234 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) { 1235 log_warn("sysctl"); 1236 free(buf); 1237 return (-1); 1238 } 1239 1240 rv = rtmsg_process(buf, len); 1241 free(buf); 1242 1243 return (rv); 1244 } 1245 1246 int 1247 dispatch_rtmsg(void) 1248 { 1249 char buf[RT_BUF_SIZE]; 1250 ssize_t n; 1251 1252 if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { 1253 if (errno == EAGAIN || errno == EINTR) 1254 return (0); 1255 log_warn("dispatch_rtmsg: read error"); 1256 return (-1); 1257 } 1258 1259 if (n == 0) { 1260 log_warnx("routing socket closed"); 1261 return (-1); 1262 } 1263 1264 return (rtmsg_process(buf, n)); 1265 } 1266 1267 int 1268 rtmsg_process(char *buf, size_t len) 1269 { 1270 struct rt_msghdr *rtm; 1271 struct if_msghdr ifm; 1272 struct ifa_msghdr *ifam; 1273 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1274 struct sockaddr_in6 *sa_in6; 1275 struct sockaddr_rtlabel *label; 1276 struct kroute_node *kr, *okr; 1277 struct in6_addr prefix, nexthop; 1278 u_int8_t prefixlen, prio; 1279 int flags, mpath; 1280 unsigned int scope; 1281 u_short ifindex = 0; 1282 int rv; 1283 size_t offset; 1284 char *next; 1285 1286 for (offset = 0; offset < len; offset += rtm->rtm_msglen) { 1287 next = buf + offset; 1288 rtm = (struct rt_msghdr *)next; 1289 if (len < offset + sizeof(u_short) || 1290 len < offset + rtm->rtm_msglen) 1291 fatalx("rtmsg_process: partial rtm in buffer"); 1292 if (rtm->rtm_version != RTM_VERSION) 1293 continue; 1294 1295 bzero(&prefix, sizeof(prefix)); 1296 bzero(&nexthop, sizeof(nexthop)); 1297 scope = 0; 1298 prefixlen = 0; 1299 flags = F_KERNEL; 1300 mpath = 0; 1301 prio = 0; 1302 1303 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 1304 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1305 1306 switch (rtm->rtm_type) { 1307 case RTM_ADD: 1308 case RTM_GET: 1309 case RTM_CHANGE: 1310 case RTM_DELETE: 1311 if (rtm->rtm_errno) /* failed attempts... */ 1312 continue; 1313 1314 if (rtm->rtm_tableid != kr_state.rdomain) 1315 continue; 1316 1317 if (rtm->rtm_type == RTM_GET && 1318 rtm->rtm_pid != kr_state.pid) /* caused by us */ 1319 continue; 1320 1321 if ((sa = rti_info[RTAX_DST]) == NULL) 1322 continue; 1323 1324 /* Skip ARP/ND cache and broadcast routes. */ 1325 if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST)) 1326 continue; 1327 1328 if (rtm->rtm_flags & RTF_MPATH) 1329 mpath = 1; 1330 prio = rtm->rtm_priority; 1331 flags = (prio == kr_state.fib_prio) ? 1332 F_OSPFD_INSERTED : F_KERNEL; 1333 1334 switch (sa->sa_family) { 1335 case AF_INET6: 1336 prefix = 1337 ((struct sockaddr_in6 *)sa)->sin6_addr; 1338 sa_in6 = (struct sockaddr_in6 *) 1339 rti_info[RTAX_NETMASK]; 1340 if (sa_in6 != NULL) { 1341 if (sa_in6->sin6_len != 0) 1342 prefixlen = mask2prefixlen( 1343 sa_in6); 1344 } else if (rtm->rtm_flags & RTF_HOST) 1345 prefixlen = 128; 1346 else 1347 fatalx("classful IPv6 address?!!"); 1348 if (rtm->rtm_flags & RTF_STATIC) 1349 flags |= F_STATIC; 1350 if (rtm->rtm_flags & RTF_BLACKHOLE) 1351 flags |= F_BLACKHOLE; 1352 if (rtm->rtm_flags & RTF_REJECT) 1353 flags |= F_REJECT; 1354 if (rtm->rtm_flags & RTF_DYNAMIC) 1355 flags |= F_DYNAMIC; 1356 break; 1357 default: 1358 continue; 1359 } 1360 1361 ifindex = rtm->rtm_index; 1362 if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { 1363 switch (sa->sa_family) { 1364 case AF_INET6: 1365 if (rtm->rtm_flags & RTF_CONNECTED) 1366 flags |= F_CONNECTED; 1367 1368 sa_in6 = (struct sockaddr_in6 *)sa; 1369 /* 1370 * XXX The kernel provides the scope 1371 * XXX via the kame hack instead of 1372 * XXX the scope_id field. 1373 */ 1374 recoverscope(sa_in6); 1375 nexthop = sa_in6->sin6_addr; 1376 scope = sa_in6->sin6_scope_id; 1377 break; 1378 case AF_LINK: 1379 flags |= F_CONNECTED; 1380 break; 1381 } 1382 } 1383 } 1384 1385 switch (rtm->rtm_type) { 1386 case RTM_ADD: 1387 case RTM_GET: 1388 case RTM_CHANGE: 1389 if (IN6_IS_ADDR_UNSPECIFIED(&nexthop) && 1390 !(flags & F_CONNECTED)) { 1391 log_warnx("rtmsg_process no nexthop for %s/%u", 1392 log_in6addr(&prefix), prefixlen); 1393 continue; 1394 } 1395 1396 if ((okr = kroute_find(&prefix, prefixlen, prio)) 1397 != NULL) { 1398 /* just add new multipath routes */ 1399 if (mpath && rtm->rtm_type == RTM_ADD) 1400 goto add; 1401 /* get the correct route */ 1402 kr = okr; 1403 if (mpath && (kr = kroute_matchgw(okr, 1404 &nexthop, scope)) == NULL) { 1405 log_warnx("rtmsg_process: mpath route" 1406 " not found"); 1407 /* add routes we missed out earlier */ 1408 goto add; 1409 } 1410 1411 if (kr->r.flags & F_REDISTRIBUTED) 1412 flags |= F_REDISTRIBUTED; 1413 kr->r.nexthop = nexthop; 1414 kr->r.scope = scope; 1415 kr->r.flags = flags; 1416 kr->r.ifindex = ifindex; 1417 1418 rtlabel_unref(kr->r.rtlabel); 1419 kr->r.rtlabel = 0; 1420 kr->r.ext_tag = 0; 1421 if ((label = (struct sockaddr_rtlabel *) 1422 rti_info[RTAX_LABEL]) != NULL) { 1423 kr->r.rtlabel = 1424 rtlabel_name2id(label->sr_label); 1425 kr->r.ext_tag = 1426 rtlabel_id2tag(kr->r.rtlabel); 1427 } 1428 1429 if (kif_validate(kr->r.ifindex)) 1430 kr->r.flags &= ~F_DOWN; 1431 else 1432 kr->r.flags |= F_DOWN; 1433 1434 /* just readd, the RDE will care */ 1435 kr_redistribute(okr); 1436 } else { 1437 add: 1438 if ((kr = calloc(1, 1439 sizeof(struct kroute_node))) == NULL) { 1440 log_warn("rtmsg_process calloc"); 1441 return (-1); 1442 } 1443 kr->r.prefix = prefix; 1444 kr->r.prefixlen = prefixlen; 1445 kr->r.nexthop = nexthop; 1446 kr->r.scope = scope; 1447 kr->r.flags = flags; 1448 kr->r.ifindex = ifindex; 1449 kr->r.priority = prio; 1450 1451 if (rtm->rtm_priority == kr_state.fib_prio) { 1452 log_warnx("alien OSPF route %s/%d", 1453 log_in6addr(&prefix), prefixlen); 1454 rv = send_rtmsg(kr_state.fd, 1455 RTM_DELETE, &kr->r); 1456 free(kr); 1457 if (rv == -1) 1458 return (-1); 1459 } else { 1460 if ((label = (struct sockaddr_rtlabel *) 1461 rti_info[RTAX_LABEL]) != NULL) { 1462 kr->r.rtlabel = 1463 rtlabel_name2id( 1464 label->sr_label); 1465 kr->r.ext_tag = 1466 rtlabel_id2tag( 1467 kr->r.rtlabel); 1468 } 1469 1470 kroute_insert(kr); 1471 } 1472 } 1473 break; 1474 case RTM_DELETE: 1475 if ((kr = kroute_find(&prefix, prefixlen, prio)) == 1476 NULL) 1477 continue; 1478 if (!(kr->r.flags & F_KERNEL)) 1479 continue; 1480 /* get the correct route */ 1481 okr = kr; 1482 if (mpath && (kr = kroute_matchgw(kr, &nexthop, 1483 scope)) == NULL) { 1484 log_warnx("rtmsg_process mpath route" 1485 " not found"); 1486 return (-1); 1487 } 1488 if (kroute_remove(kr) == -1) 1489 return (-1); 1490 break; 1491 case RTM_IFINFO: 1492 memcpy(&ifm, next, sizeof(ifm)); 1493 if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data, 1494 (struct sockaddr_dl *)rti_info[RTAX_IFP]); 1495 break; 1496 case RTM_NEWADDR: 1497 ifam = (struct ifa_msghdr *)rtm; 1498 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 1499 RTA_BRD)) == 0) 1500 break; 1501 1502 if_newaddr(ifam->ifam_index, 1503 (struct sockaddr_in6 *)rti_info[RTAX_IFA], 1504 (struct sockaddr_in6 *)rti_info[RTAX_NETMASK], 1505 (struct sockaddr_in6 *)rti_info[RTAX_BRD]); 1506 break; 1507 case RTM_DELADDR: 1508 ifam = (struct ifa_msghdr *)rtm; 1509 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 1510 RTA_BRD)) == 0) 1511 break; 1512 1513 if_deladdr(ifam->ifam_index, 1514 (struct sockaddr_in6 *)rti_info[RTAX_IFA], 1515 (struct sockaddr_in6 *)rti_info[RTAX_NETMASK], 1516 (struct sockaddr_in6 *)rti_info[RTAX_BRD]); 1517 break; 1518 case RTM_IFANNOUNCE: 1519 if_announce(next); 1520 break; 1521 default: 1522 /* ignore for now */ 1523 break; 1524 } 1525 } 1526 return (offset); 1527 } 1528