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