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