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