route6d.c revision 119037
1274201Sdim/* $FreeBSD: head/usr.sbin/route6d/route6d.c 119037 2003-08-17 17:29:54Z ume $ */ 2274201Sdim/* $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $ */ 3274201Sdim 4274201Sdim/* 5274201Sdim * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6274201Sdim * All rights reserved. 7274201Sdim * 8274201Sdim * Redistribution and use in source and binary forms, with or without 9274201Sdim * modification, are permitted provided that the following conditions 10274201Sdim * are met: 11274201Sdim * 1. Redistributions of source code must retain the above copyright 12274201Sdim * notice, this list of conditions and the following disclaimer. 13274201Sdim * 2. Redistributions in binary form must reproduce the above copyright 14274201Sdim * notice, this list of conditions and the following disclaimer in the 15274201Sdim * documentation and/or other materials provided with the distribution. 16274201Sdim * 3. Neither the name of the project nor the names of its contributors 17276789Sdim * may be used to endorse or promote products derived from this software 18276789Sdim * without specific prior written permission. 19276789Sdim * 20276789Sdim * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21274201Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22274201Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23274201Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24274201Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25276789Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26274201Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27276789Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28276789Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29274201Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30274201Sdim * SUCH DAMAGE. 31274201Sdim */ 32274201Sdim 33274201Sdim#ifndef lint 34274201Sdimstatic char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $"; 35274201Sdim#endif 36274201Sdim 37274201Sdim#include <stdio.h> 38274201Sdim 39274201Sdim#include <time.h> 40274201Sdim#include <unistd.h> 41274201Sdim#include <stdlib.h> 42274201Sdim#include <string.h> 43274201Sdim#include <signal.h> 44274201Sdim#ifdef __STDC__ 45274201Sdim#include <stdarg.h> 46274201Sdim#else 47274201Sdim#include <varargs.h> 48274201Sdim#endif 49274201Sdim#include <syslog.h> 50274201Sdim#include <stddef.h> 51274201Sdim#include <errno.h> 52274201Sdim#include <err.h> 53274201Sdim 54274201Sdim#include <sys/types.h> 55274201Sdim#include <sys/param.h> 56274201Sdim#include <sys/file.h> 57274201Sdim#include <sys/socket.h> 58274201Sdim#include <sys/ioctl.h> 59274201Sdim#include <sys/sysctl.h> 60274201Sdim#include <sys/uio.h> 61274201Sdim#include <net/if.h> 62274201Sdim#if defined(__FreeBSD__) && __FreeBSD__ >= 3 63274201Sdim#include <net/if_var.h> 64274201Sdim#endif /* __FreeBSD__ >= 3 */ 65274201Sdim#define KERNEL 1 66274201Sdim#define _KERNEL 1 67274201Sdim#include <net/route.h> 68274201Sdim#undef KERNEL 69274201Sdim#undef _KERNEL 70274201Sdim#include <netinet/in.h> 71274201Sdim#include <netinet/in_var.h> 72274201Sdim#include <netinet/ip6.h> 73274201Sdim#include <netinet/udp.h> 74274201Sdim#include <netdb.h> 75274201Sdim#include <ifaddrs.h> 76274201Sdim 77274201Sdim#include <arpa/inet.h> 78274201Sdim 79274201Sdim#include "route6d.h" 80274201Sdim 81274201Sdim#define MAXFILTER 40 82274201Sdim 83274201Sdim#ifdef DEBUG 84274201Sdim#define INIT_INTERVAL6 6 85274201Sdim#else 86274201Sdim#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest. */ 87274201Sdim#endif 88274201Sdim 89274201Sdim/* alignment constraint for routing socket */ 90274201Sdim#define ROUNDUP(a) \ 91274201Sdim ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 92274201Sdim#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 93274201Sdim 94274201Sdim/* 95274201Sdim * Following two macros are highly depending on KAME Release 96274201Sdim */ 97274201Sdim#define IN6_LINKLOCAL_IFINDEX(addr) \ 98274201Sdim ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 99274201Sdim 100274201Sdim#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 101274201Sdim do { \ 102274201Sdim (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 103274201Sdim (addr).s6_addr[3] = (index) & 0xff; \ 104274201Sdim } while (0) 105274201Sdim 106274201Sdimstruct ifc { /* Configuration of an interface */ 107274201Sdim char *ifc_name; /* if name */ 108274201Sdim struct ifc *ifc_next; 109274201Sdim int ifc_index; /* if index */ 110274201Sdim int ifc_mtu; /* if mtu */ 111274201Sdim int ifc_metric; /* if metric */ 112274201Sdim u_int ifc_flags; /* flags */ 113274201Sdim short ifc_cflags; /* IFC_XXX */ 114274201Sdim struct in6_addr ifc_mylladdr; /* my link-local address */ 115274201Sdim struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 116274201Sdim struct iff *ifc_filter; /* filter structure */ 117274201Sdim struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 118274201Sdim int ifc_joined; /* joined to ff02::9 */ 119274201Sdim}; 120274201Sdim 121274201Sdimstruct ifac { /* Adddress associated to an interface */ 122274201Sdim struct ifc *ifa_conf; /* back pointer */ 123274201Sdim struct ifac *ifa_next; 124274201Sdim struct in6_addr ifa_addr; /* address */ 125274201Sdim struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 126274201Sdim int ifa_plen; /* prefix length */ 127274201Sdim}; 128274201Sdim 129274201Sdimstruct iff { 130274201Sdim int iff_type; 131274201Sdim struct in6_addr iff_addr; 132274201Sdim int iff_plen; 133274201Sdim struct iff *iff_next; 134274201Sdim}; 135274201Sdim 136274201Sdimstruct ifc *ifc; 137274201Sdimint nifc; /* number of valid ifc's */ 138274201Sdimstruct ifc **index2ifc; 139274201Sdimint nindex2ifc; 140274201Sdimstruct ifc *loopifcp = NULL; /* pointing to loopback */ 141274201Sdimint loopifindex = 0; /* ditto */ 142274201Sdimfd_set sockvec; /* vector to select() for receiving */ 143274201Sdimint rtsock; /* the routing socket */ 144274201Sdimint ripsock; /* socket to send/receive RIP datagram */ 145274201Sdim 146274201Sdimstruct rip6 *ripbuf; /* packet buffer for sending */ 147274201Sdim 148274201Sdim/* 149274201Sdim * Maintain the routes in a linked list. When the number of the routes 150274201Sdim * grows, somebody would like to introduce a hash based or a radix tree 151274201Sdim * based structure. I believe the number of routes handled by RIP is 152274201Sdim * limited and I don't have to manage a complex data structure, however. 153274201Sdim * 154274201Sdim * One of the major drawbacks of the linear linked list is the difficulty 155274201Sdim * of representing the relationship between a couple of routes. This may 156274201Sdim * be a significant problem when we have to support route aggregation with 157274201Sdim * supressing the specifices covered by the aggregate. 158274201Sdim */ 159274201Sdim 160274201Sdimstruct riprt { 161274201Sdim struct riprt *rrt_next; /* next destination */ 162274201Sdim struct riprt *rrt_same; /* same destination - future use */ 163274201Sdim struct netinfo6 rrt_info; /* network info */ 164274201Sdim struct in6_addr rrt_gw; /* gateway */ 165274201Sdim u_long rrt_flags; /* kernel routing table flags */ 166274201Sdim u_long rrt_rflags; /* route6d routing table flags */ 167274201Sdim time_t rrt_t; /* when the route validated */ 168274201Sdim int rrt_index; /* ifindex from which this route got */ 169274201Sdim}; 170274201Sdim 171274201Sdimstruct riprt *riprt = 0; 172274201Sdim 173274201Sdimint dflag = 0; /* debug flag */ 174274201Sdimint qflag = 0; /* quiet flag */ 175274201Sdimint nflag = 0; /* don't update kernel routing table */ 176274201Sdimint aflag = 0; /* age out even the statically defined routes */ 177274201Sdimint hflag = 0; /* don't split horizon */ 178274201Sdimint lflag = 0; /* exchange site local routes */ 179274201Sdimint sflag = 0; /* announce static routes w/ split horizon */ 180274201Sdimint Sflag = 0; /* announce static routes to every interface */ 181274201Sdimunsigned long routetag = 0; /* route tag attached on originating case */ 182274201Sdim 183274201Sdimchar *filter[MAXFILTER]; 184274201Sdimint filtertype[MAXFILTER]; 185274201Sdimint nfilter = 0; 186274201Sdim 187274201Sdimpid_t pid; 188274201Sdim 189274201Sdimstruct sockaddr_storage ripsin; 190274201Sdim 191274201Sdimstruct rtentry rtentry; 192274201Sdim 193274201Sdimint interval = 1; 194274201Sdimtime_t nextalarm = 0; 195274201Sdimtime_t sup_trig_update = 0; 196274201Sdim 197274201SdimFILE *rtlog = NULL; 198274201Sdim 199274201Sdimint logopened = 0; 200274201Sdim 201274201Sdimstatic u_long seq = 0; 202274201Sdim 203274201Sdimvolatile int signo; 204274201Sdimvolatile sig_atomic_t seenalrm; 205274201Sdimvolatile sig_atomic_t seenquit; 206274201Sdimvolatile sig_atomic_t seenusr1; 207274201Sdim 208274201Sdim#define RRTF_AGGREGATE 0x08000000 209274201Sdim#define RRTF_NOADVERTISE 0x10000000 210274201Sdim#define RRTF_NH_NOT_LLADDR 0x20000000 211274201Sdim#define RRTF_SENDANYWAY 0x40000000 212274201Sdim#define RRTF_CHANGED 0x80000000 213274201Sdim 214274201Sdimint main __P((int, char **)); 215274201Sdimvoid sighandler __P((int)); 216274201Sdimvoid ripalarm __P((void)); 217274201Sdimvoid riprecv __P((void)); 218274201Sdimvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 219274201Sdimint out_filter __P((struct riprt *, struct ifc *)); 220274201Sdimvoid init __P((void)); 221274201Sdimvoid sockopt __P((struct ifc *)); 222274201Sdimvoid ifconfig __P((void)); 223274201Sdimvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 224274201Sdimvoid rtrecv __P((void)); 225274201Sdimint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 226274201Sdim const struct sockaddr_in6 *)); 227274201Sdimint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 228274201Sdim const struct sockaddr_in6 *)); 229274201Sdimvoid filterconfig __P((void)); 230274201Sdimint getifmtu __P((int)); 231274201Sdimconst char *rttypes __P((struct rt_msghdr *)); 232274201Sdimconst char *rtflags __P((struct rt_msghdr *)); 233274201Sdimconst char *ifflags __P((int)); 234274201Sdimint ifrt __P((struct ifc *, int)); 235274201Sdimvoid ifrt_p2p __P((struct ifc *, int)); 236274201Sdimvoid applymask __P((struct in6_addr *, struct in6_addr *)); 237274201Sdimvoid applyplen __P((struct in6_addr *, int)); 238274201Sdimvoid ifrtdump __P((int)); 239274201Sdimvoid ifdump __P((int)); 240274201Sdimvoid ifdump0 __P((FILE *, const struct ifc *)); 241274201Sdimvoid rtdump __P((int)); 242274201Sdimvoid rt_entry __P((struct rt_msghdr *, int)); 243274201Sdimvoid rtdexit __P((void)); 244274201Sdimvoid riprequest __P((struct ifc *, struct netinfo6 *, int, 245274201Sdim struct sockaddr_in6 *)); 246274201Sdimvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 247274201Sdimvoid sendrequest __P((struct ifc *)); 248274201Sdimint sin6mask2len __P((const struct sockaddr_in6 *)); 249274201Sdimint mask2len __P((const struct in6_addr *, int)); 250274201Sdimint sendpacket __P((struct sockaddr_in6 *, int)); 251274201Sdimint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 252274201Sdimint delroute __P((struct netinfo6 *, struct in6_addr *)); 253274201Sdimstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 254274201Sdimvoid krtread __P((int)); 255274201Sdimint tobeadv __P((struct riprt *, struct ifc *)); 256274201Sdimchar *allocopy __P((char *)); 257274201Sdimchar *hms __P((void)); 258274201Sdimconst char *inet6_n2p __P((const struct in6_addr *)); 259274201Sdimstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 260274201Sdimstruct in6_addr *plen2mask __P((int)); 261274201Sdimstruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); 262274201Sdimint ripinterval __P((int)); 263274201Sdimtime_t ripsuptrig __P((void)); 264274201Sdimvoid fatal __P((const char *, ...)) 265274201Sdim __attribute__((__format__(__printf__, 1, 2))); 266274201Sdimvoid trace __P((int, const char *, ...)) 267274201Sdim __attribute__((__format__(__printf__, 2, 3))); 268274201Sdimvoid tracet __P((int, const char *, ...)) 269274201Sdim __attribute__((__format__(__printf__, 2, 3))); 270274201Sdimunsigned int if_maxindex __P((void)); 271274201Sdimstruct ifc *ifc_find __P((char *)); 272274201Sdimstruct iff *iff_find __P((struct ifc *, int)); 273274201Sdimvoid setindex2ifc __P((int, struct ifc *)); 274274201Sdim 275274201Sdim#define MALLOC(type) ((type *)malloc(sizeof(type))) 276274201Sdim 277274201Sdimint 278274201Sdimmain(argc, argv) 279274201Sdim int argc; 280274201Sdim char **argv; 281274201Sdim{ 282274201Sdim int ch; 283274201Sdim int error = 0; 284274201Sdim struct ifc *ifcp; 285274201Sdim sigset_t mask, omask; 286274201Sdim FILE *pidfile; 287274201Sdim char *progname; 288274201Sdim char *ep; 289274201Sdim 290274201Sdim progname = strrchr(*argv, '/'); 291274201Sdim if (progname) 292274201Sdim progname++; 293274201Sdim else 294274201Sdim progname = *argv; 295274201Sdim 296274201Sdim pid = getpid(); 297274201Sdim while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 298274201Sdim switch (ch) { 299274201Sdim case 'A': 300274201Sdim case 'N': 301274201Sdim case 'O': 302274201Sdim case 'T': 303274201Sdim case 'L': 304274201Sdim if (nfilter >= MAXFILTER) { 305274201Sdim fatal("Exceeds MAXFILTER"); 306274201Sdim /*NOTREACHED*/ 307274201Sdim } 308274201Sdim filtertype[nfilter] = ch; 309274201Sdim filter[nfilter++] = allocopy(optarg); 310274201Sdim break; 311274201Sdim case 't': 312274201Sdim ep = NULL; 313274201Sdim routetag = strtoul(optarg, &ep, 0); 314274201Sdim if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 315274201Sdim fatal("invalid route tag"); 316274201Sdim /*NOTREACHED*/ 317274201Sdim } 318274201Sdim break; 319274201Sdim case 'R': 320274201Sdim if ((rtlog = fopen(optarg, "w")) == NULL) { 321274201Sdim fatal("Can not write to routelog"); 322274201Sdim /*NOTREACHED*/ 323274201Sdim } 324274201Sdim break; 325274201Sdim#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 326274201Sdim FLAG('a', aflag, 1); break; 327274201Sdim FLAG('d', dflag, 1); break; 328274201Sdim FLAG('D', dflag, 2); break; 329274201Sdim FLAG('h', hflag, 1); break; 330274201Sdim FLAG('l', lflag, 1); break; 331274201Sdim FLAG('n', nflag, 1); break; 332274201Sdim FLAG('q', qflag, 1); break; 333274201Sdim FLAG('s', sflag, 1); break; 334274201Sdim FLAG('S', Sflag, 1); break; 335274201Sdim#undef FLAG 336274201Sdim default: 337274201Sdim fatal("Invalid option specified, terminating"); 338274201Sdim /*NOTREACHED*/ 339274201Sdim } 340274201Sdim } 341274201Sdim argc -= optind; 342274201Sdim argv += optind; 343274201Sdim if (argc > 0) { 344274201Sdim fatal("bogus extra arguments"); 345274201Sdim /*NOTREACHED*/ 346274201Sdim } 347274201Sdim 348274201Sdim if (geteuid()) { 349274201Sdim nflag = 1; 350274201Sdim fprintf(stderr, "No kernel update is allowed\n"); 351274201Sdim } 352274201Sdim 353274201Sdim if (dflag == 0) { 354274201Sdim if (daemon(0, 0) < 0) { 355274201Sdim fatal("daemon"); 356274201Sdim /*NOTREACHED*/ 357274201Sdim } 358274201Sdim } 359274201Sdim 360274201Sdim openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 361274201Sdim logopened++; 362274201Sdim 363274201Sdim if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 364274201Sdim fatal("malloc"); 365274201Sdim memset(ripbuf, 0, RIP6_MAXMTU); 366274201Sdim ripbuf->rip6_cmd = RIP6_RESPONSE; 367274201Sdim ripbuf->rip6_vers = RIP6_VERSION; 368274201Sdim ripbuf->rip6_res1[0] = 0; 369274201Sdim ripbuf->rip6_res1[1] = 0; 370274201Sdim 371274201Sdim init(); 372274201Sdim ifconfig(); 373274201Sdim for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 374274201Sdim if (ifcp->ifc_index < 0) { 375274201Sdim fprintf(stderr, 376274201Sdim"No ifindex found at %s (no link-local address?)\n", 377274201Sdim ifcp->ifc_name); 378274201Sdim error++; 379274201Sdim } 380274201Sdim } 381274201Sdim if (error) 382274201Sdim exit(1); 383274201Sdim if (loopifcp == NULL) { 384274201Sdim fatal("No loopback found"); 385274201Sdim /*NOTREACHED*/ 386274201Sdim } 387274201Sdim#ifdef __FreeBSD__ 388274201Sdim sranddev(); 389274201Sdim#else 390274201Sdim srand((unsigned)(time(NULL)^(pid<<16))); 391274201Sdim#endif 392274201Sdim loopifindex = loopifcp->ifc_index; 393274201Sdim for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 394274201Sdim ifrt(ifcp, 0); 395274201Sdim filterconfig(); 396274201Sdim krtread(0); 397274201Sdim if (dflag) 398274201Sdim ifrtdump(0); 399274201Sdim 400274201Sdim pid = getpid(); 401274201Sdim if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 402274201Sdim fprintf(pidfile, "%d\n", pid); 403274201Sdim fclose(pidfile); 404274201Sdim } 405274201Sdim 406274201Sdim if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 407274201Sdim fatal("malloc"); 408274201Sdim /*NOTREACHED*/ 409274201Sdim } 410274201Sdim memset(ripbuf, 0, RIP6_MAXMTU); 411274201Sdim ripbuf->rip6_cmd = RIP6_RESPONSE; 412274201Sdim ripbuf->rip6_vers = RIP6_VERSION; 413274201Sdim ripbuf->rip6_res1[0] = 0; 414274201Sdim ripbuf->rip6_res1[1] = 0; 415274201Sdim 416274201Sdim if (signal(SIGALRM, sighandler) == SIG_ERR || 417274201Sdim signal(SIGQUIT, sighandler) == SIG_ERR || 418274201Sdim signal(SIGTERM, sighandler) == SIG_ERR || 419274201Sdim signal(SIGUSR1, sighandler) == SIG_ERR || 420274201Sdim signal(SIGHUP, sighandler) == SIG_ERR || 421274201Sdim signal(SIGINT, sighandler) == SIG_ERR) { 422274201Sdim fatal("signal"); 423274201Sdim /*NOTREACHED*/ 424274201Sdim } 425274201Sdim /* 426274201Sdim * To avoid rip packet congestion (not on a cable but in this 427274201Sdim * process), wait for a moment to send the first RIP6_RESPONSE 428274201Sdim * packets. 429274201Sdim */ 430274201Sdim alarm(ripinterval(INIT_INTERVAL6)); 431274201Sdim 432274201Sdim for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 433274201Sdim if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 434274201Sdim sendrequest(ifcp); 435274201Sdim } 436274201Sdim 437274201Sdim syslog(LOG_INFO, "**** Started ****"); 438274201Sdim sigemptyset(&mask); 439274201Sdim sigaddset(&mask, SIGALRM); 440274201Sdim while (1) { 441274201Sdim fd_set recvec; 442274201Sdim 443274201Sdim if (seenalrm) { 444274201Sdim ripalarm(); 445274201Sdim seenalrm = 0; 446274201Sdim continue; 447274201Sdim } 448274201Sdim if (seenquit) { 449274201Sdim rtdexit(); 450274201Sdim seenquit = 0; 451274201Sdim continue; 452274201Sdim } 453274201Sdim if (seenusr1) { 454274201Sdim ifrtdump(SIGUSR1); 455274201Sdim seenusr1 = 0; 456274201Sdim continue; 457274201Sdim } 458274201Sdim 459274201Sdim FD_COPY(&sockvec, &recvec); 460274201Sdim signo = 0; 461274201Sdim switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { 462274201Sdim case -1: 463274201Sdim if (errno != EINTR) { 464274201Sdim fatal("select"); 465274201Sdim /*NOTREACHED*/ 466274201Sdim } 467274201Sdim continue; 468274201Sdim case 0: 469274201Sdim continue; 470274201Sdim default: 471274201Sdim if (FD_ISSET(ripsock, &recvec)) { 472274201Sdim sigprocmask(SIG_BLOCK, &mask, &omask); 473274201Sdim riprecv(); 474274201Sdim sigprocmask(SIG_SETMASK, &omask, NULL); 475274201Sdim } 476274201Sdim if (FD_ISSET(rtsock, &recvec)) { 477274201Sdim sigprocmask(SIG_BLOCK, &mask, &omask); 478274201Sdim rtrecv(); 479274201Sdim sigprocmask(SIG_SETMASK, &omask, NULL); 480274201Sdim } 481274201Sdim } 482274201Sdim } 483274201Sdim} 484274201Sdim 485274201Sdimvoid 486274201Sdimsighandler(sig) 487274201Sdim int sig; 488274201Sdim{ 489274201Sdim 490274201Sdim signo = sig; 491274201Sdim switch (signo) { 492274201Sdim case SIGALRM: 493274201Sdim seenalrm++; 494274201Sdim break; 495274201Sdim case SIGQUIT: 496276789Sdim case SIGTERM: 497276789Sdim seenquit++; 498276789Sdim break; 499276789Sdim case SIGUSR1: 500274201Sdim case SIGHUP: 501276789Sdim case SIGINT: 502276789Sdim seenusr1++; 503274201Sdim break; 504276789Sdim } 505274201Sdim} 506274201Sdim 507274201Sdim/* 508274201Sdim * gracefully exits after resetting sockopts. 509274201Sdim */ 510274201Sdim/* ARGSUSED */ 511274201Sdimvoid 512274201Sdimrtdexit() 513274201Sdim{ 514274201Sdim struct riprt *rrt; 515274201Sdim 516274201Sdim alarm(0); 517274201Sdim for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 518274201Sdim if (rrt->rrt_rflags & RRTF_AGGREGATE) { 519274201Sdim delroute(&rrt->rrt_info, &rrt->rrt_gw); 520274201Sdim } 521274201Sdim } 522274201Sdim close(ripsock); 523296417Sdim close(rtsock); 524274201Sdim syslog(LOG_INFO, "**** Terminated ****"); 525274201Sdim closelog(); 526276789Sdim exit(1); 527276789Sdim} 528276789Sdim 529276789Sdim/* 530276789Sdim * Called periodically: 531276789Sdim * 1. age out the learned route. remove it if necessary. 532276789Sdim * 2. submit RIP6_RESPONSE packets. 533276789Sdim * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 534276789Sdim * to invoke this function in every 1 or 5 or 10 seconds only to age the 535276789Sdim * routes more precisely. 536276789Sdim */ 537276789Sdim/* ARGSUSED */ 538276789Sdimvoid 539276789Sdimripalarm() 540276789Sdim{ 541276789Sdim struct ifc *ifcp; 542276789Sdim struct riprt *rrt, *rrt_prev, *rrt_next; 543276789Sdim time_t t_lifetime, t_holddown; 544276789Sdim 545276789Sdim /* age the RIP routes */ 546276789Sdim rrt_prev = 0; 547276789Sdim t_lifetime = time(NULL) - RIP_LIFETIME; 548276789Sdim t_holddown = t_lifetime - RIP_HOLDDOWN; 549276789Sdim for (rrt = riprt; rrt; rrt = rrt_next) { 550276789Sdim rrt_next = rrt->rrt_next; 551276789Sdim 552276789Sdim if (rrt->rrt_t == 0) { 553276789Sdim rrt_prev = rrt; 554276789Sdim continue; 555276789Sdim } 556276789Sdim if (rrt->rrt_t < t_holddown) { 557274201Sdim if (rrt_prev) { 558274201Sdim rrt_prev->rrt_next = rrt->rrt_next; 559274201Sdim } else { 560274201Sdim riprt = rrt->rrt_next; 561274201Sdim } 562274201Sdim delroute(&rrt->rrt_info, &rrt->rrt_gw); 563276789Sdim free(rrt); 564274201Sdim continue; 565274201Sdim } 566274201Sdim if (rrt->rrt_t < t_lifetime) 567276789Sdim rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 568276789Sdim rrt_prev = rrt; 569274201Sdim } 570296417Sdim /* Supply updates */ 571274201Sdim for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 572274201Sdim if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 573274201Sdim ripsend(ifcp, &ifcp->ifc_ripsin, 0); 574274201Sdim } 575276789Sdim alarm(ripinterval(SUPPLY_INTERVAL6)); 576274201Sdim} 577274201Sdim 578274201Sdimvoid 579274201Sdiminit() 580274201Sdim{ 581288943Sdim int error; 582288943Sdim const int int0 = 0, int1 = 1, int255 = 255; 583288943Sdim struct addrinfo hints, *res; 584274201Sdim char port[10]; 585274201Sdim 586274201Sdim ifc = (struct ifc *)NULL; 587274201Sdim nifc = 0; 588274201Sdim nindex2ifc = 0; /*initial guess*/ 589276789Sdim index2ifc = NULL; 590274201Sdim snprintf(port, sizeof(port), "%d", RIP6_PORT); 591274201Sdim 592274201Sdim memset(&hints, 0, sizeof(hints)); 593274201Sdim hints.ai_family = PF_INET6; 594274201Sdim hints.ai_socktype = SOCK_DGRAM; 595274201Sdim hints.ai_flags = AI_PASSIVE; 596288943Sdim error = getaddrinfo(NULL, port, &hints, &res); 597288943Sdim if (error) { 598288943Sdim fatal("%s", gai_strerror(error)); 599274201Sdim /*NOTREACHED*/ 600274201Sdim } 601 if (res->ai_next) { 602 fatal(":: resolved to multiple address"); 603 /*NOTREACHED*/ 604 } 605 606 ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 607 if (ripsock < 0) { 608 fatal("rip socket"); 609 /*NOTREACHED*/ 610 } 611#ifdef IPV6_V6ONLY 612 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 613 &int1, sizeof(int1)) < 0) { 614 fatal("rip IPV6_V6ONLY"); 615 /*NOTREACHED*/ 616 } 617#endif 618 if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 619 fatal("rip bind"); 620 /*NOTREACHED*/ 621 } 622 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 623 &int255, sizeof(int255)) < 0) { 624 fatal("rip IPV6_MULTICAST_HOPS"); 625 /*NOTREACHED*/ 626 } 627 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 628 &int0, sizeof(int0)) < 0) { 629 fatal("rip IPV6_MULTICAST_LOOP"); 630 /*NOTREACHED*/ 631 } 632 633#ifdef IPV6_RECVPKTINFO 634 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 635 &int1, sizeof(int1)) < 0) { 636 fatal("rip IPV6_RECVPKTINFO"); 637 /*NOTREACHED*/ 638 } 639#else /* old adv. API */ 640 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 641 &int1, sizeof(int1)) < 0) { 642 fatal("rip IPV6_PKTINFO"); 643 /*NOTREACHED*/ 644 } 645#endif 646 647 memset(&hints, 0, sizeof(hints)); 648 hints.ai_family = PF_INET6; 649 hints.ai_socktype = SOCK_DGRAM; 650 error = getaddrinfo(RIP6_DEST, port, &hints, &res); 651 if (error) { 652 fatal("%s", gai_strerror(error)); 653 /*NOTREACHED*/ 654 } 655 if (res->ai_next) { 656 fatal("%s resolved to multiple address", RIP6_DEST); 657 /*NOTREACHED*/ 658 } 659 memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 660 661#ifdef FD_ZERO 662 FD_ZERO(&sockvec); 663#else 664 memset(&sockvec, 0, sizeof(sockvec)); 665#endif 666 FD_SET(ripsock, &sockvec); 667 668 if (nflag == 0) { 669 if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 670 fatal("route socket"); 671 /*NOTREACHED*/ 672 } 673 FD_SET(rtsock, &sockvec); 674 } else 675 rtsock = -1; /*just for safety */ 676} 677 678#define RIPSIZE(n) \ 679 (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 680 681/* 682 * ripflush flushes the rip datagram stored in the rip buffer 683 */ 684static int nrt; 685static struct netinfo6 *np; 686 687void 688ripflush(ifcp, sin6) 689 struct ifc *ifcp; 690 struct sockaddr_in6 *sin6; 691{ 692 int i; 693 int error; 694 695 if (ifcp) 696 tracet(1, "Send(%s): info(%d) to %s.%d\n", 697 ifcp->ifc_name, nrt, 698 inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 699 else 700 tracet(1, "Send: info(%d) to %s.%d\n", 701 nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 702 if (dflag >= 2) { 703 np = ripbuf->rip6_nets; 704 for (i = 0; i < nrt; i++, np++) { 705 if (np->rip6_metric == NEXTHOP_METRIC) { 706 if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 707 trace(2, " NextHop reset"); 708 else { 709 trace(2, " NextHop %s", 710 inet6_n2p(&np->rip6_dest)); 711 } 712 } else { 713 trace(2, " %s/%d[%d]", 714 inet6_n2p(&np->rip6_dest), 715 np->rip6_plen, np->rip6_metric); 716 } 717 if (np->rip6_tag) { 718 trace(2, " tag=0x%04x", 719 ntohs(np->rip6_tag) & 0xffff); 720 } 721 trace(2, "\n"); 722 } 723 } 724 error = sendpacket(sin6, RIPSIZE(nrt)); 725 if (error == EAFNOSUPPORT) { 726 /* Protocol not supported */ 727 tracet(1, "Could not send info to %s (%s): " 728 "set IFF_UP to 0\n", 729 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 730 ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 731 } 732 nrt = 0; np = ripbuf->rip6_nets; 733} 734 735/* 736 * Generate RIP6_RESPONSE packets and send them. 737 */ 738void 739ripsend(ifcp, sin6, flag) 740 struct ifc *ifcp; 741 struct sockaddr_in6 *sin6; 742 int flag; 743{ 744 struct riprt *rrt; 745 struct in6_addr *nh; /* next hop */ 746 int maxrte; 747 748 if (ifcp == NULL) { 749 /* 750 * Request from non-link local address is not 751 * a regular route6d update. 752 */ 753 maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 754 sizeof(struct udphdr) - 755 sizeof(struct rip6) + sizeof(struct netinfo6)) / 756 sizeof(struct netinfo6); 757 nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 758 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 759 if (rrt->rrt_rflags & RRTF_NOADVERTISE) 760 continue; 761 /* Put the route to the buffer */ 762 *np = rrt->rrt_info; 763 np++; nrt++; 764 if (nrt == maxrte) { 765 ripflush(NULL, sin6); 766 nh = NULL; 767 } 768 } 769 if (nrt) /* Send last packet */ 770 ripflush(NULL, sin6); 771 return; 772 } 773 774 if ((flag & RRTF_SENDANYWAY) == 0 && 775 (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 776 return; 777 778 /* -N: no use */ 779 if (iff_find(ifcp, 'N') != NULL) 780 return; 781 782 /* -T: generate default route only */ 783 if (iff_find(ifcp, 'T') != NULL) { 784 struct netinfo6 rrt_info; 785 memset(&rrt_info, 0, sizeof(struct netinfo6)); 786 rrt_info.rip6_dest = in6addr_any; 787 rrt_info.rip6_plen = 0; 788 rrt_info.rip6_metric = 1; 789 rrt_info.rip6_metric += ifcp->ifc_metric; 790 rrt_info.rip6_tag = htons(routetag & 0xffff); 791 np = ripbuf->rip6_nets; 792 *np = rrt_info; 793 nrt = 1; 794 ripflush(ifcp, sin6); 795 return; 796 } 797 798 maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 799 sizeof(struct udphdr) - 800 sizeof(struct rip6) + sizeof(struct netinfo6)) / 801 sizeof(struct netinfo6); 802 803 nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 804 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 805 if (rrt->rrt_rflags & RRTF_NOADVERTISE) 806 continue; 807 808 /* Need to check filter here */ 809 if (out_filter(rrt, ifcp) == 0) 810 continue; 811 812 /* Check split horizon and other conditions */ 813 if (tobeadv(rrt, ifcp) == 0) 814 continue; 815 816 /* Only considers the routes with flag if specified */ 817 if ((flag & RRTF_CHANGED) && 818 (rrt->rrt_rflags & RRTF_CHANGED) == 0) 819 continue; 820 821 /* Check nexthop */ 822 if (rrt->rrt_index == ifcp->ifc_index && 823 !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 824 (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 825 if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 826 if (nrt == maxrte - 2) 827 ripflush(ifcp, sin6); 828 np->rip6_dest = rrt->rrt_gw; 829 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 830 SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 831 np->rip6_plen = 0; 832 np->rip6_tag = 0; 833 np->rip6_metric = NEXTHOP_METRIC; 834 nh = &rrt->rrt_gw; 835 np++; nrt++; 836 } 837 } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 838 !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 839 rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 840 /* Reset nexthop */ 841 if (nrt == maxrte - 2) 842 ripflush(ifcp, sin6); 843 memset(np, 0, sizeof(struct netinfo6)); 844 np->rip6_metric = NEXTHOP_METRIC; 845 nh = NULL; 846 np++; nrt++; 847 } 848 849 /* Put the route to the buffer */ 850 *np = rrt->rrt_info; 851 np++; nrt++; 852 if (nrt == maxrte) { 853 ripflush(ifcp, sin6); 854 nh = NULL; 855 } 856 } 857 if (nrt) /* Send last packet */ 858 ripflush(ifcp, sin6); 859} 860 861/* 862 * outbound filter logic, per-route/interface. 863 */ 864int 865out_filter(rrt, ifcp) 866 struct riprt *rrt; 867 struct ifc *ifcp; 868{ 869 struct iff *iffp; 870 struct in6_addr ia; 871 int ok; 872 873 /* 874 * -A: filter out less specific routes, if we have aggregated 875 * route configured. 876 */ 877 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 878 if (iffp->iff_type != 'A') 879 continue; 880 if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 881 continue; 882 ia = rrt->rrt_info.rip6_dest; 883 applyplen(&ia, iffp->iff_plen); 884 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 885 return 0; 886 } 887 888 /* 889 * if it is an aggregated route, advertise it only to the 890 * interfaces specified on -A. 891 */ 892 if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 893 ok = 0; 894 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 895 if (iffp->iff_type != 'A') 896 continue; 897 if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 898 IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 899 &iffp->iff_addr)) { 900 ok = 1; 901 break; 902 } 903 } 904 if (!ok) 905 return 0; 906 } 907 908 /* 909 * -O: advertise only if prefix matches the configured prefix. 910 */ 911 if (iff_find(ifcp, 'O')) { 912 ok = 0; 913 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 914 if (iffp->iff_type != 'O') 915 continue; 916 if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 917 continue; 918 ia = rrt->rrt_info.rip6_dest; 919 applyplen(&ia, iffp->iff_plen); 920 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 921 ok = 1; 922 break; 923 } 924 } 925 if (!ok) 926 return 0; 927 } 928 929 /* the prefix should be advertised */ 930 return 1; 931} 932 933/* 934 * Determine if the route is to be advertised on the specified interface. 935 * It checks options specified in the arguments and the split horizon rule. 936 */ 937int 938tobeadv(rrt, ifcp) 939 struct riprt *rrt; 940 struct ifc *ifcp; 941{ 942 943 /* Special care for static routes */ 944 if (rrt->rrt_flags & RTF_STATIC) { 945 /* XXX don't advertise reject/blackhole routes */ 946 if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 947 return 0; 948 949 if (Sflag) /* Yes, advertise it anyway */ 950 return 1; 951 if (sflag && rrt->rrt_index != ifcp->ifc_index) 952 return 1; 953 return 0; 954 } 955 /* Regular split horizon */ 956 if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 957 return 0; 958 return 1; 959} 960 961/* 962 * Send a rip packet actually. 963 */ 964int 965sendpacket(sin6, len) 966 struct sockaddr_in6 *sin6; 967 int len; 968{ 969 /* 970 * MSG_DONTROUTE should not be specified when it responds with a 971 * RIP6_REQUEST message. SO_DONTROUTE has been specified to 972 * other sockets. 973 */ 974 struct msghdr m; 975 struct cmsghdr *cm; 976 struct iovec iov[2]; 977 u_char cmsgbuf[256]; 978 struct in6_pktinfo *pi; 979 int idx; 980 struct sockaddr_in6 sincopy; 981 982 /* do not overwrite the given sin */ 983 sincopy = *sin6; 984 sin6 = &sincopy; 985 986 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 987 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 988 idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 989 SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 990 } else 991 idx = 0; 992 993 m.msg_name = (caddr_t)sin6; 994 m.msg_namelen = sizeof(*sin6); 995 iov[0].iov_base = (caddr_t)ripbuf; 996 iov[0].iov_len = len; 997 m.msg_iov = iov; 998 m.msg_iovlen = 1; 999 if (!idx) { 1000 m.msg_control = NULL; 1001 m.msg_controllen = 0; 1002 } else { 1003 memset(cmsgbuf, 0, sizeof(cmsgbuf)); 1004 cm = (struct cmsghdr *)cmsgbuf; 1005 m.msg_control = (caddr_t)cm; 1006 m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 1007 1008 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1009 cm->cmsg_level = IPPROTO_IPV6; 1010 cm->cmsg_type = IPV6_PKTINFO; 1011 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 1012 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 1013 pi->ipi6_ifindex = idx; 1014 } 1015 1016 if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 1017 trace(1, "sendmsg: %s\n", strerror(errno)); 1018 return errno; 1019 } 1020 1021 return 0; 1022} 1023 1024/* 1025 * Receive and process RIP packets. Update the routes/kernel forwarding 1026 * table if necessary. 1027 */ 1028void 1029riprecv() 1030{ 1031 struct ifc *ifcp, *ic; 1032 struct sockaddr_in6 fsock; 1033 struct in6_addr nh; /* next hop */ 1034 struct rip6 *rp; 1035 struct netinfo6 *np, *nq; 1036 struct riprt *rrt; 1037 int len, nn, need_trigger, idx; 1038 char buf[4 * RIP6_MAXMTU]; 1039 time_t t; 1040 struct msghdr m; 1041 struct cmsghdr *cm; 1042 struct iovec iov[2]; 1043 u_char cmsgbuf[256]; 1044 struct in6_pktinfo *pi; 1045 struct iff *iffp; 1046 struct in6_addr ia; 1047 int ok; 1048 time_t t_half_lifetime; 1049 1050 need_trigger = 0; 1051 1052 m.msg_name = (caddr_t)&fsock; 1053 m.msg_namelen = sizeof(fsock); 1054 iov[0].iov_base = (caddr_t)buf; 1055 iov[0].iov_len = sizeof(buf); 1056 m.msg_iov = iov; 1057 m.msg_iovlen = 1; 1058 cm = (struct cmsghdr *)cmsgbuf; 1059 m.msg_control = (caddr_t)cm; 1060 m.msg_controllen = sizeof(cmsgbuf); 1061 if ((len = recvmsg(ripsock, &m, 0)) < 0) { 1062 fatal("recvmsg"); 1063 /*NOTREACHED*/ 1064 } 1065 idx = 0; 1066 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 1067 cm; 1068 cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 1069 if (cm->cmsg_level == IPPROTO_IPV6 && 1070 cm->cmsg_type == IPV6_PKTINFO) { 1071 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1072 idx = pi->ipi6_ifindex; 1073 break; 1074 } 1075 } 1076 if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 1077 SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 1078 1079 nh = fsock.sin6_addr; 1080 nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 1081 sizeof(struct netinfo6); 1082 rp = (struct rip6 *)buf; 1083 np = rp->rip6_nets; 1084 1085 if (rp->rip6_vers != RIP6_VERSION) { 1086 trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 1087 return; 1088 } 1089 if (rp->rip6_cmd == RIP6_REQUEST) { 1090 if (idx && idx < nindex2ifc) { 1091 ifcp = index2ifc[idx]; 1092 riprequest(ifcp, np, nn, &fsock); 1093 } else { 1094 riprequest(NULL, np, nn, &fsock); 1095 } 1096 return; 1097 } 1098 1099 if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 1100 trace(1, "Packets from non-ll addr: %s\n", 1101 inet6_n2p(&fsock.sin6_addr)); 1102 return; /* Ignore packets from non-link-local addr */ 1103 } 1104 idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 1105 ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 1106 if (!ifcp) { 1107 trace(1, "Packets to unknown interface index %d\n", idx); 1108 return; /* Ignore it */ 1109 } 1110 if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 1111 return; /* The packet is from me; ignore */ 1112 if (rp->rip6_cmd != RIP6_RESPONSE) { 1113 trace(1, "Invalid command %d\n", rp->rip6_cmd); 1114 return; 1115 } 1116 1117 /* -N: no use */ 1118 if (iff_find(ifcp, 'N') != NULL) 1119 return; 1120 1121 tracet(1, "Recv(%s): from %s.%d info(%d)\n", 1122 ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 1123 1124 t = time(NULL); 1125 t_half_lifetime = t - (RIP_LIFETIME/2); 1126 for (; nn; nn--, np++) { 1127 if (np->rip6_metric == NEXTHOP_METRIC) { 1128 /* modify neighbor address */ 1129 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 1130 nh = np->rip6_dest; 1131 SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 1132 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 1133 } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 1134 nh = fsock.sin6_addr; 1135 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 1136 } else { 1137 nh = fsock.sin6_addr; 1138 trace(1, "\tInvalid Nexthop: %s\n", 1139 inet6_n2p(&np->rip6_dest)); 1140 } 1141 continue; 1142 } 1143 if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 1144 trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 1145 inet6_n2p(&np->rip6_dest), 1146 np->rip6_plen, np->rip6_metric); 1147 continue; 1148 } 1149 if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 1150 trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 1151 inet6_n2p(&np->rip6_dest), 1152 np->rip6_plen, np->rip6_metric); 1153 continue; 1154 } 1155 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 1156 trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 1157 inet6_n2p(&np->rip6_dest), 1158 np->rip6_plen, np->rip6_metric); 1159 continue; 1160 } 1161 /* may need to pass sitelocal prefix in some case, however*/ 1162 if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 1163 trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 1164 inet6_n2p(&np->rip6_dest), 1165 np->rip6_plen, np->rip6_metric); 1166 continue; 1167 } 1168 trace(2, "\tnetinfo6: %s/%d [%d]", 1169 inet6_n2p(&np->rip6_dest), 1170 np->rip6_plen, np->rip6_metric); 1171 if (np->rip6_tag) 1172 trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 1173 if (dflag >= 2) { 1174 ia = np->rip6_dest; 1175 applyplen(&ia, np->rip6_plen); 1176 if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 1177 trace(2, " [junk outside prefix]"); 1178 } 1179 1180 /* 1181 * -L: listen only if the prefix matches the configuration 1182 */ 1183 ok = 1; /* if there's no L filter, it is ok */ 1184 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 1185 if (iffp->iff_type != 'L') 1186 continue; 1187 ok = 0; 1188 if (np->rip6_plen < iffp->iff_plen) 1189 continue; 1190 /* special rule: ::/0 means default, not "in /0" */ 1191 if (iffp->iff_plen == 0 && np->rip6_plen > 0) 1192 continue; 1193 ia = np->rip6_dest; 1194 applyplen(&ia, iffp->iff_plen); 1195 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 1196 ok = 1; 1197 break; 1198 } 1199 } 1200 if (!ok) { 1201 trace(2, " (filtered)\n"); 1202 continue; 1203 } 1204 1205 trace(2, "\n"); 1206 np->rip6_metric++; 1207 np->rip6_metric += ifcp->ifc_metric; 1208 if (np->rip6_metric > HOPCNT_INFINITY6) 1209 np->rip6_metric = HOPCNT_INFINITY6; 1210 1211 applyplen(&np->rip6_dest, np->rip6_plen); 1212 if ((rrt = rtsearch(np, NULL)) != NULL) { 1213 if (rrt->rrt_t == 0) 1214 continue; /* Intf route has priority */ 1215 nq = &rrt->rrt_info; 1216 if (nq->rip6_metric > np->rip6_metric) { 1217 if (rrt->rrt_index == ifcp->ifc_index && 1218 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1219 /* Small metric from the same gateway */ 1220 nq->rip6_metric = np->rip6_metric; 1221 } else { 1222 /* Better route found */ 1223 rrt->rrt_index = ifcp->ifc_index; 1224 /* Update routing table */ 1225 delroute(nq, &rrt->rrt_gw); 1226 rrt->rrt_gw = nh; 1227 *nq = *np; 1228 addroute(rrt, &nh, ifcp); 1229 } 1230 rrt->rrt_rflags |= RRTF_CHANGED; 1231 rrt->rrt_t = t; 1232 need_trigger = 1; 1233 } else if (nq->rip6_metric < np->rip6_metric && 1234 rrt->rrt_index == ifcp->ifc_index && 1235 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1236 /* Got worse route from same gw */ 1237 nq->rip6_metric = np->rip6_metric; 1238 rrt->rrt_t = t; 1239 rrt->rrt_rflags |= RRTF_CHANGED; 1240 need_trigger = 1; 1241 } else if (nq->rip6_metric == np->rip6_metric && 1242 np->rip6_metric < HOPCNT_INFINITY6) { 1243 if (rrt->rrt_index == ifcp->ifc_index && 1244 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1245 /* same metric, same route from same gw */ 1246 rrt->rrt_t = t; 1247 } else if (rrt->rrt_t < t_half_lifetime) { 1248 /* Better route found */ 1249 rrt->rrt_index = ifcp->ifc_index; 1250 /* Update routing table */ 1251 delroute(nq, &rrt->rrt_gw); 1252 rrt->rrt_gw = nh; 1253 *nq = *np; 1254 addroute(rrt, &nh, ifcp); 1255 rrt->rrt_rflags |= RRTF_CHANGED; 1256 rrt->rrt_t = t; 1257 } 1258 } 1259 /* 1260 * if nq->rip6_metric == HOPCNT_INFINITY6 then 1261 * do not update age value. Do nothing. 1262 */ 1263 } else if (np->rip6_metric < HOPCNT_INFINITY6) { 1264 /* Got a new valid route */ 1265 if ((rrt = MALLOC(struct riprt)) == NULL) { 1266 fatal("malloc: struct riprt"); 1267 /*NOTREACHED*/ 1268 } 1269 memset(rrt, 0, sizeof(*rrt)); 1270 nq = &rrt->rrt_info; 1271 1272 rrt->rrt_same = NULL; 1273 rrt->rrt_index = ifcp->ifc_index; 1274 rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 1275 rrt->rrt_gw = nh; 1276 *nq = *np; 1277 applyplen(&nq->rip6_dest, nq->rip6_plen); 1278 if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 1279 rrt->rrt_flags |= RTF_HOST; 1280 1281 /* Put the route to the list */ 1282 rrt->rrt_next = riprt; 1283 riprt = rrt; 1284 /* Update routing table */ 1285 addroute(rrt, &nh, ifcp); 1286 rrt->rrt_rflags |= RRTF_CHANGED; 1287 need_trigger = 1; 1288 rrt->rrt_t = t; 1289 } 1290 } 1291 /* XXX need to care the interval between triggered updates */ 1292 if (need_trigger) { 1293 if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 1294 for (ic = ifc; ic; ic = ic->ifc_next) { 1295 if (ifcp->ifc_index == ic->ifc_index) 1296 continue; 1297 if (ic->ifc_flags & IFF_UP) 1298 ripsend(ic, &ic->ifc_ripsin, 1299 RRTF_CHANGED); 1300 } 1301 } 1302 /* Reset the flag */ 1303 for (rrt = riprt; rrt; rrt = rrt->rrt_next) 1304 rrt->rrt_rflags &= ~RRTF_CHANGED; 1305 } 1306} 1307 1308/* 1309 * Send all routes request packet to the specified interface. 1310 */ 1311void 1312sendrequest(ifcp) 1313 struct ifc *ifcp; 1314{ 1315 struct netinfo6 *np; 1316 int error; 1317 1318 if (ifcp->ifc_flags & IFF_LOOPBACK) 1319 return; 1320 ripbuf->rip6_cmd = RIP6_REQUEST; 1321 np = ripbuf->rip6_nets; 1322 memset(np, 0, sizeof(struct netinfo6)); 1323 np->rip6_metric = HOPCNT_INFINITY6; 1324 tracet(1, "Send rtdump Request to %s (%s)\n", 1325 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 1326 error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 1327 if (error == EAFNOSUPPORT) { 1328 /* Protocol not supported */ 1329 tracet(1, "Could not send rtdump Request to %s (%s): " 1330 "set IFF_UP to 0\n", 1331 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 1332 ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 1333 } 1334 ripbuf->rip6_cmd = RIP6_RESPONSE; 1335} 1336 1337/* 1338 * Process a RIP6_REQUEST packet. 1339 */ 1340void 1341riprequest(ifcp, np, nn, sin6) 1342 struct ifc *ifcp; 1343 struct netinfo6 *np; 1344 int nn; 1345 struct sockaddr_in6 *sin6; 1346{ 1347 int i; 1348 struct riprt *rrt; 1349 1350 if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 1351 np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 1352 /* Specific response, don't split-horizon */ 1353 trace(1, "\tRIP Request\n"); 1354 for (i = 0; i < nn; i++, np++) { 1355 rrt = rtsearch(np, NULL); 1356 if (rrt) 1357 np->rip6_metric = rrt->rrt_info.rip6_metric; 1358 else 1359 np->rip6_metric = HOPCNT_INFINITY6; 1360 } 1361 (void)sendpacket(sin6, RIPSIZE(nn)); 1362 return; 1363 } 1364 /* Whole routing table dump */ 1365 trace(1, "\tRIP Request -- whole routing table\n"); 1366 ripsend(ifcp, sin6, RRTF_SENDANYWAY); 1367} 1368 1369/* 1370 * Get information of each interface. 1371 */ 1372void 1373ifconfig() 1374{ 1375 struct ifaddrs *ifap, *ifa; 1376 struct ifc *ifcp; 1377 struct ipv6_mreq mreq; 1378 int s; 1379 1380 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1381 fatal("socket"); 1382 /*NOTREACHED*/ 1383 } 1384 1385 if (getifaddrs(&ifap) != 0) { 1386 fatal("getifaddrs"); 1387 /*NOTREACHED*/ 1388 } 1389 1390 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1391 if (ifa->ifa_addr->sa_family != AF_INET6) 1392 continue; 1393 ifcp = ifc_find(ifa->ifa_name); 1394 /* we are interested in multicast-capable interfaces */ 1395 if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 1396 continue; 1397 if (!ifcp) { 1398 /* new interface */ 1399 if ((ifcp = MALLOC(struct ifc)) == NULL) { 1400 fatal("malloc: struct ifc"); 1401 /*NOTREACHED*/ 1402 } 1403 memset(ifcp, 0, sizeof(*ifcp)); 1404 ifcp->ifc_index = -1; 1405 ifcp->ifc_next = ifc; 1406 ifc = ifcp; 1407 nifc++; 1408 ifcp->ifc_name = allocopy(ifa->ifa_name); 1409 ifcp->ifc_addr = 0; 1410 ifcp->ifc_filter = 0; 1411 ifcp->ifc_flags = ifa->ifa_flags; 1412 trace(1, "newif %s <%s>\n", ifcp->ifc_name, 1413 ifflags(ifcp->ifc_flags)); 1414 if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 1415 loopifcp = ifcp; 1416 } else { 1417 /* update flag, this may be up again */ 1418 if (ifcp->ifc_flags != ifa->ifa_flags) { 1419 trace(1, "%s: <%s> -> ", ifcp->ifc_name, 1420 ifflags(ifcp->ifc_flags)); 1421 trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 1422 ifcp->ifc_cflags |= IFC_CHANGED; 1423 } 1424 ifcp->ifc_flags = ifa->ifa_flags; 1425 } 1426 ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 1427 if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 1428 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 1429 mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 1430 mreq.ipv6mr_interface = ifcp->ifc_index; 1431 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 1432 &mreq, sizeof(mreq)) < 0) { 1433 fatal("IPV6_JOIN_GROUP"); 1434 /*NOTREACHED*/ 1435 } 1436 trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 1437 ifcp->ifc_joined++; 1438 } 1439 } 1440 close(s); 1441 freeifaddrs(ifap); 1442} 1443 1444void 1445ifconfig1(name, sa, ifcp, s) 1446 const char *name; 1447 const struct sockaddr *sa; 1448 struct ifc *ifcp; 1449 int s; 1450{ 1451 struct in6_ifreq ifr; 1452 const struct sockaddr_in6 *sin6; 1453 struct ifac *ifa; 1454 int plen; 1455 char buf[BUFSIZ]; 1456 1457 sin6 = (const struct sockaddr_in6 *)sa; 1458 ifr.ifr_addr = *sin6; 1459 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1460 if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 1461 fatal("ioctl: SIOCGIFNETMASK_IN6"); 1462 /*NOTREACHED*/ 1463 } 1464 plen = sin6mask2len(&ifr.ifr_addr); 1465 if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 1466 /* same interface found */ 1467 /* need check if something changed */ 1468 /* XXX not yet implemented */ 1469 return; 1470 } 1471 /* 1472 * New address is found 1473 */ 1474 if ((ifa = MALLOC(struct ifac)) == NULL) { 1475 fatal("malloc: struct ifac"); 1476 /*NOTREACHED*/ 1477 } 1478 memset(ifa, 0, sizeof(*ifa)); 1479 ifa->ifa_conf = ifcp; 1480 ifa->ifa_next = ifcp->ifc_addr; 1481 ifcp->ifc_addr = ifa; 1482 ifa->ifa_addr = sin6->sin6_addr; 1483 ifa->ifa_plen = plen; 1484 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1485 ifr.ifr_addr = *sin6; 1486 if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 1487 fatal("ioctl: SIOCGIFDSTADDR_IN6"); 1488 /*NOTREACHED*/ 1489 } 1490 ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 1491 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 1492 trace(1, "found address %s/%d -- %s\n", 1493 inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 1494 } else { 1495 trace(1, "found address %s/%d\n", 1496 inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 1497 } 1498 if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 1499 ifcp->ifc_mylladdr = ifa->ifa_addr; 1500 ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 1501 memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 1502 SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 1503 ifcp->ifc_index); 1504 setindex2ifc(ifcp->ifc_index, ifcp); 1505 ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 1506 if (ifcp->ifc_mtu > RIP6_MAXMTU) 1507 ifcp->ifc_mtu = RIP6_MAXMTU; 1508 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 1509 fatal("ioctl: SIOCGIFMETRIC"); 1510 /*NOTREACHED*/ 1511 } 1512 ifcp->ifc_metric = ifr.ifr_metric; 1513 trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 1514 ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 1515 } else 1516 ifcp->ifc_cflags |= IFC_CHANGED; 1517} 1518 1519/* 1520 * Receive and process routing messages. 1521 * Update interface information as necesssary. 1522 */ 1523void 1524rtrecv() 1525{ 1526 char buf[BUFSIZ]; 1527 char *p, *q; 1528 struct rt_msghdr *rtm; 1529 struct ifa_msghdr *ifam; 1530 struct if_msghdr *ifm; 1531 int len; 1532 struct ifc *ifcp, *ic; 1533 int iface = 0, rtable = 0; 1534 struct sockaddr_in6 *rta[RTAX_MAX]; 1535 struct sockaddr_in6 mask; 1536 int i, addrs; 1537 struct riprt *rrt; 1538 1539 if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 1540 perror("read from rtsock"); 1541 exit(1); 1542 } 1543 if (len < sizeof(*rtm)) { 1544 trace(1, "short read from rtsock: %d (should be > %lu)\n", 1545 len, (u_long)sizeof(*rtm)); 1546 return; 1547 } 1548 1549 for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 1550 /* safety against bogus message */ 1551 if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 1552 trace(1, "bogus rtmsg: length=%d\n", 1553 ((struct rt_msghdr *)p)->rtm_msglen); 1554 break; 1555 } 1556 rtm = NULL; 1557 ifam = NULL; 1558 ifm = NULL; 1559 switch (((struct rt_msghdr *)p)->rtm_type) { 1560 case RTM_NEWADDR: 1561 case RTM_DELADDR: 1562 ifam = (struct ifa_msghdr *)p; 1563 addrs = ifam->ifam_addrs; 1564 q = (char *)(ifam + 1); 1565 break; 1566 case RTM_IFINFO: 1567 ifm = (struct if_msghdr *)p; 1568 addrs = ifm->ifm_addrs; 1569 q = (char *)(ifm + 1); 1570 break; 1571 default: 1572 rtm = (struct rt_msghdr *)p; 1573 addrs = rtm->rtm_addrs; 1574 q = (char *)(rtm + 1); 1575 if (rtm->rtm_version != RTM_VERSION) { 1576 trace(1, "unexpected rtmsg version %d " 1577 "(should be %d)\n", 1578 rtm->rtm_version, RTM_VERSION); 1579 continue; 1580 } 1581 if (rtm->rtm_pid == pid) { 1582#if 0 1583 trace(1, "rtmsg looped back to me, ignored\n"); 1584#endif 1585 continue; 1586 } 1587 break; 1588 } 1589 memset(&rta, 0, sizeof(rta)); 1590 for (i = 0; i < RTAX_MAX; i++) { 1591 if (addrs & (1 << i)) { 1592 rta[i] = (struct sockaddr_in6 *)q; 1593 q += ROUNDUP(rta[i]->sin6_len); 1594 } 1595 } 1596 1597 trace(1, "rtsock: %s (addrs=%x)\n", 1598 rttypes((struct rt_msghdr *)p), addrs); 1599 if (dflag >= 2) { 1600 for (i = 0; 1601 i < ((struct rt_msghdr *)p)->rtm_msglen; 1602 i++) { 1603 fprintf(stderr, "%02x ", p[i] & 0xff); 1604 if (i % 16 == 15) fprintf(stderr, "\n"); 1605 } 1606 fprintf(stderr, "\n"); 1607 } 1608 1609 /* 1610 * Easy ones first. 1611 * 1612 * We may be able to optimize by using ifm->ifm_index or 1613 * ifam->ifam_index. For simplicity we don't do that here. 1614 */ 1615 switch (((struct rt_msghdr *)p)->rtm_type) { 1616 case RTM_NEWADDR: 1617 case RTM_IFINFO: 1618 iface++; 1619 continue; 1620 case RTM_ADD: 1621 rtable++; 1622 continue; 1623 case RTM_LOSING: 1624 case RTM_MISS: 1625 case RTM_RESOLVE: 1626 case RTM_GET: 1627 case RTM_LOCK: 1628 /* nothing to be done here */ 1629 trace(1, "\tnothing to be done, ignored\n"); 1630 continue; 1631 } 1632 1633#if 0 1634 if (rta[RTAX_DST] == NULL) { 1635 trace(1, "\tno destination, ignored\n"); 1636 continue; 1637 } 1638 if (rta[RTAX_DST]->sin6_family != AF_INET6) { 1639 trace(1, "\taf mismatch, ignored\n"); 1640 continue; 1641 } 1642 if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 1643 trace(1, "\tlinklocal destination, ignored\n"); 1644 continue; 1645 } 1646 if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 1647 trace(1, "\tloopback destination, ignored\n"); 1648 continue; /* Loopback */ 1649 } 1650 if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 1651 trace(1, "\tmulticast destination, ignored\n"); 1652 continue; 1653 } 1654#endif 1655 1656 /* hard ones */ 1657 switch (((struct rt_msghdr *)p)->rtm_type) { 1658 case RTM_NEWADDR: 1659 case RTM_IFINFO: 1660 case RTM_ADD: 1661 case RTM_LOSING: 1662 case RTM_MISS: 1663 case RTM_RESOLVE: 1664 case RTM_GET: 1665 case RTM_LOCK: 1666 /* should already be handled */ 1667 fatal("rtrecv: never reach here"); 1668 /*NOTREACHED*/ 1669 case RTM_DELETE: 1670 if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 1671 trace(1, "\tsome of dst/gw/netamsk are " 1672 "unavailable, ignored\n"); 1673 break; 1674 } 1675 if ((rtm->rtm_flags & RTF_HOST) != 0) { 1676 mask.sin6_len = sizeof(mask); 1677 memset(&mask.sin6_addr, 0xff, 1678 sizeof(mask.sin6_addr)); 1679 rta[RTAX_NETMASK] = &mask; 1680 } else if (!rta[RTAX_NETMASK]) { 1681 trace(1, "\tsome of dst/gw/netamsk are " 1682 "unavailable, ignored\n"); 1683 break; 1684 } 1685 if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 1686 rta[RTAX_NETMASK]) == 0) { 1687 rtable++; /*just to be sure*/ 1688 } 1689 break; 1690 case RTM_CHANGE: 1691 case RTM_REDIRECT: 1692 trace(1, "\tnot supported yet, ignored\n"); 1693 break; 1694 case RTM_DELADDR: 1695 if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 1696 trace(1, "\tno netmask or ifa given, ignored\n"); 1697 break; 1698 } 1699 if (ifam->ifam_index < nindex2ifc) 1700 ifcp = index2ifc[ifam->ifam_index]; 1701 else 1702 ifcp = NULL; 1703 if (!ifcp) { 1704 trace(1, "\tinvalid ifam_index %d, ignored\n", 1705 ifam->ifam_index); 1706 break; 1707 } 1708 if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 1709 iface++; 1710 break; 1711 case RTM_OLDADD: 1712 case RTM_OLDDEL: 1713 trace(1, "\tnot supported yet, ignored\n"); 1714 break; 1715 } 1716 1717 } 1718 1719 if (iface) { 1720 trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 1721 ifconfig(); 1722 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 1723 if (ifcp->ifc_cflags & IFC_CHANGED) { 1724 if (ifrt(ifcp, 1)) { 1725 for (ic = ifc; ic; ic = ic->ifc_next) { 1726 if (ifcp->ifc_index == ic->ifc_index) 1727 continue; 1728 if (ic->ifc_flags & IFF_UP) 1729 ripsend(ic, &ic->ifc_ripsin, 1730 RRTF_CHANGED); 1731 } 1732 /* Reset the flag */ 1733 for (rrt = riprt; rrt; rrt = rrt->rrt_next) 1734 rrt->rrt_rflags &= ~RRTF_CHANGED; 1735 } 1736 ifcp->ifc_cflags &= ~IFC_CHANGED; 1737 } 1738 } 1739 if (rtable) { 1740 trace(1, "rtsock: read routing table again\n"); 1741 krtread(1); 1742 } 1743} 1744 1745/* 1746 * remove specified route from the internal routing table. 1747 */ 1748int 1749rt_del(sdst, sgw, smask) 1750 const struct sockaddr_in6 *sdst; 1751 const struct sockaddr_in6 *sgw; 1752 const struct sockaddr_in6 *smask; 1753{ 1754 const struct in6_addr *dst = NULL; 1755 const struct in6_addr *gw = NULL; 1756 int prefix; 1757 struct netinfo6 ni6; 1758 struct riprt *rrt = NULL; 1759 time_t t_lifetime; 1760 1761 if (sdst->sin6_family != AF_INET6) { 1762 trace(1, "\tother AF, ignored\n"); 1763 return -1; 1764 } 1765 if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 1766 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 1767 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 1768 trace(1, "\taddress %s not interesting, ignored\n", 1769 inet6_n2p(&sdst->sin6_addr)); 1770 return -1; 1771 } 1772 dst = &sdst->sin6_addr; 1773 if (sgw->sin6_family == AF_INET6) { 1774 /* easy case */ 1775 gw = &sgw->sin6_addr; 1776 prefix = sin6mask2len(smask); 1777 } else if (sgw->sin6_family == AF_LINK) { 1778 /* 1779 * Interface route... a hard case. We need to get the prefix 1780 * length from the kernel, but we now are parsing rtmsg. 1781 * We'll purge matching routes from my list, then get the 1782 * fresh list. 1783 */ 1784 struct riprt *longest; 1785 trace(1, "\t%s is an interface route, guessing prefixlen\n", 1786 inet6_n2p(dst)); 1787 longest = NULL; 1788 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 1789 if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 1790 &sdst->sin6_addr) 1791 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 1792 if (!longest 1793 || longest->rrt_info.rip6_plen < 1794 rrt->rrt_info.rip6_plen) { 1795 longest = rrt; 1796 } 1797 } 1798 } 1799 rrt = longest; 1800 if (!rrt) { 1801 trace(1, "\tno matching interface route found\n"); 1802 return -1; 1803 } 1804 gw = &in6addr_loopback; 1805 prefix = rrt->rrt_info.rip6_plen; 1806 } else { 1807 trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 1808 return -1; 1809 } 1810 1811 trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 1812 trace(1, "gw %s\n", inet6_n2p(gw)); 1813 t_lifetime = time(NULL) - RIP_LIFETIME; 1814 /* age route for interface address */ 1815 memset(&ni6, 0, sizeof(ni6)); 1816 ni6.rip6_dest = *dst; 1817 ni6.rip6_plen = prefix; 1818 applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 1819 trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 1820 ni6.rip6_plen); 1821 if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 1822 trace(1, "\tno route found\n"); 1823 return -1; 1824 } 1825#if 0 1826 if ((rrt->rrt_flags & RTF_STATIC) == 0) { 1827 trace(1, "\tyou can delete static routes only\n"); 1828 } else 1829#endif 1830 if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 1831 trace(1, "\tgw mismatch: %s <-> ", 1832 inet6_n2p(&rrt->rrt_gw)); 1833 trace(1, "%s\n", inet6_n2p(gw)); 1834 } else { 1835 trace(1, "\troute found, age it\n"); 1836 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 1837 rrt->rrt_t = t_lifetime; 1838 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 1839 } 1840 } 1841 return 0; 1842} 1843 1844/* 1845 * remove specified address from internal interface/routing table. 1846 */ 1847int 1848rt_deladdr(ifcp, sifa, smask) 1849 struct ifc *ifcp; 1850 const struct sockaddr_in6 *sifa; 1851 const struct sockaddr_in6 *smask; 1852{ 1853 const struct in6_addr *addr = NULL; 1854 int prefix; 1855 struct ifac *ifa = NULL; 1856 struct netinfo6 ni6; 1857 struct riprt *rrt = NULL; 1858 time_t t_lifetime; 1859 int updated = 0; 1860 1861 if (sifa->sin6_family != AF_INET6) { 1862 trace(1, "\tother AF, ignored\n"); 1863 return -1; 1864 } 1865 addr = &sifa->sin6_addr; 1866 prefix = sin6mask2len(smask); 1867 1868 trace(1, "\tdeleting %s/%d from %s\n", 1869 inet6_n2p(addr), prefix, ifcp->ifc_name); 1870 ifa = ifa_match(ifcp, addr, prefix); 1871 if (!ifa) { 1872 trace(1, "\tno matching ifa found for %s/%d on %s\n", 1873 inet6_n2p(addr), prefix, ifcp->ifc_name); 1874 return -1; 1875 } 1876 if (ifa->ifa_conf != ifcp) { 1877 trace(1, "\taddress table corrupt: back pointer does not match " 1878 "(%s != %s)\n", 1879 ifcp->ifc_name, ifa->ifa_conf->ifc_name); 1880 return -1; 1881 } 1882 /* remove ifa from interface */ 1883 if (ifcp->ifc_addr == ifa) 1884 ifcp->ifc_addr = ifa->ifa_next; 1885 else { 1886 struct ifac *p; 1887 for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 1888 if (p->ifa_next == ifa) { 1889 p->ifa_next = ifa->ifa_next; 1890 break; 1891 } 1892 } 1893 } 1894 ifa->ifa_next = NULL; 1895 ifa->ifa_conf = NULL; 1896 t_lifetime = time(NULL) - RIP_LIFETIME; 1897 /* age route for interface address */ 1898 memset(&ni6, 0, sizeof(ni6)); 1899 ni6.rip6_dest = ifa->ifa_addr; 1900 ni6.rip6_plen = ifa->ifa_plen; 1901 applyplen(&ni6.rip6_dest, ni6.rip6_plen); 1902 trace(1, "\tfind interface route %s/%d on %d\n", 1903 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 1904 if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 1905 struct in6_addr none; 1906 memset(&none, 0, sizeof(none)); 1907 if (rrt->rrt_index == ifcp->ifc_index && 1908 (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 1909 IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 1910 trace(1, "\troute found, age it\n"); 1911 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 1912 rrt->rrt_t = t_lifetime; 1913 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 1914 } 1915 updated++; 1916 } else { 1917 trace(1, "\tnon-interface route found: %s/%d on %d\n", 1918 inet6_n2p(&rrt->rrt_info.rip6_dest), 1919 rrt->rrt_info.rip6_plen, 1920 rrt->rrt_index); 1921 } 1922 } else 1923 trace(1, "\tno interface route found\n"); 1924 /* age route for p2p destination */ 1925 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1926 memset(&ni6, 0, sizeof(ni6)); 1927 ni6.rip6_dest = ifa->ifa_raddr; 1928 ni6.rip6_plen = 128; 1929 applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 1930 trace(1, "\tfind p2p route %s/%d on %d\n", 1931 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 1932 ifcp->ifc_index); 1933 if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 1934 if (rrt->rrt_index == ifcp->ifc_index && 1935 IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 1936 trace(1, "\troute found, age it\n"); 1937 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 1938 rrt->rrt_t = t_lifetime; 1939 rrt->rrt_info.rip6_metric = 1940 HOPCNT_INFINITY6; 1941 updated++; 1942 } 1943 } else { 1944 trace(1, "\tnon-p2p route found: %s/%d on %d\n", 1945 inet6_n2p(&rrt->rrt_info.rip6_dest), 1946 rrt->rrt_info.rip6_plen, 1947 rrt->rrt_index); 1948 } 1949 } else 1950 trace(1, "\tno p2p route found\n"); 1951 } 1952 return updated ? 0 : -1; 1953} 1954 1955/* 1956 * Get each interface address and put those interface routes to the route 1957 * list. 1958 */ 1959int 1960ifrt(ifcp, again) 1961 struct ifc *ifcp; 1962 int again; 1963{ 1964 struct ifac *ifa; 1965 struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt; 1966 struct netinfo6 *np; 1967 time_t t_lifetime; 1968 int need_trigger = 0; 1969 1970 if (ifcp->ifc_flags & IFF_LOOPBACK) 1971 return 0; /* ignore loopback */ 1972 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1973 ifrt_p2p(ifcp, again); 1974 return 0; 1975 } 1976 1977 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 1978 if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 1979#if 0 1980 trace(1, "route: %s on %s: " 1981 "skip linklocal interface address\n", 1982 inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 1983#endif 1984 continue; 1985 } 1986 if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 1987#if 0 1988 trace(1, "route: %s: skip unspec interface address\n", 1989 ifcp->ifc_name); 1990#endif 1991 continue; 1992 } 1993 if (ifcp->ifc_flags & IFF_UP) { 1994 if ((rrt = MALLOC(struct riprt)) == NULL) 1995 fatal("malloc: struct riprt"); 1996 memset(rrt, 0, sizeof(*rrt)); 1997 rrt->rrt_same = NULL; 1998 rrt->rrt_index = ifcp->ifc_index; 1999 rrt->rrt_t = 0; /* don't age */ 2000 rrt->rrt_info.rip6_dest = ifa->ifa_addr; 2001 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 2002 rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 2003 rrt->rrt_info.rip6_plen = ifa->ifa_plen; 2004 rrt->rrt_flags = RTF_CLONING; 2005 rrt->rrt_rflags |= RRTF_CHANGED; 2006 applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 2007 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2008#if 0 2009 /* XXX why gateway address == network adddress? */ 2010 rrt->rrt_gw = ifa->ifa_addr; 2011#endif 2012 np = &rrt->rrt_info; 2013 search_rrt = rtsearch(np, &prev_rrt); 2014 if (search_rrt != NULL) { 2015 if (search_rrt->rrt_info.rip6_metric > 2016 rrt->rrt_info.rip6_metric) { 2017 if (prev_rrt) 2018 prev_rrt->rrt_next = rrt->rrt_next; 2019 else 2020 riprt = rrt->rrt_next; 2021 delroute(&rrt->rrt_info, &rrt->rrt_gw); 2022 free(rrt); 2023 } else { 2024 /* Already have better route */ 2025 if (!again) { 2026 trace(1, "route: %s/%d: " 2027 "already registered (%s)\n", 2028 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2029 ifcp->ifc_name); 2030 } 2031 free(rrt); 2032 continue; 2033 } 2034 } 2035 /* Attach the route to the list */ 2036 trace(1, "route: %s/%d: register route (%s)\n", 2037 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2038 ifcp->ifc_name); 2039 rrt->rrt_next = riprt; 2040 riprt = rrt; 2041 addroute(rrt, &rrt->rrt_gw, ifcp); 2042 sendrequest(ifcp); 2043 ripsend(ifcp, &ifcp->ifc_ripsin, 0); 2044 need_trigger = 1; 2045 } else { 2046 for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 2047 if (loop_rrt->rrt_index == ifcp->ifc_index) { 2048 t_lifetime = time(NULL) - RIP_LIFETIME; 2049 if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 2050 loop_rrt->rrt_t = t_lifetime; 2051 loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 2052 loop_rrt->rrt_rflags |= RRTF_CHANGED; 2053 need_trigger = 1; 2054 } 2055 } 2056 } 2057 } 2058 } 2059 return need_trigger; 2060} 2061 2062/* 2063 * there are couple of p2p interface routing models. "behavior" lets 2064 * you pick one. it looks that gated behavior fits best with BSDs, 2065 * since BSD kernels do not look at prefix length on p2p interfaces. 2066 */ 2067void 2068ifrt_p2p(ifcp, again) 2069 struct ifc *ifcp; 2070 int again; 2071{ 2072 struct ifac *ifa; 2073 struct riprt *rrt, *orrt, *prevrrt; 2074 struct netinfo6 *np; 2075 struct in6_addr addr, dest; 2076 int advert, ignore, i; 2077#define P2PADVERT_NETWORK 1 2078#define P2PADVERT_ADDR 2 2079#define P2PADVERT_DEST 4 2080#define P2PADVERT_MAX 4 2081 const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 2082 const char *category = ""; 2083 const char *noadv; 2084 2085 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 2086 addr = ifa->ifa_addr; 2087 dest = ifa->ifa_raddr; 2088 applyplen(&addr, ifa->ifa_plen); 2089 applyplen(&dest, ifa->ifa_plen); 2090 advert = ignore = 0; 2091 switch (behavior) { 2092 case CISCO: 2093 /* 2094 * honor addr/plen, just like normal shared medium 2095 * interface. this may cause trouble if you reuse 2096 * addr/plen on other interfaces. 2097 * 2098 * advertise addr/plen. 2099 */ 2100 advert |= P2PADVERT_NETWORK; 2101 break; 2102 case GATED: 2103 /* 2104 * prefixlen on p2p interface is meaningless. 2105 * advertise addr/128 and dest/128. 2106 * 2107 * do not install network route to route6d routing 2108 * table (if we do, it would prevent route installation 2109 * for other p2p interface that shares addr/plen). 2110 * 2111 * XXX what should we do if dest is ::? it will not 2112 * get announced anyways (see following filter), 2113 * but we need to think. 2114 */ 2115 advert |= P2PADVERT_ADDR; 2116 advert |= P2PADVERT_DEST; 2117 ignore |= P2PADVERT_NETWORK; 2118 break; 2119 case ROUTE6D: 2120 /* 2121 * just for testing. actually the code is redundant 2122 * given the current p2p interface address assignment 2123 * rule for kame kernel. 2124 * 2125 * intent: 2126 * A/n -> announce A/n 2127 * A B/n, A and B share prefix -> A/n (= B/n) 2128 * A B/n, do not share prefix -> A/128 and B/128 2129 * actually, A/64 and A B/128 are the only cases 2130 * permitted by the kernel: 2131 * A/64 -> A/64 2132 * A B/128 -> A/128 and B/128 2133 */ 2134 if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 2135 if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 2136 advert |= P2PADVERT_NETWORK; 2137 else { 2138 advert |= P2PADVERT_ADDR; 2139 advert |= P2PADVERT_DEST; 2140 ignore |= P2PADVERT_NETWORK; 2141 } 2142 } else 2143 advert |= P2PADVERT_NETWORK; 2144 break; 2145 } 2146 2147 for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 2148 if ((ignore & i) != 0) 2149 continue; 2150 if ((rrt = MALLOC(struct riprt)) == NULL) { 2151 fatal("malloc: struct riprt"); 2152 /*NOTREACHED*/ 2153 } 2154 memset(rrt, 0, sizeof(*rrt)); 2155 rrt->rrt_same = NULL; 2156 rrt->rrt_index = ifcp->ifc_index; 2157 rrt->rrt_t = 0; /* don't age */ 2158 switch (i) { 2159 case P2PADVERT_NETWORK: 2160 rrt->rrt_info.rip6_dest = ifa->ifa_addr; 2161 rrt->rrt_info.rip6_plen = ifa->ifa_plen; 2162 applyplen(&rrt->rrt_info.rip6_dest, 2163 ifa->ifa_plen); 2164 category = "network"; 2165 break; 2166 case P2PADVERT_ADDR: 2167 rrt->rrt_info.rip6_dest = ifa->ifa_addr; 2168 rrt->rrt_info.rip6_plen = 128; 2169 rrt->rrt_gw = in6addr_loopback; 2170 category = "addr"; 2171 break; 2172 case P2PADVERT_DEST: 2173 rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 2174 rrt->rrt_info.rip6_plen = 128; 2175 rrt->rrt_gw = ifa->ifa_addr; 2176 category = "dest"; 2177 break; 2178 } 2179 if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 2180 IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 2181#if 0 2182 trace(1, "route: %s: skip unspec/linklocal " 2183 "(%s on %s)\n", category, ifcp->ifc_name); 2184#endif 2185 free(rrt); 2186 continue; 2187 } 2188 if ((advert & i) == 0) { 2189 rrt->rrt_rflags |= RRTF_NOADVERTISE; 2190 noadv = ", NO-ADV"; 2191 } else 2192 noadv = ""; 2193 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 2194 rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 2195 np = &rrt->rrt_info; 2196 orrt = rtsearch(np, &prevrrt); 2197 if (!orrt) { 2198 /* Attach the route to the list */ 2199 trace(1, "route: %s/%d: register route " 2200 "(%s on %s%s)\n", 2201 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2202 category, ifcp->ifc_name, noadv); 2203 rrt->rrt_next = riprt; 2204 riprt = rrt; 2205 } else if (rrt->rrt_index != orrt->rrt_index || 2206 rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 2207 /* swap route */ 2208 rrt->rrt_next = orrt->rrt_next; 2209 if (prevrrt) 2210 prevrrt->rrt_next = rrt; 2211 else 2212 riprt = rrt; 2213 free(orrt); 2214 2215 trace(1, "route: %s/%d: update (%s on %s%s)\n", 2216 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2217 category, ifcp->ifc_name, noadv); 2218 } else { 2219 /* Already found */ 2220 if (!again) { 2221 trace(1, "route: %s/%d: " 2222 "already registered (%s on %s%s)\n", 2223 inet6_n2p(&np->rip6_dest), 2224 np->rip6_plen, category, 2225 ifcp->ifc_name, noadv); 2226 } 2227 free(rrt); 2228 } 2229 } 2230 } 2231#undef P2PADVERT_NETWORK 2232#undef P2PADVERT_ADDR 2233#undef P2PADVERT_DEST 2234#undef P2PADVERT_MAX 2235} 2236 2237int 2238getifmtu(ifindex) 2239 int ifindex; 2240{ 2241 int mib[6]; 2242 char *buf; 2243 size_t msize; 2244 struct if_msghdr *ifm; 2245 int mtu; 2246 2247 mib[0] = CTL_NET; 2248 mib[1] = PF_ROUTE; 2249 mib[2] = 0; 2250 mib[3] = AF_INET6; 2251 mib[4] = NET_RT_IFLIST; 2252 mib[5] = ifindex; 2253 if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 2254 fatal("sysctl estimate NET_RT_IFLIST"); 2255 /*NOTREACHED*/ 2256 } 2257 if ((buf = malloc(msize)) == NULL) { 2258 fatal("malloc"); 2259 /*NOTREACHED*/ 2260 } 2261 if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 2262 fatal("sysctl NET_RT_IFLIST"); 2263 /*NOTREACHED*/ 2264 } 2265 ifm = (struct if_msghdr *)buf; 2266 mtu = ifm->ifm_data.ifi_mtu; 2267#ifdef __FreeBSD__ 2268 if (ifindex != ifm->ifm_index) { 2269 fatal("ifindex does not match with ifm_index"); 2270 /*NOTREACHED*/ 2271 } 2272#endif 2273 free(buf); 2274 return mtu; 2275} 2276 2277const char * 2278rttypes(rtm) 2279 struct rt_msghdr *rtm; 2280{ 2281#define RTTYPE(s, f) \ 2282do { \ 2283 if (rtm->rtm_type == (f)) \ 2284 return (s); \ 2285} while (0) 2286 RTTYPE("ADD", RTM_ADD); 2287 RTTYPE("DELETE", RTM_DELETE); 2288 RTTYPE("CHANGE", RTM_CHANGE); 2289 RTTYPE("GET", RTM_GET); 2290 RTTYPE("LOSING", RTM_LOSING); 2291 RTTYPE("REDIRECT", RTM_REDIRECT); 2292 RTTYPE("MISS", RTM_MISS); 2293 RTTYPE("LOCK", RTM_LOCK); 2294 RTTYPE("OLDADD", RTM_OLDADD); 2295 RTTYPE("OLDDEL", RTM_OLDDEL); 2296 RTTYPE("RESOLVE", RTM_RESOLVE); 2297 RTTYPE("NEWADDR", RTM_NEWADDR); 2298 RTTYPE("DELADDR", RTM_DELADDR); 2299 RTTYPE("IFINFO", RTM_IFINFO); 2300#ifdef RTM_OLDADD 2301 RTTYPE("OLDADD", RTM_OLDADD); 2302#endif 2303#ifdef RTM_OLDDEL 2304 RTTYPE("OLDDEL", RTM_OLDDEL); 2305#endif 2306#ifdef RTM_OIFINFO 2307 RTTYPE("OIFINFO", RTM_OIFINFO); 2308#endif 2309#ifdef RTM_IFANNOUNCE 2310 RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 2311#endif 2312#ifdef RTM_NEWMADDR 2313 RTTYPE("NEWMADDR", RTM_NEWMADDR); 2314#endif 2315#ifdef RTM_DELMADDR 2316 RTTYPE("DELMADDR", RTM_DELMADDR); 2317#endif 2318#undef RTTYPE 2319 return NULL; 2320} 2321 2322const char * 2323rtflags(rtm) 2324 struct rt_msghdr *rtm; 2325{ 2326 static char buf[BUFSIZ]; 2327 2328 /* 2329 * letter conflict should be okay. painful when *BSD diverges... 2330 */ 2331 strlcpy(buf, "", sizeof(buf)); 2332#define RTFLAG(s, f) \ 2333do { \ 2334 if (rtm->rtm_flags & (f)) \ 2335 strlcat(buf, (s), sizeof(buf)); \ 2336} while (0) 2337 RTFLAG("U", RTF_UP); 2338 RTFLAG("G", RTF_GATEWAY); 2339 RTFLAG("H", RTF_HOST); 2340 RTFLAG("R", RTF_REJECT); 2341 RTFLAG("D", RTF_DYNAMIC); 2342 RTFLAG("M", RTF_MODIFIED); 2343 RTFLAG("d", RTF_DONE); 2344#ifdef RTF_MASK 2345 RTFLAG("m", RTF_MASK); 2346#endif 2347 RTFLAG("C", RTF_CLONING); 2348#ifdef RTF_CLONED 2349 RTFLAG("c", RTF_CLONED); 2350#endif 2351#ifdef RTF_PRCLONING 2352 RTFLAG("c", RTF_PRCLONING); 2353#endif 2354#ifdef RTF_WASCLONED 2355 RTFLAG("W", RTF_WASCLONED); 2356#endif 2357 RTFLAG("X", RTF_XRESOLVE); 2358 RTFLAG("L", RTF_LLINFO); 2359 RTFLAG("S", RTF_STATIC); 2360 RTFLAG("B", RTF_BLACKHOLE); 2361#ifdef RTF_PROTO3 2362 RTFLAG("3", RTF_PROTO3); 2363#endif 2364 RTFLAG("2", RTF_PROTO2); 2365 RTFLAG("1", RTF_PROTO1); 2366#ifdef RTF_BROADCAST 2367 RTFLAG("b", RTF_BROADCAST); 2368#endif 2369#ifdef RTF_DEFAULT 2370 RTFLAG("d", RTF_DEFAULT); 2371#endif 2372#ifdef RTF_ISAROUTER 2373 RTFLAG("r", RTF_ISAROUTER); 2374#endif 2375#ifdef RTF_TUNNEL 2376 RTFLAG("T", RTF_TUNNEL); 2377#endif 2378#ifdef RTF_AUTH 2379 RTFLAG("A", RTF_AUTH); 2380#endif 2381#ifdef RTF_CRYPT 2382 RTFLAG("E", RTF_CRYPT); 2383#endif 2384#undef RTFLAG 2385 return buf; 2386} 2387 2388const char * 2389ifflags(flags) 2390 int flags; 2391{ 2392 static char buf[BUFSIZ]; 2393 2394 strlcpy(buf, "", sizeof(buf)); 2395#define IFFLAG(s, f) \ 2396do { \ 2397 if (flags & f) { \ 2398 if (buf[0]) \ 2399 strlcat(buf, ",", sizeof(buf)); \ 2400 strlcat(buf, s, sizeof(buf)); \ 2401 } \ 2402} while (0) 2403 IFFLAG("UP", IFF_UP); 2404 IFFLAG("BROADCAST", IFF_BROADCAST); 2405 IFFLAG("DEBUG", IFF_DEBUG); 2406 IFFLAG("LOOPBACK", IFF_LOOPBACK); 2407 IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 2408#ifdef IFF_NOTRAILERS 2409 IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 2410#endif 2411#ifdef IFF_SMART 2412 IFFLAG("SMART", IFF_SMART); 2413#endif 2414 IFFLAG("RUNNING", IFF_RUNNING); 2415 IFFLAG("NOARP", IFF_NOARP); 2416 IFFLAG("PROMISC", IFF_PROMISC); 2417 IFFLAG("ALLMULTI", IFF_ALLMULTI); 2418 IFFLAG("OACTIVE", IFF_OACTIVE); 2419 IFFLAG("SIMPLEX", IFF_SIMPLEX); 2420 IFFLAG("LINK0", IFF_LINK0); 2421 IFFLAG("LINK1", IFF_LINK1); 2422 IFFLAG("LINK2", IFF_LINK2); 2423 IFFLAG("MULTICAST", IFF_MULTICAST); 2424#undef IFFLAG 2425 return buf; 2426} 2427 2428void 2429krtread(again) 2430 int again; 2431{ 2432 int mib[6]; 2433 size_t msize; 2434 char *buf, *p, *lim; 2435 struct rt_msghdr *rtm; 2436 int retry; 2437 const char *errmsg; 2438 2439 retry = 0; 2440 buf = NULL; 2441 mib[0] = CTL_NET; 2442 mib[1] = PF_ROUTE; 2443 mib[2] = 0; 2444 mib[3] = AF_INET6; /* Address family */ 2445 mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 2446 mib[5] = 0; /* No flags */ 2447 do { 2448 retry++; 2449 errmsg = NULL; 2450 if (buf) 2451 free(buf); 2452 if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 2453 errmsg = "sysctl estimate"; 2454 continue; 2455 } 2456 if ((buf = malloc(msize)) == NULL) { 2457 errmsg = "malloc"; 2458 continue; 2459 } 2460 if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 2461 errmsg = "sysctl NET_RT_DUMP"; 2462 continue; 2463 } 2464 } while (retry < 5 && errmsg != NULL); 2465 if (errmsg) { 2466 fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 2467 (u_long)msize); 2468 /*NOTREACHED*/ 2469 } else if (1 < retry) 2470 syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 2471 2472 lim = buf + msize; 2473 for (p = buf; p < lim; p += rtm->rtm_msglen) { 2474 rtm = (struct rt_msghdr *)p; 2475 rt_entry(rtm, again); 2476 } 2477 free(buf); 2478} 2479 2480void 2481rt_entry(rtm, again) 2482 struct rt_msghdr *rtm; 2483 int again; 2484{ 2485 struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 2486 struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 2487 char *rtmp, *ifname = NULL; 2488 struct riprt *rrt, *orrt; 2489 struct netinfo6 *np; 2490 int s; 2491 2492 sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 2493 if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 2494 (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 2495 return; /* not interested in the link route */ 2496 } 2497 /* do not look at cloned routes */ 2498#ifdef RTF_WASCLONED 2499 if (rtm->rtm_flags & RTF_WASCLONED) 2500 return; 2501#endif 2502#ifdef RTF_CLONED 2503 if (rtm->rtm_flags & RTF_CLONED) 2504 return; 2505#endif 2506 /* 2507 * do not look at dynamic routes. 2508 * netbsd/openbsd cloned routes have UGHD. 2509 */ 2510 if (rtm->rtm_flags & RTF_DYNAMIC) 2511 return; 2512 rtmp = (char *)(rtm + 1); 2513 /* Destination */ 2514 if ((rtm->rtm_addrs & RTA_DST) == 0) 2515 return; /* ignore routes without destination address */ 2516 sin6_dst = (struct sockaddr_in6 *)rtmp; 2517 rtmp += ROUNDUP(sin6_dst->sin6_len); 2518 if (rtm->rtm_addrs & RTA_GATEWAY) { 2519 sin6_gw = (struct sockaddr_in6 *)rtmp; 2520 rtmp += ROUNDUP(sin6_gw->sin6_len); 2521 } 2522 if (rtm->rtm_addrs & RTA_NETMASK) { 2523 sin6_mask = (struct sockaddr_in6 *)rtmp; 2524 rtmp += ROUNDUP(sin6_mask->sin6_len); 2525 } 2526 if (rtm->rtm_addrs & RTA_GENMASK) { 2527 sin6_genmask = (struct sockaddr_in6 *)rtmp; 2528 rtmp += ROUNDUP(sin6_genmask->sin6_len); 2529 } 2530 if (rtm->rtm_addrs & RTA_IFP) { 2531 sin6_ifp = (struct sockaddr_in6 *)rtmp; 2532 rtmp += ROUNDUP(sin6_ifp->sin6_len); 2533 } 2534 2535 /* Destination */ 2536 if (sin6_dst->sin6_family != AF_INET6) 2537 return; 2538 if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 2539 return; /* Link-local */ 2540 if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 2541 return; /* Loopback */ 2542 if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 2543 return; 2544 2545 if ((rrt = MALLOC(struct riprt)) == NULL) { 2546 fatal("malloc: struct riprt"); 2547 /*NOTREACHED*/ 2548 } 2549 memset(rrt, 0, sizeof(*rrt)); 2550 np = &rrt->rrt_info; 2551 rrt->rrt_same = NULL; 2552 rrt->rrt_t = time(NULL); 2553 if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 2554 rrt->rrt_t = 0; /* Don't age static routes */ 2555 np->rip6_tag = 0; 2556 np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 2557 if (np->rip6_metric < 1) 2558 np->rip6_metric = 1; 2559 rrt->rrt_flags = rtm->rtm_flags; 2560 np->rip6_dest = sin6_dst->sin6_addr; 2561 2562 /* Mask or plen */ 2563 if (rtm->rtm_flags & RTF_HOST) 2564 np->rip6_plen = 128; /* Host route */ 2565 else if (sin6_mask) 2566 np->rip6_plen = sin6mask2len(sin6_mask); 2567 else 2568 np->rip6_plen = 0; 2569 2570 orrt = rtsearch(np, NULL); 2571 if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 2572 /* Already found */ 2573 if (!again) { 2574 trace(1, "route: %s/%d flags %s: already registered\n", 2575 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2576 rtflags(rtm)); 2577 } 2578 free(rrt); 2579 return; 2580 } 2581 /* Gateway */ 2582 if (!sin6_gw) 2583 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2584 else { 2585 if (sin6_gw->sin6_family == AF_INET6) 2586 rrt->rrt_gw = sin6_gw->sin6_addr; 2587 else if (sin6_gw->sin6_family == AF_LINK) { 2588 /* XXX in case ppp link? */ 2589 rrt->rrt_gw = in6addr_loopback; 2590 } else 2591 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2592 } 2593 trace(1, "route: %s/%d flags %s", 2594 inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 2595 trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 2596 2597 /* Interface */ 2598 s = rtm->rtm_index; 2599 if (s < nindex2ifc && index2ifc[s]) 2600 ifname = index2ifc[s]->ifc_name; 2601 else { 2602 trace(1, " not configured\n"); 2603 free(rrt); 2604 return; 2605 } 2606 trace(1, " if %s sock %d", ifname, s); 2607 rrt->rrt_index = s; 2608 2609 trace(1, "\n"); 2610 2611 /* Check gateway */ 2612 if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 2613 !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 2614#ifdef __FreeBSD__ 2615 && (rrt->rrt_flags & RTF_LOCAL) == 0 2616#endif 2617 ) { 2618 trace(0, "***** Gateway %s is not a link-local address.\n", 2619 inet6_n2p(&rrt->rrt_gw)); 2620 trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 2621 inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 2622 rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 2623 } 2624 2625 /* Put it to the route list */ 2626 if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 2627 /* replace route list */ 2628 rrt->rrt_next = orrt->rrt_next; 2629 *orrt = *rrt; 2630 trace(1, "route: %s/%d flags %s: replace new route\n", 2631 inet6_n2p(&np->rip6_dest), np->rip6_plen, 2632 rtflags(rtm)); 2633 free(rrt); 2634 } else { 2635 rrt->rrt_next = riprt; 2636 riprt = rrt; 2637 } 2638} 2639 2640int 2641addroute(rrt, gw, ifcp) 2642 struct riprt *rrt; 2643 const struct in6_addr *gw; 2644 struct ifc *ifcp; 2645{ 2646 struct netinfo6 *np; 2647 u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 2648 struct rt_msghdr *rtm; 2649 struct sockaddr_in6 *sin6; 2650 int len; 2651 2652 np = &rrt->rrt_info; 2653 inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 2654 inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 2655 tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 2656 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 2657 np->rip6_metric - 1, buf2); 2658 if (rtlog) 2659 fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 2660 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 2661 np->rip6_metric - 1, buf2); 2662 if (nflag) 2663 return 0; 2664 2665 memset(buf, 0, sizeof(buf)); 2666 rtm = (struct rt_msghdr *)buf; 2667 rtm->rtm_type = RTM_ADD; 2668 rtm->rtm_version = RTM_VERSION; 2669 rtm->rtm_seq = ++seq; 2670 rtm->rtm_pid = pid; 2671 rtm->rtm_flags = rrt->rrt_flags; 2672 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2673 rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 2674 rtm->rtm_inits = RTV_HOPCOUNT; 2675 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2676 /* Destination */ 2677 sin6->sin6_len = sizeof(struct sockaddr_in6); 2678 sin6->sin6_family = AF_INET6; 2679 sin6->sin6_addr = np->rip6_dest; 2680 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2681 /* Gateway */ 2682 sin6->sin6_len = sizeof(struct sockaddr_in6); 2683 sin6->sin6_family = AF_INET6; 2684 sin6->sin6_addr = *gw; 2685 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2686 /* Netmask */ 2687 sin6->sin6_len = sizeof(struct sockaddr_in6); 2688 sin6->sin6_family = AF_INET6; 2689 sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2690 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2691 2692 len = (char *)sin6 - (char *)buf; 2693 rtm->rtm_msglen = len; 2694 if (write(rtsock, buf, len) > 0) 2695 return 0; 2696 2697 if (errno == EEXIST) { 2698 trace(0, "ADD: Route already exists %s/%d gw %s\n", 2699 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 2700 if (rtlog) 2701 fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2702 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 2703 } else { 2704 trace(0, "Can not write to rtsock (addroute): %s\n", 2705 strerror(errno)); 2706 if (rtlog) 2707 fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2708 strerror(errno)); 2709 } 2710 return -1; 2711} 2712 2713int 2714delroute(np, gw) 2715 struct netinfo6 *np; 2716 struct in6_addr *gw; 2717{ 2718 u_char buf[BUFSIZ], buf2[BUFSIZ]; 2719 struct rt_msghdr *rtm; 2720 struct sockaddr_in6 *sin6; 2721 int len; 2722 2723 inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 2724 tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 2725 np->rip6_plen, buf2); 2726 if (rtlog) 2727 fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 2728 hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2729 if (nflag) 2730 return 0; 2731 2732 memset(buf, 0, sizeof(buf)); 2733 rtm = (struct rt_msghdr *)buf; 2734 rtm->rtm_type = RTM_DELETE; 2735 rtm->rtm_version = RTM_VERSION; 2736 rtm->rtm_seq = ++seq; 2737 rtm->rtm_pid = pid; 2738 rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 2739 if (np->rip6_plen == sizeof(struct in6_addr) * 8) 2740 rtm->rtm_flags |= RTF_HOST; 2741 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2742 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2743 /* Destination */ 2744 sin6->sin6_len = sizeof(struct sockaddr_in6); 2745 sin6->sin6_family = AF_INET6; 2746 sin6->sin6_addr = np->rip6_dest; 2747 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2748 /* Gateway */ 2749 sin6->sin6_len = sizeof(struct sockaddr_in6); 2750 sin6->sin6_family = AF_INET6; 2751 sin6->sin6_addr = *gw; 2752 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2753 /* Netmask */ 2754 sin6->sin6_len = sizeof(struct sockaddr_in6); 2755 sin6->sin6_family = AF_INET6; 2756 sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2757 sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2758 2759 len = (char *)sin6 - (char *)buf; 2760 rtm->rtm_msglen = len; 2761 if (write(rtsock, buf, len) >= 0) 2762 return 0; 2763 2764 if (errno == ESRCH) { 2765 trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2766 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2767 if (rtlog) 2768 fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2769 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2770 } else { 2771 trace(0, "Can not write to rtsock (delroute): %s\n", 2772 strerror(errno)); 2773 if (rtlog) 2774 fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2775 strerror(errno)); 2776 } 2777 return -1; 2778} 2779 2780struct in6_addr * 2781getroute(np, gw) 2782 struct netinfo6 *np; 2783 struct in6_addr *gw; 2784{ 2785 u_char buf[BUFSIZ]; 2786 u_long myseq; 2787 int len; 2788 struct rt_msghdr *rtm; 2789 struct sockaddr_in6 *sin6; 2790 2791 rtm = (struct rt_msghdr *)buf; 2792 len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 2793 memset(rtm, 0, len); 2794 rtm->rtm_type = RTM_GET; 2795 rtm->rtm_version = RTM_VERSION; 2796 myseq = ++seq; 2797 rtm->rtm_seq = myseq; 2798 rtm->rtm_addrs = RTA_DST; 2799 rtm->rtm_msglen = len; 2800 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2801 sin6->sin6_len = sizeof(struct sockaddr_in6); 2802 sin6->sin6_family = AF_INET6; 2803 sin6->sin6_addr = np->rip6_dest; 2804 if (write(rtsock, buf, len) < 0) { 2805 if (errno == ESRCH) /* No such route found */ 2806 return NULL; 2807 perror("write to rtsock"); 2808 exit(1); 2809 } 2810 do { 2811 if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 2812 perror("read from rtsock"); 2813 exit(1); 2814 } 2815 rtm = (struct rt_msghdr *)buf; 2816 } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2817 sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2818 if (rtm->rtm_addrs & RTA_DST) { 2819 sin6 = (struct sockaddr_in6 *) 2820 ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2821 } 2822 if (rtm->rtm_addrs & RTA_GATEWAY) { 2823 *gw = sin6->sin6_addr; 2824 return gw; 2825 } 2826 return NULL; 2827} 2828 2829const char * 2830inet6_n2p(p) 2831 const struct in6_addr *p; 2832{ 2833 static char buf[BUFSIZ]; 2834 2835 return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 2836} 2837 2838void 2839ifrtdump(sig) 2840 int sig; 2841{ 2842 2843 ifdump(sig); 2844 rtdump(sig); 2845} 2846 2847void 2848ifdump(sig) 2849 int sig; 2850{ 2851 struct ifc *ifcp; 2852 FILE *dump; 2853 int i; 2854 2855 if (sig == 0) 2856 dump = stderr; 2857 else 2858 if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 2859 dump = stderr; 2860 2861 fprintf(dump, "%s: Interface Table Dump\n", hms()); 2862 fprintf(dump, " Number of interfaces: %d\n", nifc); 2863 for (i = 0; i < 2; i++) { 2864 fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 2865 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 2866 if (i == 0) { 2867 if ((ifcp->ifc_flags & IFF_UP) == 0) 2868 continue; 2869 if (iff_find(ifcp, 'N') != NULL) 2870 continue; 2871 } else { 2872 if (ifcp->ifc_flags & IFF_UP) 2873 continue; 2874 } 2875 ifdump0(dump, ifcp); 2876 } 2877 } 2878 fprintf(dump, "\n"); 2879 if (dump != stderr) 2880 fclose(dump); 2881} 2882 2883void 2884ifdump0(dump, ifcp) 2885 FILE *dump; 2886 const struct ifc *ifcp; 2887{ 2888 struct ifac *ifa; 2889 struct iff *iffp; 2890 char buf[BUFSIZ]; 2891 const char *ft; 2892 int addr; 2893 2894 fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 2895 ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 2896 inet6_n2p(&ifcp->ifc_mylladdr), 2897 ifcp->ifc_mtu, ifcp->ifc_metric); 2898 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 2899 if (ifcp->ifc_flags & IFF_POINTOPOINT) { 2900 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 2901 buf, sizeof(buf)); 2902 fprintf(dump, "\t%s/%d -- %s\n", 2903 inet6_n2p(&ifa->ifa_addr), 2904 ifa->ifa_plen, buf); 2905 } else { 2906 fprintf(dump, "\t%s/%d\n", 2907 inet6_n2p(&ifa->ifa_addr), 2908 ifa->ifa_plen); 2909 } 2910 } 2911 if (ifcp->ifc_filter) { 2912 fprintf(dump, "\tFilter:"); 2913 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 2914 addr = 0; 2915 switch (iffp->iff_type) { 2916 case 'A': 2917 ft = "Aggregate"; addr++; break; 2918 case 'N': 2919 ft = "No-use"; break; 2920 case 'O': 2921 ft = "Advertise-only"; addr++; break; 2922 case 'T': 2923 ft = "Default-only"; break; 2924 case 'L': 2925 ft = "Listen-only"; addr++; break; 2926 default: 2927 snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 2928 ft = buf; 2929 addr++; 2930 break; 2931 } 2932 fprintf(dump, " %s", ft); 2933 if (addr) { 2934 fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 2935 iffp->iff_plen); 2936 } 2937 } 2938 fprintf(dump, "\n"); 2939 } 2940} 2941 2942void 2943rtdump(sig) 2944 int sig; 2945{ 2946 struct riprt *rrt; 2947 char buf[BUFSIZ]; 2948 FILE *dump; 2949 time_t t, age; 2950 2951 if (sig == 0) 2952 dump = stderr; 2953 else 2954 if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 2955 dump = stderr; 2956 2957 t = time(NULL); 2958 fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 2959 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 2960 if (rrt->rrt_t == 0) 2961 age = 0; 2962 else 2963 age = t - rrt->rrt_t; 2964 inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 2965 buf, sizeof(buf)); 2966 fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 2967 buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 2968 index2ifc[rrt->rrt_index]->ifc_name, 2969 inet6_n2p(&rrt->rrt_gw), 2970 rrt->rrt_info.rip6_metric, (long)age); 2971 if (rrt->rrt_info.rip6_tag) { 2972 fprintf(dump, " tag(0x%04x)", 2973 ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 2974 } 2975 if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 2976 fprintf(dump, " NOT-LL"); 2977 if (rrt->rrt_rflags & RRTF_NOADVERTISE) 2978 fprintf(dump, " NO-ADV"); 2979 fprintf(dump, "\n"); 2980 } 2981 fprintf(dump, "\n"); 2982 if (dump != stderr) 2983 fclose(dump); 2984} 2985 2986/* 2987 * Parse the -A (and -O) options and put corresponding filter object to the 2988 * specified interface structures. Each of the -A/O option has the following 2989 * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 2990 * -O 5f09:c400::/32,ef0,ef1 (only when match) 2991 */ 2992void 2993filterconfig() 2994{ 2995 int i; 2996 char *p, *ap, *iflp, *ifname; 2997 struct iff ftmp, *iff_obj; 2998 struct ifc *ifcp; 2999 struct riprt *rrt; 3000#if 0 3001 struct in6_addr gw; 3002#endif 3003 3004 for (i = 0; i < nfilter; i++) { 3005 ap = filter[i]; 3006 iflp = NULL; 3007 ifcp = NULL; 3008 if (filtertype[i] == 'N' || filtertype[i] == 'T') { 3009 iflp = ap; 3010 goto ifonly; 3011 } 3012 if ((p = index(ap, ',')) != NULL) { 3013 *p++ = '\0'; 3014 iflp = p; 3015 } 3016 if ((p = index(ap, '/')) == NULL) { 3017 fatal("no prefixlen specified for '%s'", ap); 3018 /*NOTREACHED*/ 3019 } 3020 *p++ = '\0'; 3021 if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 3022 fatal("invalid prefix specified for '%s'", ap); 3023 /*NOTREACHED*/ 3024 } 3025 ftmp.iff_plen = atoi(p); 3026 ftmp.iff_next = NULL; 3027 applyplen(&ftmp.iff_addr, ftmp.iff_plen); 3028ifonly: 3029 ftmp.iff_type = filtertype[i]; 3030 if (iflp == NULL || *iflp == '\0') { 3031 fatal("no interface specified for '%s'", ap); 3032 /*NOTREACHED*/ 3033 } 3034 /* parse the interface listing portion */ 3035 while (iflp) { 3036 ifname = iflp; 3037 if ((iflp = index(iflp, ',')) != NULL) 3038 *iflp++ = '\0'; 3039 ifcp = ifc_find(ifname); 3040 if (ifcp == NULL) { 3041 fatal("no interface %s exists", ifname); 3042 /*NOTREACHED*/ 3043 } 3044 iff_obj = (struct iff *)malloc(sizeof(struct iff)); 3045 if (iff_obj == NULL) { 3046 fatal("malloc of iff_obj"); 3047 /*NOTREACHED*/ 3048 } 3049 memcpy((void *)iff_obj, (void *)&ftmp, 3050 sizeof(struct iff)); 3051 /* link it to the interface filter */ 3052 iff_obj->iff_next = ifcp->ifc_filter; 3053 ifcp->ifc_filter = iff_obj; 3054 } 3055 3056 /* 3057 * -A: aggregate configuration. 3058 */ 3059 if (filtertype[i] != 'A') 3060 continue; 3061 /* put the aggregate to the kernel routing table */ 3062 rrt = (struct riprt *)malloc(sizeof(struct riprt)); 3063 if (rrt == NULL) { 3064 fatal("malloc: rrt"); 3065 /*NOTREACHED*/ 3066 } 3067 memset(rrt, 0, sizeof(struct riprt)); 3068 rrt->rrt_info.rip6_dest = ftmp.iff_addr; 3069 rrt->rrt_info.rip6_plen = ftmp.iff_plen; 3070 rrt->rrt_info.rip6_metric = 1; 3071 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 3072 rrt->rrt_gw = in6addr_loopback; 3073 rrt->rrt_flags = RTF_UP | RTF_REJECT; 3074 rrt->rrt_rflags = RRTF_AGGREGATE; 3075 rrt->rrt_t = 0; 3076 rrt->rrt_index = loopifindex; 3077#if 0 3078 if (getroute(&rrt->rrt_info, &gw)) { 3079#if 0 3080 /* 3081 * When the address has already been registered in the 3082 * kernel routing table, it should be removed 3083 */ 3084 delroute(&rrt->rrt_info, &gw); 3085#else 3086 /* it is safer behavior */ 3087 errno = EINVAL; 3088 fatal("%s/%u already in routing table, " 3089 "cannot aggregate", 3090 inet6_n2p(&rrt->rrt_info.rip6_dest), 3091 rrt->rrt_info.rip6_plen); 3092 /*NOTREACHED*/ 3093#endif 3094 } 3095#endif 3096 /* Put the route to the list */ 3097 rrt->rrt_next = riprt; 3098 riprt = rrt; 3099 trace(1, "Aggregate: %s/%d for %s\n", 3100 inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 3101 ifcp->ifc_name); 3102 /* Add this route to the kernel */ 3103 if (nflag) /* do not modify kernel routing table */ 3104 continue; 3105 addroute(rrt, &in6addr_loopback, loopifcp); 3106 } 3107} 3108 3109/***************** utility functions *****************/ 3110 3111/* 3112 * Returns a pointer to ifac whose address and prefix length matches 3113 * with the address and prefix length specified in the arguments. 3114 */ 3115struct ifac * 3116ifa_match(ifcp, ia, plen) 3117 const struct ifc *ifcp; 3118 const struct in6_addr *ia; 3119 int plen; 3120{ 3121 struct ifac *ifa; 3122 3123 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 3124 if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 3125 ifa->ifa_plen == plen) 3126 break; 3127 } 3128 return ifa; 3129} 3130 3131/* 3132 * Return a pointer to riprt structure whose address and prefix length 3133 * matches with the address and prefix length found in the argument. 3134 * Note: This is not a rtalloc(). Therefore exact match is necessary. 3135 */ 3136struct riprt * 3137rtsearch(np, prev_rrt) 3138 struct netinfo6 *np; 3139 struct riprt **prev_rrt; 3140{ 3141 struct riprt *rrt; 3142 3143 if (prev_rrt) 3144 *prev_rrt = NULL; 3145 for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 3146 if (rrt->rrt_info.rip6_plen == np->rip6_plen && 3147 IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 3148 &np->rip6_dest)) 3149 return rrt; 3150 if (prev_rrt) 3151 *prev_rrt = rrt; 3152 } 3153 if (prev_rrt) 3154 *prev_rrt = NULL; 3155 return 0; 3156} 3157 3158int 3159sin6mask2len(sin6) 3160 const struct sockaddr_in6 *sin6; 3161{ 3162 3163 return mask2len(&sin6->sin6_addr, 3164 sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 3165} 3166 3167int 3168mask2len(addr, lenlim) 3169 const struct in6_addr *addr; 3170 int lenlim; 3171{ 3172 int i = 0, j; 3173 const u_char *p = (const u_char *)addr; 3174 3175 for (j = 0; j < lenlim; j++, p++) { 3176 if (*p != 0xff) 3177 break; 3178 i += 8; 3179 } 3180 if (j < lenlim) { 3181 switch (*p) { 3182#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 3183 MASKLEN(0xfe, 7); break; 3184 MASKLEN(0xfc, 6); break; 3185 MASKLEN(0xf8, 5); break; 3186 MASKLEN(0xf0, 4); break; 3187 MASKLEN(0xe0, 3); break; 3188 MASKLEN(0xc0, 2); break; 3189 MASKLEN(0x80, 1); break; 3190#undef MASKLEN 3191 } 3192 } 3193 return i; 3194} 3195 3196void 3197applymask(addr, mask) 3198 struct in6_addr *addr, *mask; 3199{ 3200 int i; 3201 u_long *p, *q; 3202 3203 p = (u_long *)addr; q = (u_long *)mask; 3204 for (i = 0; i < 4; i++) 3205 *p++ &= *q++; 3206} 3207 3208static const u_char plent[8] = { 3209 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 3210}; 3211 3212void 3213applyplen(ia, plen) 3214 struct in6_addr *ia; 3215 int plen; 3216{ 3217 u_char *p; 3218 int i; 3219 3220 p = ia->s6_addr; 3221 for (i = 0; i < 16; i++) { 3222 if (plen <= 0) 3223 *p = 0; 3224 else if (plen < 8) 3225 *p &= plent[plen]; 3226 p++, plen -= 8; 3227 } 3228} 3229 3230static const int pl2m[9] = { 3231 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 3232}; 3233 3234struct in6_addr * 3235plen2mask(n) 3236 int n; 3237{ 3238 static struct in6_addr ia; 3239 u_char *p; 3240 int i; 3241 3242 memset(&ia, 0, sizeof(struct in6_addr)); 3243 p = (u_char *)&ia; 3244 for (i = 0; i < 16; i++, p++, n -= 8) { 3245 if (n >= 8) { 3246 *p = 0xff; 3247 continue; 3248 } 3249 *p = pl2m[n]; 3250 break; 3251 } 3252 return &ia; 3253} 3254 3255char * 3256allocopy(p) 3257 char *p; 3258{ 3259 int len = strlen(p) + 1; 3260 char *q = (char *)malloc(len); 3261 3262 if (!q) { 3263 fatal("malloc"); 3264 /*NOTREACHED*/ 3265 } 3266 3267 strlcpy(q, p, len); 3268 return q; 3269} 3270 3271char * 3272hms() 3273{ 3274 static char buf[BUFSIZ]; 3275 time_t t; 3276 struct tm *tm; 3277 3278 t = time(NULL); 3279 if ((tm = localtime(&t)) == 0) { 3280 fatal("localtime"); 3281 /*NOTREACHED*/ 3282 } 3283 snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 3284 tm->tm_sec); 3285 return buf; 3286} 3287 3288#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 3289 3290int 3291ripinterval(timer) 3292 int timer; 3293{ 3294 double r = rand(); 3295 3296 interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 3297 nextalarm = time(NULL) + interval; 3298 return interval; 3299} 3300 3301time_t 3302ripsuptrig() 3303{ 3304 time_t t; 3305 3306 double r = rand(); 3307 t = (int)(RIP_TRIG_INT6_MIN + 3308 (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 3309 sup_trig_update = time(NULL) + t; 3310 return t; 3311} 3312 3313void 3314#ifdef __STDC__ 3315fatal(const char *fmt, ...) 3316#else 3317fatal(fmt, va_alist) 3318 char *fmt; 3319 va_dcl 3320#endif 3321{ 3322 va_list ap; 3323 char buf[1024]; 3324 3325#ifdef __STDC__ 3326 va_start(ap, fmt); 3327#else 3328 va_start(ap); 3329#endif 3330 vsnprintf(buf, sizeof(buf), fmt, ap); 3331 perror(buf); 3332 syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 3333 rtdexit(); 3334 va_end(ap); 3335} 3336 3337void 3338#ifdef __STDC__ 3339tracet(int level, const char *fmt, ...) 3340#else 3341tracet(level, fmt, va_alist) 3342 int level; 3343 char *fmt; 3344 va_dcl 3345#endif 3346{ 3347 va_list ap; 3348 3349#ifdef __STDC__ 3350 va_start(ap, fmt); 3351#else 3352 va_start(ap); 3353#endif 3354 if (level <= dflag) { 3355 fprintf(stderr, "%s: ", hms()); 3356 vfprintf(stderr, fmt, ap); 3357 } 3358 if (dflag) { 3359 if (level > 0) 3360 vsyslog(LOG_DEBUG, fmt, ap); 3361 else 3362 vsyslog(LOG_WARNING, fmt, ap); 3363 } 3364 va_end(ap); 3365} 3366 3367void 3368#ifdef __STDC__ 3369trace(int level, const char *fmt, ...) 3370#else 3371trace(level, fmt, va_alist) 3372 int level; 3373 char *fmt; 3374 va_dcl 3375#endif 3376{ 3377 va_list ap; 3378 3379#ifdef __STDC__ 3380 va_start(ap, fmt); 3381#else 3382 va_start(ap); 3383#endif 3384 if (level <= dflag) 3385 vfprintf(stderr, fmt, ap); 3386 if (dflag) { 3387 if (level > 0) 3388 vsyslog(LOG_DEBUG, fmt, ap); 3389 else 3390 vsyslog(LOG_WARNING, fmt, ap); 3391 } 3392 va_end(ap); 3393} 3394 3395unsigned int 3396if_maxindex() 3397{ 3398 struct if_nameindex *p, *p0; 3399 unsigned int max = 0; 3400 3401 p0 = if_nameindex(); 3402 for (p = p0; p && p->if_index && p->if_name; p++) { 3403 if (max < p->if_index) 3404 max = p->if_index; 3405 } 3406 if_freenameindex(p0); 3407 return max; 3408} 3409 3410struct ifc * 3411ifc_find(name) 3412 char *name; 3413{ 3414 struct ifc *ifcp; 3415 3416 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 3417 if (strcmp(name, ifcp->ifc_name) == 0) 3418 return ifcp; 3419 } 3420 return (struct ifc *)NULL; 3421} 3422 3423struct iff * 3424iff_find(ifcp, type) 3425 struct ifc *ifcp; 3426 int type; 3427{ 3428 struct iff *iffp; 3429 3430 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 3431 if (iffp->iff_type == type) 3432 return iffp; 3433 } 3434 return NULL; 3435} 3436 3437void 3438setindex2ifc(idx, ifcp) 3439 int idx; 3440 struct ifc *ifcp; 3441{ 3442 int n; 3443 struct ifc **p; 3444 3445 if (!index2ifc) { 3446 nindex2ifc = 5; /*initial guess*/ 3447 index2ifc = (struct ifc **) 3448 malloc(sizeof(*index2ifc) * nindex2ifc); 3449 if (index2ifc == NULL) { 3450 fatal("malloc"); 3451 /*NOTREACHED*/ 3452 } 3453 memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 3454 } 3455 n = nindex2ifc; 3456 while (nindex2ifc <= idx) 3457 nindex2ifc *= 2; 3458 if (n != nindex2ifc) { 3459 p = (struct ifc **)realloc(index2ifc, 3460 sizeof(*index2ifc) * nindex2ifc); 3461 if (p == NULL) { 3462 fatal("realloc"); 3463 /*NOTREACHED*/ 3464 } 3465 memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 3466 index2ifc = p; 3467 } 3468 index2ifc[idx] = ifcp; 3469} 3470