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