route6d.c revision 122677
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 122677 2003-11-14 17:16:50Z ume $ */ 2122677Sume/* $KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $ */ 355163Sshin 455163Sshin/* 555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 655163Sshin * All rights reserved. 762607Sitojun * 855163Sshin * Redistribution and use in source and binary forms, with or without 955163Sshin * modification, are permitted provided that the following conditions 1055163Sshin * are met: 1155163Sshin * 1. Redistributions of source code must retain the above copyright 1255163Sshin * notice, this list of conditions and the following disclaimer. 1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455163Sshin * notice, this list of conditions and the following disclaimer in the 1555163Sshin * documentation and/or other materials provided with the distribution. 1655163Sshin * 3. Neither the name of the project nor the names of its contributors 1755163Sshin * may be used to endorse or promote products derived from this software 1855163Sshin * without specific prior written permission. 1962607Sitojun * 2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055163Sshin * SUCH DAMAGE. 3155163Sshin */ 3255163Sshin 3355163Sshin#ifndef lint 34122677Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $"; 3555163Sshin#endif 3655163Sshin 3755163Sshin#include <stdio.h> 3855163Sshin 3955163Sshin#include <time.h> 4055163Sshin#include <unistd.h> 4155163Sshin#include <stdlib.h> 4255163Sshin#include <string.h> 4355163Sshin#include <signal.h> 4455163Sshin#ifdef __STDC__ 4555163Sshin#include <stdarg.h> 4655163Sshin#else 4755163Sshin#include <varargs.h> 4855163Sshin#endif 4955163Sshin#include <syslog.h> 5055163Sshin#include <stddef.h> 5162607Sitojun#include <errno.h> 5255163Sshin#include <err.h> 53119076Sume#ifdef HAVE_POLL_H 54119076Sume#include <poll.h> 55119076Sume#endif 5655163Sshin 5755163Sshin#include <sys/types.h> 5855163Sshin#include <sys/param.h> 5955163Sshin#include <sys/file.h> 6055163Sshin#include <sys/socket.h> 6155163Sshin#include <sys/ioctl.h> 6255163Sshin#include <sys/sysctl.h> 6355163Sshin#include <sys/uio.h> 6455163Sshin#include <net/if.h> 6555163Sshin#include <net/if_var.h> 6662607Sitojun#define _KERNEL 1 6755163Sshin#include <net/route.h> 6862607Sitojun#undef _KERNEL 6955163Sshin#include <netinet/in.h> 7055163Sshin#include <netinet/in_var.h> 7155163Sshin#include <netinet/ip6.h> 7255163Sshin#include <netinet/udp.h> 7355163Sshin#include <netdb.h> 7462607Sitojun#include <ifaddrs.h> 7555163Sshin 7655163Sshin#include <arpa/inet.h> 7755163Sshin 7855163Sshin#include "route6d.h" 7955163Sshin 8055163Sshin#define MAXFILTER 40 8155163Sshin 8255163Sshin#ifdef DEBUG 8355163Sshin#define INIT_INTERVAL6 6 8455163Sshin#else 85119039Sume#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ 8655163Sshin#endif 8755163Sshin 8855163Sshin/* alignment constraint for routing socket */ 8962607Sitojun#define ROUNDUP(a) \ 9055163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9162607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9255163Sshin 9355163Sshin/* 9455163Sshin * Following two macros are highly depending on KAME Release 9555163Sshin */ 9655163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 9755163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 9855163Sshin 9955163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10055163Sshin do { \ 10155163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10255163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10355163Sshin } while (0) 10455163Sshin 10555163Sshinstruct ifc { /* Configuration of an interface */ 10655163Sshin char *ifc_name; /* if name */ 10755163Sshin struct ifc *ifc_next; 10855163Sshin int ifc_index; /* if index */ 10955163Sshin int ifc_mtu; /* if mtu */ 11055163Sshin int ifc_metric; /* if metric */ 11178064Sume u_int ifc_flags; /* flags */ 11278064Sume short ifc_cflags; /* IFC_XXX */ 11355163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11455163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11555163Sshin struct iff *ifc_filter; /* filter structure */ 11655163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 11755163Sshin int ifc_joined; /* joined to ff02::9 */ 11855163Sshin}; 11955163Sshin 12062607Sitojunstruct ifac { /* Adddress associated to an interface */ 12155163Sshin struct ifc *ifa_conf; /* back pointer */ 12255163Sshin struct ifac *ifa_next; 12355163Sshin struct in6_addr ifa_addr; /* address */ 12455163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12555163Sshin int ifa_plen; /* prefix length */ 12655163Sshin}; 12755163Sshin 12855163Sshinstruct iff { 12955163Sshin int iff_type; 13055163Sshin struct in6_addr iff_addr; 13155163Sshin int iff_plen; 13255163Sshin struct iff *iff_next; 13355163Sshin}; 13455163Sshin 13555163Sshinstruct ifc *ifc; 13655163Sshinint nifc; /* number of valid ifc's */ 13755163Sshinstruct ifc **index2ifc; 13855163Sshinint nindex2ifc; 13955163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 140119076Sume#ifdef HAVE_POLL_H 141119076Sumestruct pollfd set[2]; 142119076Sume#else 143119070Sumefd_set *sockvecp; /* vector to select() for receiving */ 144119070Sumefd_set *recvecp; 145119070Sumeint fdmasks; 146119070Sumeint maxfd; /* maximum fd for select() */ 147119076Sume#endif 14855163Sshinint rtsock; /* the routing socket */ 14955163Sshinint ripsock; /* socket to send/receive RIP datagram */ 15055163Sshin 15155163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 15255163Sshin 15355163Sshin/* 15478064Sume * Maintain the routes in a linked list. When the number of the routes 15555163Sshin * grows, somebody would like to introduce a hash based or a radix tree 15678064Sume * based structure. I believe the number of routes handled by RIP is 15755163Sshin * limited and I don't have to manage a complex data structure, however. 15855163Sshin * 15955163Sshin * One of the major drawbacks of the linear linked list is the difficulty 16078064Sume * of representing the relationship between a couple of routes. This may 16155163Sshin * be a significant problem when we have to support route aggregation with 16255163Sshin * supressing the specifices covered by the aggregate. 16355163Sshin */ 16455163Sshin 16555163Sshinstruct riprt { 16655163Sshin struct riprt *rrt_next; /* next destination */ 16755163Sshin struct riprt *rrt_same; /* same destination - future use */ 16855163Sshin struct netinfo6 rrt_info; /* network info */ 16955163Sshin struct in6_addr rrt_gw; /* gateway */ 17062607Sitojun u_long rrt_flags; /* kernel routing table flags */ 17162607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 17255163Sshin time_t rrt_t; /* when the route validated */ 17355163Sshin int rrt_index; /* ifindex from which this route got */ 17455163Sshin}; 17555163Sshin 17655163Sshinstruct riprt *riprt = 0; 17755163Sshin 17855163Sshinint dflag = 0; /* debug flag */ 17955163Sshinint qflag = 0; /* quiet flag */ 18055163Sshinint nflag = 0; /* don't update kernel routing table */ 18155163Sshinint aflag = 0; /* age out even the statically defined routes */ 18255163Sshinint hflag = 0; /* don't split horizon */ 18355163Sshinint lflag = 0; /* exchange site local routes */ 18455163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 18555163Sshinint Sflag = 0; /* announce static routes to every interface */ 18662607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 18755163Sshin 18855163Sshinchar *filter[MAXFILTER]; 18955163Sshinint filtertype[MAXFILTER]; 19055163Sshinint nfilter = 0; 19155163Sshin 19255163Sshinpid_t pid; 19355163Sshin 19455163Sshinstruct sockaddr_storage ripsin; 19555163Sshin 19655163Sshinint interval = 1; 19755163Sshintime_t nextalarm = 0; 19855163Sshintime_t sup_trig_update = 0; 19955163Sshin 20055163SshinFILE *rtlog = NULL; 20155163Sshin 20255163Sshinint logopened = 0; 20355163Sshin 204119085Sumestatic int seq = 0; 20555163Sshin 20678064Sumevolatile sig_atomic_t seenalrm; 20778064Sumevolatile sig_atomic_t seenquit; 20878064Sumevolatile sig_atomic_t seenusr1; 20978064Sume 21062607Sitojun#define RRTF_AGGREGATE 0x08000000 21162607Sitojun#define RRTF_NOADVERTISE 0x10000000 21262607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 21362607Sitojun#define RRTF_SENDANYWAY 0x40000000 21462607Sitojun#define RRTF_CHANGED 0x80000000 21555163Sshin 21655163Sshinint main __P((int, char **)); 21778064Sumevoid sighandler __P((int)); 21878064Sumevoid ripalarm __P((void)); 21955163Sshinvoid riprecv __P((void)); 22055163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 22178064Sumeint out_filter __P((struct riprt *, struct ifc *)); 22255163Sshinvoid init __P((void)); 22355163Sshinvoid sockopt __P((struct ifc *)); 22455163Sshinvoid ifconfig __P((void)); 22562607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 22655163Sshinvoid rtrecv __P((void)); 22755163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 22855163Sshin const struct sockaddr_in6 *)); 22955163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 23055163Sshin const struct sockaddr_in6 *)); 23155163Sshinvoid filterconfig __P((void)); 23255163Sshinint getifmtu __P((int)); 23378064Sumeconst char *rttypes __P((struct rt_msghdr *)); 23478064Sumeconst char *rtflags __P((struct rt_msghdr *)); 23578064Sumeconst char *ifflags __P((int)); 23678064Sumeint ifrt __P((struct ifc *, int)); 23762607Sitojunvoid ifrt_p2p __P((struct ifc *, int)); 23855163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 23955163Sshinvoid applyplen __P((struct in6_addr *, int)); 24055163Sshinvoid ifrtdump __P((int)); 24155163Sshinvoid ifdump __P((int)); 24255163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 24355163Sshinvoid rtdump __P((int)); 24455163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 24578064Sumevoid rtdexit __P((void)); 24678064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int, 24778064Sume struct sockaddr_in6 *)); 24855163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 24955163Sshinvoid sendrequest __P((struct ifc *)); 25078064Sumeint sin6mask2len __P((const struct sockaddr_in6 *)); 25155163Sshinint mask2len __P((const struct in6_addr *, int)); 25255163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 25355163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 25455163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 25555163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 25655163Sshinvoid krtread __P((int)); 25755163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 25855163Sshinchar *allocopy __P((char *)); 25955163Sshinchar *hms __P((void)); 26055163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 26155163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 26255163Sshinstruct in6_addr *plen2mask __P((int)); 26378064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); 26455163Sshinint ripinterval __P((int)); 26555163Sshintime_t ripsuptrig __P((void)); 26666807Skrisvoid fatal __P((const char *, ...)) 26766807Skris __attribute__((__format__(__printf__, 1, 2))); 26866807Skrisvoid trace __P((int, const char *, ...)) 26966807Skris __attribute__((__format__(__printf__, 2, 3))); 27066807Skrisvoid tracet __P((int, const char *, ...)) 27166807Skris __attribute__((__format__(__printf__, 2, 3))); 27255163Sshinunsigned int if_maxindex __P((void)); 27355163Sshinstruct ifc *ifc_find __P((char *)); 27455163Sshinstruct iff *iff_find __P((struct ifc *, int)); 27555163Sshinvoid setindex2ifc __P((int, struct ifc *)); 27655163Sshin 27755163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 27855163Sshin 27955163Sshinint 28055163Sshinmain(argc, argv) 28155163Sshin int argc; 28255163Sshin char **argv; 28355163Sshin{ 28455163Sshin int ch; 28555163Sshin int error = 0; 28655163Sshin struct ifc *ifcp; 28755163Sshin sigset_t mask, omask; 28855163Sshin FILE *pidfile; 28955163Sshin char *progname; 29062607Sitojun char *ep; 29155163Sshin 29255163Sshin progname = strrchr(*argv, '/'); 29355163Sshin if (progname) 29455163Sshin progname++; 29555163Sshin else 29655163Sshin progname = *argv; 29755163Sshin 29855163Sshin pid = getpid(); 29978064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 30055163Sshin switch (ch) { 30155163Sshin case 'A': 30255163Sshin case 'N': 30355163Sshin case 'O': 30455163Sshin case 'T': 30555163Sshin case 'L': 30662607Sitojun if (nfilter >= MAXFILTER) { 30755163Sshin fatal("Exceeds MAXFILTER"); 30862607Sitojun /*NOTREACHED*/ 30962607Sitojun } 31055163Sshin filtertype[nfilter] = ch; 31155163Sshin filter[nfilter++] = allocopy(optarg); 31255163Sshin break; 31355163Sshin case 't': 31462607Sitojun ep = NULL; 31562607Sitojun routetag = strtoul(optarg, &ep, 0); 31662607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 31755163Sshin fatal("invalid route tag"); 31855163Sshin /*NOTREACHED*/ 31955163Sshin } 32055163Sshin break; 32155163Sshin case 'R': 32262607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 32355163Sshin fatal("Can not write to routelog"); 32462607Sitojun /*NOTREACHED*/ 32562607Sitojun } 32655163Sshin break; 32762607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 32862607Sitojun FLAG('a', aflag, 1); break; 32962607Sitojun FLAG('d', dflag, 1); break; 33062607Sitojun FLAG('D', dflag, 2); break; 33162607Sitojun FLAG('h', hflag, 1); break; 33262607Sitojun FLAG('l', lflag, 1); break; 33362607Sitojun FLAG('n', nflag, 1); break; 33462607Sitojun FLAG('q', qflag, 1); break; 33562607Sitojun FLAG('s', sflag, 1); break; 33662607Sitojun FLAG('S', Sflag, 1); break; 33755163Sshin#undef FLAG 33855163Sshin default: 33955163Sshin fatal("Invalid option specified, terminating"); 34062607Sitojun /*NOTREACHED*/ 34155163Sshin } 34255163Sshin } 34355163Sshin argc -= optind; 34455163Sshin argv += optind; 34578064Sume if (argc > 0) { 34655163Sshin fatal("bogus extra arguments"); 34778064Sume /*NOTREACHED*/ 34878064Sume } 34955163Sshin 35055163Sshin if (geteuid()) { 35155163Sshin nflag = 1; 35255163Sshin fprintf(stderr, "No kernel update is allowed\n"); 35355163Sshin } 354119037Sume 355119037Sume if (dflag == 0) { 356119037Sume if (daemon(0, 0) < 0) { 357119037Sume fatal("daemon"); 358119037Sume /*NOTREACHED*/ 359119037Sume } 360119037Sume } 361119037Sume 36255163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 36355163Sshin logopened++; 36478064Sume 36578064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 36678064Sume fatal("malloc"); 36778064Sume memset(ripbuf, 0, RIP6_MAXMTU); 36878064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 36978064Sume ripbuf->rip6_vers = RIP6_VERSION; 37078064Sume ripbuf->rip6_res1[0] = 0; 37178064Sume ripbuf->rip6_res1[1] = 0; 37278064Sume 37355163Sshin init(); 37455163Sshin ifconfig(); 37555163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 37655163Sshin if (ifcp->ifc_index < 0) { 37755163Sshin fprintf(stderr, 37855163Sshin"No ifindex found at %s (no link-local address?)\n", 37955163Sshin ifcp->ifc_name); 38055163Sshin error++; 38155163Sshin } 38255163Sshin } 38355163Sshin if (error) 38455163Sshin exit(1); 38578064Sume if (loopifcp == NULL) { 38655163Sshin fatal("No loopback found"); 38778064Sume /*NOTREACHED*/ 38878064Sume } 38955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 39055163Sshin ifrt(ifcp, 0); 39155163Sshin filterconfig(); 39255163Sshin krtread(0); 39355163Sshin if (dflag) 39455163Sshin ifrtdump(0); 39555163Sshin 396122677Sume#if 1 39755163Sshin pid = getpid(); 39855163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 39955163Sshin fprintf(pidfile, "%d\n", pid); 40055163Sshin fclose(pidfile); 40155163Sshin } 402122677Sume#endif 40355163Sshin 40478064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 40555163Sshin fatal("malloc"); 40678064Sume /*NOTREACHED*/ 40778064Sume } 40862607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 40955163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 41055163Sshin ripbuf->rip6_vers = RIP6_VERSION; 41155163Sshin ripbuf->rip6_res1[0] = 0; 41255163Sshin ripbuf->rip6_res1[1] = 0; 41355163Sshin 41478064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 41578064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 41678064Sume signal(SIGTERM, sighandler) == SIG_ERR || 41778064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 41878064Sume signal(SIGHUP, sighandler) == SIG_ERR || 41978064Sume signal(SIGINT, sighandler) == SIG_ERR) { 42078064Sume fatal("signal"); 42178064Sume /*NOTREACHED*/ 42278064Sume } 42355163Sshin /* 42455163Sshin * To avoid rip packet congestion (not on a cable but in this 42555163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 42655163Sshin * packets. 42755163Sshin */ 42855163Sshin alarm(ripinterval(INIT_INTERVAL6)); 42955163Sshin 43055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 431119041Sume if (iff_find(ifcp, 'N')) 432119041Sume continue; 43355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 43455163Sshin sendrequest(ifcp); 43555163Sshin } 43655163Sshin 43755163Sshin syslog(LOG_INFO, "**** Started ****"); 43855163Sshin sigemptyset(&mask); 43955163Sshin sigaddset(&mask, SIGALRM); 44055163Sshin while (1) { 44178064Sume if (seenalrm) { 44278064Sume ripalarm(); 44378064Sume seenalrm = 0; 44478064Sume continue; 44578064Sume } 44678064Sume if (seenquit) { 44778064Sume rtdexit(); 44878064Sume seenquit = 0; 44978064Sume continue; 45078064Sume } 45178064Sume if (seenusr1) { 45278064Sume ifrtdump(SIGUSR1); 45378064Sume seenusr1 = 0; 45478064Sume continue; 45578064Sume } 45678064Sume 457119076Sume#ifdef HAVE_POLL_H 458119076Sume switch (poll(set, 2, INFTIM)) 459119076Sume#else 460119070Sume memcpy(recvecp, sockvecp, fdmasks); 461119076Sume switch (select(maxfd + 1, recvecp, 0, 0, 0)) 462119076Sume#endif 463119076Sume { 46455163Sshin case -1: 46578064Sume if (errno != EINTR) { 46678064Sume fatal("select"); 46778064Sume /*NOTREACHED*/ 46878064Sume } 46978064Sume continue; 47055163Sshin case 0: 47155163Sshin continue; 47255163Sshin default: 473119076Sume#ifdef HAVE_POLL_H 474119076Sume if (set[0].revents & POLLIN) 475119076Sume#else 476119076Sume if (FD_ISSET(ripsock, recvecp)) 477119076Sume#endif 478119076Sume { 47955163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 48055163Sshin riprecv(); 48155163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 48255163Sshin } 483119076Sume#ifdef HAVE_POLL_H 484119076Sume if (set[1].revents & POLLIN) 485119076Sume#else 486119076Sume if (FD_ISSET(rtsock, recvecp)) 487119076Sume#endif 488119076Sume { 48955163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 49055163Sshin rtrecv(); 49155163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 49255163Sshin } 49355163Sshin } 49455163Sshin } 49555163Sshin} 49655163Sshin 49778064Sumevoid 498119079Sumesighandler(signo) 499119079Sume int signo; 50078064Sume{ 50178064Sume 50278064Sume switch (signo) { 50378064Sume case SIGALRM: 50478064Sume seenalrm++; 50578064Sume break; 50678064Sume case SIGQUIT: 50778064Sume case SIGTERM: 50878064Sume seenquit++; 50978064Sume break; 51078064Sume case SIGUSR1: 51178064Sume case SIGHUP: 51278064Sume case SIGINT: 51378064Sume seenusr1++; 51478064Sume break; 51578064Sume } 51678064Sume} 51778064Sume 51855163Sshin/* 51955163Sshin * gracefully exits after resetting sockopts. 52055163Sshin */ 52155163Sshin/* ARGSUSED */ 52255163Sshinvoid 52378064Sumertdexit() 52455163Sshin{ 52555163Sshin struct riprt *rrt; 52655163Sshin 52755163Sshin alarm(0); 52855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 52962607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 53055163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 53155163Sshin } 53255163Sshin } 53355163Sshin close(ripsock); 53455163Sshin close(rtsock); 53555163Sshin syslog(LOG_INFO, "**** Terminated ****"); 53655163Sshin closelog(); 53755163Sshin exit(1); 53855163Sshin} 53955163Sshin 54055163Sshin/* 54155163Sshin * Called periodically: 54255163Sshin * 1. age out the learned route. remove it if necessary. 54355163Sshin * 2. submit RIP6_RESPONSE packets. 54478064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 54555163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 54655163Sshin * routes more precisely. 54755163Sshin */ 54855163Sshin/* ARGSUSED */ 54955163Sshinvoid 55078064Sumeripalarm() 55155163Sshin{ 55255163Sshin struct ifc *ifcp; 55355163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 55455163Sshin time_t t_lifetime, t_holddown; 55555163Sshin 55655163Sshin /* age the RIP routes */ 55755163Sshin rrt_prev = 0; 55855163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 55955163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 56055163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 56155163Sshin rrt_next = rrt->rrt_next; 56255163Sshin 56355163Sshin if (rrt->rrt_t == 0) { 56455163Sshin rrt_prev = rrt; 56555163Sshin continue; 56655163Sshin } 56755163Sshin if (rrt->rrt_t < t_holddown) { 56855163Sshin if (rrt_prev) { 56955163Sshin rrt_prev->rrt_next = rrt->rrt_next; 57055163Sshin } else { 57155163Sshin riprt = rrt->rrt_next; 57255163Sshin } 57355163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 57455163Sshin free(rrt); 57555163Sshin continue; 57655163Sshin } 57755163Sshin if (rrt->rrt_t < t_lifetime) 57855163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 57955163Sshin rrt_prev = rrt; 58055163Sshin } 58155163Sshin /* Supply updates */ 58255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 58355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 58455163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 58555163Sshin } 58655163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 58755163Sshin} 58855163Sshin 58955163Sshinvoid 59055163Sshininit() 59155163Sshin{ 592119034Sume int error; 593119034Sume const int int0 = 0, int1 = 1, int255 = 255; 59455163Sshin struct addrinfo hints, *res; 595119081Sume char port[NI_MAXSERV]; 59655163Sshin 59755163Sshin ifc = (struct ifc *)NULL; 59855163Sshin nifc = 0; 59955163Sshin nindex2ifc = 0; /*initial guess*/ 60055163Sshin index2ifc = NULL; 601119081Sume snprintf(port, sizeof(port), "%u", RIP6_PORT); 60255163Sshin 60355163Sshin memset(&hints, 0, sizeof(hints)); 60455163Sshin hints.ai_family = PF_INET6; 60555163Sshin hints.ai_socktype = SOCK_DGRAM; 606119080Sume hints.ai_protocol = IPPROTO_UDP; 60755163Sshin hints.ai_flags = AI_PASSIVE; 60855163Sshin error = getaddrinfo(NULL, port, &hints, &res); 60978064Sume if (error) { 61066807Skris fatal("%s", gai_strerror(error)); 61178064Sume /*NOTREACHED*/ 61278064Sume } 61378064Sume if (res->ai_next) { 61455163Sshin fatal(":: resolved to multiple address"); 61578064Sume /*NOTREACHED*/ 61678064Sume } 61755163Sshin 61855163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 61978064Sume if (ripsock < 0) { 62055163Sshin fatal("rip socket"); 62178064Sume /*NOTREACHED*/ 62278064Sume } 623119034Sume#ifdef IPV6_V6ONLY 624119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 625119034Sume &int1, sizeof(int1)) < 0) { 626119034Sume fatal("rip IPV6_V6ONLY"); 627119034Sume /*NOTREACHED*/ 628119034Sume } 629119034Sume#endif 63078064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 63155163Sshin fatal("rip bind"); 63278064Sume /*NOTREACHED*/ 63378064Sume } 63455163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 63578064Sume &int255, sizeof(int255)) < 0) { 63655163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 63778064Sume /*NOTREACHED*/ 63878064Sume } 63955163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 64078064Sume &int0, sizeof(int0)) < 0) { 64155163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 64278064Sume /*NOTREACHED*/ 64378064Sume } 64462921Sume 64562607Sitojun#ifdef IPV6_RECVPKTINFO 646119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 647119034Sume &int1, sizeof(int1)) < 0) { 64862607Sitojun fatal("rip IPV6_RECVPKTINFO"); 64978064Sume /*NOTREACHED*/ 65078064Sume } 65162607Sitojun#else /* old adv. API */ 652119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 653119034Sume &int1, sizeof(int1)) < 0) { 65455163Sshin fatal("rip IPV6_PKTINFO"); 65578064Sume /*NOTREACHED*/ 65678064Sume } 65762607Sitojun#endif 65855163Sshin 65955163Sshin memset(&hints, 0, sizeof(hints)); 66055163Sshin hints.ai_family = PF_INET6; 66155163Sshin hints.ai_socktype = SOCK_DGRAM; 662119080Sume hints.ai_protocol = IPPROTO_UDP; 66355163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 66478064Sume if (error) { 66566807Skris fatal("%s", gai_strerror(error)); 66678064Sume /*NOTREACHED*/ 66778064Sume } 66878064Sume if (res->ai_next) { 66955163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 67078064Sume /*NOTREACHED*/ 67178064Sume } 67255163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 67355163Sshin 674119076Sume#ifdef HAVE_POLL_H 675119076Sume set[0].fd = ripsock; 676119076Sume set[0].events = POLLIN; 677119076Sume#else 678119070Sume maxfd = ripsock; 679119076Sume#endif 68055163Sshin 68155163Sshin if (nflag == 0) { 68278064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 68355163Sshin fatal("route socket"); 68478064Sume /*NOTREACHED*/ 68578064Sume } 686119076Sume#ifdef HAVE_POLL_H 687119076Sume set[1].fd = rtsock; 688119076Sume set[1].events = POLLIN; 689119076Sume#else 690119070Sume if (rtsock > maxfd) 691119070Sume maxfd = rtsock; 692119076Sume#endif 693119076Sume } else { 694119076Sume#ifdef HAVE_POLL_H 695119076Sume set[1].fd = -1; 696119076Sume#else 69755163Sshin rtsock = -1; /*just for safety */ 698119076Sume#endif 699119076Sume } 700119070Sume 701119076Sume#ifndef HAVE_POLL_H 702119070Sume fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 703119070Sume if ((sockvecp = malloc(fdmasks)) == NULL) { 704119070Sume fatal("malloc"); 705119070Sume /*NOTREACHED*/ 706119070Sume } 707119070Sume if ((recvecp = malloc(fdmasks)) == NULL) { 708119070Sume fatal("malloc"); 709119070Sume /*NOTREACHED*/ 710119070Sume } 711119070Sume memset(sockvecp, 0, fdmasks); 712119070Sume FD_SET(ripsock, sockvecp); 713119070Sume if (rtsock >= 0) 714119070Sume FD_SET(rtsock, sockvecp); 715119076Sume#endif 71655163Sshin} 71755163Sshin 71862607Sitojun#define RIPSIZE(n) \ 71962607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 72055163Sshin 72155163Sshin/* 72255163Sshin * ripflush flushes the rip datagram stored in the rip buffer 72355163Sshin */ 72455163Sshinstatic int nrt; 72555163Sshinstatic struct netinfo6 *np; 72655163Sshin 72755163Sshinvoid 728119031Sumeripflush(ifcp, sin6) 72955163Sshin struct ifc *ifcp; 730119031Sume struct sockaddr_in6 *sin6; 73155163Sshin{ 73255163Sshin int i; 73355163Sshin int error; 73455163Sshin 73555163Sshin if (ifcp) 73655163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 73755163Sshin ifcp->ifc_name, nrt, 738119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 73955163Sshin else 74055163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 741119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 74255163Sshin if (dflag >= 2) { 74355163Sshin np = ripbuf->rip6_nets; 74455163Sshin for (i = 0; i < nrt; i++, np++) { 74555163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 74655163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 74762607Sitojun trace(2, " NextHop reset"); 74855163Sshin else { 74955163Sshin trace(2, " NextHop %s", 75055163Sshin inet6_n2p(&np->rip6_dest)); 75155163Sshin } 75255163Sshin } else { 75355163Sshin trace(2, " %s/%d[%d]", 75455163Sshin inet6_n2p(&np->rip6_dest), 75555163Sshin np->rip6_plen, np->rip6_metric); 75655163Sshin } 75755163Sshin if (np->rip6_tag) { 75855163Sshin trace(2, " tag=0x%04x", 75955163Sshin ntohs(np->rip6_tag) & 0xffff); 76055163Sshin } 76155163Sshin trace(2, "\n"); 76255163Sshin } 76355163Sshin } 764119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 76555163Sshin if (error == EAFNOSUPPORT) { 76655163Sshin /* Protocol not supported */ 76755163Sshin tracet(1, "Could not send info to %s (%s): " 76855163Sshin "set IFF_UP to 0\n", 76955163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 77055163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 77155163Sshin } 77255163Sshin nrt = 0; np = ripbuf->rip6_nets; 77355163Sshin} 77455163Sshin 77555163Sshin/* 77655163Sshin * Generate RIP6_RESPONSE packets and send them. 77755163Sshin */ 77855163Sshinvoid 779119031Sumeripsend(ifcp, sin6, flag) 78055163Sshin struct ifc *ifcp; 781119031Sume struct sockaddr_in6 *sin6; 78255163Sshin int flag; 78355163Sshin{ 78455163Sshin struct riprt *rrt; 78555163Sshin struct in6_addr *nh; /* next hop */ 78678064Sume int maxrte; 78755163Sshin 788119084Sume if (qflag) 789119084Sume return; 790119084Sume 79155163Sshin if (ifcp == NULL) { 79255163Sshin /* 79355163Sshin * Request from non-link local address is not 79455163Sshin * a regular route6d update. 79555163Sshin */ 79662607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 79762607Sitojun sizeof(struct udphdr) - 79855163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 79955163Sshin sizeof(struct netinfo6); 80055163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 80155163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 80262607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 80355163Sshin continue; 80455163Sshin /* Put the route to the buffer */ 80555163Sshin *np = rrt->rrt_info; 80655163Sshin np++; nrt++; 80755163Sshin if (nrt == maxrte) { 808119031Sume ripflush(NULL, sin6); 80955163Sshin nh = NULL; 81055163Sshin } 81155163Sshin } 81255163Sshin if (nrt) /* Send last packet */ 813119031Sume ripflush(NULL, sin6); 81455163Sshin return; 81555163Sshin } 81655163Sshin 81762607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 81855163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 81955163Sshin return; 82078064Sume 82178064Sume /* -N: no use */ 82255163Sshin if (iff_find(ifcp, 'N') != NULL) 82355163Sshin return; 82478064Sume 82578064Sume /* -T: generate default route only */ 82655163Sshin if (iff_find(ifcp, 'T') != NULL) { 82755163Sshin struct netinfo6 rrt_info; 82855163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 82955163Sshin rrt_info.rip6_dest = in6addr_any; 83055163Sshin rrt_info.rip6_plen = 0; 83155163Sshin rrt_info.rip6_metric = 1; 83278064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 83355163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 83455163Sshin np = ripbuf->rip6_nets; 83555163Sshin *np = rrt_info; 83655163Sshin nrt = 1; 837119031Sume ripflush(ifcp, sin6); 83855163Sshin return; 83955163Sshin } 84078064Sume 84162607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 84262607Sitojun sizeof(struct udphdr) - 84355163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 84455163Sshin sizeof(struct netinfo6); 84578064Sume 84655163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 84755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 84862607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 84955163Sshin continue; 85078064Sume 85178064Sume /* Need to check filter here */ 85278064Sume if (out_filter(rrt, ifcp) == 0) 85355163Sshin continue; 85478064Sume 85555163Sshin /* Check split horizon and other conditions */ 85655163Sshin if (tobeadv(rrt, ifcp) == 0) 85755163Sshin continue; 85878064Sume 85955163Sshin /* Only considers the routes with flag if specified */ 86062607Sitojun if ((flag & RRTF_CHANGED) && 86162607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 86255163Sshin continue; 86378064Sume 86455163Sshin /* Check nexthop */ 86555163Sshin if (rrt->rrt_index == ifcp->ifc_index && 86655163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 86762607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 86855163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 86955163Sshin if (nrt == maxrte - 2) 870119031Sume ripflush(ifcp, sin6); 87155163Sshin np->rip6_dest = rrt->rrt_gw; 87255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 87355163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 87455163Sshin np->rip6_plen = 0; 87555163Sshin np->rip6_tag = 0; 87655163Sshin np->rip6_metric = NEXTHOP_METRIC; 87755163Sshin nh = &rrt->rrt_gw; 87855163Sshin np++; nrt++; 87955163Sshin } 88055163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 88155163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 88262607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 88355163Sshin /* Reset nexthop */ 88455163Sshin if (nrt == maxrte - 2) 885119031Sume ripflush(ifcp, sin6); 88655163Sshin memset(np, 0, sizeof(struct netinfo6)); 88755163Sshin np->rip6_metric = NEXTHOP_METRIC; 88855163Sshin nh = NULL; 88955163Sshin np++; nrt++; 89055163Sshin } 89178064Sume 89255163Sshin /* Put the route to the buffer */ 89355163Sshin *np = rrt->rrt_info; 89455163Sshin np++; nrt++; 89555163Sshin if (nrt == maxrte) { 896119031Sume ripflush(ifcp, sin6); 89755163Sshin nh = NULL; 89855163Sshin } 89955163Sshin } 90055163Sshin if (nrt) /* Send last packet */ 901119031Sume ripflush(ifcp, sin6); 90255163Sshin} 90355163Sshin 90455163Sshin/* 90578064Sume * outbound filter logic, per-route/interface. 90678064Sume */ 90778064Sumeint 90878064Sumeout_filter(rrt, ifcp) 90978064Sume struct riprt *rrt; 91078064Sume struct ifc *ifcp; 91178064Sume{ 91278064Sume struct iff *iffp; 91378064Sume struct in6_addr ia; 91478064Sume int ok; 91578064Sume 91678064Sume /* 91778064Sume * -A: filter out less specific routes, if we have aggregated 91878064Sume * route configured. 91978064Sume */ 92078064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 92178064Sume if (iffp->iff_type != 'A') 92278064Sume continue; 92378064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 92478064Sume continue; 92578064Sume ia = rrt->rrt_info.rip6_dest; 92678064Sume applyplen(&ia, iffp->iff_plen); 92778064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 92878064Sume return 0; 92978064Sume } 93078064Sume 93178064Sume /* 93278064Sume * if it is an aggregated route, advertise it only to the 93378064Sume * interfaces specified on -A. 93478064Sume */ 93578064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 93678064Sume ok = 0; 93778064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 93878064Sume if (iffp->iff_type != 'A') 93978064Sume continue; 94078064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 94178064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 94278064Sume &iffp->iff_addr)) { 94378064Sume ok = 1; 94478064Sume break; 94578064Sume } 94678064Sume } 94778064Sume if (!ok) 94878064Sume return 0; 94978064Sume } 95078064Sume 95178064Sume /* 95278064Sume * -O: advertise only if prefix matches the configured prefix. 95378064Sume */ 95478064Sume if (iff_find(ifcp, 'O')) { 95578064Sume ok = 0; 95678064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 95778064Sume if (iffp->iff_type != 'O') 95878064Sume continue; 95978064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 96078064Sume continue; 96178064Sume ia = rrt->rrt_info.rip6_dest; 96278064Sume applyplen(&ia, iffp->iff_plen); 96378064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 96478064Sume ok = 1; 96578064Sume break; 96678064Sume } 96778064Sume } 96878064Sume if (!ok) 96978064Sume return 0; 97078064Sume } 97178064Sume 97278064Sume /* the prefix should be advertised */ 97378064Sume return 1; 97478064Sume} 97578064Sume 97678064Sume/* 97755163Sshin * Determine if the route is to be advertised on the specified interface. 97855163Sshin * It checks options specified in the arguments and the split horizon rule. 97955163Sshin */ 98055163Sshinint 98155163Sshintobeadv(rrt, ifcp) 98255163Sshin struct riprt *rrt; 98355163Sshin struct ifc *ifcp; 98455163Sshin{ 98555163Sshin 98655163Sshin /* Special care for static routes */ 98755163Sshin if (rrt->rrt_flags & RTF_STATIC) { 98862607Sitojun /* XXX don't advertise reject/blackhole routes */ 98962607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 99062607Sitojun return 0; 99162607Sitojun 99255163Sshin if (Sflag) /* Yes, advertise it anyway */ 99355163Sshin return 1; 99455163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 99555163Sshin return 1; 99655163Sshin return 0; 99755163Sshin } 99855163Sshin /* Regular split horizon */ 99955163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 100055163Sshin return 0; 100155163Sshin return 1; 100255163Sshin} 100355163Sshin 100455163Sshin/* 100555163Sshin * Send a rip packet actually. 100655163Sshin */ 100755163Sshinint 1008119031Sumesendpacket(sin6, len) 1009119031Sume struct sockaddr_in6 *sin6; 101055163Sshin int len; 101155163Sshin{ 101255163Sshin struct msghdr m; 101355163Sshin struct cmsghdr *cm; 101455163Sshin struct iovec iov[2]; 101555163Sshin u_char cmsgbuf[256]; 101655163Sshin struct in6_pktinfo *pi; 101778064Sume int idx; 101855163Sshin struct sockaddr_in6 sincopy; 101955163Sshin 102055163Sshin /* do not overwrite the given sin */ 1021119031Sume sincopy = *sin6; 1022119031Sume sin6 = &sincopy; 102355163Sshin 1024119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 1025119035Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 1026122677Sume /* XXX: do not mix the interface index and link index */ 1027119031Sume idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 1028119031Sume SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 1029122677Sume sin6->sin6_scope_id = idx; 103055163Sshin } else 103178064Sume idx = 0; 103255163Sshin 1033119031Sume m.msg_name = (caddr_t)sin6; 1034119031Sume m.msg_namelen = sizeof(*sin6); 103555163Sshin iov[0].iov_base = (caddr_t)ripbuf; 103655163Sshin iov[0].iov_len = len; 103755163Sshin m.msg_iov = iov; 103855163Sshin m.msg_iovlen = 1; 103978064Sume if (!idx) { 104055163Sshin m.msg_control = NULL; 104155163Sshin m.msg_controllen = 0; 104255163Sshin } else { 104355163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 104455163Sshin cm = (struct cmsghdr *)cmsgbuf; 104555163Sshin m.msg_control = (caddr_t)cm; 104655163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 104755163Sshin 104855163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 104955163Sshin cm->cmsg_level = IPPROTO_IPV6; 105055163Sshin cm->cmsg_type = IPV6_PKTINFO; 105155163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 105255163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 105378064Sume pi->ipi6_ifindex = idx; 105455163Sshin } 105555163Sshin 105655163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 105755163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 105855163Sshin return errno; 105955163Sshin } 106062921Sume 106155163Sshin return 0; 106255163Sshin} 106355163Sshin 106455163Sshin/* 106578064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 106655163Sshin * table if necessary. 106755163Sshin */ 106855163Sshinvoid 106955163Sshinriprecv() 107055163Sshin{ 107155163Sshin struct ifc *ifcp, *ic; 107255163Sshin struct sockaddr_in6 fsock; 107355163Sshin struct in6_addr nh; /* next hop */ 107455163Sshin struct rip6 *rp; 107555163Sshin struct netinfo6 *np, *nq; 107655163Sshin struct riprt *rrt; 1077122677Sume ssize_t len, nn; 1078122677Sume unsigned int need_trigger, idx; 107955163Sshin char buf[4 * RIP6_MAXMTU]; 108055163Sshin time_t t; 108155163Sshin struct msghdr m; 108255163Sshin struct cmsghdr *cm; 108355163Sshin struct iovec iov[2]; 108455163Sshin u_char cmsgbuf[256]; 108555163Sshin struct in6_pktinfo *pi; 108655163Sshin struct iff *iffp; 108755163Sshin struct in6_addr ia; 108855163Sshin int ok; 108978064Sume time_t t_half_lifetime; 109055163Sshin 109155163Sshin need_trigger = 0; 109262921Sume 109355163Sshin m.msg_name = (caddr_t)&fsock; 109455163Sshin m.msg_namelen = sizeof(fsock); 109555163Sshin iov[0].iov_base = (caddr_t)buf; 109655163Sshin iov[0].iov_len = sizeof(buf); 109755163Sshin m.msg_iov = iov; 109855163Sshin m.msg_iovlen = 1; 109955163Sshin cm = (struct cmsghdr *)cmsgbuf; 110055163Sshin m.msg_control = (caddr_t)cm; 110155163Sshin m.msg_controllen = sizeof(cmsgbuf); 110278064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 110355163Sshin fatal("recvmsg"); 110478064Sume /*NOTREACHED*/ 110578064Sume } 110678064Sume idx = 0; 110755163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 110855163Sshin cm; 110955163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 111078064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 111178064Sume cm->cmsg_type == IPV6_PKTINFO) { 111255163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 111378064Sume idx = pi->ipi6_ifindex; 111455163Sshin break; 111555163Sshin } 111655163Sshin } 111778064Sume if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 111878064Sume SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 111955163Sshin 1120121779Ssuz if (len < sizeof(struct rip6)) { 1121121779Ssuz trace(1, "Packet too short\n"); 1122121779Ssuz return; 1123121779Ssuz } 1124121779Ssuz 112555163Sshin nh = fsock.sin6_addr; 112655163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 112755163Sshin sizeof(struct netinfo6); 112855163Sshin rp = (struct rip6 *)buf; 112955163Sshin np = rp->rip6_nets; 113055163Sshin 1131119035Sume if (rp->rip6_vers != RIP6_VERSION) { 113255163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 113355163Sshin return; 113455163Sshin } 113555163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 113678064Sume if (idx && idx < nindex2ifc) { 113778064Sume ifcp = index2ifc[idx]; 113855163Sshin riprequest(ifcp, np, nn, &fsock); 113955163Sshin } else { 114055163Sshin riprequest(NULL, np, nn, &fsock); 114155163Sshin } 114262607Sitojun return; 114362607Sitojun } 114455163Sshin 114555163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 114655163Sshin trace(1, "Packets from non-ll addr: %s\n", 114778064Sume inet6_n2p(&fsock.sin6_addr)); 114855163Sshin return; /* Ignore packets from non-link-local addr */ 114955163Sshin } 115078064Sume idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 115178064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 115255163Sshin if (!ifcp) { 115378064Sume trace(1, "Packets to unknown interface index %d\n", idx); 115455163Sshin return; /* Ignore it */ 115555163Sshin } 115655163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 115755163Sshin return; /* The packet is from me; ignore */ 115855163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 115955163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 116062607Sitojun return; 116155163Sshin } 116278064Sume 116378064Sume /* -N: no use */ 116455163Sshin if (iff_find(ifcp, 'N') != NULL) 116555163Sshin return; 116678064Sume 116755163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 116878064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 116955163Sshin 117055163Sshin t = time(NULL); 117178064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 117255163Sshin for (; nn; nn--, np++) { 117355163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 117455163Sshin /* modify neighbor address */ 117555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 117655163Sshin nh = np->rip6_dest; 117778064Sume SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 117855163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 117955163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 118055163Sshin nh = fsock.sin6_addr; 118155163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 118255163Sshin } else { 118355163Sshin nh = fsock.sin6_addr; 118455163Sshin trace(1, "\tInvalid Nexthop: %s\n", 118578064Sume inet6_n2p(&np->rip6_dest)); 118655163Sshin } 118755163Sshin continue; 118855163Sshin } 118955163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 119055163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 119155163Sshin inet6_n2p(&np->rip6_dest), 119255163Sshin np->rip6_plen, np->rip6_metric); 119355163Sshin continue; 119455163Sshin } 119555163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 119655163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 119755163Sshin inet6_n2p(&np->rip6_dest), 119855163Sshin np->rip6_plen, np->rip6_metric); 119955163Sshin continue; 120055163Sshin } 120155163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 120255163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 120355163Sshin inet6_n2p(&np->rip6_dest), 120455163Sshin np->rip6_plen, np->rip6_metric); 120555163Sshin continue; 120655163Sshin } 120755163Sshin /* may need to pass sitelocal prefix in some case, however*/ 120855163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 120955163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 121055163Sshin inet6_n2p(&np->rip6_dest), 121155163Sshin np->rip6_plen, np->rip6_metric); 121255163Sshin continue; 121355163Sshin } 121455163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 121555163Sshin inet6_n2p(&np->rip6_dest), 121655163Sshin np->rip6_plen, np->rip6_metric); 121755163Sshin if (np->rip6_tag) 121855163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 121962607Sitojun if (dflag >= 2) { 122062607Sitojun ia = np->rip6_dest; 122162607Sitojun applyplen(&ia, np->rip6_plen); 122262607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 122362607Sitojun trace(2, " [junk outside prefix]"); 122462607Sitojun } 122555163Sshin 122678064Sume /* 122778064Sume * -L: listen only if the prefix matches the configuration 122878064Sume */ 122955163Sshin ok = 1; /* if there's no L filter, it is ok */ 123055163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 123155163Sshin if (iffp->iff_type != 'L') 123255163Sshin continue; 123355163Sshin ok = 0; 123455163Sshin if (np->rip6_plen < iffp->iff_plen) 123555163Sshin continue; 123655163Sshin /* special rule: ::/0 means default, not "in /0" */ 123755163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 123855163Sshin continue; 123962607Sitojun ia = np->rip6_dest; 124055163Sshin applyplen(&ia, iffp->iff_plen); 124155163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 124255163Sshin ok = 1; 124355163Sshin break; 124455163Sshin } 124555163Sshin } 124655163Sshin if (!ok) { 124755163Sshin trace(2, " (filtered)\n"); 124855163Sshin continue; 124955163Sshin } 125055163Sshin 125155163Sshin trace(2, "\n"); 125255163Sshin np->rip6_metric++; 125355163Sshin np->rip6_metric += ifcp->ifc_metric; 125455163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 125555163Sshin np->rip6_metric = HOPCNT_INFINITY6; 125655163Sshin 125755163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 125878064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 125955163Sshin if (rrt->rrt_t == 0) 126055163Sshin continue; /* Intf route has priority */ 126155163Sshin nq = &rrt->rrt_info; 126255163Sshin if (nq->rip6_metric > np->rip6_metric) { 126355163Sshin if (rrt->rrt_index == ifcp->ifc_index && 126455163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 126555163Sshin /* Small metric from the same gateway */ 126655163Sshin nq->rip6_metric = np->rip6_metric; 126755163Sshin } else { 126855163Sshin /* Better route found */ 126955163Sshin rrt->rrt_index = ifcp->ifc_index; 127055163Sshin /* Update routing table */ 127155163Sshin delroute(nq, &rrt->rrt_gw); 127255163Sshin rrt->rrt_gw = nh; 127355163Sshin *nq = *np; 127455163Sshin addroute(rrt, &nh, ifcp); 127555163Sshin } 127662607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 127755163Sshin rrt->rrt_t = t; 127855163Sshin need_trigger = 1; 127955163Sshin } else if (nq->rip6_metric < np->rip6_metric && 128055163Sshin rrt->rrt_index == ifcp->ifc_index && 128155163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 128255163Sshin /* Got worse route from same gw */ 128355163Sshin nq->rip6_metric = np->rip6_metric; 128455163Sshin rrt->rrt_t = t; 128562607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 128655163Sshin need_trigger = 1; 128755163Sshin } else if (nq->rip6_metric == np->rip6_metric && 128855163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 128978064Sume if (rrt->rrt_index == ifcp->ifc_index && 129078064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 129178064Sume /* same metric, same route from same gw */ 129278064Sume rrt->rrt_t = t; 129378064Sume } else if (rrt->rrt_t < t_half_lifetime) { 129478064Sume /* Better route found */ 129578064Sume rrt->rrt_index = ifcp->ifc_index; 129678064Sume /* Update routing table */ 129778064Sume delroute(nq, &rrt->rrt_gw); 129878064Sume rrt->rrt_gw = nh; 129978064Sume *nq = *np; 130078064Sume addroute(rrt, &nh, ifcp); 130178064Sume rrt->rrt_rflags |= RRTF_CHANGED; 130278064Sume rrt->rrt_t = t; 130378064Sume } 130455163Sshin } 130562607Sitojun /* 130655163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 130778064Sume * do not update age value. Do nothing. 130855163Sshin */ 130955163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 131055163Sshin /* Got a new valid route */ 131178064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 131255163Sshin fatal("malloc: struct riprt"); 131378064Sume /*NOTREACHED*/ 131478064Sume } 131562607Sitojun memset(rrt, 0, sizeof(*rrt)); 131655163Sshin nq = &rrt->rrt_info; 131755163Sshin 131855163Sshin rrt->rrt_same = NULL; 131955163Sshin rrt->rrt_index = ifcp->ifc_index; 132055163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 132155163Sshin rrt->rrt_gw = nh; 132255163Sshin *nq = *np; 132355163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 132455163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 132555163Sshin rrt->rrt_flags |= RTF_HOST; 132655163Sshin 132755163Sshin /* Put the route to the list */ 132855163Sshin rrt->rrt_next = riprt; 132955163Sshin riprt = rrt; 133055163Sshin /* Update routing table */ 133155163Sshin addroute(rrt, &nh, ifcp); 133262607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 133355163Sshin need_trigger = 1; 133455163Sshin rrt->rrt_t = t; 133555163Sshin } 133655163Sshin } 133755163Sshin /* XXX need to care the interval between triggered updates */ 133855163Sshin if (need_trigger) { 133955163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 134055163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 134155163Sshin if (ifcp->ifc_index == ic->ifc_index) 134255163Sshin continue; 134355163Sshin if (ic->ifc_flags & IFF_UP) 134455163Sshin ripsend(ic, &ic->ifc_ripsin, 134562607Sitojun RRTF_CHANGED); 134655163Sshin } 134755163Sshin } 134855163Sshin /* Reset the flag */ 134955163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 135062607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 135155163Sshin } 135255163Sshin} 135355163Sshin 135455163Sshin/* 135555163Sshin * Send all routes request packet to the specified interface. 135655163Sshin */ 135755163Sshinvoid 135855163Sshinsendrequest(ifcp) 135955163Sshin struct ifc *ifcp; 136055163Sshin{ 136155163Sshin struct netinfo6 *np; 136255163Sshin int error; 136355163Sshin 136455163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 136555163Sshin return; 136655163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 136755163Sshin np = ripbuf->rip6_nets; 136855163Sshin memset(np, 0, sizeof(struct netinfo6)); 136955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 137055163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 137155163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 137255163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 137355163Sshin if (error == EAFNOSUPPORT) { 137455163Sshin /* Protocol not supported */ 137555163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 137655163Sshin "set IFF_UP to 0\n", 137755163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 137855163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 137955163Sshin } 138055163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 138155163Sshin} 138255163Sshin 138355163Sshin/* 138455163Sshin * Process a RIP6_REQUEST packet. 138555163Sshin */ 138655163Sshinvoid 1387119031Sumeriprequest(ifcp, np, nn, sin6) 138855163Sshin struct ifc *ifcp; 138955163Sshin struct netinfo6 *np; 139055163Sshin int nn; 1391119031Sume struct sockaddr_in6 *sin6; 139255163Sshin{ 139355163Sshin int i; 139455163Sshin struct riprt *rrt; 139555163Sshin 139655163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 139755163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 139855163Sshin /* Specific response, don't split-horizon */ 139955163Sshin trace(1, "\tRIP Request\n"); 140055163Sshin for (i = 0; i < nn; i++, np++) { 140178064Sume rrt = rtsearch(np, NULL); 140255163Sshin if (rrt) 140355163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 140455163Sshin else 140555163Sshin np->rip6_metric = HOPCNT_INFINITY6; 140655163Sshin } 1407119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 140855163Sshin return; 140955163Sshin } 141055163Sshin /* Whole routing table dump */ 141155163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1412119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 141355163Sshin} 141455163Sshin 141555163Sshin/* 141655163Sshin * Get information of each interface. 141755163Sshin */ 141855163Sshinvoid 141955163Sshinifconfig() 142055163Sshin{ 142162607Sitojun struct ifaddrs *ifap, *ifa; 142262607Sitojun struct ifc *ifcp; 142362607Sitojun struct ipv6_mreq mreq; 142462607Sitojun int s; 142562607Sitojun 142678064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 142762607Sitojun fatal("socket"); 142878064Sume /*NOTREACHED*/ 142978064Sume } 143062607Sitojun 143178064Sume if (getifaddrs(&ifap) != 0) { 143262607Sitojun fatal("getifaddrs"); 143378064Sume /*NOTREACHED*/ 143478064Sume } 143562607Sitojun 143662607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 143762607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 143862607Sitojun continue; 143962607Sitojun ifcp = ifc_find(ifa->ifa_name); 144062607Sitojun /* we are interested in multicast-capable interfaces */ 144162607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 144262607Sitojun continue; 144362607Sitojun if (!ifcp) { 144462607Sitojun /* new interface */ 144578064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 144662607Sitojun fatal("malloc: struct ifc"); 144778064Sume /*NOTREACHED*/ 144878064Sume } 144962607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 145062607Sitojun ifcp->ifc_index = -1; 145162607Sitojun ifcp->ifc_next = ifc; 145262607Sitojun ifc = ifcp; 145362607Sitojun nifc++; 145462607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 145562607Sitojun ifcp->ifc_addr = 0; 145662607Sitojun ifcp->ifc_filter = 0; 145762607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 145862607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 145962607Sitojun ifflags(ifcp->ifc_flags)); 146062607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 146162607Sitojun loopifcp = ifcp; 146262607Sitojun } else { 146362607Sitojun /* update flag, this may be up again */ 146462607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 146562607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 146662607Sitojun ifflags(ifcp->ifc_flags)); 146762607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 146878064Sume ifcp->ifc_cflags |= IFC_CHANGED; 146962607Sitojun } 147062607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 147162607Sitojun } 147262607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 147362607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 147462607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 147562607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 147662607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 147778064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 147878064Sume &mreq, sizeof(mreq)) < 0) { 147962607Sitojun fatal("IPV6_JOIN_GROUP"); 148078064Sume /*NOTREACHED*/ 148178064Sume } 148262607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 148362607Sitojun ifcp->ifc_joined++; 148462607Sitojun } 148562607Sitojun } 148662607Sitojun close(s); 148762607Sitojun freeifaddrs(ifap); 148855163Sshin} 148955163Sshin 149055163Sshinvoid 149162607Sitojunifconfig1(name, sa, ifcp, s) 149262607Sitojun const char *name; 149362607Sitojun const struct sockaddr *sa; 149455163Sshin struct ifc *ifcp; 149555163Sshin int s; 149655163Sshin{ 149755163Sshin struct in6_ifreq ifr; 1498119031Sume const struct sockaddr_in6 *sin6; 149955163Sshin struct ifac *ifa; 150055163Sshin int plen; 150155163Sshin char buf[BUFSIZ]; 150255163Sshin 1503119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1504122677Sume if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) 1505122677Sume return; 1506119031Sume ifr.ifr_addr = *sin6; 1507119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 150878064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 150955163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 151078064Sume /*NOTREACHED*/ 151178064Sume } 151278064Sume plen = sin6mask2len(&ifr.ifr_addr); 1513119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 151455163Sshin /* same interface found */ 151555163Sshin /* need check if something changed */ 151655163Sshin /* XXX not yet implemented */ 151755163Sshin return; 151855163Sshin } 151955163Sshin /* 152055163Sshin * New address is found 152155163Sshin */ 152278064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 152355163Sshin fatal("malloc: struct ifac"); 152478064Sume /*NOTREACHED*/ 152578064Sume } 152662607Sitojun memset(ifa, 0, sizeof(*ifa)); 152755163Sshin ifa->ifa_conf = ifcp; 152855163Sshin ifa->ifa_next = ifcp->ifc_addr; 152955163Sshin ifcp->ifc_addr = ifa; 1530119031Sume ifa->ifa_addr = sin6->sin6_addr; 153155163Sshin ifa->ifa_plen = plen; 153255163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1533119031Sume ifr.ifr_addr = *sin6; 153478064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 153555163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 153678064Sume /*NOTREACHED*/ 153778064Sume } 153855163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 153955163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 154055163Sshin trace(1, "found address %s/%d -- %s\n", 154155163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 154255163Sshin } else { 154355163Sshin trace(1, "found address %s/%d\n", 154455163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 154555163Sshin } 154655163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 154755163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 154855163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 154955163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 155055163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 155155163Sshin ifcp->ifc_index); 155255163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 155355163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 155455163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 155555163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 155678064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 155755163Sshin fatal("ioctl: SIOCGIFMETRIC"); 155878064Sume /*NOTREACHED*/ 155978064Sume } 156055163Sshin ifcp->ifc_metric = ifr.ifr_metric; 156155163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 156255163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 156378064Sume } else 156478064Sume ifcp->ifc_cflags |= IFC_CHANGED; 156555163Sshin} 156655163Sshin 156755163Sshin/* 156855163Sshin * Receive and process routing messages. 156955163Sshin * Update interface information as necesssary. 157055163Sshin */ 157155163Sshinvoid 157255163Sshinrtrecv() 157355163Sshin{ 157455163Sshin char buf[BUFSIZ]; 157555163Sshin char *p, *q; 157655163Sshin struct rt_msghdr *rtm; 157755163Sshin struct ifa_msghdr *ifam; 157855163Sshin struct if_msghdr *ifm; 157955163Sshin int len; 158078064Sume struct ifc *ifcp, *ic; 158155163Sshin int iface = 0, rtable = 0; 158255163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 158378064Sume struct sockaddr_in6 mask; 158455163Sshin int i, addrs; 158578064Sume struct riprt *rrt; 158655163Sshin 158755163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 158855163Sshin perror("read from rtsock"); 158978064Sume exit(1); 159055163Sshin } 159155163Sshin if (len < sizeof(*rtm)) { 159269279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 159369279Sume len, (u_long)sizeof(*rtm)); 159455163Sshin return; 159555163Sshin } 1596119042Sume if (dflag >= 2) { 1597119042Sume fprintf(stderr, "rtmsg:\n"); 1598119042Sume for (i = 0; i < len; i++) { 1599119042Sume fprintf(stderr, "%02x ", buf[i] & 0xff); 1600119042Sume if (i % 16 == 15) fprintf(stderr, "\n"); 1601119042Sume } 1602119042Sume fprintf(stderr, "\n"); 1603119042Sume } 160455163Sshin 160555163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 160655163Sshin /* safety against bogus message */ 160755163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 160855163Sshin trace(1, "bogus rtmsg: length=%d\n", 160955163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 161055163Sshin break; 161155163Sshin } 161255163Sshin rtm = NULL; 161355163Sshin ifam = NULL; 161455163Sshin ifm = NULL; 161555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 161655163Sshin case RTM_NEWADDR: 161755163Sshin case RTM_DELADDR: 161855163Sshin ifam = (struct ifa_msghdr *)p; 161955163Sshin addrs = ifam->ifam_addrs; 162055163Sshin q = (char *)(ifam + 1); 162155163Sshin break; 162255163Sshin case RTM_IFINFO: 162355163Sshin ifm = (struct if_msghdr *)p; 162455163Sshin addrs = ifm->ifm_addrs; 162555163Sshin q = (char *)(ifm + 1); 162655163Sshin break; 162755163Sshin default: 162855163Sshin rtm = (struct rt_msghdr *)p; 162955163Sshin addrs = rtm->rtm_addrs; 163055163Sshin q = (char *)(rtm + 1); 163155163Sshin if (rtm->rtm_version != RTM_VERSION) { 163255163Sshin trace(1, "unexpected rtmsg version %d " 163355163Sshin "(should be %d)\n", 163455163Sshin rtm->rtm_version, RTM_VERSION); 163555163Sshin continue; 163655163Sshin } 163755163Sshin if (rtm->rtm_pid == pid) { 163855163Sshin#if 0 163955163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 164055163Sshin#endif 164155163Sshin continue; 164255163Sshin } 164355163Sshin break; 164455163Sshin } 164555163Sshin memset(&rta, 0, sizeof(rta)); 164655163Sshin for (i = 0; i < RTAX_MAX; i++) { 164755163Sshin if (addrs & (1 << i)) { 164855163Sshin rta[i] = (struct sockaddr_in6 *)q; 164955163Sshin q += ROUNDUP(rta[i]->sin6_len); 165055163Sshin } 165155163Sshin } 165255163Sshin 165355163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 165455163Sshin rttypes((struct rt_msghdr *)p), addrs); 165555163Sshin if (dflag >= 2) { 165655163Sshin for (i = 0; 165755163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 165855163Sshin i++) { 165955163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 166055163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 166155163Sshin } 166255163Sshin fprintf(stderr, "\n"); 166355163Sshin } 166455163Sshin 166555163Sshin /* 166655163Sshin * Easy ones first. 166755163Sshin * 166855163Sshin * We may be able to optimize by using ifm->ifm_index or 166955163Sshin * ifam->ifam_index. For simplicity we don't do that here. 167055163Sshin */ 167155163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 167255163Sshin case RTM_NEWADDR: 167355163Sshin case RTM_IFINFO: 167455163Sshin iface++; 167555163Sshin continue; 167655163Sshin case RTM_ADD: 167755163Sshin rtable++; 167855163Sshin continue; 167955163Sshin case RTM_LOSING: 168055163Sshin case RTM_MISS: 168155163Sshin case RTM_RESOLVE: 168255163Sshin case RTM_GET: 168355163Sshin case RTM_LOCK: 168455163Sshin /* nothing to be done here */ 168555163Sshin trace(1, "\tnothing to be done, ignored\n"); 168655163Sshin continue; 168755163Sshin } 168855163Sshin 168955163Sshin#if 0 169055163Sshin if (rta[RTAX_DST] == NULL) { 169155163Sshin trace(1, "\tno destination, ignored\n"); 169262607Sitojun continue; 169355163Sshin } 169455163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 169555163Sshin trace(1, "\taf mismatch, ignored\n"); 169655163Sshin continue; 169755163Sshin } 169855163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 169955163Sshin trace(1, "\tlinklocal destination, ignored\n"); 170055163Sshin continue; 170155163Sshin } 170255163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 170355163Sshin trace(1, "\tloopback destination, ignored\n"); 170455163Sshin continue; /* Loopback */ 170555163Sshin } 170655163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 170755163Sshin trace(1, "\tmulticast destination, ignored\n"); 170855163Sshin continue; 170955163Sshin } 171055163Sshin#endif 171155163Sshin 171255163Sshin /* hard ones */ 171355163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 171455163Sshin case RTM_NEWADDR: 171555163Sshin case RTM_IFINFO: 171655163Sshin case RTM_ADD: 171755163Sshin case RTM_LOSING: 171855163Sshin case RTM_MISS: 171955163Sshin case RTM_RESOLVE: 172055163Sshin case RTM_GET: 172155163Sshin case RTM_LOCK: 172255163Sshin /* should already be handled */ 172355163Sshin fatal("rtrecv: never reach here"); 172478064Sume /*NOTREACHED*/ 172555163Sshin case RTM_DELETE: 172678064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 172778064Sume trace(1, "\tsome of dst/gw/netamsk are " 172878064Sume "unavailable, ignored\n"); 172955163Sshin break; 173055163Sshin } 173178064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 173278064Sume mask.sin6_len = sizeof(mask); 173378064Sume memset(&mask.sin6_addr, 0xff, 173478064Sume sizeof(mask.sin6_addr)); 173578064Sume rta[RTAX_NETMASK] = &mask; 173678064Sume } else if (!rta[RTAX_NETMASK]) { 173778064Sume trace(1, "\tsome of dst/gw/netamsk are " 173878064Sume "unavailable, ignored\n"); 173978064Sume break; 174078064Sume } 174178064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 174278064Sume rta[RTAX_NETMASK]) == 0) { 174355163Sshin rtable++; /*just to be sure*/ 174455163Sshin } 174555163Sshin break; 174655163Sshin case RTM_CHANGE: 174755163Sshin case RTM_REDIRECT: 174855163Sshin trace(1, "\tnot supported yet, ignored\n"); 174955163Sshin break; 175055163Sshin case RTM_DELADDR: 175155163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 175255163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 175355163Sshin break; 175455163Sshin } 175555163Sshin if (ifam->ifam_index < nindex2ifc) 175655163Sshin ifcp = index2ifc[ifam->ifam_index]; 175755163Sshin else 175855163Sshin ifcp = NULL; 175955163Sshin if (!ifcp) { 176055163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 176155163Sshin ifam->ifam_index); 176255163Sshin break; 176355163Sshin } 176478064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 176578064Sume iface++; 176655163Sshin break; 176755163Sshin case RTM_OLDADD: 176855163Sshin case RTM_OLDDEL: 176955163Sshin trace(1, "\tnot supported yet, ignored\n"); 177055163Sshin break; 177155163Sshin } 177255163Sshin 177355163Sshin } 177455163Sshin 177555163Sshin if (iface) { 177655163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 177755163Sshin ifconfig(); 177855163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 177978064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 178078064Sume if (ifrt(ifcp, 1)) { 178178064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 178278064Sume if (ifcp->ifc_index == ic->ifc_index) 178378064Sume continue; 178478064Sume if (ic->ifc_flags & IFF_UP) 178578064Sume ripsend(ic, &ic->ifc_ripsin, 178678064Sume RRTF_CHANGED); 178778064Sume } 178878064Sume /* Reset the flag */ 178978064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 179078064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 179178064Sume } 179278064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 179378064Sume } 179455163Sshin } 179555163Sshin if (rtable) { 179655163Sshin trace(1, "rtsock: read routing table again\n"); 179755163Sshin krtread(1); 179855163Sshin } 179955163Sshin} 180055163Sshin 180155163Sshin/* 180255163Sshin * remove specified route from the internal routing table. 180355163Sshin */ 180455163Sshinint 180555163Sshinrt_del(sdst, sgw, smask) 180655163Sshin const struct sockaddr_in6 *sdst; 180755163Sshin const struct sockaddr_in6 *sgw; 180855163Sshin const struct sockaddr_in6 *smask; 180955163Sshin{ 181055163Sshin const struct in6_addr *dst = NULL; 181155163Sshin const struct in6_addr *gw = NULL; 181255163Sshin int prefix; 181355163Sshin struct netinfo6 ni6; 181455163Sshin struct riprt *rrt = NULL; 181555163Sshin time_t t_lifetime; 181655163Sshin 181755163Sshin if (sdst->sin6_family != AF_INET6) { 181855163Sshin trace(1, "\tother AF, ignored\n"); 181955163Sshin return -1; 182055163Sshin } 182155163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 182255163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 182355163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 182455163Sshin trace(1, "\taddress %s not interesting, ignored\n", 182555163Sshin inet6_n2p(&sdst->sin6_addr)); 182655163Sshin return -1; 182755163Sshin } 182855163Sshin dst = &sdst->sin6_addr; 182978064Sume if (sgw->sin6_family == AF_INET6) { 183055163Sshin /* easy case */ 183155163Sshin gw = &sgw->sin6_addr; 183278064Sume prefix = sin6mask2len(smask); 183355163Sshin } else if (sgw->sin6_family == AF_LINK) { 183455163Sshin /* 183555163Sshin * Interface route... a hard case. We need to get the prefix 183655163Sshin * length from the kernel, but we now are parsing rtmsg. 183755163Sshin * We'll purge matching routes from my list, then get the 183855163Sshin * fresh list. 183955163Sshin */ 184055163Sshin struct riprt *longest; 1841108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 184255163Sshin inet6_n2p(dst)); 184355163Sshin longest = NULL; 184455163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 184555163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 184655163Sshin &sdst->sin6_addr) 184755163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 184855163Sshin if (!longest 184955163Sshin || longest->rrt_info.rip6_plen < 185055163Sshin rrt->rrt_info.rip6_plen) { 185155163Sshin longest = rrt; 185255163Sshin } 185355163Sshin } 185455163Sshin } 185555163Sshin rrt = longest; 185655163Sshin if (!rrt) { 185755163Sshin trace(1, "\tno matching interface route found\n"); 185855163Sshin return -1; 185955163Sshin } 186055163Sshin gw = &in6addr_loopback; 186155163Sshin prefix = rrt->rrt_info.rip6_plen; 186255163Sshin } else { 186378064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 186455163Sshin return -1; 186555163Sshin } 186655163Sshin 186755163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 186855163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 186955163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 187055163Sshin /* age route for interface address */ 187155163Sshin memset(&ni6, 0, sizeof(ni6)); 187255163Sshin ni6.rip6_dest = *dst; 187355163Sshin ni6.rip6_plen = prefix; 187455163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 187555163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 187655163Sshin ni6.rip6_plen); 187778064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 187855163Sshin trace(1, "\tno route found\n"); 187955163Sshin return -1; 188055163Sshin } 188178064Sume#if 0 188255163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 188355163Sshin trace(1, "\tyou can delete static routes only\n"); 188478064Sume } else 188578064Sume#endif 188678064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 188755163Sshin trace(1, "\tgw mismatch: %s <-> ", 188855163Sshin inet6_n2p(&rrt->rrt_gw)); 188955163Sshin trace(1, "%s\n", inet6_n2p(gw)); 189055163Sshin } else { 189155163Sshin trace(1, "\troute found, age it\n"); 189255163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 189355163Sshin rrt->rrt_t = t_lifetime; 189455163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 189555163Sshin } 189655163Sshin } 189755163Sshin return 0; 189855163Sshin} 189955163Sshin 190055163Sshin/* 190155163Sshin * remove specified address from internal interface/routing table. 190255163Sshin */ 190355163Sshinint 190455163Sshinrt_deladdr(ifcp, sifa, smask) 190555163Sshin struct ifc *ifcp; 190655163Sshin const struct sockaddr_in6 *sifa; 190755163Sshin const struct sockaddr_in6 *smask; 190855163Sshin{ 190955163Sshin const struct in6_addr *addr = NULL; 191055163Sshin int prefix; 191155163Sshin struct ifac *ifa = NULL; 191255163Sshin struct netinfo6 ni6; 191355163Sshin struct riprt *rrt = NULL; 191455163Sshin time_t t_lifetime; 191555163Sshin int updated = 0; 191655163Sshin 191778064Sume if (sifa->sin6_family != AF_INET6) { 191855163Sshin trace(1, "\tother AF, ignored\n"); 191955163Sshin return -1; 192055163Sshin } 192155163Sshin addr = &sifa->sin6_addr; 192278064Sume prefix = sin6mask2len(smask); 192355163Sshin 192455163Sshin trace(1, "\tdeleting %s/%d from %s\n", 192555163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 192655163Sshin ifa = ifa_match(ifcp, addr, prefix); 192755163Sshin if (!ifa) { 192855163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 192955163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 193055163Sshin return -1; 193155163Sshin } 193255163Sshin if (ifa->ifa_conf != ifcp) { 193355163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 193455163Sshin "(%s != %s)\n", 193555163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 193655163Sshin return -1; 193755163Sshin } 193855163Sshin /* remove ifa from interface */ 193955163Sshin if (ifcp->ifc_addr == ifa) 194055163Sshin ifcp->ifc_addr = ifa->ifa_next; 194155163Sshin else { 194255163Sshin struct ifac *p; 194355163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 194455163Sshin if (p->ifa_next == ifa) { 194555163Sshin p->ifa_next = ifa->ifa_next; 194655163Sshin break; 194755163Sshin } 194855163Sshin } 194955163Sshin } 195055163Sshin ifa->ifa_next = NULL; 195155163Sshin ifa->ifa_conf = NULL; 195255163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 195355163Sshin /* age route for interface address */ 195455163Sshin memset(&ni6, 0, sizeof(ni6)); 195555163Sshin ni6.rip6_dest = ifa->ifa_addr; 195655163Sshin ni6.rip6_plen = ifa->ifa_plen; 195755163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 195855163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 195955163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 196078064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 196155163Sshin struct in6_addr none; 196255163Sshin memset(&none, 0, sizeof(none)); 196378064Sume if (rrt->rrt_index == ifcp->ifc_index && 196478064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 196578064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 196655163Sshin trace(1, "\troute found, age it\n"); 196755163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 196855163Sshin rrt->rrt_t = t_lifetime; 196955163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 197055163Sshin } 197155163Sshin updated++; 197255163Sshin } else { 197355163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 197455163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 197555163Sshin rrt->rrt_info.rip6_plen, 197655163Sshin rrt->rrt_index); 197755163Sshin } 197855163Sshin } else 197955163Sshin trace(1, "\tno interface route found\n"); 198055163Sshin /* age route for p2p destination */ 198155163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 198255163Sshin memset(&ni6, 0, sizeof(ni6)); 198355163Sshin ni6.rip6_dest = ifa->ifa_raddr; 198455163Sshin ni6.rip6_plen = 128; 198555163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 198655163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 198755163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 198855163Sshin ifcp->ifc_index); 198978064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 199078064Sume if (rrt->rrt_index == ifcp->ifc_index && 199178064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 199255163Sshin trace(1, "\troute found, age it\n"); 199355163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 199455163Sshin rrt->rrt_t = t_lifetime; 199555163Sshin rrt->rrt_info.rip6_metric = 199678064Sume HOPCNT_INFINITY6; 199755163Sshin updated++; 199855163Sshin } 199955163Sshin } else { 200055163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 200155163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 200255163Sshin rrt->rrt_info.rip6_plen, 200355163Sshin rrt->rrt_index); 200455163Sshin } 200555163Sshin } else 200655163Sshin trace(1, "\tno p2p route found\n"); 200755163Sshin } 200855163Sshin return updated ? 0 : -1; 200955163Sshin} 201055163Sshin 201155163Sshin/* 201255163Sshin * Get each interface address and put those interface routes to the route 201355163Sshin * list. 201455163Sshin */ 201578064Sumeint 201655163Sshinifrt(ifcp, again) 201762607Sitojun struct ifc *ifcp; 201855163Sshin int again; 201955163Sshin{ 202062607Sitojun struct ifac *ifa; 2021119042Sume struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; 202262607Sitojun struct netinfo6 *np; 202378064Sume time_t t_lifetime; 202478064Sume int need_trigger = 0; 202555163Sshin 2026122677Sume#if 0 202755163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 202878064Sume return 0; /* ignore loopback */ 2029122677Sume#endif 2030122677Sume 203162607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 203262607Sitojun ifrt_p2p(ifcp, again); 203378064Sume return 0; 203462607Sitojun } 203562607Sitojun 203655163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 203762607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 203862607Sitojun#if 0 203962607Sitojun trace(1, "route: %s on %s: " 204062607Sitojun "skip linklocal interface address\n", 204162607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 204262607Sitojun#endif 204362607Sitojun continue; 204462607Sitojun } 204562607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 204662607Sitojun#if 0 204762607Sitojun trace(1, "route: %s: skip unspec interface address\n", 204862607Sitojun ifcp->ifc_name); 204962607Sitojun#endif 205062607Sitojun continue; 205162607Sitojun } 2052122677Sume if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) { 2053122677Sume#if 0 2054122677Sume trace(1, "route: %s: skip loopback address\n", 2055122677Sume ifcp->ifc_name); 2056122677Sume#endif 2057122677Sume continue; 2058122677Sume } 205978064Sume if (ifcp->ifc_flags & IFF_UP) { 206078064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 206178064Sume fatal("malloc: struct riprt"); 206278064Sume memset(rrt, 0, sizeof(*rrt)); 206378064Sume rrt->rrt_same = NULL; 206478064Sume rrt->rrt_index = ifcp->ifc_index; 206578064Sume rrt->rrt_t = 0; /* don't age */ 206678064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 206778064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 206878064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 206978064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 2070122677Sume if (ifa->ifa_plen == 128) 2071122677Sume rrt->rrt_flags = RTF_HOST; 2072122677Sume else 2073122677Sume rrt->rrt_flags = RTF_CLONING; 207478064Sume rrt->rrt_rflags |= RRTF_CHANGED; 207578064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 207678064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 207778064Sume rrt->rrt_gw = ifa->ifa_addr; 207878064Sume np = &rrt->rrt_info; 207978064Sume search_rrt = rtsearch(np, &prev_rrt); 208078064Sume if (search_rrt != NULL) { 2081119042Sume if (search_rrt->rrt_info.rip6_metric <= 208278064Sume rrt->rrt_info.rip6_metric) { 208378064Sume /* Already have better route */ 208478064Sume if (!again) { 208578064Sume trace(1, "route: %s/%d: " 208678064Sume "already registered (%s)\n", 208778064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 208878064Sume ifcp->ifc_name); 208978064Sume } 2090119042Sume goto next; 209178064Sume } 2092119042Sume 2093119042Sume if (prev_rrt) 2094119042Sume prev_rrt->rrt_next = rrt->rrt_next; 2095119042Sume else 2096119042Sume riprt = rrt->rrt_next; 2097119042Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 209878064Sume } 209955163Sshin /* Attach the route to the list */ 210062607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 210162607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 210262607Sitojun ifcp->ifc_name); 210355163Sshin rrt->rrt_next = riprt; 210455163Sshin riprt = rrt; 210578064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 2106119042Sume rrt = NULL; 210778064Sume sendrequest(ifcp); 210878064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 210978064Sume need_trigger = 1; 211055163Sshin } else { 211178064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 211278064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 211378064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 211478064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 211578064Sume loop_rrt->rrt_t = t_lifetime; 211678064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 211778064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 211878064Sume need_trigger = 1; 211978064Sume } 212078064Sume } 212155163Sshin } 212278064Sume } 2123119042Sume next: 2124119042Sume if (rrt) 2125119042Sume free(rrt); 212662607Sitojun } 212778064Sume return need_trigger; 212862607Sitojun} 212955163Sshin 213062607Sitojun/* 213162607Sitojun * there are couple of p2p interface routing models. "behavior" lets 213262607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2133119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 213462607Sitojun */ 213562607Sitojunvoid 213662607Sitojunifrt_p2p(ifcp, again) 213762607Sitojun struct ifc *ifcp; 213862607Sitojun int again; 213962607Sitojun{ 214062607Sitojun struct ifac *ifa; 214178064Sume struct riprt *rrt, *orrt, *prevrrt; 214262607Sitojun struct netinfo6 *np; 214362607Sitojun struct in6_addr addr, dest; 214462607Sitojun int advert, ignore, i; 214562607Sitojun#define P2PADVERT_NETWORK 1 214662607Sitojun#define P2PADVERT_ADDR 2 214762607Sitojun#define P2PADVERT_DEST 4 214862607Sitojun#define P2PADVERT_MAX 4 214962607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 215078064Sume const char *category = ""; 215162607Sitojun const char *noadv; 215262607Sitojun 215362607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 215462607Sitojun addr = ifa->ifa_addr; 215562607Sitojun dest = ifa->ifa_raddr; 215662607Sitojun applyplen(&addr, ifa->ifa_plen); 215762607Sitojun applyplen(&dest, ifa->ifa_plen); 215862607Sitojun advert = ignore = 0; 215962607Sitojun switch (behavior) { 216062607Sitojun case CISCO: 216162607Sitojun /* 216262607Sitojun * honor addr/plen, just like normal shared medium 216362607Sitojun * interface. this may cause trouble if you reuse 216462607Sitojun * addr/plen on other interfaces. 216562607Sitojun * 216662607Sitojun * advertise addr/plen. 216762607Sitojun */ 216862607Sitojun advert |= P2PADVERT_NETWORK; 216962607Sitojun break; 217062607Sitojun case GATED: 217162607Sitojun /* 217262607Sitojun * prefixlen on p2p interface is meaningless. 217362607Sitojun * advertise addr/128 and dest/128. 217462607Sitojun * 217562607Sitojun * do not install network route to route6d routing 217662607Sitojun * table (if we do, it would prevent route installation 217762607Sitojun * for other p2p interface that shares addr/plen). 217878064Sume * 217978064Sume * XXX what should we do if dest is ::? it will not 218078064Sume * get announced anyways (see following filter), 218178064Sume * but we need to think. 218262607Sitojun */ 218362607Sitojun advert |= P2PADVERT_ADDR; 218462607Sitojun advert |= P2PADVERT_DEST; 218562607Sitojun ignore |= P2PADVERT_NETWORK; 218662607Sitojun break; 218762607Sitojun case ROUTE6D: 218862607Sitojun /* 218978064Sume * just for testing. actually the code is redundant 219078064Sume * given the current p2p interface address assignment 219178064Sume * rule for kame kernel. 219278064Sume * 219378064Sume * intent: 219478064Sume * A/n -> announce A/n 219578064Sume * A B/n, A and B share prefix -> A/n (= B/n) 219678064Sume * A B/n, do not share prefix -> A/128 and B/128 219778064Sume * actually, A/64 and A B/128 are the only cases 219878064Sume * permitted by the kernel: 219978064Sume * A/64 -> A/64 220078064Sume * A B/128 -> A/128 and B/128 220162607Sitojun */ 220278064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 220378064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 220478064Sume advert |= P2PADVERT_NETWORK; 220578064Sume else { 220678064Sume advert |= P2PADVERT_ADDR; 220778064Sume advert |= P2PADVERT_DEST; 220878064Sume ignore |= P2PADVERT_NETWORK; 220978064Sume } 221078064Sume } else 221162607Sitojun advert |= P2PADVERT_NETWORK; 221262607Sitojun break; 221362607Sitojun } 221462607Sitojun 221562607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 221662607Sitojun if ((ignore & i) != 0) 221762607Sitojun continue; 221878064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 221955163Sshin fatal("malloc: struct riprt"); 222078064Sume /*NOTREACHED*/ 222178064Sume } 222262607Sitojun memset(rrt, 0, sizeof(*rrt)); 222355163Sshin rrt->rrt_same = NULL; 222455163Sshin rrt->rrt_index = ifcp->ifc_index; 222562607Sitojun rrt->rrt_t = 0; /* don't age */ 222662607Sitojun switch (i) { 222762607Sitojun case P2PADVERT_NETWORK: 222862607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 222962607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 223062607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 223162607Sitojun ifa->ifa_plen); 223262607Sitojun category = "network"; 223362607Sitojun break; 223462607Sitojun case P2PADVERT_ADDR: 223562607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 223662607Sitojun rrt->rrt_info.rip6_plen = 128; 223778064Sume rrt->rrt_gw = in6addr_loopback; 223862607Sitojun category = "addr"; 223962607Sitojun break; 224062607Sitojun case P2PADVERT_DEST: 224162607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 224262607Sitojun rrt->rrt_info.rip6_plen = 128; 224378064Sume rrt->rrt_gw = ifa->ifa_addr; 224462607Sitojun category = "dest"; 224562607Sitojun break; 224662607Sitojun } 224762607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 224862607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 224962607Sitojun#if 0 225062607Sitojun trace(1, "route: %s: skip unspec/linklocal " 225162607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 225262607Sitojun#endif 225362607Sitojun free(rrt); 225462607Sitojun continue; 225562607Sitojun } 225662607Sitojun if ((advert & i) == 0) { 225762607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 225862607Sitojun noadv = ", NO-ADV"; 225962607Sitojun } else 226062607Sitojun noadv = ""; 226155163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 226262607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 226355163Sshin np = &rrt->rrt_info; 226478064Sume orrt = rtsearch(np, &prevrrt); 226578064Sume if (!orrt) { 226655163Sshin /* Attach the route to the list */ 226762607Sitojun trace(1, "route: %s/%d: register route " 226862607Sitojun "(%s on %s%s)\n", 226962607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 227062607Sitojun category, ifcp->ifc_name, noadv); 227155163Sshin rrt->rrt_next = riprt; 227255163Sshin riprt = rrt; 227378064Sume } else if (rrt->rrt_index != orrt->rrt_index || 227478064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 227578064Sume /* swap route */ 227678064Sume rrt->rrt_next = orrt->rrt_next; 227778064Sume if (prevrrt) 227878064Sume prevrrt->rrt_next = rrt; 227978064Sume else 228078064Sume riprt = rrt; 228178064Sume free(orrt); 228278064Sume 228378064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 228478064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 228578064Sume category, ifcp->ifc_name, noadv); 228655163Sshin } else { 228755163Sshin /* Already found */ 228855163Sshin if (!again) { 228962607Sitojun trace(1, "route: %s/%d: " 229062607Sitojun "already registered (%s on %s%s)\n", 229162607Sitojun inet6_n2p(&np->rip6_dest), 229262607Sitojun np->rip6_plen, category, 229362607Sitojun ifcp->ifc_name, noadv); 229455163Sshin } 229555163Sshin free(rrt); 229655163Sshin } 229755163Sshin } 229855163Sshin } 229962607Sitojun#undef P2PADVERT_NETWORK 230062607Sitojun#undef P2PADVERT_ADDR 230162607Sitojun#undef P2PADVERT_DEST 230262607Sitojun#undef P2PADVERT_MAX 230355163Sshin} 230455163Sshin 230555163Sshinint 230655163Sshingetifmtu(ifindex) 230755163Sshin int ifindex; 230855163Sshin{ 230955163Sshin int mib[6]; 231055163Sshin char *buf; 231155163Sshin size_t msize; 231255163Sshin struct if_msghdr *ifm; 231355163Sshin int mtu; 231455163Sshin 231555163Sshin mib[0] = CTL_NET; 231655163Sshin mib[1] = PF_ROUTE; 231755163Sshin mib[2] = 0; 231855163Sshin mib[3] = AF_INET6; 231955163Sshin mib[4] = NET_RT_IFLIST; 232055163Sshin mib[5] = ifindex; 232178064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 232255163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 232378064Sume /*NOTREACHED*/ 232478064Sume } 232578064Sume if ((buf = malloc(msize)) == NULL) { 232655163Sshin fatal("malloc"); 232778064Sume /*NOTREACHED*/ 232878064Sume } 232978064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 233055163Sshin fatal("sysctl NET_RT_IFLIST"); 233178064Sume /*NOTREACHED*/ 233278064Sume } 233355163Sshin ifm = (struct if_msghdr *)buf; 233455163Sshin mtu = ifm->ifm_data.ifi_mtu; 233578064Sume if (ifindex != ifm->ifm_index) { 233655163Sshin fatal("ifindex does not match with ifm_index"); 233778064Sume /*NOTREACHED*/ 233878064Sume } 233955163Sshin free(buf); 234055163Sshin return mtu; 234155163Sshin} 234255163Sshin 234355163Sshinconst char * 234455163Sshinrttypes(rtm) 234555163Sshin struct rt_msghdr *rtm; 234655163Sshin{ 234762607Sitojun#define RTTYPE(s, f) \ 234862607Sitojundo { \ 234962607Sitojun if (rtm->rtm_type == (f)) \ 235062607Sitojun return (s); \ 235162607Sitojun} while (0) 235255163Sshin RTTYPE("ADD", RTM_ADD); 235355163Sshin RTTYPE("DELETE", RTM_DELETE); 235455163Sshin RTTYPE("CHANGE", RTM_CHANGE); 235555163Sshin RTTYPE("GET", RTM_GET); 235655163Sshin RTTYPE("LOSING", RTM_LOSING); 235755163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 235855163Sshin RTTYPE("MISS", RTM_MISS); 235955163Sshin RTTYPE("LOCK", RTM_LOCK); 236055163Sshin RTTYPE("OLDADD", RTM_OLDADD); 236155163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 236255163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 236355163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 236455163Sshin RTTYPE("DELADDR", RTM_DELADDR); 236555163Sshin RTTYPE("IFINFO", RTM_IFINFO); 236678064Sume#ifdef RTM_OLDADD 236778064Sume RTTYPE("OLDADD", RTM_OLDADD); 236878064Sume#endif 236978064Sume#ifdef RTM_OLDDEL 237078064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 237178064Sume#endif 237278064Sume#ifdef RTM_OIFINFO 237378064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 237478064Sume#endif 237578064Sume#ifdef RTM_IFANNOUNCE 237678064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 237778064Sume#endif 237878064Sume#ifdef RTM_NEWMADDR 237978064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 238078064Sume#endif 238178064Sume#ifdef RTM_DELMADDR 238278064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 238378064Sume#endif 238455163Sshin#undef RTTYPE 238555163Sshin return NULL; 238655163Sshin} 238755163Sshin 238855163Sshinconst char * 238955163Sshinrtflags(rtm) 239055163Sshin struct rt_msghdr *rtm; 239155163Sshin{ 239255163Sshin static char buf[BUFSIZ]; 239355163Sshin 239478064Sume /* 239578064Sume * letter conflict should be okay. painful when *BSD diverges... 239678064Sume */ 239778064Sume strlcpy(buf, "", sizeof(buf)); 239862607Sitojun#define RTFLAG(s, f) \ 239962607Sitojundo { \ 240062607Sitojun if (rtm->rtm_flags & (f)) \ 240178064Sume strlcat(buf, (s), sizeof(buf)); \ 240262607Sitojun} while (0) 240355163Sshin RTFLAG("U", RTF_UP); 240455163Sshin RTFLAG("G", RTF_GATEWAY); 240555163Sshin RTFLAG("H", RTF_HOST); 240655163Sshin RTFLAG("R", RTF_REJECT); 240755163Sshin RTFLAG("D", RTF_DYNAMIC); 240855163Sshin RTFLAG("M", RTF_MODIFIED); 240955163Sshin RTFLAG("d", RTF_DONE); 241055163Sshin#ifdef RTF_MASK 241155163Sshin RTFLAG("m", RTF_MASK); 241255163Sshin#endif 241355163Sshin RTFLAG("C", RTF_CLONING); 241478064Sume#ifdef RTF_CLONED 241578064Sume RTFLAG("c", RTF_CLONED); 241678064Sume#endif 241778064Sume#ifdef RTF_PRCLONING 241878064Sume RTFLAG("c", RTF_PRCLONING); 241978064Sume#endif 242078064Sume#ifdef RTF_WASCLONED 242178064Sume RTFLAG("W", RTF_WASCLONED); 242278064Sume#endif 242355163Sshin RTFLAG("X", RTF_XRESOLVE); 242455163Sshin RTFLAG("L", RTF_LLINFO); 242555163Sshin RTFLAG("S", RTF_STATIC); 242655163Sshin RTFLAG("B", RTF_BLACKHOLE); 242778064Sume#ifdef RTF_PROTO3 242878064Sume RTFLAG("3", RTF_PROTO3); 242978064Sume#endif 243055163Sshin RTFLAG("2", RTF_PROTO2); 243155163Sshin RTFLAG("1", RTF_PROTO1); 243278064Sume#ifdef RTF_BROADCAST 243378064Sume RTFLAG("b", RTF_BROADCAST); 243478064Sume#endif 243578064Sume#ifdef RTF_DEFAULT 243678064Sume RTFLAG("d", RTF_DEFAULT); 243778064Sume#endif 243878064Sume#ifdef RTF_ISAROUTER 243978064Sume RTFLAG("r", RTF_ISAROUTER); 244078064Sume#endif 244178064Sume#ifdef RTF_TUNNEL 244278064Sume RTFLAG("T", RTF_TUNNEL); 244378064Sume#endif 244478064Sume#ifdef RTF_AUTH 244578064Sume RTFLAG("A", RTF_AUTH); 244678064Sume#endif 244778064Sume#ifdef RTF_CRYPT 244878064Sume RTFLAG("E", RTF_CRYPT); 244978064Sume#endif 245055163Sshin#undef RTFLAG 245155163Sshin return buf; 245255163Sshin} 245355163Sshin 245455163Sshinconst char * 245555163Sshinifflags(flags) 245655163Sshin int flags; 245755163Sshin{ 245855163Sshin static char buf[BUFSIZ]; 245955163Sshin 246078064Sume strlcpy(buf, "", sizeof(buf)); 246162607Sitojun#define IFFLAG(s, f) \ 246262607Sitojundo { \ 2463119040Sume if (flags & (f)) { \ 246462607Sitojun if (buf[0]) \ 246578064Sume strlcat(buf, ",", sizeof(buf)); \ 2466119040Sume strlcat(buf, (s), sizeof(buf)); \ 246762607Sitojun } \ 246862607Sitojun} while (0) 246955163Sshin IFFLAG("UP", IFF_UP); 247055163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 247155163Sshin IFFLAG("DEBUG", IFF_DEBUG); 247255163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 247355163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 247455163Sshin#ifdef IFF_NOTRAILERS 247555163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 247655163Sshin#endif 247778064Sume#ifdef IFF_SMART 247878064Sume IFFLAG("SMART", IFF_SMART); 247978064Sume#endif 248055163Sshin IFFLAG("RUNNING", IFF_RUNNING); 248155163Sshin IFFLAG("NOARP", IFF_NOARP); 248255163Sshin IFFLAG("PROMISC", IFF_PROMISC); 248355163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 248455163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 248555163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 248655163Sshin IFFLAG("LINK0", IFF_LINK0); 248755163Sshin IFFLAG("LINK1", IFF_LINK1); 248855163Sshin IFFLAG("LINK2", IFF_LINK2); 248955163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 249055163Sshin#undef IFFLAG 249155163Sshin return buf; 249255163Sshin} 249355163Sshin 249455163Sshinvoid 249555163Sshinkrtread(again) 249655163Sshin int again; 249755163Sshin{ 249855163Sshin int mib[6]; 249955163Sshin size_t msize; 250055163Sshin char *buf, *p, *lim; 250155163Sshin struct rt_msghdr *rtm; 250255163Sshin int retry; 250355163Sshin const char *errmsg; 250455163Sshin 250555163Sshin retry = 0; 250655163Sshin buf = NULL; 250755163Sshin mib[0] = CTL_NET; 250855163Sshin mib[1] = PF_ROUTE; 250955163Sshin mib[2] = 0; 251055163Sshin mib[3] = AF_INET6; /* Address family */ 251155163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 251255163Sshin mib[5] = 0; /* No flags */ 251355163Sshin do { 251455163Sshin retry++; 251555163Sshin errmsg = NULL; 251655163Sshin if (buf) 251755163Sshin free(buf); 251855163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 251955163Sshin errmsg = "sysctl estimate"; 252055163Sshin continue; 252155163Sshin } 252255163Sshin if ((buf = malloc(msize)) == NULL) { 252355163Sshin errmsg = "malloc"; 252455163Sshin continue; 252555163Sshin } 252655163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 252755163Sshin errmsg = "sysctl NET_RT_DUMP"; 252855163Sshin continue; 252955163Sshin } 253055163Sshin } while (retry < 5 && errmsg != NULL); 253178064Sume if (errmsg) { 253269279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 253369279Sume (u_long)msize); 253478064Sume /*NOTREACHED*/ 253578064Sume } else if (1 < retry) 253655163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 253755163Sshin 253855163Sshin lim = buf + msize; 253955163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 254055163Sshin rtm = (struct rt_msghdr *)p; 254155163Sshin rt_entry(rtm, again); 254255163Sshin } 254355163Sshin free(buf); 254455163Sshin} 254555163Sshin 254655163Sshinvoid 254755163Sshinrt_entry(rtm, again) 254855163Sshin struct rt_msghdr *rtm; 254955163Sshin int again; 255055163Sshin{ 255155163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 255255163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 255355163Sshin char *rtmp, *ifname = NULL; 255478064Sume struct riprt *rrt, *orrt; 255555163Sshin struct netinfo6 *np; 255655163Sshin int s; 255755163Sshin 255855163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 255955163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 256062607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 256155163Sshin return; /* not interested in the link route */ 256262607Sitojun } 256369279Sume /* do not look at cloned routes */ 256469279Sume#ifdef RTF_WASCLONED 256569279Sume if (rtm->rtm_flags & RTF_WASCLONED) 256669279Sume return; 256769279Sume#endif 256869279Sume#ifdef RTF_CLONED 256969279Sume if (rtm->rtm_flags & RTF_CLONED) 257069279Sume return; 257169279Sume#endif 257269279Sume /* 257369279Sume * do not look at dynamic routes. 257469279Sume * netbsd/openbsd cloned routes have UGHD. 257569279Sume */ 257669279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 257769279Sume return; 257855163Sshin rtmp = (char *)(rtm + 1); 257955163Sshin /* Destination */ 258055163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 258155163Sshin return; /* ignore routes without destination address */ 258255163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 258364631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 258455163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 258555163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 258655163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 258755163Sshin } 258855163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 258955163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 259055163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 259155163Sshin } 259255163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 259355163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 259455163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 259555163Sshin } 259655163Sshin if (rtm->rtm_addrs & RTA_IFP) { 259755163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 259855163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 259955163Sshin } 260055163Sshin 260155163Sshin /* Destination */ 260255163Sshin if (sin6_dst->sin6_family != AF_INET6) 260355163Sshin return; 260455163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 260555163Sshin return; /* Link-local */ 260655163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 260755163Sshin return; /* Loopback */ 260855163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 260955163Sshin return; 261055163Sshin 261178064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 261255163Sshin fatal("malloc: struct riprt"); 261378064Sume /*NOTREACHED*/ 261478064Sume } 261562607Sitojun memset(rrt, 0, sizeof(*rrt)); 261655163Sshin np = &rrt->rrt_info; 261755163Sshin rrt->rrt_same = NULL; 261855163Sshin rrt->rrt_t = time(NULL); 261955163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 262055163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 2621122677Sume if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) 2622122677Sume rrt->rrt_t = 0; /* Don't age non-gateway host routes */ 262355163Sshin np->rip6_tag = 0; 262455163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 262555163Sshin if (np->rip6_metric < 1) 262655163Sshin np->rip6_metric = 1; 262755163Sshin rrt->rrt_flags = rtm->rtm_flags; 262855163Sshin np->rip6_dest = sin6_dst->sin6_addr; 262955163Sshin 263055163Sshin /* Mask or plen */ 263155163Sshin if (rtm->rtm_flags & RTF_HOST) 263255163Sshin np->rip6_plen = 128; /* Host route */ 263378064Sume else if (sin6_mask) 263478064Sume np->rip6_plen = sin6mask2len(sin6_mask); 263578064Sume else 263655163Sshin np->rip6_plen = 0; 263755163Sshin 263878064Sume orrt = rtsearch(np, NULL); 263978064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 264055163Sshin /* Already found */ 264155163Sshin if (!again) { 264255163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 264355163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 264455163Sshin rtflags(rtm)); 264555163Sshin } 264655163Sshin free(rrt); 264755163Sshin return; 264855163Sshin } 264955163Sshin /* Gateway */ 265055163Sshin if (!sin6_gw) 265155163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 265255163Sshin else { 265355163Sshin if (sin6_gw->sin6_family == AF_INET6) 265455163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 265555163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 265655163Sshin /* XXX in case ppp link? */ 265755163Sshin rrt->rrt_gw = in6addr_loopback; 265855163Sshin } else 265955163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 266055163Sshin } 266155163Sshin trace(1, "route: %s/%d flags %s", 266255163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 266355163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 266455163Sshin 266555163Sshin /* Interface */ 266655163Sshin s = rtm->rtm_index; 266755163Sshin if (s < nindex2ifc && index2ifc[s]) 266855163Sshin ifname = index2ifc[s]->ifc_name; 266958070Sshin else { 267058070Sshin trace(1, " not configured\n"); 267162607Sitojun free(rrt); 267258070Sshin return; 267358070Sshin } 267462607Sitojun trace(1, " if %s sock %d", ifname, s); 267555163Sshin rrt->rrt_index = s; 267655163Sshin 267762607Sitojun trace(1, "\n"); 267862607Sitojun 267955163Sshin /* Check gateway */ 268055163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 2681122677Sume !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) && 2682122677Sume (rrt->rrt_flags & RTF_LOCAL) == 0) { 268355163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 268455163Sshin inet6_n2p(&rrt->rrt_gw)); 268555163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 268662607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 268762607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 268855163Sshin } 268955163Sshin 269055163Sshin /* Put it to the route list */ 269178064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 269278064Sume /* replace route list */ 269378064Sume rrt->rrt_next = orrt->rrt_next; 269478064Sume *orrt = *rrt; 269578064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 269678064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 269778064Sume rtflags(rtm)); 269878064Sume free(rrt); 269978064Sume } else { 270078064Sume rrt->rrt_next = riprt; 270178064Sume riprt = rrt; 270278064Sume } 270355163Sshin} 270455163Sshin 270555163Sshinint 270655163Sshinaddroute(rrt, gw, ifcp) 270755163Sshin struct riprt *rrt; 270855163Sshin const struct in6_addr *gw; 270955163Sshin struct ifc *ifcp; 271055163Sshin{ 271155163Sshin struct netinfo6 *np; 271255163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 271355163Sshin struct rt_msghdr *rtm; 2714119031Sume struct sockaddr_in6 *sin6; 271555163Sshin int len; 271655163Sshin 271755163Sshin np = &rrt->rrt_info; 271878064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 271955163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 272055163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 272155163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 272255163Sshin np->rip6_metric - 1, buf2); 272355163Sshin if (rtlog) 272455163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 272555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 272655163Sshin np->rip6_metric - 1, buf2); 272755163Sshin if (nflag) 272855163Sshin return 0; 272955163Sshin 273055163Sshin memset(buf, 0, sizeof(buf)); 273155163Sshin rtm = (struct rt_msghdr *)buf; 273255163Sshin rtm->rtm_type = RTM_ADD; 273355163Sshin rtm->rtm_version = RTM_VERSION; 273455163Sshin rtm->rtm_seq = ++seq; 273555163Sshin rtm->rtm_pid = pid; 273662607Sitojun rtm->rtm_flags = rrt->rrt_flags; 273755163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 273855163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 273955163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2740119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 274155163Sshin /* Destination */ 2742119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2743119031Sume sin6->sin6_family = AF_INET6; 2744119031Sume sin6->sin6_addr = np->rip6_dest; 2745119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 274655163Sshin /* Gateway */ 2747119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2748119031Sume sin6->sin6_family = AF_INET6; 2749119031Sume sin6->sin6_addr = *gw; 2750119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275155163Sshin /* Netmask */ 2752119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2753119031Sume sin6->sin6_family = AF_INET6; 2754119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2755119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275655163Sshin 2757119031Sume len = (char *)sin6 - (char *)buf; 275855163Sshin rtm->rtm_msglen = len; 275955163Sshin if (write(rtsock, buf, len) > 0) 276055163Sshin return 0; 276155163Sshin 276255163Sshin if (errno == EEXIST) { 276355163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2764119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 276555163Sshin if (rtlog) 276655163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2767119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 276855163Sshin } else { 276955163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2770119035Sume strerror(errno)); 277155163Sshin if (rtlog) 277255163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2773119035Sume strerror(errno)); 277455163Sshin } 277555163Sshin return -1; 277655163Sshin} 277755163Sshin 277855163Sshinint 277955163Sshindelroute(np, gw) 278055163Sshin struct netinfo6 *np; 278155163Sshin struct in6_addr *gw; 278255163Sshin{ 278355163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 278455163Sshin struct rt_msghdr *rtm; 2785119031Sume struct sockaddr_in6 *sin6; 278655163Sshin int len; 278755163Sshin 278855163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 278955163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 279055163Sshin np->rip6_plen, buf2); 279155163Sshin if (rtlog) 279255163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 279355163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 279455163Sshin if (nflag) 279555163Sshin return 0; 279655163Sshin 279755163Sshin memset(buf, 0, sizeof(buf)); 279855163Sshin rtm = (struct rt_msghdr *)buf; 279955163Sshin rtm->rtm_type = RTM_DELETE; 280055163Sshin rtm->rtm_version = RTM_VERSION; 280155163Sshin rtm->rtm_seq = ++seq; 280255163Sshin rtm->rtm_pid = pid; 280355163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 280478064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 280578064Sume rtm->rtm_flags |= RTF_HOST; 280655163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2807119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 280855163Sshin /* Destination */ 2809119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2810119031Sume sin6->sin6_family = AF_INET6; 2811119031Sume sin6->sin6_addr = np->rip6_dest; 2812119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 281355163Sshin /* Gateway */ 2814119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2815119031Sume sin6->sin6_family = AF_INET6; 2816119031Sume sin6->sin6_addr = *gw; 2817119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 281855163Sshin /* Netmask */ 2819119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2820119031Sume sin6->sin6_family = AF_INET6; 2821119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2822119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 282355163Sshin 2824119031Sume len = (char *)sin6 - (char *)buf; 282555163Sshin rtm->rtm_msglen = len; 282655163Sshin if (write(rtsock, buf, len) >= 0) 282755163Sshin return 0; 282855163Sshin 282955163Sshin if (errno == ESRCH) { 283055163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2831119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 283255163Sshin if (rtlog) 283355163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2834119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 283555163Sshin } else { 283655163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2837119035Sume strerror(errno)); 283855163Sshin if (rtlog) 283955163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2840119035Sume strerror(errno)); 284155163Sshin } 284255163Sshin return -1; 284355163Sshin} 284455163Sshin 284555163Sshinstruct in6_addr * 284655163Sshingetroute(np, gw) 284755163Sshin struct netinfo6 *np; 284855163Sshin struct in6_addr *gw; 284955163Sshin{ 285055163Sshin u_char buf[BUFSIZ]; 2851119085Sume int myseq; 285255163Sshin int len; 285355163Sshin struct rt_msghdr *rtm; 2854119031Sume struct sockaddr_in6 *sin6; 285555163Sshin 285655163Sshin rtm = (struct rt_msghdr *)buf; 285755163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 285855163Sshin memset(rtm, 0, len); 285955163Sshin rtm->rtm_type = RTM_GET; 286055163Sshin rtm->rtm_version = RTM_VERSION; 286155163Sshin myseq = ++seq; 286255163Sshin rtm->rtm_seq = myseq; 286355163Sshin rtm->rtm_addrs = RTA_DST; 286455163Sshin rtm->rtm_msglen = len; 2865119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2866119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2867119031Sume sin6->sin6_family = AF_INET6; 2868119031Sume sin6->sin6_addr = np->rip6_dest; 286955163Sshin if (write(rtsock, buf, len) < 0) { 287055163Sshin if (errno == ESRCH) /* No such route found */ 287155163Sshin return NULL; 287255163Sshin perror("write to rtsock"); 287378064Sume exit(1); 287455163Sshin } 287555163Sshin do { 287655163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 287755163Sshin perror("read from rtsock"); 287878064Sume exit(1); 287955163Sshin } 288055163Sshin rtm = (struct rt_msghdr *)buf; 288155163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2882119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 288355163Sshin if (rtm->rtm_addrs & RTA_DST) { 2884119031Sume sin6 = (struct sockaddr_in6 *) 2885119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 288655163Sshin } 288755163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2888119031Sume *gw = sin6->sin6_addr; 288955163Sshin return gw; 289055163Sshin } 289155163Sshin return NULL; 289255163Sshin} 289355163Sshin 289455163Sshinconst char * 289555163Sshininet6_n2p(p) 289655163Sshin const struct in6_addr *p; 289755163Sshin{ 289855163Sshin static char buf[BUFSIZ]; 289955163Sshin 290078064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 290155163Sshin} 290255163Sshin 290355163Sshinvoid 290455163Sshinifrtdump(sig) 290555163Sshin int sig; 290655163Sshin{ 290755163Sshin 290855163Sshin ifdump(sig); 290955163Sshin rtdump(sig); 291055163Sshin} 291155163Sshin 291255163Sshinvoid 291355163Sshinifdump(sig) 291455163Sshin int sig; 291555163Sshin{ 291655163Sshin struct ifc *ifcp; 291755163Sshin FILE *dump; 291855163Sshin int i; 291955163Sshin 292055163Sshin if (sig == 0) 292155163Sshin dump = stderr; 292255163Sshin else 292355163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 292455163Sshin dump = stderr; 292555163Sshin 292655163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 292755163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 292855163Sshin for (i = 0; i < 2; i++) { 292955163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 293055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 293155163Sshin if (i == 0) { 293255163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 293355163Sshin continue; 293455163Sshin if (iff_find(ifcp, 'N') != NULL) 293555163Sshin continue; 293655163Sshin } else { 293755163Sshin if (ifcp->ifc_flags & IFF_UP) 293855163Sshin continue; 293955163Sshin } 294055163Sshin ifdump0(dump, ifcp); 294155163Sshin } 294255163Sshin } 294355163Sshin fprintf(dump, "\n"); 294455163Sshin if (dump != stderr) 294555163Sshin fclose(dump); 294655163Sshin} 294755163Sshin 294855163Sshinvoid 294955163Sshinifdump0(dump, ifcp) 295055163Sshin FILE *dump; 295155163Sshin const struct ifc *ifcp; 295255163Sshin{ 295355163Sshin struct ifac *ifa; 295455163Sshin struct iff *iffp; 295555163Sshin char buf[BUFSIZ]; 295655163Sshin const char *ft; 295755163Sshin int addr; 295855163Sshin 295955163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 296055163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 296155163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 296255163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 296355163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 296455163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 296555163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 296655163Sshin buf, sizeof(buf)); 296755163Sshin fprintf(dump, "\t%s/%d -- %s\n", 296855163Sshin inet6_n2p(&ifa->ifa_addr), 296955163Sshin ifa->ifa_plen, buf); 297055163Sshin } else { 297155163Sshin fprintf(dump, "\t%s/%d\n", 297255163Sshin inet6_n2p(&ifa->ifa_addr), 297355163Sshin ifa->ifa_plen); 297455163Sshin } 297555163Sshin } 297655163Sshin if (ifcp->ifc_filter) { 297755163Sshin fprintf(dump, "\tFilter:"); 297855163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 297955163Sshin addr = 0; 298055163Sshin switch (iffp->iff_type) { 298155163Sshin case 'A': 298255163Sshin ft = "Aggregate"; addr++; break; 298355163Sshin case 'N': 298478064Sume ft = "No-use"; break; 298555163Sshin case 'O': 298655163Sshin ft = "Advertise-only"; addr++; break; 298755163Sshin case 'T': 298855163Sshin ft = "Default-only"; break; 298955163Sshin case 'L': 299055163Sshin ft = "Listen-only"; addr++; break; 299155163Sshin default: 299255163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 299355163Sshin ft = buf; 299455163Sshin addr++; 299555163Sshin break; 299655163Sshin } 299755163Sshin fprintf(dump, " %s", ft); 299855163Sshin if (addr) { 299955163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 300055163Sshin iffp->iff_plen); 300155163Sshin } 300255163Sshin } 300355163Sshin fprintf(dump, "\n"); 300455163Sshin } 300555163Sshin} 300655163Sshin 300755163Sshinvoid 300855163Sshinrtdump(sig) 300955163Sshin int sig; 301055163Sshin{ 301155163Sshin struct riprt *rrt; 301255163Sshin char buf[BUFSIZ]; 301355163Sshin FILE *dump; 301455163Sshin time_t t, age; 301555163Sshin 301655163Sshin if (sig == 0) 301755163Sshin dump = stderr; 301855163Sshin else 301955163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 302055163Sshin dump = stderr; 302155163Sshin 302255163Sshin t = time(NULL); 302355163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 302455163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 302555163Sshin if (rrt->rrt_t == 0) 302655163Sshin age = 0; 302755163Sshin else 302855163Sshin age = t - rrt->rrt_t; 302955163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 303055163Sshin buf, sizeof(buf)); 303155163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 303255163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 303355163Sshin index2ifc[rrt->rrt_index]->ifc_name, 303455163Sshin inet6_n2p(&rrt->rrt_gw), 303555163Sshin rrt->rrt_info.rip6_metric, (long)age); 303655163Sshin if (rrt->rrt_info.rip6_tag) { 303755163Sshin fprintf(dump, " tag(0x%04x)", 303855163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 303955163Sshin } 304062607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 304155163Sshin fprintf(dump, " NOT-LL"); 304262607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 304355163Sshin fprintf(dump, " NO-ADV"); 304455163Sshin fprintf(dump, "\n"); 304555163Sshin } 304655163Sshin fprintf(dump, "\n"); 304755163Sshin if (dump != stderr) 304855163Sshin fclose(dump); 304955163Sshin} 305055163Sshin 305155163Sshin/* 305255163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 305378064Sume * specified interface structures. Each of the -A/O option has the following 305455163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 305555163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 305655163Sshin */ 305755163Sshinvoid 305855163Sshinfilterconfig() 305955163Sshin{ 306055163Sshin int i; 3061119083Sume char *p, *ap, *iflp, *ifname, *ep; 306278064Sume struct iff ftmp, *iff_obj; 306378064Sume struct ifc *ifcp; 306478064Sume struct riprt *rrt; 306564631Sitojun#if 0 306678064Sume struct in6_addr gw; 306764631Sitojun#endif 3068119083Sume u_long plen; 306955163Sshin 307055163Sshin for (i = 0; i < nfilter; i++) { 307155163Sshin ap = filter[i]; 307255163Sshin iflp = NULL; 307355163Sshin ifcp = NULL; 307455163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 307555163Sshin iflp = ap; 307655163Sshin goto ifonly; 307755163Sshin } 3078119038Sume if ((p = strchr(ap, ',')) != NULL) { 307955163Sshin *p++ = '\0'; 308055163Sshin iflp = p; 308155163Sshin } 3082119038Sume if ((p = strchr(ap, '/')) == NULL) { 308355163Sshin fatal("no prefixlen specified for '%s'", ap); 308478064Sume /*NOTREACHED*/ 308578064Sume } 308655163Sshin *p++ = '\0'; 308778064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 308855163Sshin fatal("invalid prefix specified for '%s'", ap); 308978064Sume /*NOTREACHED*/ 309078064Sume } 3091119083Sume errno = 0; 3092119083Sume ep = NULL; 3093119083Sume plen = strtoul(p, &ep, 10); 3094119083Sume if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) { 3095119083Sume fatal("invalid prefix length specified for '%s'", ap); 3096119083Sume /*NOTREACHED*/ 3097119083Sume } 3098119083Sume ftmp.iff_plen = plen; 309955163Sshin ftmp.iff_next = NULL; 310055163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 310155163Sshinifonly: 310255163Sshin ftmp.iff_type = filtertype[i]; 310378064Sume if (iflp == NULL || *iflp == '\0') { 310455163Sshin fatal("no interface specified for '%s'", ap); 310578064Sume /*NOTREACHED*/ 310678064Sume } 310755163Sshin /* parse the interface listing portion */ 310855163Sshin while (iflp) { 310955163Sshin ifname = iflp; 3110119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 311155163Sshin *iflp++ = '\0'; 311255163Sshin ifcp = ifc_find(ifname); 311378064Sume if (ifcp == NULL) { 311455163Sshin fatal("no interface %s exists", ifname); 311578064Sume /*NOTREACHED*/ 311678064Sume } 311755163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 311878064Sume if (iff_obj == NULL) { 311955163Sshin fatal("malloc of iff_obj"); 312078064Sume /*NOTREACHED*/ 312178064Sume } 312255163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 312378064Sume sizeof(struct iff)); 312455163Sshin /* link it to the interface filter */ 312555163Sshin iff_obj->iff_next = ifcp->ifc_filter; 312655163Sshin ifcp->ifc_filter = iff_obj; 312755163Sshin } 312878064Sume 312978064Sume /* 313078064Sume * -A: aggregate configuration. 313178064Sume */ 313255163Sshin if (filtertype[i] != 'A') 313355163Sshin continue; 313455163Sshin /* put the aggregate to the kernel routing table */ 313555163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 313678064Sume if (rrt == NULL) { 313755163Sshin fatal("malloc: rrt"); 313878064Sume /*NOTREACHED*/ 313978064Sume } 314055163Sshin memset(rrt, 0, sizeof(struct riprt)); 314155163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 314255163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 314355163Sshin rrt->rrt_info.rip6_metric = 1; 314455163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 314555163Sshin rrt->rrt_gw = in6addr_loopback; 314662607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 314762607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 314855163Sshin rrt->rrt_t = 0; 3149119039Sume rrt->rrt_index = loopifcp->ifc_index; 315064631Sitojun#if 0 315164631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 315264631Sitojun#if 0 315364631Sitojun /* 315464631Sitojun * When the address has already been registered in the 315564631Sitojun * kernel routing table, it should be removed 315664631Sitojun */ 315764631Sitojun delroute(&rrt->rrt_info, &gw); 315864631Sitojun#else 315978064Sume /* it is safer behavior */ 316064631Sitojun errno = EINVAL; 316164631Sitojun fatal("%s/%u already in routing table, " 316264631Sitojun "cannot aggregate", 316364631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 316464631Sitojun rrt->rrt_info.rip6_plen); 316578064Sume /*NOTREACHED*/ 316664631Sitojun#endif 316764631Sitojun } 316864631Sitojun#endif 316955163Sshin /* Put the route to the list */ 317055163Sshin rrt->rrt_next = riprt; 317155163Sshin riprt = rrt; 317255163Sshin trace(1, "Aggregate: %s/%d for %s\n", 317355163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 317455163Sshin ifcp->ifc_name); 317555163Sshin /* Add this route to the kernel */ 317655163Sshin if (nflag) /* do not modify kernel routing table */ 317755163Sshin continue; 317855163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 317955163Sshin } 318055163Sshin} 318155163Sshin 318255163Sshin/***************** utility functions *****************/ 318355163Sshin 318455163Sshin/* 318555163Sshin * Returns a pointer to ifac whose address and prefix length matches 318655163Sshin * with the address and prefix length specified in the arguments. 318755163Sshin */ 318855163Sshinstruct ifac * 318955163Sshinifa_match(ifcp, ia, plen) 319055163Sshin const struct ifc *ifcp; 319155163Sshin const struct in6_addr *ia; 319255163Sshin int plen; 319355163Sshin{ 319455163Sshin struct ifac *ifa; 319555163Sshin 319655163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 319755163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 319855163Sshin ifa->ifa_plen == plen) 319955163Sshin break; 320055163Sshin } 320155163Sshin return ifa; 320255163Sshin} 320355163Sshin 320455163Sshin/* 320555163Sshin * Return a pointer to riprt structure whose address and prefix length 320655163Sshin * matches with the address and prefix length found in the argument. 320778064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 320855163Sshin */ 320955163Sshinstruct riprt * 321078064Sumertsearch(np, prev_rrt) 321155163Sshin struct netinfo6 *np; 321278064Sume struct riprt **prev_rrt; 321355163Sshin{ 321455163Sshin struct riprt *rrt; 321555163Sshin 321678064Sume if (prev_rrt) 321778064Sume *prev_rrt = NULL; 321855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 321955163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 322055163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 322155163Sshin &np->rip6_dest)) 322255163Sshin return rrt; 322378064Sume if (prev_rrt) 322478064Sume *prev_rrt = rrt; 322555163Sshin } 322678064Sume if (prev_rrt) 322778064Sume *prev_rrt = NULL; 322855163Sshin return 0; 322955163Sshin} 323055163Sshin 323155163Sshinint 323278064Sumesin6mask2len(sin6) 323378064Sume const struct sockaddr_in6 *sin6; 323478064Sume{ 323578064Sume 323678064Sume return mask2len(&sin6->sin6_addr, 323778064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 323878064Sume} 323978064Sume 324078064Sumeint 324155163Sshinmask2len(addr, lenlim) 324255163Sshin const struct in6_addr *addr; 324355163Sshin int lenlim; 324455163Sshin{ 324555163Sshin int i = 0, j; 324678064Sume const u_char *p = (const u_char *)addr; 324762607Sitojun 324855163Sshin for (j = 0; j < lenlim; j++, p++) { 324955163Sshin if (*p != 0xff) 325055163Sshin break; 325155163Sshin i += 8; 325255163Sshin } 325355163Sshin if (j < lenlim) { 325455163Sshin switch (*p) { 325562607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 325662607Sitojun MASKLEN(0xfe, 7); break; 325762607Sitojun MASKLEN(0xfc, 6); break; 325862607Sitojun MASKLEN(0xf8, 5); break; 325962607Sitojun MASKLEN(0xf0, 4); break; 326062607Sitojun MASKLEN(0xe0, 3); break; 326162607Sitojun MASKLEN(0xc0, 2); break; 326262607Sitojun MASKLEN(0x80, 1); break; 326355163Sshin#undef MASKLEN 326455163Sshin } 326555163Sshin } 326655163Sshin return i; 326755163Sshin} 326855163Sshin 326955163Sshinvoid 327055163Sshinapplymask(addr, mask) 327155163Sshin struct in6_addr *addr, *mask; 327255163Sshin{ 327355163Sshin int i; 327455163Sshin u_long *p, *q; 327555163Sshin 327655163Sshin p = (u_long *)addr; q = (u_long *)mask; 327755163Sshin for (i = 0; i < 4; i++) 327855163Sshin *p++ &= *q++; 327955163Sshin} 328055163Sshin 328155163Sshinstatic const u_char plent[8] = { 328255163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 328355163Sshin}; 328455163Sshin 328555163Sshinvoid 328655163Sshinapplyplen(ia, plen) 328755163Sshin struct in6_addr *ia; 328855163Sshin int plen; 328955163Sshin{ 329055163Sshin u_char *p; 329155163Sshin int i; 329255163Sshin 329355163Sshin p = ia->s6_addr; 329455163Sshin for (i = 0; i < 16; i++) { 329555163Sshin if (plen <= 0) 329655163Sshin *p = 0; 329755163Sshin else if (plen < 8) 329855163Sshin *p &= plent[plen]; 329955163Sshin p++, plen -= 8; 330055163Sshin } 330155163Sshin} 330255163Sshin 330355163Sshinstatic const int pl2m[9] = { 330455163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 330555163Sshin}; 330655163Sshin 330755163Sshinstruct in6_addr * 330855163Sshinplen2mask(n) 330955163Sshin int n; 331055163Sshin{ 331155163Sshin static struct in6_addr ia; 331255163Sshin u_char *p; 331355163Sshin int i; 331455163Sshin 331555163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 331655163Sshin p = (u_char *)&ia; 331755163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 331855163Sshin if (n >= 8) { 331955163Sshin *p = 0xff; 332055163Sshin continue; 332155163Sshin } 332255163Sshin *p = pl2m[n]; 332355163Sshin break; 332455163Sshin } 332555163Sshin return &ia; 332655163Sshin} 332755163Sshin 332855163Sshinchar * 332955163Sshinallocopy(p) 333055163Sshin char *p; 333155163Sshin{ 3332119033Sume int len = strlen(p) + 1; 3333119033Sume char *q = (char *)malloc(len); 333455163Sshin 3335119033Sume if (!q) { 3336119033Sume fatal("malloc"); 3337119033Sume /*NOTREACHED*/ 3338119033Sume } 3339119033Sume 3340119033Sume strlcpy(q, p, len); 334155163Sshin return q; 334255163Sshin} 334355163Sshin 334455163Sshinchar * 334555163Sshinhms() 334655163Sshin{ 334755163Sshin static char buf[BUFSIZ]; 334855163Sshin time_t t; 334955163Sshin struct tm *tm; 335055163Sshin 335155163Sshin t = time(NULL); 335278064Sume if ((tm = localtime(&t)) == 0) { 335355163Sshin fatal("localtime"); 335478064Sume /*NOTREACHED*/ 335578064Sume } 335678064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 335778064Sume tm->tm_sec); 335855163Sshin return buf; 335955163Sshin} 336055163Sshin 336155163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 336255163Sshin 336355163Sshinint 336455163Sshinripinterval(timer) 336555163Sshin int timer; 336655163Sshin{ 336755163Sshin double r = rand(); 336855163Sshin 336955163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 337055163Sshin nextalarm = time(NULL) + interval; 337155163Sshin return interval; 337255163Sshin} 337355163Sshin 337455163Sshintime_t 337555163Sshinripsuptrig() 337655163Sshin{ 337755163Sshin time_t t; 337855163Sshin 337955163Sshin double r = rand(); 338062607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 338178064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 338255163Sshin sup_trig_update = time(NULL) + t; 338355163Sshin return t; 338455163Sshin} 338555163Sshin 338655163Sshinvoid 338755163Sshin#ifdef __STDC__ 338855163Sshinfatal(const char *fmt, ...) 338955163Sshin#else 339055163Sshinfatal(fmt, va_alist) 339155163Sshin char *fmt; 339255163Sshin va_dcl 339355163Sshin#endif 339455163Sshin{ 339555163Sshin va_list ap; 339655163Sshin char buf[1024]; 339755163Sshin 339855163Sshin#ifdef __STDC__ 339955163Sshin va_start(ap, fmt); 340055163Sshin#else 340155163Sshin va_start(ap); 340255163Sshin#endif 340355163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 3404119043Sume va_end(ap); 340555163Sshin perror(buf); 3406119043Sume if (errno) 3407119043Sume syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 3408119043Sume else 3409119043Sume syslog(LOG_ERR, "%s", buf); 341078064Sume rtdexit(); 341155163Sshin} 341255163Sshin 341355163Sshinvoid 341455163Sshin#ifdef __STDC__ 341555163Sshintracet(int level, const char *fmt, ...) 341655163Sshin#else 341755163Sshintracet(level, fmt, va_alist) 341855163Sshin int level; 341955163Sshin char *fmt; 342055163Sshin va_dcl 342155163Sshin#endif 342255163Sshin{ 342355163Sshin va_list ap; 342455163Sshin 3425119043Sume if (level <= dflag) { 342655163Sshin#ifdef __STDC__ 3427119043Sume va_start(ap, fmt); 342855163Sshin#else 3429119043Sume va_start(ap); 343055163Sshin#endif 343155163Sshin fprintf(stderr, "%s: ", hms()); 343255163Sshin vfprintf(stderr, fmt, ap); 3433119043Sume va_end(ap); 343455163Sshin } 343555163Sshin if (dflag) { 3436119043Sume#ifdef __STDC__ 3437119043Sume va_start(ap, fmt); 3438119043Sume#else 3439119043Sume va_start(ap); 3440119043Sume#endif 344155163Sshin if (level > 0) 344255163Sshin vsyslog(LOG_DEBUG, fmt, ap); 344355163Sshin else 344455163Sshin vsyslog(LOG_WARNING, fmt, ap); 3445119043Sume va_end(ap); 344655163Sshin } 344755163Sshin} 344855163Sshin 344955163Sshinvoid 345055163Sshin#ifdef __STDC__ 345155163Sshintrace(int level, const char *fmt, ...) 345255163Sshin#else 345355163Sshintrace(level, fmt, va_alist) 345455163Sshin int level; 345555163Sshin char *fmt; 345655163Sshin va_dcl 345755163Sshin#endif 345855163Sshin{ 345955163Sshin va_list ap; 346055163Sshin 3461119043Sume if (level <= dflag) { 346255163Sshin#ifdef __STDC__ 3463119043Sume va_start(ap, fmt); 346455163Sshin#else 3465119043Sume va_start(ap); 346655163Sshin#endif 346755163Sshin vfprintf(stderr, fmt, ap); 3468119043Sume va_end(ap); 3469119043Sume } 347055163Sshin if (dflag) { 3471119043Sume#ifdef __STDC__ 3472119043Sume va_start(ap, fmt); 3473119043Sume#else 3474119043Sume va_start(ap); 3475119043Sume#endif 347655163Sshin if (level > 0) 347755163Sshin vsyslog(LOG_DEBUG, fmt, ap); 347855163Sshin else 347955163Sshin vsyslog(LOG_WARNING, fmt, ap); 3480119043Sume va_end(ap); 348155163Sshin } 348255163Sshin} 348355163Sshin 348455163Sshinunsigned int 348555163Sshinif_maxindex() 348655163Sshin{ 348755163Sshin struct if_nameindex *p, *p0; 348855163Sshin unsigned int max = 0; 348955163Sshin 349055163Sshin p0 = if_nameindex(); 349155163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 349255163Sshin if (max < p->if_index) 349355163Sshin max = p->if_index; 349455163Sshin } 349555163Sshin if_freenameindex(p0); 349655163Sshin return max; 349755163Sshin} 349855163Sshin 349955163Sshinstruct ifc * 350055163Sshinifc_find(name) 350155163Sshin char *name; 350255163Sshin{ 350355163Sshin struct ifc *ifcp; 350455163Sshin 350555163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 350655163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 350755163Sshin return ifcp; 350855163Sshin } 350955163Sshin return (struct ifc *)NULL; 351055163Sshin} 351155163Sshin 351255163Sshinstruct iff * 351355163Sshiniff_find(ifcp, type) 351455163Sshin struct ifc *ifcp; 351555163Sshin int type; 351655163Sshin{ 351755163Sshin struct iff *iffp; 351855163Sshin 351955163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 352055163Sshin if (iffp->iff_type == type) 352155163Sshin return iffp; 352255163Sshin } 352355163Sshin return NULL; 352455163Sshin} 352555163Sshin 352655163Sshinvoid 352778064Sumesetindex2ifc(idx, ifcp) 352878064Sume int idx; 352955163Sshin struct ifc *ifcp; 353055163Sshin{ 3531122677Sume int n, nsize; 353262607Sitojun struct ifc **p; 353355163Sshin 353455163Sshin if (!index2ifc) { 353555163Sshin nindex2ifc = 5; /*initial guess*/ 353655163Sshin index2ifc = (struct ifc **) 353755163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 353878064Sume if (index2ifc == NULL) { 353955163Sshin fatal("malloc"); 354078064Sume /*NOTREACHED*/ 354178064Sume } 354255163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 354355163Sshin } 354455163Sshin n = nindex2ifc; 3545122677Sume for (nsize = nindex2ifc; nsize <= idx; nsize *= 2) 3546122677Sume ; 3547122677Sume if (n != nsize) { 354862607Sitojun p = (struct ifc **)realloc(index2ifc, 3549122677Sume sizeof(*index2ifc) * nsize); 355078064Sume if (p == NULL) { 355155163Sshin fatal("realloc"); 355278064Sume /*NOTREACHED*/ 355378064Sume } 355478064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 355562607Sitojun index2ifc = p; 3556122677Sume nindex2ifc = nsize; 355755163Sshin } 355878064Sume index2ifc[idx] = ifcp; 355955163Sshin} 3560