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