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