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