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