1 /* $OpenBSD: route6d.c,v 1.99 2019/06/28 13:32:50 deraadt Exp $ */ 2 /* $KAME: route6d.c,v 1.111 2006/10/25 06:38:13 jinmei Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/ioctl.h> 35 #include <sys/socket.h> 36 #include <sys/sysctl.h> 37 #include <sys/uio.h> 38 39 #include <net/if.h> 40 #include <net/route.h> 41 #include <netinet/in.h> 42 #include <netinet/ip6.h> 43 #include <netinet/udp.h> 44 #include <netinet6/in6_var.h> 45 46 #include <arpa/inet.h> 47 #include <errno.h> 48 #include <ifaddrs.h> 49 #include <netdb.h> 50 #include <poll.h> 51 #include <signal.h> 52 #include <stdarg.h> 53 #include <stddef.h> 54 #include <stdint.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <time.h> 59 #include <unistd.h> 60 61 #include "route6d.h" 62 #include "log.h" 63 64 #define MAXFILTER 40 65 66 #ifdef DEBUG 67 #define INIT_INTERVAL6 6 68 #else 69 #define INIT_INTERVAL6 10 /* Wait to submit a initial riprequest */ 70 #endif 71 72 /* alignment constraint for routing socket */ 73 #define ROUNDUP(a) \ 74 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 75 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 76 77 /* 78 * Following two macros are highly depending on KAME Release 79 */ 80 #define IN6_LINKLOCAL_IFINDEX(addr) \ 81 ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 82 83 #define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 84 do { \ 85 (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 86 (addr).s6_addr[3] = (index) & 0xff; \ 87 } while (0) 88 89 struct ifc { /* Configuration of an interface */ 90 char *ifc_name; /* if name */ 91 struct ifc *ifc_next; 92 int ifc_index; /* if index */ 93 int ifc_mtu; /* if mtu */ 94 int ifc_metric; /* if metric */ 95 u_int ifc_flags; /* flags */ 96 short ifc_cflags; /* IFC_XXX */ 97 struct in6_addr ifc_mylladdr; /* my link-local address */ 98 struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 99 struct iff *ifc_filter; /* filter structure */ 100 struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 101 int ifc_joined; /* joined to ff02::9 */ 102 }; 103 104 struct ifac { /* Address associated to an interface */ 105 struct ifc *ifa_conf; /* back pointer */ 106 struct ifac *ifa_next; 107 struct in6_addr ifa_addr; /* address */ 108 struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 109 int ifa_plen; /* prefix length */ 110 }; 111 112 struct iff { 113 int iff_type; 114 struct in6_addr iff_addr; 115 int iff_plen; 116 struct iff *iff_next; 117 }; 118 119 struct ifc *ifc; 120 int nifc; /* number of valid ifc's */ 121 struct ifc **index2ifc; 122 int nindex2ifc; 123 struct ifc *loopifcp = NULL; /* pointing to loopback */ 124 struct pollfd pfd[2]; 125 int rtsock; /* the routing socket */ 126 int ripsock; /* socket to send/receive RIP datagram */ 127 128 struct rip6 *ripbuf; /* packet buffer for sending */ 129 130 /* 131 * Maintain the routes in a linked list. When the number of the routes 132 * grows, somebody would like to introduce a hash based or a radix tree 133 * based structure. I believe the number of routes handled by RIP is 134 * limited and I don't have to manage a complex data structure, however. 135 * 136 * One of the major drawbacks of the linear linked list is the difficulty 137 * of representing the relationship between a couple of routes. This may 138 * be a significant problem when we have to support route aggregation with 139 * suppressing the specifics covered by the aggregate. 140 */ 141 142 struct riprt { 143 struct riprt *rrt_next; /* next destination */ 144 struct netinfo6 rrt_info; /* network info */ 145 struct in6_addr rrt_gw; /* gateway */ 146 u_long rrt_flags; /* kernel routing table flags */ 147 u_long rrt_rflags; /* route6d routing table flags */ 148 time_t rrt_t; /* when the route validated */ 149 int rrt_index; /* ifindex from which this route got */ 150 }; 151 152 struct riprt *riprt = 0; 153 154 int dflag = 0; /* debug flag */ 155 int qflag = 0; /* quiet flag */ 156 int nflag = 0; /* don't update kernel routing table */ 157 int aflag = 0; /* age out even the statically defined routes */ 158 int hflag = 0; /* don't split horizon */ 159 int lflag = 0; /* exchange site local routes */ 160 int sflag = 0; /* announce static routes w/ split horizon */ 161 int Sflag = 0; /* announce static routes to every interface */ 162 int uflag = 0; /* always log route updates (additions/deletions) */ 163 unsigned long routetag = 0; /* route tag attached on originating case */ 164 165 char *filter[MAXFILTER]; 166 int filtertype[MAXFILTER]; 167 int nfilter = 0; 168 169 pid_t pid; 170 171 struct sockaddr_storage ripsin; 172 173 time_t nextalarm = 0; 174 time_t sup_trig_update = 0; 175 176 static int seq = 0; 177 178 volatile sig_atomic_t seenalrm; 179 volatile sig_atomic_t seenquit; 180 volatile sig_atomic_t seenusr1; 181 182 #define RRTF_AGGREGATE 0x08000000 183 #define RRTF_NOADVERTISE 0x10000000 184 #define RRTF_NH_NOT_LLADDR 0x20000000 185 #define RRTF_SENDANYWAY 0x40000000 186 #define RRTF_CHANGED 0x80000000 187 188 void sighandler(int); 189 void ripalarm(void); 190 void riprecv(void); 191 void ripsend(struct ifc *, struct sockaddr_in6 *, int); 192 int out_filter(struct riprt *, struct ifc *); 193 void init(void); 194 void sockopt(struct ifc *); 195 void ifconfig(void); 196 void ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); 197 void rtrecv(void); 198 int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *, 199 const struct sockaddr_in6 *); 200 int rt_deladdr(struct ifc *, const struct sockaddr_in6 *, 201 const struct sockaddr_in6 *); 202 void filterconfig(void); 203 int getifmtu(int); 204 const char *rttypes(struct rt_msghdr *); 205 const char *rtflags(struct rt_msghdr *); 206 const char *ifflags(int); 207 int ifrt(struct ifc *, int); 208 void ifrt_p2p(struct ifc *, int); 209 void applyplen(struct in6_addr *, int); 210 void ifrtdump(int); 211 void ifdump(int); 212 void ifdump0(const struct ifc *); 213 void rtdump(int); 214 void rt_entry(struct rt_msghdr *, int); 215 __dead void rtdexit(void); 216 void riprequest(struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *); 217 void ripflush(struct ifc *, struct sockaddr_in6 *); 218 void sendrequest(struct ifc *); 219 int sin6mask2len(const struct sockaddr_in6 *); 220 int mask2len(const struct in6_addr *, int); 221 int sendpacket(struct sockaddr_in6 *, int); 222 int addroute(struct riprt *, const struct in6_addr *, struct ifc *); 223 int delroute(struct netinfo6 *, struct in6_addr *); 224 struct in6_addr *getroute(struct netinfo6 *, struct in6_addr *); 225 void krtread(int); 226 int tobeadv(struct riprt *, struct ifc *); 227 char *xstrdup(const char *); 228 const char *hms(void); 229 const char *inet6_n2p(const struct in6_addr *); 230 struct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int); 231 struct in6_addr *plen2mask(int); 232 struct riprt *rtsearch(struct netinfo6 *, struct riprt **); 233 int ripinterval(int); 234 time_t ripsuptrig(void); 235 unsigned int if_maxindex(void); 236 struct ifc *ifc_find(char *); 237 struct iff *iff_find(struct ifc *, int); 238 void setindex2ifc(int, struct ifc *); 239 240 int 241 main(int argc, char *argv[]) 242 { 243 int ch; 244 int error = 0; 245 struct ifc *ifcp; 246 sigset_t mask, omask; 247 char *ep; 248 249 log_init(1); /* log to stderr until daemonized */ 250 251 while ((ch = getopt(argc, argv, "A:N:O:T:L:t:adDhlnqsSu")) != -1) { 252 switch (ch) { 253 case 'A': 254 case 'N': 255 case 'O': 256 case 'T': 257 case 'L': 258 if (nfilter >= MAXFILTER) { 259 fatalx("Exceeds MAXFILTER"); 260 /*NOTREACHED*/ 261 } 262 filtertype[nfilter] = ch; 263 filter[nfilter++] = xstrdup(optarg); 264 break; 265 case 't': 266 ep = NULL; 267 routetag = strtoul(optarg, &ep, 0); 268 if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 269 fatalx("invalid route tag"); 270 /*NOTREACHED*/ 271 } 272 break; 273 #define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 274 FLAG('a', aflag, 1); break; 275 FLAG('d', dflag, 1); break; 276 FLAG('D', dflag, 2); break; 277 FLAG('h', hflag, 1); break; 278 FLAG('l', lflag, 1); break; 279 FLAG('n', nflag, 1); break; 280 FLAG('q', qflag, 1); break; 281 FLAG('s', sflag, 1); break; 282 FLAG('S', Sflag, 1); break; 283 FLAG('u', uflag, 1); break; 284 #undef FLAG 285 default: 286 fatalx("Invalid option specified, terminating"); 287 /*NOTREACHED*/ 288 } 289 } 290 argc -= optind; 291 argv += optind; 292 if (argc > 0) { 293 fatalx("bogus extra arguments"); 294 /*NOTREACHED*/ 295 } 296 297 if (geteuid()) { 298 nflag = 1; 299 log_warn("No kernel update is allowed"); 300 } 301 302 if (dflag == 0) { 303 if (daemon(0, 0) == -1) { 304 fatal("daemon"); 305 /*NOTREACHED*/ 306 } 307 } 308 309 log_init(dflag); 310 311 pid = getpid(); 312 313 if ((ripbuf = calloc(RIP6_MAXMTU, 1)) == NULL) 314 fatal(NULL); 315 ripbuf->rip6_cmd = RIP6_RESPONSE; 316 ripbuf->rip6_vers = RIP6_VERSION; 317 ripbuf->rip6_res1[0] = 0; 318 ripbuf->rip6_res1[1] = 0; 319 320 init(); 321 322 if (pledge("stdio inet route mcast", NULL) == -1) 323 fatal("pledge"); 324 325 ifconfig(); 326 327 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 328 if (ifcp->ifc_index < 0) { 329 log_warn( 330 "No ifindex found at %s (no link-local address?)", 331 ifcp->ifc_name); 332 error++; 333 } 334 } 335 if (error) 336 exit(1); 337 if (loopifcp == NULL) { 338 fatalx("No loopback found"); 339 /*NOTREACHED*/ 340 } 341 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 342 ifrt(ifcp, 0); 343 filterconfig(); 344 krtread(0); 345 if (dflag) 346 ifrtdump(0); 347 348 if (signal(SIGALRM, sighandler) == SIG_ERR || 349 signal(SIGQUIT, sighandler) == SIG_ERR || 350 signal(SIGTERM, sighandler) == SIG_ERR || 351 signal(SIGUSR1, sighandler) == SIG_ERR || 352 signal(SIGHUP, sighandler) == SIG_ERR || 353 signal(SIGINT, sighandler) == SIG_ERR) { 354 fatal("signal"); 355 /*NOTREACHED*/ 356 } 357 /* 358 * To avoid rip packet congestion (not on a cable but in this 359 * process), wait for a moment to send the first RIP6_RESPONSE 360 * packets. 361 */ 362 alarm(ripinterval(INIT_INTERVAL6)); 363 364 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 365 if (iff_find(ifcp, 'N')) 366 continue; 367 if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 368 sendrequest(ifcp); 369 } 370 371 log_info("**** Started ****"); 372 sigemptyset(&mask); 373 sigaddset(&mask, SIGALRM); 374 while (1) { 375 if (seenalrm) { 376 ripalarm(); 377 seenalrm = 0; 378 continue; 379 } 380 if (seenquit) { 381 rtdexit(); 382 seenquit = 0; 383 continue; 384 } 385 if (seenusr1) { 386 ifrtdump(SIGUSR1); 387 seenusr1 = 0; 388 continue; 389 } 390 391 switch (poll(pfd, 2, INFTIM)) 392 { 393 case -1: 394 if (errno != EINTR) { 395 fatal("poll"); 396 /*NOTREACHED*/ 397 } 398 continue; 399 case 0: 400 continue; 401 default: 402 if (pfd[0].revents & POLLIN) { 403 sigprocmask(SIG_BLOCK, &mask, &omask); 404 riprecv(); 405 sigprocmask(SIG_SETMASK, &omask, NULL); 406 } 407 if (pfd[1].revents & POLLIN) { 408 sigprocmask(SIG_BLOCK, &mask, &omask); 409 rtrecv(); 410 sigprocmask(SIG_SETMASK, &omask, NULL); 411 } 412 } 413 } 414 } 415 416 void 417 sighandler(int signo) 418 { 419 420 switch (signo) { 421 case SIGALRM: 422 seenalrm++; 423 break; 424 case SIGQUIT: 425 case SIGTERM: 426 seenquit++; 427 break; 428 case SIGUSR1: 429 case SIGHUP: 430 case SIGINT: 431 seenusr1++; 432 break; 433 } 434 } 435 436 /* 437 * gracefully exits after resetting sockopts. 438 */ 439 void 440 rtdexit(void) 441 { 442 struct riprt *rrt; 443 444 alarm(0); 445 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 446 if (rrt->rrt_rflags & RRTF_AGGREGATE) { 447 delroute(&rrt->rrt_info, &rrt->rrt_gw); 448 } 449 } 450 close(ripsock); 451 close(rtsock); 452 log_info("**** Terminated ****"); 453 exit(1); 454 } 455 456 /* 457 * Called periodically: 458 * 1. age out the learned route. remove it if necessary. 459 * 2. submit RIP6_RESPONSE packets. 460 * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 461 * to invoke this function in every 1 or 5 or 10 seconds only to age the 462 * routes more precisely. 463 */ 464 void 465 ripalarm(void) 466 { 467 struct ifc *ifcp; 468 struct riprt *rrt, *rrt_prev, *rrt_next; 469 time_t t_lifetime, t_holddown; 470 471 /* age the RIP routes */ 472 rrt_prev = 0; 473 t_lifetime = time(NULL) - RIP_LIFETIME; 474 t_holddown = t_lifetime - RIP_HOLDDOWN; 475 for (rrt = riprt; rrt; rrt = rrt_next) { 476 rrt_next = rrt->rrt_next; 477 478 if (rrt->rrt_t == 0) { 479 rrt_prev = rrt; 480 continue; 481 } 482 if (rrt->rrt_t < t_holddown) { 483 if (rrt_prev) { 484 rrt_prev->rrt_next = rrt->rrt_next; 485 } else { 486 riprt = rrt->rrt_next; 487 } 488 delroute(&rrt->rrt_info, &rrt->rrt_gw); 489 free(rrt); 490 continue; 491 } 492 if (rrt->rrt_t < t_lifetime) 493 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 494 rrt_prev = rrt; 495 } 496 /* Supply updates */ 497 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 498 if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 499 ripsend(ifcp, &ifcp->ifc_ripsin, 0); 500 } 501 alarm(ripinterval(SUPPLY_INTERVAL6)); 502 } 503 504 void 505 init(void) 506 { 507 int i, error; 508 const int int0 = 0, int1 = 1, int255 = 255; 509 struct addrinfo hints, *res; 510 char port[NI_MAXSERV]; 511 512 ifc = (struct ifc *)NULL; 513 nifc = 0; 514 nindex2ifc = 0; /*initial guess*/ 515 index2ifc = NULL; 516 snprintf(port, sizeof(port), "%u", RIP6_PORT); 517 518 memset(&hints, 0, sizeof(hints)); 519 hints.ai_family = PF_INET6; 520 hints.ai_socktype = SOCK_DGRAM; 521 hints.ai_flags = AI_PASSIVE; 522 error = getaddrinfo(NULL, port, &hints, &res); 523 if (error) { 524 fatalx(gai_strerror(error)); 525 /*NOTREACHED*/ 526 } 527 if (res->ai_next) { 528 fatalx(":: resolved to multiple address"); 529 /*NOTREACHED*/ 530 } 531 532 ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 533 if (ripsock == -1) { 534 fatal("rip socket"); 535 /*NOTREACHED*/ 536 } 537 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 538 &int1, sizeof(int1)) == -1) { 539 fatal("rip IPV6_V6ONLY"); 540 /*NOTREACHED*/ 541 } 542 if (bind(ripsock, res->ai_addr, res->ai_addrlen) == -1) { 543 fatal("rip bind"); 544 /*NOTREACHED*/ 545 } 546 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 547 &int255, sizeof(int255)) == -1) { 548 fatal("rip IPV6_MULTICAST_HOPS"); 549 /*NOTREACHED*/ 550 } 551 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 552 &int0, sizeof(int0)) == -1) { 553 fatal("rip IPV6_MULTICAST_LOOP"); 554 /*NOTREACHED*/ 555 } 556 557 i = 1; 558 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i, 559 sizeof(i)) == -1) { 560 fatal("rip IPV6_RECVPKTINFO"); 561 /*NOTREACHED*/ 562 } 563 564 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 565 &int1, sizeof(int1)) == -1) { 566 fatal("rip IPV6_RECVHOPLIMIT"); 567 /*NOTREACHED*/ 568 } 569 570 freeaddrinfo(res); 571 memset(&hints, 0, sizeof(hints)); 572 hints.ai_family = PF_INET6; 573 hints.ai_socktype = SOCK_DGRAM; 574 error = getaddrinfo(RIP6_DEST, port, &hints, &res); 575 if (error) { 576 fatalx(gai_strerror(error)); 577 /*NOTREACHED*/ 578 } 579 if (res->ai_next) { 580 fatalx(RIP6_DEST " resolved to multiple address"); 581 /*NOTREACHED*/ 582 } 583 memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 584 freeaddrinfo(res); 585 586 pfd[0].fd = ripsock; 587 pfd[0].events = POLLIN; 588 589 if (nflag == 0) { 590 if ((rtsock = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { 591 fatal("route socket"); 592 /*NOTREACHED*/ 593 } 594 pfd[1].fd = rtsock; 595 pfd[1].events = POLLIN; 596 } else 597 pfd[1].fd = -1; 598 599 } 600 601 #define RIPSIZE(n) \ 602 (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 603 604 /* 605 * ripflush flushes the rip datagram stored in the rip buffer 606 */ 607 static int nrt; 608 static struct netinfo6 *np; 609 610 void 611 ripflush(struct ifc *ifcp, struct sockaddr_in6 *sin6) 612 { 613 int i; 614 int error; 615 616 if (ifcp) 617 log_debug("Send(%s): info(%d) to %s.%d", 618 ifcp->ifc_name, nrt, 619 inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 620 else 621 log_debug("Send: info(%d) to %s.%d", 622 nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 623 if (dflag >= 2) { 624 np = ripbuf->rip6_nets; 625 for (i = 0; i < nrt; i++, np++) { 626 if (np->rip6_metric == NEXTHOP_METRIC) { 627 if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 628 log_enqueue(" NextHop reset"); 629 else { 630 log_enqueue(" NextHop %s", 631 inet6_n2p(&np->rip6_dest)); 632 } 633 } else { 634 log_enqueue(" %s/%d[%d]", 635 inet6_n2p(&np->rip6_dest), 636 np->rip6_plen, np->rip6_metric); 637 } 638 if (np->rip6_tag) { 639 log_enqueue(" tag=0x%04x", 640 ntohs(np->rip6_tag) & 0xffff); 641 } 642 log_debug(""); 643 } 644 } 645 error = sendpacket(sin6, RIPSIZE(nrt)); 646 if (error == EAFNOSUPPORT) { 647 /* Protocol not supported */ 648 log_debug("Could not send info to %s (%s): " 649 "set IFF_UP to 0", 650 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 651 ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 652 } 653 nrt = 0; np = ripbuf->rip6_nets; 654 } 655 656 /* 657 * Generate RIP6_RESPONSE packets and send them. 658 */ 659 void 660 ripsend(struct ifc *ifcp, struct sockaddr_in6 *sin6, int flag) 661 { 662 struct riprt *rrt; 663 struct in6_addr *nh; /* next hop */ 664 int maxrte; 665 666 if (qflag) 667 return; 668 669 if (ifcp == NULL) { 670 /* 671 * Request from non-link local address is not 672 * a regular route6d update. 673 */ 674 maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 675 sizeof(struct udphdr) - 676 sizeof(struct rip6) + sizeof(struct netinfo6)) / 677 sizeof(struct netinfo6); 678 nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 679 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 680 if (rrt->rrt_rflags & RRTF_NOADVERTISE) 681 continue; 682 /* Put the route to the buffer */ 683 *np = rrt->rrt_info; 684 np++; nrt++; 685 if (nrt == maxrte) { 686 ripflush(NULL, sin6); 687 nh = NULL; 688 } 689 } 690 if (nrt) /* Send last packet */ 691 ripflush(NULL, sin6); 692 return; 693 } 694 695 if ((flag & RRTF_SENDANYWAY) == 0 && 696 (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 697 return; 698 699 /* -N: no use */ 700 if (iff_find(ifcp, 'N') != NULL) 701 return; 702 703 /* -T: generate default route only */ 704 if (iff_find(ifcp, 'T') != NULL) { 705 struct netinfo6 rrt_info; 706 memset(&rrt_info, 0, sizeof(struct netinfo6)); 707 rrt_info.rip6_dest = in6addr_any; 708 rrt_info.rip6_plen = 0; 709 rrt_info.rip6_metric = 1; 710 rrt_info.rip6_metric += ifcp->ifc_metric; 711 rrt_info.rip6_tag = htons(routetag & 0xffff); 712 np = ripbuf->rip6_nets; 713 *np = rrt_info; 714 nrt = 1; 715 ripflush(ifcp, sin6); 716 return; 717 } 718 719 maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 720 sizeof(struct udphdr) - 721 sizeof(struct rip6) + sizeof(struct netinfo6)) / 722 sizeof(struct netinfo6); 723 724 nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 725 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 726 if (rrt->rrt_rflags & RRTF_NOADVERTISE) 727 continue; 728 729 /* Need to check filter here */ 730 if (out_filter(rrt, ifcp) == 0) 731 continue; 732 733 /* Check split horizon and other conditions */ 734 if (tobeadv(rrt, ifcp) == 0) 735 continue; 736 737 /* Only considers the routes with flag if specified */ 738 if ((flag & RRTF_CHANGED) && 739 (rrt->rrt_rflags & RRTF_CHANGED) == 0) 740 continue; 741 742 /* Check nexthop */ 743 if (rrt->rrt_index == ifcp->ifc_index && 744 !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 745 (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 746 if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 747 if (nrt == maxrte - 2) 748 ripflush(ifcp, sin6); 749 np->rip6_dest = rrt->rrt_gw; 750 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 751 SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 752 np->rip6_plen = 0; 753 np->rip6_tag = 0; 754 np->rip6_metric = NEXTHOP_METRIC; 755 nh = &rrt->rrt_gw; 756 np++; nrt++; 757 } 758 } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 759 !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 760 rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 761 /* Reset nexthop */ 762 if (nrt == maxrte - 2) 763 ripflush(ifcp, sin6); 764 memset(np, 0, sizeof(struct netinfo6)); 765 np->rip6_metric = NEXTHOP_METRIC; 766 nh = NULL; 767 np++; nrt++; 768 } 769 770 /* Put the route to the buffer */ 771 *np = rrt->rrt_info; 772 np++; nrt++; 773 if (nrt == maxrte) { 774 ripflush(ifcp, sin6); 775 nh = NULL; 776 } 777 } 778 if (nrt) /* Send last packet */ 779 ripflush(ifcp, sin6); 780 } 781 782 /* 783 * outbound filter logic, per-route/interface. 784 */ 785 int 786 out_filter(struct riprt *rrt, struct ifc *ifcp) 787 { 788 struct iff *iffp; 789 struct in6_addr ia; 790 int ok; 791 792 /* 793 * -A: filter out less specific routes, if we have aggregated 794 * route configured. 795 */ 796 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 797 if (iffp->iff_type != 'A') 798 continue; 799 if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 800 continue; 801 ia = rrt->rrt_info.rip6_dest; 802 applyplen(&ia, iffp->iff_plen); 803 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 804 return 0; 805 } 806 807 /* 808 * if it is an aggregated route, advertise it only to the 809 * interfaces specified on -A. 810 */ 811 if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 812 ok = 0; 813 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 814 if (iffp->iff_type != 'A') 815 continue; 816 if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 817 IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 818 &iffp->iff_addr)) { 819 ok = 1; 820 break; 821 } 822 } 823 if (!ok) 824 return 0; 825 } 826 827 /* 828 * -O: advertise only if prefix matches the configured prefix. 829 */ 830 if (iff_find(ifcp, 'O')) { 831 ok = 0; 832 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 833 if (iffp->iff_type != 'O') 834 continue; 835 if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 836 continue; 837 ia = rrt->rrt_info.rip6_dest; 838 applyplen(&ia, iffp->iff_plen); 839 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 840 ok = 1; 841 break; 842 } 843 } 844 if (!ok) 845 return 0; 846 } 847 848 /* the prefix should be advertised */ 849 return 1; 850 } 851 852 /* 853 * Determine if the route is to be advertised on the specified interface. 854 * It checks options specified in the arguments and the split horizon rule. 855 */ 856 int 857 tobeadv(struct riprt *rrt, struct ifc *ifcp) 858 { 859 860 /* Special care for static routes */ 861 if (rrt->rrt_flags & RTF_STATIC) { 862 /* XXX don't advertise reject/blackhole routes */ 863 if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 864 return 0; 865 866 if (Sflag) /* Yes, advertise it anyway */ 867 return 1; 868 if (sflag && rrt->rrt_index != ifcp->ifc_index) 869 return 1; 870 return 0; 871 } 872 /* Regular split horizon */ 873 if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 874 return 0; 875 return 1; 876 } 877 878 /* 879 * Send a rip packet actually. 880 */ 881 int 882 sendpacket(struct sockaddr_in6 *sin6, int len) 883 { 884 struct msghdr m; 885 struct cmsghdr *cm; 886 struct iovec iov[2]; 887 union { 888 struct cmsghdr hdr; 889 u_char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 890 } cmsgbuf; 891 struct in6_pktinfo *pi; 892 int idx; 893 struct sockaddr_in6 sincopy; 894 895 /* do not overwrite the given sin */ 896 sincopy = *sin6; 897 sin6 = &sincopy; 898 899 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 900 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 901 /* XXX: do not mix the interface index and link index */ 902 idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 903 SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 904 sin6->sin6_scope_id = idx; 905 } else 906 idx = 0; 907 908 m.msg_name = (caddr_t)sin6; 909 m.msg_namelen = sizeof(*sin6); 910 iov[0].iov_base = (caddr_t)ripbuf; 911 iov[0].iov_len = len; 912 m.msg_iov = iov; 913 m.msg_iovlen = 1; 914 if (!idx) { 915 m.msg_control = NULL; 916 m.msg_controllen = 0; 917 } else { 918 memset(&cmsgbuf, 0, sizeof(cmsgbuf)); 919 m.msg_control = (caddr_t)&cmsgbuf.buf; 920 m.msg_controllen = sizeof(cmsgbuf.buf); 921 cm = CMSG_FIRSTHDR(&m); 922 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 923 cm->cmsg_level = IPPROTO_IPV6; 924 cm->cmsg_type = IPV6_PKTINFO; 925 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 926 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 927 pi->ipi6_ifindex = idx; 928 } 929 930 if (sendmsg(ripsock, &m, 0) == -1) { 931 log_debug("sendmsg: %s", strerror(errno)); 932 return errno; 933 } 934 935 return 0; 936 } 937 938 /* 939 * Receive and process RIP packets. Update the routes/kernel forwarding 940 * table if necessary. 941 */ 942 void 943 riprecv(void) 944 { 945 struct ifc *ifcp, *ic; 946 struct sockaddr_in6 fsock; 947 struct in6_addr nh; /* next hop */ 948 struct rip6 *rp; 949 struct netinfo6 *np, *nq; 950 struct riprt *rrt; 951 ssize_t len, nn; 952 unsigned int need_trigger, idx; 953 char buf[4 * RIP6_MAXMTU]; 954 time_t t; 955 struct msghdr m; 956 struct cmsghdr *cm; 957 struct iovec iov[2]; 958 union { 959 struct cmsghdr hdr; 960 u_char buf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + 961 CMSG_SPACE(sizeof(int))]; 962 } cmsgbuf; 963 struct in6_pktinfo *pi = NULL; 964 int *hlimp = NULL; 965 struct iff *iffp; 966 struct in6_addr ia; 967 int ok; 968 time_t t_half_lifetime; 969 970 need_trigger = 0; 971 972 m.msg_name = (caddr_t)&fsock; 973 m.msg_namelen = sizeof(fsock); 974 iov[0].iov_base = (caddr_t)buf; 975 iov[0].iov_len = sizeof(buf); 976 m.msg_iov = iov; 977 m.msg_iovlen = 1; 978 m.msg_control = (caddr_t)&cmsgbuf.buf; 979 m.msg_controllen = sizeof(cmsgbuf.buf); 980 if ((len = recvmsg(ripsock, &m, 0)) == -1) { 981 fatal("recvmsg"); 982 /*NOTREACHED*/ 983 } 984 idx = 0; 985 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 986 cm; 987 cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 988 if (cm->cmsg_level != IPPROTO_IPV6) 989 continue; 990 switch (cm->cmsg_type) { 991 case IPV6_PKTINFO: 992 if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) { 993 log_debug( 994 "invalid cmsg length for IPV6_PKTINFO"); 995 return; 996 } 997 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 998 idx = pi->ipi6_ifindex; 999 break; 1000 case IPV6_HOPLIMIT: 1001 if (cm->cmsg_len != CMSG_LEN(sizeof(int))) { 1002 log_debug( 1003 "invalid cmsg length for IPV6_HOPLIMIT"); 1004 return; 1005 } 1006 hlimp = (int *)CMSG_DATA(cm); 1007 break; 1008 } 1009 } 1010 if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 1011 SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 1012 1013 if (len < sizeof(struct rip6)) { 1014 log_debug("Packet too short"); 1015 return; 1016 } 1017 1018 if (pi == NULL || hlimp == NULL) { 1019 /* 1020 * This can happen when the kernel failed to allocate memory 1021 * for the ancillary data. Although we might be able to handle 1022 * some cases without this info, those are minor and not so 1023 * important, so it's better to discard the packet for safer 1024 * operation. 1025 */ 1026 log_debug("IPv6 packet information cannot be retrieved"); 1027 return; 1028 } 1029 1030 nh = fsock.sin6_addr; 1031 nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 1032 sizeof(struct netinfo6); 1033 rp = (struct rip6 *)buf; 1034 np = rp->rip6_nets; 1035 1036 if (rp->rip6_vers != RIP6_VERSION) { 1037 log_debug("Incorrect RIP version %d", rp->rip6_vers); 1038 return; 1039 } 1040 if (rp->rip6_cmd == RIP6_REQUEST) { 1041 if (idx && idx < nindex2ifc) { 1042 ifcp = index2ifc[idx]; 1043 riprequest(ifcp, np, nn, &fsock); 1044 } else { 1045 riprequest(NULL, np, nn, &fsock); 1046 } 1047 return; 1048 } 1049 1050 if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 1051 log_debug("Response from non-ll addr: %s", 1052 inet6_n2p(&fsock.sin6_addr)); 1053 return; /* Ignore packets from non-link-local addr */ 1054 } 1055 if (ntohs(fsock.sin6_port) != RIP6_PORT) { 1056 log_debug("Response from non-rip port from %s", 1057 inet6_n2p(&fsock.sin6_addr)); 1058 return; 1059 } 1060 if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) { 1061 log_debug( 1062 "Response packet with a smaller hop limit (%d) from %s", 1063 *hlimp, inet6_n2p(&fsock.sin6_addr)); 1064 return; 1065 } 1066 /* 1067 * Further validation: since this program does not send off-link 1068 * requests, an incoming response must always come from an on-link 1069 * node. Although this is normally ensured by the source address 1070 * check above, it may not 100% be safe because there are router 1071 * implementations that (invalidly) allow a packet with a link-local 1072 * source address to be forwarded to a different link. 1073 * So we also check whether the destination address is a link-local 1074 * address or the hop limit is 255. Note that RFC2080 does not require 1075 * the specific hop limit for a unicast response, so we cannot assume 1076 * the limitation. 1077 */ 1078 if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) { 1079 log_debug( 1080 "Response packet possibly from an off-link node: " 1081 "from %s to %s hlim=%d", 1082 inet6_n2p(&fsock.sin6_addr), inet6_n2p(&pi->ipi6_addr), 1083 *hlimp); 1084 return; 1085 } 1086 1087 idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 1088 ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 1089 if (!ifcp) { 1090 log_debug("Packets to unknown interface index %d", idx); 1091 return; /* Ignore it */ 1092 } 1093 if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 1094 return; /* The packet is from me; ignore */ 1095 if (rp->rip6_cmd != RIP6_RESPONSE) { 1096 log_debug("Invalid command %d", rp->rip6_cmd); 1097 return; 1098 } 1099 1100 /* -N: no use */ 1101 if (iff_find(ifcp, 'N') != NULL) 1102 return; 1103 1104 log_debug("Recv(%s): from %s.%d info(%zd)", 1105 ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 1106 1107 t = time(NULL); 1108 t_half_lifetime = t - (RIP_LIFETIME/2); 1109 for (; nn; nn--, np++) { 1110 if (np->rip6_metric == NEXTHOP_METRIC) { 1111 /* modify neighbor address */ 1112 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 1113 nh = np->rip6_dest; 1114 SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 1115 log_debug("\tNexthop: %s", inet6_n2p(&nh)); 1116 } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 1117 nh = fsock.sin6_addr; 1118 log_debug("\tNexthop: %s", inet6_n2p(&nh)); 1119 } else { 1120 nh = fsock.sin6_addr; 1121 log_debug("\tInvalid Nexthop: %s", 1122 inet6_n2p(&np->rip6_dest)); 1123 } 1124 continue; 1125 } 1126 if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 1127 log_debug("\tMulticast netinfo6: %s/%d [%d]", 1128 inet6_n2p(&np->rip6_dest), 1129 np->rip6_plen, np->rip6_metric); 1130 continue; 1131 } 1132 if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 1133 log_debug("\tLoopback netinfo6: %s/%d [%d]", 1134 inet6_n2p(&np->rip6_dest), 1135 np->rip6_plen, np->rip6_metric); 1136 continue; 1137 } 1138 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 1139 log_debug("\tLink Local netinfo6: %s/%d [%d]", 1140 inet6_n2p(&np->rip6_dest), 1141 np->rip6_plen, np->rip6_metric); 1142 continue; 1143 } 1144 /* may need to pass sitelocal prefix in some case, however*/ 1145 if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 1146 log_debug("\tSite Local netinfo6: %s/%d [%d]", 1147 inet6_n2p(&np->rip6_dest), 1148 np->rip6_plen, np->rip6_metric); 1149 continue; 1150 } 1151 if (dflag >= 2) { 1152 log_enqueue("\tnetinfo6: %s/%d [%d]", 1153 inet6_n2p(&np->rip6_dest), 1154 np->rip6_plen, np->rip6_metric); 1155 if (np->rip6_tag) 1156 log_enqueue(" tag=0x%04x", 1157 ntohs(np->rip6_tag) & 0xffff); 1158 ia = np->rip6_dest; 1159 applyplen(&ia, np->rip6_plen); 1160 if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 1161 log_enqueue(" [junk outside prefix]"); 1162 } 1163 1164 /* 1165 * -L: listen only if the prefix matches the configuration 1166 */ 1167 ok = 1; /* if there's no L filter, it is ok */ 1168 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 1169 if (iffp->iff_type != 'L') 1170 continue; 1171 ok = 0; 1172 if (np->rip6_plen < iffp->iff_plen) 1173 continue; 1174 /* special rule: ::/0 means default, not "in /0" */ 1175 if (iffp->iff_plen == 0 && np->rip6_plen > 0) 1176 continue; 1177 ia = np->rip6_dest; 1178 applyplen(&ia, iffp->iff_plen); 1179 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 1180 ok = 1; 1181 break; 1182 } 1183 } 1184 1185 if (!ok) { 1186 if (dflag >= 2) 1187 log_debug(" (filtered)"); 1188 continue; 1189 } 1190 1191 if (dflag >= 2) 1192 log_debug(""); 1193 1194 np->rip6_metric++; 1195 np->rip6_metric += ifcp->ifc_metric; 1196 if (np->rip6_metric > HOPCNT_INFINITY6) 1197 np->rip6_metric = HOPCNT_INFINITY6; 1198 1199 applyplen(&np->rip6_dest, np->rip6_plen); 1200 if ((rrt = rtsearch(np, NULL)) != NULL) { 1201 if (rrt->rrt_t == 0) 1202 continue; /* Intf route has priority */ 1203 nq = &rrt->rrt_info; 1204 if (nq->rip6_metric > np->rip6_metric) { 1205 if (rrt->rrt_index == ifcp->ifc_index && 1206 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1207 /* Small metric from the same gateway */ 1208 nq->rip6_metric = np->rip6_metric; 1209 } else { 1210 /* Better route found */ 1211 rrt->rrt_index = ifcp->ifc_index; 1212 /* Update routing table */ 1213 delroute(nq, &rrt->rrt_gw); 1214 rrt->rrt_gw = nh; 1215 *nq = *np; 1216 addroute(rrt, &nh, ifcp); 1217 } 1218 rrt->rrt_rflags |= RRTF_CHANGED; 1219 rrt->rrt_t = t; 1220 need_trigger = 1; 1221 } else if (nq->rip6_metric < np->rip6_metric && 1222 rrt->rrt_index == ifcp->ifc_index && 1223 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1224 /* Got worse route from same gw */ 1225 nq->rip6_metric = np->rip6_metric; 1226 rrt->rrt_t = t; 1227 rrt->rrt_rflags |= RRTF_CHANGED; 1228 need_trigger = 1; 1229 } else if (nq->rip6_metric == np->rip6_metric && 1230 np->rip6_metric < HOPCNT_INFINITY6) { 1231 if (rrt->rrt_index == ifcp->ifc_index && 1232 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1233 /* same metric, same route from same gw */ 1234 rrt->rrt_t = t; 1235 } else if (rrt->rrt_t < t_half_lifetime) { 1236 /* Better route found */ 1237 rrt->rrt_index = ifcp->ifc_index; 1238 /* Update routing table */ 1239 delroute(nq, &rrt->rrt_gw); 1240 rrt->rrt_gw = nh; 1241 *nq = *np; 1242 addroute(rrt, &nh, ifcp); 1243 rrt->rrt_rflags |= RRTF_CHANGED; 1244 rrt->rrt_t = t; 1245 } 1246 } 1247 /* 1248 * if nq->rip6_metric == HOPCNT_INFINITY6 then 1249 * do not update age value. Do nothing. 1250 */ 1251 } else if (np->rip6_metric < HOPCNT_INFINITY6) { 1252 /* Got a new valid route */ 1253 if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) { 1254 fatal("calloc: struct riprt"); 1255 /*NOTREACHED*/ 1256 } 1257 nq = &rrt->rrt_info; 1258 1259 rrt->rrt_index = ifcp->ifc_index; 1260 rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 1261 rrt->rrt_gw = nh; 1262 *nq = *np; 1263 applyplen(&nq->rip6_dest, nq->rip6_plen); 1264 if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 1265 rrt->rrt_flags |= RTF_HOST; 1266 1267 /* Put the route to the list */ 1268 rrt->rrt_next = riprt; 1269 riprt = rrt; 1270 /* Update routing table */ 1271 addroute(rrt, &nh, ifcp); 1272 rrt->rrt_rflags |= RRTF_CHANGED; 1273 need_trigger = 1; 1274 rrt->rrt_t = t; 1275 } 1276 } 1277 /* XXX need to care the interval between triggered updates */ 1278 if (need_trigger) { 1279 if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 1280 for (ic = ifc; ic; ic = ic->ifc_next) { 1281 if (ifcp->ifc_index == ic->ifc_index) 1282 continue; 1283 if (ic->ifc_flags & IFF_UP) 1284 ripsend(ic, &ic->ifc_ripsin, 1285 RRTF_CHANGED); 1286 } 1287 } 1288 /* Reset the flag */ 1289 for (rrt = riprt; rrt; rrt = rrt->rrt_next) 1290 rrt->rrt_rflags &= ~RRTF_CHANGED; 1291 } 1292 } 1293 1294 /* 1295 * Send all routes request packet to the specified interface. 1296 */ 1297 void 1298 sendrequest(struct ifc *ifcp) 1299 { 1300 struct netinfo6 *np; 1301 int error; 1302 1303 if (ifcp->ifc_flags & IFF_LOOPBACK) 1304 return; 1305 ripbuf->rip6_cmd = RIP6_REQUEST; 1306 np = ripbuf->rip6_nets; 1307 memset(np, 0, sizeof(struct netinfo6)); 1308 np->rip6_metric = HOPCNT_INFINITY6; 1309 log_debug("Send rtdump Request to %s (%s)", 1310 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 1311 error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 1312 if (error == EAFNOSUPPORT) { 1313 /* Protocol not supported */ 1314 log_debug("Could not send rtdump Request to %s (%s): " 1315 "set IFF_UP to 0", 1316 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 1317 ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 1318 } 1319 ripbuf->rip6_cmd = RIP6_RESPONSE; 1320 } 1321 1322 /* 1323 * Process a RIP6_REQUEST packet. 1324 */ 1325 void 1326 riprequest(struct ifc *ifcp, struct netinfo6 *np, int nn, 1327 struct sockaddr_in6 *sin6) 1328 { 1329 int i; 1330 struct riprt *rrt; 1331 1332 if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 1333 np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 1334 /* Specific response, don't split-horizon */ 1335 log_debug("\tRIP Request"); 1336 for (i = 0; i < nn; i++, np++) { 1337 rrt = rtsearch(np, NULL); 1338 if (rrt) 1339 np->rip6_metric = rrt->rrt_info.rip6_metric; 1340 else 1341 np->rip6_metric = HOPCNT_INFINITY6; 1342 } 1343 (void)sendpacket(sin6, RIPSIZE(nn)); 1344 return; 1345 } 1346 /* Whole routing table dump */ 1347 log_debug("\tRIP Request -- whole routing table"); 1348 ripsend(ifcp, sin6, RRTF_SENDANYWAY); 1349 } 1350 1351 /* 1352 * Get information of each interface. 1353 */ 1354 void 1355 ifconfig(void) 1356 { 1357 struct ifaddrs *ifap, *ifa; 1358 struct ifc *ifcp; 1359 struct ipv6_mreq mreq; 1360 int s; 1361 1362 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { 1363 fatal("socket"); 1364 /*NOTREACHED*/ 1365 } 1366 1367 if (getifaddrs(&ifap) != 0) { 1368 fatal("getifaddrs"); 1369 /*NOTREACHED*/ 1370 } 1371 1372 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1373 if (ifa->ifa_addr->sa_family != AF_INET6) 1374 continue; 1375 ifcp = ifc_find(ifa->ifa_name); 1376 /* we are interested in multicast-capable interfaces */ 1377 if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 1378 continue; 1379 if (!ifcp) { 1380 /* new interface */ 1381 if ((ifcp = calloc(1, sizeof(struct ifc))) == NULL) { 1382 fatal("calloc: struct ifc"); 1383 /*NOTREACHED*/ 1384 } 1385 ifcp->ifc_index = -1; 1386 ifcp->ifc_next = ifc; 1387 ifc = ifcp; 1388 nifc++; 1389 ifcp->ifc_name = xstrdup(ifa->ifa_name); 1390 ifcp->ifc_addr = 0; 1391 ifcp->ifc_filter = 0; 1392 ifcp->ifc_flags = ifa->ifa_flags; 1393 log_debug("newif %s <%s>", ifcp->ifc_name, 1394 ifflags(ifcp->ifc_flags)); 1395 if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 1396 loopifcp = ifcp; 1397 } else { 1398 /* update flag, this may be up again */ 1399 if (ifcp->ifc_flags != ifa->ifa_flags) { 1400 log_enqueue("%s: <%s> -> ", ifcp->ifc_name, 1401 ifflags(ifcp->ifc_flags)); 1402 log_debug("<%s>", ifflags(ifa->ifa_flags)); 1403 ifcp->ifc_cflags |= IFC_CHANGED; 1404 } 1405 ifcp->ifc_flags = ifa->ifa_flags; 1406 } 1407 ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 1408 if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 1409 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 1410 mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 1411 mreq.ipv6mr_interface = ifcp->ifc_index; 1412 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 1413 &mreq, sizeof(mreq)) == -1) { 1414 fatalx("IPV6_JOIN_GROUP"); 1415 /*NOTREACHED*/ 1416 } 1417 log_debug("join %s %s", ifcp->ifc_name, RIP6_DEST); 1418 ifcp->ifc_joined++; 1419 } 1420 } 1421 close(s); 1422 freeifaddrs(ifap); 1423 } 1424 1425 void 1426 ifconfig1(const char *name, const struct sockaddr *sa, struct ifc *ifcp, int s) 1427 { 1428 struct in6_ifreq ifr; 1429 const struct sockaddr_in6 *sin6; 1430 struct ifac *ifa; 1431 int plen; 1432 char buf[BUFSIZ]; 1433 1434 sin6 = (const struct sockaddr_in6 *)sa; 1435 if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) 1436 return; 1437 ifr.ifr_addr = *sin6; 1438 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1439 if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) == -1) { 1440 fatal("ioctl: SIOCGIFNETMASK_IN6"); 1441 /*NOTREACHED*/ 1442 } 1443 plen = sin6mask2len(&ifr.ifr_addr); 1444 if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 1445 /* same interface found */ 1446 /* need check if something changed */ 1447 /* XXX not yet implemented */ 1448 return; 1449 } 1450 /* 1451 * New address is found 1452 */ 1453 if ((ifa = calloc(1, sizeof(struct ifac))) == NULL) { 1454 fatal("calloc: struct ifac"); 1455 /*NOTREACHED*/ 1456 } 1457 ifa->ifa_conf = ifcp; 1458 ifa->ifa_next = ifcp->ifc_addr; 1459 ifcp->ifc_addr = ifa; 1460 ifa->ifa_addr = sin6->sin6_addr; 1461 ifa->ifa_plen = plen; 1462 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1463 ifr.ifr_addr = *sin6; 1464 if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) == -1) { 1465 fatal("ioctl: SIOCGIFDSTADDR_IN6"); 1466 /*NOTREACHED*/ 1467 } 1468 ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 1469 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 1470 log_debug("found address %s/%d -- %s", 1471 inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 1472 } else { 1473 log_debug("found address %s/%d", 1474 inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 1475 } 1476 if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 1477 ifcp->ifc_mylladdr = ifa->ifa_addr; 1478 ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 1479 memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 1480 SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 1481 ifcp->ifc_index); 1482 setindex2ifc(ifcp->ifc_index, ifcp); 1483 ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 1484 if (ifcp->ifc_mtu > RIP6_MAXMTU) 1485 ifcp->ifc_mtu = RIP6_MAXMTU; 1486 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) == -1) { 1487 fatal("ioctl: SIOCGIFMETRIC"); 1488 /*NOTREACHED*/ 1489 } 1490 ifcp->ifc_metric = ifr.ifr_metric; 1491 log_debug("\tindex: %d, mtu: %d, metric: %d", 1492 ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 1493 } else 1494 ifcp->ifc_cflags |= IFC_CHANGED; 1495 } 1496 1497 /* 1498 * Receive and process routing messages. 1499 * Update interface information as necesssary. 1500 */ 1501 void 1502 rtrecv(void) 1503 { 1504 char buf[BUFSIZ]; 1505 char *p, *q; 1506 struct rt_msghdr *rtm; 1507 struct ifa_msghdr *ifam; 1508 struct if_msghdr *ifm; 1509 int len; 1510 struct ifc *ifcp, *ic; 1511 int iface = 0, rtable = 0; 1512 struct sockaddr_in6 *rta[RTAX_MAX]; 1513 struct sockaddr_in6 mask; 1514 int i, addrs; 1515 struct riprt *rrt; 1516 1517 if ((len = read(rtsock, buf, sizeof(buf))) == -1) { 1518 perror("read from rtsock"); 1519 exit(1); 1520 } 1521 if (len < sizeof(*rtm)) { 1522 log_debug("short read from rtsock: %d (should be > %zu)", 1523 len, sizeof(*rtm)); 1524 return; 1525 } 1526 if (dflag >= 2) { 1527 log_debug("rtmsg:"); 1528 for (i = 0; i < len; i++) { 1529 log_enqueue("%02x ", buf[i] & 0xff); 1530 if (i % 16 == 15) 1531 log_debug(""); 1532 } 1533 log_debug(""); 1534 } 1535 1536 p = buf; 1537 /* safety against bogus message */ 1538 if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 1539 log_debug("bogus rtmsg: length=%d", 1540 ((struct rt_msghdr *)p)->rtm_msglen); 1541 return; 1542 } 1543 if (((struct rt_msghdr *)p)->rtm_version != RTM_VERSION) 1544 return; 1545 1546 rtm = NULL; 1547 ifam = NULL; 1548 ifm = NULL; 1549 switch (((struct rt_msghdr *)p)->rtm_type) { 1550 case RTM_NEWADDR: 1551 case RTM_DELADDR: 1552 ifam = (struct ifa_msghdr *)p; 1553 addrs = ifam->ifam_addrs; 1554 q = (char *)(ifam + 1); 1555 break; 1556 case RTM_IFINFO: 1557 ifm = (struct if_msghdr *)p; 1558 addrs = ifm->ifm_addrs; 1559 q = (char *)(ifm + 1); 1560 break; 1561 default: 1562 rtm = (struct rt_msghdr *)p; 1563 addrs = rtm->rtm_addrs; 1564 q = (char *)(p + rtm->rtm_hdrlen); 1565 if (rtm->rtm_pid == pid) { 1566 #if 0 1567 log_debug("rtmsg looped back to me, ignored"); 1568 #endif 1569 return; 1570 } 1571 break; 1572 } 1573 memset(&rta, 0, sizeof(rta)); 1574 for (i = 0; i < RTAX_MAX; i++) { 1575 if (addrs & (1 << i)) { 1576 rta[i] = (struct sockaddr_in6 *)q; 1577 q += ROUNDUP(rta[i]->sin6_len); 1578 } 1579 } 1580 1581 log_debug("rtsock: %s (addrs=%x)", 1582 rttypes((struct rt_msghdr *)p), addrs); 1583 if (dflag >= 2) { 1584 for (i = 0; 1585 i < ((struct rt_msghdr *)p)->rtm_msglen; 1586 i++) { 1587 log_enqueue("%02x ", p[i] & 0xff); 1588 if (i % 16 == 15) 1589 log_debug(""); 1590 } 1591 log_debug(""); 1592 } 1593 /* 1594 * Easy ones first. 1595 * 1596 * We may be able to optimize by using ifm->ifm_index or 1597 * ifam->ifam_index. For simplicity we don't do that here. 1598 */ 1599 switch (((struct rt_msghdr *)p)->rtm_type) { 1600 case RTM_NEWADDR: 1601 case RTM_IFINFO: 1602 iface++; 1603 return; 1604 case RTM_ADD: 1605 rtable++; 1606 return; 1607 case RTM_MISS: 1608 case RTM_RESOLVE: 1609 case RTM_GET: 1610 /* nothing to be done here */ 1611 log_debug("\tnothing to be done, ignored"); 1612 return; 1613 } 1614 1615 #if 0 1616 if (rta[RTAX_DST] == NULL) { 1617 log_debug("\tno destination, ignored"); 1618 return; 1619 } 1620 if (rta[RTAX_DST]->sin6_family != AF_INET6) { 1621 log_debug("\taf mismatch, ignored"); 1622 return; 1623 } 1624 if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 1625 log_debug("\tlinklocal destination, ignored"); 1626 return; 1627 } 1628 if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 1629 log_debug("\tloopback destination, ignored"); 1630 return; /* Loopback */ 1631 } 1632 if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 1633 log_debug("\tmulticast destination, ignored"); 1634 return; 1635 } 1636 #endif 1637 1638 /* hard ones */ 1639 switch (((struct rt_msghdr *)p)->rtm_type) { 1640 case RTM_NEWADDR: 1641 case RTM_IFINFO: 1642 case RTM_ADD: 1643 case RTM_MISS: 1644 case RTM_RESOLVE: 1645 case RTM_GET: 1646 /* should already be handled */ 1647 fatalx("rtrecv: never reach here"); 1648 /*NOTREACHED*/ 1649 case RTM_DELETE: 1650 if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 1651 log_debug("\tsome of dst/gw/netmask are " 1652 "unavailable, ignored"); 1653 break; 1654 } 1655 if ((rtm->rtm_flags & RTF_HOST) != 0) { 1656 mask.sin6_len = sizeof(mask); 1657 memset(&mask.sin6_addr, 0xff, 1658 sizeof(mask.sin6_addr)); 1659 rta[RTAX_NETMASK] = &mask; 1660 } else if (!rta[RTAX_NETMASK]) { 1661 log_debug("\tsome of dst/gw/netmask are " 1662 "unavailable, ignored"); 1663 break; 1664 } 1665 if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 1666 rta[RTAX_NETMASK]) == 0) { 1667 rtable++; /*just to be sure*/ 1668 } 1669 break; 1670 case RTM_CHANGE: 1671 case RTM_REDIRECT: 1672 log_debug("\tnot supported yet, ignored"); 1673 break; 1674 case RTM_DELADDR: 1675 if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 1676 log_debug("\tno netmask or ifa given, ignored"); 1677 break; 1678 } 1679 if (ifam->ifam_index < nindex2ifc) 1680 ifcp = index2ifc[ifam->ifam_index]; 1681 else 1682 ifcp = NULL; 1683 if (!ifcp) { 1684 log_debug("\tinvalid ifam_index %d, ignored", 1685 ifam->ifam_index); 1686 break; 1687 } 1688 if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 1689 iface++; 1690 break; 1691 } 1692 1693 if (iface) { 1694 log_debug("rtsock: reconfigure interfaces, refresh interface routes"); 1695 ifconfig(); 1696 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 1697 if (ifcp->ifc_cflags & IFC_CHANGED) { 1698 if (ifrt(ifcp, 1)) { 1699 for (ic = ifc; ic; ic = ic->ifc_next) { 1700 if (ifcp->ifc_index == ic->ifc_index) 1701 continue; 1702 if (ic->ifc_flags & IFF_UP) 1703 ripsend(ic, &ic->ifc_ripsin, 1704 RRTF_CHANGED); 1705 } 1706 /* Reset the flag */ 1707 for (rrt = riprt; rrt; rrt = rrt->rrt_next) 1708 rrt->rrt_rflags &= ~RRTF_CHANGED; 1709 } 1710 ifcp->ifc_cflags &= ~IFC_CHANGED; 1711 } 1712 } 1713 if (rtable) { 1714 log_debug("rtsock: read routing table again"); 1715 krtread(1); 1716 } 1717 } 1718 1719 /* 1720 * remove specified route from the internal routing table. 1721 */ 1722 int 1723 rt_del(const struct sockaddr_in6 *sdst, const struct sockaddr_in6 *sgw, 1724 const struct sockaddr_in6 *smask) 1725 { 1726 const struct in6_addr *dst = NULL; 1727 const struct in6_addr *gw = NULL; 1728 int prefix; 1729 struct netinfo6 ni6; 1730 struct riprt *rrt = NULL; 1731 time_t t_lifetime; 1732 1733 if (sdst->sin6_family != AF_INET6) { 1734 log_debug("\tother AF, ignored"); 1735 return -1; 1736 } 1737 if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 1738 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 1739 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 1740 log_debug("\taddress %s not interesting, ignored", 1741 inet6_n2p(&sdst->sin6_addr)); 1742 return -1; 1743 } 1744 dst = &sdst->sin6_addr; 1745 if (sgw->sin6_family == AF_INET6) { 1746 /* easy case */ 1747 gw = &sgw->sin6_addr; 1748 prefix = sin6mask2len(smask); 1749 } else if (sgw->sin6_family == AF_LINK) { 1750 /* 1751 * Interface route... a hard case. We need to get the prefix 1752 * length from the kernel, but we now are parsing rtmsg. 1753 * We'll purge matching routes from my list, then get the 1754 * fresh list. 1755 */ 1756 struct riprt *longest; 1757 log_debug("\t%s is a interface route, guessing prefixlen", 1758 inet6_n2p(dst)); 1759 longest = NULL; 1760 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 1761 if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 1762 &sdst->sin6_addr) 1763 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 1764 if (!longest 1765 || longest->rrt_info.rip6_plen < 1766 rrt->rrt_info.rip6_plen) { 1767 longest = rrt; 1768 } 1769 } 1770 } 1771 rrt = longest; 1772 if (!rrt) { 1773 log_debug("\tno matching interface route found"); 1774 return -1; 1775 } 1776 gw = &in6addr_loopback; 1777 prefix = rrt->rrt_info.rip6_plen; 1778 } else { 1779 log_debug("\tunsupported af: (gw=%d)", sgw->sin6_family); 1780 return -1; 1781 } 1782 1783 log_enqueue("\tdeleting %s/%d ", inet6_n2p(dst), prefix); 1784 log_debug("gw %s", inet6_n2p(gw)); 1785 t_lifetime = time(NULL) - RIP_LIFETIME; 1786 /* age route for interface address */ 1787 memset(&ni6, 0, sizeof(ni6)); 1788 ni6.rip6_dest = *dst; 1789 ni6.rip6_plen = prefix; 1790 applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 1791 log_debug("\tfind route %s/%d", inet6_n2p(&ni6.rip6_dest), 1792 ni6.rip6_plen); 1793 if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 1794 log_debug("\tno route found"); 1795 return -1; 1796 } 1797 #if 0 1798 if ((rrt->rrt_flags & RTF_STATIC) == 0) { 1799 log_debug("\tyou can delete static routes only"); 1800 } else 1801 #endif 1802 if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 1803 log_enqueue("\tgw mismatch: %s <-> ", 1804 inet6_n2p(&rrt->rrt_gw)); 1805 log_debug("%s", inet6_n2p(gw)); 1806 } else { 1807 log_debug("\troute found, age it"); 1808 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 1809 rrt->rrt_t = t_lifetime; 1810 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 1811 } 1812 } 1813 return 0; 1814 } 1815 1816 /* 1817 * remove specified address from internal interface/routing table. 1818 */ 1819 int 1820 rt_deladdr(struct ifc *ifcp, const struct sockaddr_in6 *sifa, 1821 const struct sockaddr_in6 *smask) 1822 { 1823 const struct in6_addr *addr = NULL; 1824 int prefix; 1825 struct ifac *ifa = NULL; 1826 struct netinfo6 ni6; 1827 struct riprt *rrt = NULL; 1828 time_t t_lifetime; 1829 int updated = 0; 1830 1831 if (sifa->sin6_family != AF_INET6) { 1832 log_debug("\tother AF, ignored"); 1833 return -1; 1834 } 1835 addr = &sifa->sin6_addr; 1836 prefix = sin6mask2len(smask); 1837 1838 log_debug("\tdeleting %s/%d from %s", 1839 inet6_n2p(addr), prefix, ifcp->ifc_name); 1840 ifa = ifa_match(ifcp, addr, prefix); 1841 if (!ifa) { 1842 log_debug("\tno matching ifa found for %s/%d on %s", 1843 inet6_n2p(addr), prefix, ifcp->ifc_name); 1844 return -1; 1845 } 1846 if (ifa->ifa_conf != ifcp) { 1847 log_debug("\taddress table corrupt: back pointer does not match " 1848 "(%s != %s)", 1849 ifcp->ifc_name, ifa->ifa_conf->ifc_name); 1850 return -1; 1851 } 1852 /* remove ifa from interface */ 1853 if (ifcp->ifc_addr == ifa) 1854 ifcp->ifc_addr = ifa->ifa_next; 1855 else { 1856 struct ifac *p; 1857 for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 1858 if (p->ifa_next == ifa) { 1859 p->ifa_next = ifa->ifa_next; 1860 break; 1861 } 1862 } 1863 } 1864 ifa->ifa_next = NULL; 1865 ifa->ifa_conf = NULL; 1866 t_lifetime = time(NULL) - RIP_LIFETIME; 1867 /* age route for interface address */ 1868 memset(&ni6, 0, sizeof(ni6)); 1869 ni6.rip6_dest = ifa->ifa_addr; 1870 ni6.rip6_plen = ifa->ifa_plen; 1871 applyplen(&ni6.rip6_dest, ni6.rip6_plen); 1872 log_debug("\tfind interface route %s/%d on %d", 1873 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 1874 if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 1875 struct in6_addr none; 1876 memset(&none, 0, sizeof(none)); 1877 if (rrt->rrt_index == ifcp->ifc_index && 1878 (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 1879 IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 1880 log_debug("\troute found, age it"); 1881 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 1882 rrt->rrt_t = t_lifetime; 1883 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 1884 } 1885 updated++; 1886 } else { 1887 log_debug("\tnon-interface route found: %s/%d on %d", 1888 inet6_n2p(&rrt->rrt_info.rip6_dest), 1889 rrt->rrt_info.rip6_plen, 1890 rrt->rrt_index); 1891 } 1892 } else 1893 log_debug("\tno interface route found"); 1894 /* age route for p2p destination */ 1895 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1896 memset(&ni6, 0, sizeof(ni6)); 1897 ni6.rip6_dest = ifa->ifa_raddr; 1898 ni6.rip6_plen = 128; 1899 applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 1900 log_debug("\tfind p2p route %s/%d on %d", 1901 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 1902 ifcp->ifc_index); 1903 if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 1904 if (rrt->rrt_index == ifcp->ifc_index && 1905 IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 1906 log_debug("\troute found, age it"); 1907 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 1908 rrt->rrt_t = t_lifetime; 1909 rrt->rrt_info.rip6_metric = 1910 HOPCNT_INFINITY6; 1911 updated++; 1912 } 1913 } else { 1914 log_debug("\tnon-p2p route found: %s/%d on %d", 1915 inet6_n2p(&rrt->rrt_info.rip6_dest), 1916 rrt->rrt_info.rip6_plen, 1917 rrt->rrt_index); 1918 } 1919 } else 1920 log_debug("\tno p2p route found"); 1921 } 1922 return updated ? 0 : -1; 1923 } 1924 1925 /* 1926 * Get each interface address and put those interface routes to the route 1927 * list. 1928 */ 1929 int 1930 ifrt(struct ifc *ifcp, int again) 1931 { 1932 struct ifac *ifa; 1933 struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; 1934 struct netinfo6 *np; 1935 time_t t_lifetime; 1936 int need_trigger = 0; 1937 1938 #if 0 1939 if (ifcp->ifc_flags & IFF_LOOPBACK) 1940 return 0; /* ignore loopback */ 1941 #endif 1942 1943 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1944 ifrt_p2p(ifcp, again); 1945 return 0; 1946 } 1947 1948 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 1949 if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 1950 #if 0 1951 log_debug("route: %s on %s: " 1952 "skip linklocal interface address", 1953 inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 1954 #endif 1955 continue; 1956 } 1957 if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 1958 #if 0 1959 log_debug("route: %s: skip unspec interface address", 1960 ifcp->ifc_name); 1961 #endif 1962 continue; 1963 } 1964 if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) { 1965 #if 0 1966 log_debug("route: %s: skip loopback address", 1967 ifcp->ifc_name); 1968 #endif 1969 continue; 1970 } 1971 if (ifcp->ifc_flags & IFF_UP) { 1972 if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) 1973 fatal("calloc: struct riprt"); 1974 rrt->rrt_index = ifcp->ifc_index; 1975 rrt->rrt_t = 0; /* don't age */ 1976 rrt->rrt_info.rip6_dest = ifa->ifa_addr; 1977 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 1978 rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 1979 rrt->rrt_info.rip6_plen = ifa->ifa_plen; 1980 if (ifa->ifa_plen == 128) 1981 rrt->rrt_flags = RTF_HOST; 1982 else 1983 rrt->rrt_flags = RTF_CLONING; 1984 rrt->rrt_rflags |= RRTF_CHANGED; 1985 applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 1986 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 1987 rrt->rrt_gw = ifa->ifa_addr; 1988 np = &rrt->rrt_info; 1989 search_rrt = rtsearch(np, &prev_rrt); 1990 if (search_rrt != NULL) { 1991 if (search_rrt->rrt_info.rip6_metric <= 1992 rrt->rrt_info.rip6_metric) { 1993 /* Already have better route */ 1994 if (!again) { 1995 log_debug("route: %s/%d: " 1996 "already registered (%s)", 1997 inet6_n2p(&np->rip6_dest), np->rip6_plen, 1998 ifcp->ifc_name); 1999 } 2000 goto next; 2001 } 2002 2003 if (prev_rrt) 2004 prev_rrt->rrt_next = rrt->rrt_next; 2005 else 2006 riprt = rrt->rrt_next; 2007 delroute(&rrt->rrt_info, &rrt->rrt_gw); 2008 } 2009 /* Attach the route to the list */ 2010 log_debug("route: %s/%d: register route (%s)", 2011 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2012 ifcp->ifc_name); 2013 rrt->rrt_next = riprt; 2014 riprt = rrt; 2015 addroute(rrt, &rrt->rrt_gw, ifcp); 2016 rrt = NULL; 2017 sendrequest(ifcp); 2018 ripsend(ifcp, &ifcp->ifc_ripsin, 0); 2019 need_trigger = 1; 2020 } else { 2021 for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 2022 if (loop_rrt->rrt_index == ifcp->ifc_index) { 2023 t_lifetime = time(NULL) - RIP_LIFETIME; 2024 if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 2025 loop_rrt->rrt_t = t_lifetime; 2026 loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 2027 loop_rrt->rrt_rflags |= RRTF_CHANGED; 2028 need_trigger = 1; 2029 } 2030 } 2031 } 2032 } 2033 next: 2034 free(rrt); 2035 } 2036 return need_trigger; 2037 } 2038 2039 /* 2040 * there are couple of p2p interface routing models. "behavior" lets 2041 * you pick one. it looks that gated behavior fits best with BSDs, 2042 * since BSD kernels do not look at prefix length on p2p interfaces. 2043 */ 2044 void 2045 ifrt_p2p(struct ifc *ifcp, int again) 2046 { 2047 struct ifac *ifa; 2048 struct riprt *rrt, *orrt, *prevrrt; 2049 struct netinfo6 *np; 2050 struct in6_addr addr, dest; 2051 int advert, ignore, i; 2052 #define P2PADVERT_NETWORK 1 2053 #define P2PADVERT_ADDR 2 2054 #define P2PADVERT_DEST 4 2055 #define P2PADVERT_MAX 4 2056 const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 2057 const char *category = ""; 2058 const char *noadv; 2059 2060 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 2061 addr = ifa->ifa_addr; 2062 dest = ifa->ifa_raddr; 2063 applyplen(&addr, ifa->ifa_plen); 2064 applyplen(&dest, ifa->ifa_plen); 2065 advert = ignore = 0; 2066 switch (behavior) { 2067 case CISCO: 2068 /* 2069 * honor addr/plen, just like normal shared medium 2070 * interface. this may cause trouble if you reuse 2071 * addr/plen on other interfaces. 2072 * 2073 * advertise addr/plen. 2074 */ 2075 advert |= P2PADVERT_NETWORK; 2076 break; 2077 case GATED: 2078 /* 2079 * prefixlen on p2p interface is meaningless. 2080 * advertise addr/128 and dest/128. 2081 * 2082 * do not install network route to route6d routing 2083 * table (if we do, it would prevent route installation 2084 * for other p2p interface that shares addr/plen). 2085 * 2086 * XXX what should we do if dest is ::? it will not 2087 * get announced anyways (see following filter), 2088 * but we need to think. 2089 */ 2090 advert |= P2PADVERT_ADDR; 2091 advert |= P2PADVERT_DEST; 2092 ignore |= P2PADVERT_NETWORK; 2093 break; 2094 case ROUTE6D: 2095 /* 2096 * just for testing. actually the code is redundant 2097 * given the current p2p interface address assignment 2098 * rule for kame kernel. 2099 * 2100 * intent: 2101 * A/n -> announce A/n 2102 * A B/n, A and B share prefix -> A/n (= B/n) 2103 * A B/n, do not share prefix -> A/128 and B/128 2104 * actually, A/64 and A B/128 are the only cases 2105 * permitted by the kernel: 2106 * A/64 -> A/64 2107 * A B/128 -> A/128 and B/128 2108 */ 2109 if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 2110 if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 2111 advert |= P2PADVERT_NETWORK; 2112 else { 2113 advert |= P2PADVERT_ADDR; 2114 advert |= P2PADVERT_DEST; 2115 ignore |= P2PADVERT_NETWORK; 2116 } 2117 } else 2118 advert |= P2PADVERT_NETWORK; 2119 break; 2120 } 2121 2122 for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 2123 if ((ignore & i) != 0) 2124 continue; 2125 if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) { 2126 fatal("calloc: struct riprt"); 2127 /*NOTREACHED*/ 2128 } 2129 rrt->rrt_index = ifcp->ifc_index; 2130 rrt->rrt_t = 0; /* don't age */ 2131 switch (i) { 2132 case P2PADVERT_NETWORK: 2133 rrt->rrt_info.rip6_dest = ifa->ifa_addr; 2134 rrt->rrt_info.rip6_plen = ifa->ifa_plen; 2135 applyplen(&rrt->rrt_info.rip6_dest, 2136 ifa->ifa_plen); 2137 category = "network"; 2138 break; 2139 case P2PADVERT_ADDR: 2140 rrt->rrt_info.rip6_dest = ifa->ifa_addr; 2141 rrt->rrt_info.rip6_plen = 128; 2142 rrt->rrt_gw = in6addr_loopback; 2143 category = "addr"; 2144 break; 2145 case P2PADVERT_DEST: 2146 rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 2147 rrt->rrt_info.rip6_plen = 128; 2148 rrt->rrt_gw = ifa->ifa_addr; 2149 category = "dest"; 2150 break; 2151 } 2152 if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 2153 IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 2154 #if 0 2155 log_debug("route: %s: skip unspec/linklocal " 2156 "(%s on %s)", category, ifcp->ifc_name); 2157 #endif 2158 free(rrt); 2159 continue; 2160 } 2161 if ((advert & i) == 0) { 2162 rrt->rrt_rflags |= RRTF_NOADVERTISE; 2163 noadv = ", NO-ADV"; 2164 } else 2165 noadv = ""; 2166 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 2167 rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 2168 np = &rrt->rrt_info; 2169 orrt = rtsearch(np, &prevrrt); 2170 if (!orrt) { 2171 /* Attach the route to the list */ 2172 log_debug("route: %s/%d: register route " 2173 "(%s on %s%s)", 2174 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2175 category, ifcp->ifc_name, noadv); 2176 rrt->rrt_next = riprt; 2177 riprt = rrt; 2178 } else if (rrt->rrt_index != orrt->rrt_index || 2179 rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 2180 /* swap route */ 2181 rrt->rrt_next = orrt->rrt_next; 2182 if (prevrrt) 2183 prevrrt->rrt_next = rrt; 2184 else 2185 riprt = rrt; 2186 free(orrt); 2187 2188 log_debug("route: %s/%d: update (%s on %s%s)", 2189 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2190 category, ifcp->ifc_name, noadv); 2191 } else { 2192 /* Already found */ 2193 if (!again) { 2194 log_debug("route: %s/%d: " 2195 "already registered (%s on %s%s)", 2196 inet6_n2p(&np->rip6_dest), 2197 np->rip6_plen, category, 2198 ifcp->ifc_name, noadv); 2199 } 2200 free(rrt); 2201 } 2202 } 2203 } 2204 #undef P2PADVERT_NETWORK 2205 #undef P2PADVERT_ADDR 2206 #undef P2PADVERT_DEST 2207 #undef P2PADVERT_MAX 2208 } 2209 2210 int 2211 getifmtu(int ifindex) 2212 { 2213 int mib[6]; 2214 char *buf = NULL; 2215 size_t needed; 2216 struct if_msghdr *ifm; 2217 int mtu; 2218 2219 mib[0] = CTL_NET; 2220 mib[1] = PF_ROUTE; 2221 mib[2] = 0; 2222 mib[3] = AF_INET6; 2223 mib[4] = NET_RT_IFLIST; 2224 mib[5] = ifindex; 2225 while (1) { 2226 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 2227 fatal("sysctl estimate NET_RT_IFLIST"); 2228 if (needed == 0) 2229 break; 2230 if ((buf = realloc(buf, needed)) == NULL) 2231 fatal(NULL); 2232 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { 2233 if (errno == ENOMEM) 2234 continue; 2235 fatal("sysctl NET_RT_IFLIST"); 2236 } 2237 break; 2238 } 2239 ifm = (struct if_msghdr *)buf; 2240 mtu = ifm->ifm_data.ifi_mtu; 2241 free(buf); 2242 return mtu; 2243 } 2244 2245 const char * 2246 rttypes(struct rt_msghdr *rtm) 2247 { 2248 #define RTTYPE(s, f) \ 2249 do { \ 2250 if (rtm->rtm_type == (f)) \ 2251 return (s); \ 2252 } while (0) 2253 RTTYPE("ADD", RTM_ADD); 2254 RTTYPE("DELETE", RTM_DELETE); 2255 RTTYPE("CHANGE", RTM_CHANGE); 2256 RTTYPE("GET", RTM_GET); 2257 RTTYPE("REDIRECT", RTM_REDIRECT); 2258 RTTYPE("MISS", RTM_MISS); 2259 RTTYPE("RESOLVE", RTM_RESOLVE); 2260 RTTYPE("NEWADDR", RTM_NEWADDR); 2261 RTTYPE("DELADDR", RTM_DELADDR); 2262 RTTYPE("IFINFO", RTM_IFINFO); 2263 #ifdef RTM_OIFINFO 2264 RTTYPE("OIFINFO", RTM_OIFINFO); 2265 #endif 2266 #ifdef RTM_IFANNOUNCE 2267 RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 2268 #endif 2269 #ifdef RTM_NEWMADDR 2270 RTTYPE("NEWMADDR", RTM_NEWMADDR); 2271 #endif 2272 #ifdef RTM_DELMADDR 2273 RTTYPE("DELMADDR", RTM_DELMADDR); 2274 #endif 2275 #undef RTTYPE 2276 return NULL; 2277 } 2278 2279 const char * 2280 rtflags(struct rt_msghdr *rtm) 2281 { 2282 static char buf[BUFSIZ]; 2283 2284 /* 2285 * letter conflict should be okay. painful when *BSD diverges... 2286 */ 2287 strlcpy(buf, "", sizeof(buf)); 2288 #define RTFLAG(s, f) \ 2289 do { \ 2290 if (rtm->rtm_flags & (f)) \ 2291 strlcat(buf, (s), sizeof(buf)); \ 2292 } while (0) 2293 RTFLAG("U", RTF_UP); 2294 RTFLAG("G", RTF_GATEWAY); 2295 RTFLAG("H", RTF_HOST); 2296 RTFLAG("R", RTF_REJECT); 2297 RTFLAG("D", RTF_DYNAMIC); 2298 RTFLAG("M", RTF_MODIFIED); 2299 RTFLAG("d", RTF_DONE); 2300 RTFLAG("m", RTF_MULTICAST); 2301 RTFLAG("C", RTF_CLONING); 2302 RTFLAG("c", RTF_CLONED); 2303 RTFLAG("L", RTF_LLINFO); 2304 RTFLAG("S", RTF_STATIC); 2305 RTFLAG("B", RTF_BLACKHOLE); 2306 RTFLAG("3", RTF_PROTO3); 2307 RTFLAG("2", RTF_PROTO2); 2308 RTFLAG("1", RTF_PROTO1); 2309 RTFLAG("b", RTF_BROADCAST); 2310 #undef RTFLAG 2311 return buf; 2312 } 2313 2314 const char * 2315 ifflags(int flags) 2316 { 2317 static char buf[BUFSIZ]; 2318 2319 strlcpy(buf, "", sizeof(buf)); 2320 #define IFFLAG(s, f) \ 2321 do { \ 2322 if (flags & (f)) { \ 2323 if (buf[0]) \ 2324 strlcat(buf, ",", sizeof(buf)); \ 2325 strlcat(buf, (s), sizeof(buf)); \ 2326 } \ 2327 } while (0) 2328 IFFLAG("UP", IFF_UP); 2329 IFFLAG("BROADCAST", IFF_BROADCAST); 2330 IFFLAG("DEBUG", IFF_DEBUG); 2331 IFFLAG("LOOPBACK", IFF_LOOPBACK); 2332 IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 2333 IFFLAG("STATICARP", IFF_STATICARP); 2334 IFFLAG("RUNNING", IFF_RUNNING); 2335 IFFLAG("NOARP", IFF_NOARP); 2336 IFFLAG("PROMISC", IFF_PROMISC); 2337 IFFLAG("ALLMULTI", IFF_ALLMULTI); 2338 IFFLAG("OACTIVE", IFF_OACTIVE); 2339 IFFLAG("SIMPLEX", IFF_SIMPLEX); 2340 IFFLAG("LINK0", IFF_LINK0); 2341 IFFLAG("LINK1", IFF_LINK1); 2342 IFFLAG("LINK2", IFF_LINK2); 2343 IFFLAG("MULTICAST", IFF_MULTICAST); 2344 #undef IFFLAG 2345 return buf; 2346 } 2347 2348 void 2349 krtread(int again) 2350 { 2351 int mib[6]; 2352 size_t msize; 2353 char *buf, *p, *lim; 2354 struct rt_msghdr *rtm; 2355 int retry; 2356 const char *errmsg; 2357 2358 retry = 0; 2359 buf = NULL; 2360 mib[0] = CTL_NET; 2361 mib[1] = PF_ROUTE; 2362 mib[2] = 0; 2363 mib[3] = AF_INET6; /* Address family */ 2364 mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 2365 mib[5] = 0; /* No flags */ 2366 do { 2367 retry++; 2368 free(buf); 2369 buf = NULL; 2370 errmsg = NULL; 2371 if (sysctl(mib, 6, NULL, &msize, NULL, 0) == -1) { 2372 errmsg = "sysctl estimate"; 2373 continue; 2374 } 2375 if ((buf = malloc(msize)) == NULL) { 2376 errmsg = "malloc"; 2377 continue; 2378 } 2379 if (sysctl(mib, 6, buf, &msize, NULL, 0) == -1) { 2380 errmsg = "sysctl NET_RT_DUMP"; 2381 continue; 2382 } 2383 } while (retry < 5 && errmsg != NULL); 2384 if (errmsg) { 2385 fatal(errmsg); 2386 /*NOTREACHED*/ 2387 } else if (1 < retry) 2388 log_info("NET_RT_DUMP %d retries", retry); 2389 2390 lim = buf + msize; 2391 for (p = buf; p < lim; p += rtm->rtm_msglen) { 2392 rtm = (struct rt_msghdr *)p; 2393 if (rtm->rtm_version != RTM_VERSION) 2394 continue; 2395 rt_entry(rtm, again); 2396 } 2397 free(buf); 2398 } 2399 2400 void 2401 rt_entry(struct rt_msghdr *rtm, int again) 2402 { 2403 struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 2404 struct sockaddr_in6 *sin6_ifp; 2405 char *rtmp, *ifname = NULL; 2406 struct riprt *rrt, *orrt; 2407 struct netinfo6 *np; 2408 int s; 2409 2410 sin6_dst = sin6_gw = sin6_mask = sin6_ifp = 0; 2411 if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 2412 (RTF_CLONING|RTF_LLINFO|RTF_BLACKHOLE)) { 2413 return; /* not interested in the link route */ 2414 } 2415 /* do not look at cloned routes */ 2416 #ifdef RTF_WASCLONED 2417 if (rtm->rtm_flags & RTF_WASCLONED) 2418 return; 2419 #endif 2420 #ifdef RTF_CLONED 2421 if (rtm->rtm_flags & RTF_CLONED) 2422 return; 2423 #endif 2424 /* 2425 * do not look at dynamic routes. 2426 * netbsd/openbsd cloned routes have UGHD. 2427 */ 2428 if (rtm->rtm_flags & RTF_DYNAMIC) 2429 return; 2430 rtmp = (char *)((char *)rtm + rtm->rtm_hdrlen); 2431 /* Destination */ 2432 if ((rtm->rtm_addrs & RTA_DST) == 0) 2433 return; /* ignore routes without destination address */ 2434 sin6_dst = (struct sockaddr_in6 *)rtmp; 2435 rtmp += ROUNDUP(sin6_dst->sin6_len); 2436 if (rtm->rtm_addrs & RTA_GATEWAY) { 2437 sin6_gw = (struct sockaddr_in6 *)rtmp; 2438 rtmp += ROUNDUP(sin6_gw->sin6_len); 2439 } 2440 if (rtm->rtm_addrs & RTA_NETMASK) { 2441 sin6_mask = (struct sockaddr_in6 *)rtmp; 2442 rtmp += ROUNDUP(sin6_mask->sin6_len); 2443 } 2444 if (rtm->rtm_addrs & RTA_IFP) { 2445 sin6_ifp = (struct sockaddr_in6 *)rtmp; 2446 rtmp += ROUNDUP(sin6_ifp->sin6_len); 2447 } 2448 2449 /* Destination */ 2450 if (sin6_dst->sin6_family != AF_INET6) 2451 return; 2452 if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 2453 return; /* Link-local */ 2454 if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 2455 return; /* Loopback */ 2456 if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 2457 return; 2458 2459 if ((rrt = calloc(1, sizeof(struct riprt))) == NULL) { 2460 fatal("calloc: struct riprt"); 2461 /*NOTREACHED*/ 2462 } 2463 np = &rrt->rrt_info; 2464 rrt->rrt_t = time(NULL); 2465 if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 2466 rrt->rrt_t = 0; /* Don't age static routes */ 2467 if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) 2468 rrt->rrt_t = 0; /* Don't age non-gateway host routes */ 2469 np->rip6_tag = 0; 2470 np->rip6_metric = 1; 2471 rrt->rrt_flags = rtm->rtm_flags; 2472 np->rip6_dest = sin6_dst->sin6_addr; 2473 2474 /* Mask or plen */ 2475 if (rtm->rtm_flags & RTF_HOST) 2476 np->rip6_plen = 128; /* Host route */ 2477 else if (sin6_mask) 2478 np->rip6_plen = sin6mask2len(sin6_mask); 2479 else 2480 np->rip6_plen = 0; 2481 2482 orrt = rtsearch(np, NULL); 2483 if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 2484 /* Already found */ 2485 if (!again) { 2486 log_debug("route: %s/%d flags %s: already registered", 2487 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2488 rtflags(rtm)); 2489 } 2490 free(rrt); 2491 return; 2492 } 2493 /* Gateway */ 2494 if (!sin6_gw) 2495 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2496 else { 2497 if (sin6_gw->sin6_family == AF_INET6) 2498 rrt->rrt_gw = sin6_gw->sin6_addr; 2499 else if (sin6_gw->sin6_family == AF_LINK) { 2500 /* XXX in case ppp link? */ 2501 rrt->rrt_gw = in6addr_loopback; 2502 } else 2503 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2504 } 2505 log_enqueue("route: %s/%d flags %s", 2506 inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 2507 log_enqueue(" gw %s", inet6_n2p(&rrt->rrt_gw)); 2508 2509 /* Interface */ 2510 s = rtm->rtm_index; 2511 if (s < nindex2ifc && index2ifc[s]) 2512 ifname = index2ifc[s]->ifc_name; 2513 else { 2514 log_debug(" not configured"); 2515 free(rrt); 2516 return; 2517 } 2518 log_debug(" if %s sock %d", ifname, s); 2519 rrt->rrt_index = s; 2520 2521 /* Check gateway */ 2522 if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 2523 !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 2524 log_warnx("***** Gateway %s is not a link-local address.", 2525 inet6_n2p(&rrt->rrt_gw)); 2526 log_warnx("***** dest(%s) if(%s) -- Not optimized.", 2527 inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 2528 rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 2529 } 2530 2531 /* Put it to the route list */ 2532 if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 2533 /* replace route list */ 2534 rrt->rrt_next = orrt->rrt_next; 2535 *orrt = *rrt; 2536 log_debug("route: %s/%d flags %s: replace new route", 2537 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2538 rtflags(rtm)); 2539 free(rrt); 2540 } else { 2541 rrt->rrt_next = riprt; 2542 riprt = rrt; 2543 } 2544 } 2545 2546 int 2547 addroute(struct riprt *rrt, const struct in6_addr *gw, struct ifc *ifcp) 2548 { 2549 struct netinfo6 *np; 2550 u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 2551 struct rt_msghdr *rtm; 2552 struct sockaddr_in6 *sin6; 2553 int len; 2554 2555 np = &rrt->rrt_info; 2556 inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 2557 inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 2558 if (uflag) 2559 log_info("RTADD: %s/%d gw %s [%d] ifa %s", 2560 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 2561 np->rip6_metric - 1, buf2); 2562 else 2563 log_debug("RTADD: %s/%d gw %s [%d] ifa %s", 2564 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 2565 np->rip6_metric - 1, buf2); 2566 2567 if (nflag) 2568 return 0; 2569 2570 memset(buf, 0, sizeof(buf)); 2571 rtm = (struct rt_msghdr *)buf; 2572 rtm->rtm_type = RTM_ADD; 2573 rtm->rtm_version = RTM_VERSION; 2574 rtm->rtm_seq = ++seq; 2575 rtm->rtm_flags = rrt->rrt_flags; 2576 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2577 rtm->rtm_inits = RTV_HOPCOUNT; 2578 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2579 /* Destination */ 2580 sin6->sin6_len = sizeof(struct sockaddr_in6); 2581 sin6->sin6_family = AF_INET6; 2582 sin6->sin6_addr = np->rip6_dest; 2583 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2584 /* Gateway */ 2585 sin6->sin6_len = sizeof(struct sockaddr_in6); 2586 sin6->sin6_family = AF_INET6; 2587 sin6->sin6_addr = *gw; 2588 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2589 /* Netmask */ 2590 sin6->sin6_len = sizeof(struct sockaddr_in6); 2591 sin6->sin6_family = AF_INET6; 2592 sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2593 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2594 2595 len = (char *)sin6 - (char *)buf; 2596 rtm->rtm_msglen = len; 2597 if (write(rtsock, buf, len) > 0) 2598 return 0; 2599 2600 if (errno == EEXIST) { 2601 log_warnx("RTADD: Route already exists %s/%d gw %s", 2602 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 2603 } else { 2604 log_warnx("RTADD: Can not write to rtsock (addroute): %s", 2605 strerror(errno)); 2606 } 2607 return -1; 2608 } 2609 2610 int 2611 delroute(struct netinfo6 *np, struct in6_addr *gw) 2612 { 2613 u_char buf[BUFSIZ], buf2[BUFSIZ]; 2614 struct rt_msghdr *rtm; 2615 struct sockaddr_in6 *sin6; 2616 int len; 2617 2618 inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 2619 if (uflag) 2620 log_info("RTDEL: %s/%d gw %s", inet6_n2p(&np->rip6_dest), 2621 np->rip6_plen, buf2); 2622 else 2623 log_debug("RTDEL: %s/%d gw %s", inet6_n2p(&np->rip6_dest), 2624 np->rip6_plen, buf2); 2625 2626 if (nflag) 2627 return 0; 2628 2629 memset(buf, 0, sizeof(buf)); 2630 rtm = (struct rt_msghdr *)buf; 2631 rtm->rtm_type = RTM_DELETE; 2632 rtm->rtm_version = RTM_VERSION; 2633 rtm->rtm_seq = ++seq; 2634 rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 2635 if (np->rip6_plen == sizeof(struct in6_addr) * 8) 2636 rtm->rtm_flags |= RTF_HOST; 2637 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2638 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2639 /* Destination */ 2640 sin6->sin6_len = sizeof(struct sockaddr_in6); 2641 sin6->sin6_family = AF_INET6; 2642 sin6->sin6_addr = np->rip6_dest; 2643 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2644 /* Gateway */ 2645 sin6->sin6_len = sizeof(struct sockaddr_in6); 2646 sin6->sin6_family = AF_INET6; 2647 sin6->sin6_addr = *gw; 2648 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2649 /* Netmask */ 2650 sin6->sin6_len = sizeof(struct sockaddr_in6); 2651 sin6->sin6_family = AF_INET6; 2652 sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2653 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2654 2655 len = (char *)sin6 - (char *)buf; 2656 rtm->rtm_msglen = len; 2657 if (write(rtsock, buf, len) >= 0) 2658 return 0; 2659 2660 if (errno == ESRCH) { 2661 log_warnx("RTDEL: Route does not exist: %s/%d gw %s", 2662 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2663 } else { 2664 log_warnx("RTDEL: Can not write to rtsock (delroute): %s", 2665 strerror(errno)); 2666 } 2667 return -1; 2668 } 2669 2670 struct in6_addr * 2671 getroute(struct netinfo6 *np, struct in6_addr *gw) 2672 { 2673 u_char buf[BUFSIZ]; 2674 int len; 2675 struct rt_msghdr *rtm; 2676 struct sockaddr_in6 *sin6; 2677 2678 rtm = (struct rt_msghdr *)buf; 2679 len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 2680 memset(rtm, 0, len); 2681 rtm->rtm_type = RTM_GET; 2682 rtm->rtm_version = RTM_VERSION; 2683 rtm->rtm_seq = ++seq; 2684 rtm->rtm_addrs = RTA_DST; 2685 rtm->rtm_msglen = len; 2686 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2687 sin6->sin6_len = sizeof(struct sockaddr_in6); 2688 sin6->sin6_family = AF_INET6; 2689 sin6->sin6_addr = np->rip6_dest; 2690 if (write(rtsock, buf, len) == -1) { 2691 if (errno == ESRCH) /* No such route found */ 2692 return NULL; 2693 perror("write to rtsock"); 2694 exit(1); 2695 } 2696 do { 2697 if ((len = read(rtsock, buf, sizeof(buf))) == -1) { 2698 perror("read from rtsock"); 2699 exit(1); 2700 } 2701 rtm = (struct rt_msghdr *)buf; 2702 } while (rtm->rtm_version != RTM_VERSION || 2703 rtm->rtm_seq != seq || rtm->rtm_pid != pid); 2704 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2705 if (rtm->rtm_addrs & RTA_DST) { 2706 sin6 = (struct sockaddr_in6 *) 2707 ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2708 } 2709 if (rtm->rtm_addrs & RTA_GATEWAY) { 2710 *gw = sin6->sin6_addr; 2711 return gw; 2712 } 2713 return NULL; 2714 } 2715 2716 const char * 2717 inet6_n2p(const struct in6_addr *p) 2718 { 2719 static char buf[BUFSIZ]; 2720 2721 return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 2722 } 2723 2724 void 2725 ifrtdump(int sig) 2726 { 2727 2728 ifdump(sig); 2729 rtdump(sig); 2730 } 2731 2732 void 2733 ifdump(int sig) 2734 { 2735 struct ifc *ifcp; 2736 int i; 2737 2738 log_info("%s: Interface Table Dump", hms()); 2739 log_info(" Number of interfaces: %d", nifc); 2740 for (i = 0; i < 2; i++) { 2741 log_info(" %sadvertising interfaces:", i ? "non-" : ""); 2742 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 2743 if (i == 0) { 2744 if ((ifcp->ifc_flags & IFF_UP) == 0) 2745 continue; 2746 if (iff_find(ifcp, 'N') != NULL) 2747 continue; 2748 } else { 2749 if (ifcp->ifc_flags & IFF_UP) 2750 continue; 2751 } 2752 ifdump0(ifcp); 2753 } 2754 } 2755 log_info(""); 2756 } 2757 2758 void 2759 ifdump0(const struct ifc *ifcp) 2760 { 2761 struct ifac *ifa; 2762 struct iff *iffp; 2763 char buf[BUFSIZ]; 2764 const char *ft; 2765 int addr; 2766 2767 log_info(" %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)", 2768 ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 2769 inet6_n2p(&ifcp->ifc_mylladdr), 2770 ifcp->ifc_mtu, ifcp->ifc_metric); 2771 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 2772 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 2773 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 2774 buf, sizeof(buf)); 2775 log_info("\t%s/%d -- %s", 2776 inet6_n2p(&ifa->ifa_addr), 2777 ifa->ifa_plen, buf); 2778 } else { 2779 log_info("\t%s/%d", 2780 inet6_n2p(&ifa->ifa_addr), 2781 ifa->ifa_plen); 2782 } 2783 } 2784 if (ifcp->ifc_filter) { 2785 log_enqueue("\tFilter:"); 2786 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 2787 addr = 0; 2788 switch (iffp->iff_type) { 2789 case 'A': 2790 ft = "Aggregate"; addr++; break; 2791 case 'N': 2792 ft = "No-use"; break; 2793 case 'O': 2794 ft = "Advertise-only"; addr++; break; 2795 case 'T': 2796 ft = "Default-only"; break; 2797 case 'L': 2798 ft = "Listen-only"; addr++; break; 2799 default: 2800 snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 2801 ft = buf; 2802 addr++; 2803 break; 2804 } 2805 log_enqueue(" %s", ft); 2806 if (addr) { 2807 log_enqueue("(%s/%d)", 2808 inet6_n2p(&iffp->iff_addr), iffp->iff_plen); 2809 } 2810 } 2811 log_info(""); 2812 } 2813 } 2814 2815 void 2816 rtdump(int sig) 2817 { 2818 struct riprt *rrt; 2819 char buf[BUFSIZ]; 2820 time_t t, age; 2821 2822 t = time(NULL); 2823 log_info("%s: Routing Table Dump", hms()); 2824 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 2825 if (rrt->rrt_t == 0) 2826 age = 0; 2827 else 2828 age = t - rrt->rrt_t; 2829 inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 2830 buf, sizeof(buf)); 2831 log_enqueue(" %s/%d if(%d:%s) gw(%s) [%d] age(%lld)", 2832 buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 2833 index2ifc[rrt->rrt_index]->ifc_name, 2834 inet6_n2p(&rrt->rrt_gw), 2835 rrt->rrt_info.rip6_metric, (long long)age); 2836 if (rrt->rrt_info.rip6_tag) { 2837 log_enqueue(" tag(0x%04x)", 2838 ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 2839 } 2840 if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 2841 log_enqueue(" NOT-LL"); 2842 if (rrt->rrt_rflags & RRTF_NOADVERTISE) 2843 log_enqueue(" NO-ADV"); 2844 log_info(""); 2845 } 2846 } 2847 2848 /* 2849 * Parse the -A (and -O) options and put corresponding filter object to the 2850 * specified interface structures. Each of the -A/O option has the following 2851 * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 2852 * -O 5f09:c400::/32,ef0,ef1 (only when match) 2853 */ 2854 void 2855 filterconfig(void) 2856 { 2857 int i; 2858 char *p, *ap, *iflp, *ifname, *ep; 2859 struct iff ftmp, *iff_obj; 2860 struct ifc *ifcp; 2861 struct riprt *rrt; 2862 #if 0 2863 struct in6_addr gw; 2864 #endif 2865 u_long plen; 2866 2867 for (i = 0; i < nfilter; i++) { 2868 ap = filter[i]; 2869 iflp = NULL; 2870 ifcp = NULL; 2871 if (filtertype[i] == 'N' || filtertype[i] == 'T') { 2872 iflp = ap; 2873 goto ifonly; 2874 } 2875 if ((p = strchr(ap, ',')) != NULL) { 2876 *p++ = '\0'; 2877 iflp = p; 2878 } 2879 if ((p = strchr(ap, '/')) == NULL) { 2880 log_warnx("no prefixlen specified for '%s'", ap); 2881 fatalx("exiting"); 2882 /*NOTREACHED*/ 2883 } 2884 *p++ = '\0'; 2885 if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 2886 log_warnx("invalid prefix specified for '%s'", ap); 2887 fatalx("exiting"); 2888 /*NOTREACHED*/ 2889 } 2890 errno = 0; 2891 ep = NULL; 2892 plen = strtoul(p, &ep, 10); 2893 if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) { 2894 log_warnx("invalid prefix length specified for '%s'", ap); 2895 fatalx("exiting"); 2896 /*NOTREACHED*/ 2897 } 2898 ftmp.iff_plen = plen; 2899 ftmp.iff_next = NULL; 2900 applyplen(&ftmp.iff_addr, ftmp.iff_plen); 2901 ifonly: 2902 ftmp.iff_type = filtertype[i]; 2903 if (iflp == NULL || *iflp == '\0') { 2904 log_warnx("no interface specified for '%s'", ap); 2905 fatal("exiting"); 2906 /*NOTREACHED*/ 2907 } 2908 /* parse the interface listing portion */ 2909 while (iflp) { 2910 ifname = iflp; 2911 if ((iflp = strchr(iflp, ',')) != NULL) 2912 *iflp++ = '\0'; 2913 ifcp = ifc_find(ifname); 2914 if (ifcp == NULL) { 2915 log_warnx("no interface %s exists", ifname); 2916 fatalx("exiting"); 2917 /*NOTREACHED*/ 2918 } 2919 iff_obj = malloc(sizeof(struct iff)); 2920 if (iff_obj == NULL) { 2921 fatal("malloc of iff_obj"); 2922 /*NOTREACHED*/ 2923 } 2924 memcpy((void *)iff_obj, (void *)&ftmp, 2925 sizeof(struct iff)); 2926 /* link it to the interface filter */ 2927 iff_obj->iff_next = ifcp->ifc_filter; 2928 ifcp->ifc_filter = iff_obj; 2929 } 2930 2931 /* 2932 * -A: aggregate configuration. 2933 */ 2934 if (filtertype[i] != 'A') 2935 continue; 2936 /* put the aggregate to the kernel routing table */ 2937 rrt = calloc(1, sizeof(struct riprt)); 2938 if (rrt == NULL) { 2939 fatal("calloc: rrt"); 2940 /*NOTREACHED*/ 2941 } 2942 rrt->rrt_info.rip6_dest = ftmp.iff_addr; 2943 rrt->rrt_info.rip6_plen = ftmp.iff_plen; 2944 rrt->rrt_info.rip6_metric = 1; 2945 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 2946 rrt->rrt_gw = in6addr_loopback; 2947 rrt->rrt_flags = RTF_UP | RTF_REJECT; 2948 rrt->rrt_rflags = RRTF_AGGREGATE; 2949 rrt->rrt_t = 0; 2950 rrt->rrt_index = loopifcp->ifc_index; 2951 #if 0 2952 if (getroute(&rrt->rrt_info, &gw)) { 2953 #if 0 2954 /* 2955 * When the address has already been registered in the 2956 * kernel routing table, it should be removed 2957 */ 2958 delroute(&rrt->rrt_info, &gw); 2959 #else 2960 /* it is safer behavior */ 2961 errno = EINVAL; 2962 fatal("%s/%u already in routing table, " 2963 "cannot aggregate", 2964 inet6_n2p(&rrt->rrt_info.rip6_dest), 2965 rrt->rrt_info.rip6_plen); 2966 /*NOTREACHED*/ 2967 #endif 2968 } 2969 #endif 2970 /* Put the route to the list */ 2971 rrt->rrt_next = riprt; 2972 riprt = rrt; 2973 log_debug("Aggregate: %s/%d for %s", 2974 inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 2975 ifcp->ifc_name); 2976 /* Add this route to the kernel */ 2977 if (nflag) /* do not modify kernel routing table */ 2978 continue; 2979 addroute(rrt, &in6addr_loopback, loopifcp); 2980 } 2981 } 2982 2983 /***************** utility functions *****************/ 2984 2985 /* 2986 * Returns a pointer to ifac whose address and prefix length matches 2987 * with the address and prefix length specified in the arguments. 2988 */ 2989 struct ifac * 2990 ifa_match(const struct ifc *ifcp, const struct in6_addr *ia, int plen) 2991 { 2992 struct ifac *ifa; 2993 2994 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 2995 if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 2996 ifa->ifa_plen == plen) 2997 break; 2998 } 2999 return ifa; 3000 } 3001 3002 /* 3003 * Return a pointer to riprt structure whose address and prefix length 3004 * matches with the address and prefix length found in the argument. 3005 * Note: This is not a rtalloc(). Therefore exact match is necessary. 3006 */ 3007 struct riprt * 3008 rtsearch(struct netinfo6 *np, struct riprt **prev_rrt) 3009 { 3010 struct riprt *rrt; 3011 3012 if (prev_rrt) 3013 *prev_rrt = NULL; 3014 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 3015 if (rrt->rrt_info.rip6_plen == np->rip6_plen && 3016 IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 3017 &np->rip6_dest)) 3018 return rrt; 3019 if (prev_rrt) 3020 *prev_rrt = rrt; 3021 } 3022 if (prev_rrt) 3023 *prev_rrt = NULL; 3024 return 0; 3025 } 3026 3027 int 3028 sin6mask2len(const struct sockaddr_in6 *sin6) 3029 { 3030 3031 return mask2len(&sin6->sin6_addr, 3032 sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 3033 } 3034 3035 int 3036 mask2len(const struct in6_addr *addr, int lenlim) 3037 { 3038 int i = 0, j; 3039 const u_char *p = (const u_char *)addr; 3040 3041 for (j = 0; j < lenlim; j++, p++) { 3042 if (*p != 0xff) 3043 break; 3044 i += 8; 3045 } 3046 if (j < lenlim) { 3047 switch (*p) { 3048 #define MASKLEN(m, l) case m: do { i += l; break; } while (0) 3049 MASKLEN(0xfe, 7); break; 3050 MASKLEN(0xfc, 6); break; 3051 MASKLEN(0xf8, 5); break; 3052 MASKLEN(0xf0, 4); break; 3053 MASKLEN(0xe0, 3); break; 3054 MASKLEN(0xc0, 2); break; 3055 MASKLEN(0x80, 1); break; 3056 #undef MASKLEN 3057 } 3058 } 3059 return i; 3060 } 3061 3062 void 3063 applyplen(struct in6_addr *ia, int plen) 3064 { 3065 static const u_char plent[8] = { 3066 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 3067 }; 3068 u_char *p; 3069 int i; 3070 3071 p = ia->s6_addr; 3072 for (i = 0; i < 16; i++) { 3073 if (plen <= 0) 3074 *p = 0; 3075 else if (plen < 8) 3076 *p &= plent[plen]; 3077 p++, plen -= 8; 3078 } 3079 } 3080 3081 struct in6_addr * 3082 plen2mask(int n) 3083 { 3084 static const int pl2m[9] = { 3085 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 3086 }; 3087 static struct in6_addr ia; 3088 u_char *p; 3089 int i; 3090 3091 memset(&ia, 0, sizeof(struct in6_addr)); 3092 p = (u_char *)&ia; 3093 for (i = 0; i < 16; i++, p++, n -= 8) { 3094 if (n >= 8) { 3095 *p = 0xff; 3096 continue; 3097 } 3098 *p = pl2m[n]; 3099 break; 3100 } 3101 return &ia; 3102 } 3103 3104 char * 3105 xstrdup(const char *p) 3106 { 3107 char *q; 3108 3109 q = strdup(p); 3110 if (q == NULL) { 3111 fatal("strdup"); 3112 /*NOTREACHED*/ 3113 } 3114 return q; 3115 } 3116 3117 const char * 3118 hms(void) 3119 { 3120 static char buf[BUFSIZ]; 3121 time_t t; 3122 struct tm *tm; 3123 3124 t = time(NULL); 3125 if ((tm = localtime(&t)) == 0) { 3126 fatal("localtime"); 3127 /*NOTREACHED*/ 3128 } 3129 snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 3130 tm->tm_sec); 3131 return buf; 3132 } 3133 3134 #define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 3135 3136 int 3137 ripinterval(int timer) 3138 { 3139 double r = arc4random(); 3140 int interval; 3141 3142 interval = (int)(timer + timer * RIPRANDDEV * (r / UINT32_MAX - 0.5)); 3143 nextalarm = time(NULL) + interval; 3144 return interval; 3145 } 3146 3147 time_t 3148 ripsuptrig(void) 3149 { 3150 time_t t; 3151 3152 double r = arc4random(); 3153 t = (int)(RIP_TRIG_INT6_MIN + 3154 (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / UINT32_MAX)); 3155 sup_trig_update = time(NULL) + t; 3156 return t; 3157 } 3158 3159 unsigned int 3160 if_maxindex(void) 3161 { 3162 struct if_nameindex *p, *p0; 3163 unsigned int max = 0; 3164 3165 p0 = if_nameindex(); 3166 for (p = p0; p && p->if_index && p->if_name; p++) { 3167 if (max < p->if_index) 3168 max = p->if_index; 3169 } 3170 if_freenameindex(p0); 3171 return max; 3172 } 3173 3174 struct ifc * 3175 ifc_find(char *name) 3176 { 3177 struct ifc *ifcp; 3178 3179 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 3180 if (strcmp(name, ifcp->ifc_name) == 0) 3181 return ifcp; 3182 } 3183 return (struct ifc *)NULL; 3184 } 3185 3186 struct iff * 3187 iff_find(struct ifc *ifcp, int type) 3188 { 3189 struct iff *iffp; 3190 3191 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 3192 if (iffp->iff_type == type) 3193 return iffp; 3194 } 3195 return NULL; 3196 } 3197 3198 void 3199 setindex2ifc(int idx, struct ifc *ifcp) 3200 { 3201 int n; 3202 struct ifc **p; 3203 3204 if (!index2ifc) { 3205 nindex2ifc = 5; /*initial guess*/ 3206 index2ifc = calloc(nindex2ifc, sizeof(*index2ifc)); 3207 if (index2ifc == NULL) { 3208 fatal("calloc"); 3209 /*NOTREACHED*/ 3210 } 3211 } 3212 n = nindex2ifc; 3213 while (nindex2ifc <= idx) 3214 nindex2ifc *= 2; 3215 if (n != nindex2ifc) { 3216 p = reallocarray(index2ifc, nindex2ifc, sizeof(*index2ifc)); 3217 if (p == NULL) { 3218 fatal("reallocarray"); 3219 /*NOTREACHED*/ 3220 } 3221 memset(p + n, 0, (nindex2ifc - n) * sizeof(*index2ifc)); 3222 index2ifc = p; 3223 } 3224 index2ifc[idx] = ifcp; 3225 } 3226