route6d.c revision 119076
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 119076 2003-08-18 15:35:33Z ume $ */ 278064Sume/* $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 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 3478064Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 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> 6562607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3 6655163Sshin#include <net/if_var.h> 6762607Sitojun#endif /* __FreeBSD__ >= 3 */ 6862607Sitojun#define KERNEL 1 6962607Sitojun#define _KERNEL 1 7055163Sshin#include <net/route.h> 7162607Sitojun#undef KERNEL 7262607Sitojun#undef _KERNEL 7355163Sshin#include <netinet/in.h> 7455163Sshin#include <netinet/in_var.h> 7555163Sshin#include <netinet/ip6.h> 7655163Sshin#include <netinet/udp.h> 7755163Sshin#include <netdb.h> 7862607Sitojun#include <ifaddrs.h> 7955163Sshin 8055163Sshin#include <arpa/inet.h> 8155163Sshin 8255163Sshin#include "route6d.h" 8355163Sshin 8455163Sshin#define MAXFILTER 40 8555163Sshin 8655163Sshin#ifdef DEBUG 8755163Sshin#define INIT_INTERVAL6 6 8855163Sshin#else 89119039Sume#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ 9055163Sshin#endif 9155163Sshin 9255163Sshin/* alignment constraint for routing socket */ 9362607Sitojun#define ROUNDUP(a) \ 9455163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9562607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9655163Sshin 9755163Sshin/* 9855163Sshin * Following two macros are highly depending on KAME Release 9955163Sshin */ 10055163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 10155163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 10255163Sshin 10355163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10455163Sshin do { \ 10555163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10655163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10755163Sshin } while (0) 10855163Sshin 10955163Sshinstruct ifc { /* Configuration of an interface */ 11055163Sshin char *ifc_name; /* if name */ 11155163Sshin struct ifc *ifc_next; 11255163Sshin int ifc_index; /* if index */ 11355163Sshin int ifc_mtu; /* if mtu */ 11455163Sshin int ifc_metric; /* if metric */ 11578064Sume u_int ifc_flags; /* flags */ 11678064Sume short ifc_cflags; /* IFC_XXX */ 11755163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11855163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11955163Sshin struct iff *ifc_filter; /* filter structure */ 12055163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 12155163Sshin int ifc_joined; /* joined to ff02::9 */ 12255163Sshin}; 12355163Sshin 12462607Sitojunstruct ifac { /* Adddress associated to an interface */ 12555163Sshin struct ifc *ifa_conf; /* back pointer */ 12655163Sshin struct ifac *ifa_next; 12755163Sshin struct in6_addr ifa_addr; /* address */ 12855163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12955163Sshin int ifa_plen; /* prefix length */ 13055163Sshin}; 13155163Sshin 13255163Sshinstruct iff { 13355163Sshin int iff_type; 13455163Sshin struct in6_addr iff_addr; 13555163Sshin int iff_plen; 13655163Sshin struct iff *iff_next; 13755163Sshin}; 13855163Sshin 13955163Sshinstruct ifc *ifc; 14055163Sshinint nifc; /* number of valid ifc's */ 14155163Sshinstruct ifc **index2ifc; 14255163Sshinint nindex2ifc; 14355163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 144119076Sume#ifdef HAVE_POLL_H 145119076Sumestruct pollfd set[2]; 146119076Sume#else 147119070Sumefd_set *sockvecp; /* vector to select() for receiving */ 148119070Sumefd_set *recvecp; 149119070Sumeint fdmasks; 150119070Sumeint maxfd; /* maximum fd for select() */ 151119076Sume#endif 15255163Sshinint rtsock; /* the routing socket */ 15355163Sshinint ripsock; /* socket to send/receive RIP datagram */ 15455163Sshin 15555163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 15655163Sshin 15755163Sshin/* 15878064Sume * Maintain the routes in a linked list. When the number of the routes 15955163Sshin * grows, somebody would like to introduce a hash based or a radix tree 16078064Sume * based structure. I believe the number of routes handled by RIP is 16155163Sshin * limited and I don't have to manage a complex data structure, however. 16255163Sshin * 16355163Sshin * One of the major drawbacks of the linear linked list is the difficulty 16478064Sume * of representing the relationship between a couple of routes. This may 16555163Sshin * be a significant problem when we have to support route aggregation with 16655163Sshin * supressing the specifices covered by the aggregate. 16755163Sshin */ 16855163Sshin 16955163Sshinstruct riprt { 17055163Sshin struct riprt *rrt_next; /* next destination */ 17155163Sshin struct riprt *rrt_same; /* same destination - future use */ 17255163Sshin struct netinfo6 rrt_info; /* network info */ 17355163Sshin struct in6_addr rrt_gw; /* gateway */ 17462607Sitojun u_long rrt_flags; /* kernel routing table flags */ 17562607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 17655163Sshin time_t rrt_t; /* when the route validated */ 17755163Sshin int rrt_index; /* ifindex from which this route got */ 17855163Sshin}; 17955163Sshin 18055163Sshinstruct riprt *riprt = 0; 18155163Sshin 18255163Sshinint dflag = 0; /* debug flag */ 18355163Sshinint qflag = 0; /* quiet flag */ 18455163Sshinint nflag = 0; /* don't update kernel routing table */ 18555163Sshinint aflag = 0; /* age out even the statically defined routes */ 18655163Sshinint hflag = 0; /* don't split horizon */ 18755163Sshinint lflag = 0; /* exchange site local routes */ 18855163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 18955163Sshinint Sflag = 0; /* announce static routes to every interface */ 19062607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 19155163Sshin 19255163Sshinchar *filter[MAXFILTER]; 19355163Sshinint filtertype[MAXFILTER]; 19455163Sshinint nfilter = 0; 19555163Sshin 19655163Sshinpid_t pid; 19755163Sshin 19855163Sshinstruct sockaddr_storage ripsin; 19955163Sshin 20055163Sshinstruct rtentry rtentry; 20155163Sshin 20255163Sshinint interval = 1; 20355163Sshintime_t nextalarm = 0; 20455163Sshintime_t sup_trig_update = 0; 20555163Sshin 20655163SshinFILE *rtlog = NULL; 20755163Sshin 20855163Sshinint logopened = 0; 20955163Sshin 21055163Sshinstatic u_long seq = 0; 21155163Sshin 21278064Sumevolatile int signo; 21378064Sumevolatile sig_atomic_t seenalrm; 21478064Sumevolatile sig_atomic_t seenquit; 21578064Sumevolatile sig_atomic_t seenusr1; 21678064Sume 21762607Sitojun#define RRTF_AGGREGATE 0x08000000 21862607Sitojun#define RRTF_NOADVERTISE 0x10000000 21962607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 22062607Sitojun#define RRTF_SENDANYWAY 0x40000000 22162607Sitojun#define RRTF_CHANGED 0x80000000 22255163Sshin 22355163Sshinint main __P((int, char **)); 22478064Sumevoid sighandler __P((int)); 22578064Sumevoid ripalarm __P((void)); 22655163Sshinvoid riprecv __P((void)); 22755163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 22878064Sumeint out_filter __P((struct riprt *, struct ifc *)); 22955163Sshinvoid init __P((void)); 23055163Sshinvoid sockopt __P((struct ifc *)); 23155163Sshinvoid ifconfig __P((void)); 23262607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 23355163Sshinvoid rtrecv __P((void)); 23455163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 23555163Sshin const struct sockaddr_in6 *)); 23655163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 23755163Sshin const struct sockaddr_in6 *)); 23855163Sshinvoid filterconfig __P((void)); 23955163Sshinint getifmtu __P((int)); 24078064Sumeconst char *rttypes __P((struct rt_msghdr *)); 24178064Sumeconst char *rtflags __P((struct rt_msghdr *)); 24278064Sumeconst char *ifflags __P((int)); 24378064Sumeint ifrt __P((struct ifc *, int)); 24462607Sitojunvoid ifrt_p2p __P((struct ifc *, int)); 24555163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 24655163Sshinvoid applyplen __P((struct in6_addr *, int)); 24755163Sshinvoid ifrtdump __P((int)); 24855163Sshinvoid ifdump __P((int)); 24955163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 25055163Sshinvoid rtdump __P((int)); 25155163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 25278064Sumevoid rtdexit __P((void)); 25378064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int, 25478064Sume struct sockaddr_in6 *)); 25555163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 25655163Sshinvoid sendrequest __P((struct ifc *)); 25778064Sumeint sin6mask2len __P((const struct sockaddr_in6 *)); 25855163Sshinint mask2len __P((const struct in6_addr *, int)); 25955163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 26055163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 26155163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 26255163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 26355163Sshinvoid krtread __P((int)); 26455163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 26555163Sshinchar *allocopy __P((char *)); 26655163Sshinchar *hms __P((void)); 26755163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 26855163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 26955163Sshinstruct in6_addr *plen2mask __P((int)); 27078064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); 27155163Sshinint ripinterval __P((int)); 27255163Sshintime_t ripsuptrig __P((void)); 27366807Skrisvoid fatal __P((const char *, ...)) 27466807Skris __attribute__((__format__(__printf__, 1, 2))); 27566807Skrisvoid trace __P((int, const char *, ...)) 27666807Skris __attribute__((__format__(__printf__, 2, 3))); 27766807Skrisvoid tracet __P((int, const char *, ...)) 27866807Skris __attribute__((__format__(__printf__, 2, 3))); 27955163Sshinunsigned int if_maxindex __P((void)); 28055163Sshinstruct ifc *ifc_find __P((char *)); 28155163Sshinstruct iff *iff_find __P((struct ifc *, int)); 28255163Sshinvoid setindex2ifc __P((int, struct ifc *)); 28355163Sshin 28455163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 28555163Sshin 28655163Sshinint 28755163Sshinmain(argc, argv) 28855163Sshin int argc; 28955163Sshin char **argv; 29055163Sshin{ 29155163Sshin int ch; 29255163Sshin int error = 0; 29355163Sshin struct ifc *ifcp; 29455163Sshin sigset_t mask, omask; 29555163Sshin FILE *pidfile; 29655163Sshin char *progname; 29762607Sitojun char *ep; 29855163Sshin 29955163Sshin progname = strrchr(*argv, '/'); 30055163Sshin if (progname) 30155163Sshin progname++; 30255163Sshin else 30355163Sshin progname = *argv; 30455163Sshin 30555163Sshin pid = getpid(); 30678064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 30755163Sshin switch (ch) { 30855163Sshin case 'A': 30955163Sshin case 'N': 31055163Sshin case 'O': 31155163Sshin case 'T': 31255163Sshin case 'L': 31362607Sitojun if (nfilter >= MAXFILTER) { 31455163Sshin fatal("Exceeds MAXFILTER"); 31562607Sitojun /*NOTREACHED*/ 31662607Sitojun } 31755163Sshin filtertype[nfilter] = ch; 31855163Sshin filter[nfilter++] = allocopy(optarg); 31955163Sshin break; 32055163Sshin case 't': 32162607Sitojun ep = NULL; 32262607Sitojun routetag = strtoul(optarg, &ep, 0); 32362607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 32455163Sshin fatal("invalid route tag"); 32555163Sshin /*NOTREACHED*/ 32655163Sshin } 32755163Sshin break; 32855163Sshin case 'R': 32962607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 33055163Sshin fatal("Can not write to routelog"); 33162607Sitojun /*NOTREACHED*/ 33262607Sitojun } 33355163Sshin break; 33462607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 33562607Sitojun FLAG('a', aflag, 1); break; 33662607Sitojun FLAG('d', dflag, 1); break; 33762607Sitojun FLAG('D', dflag, 2); break; 33862607Sitojun FLAG('h', hflag, 1); break; 33962607Sitojun FLAG('l', lflag, 1); break; 34062607Sitojun FLAG('n', nflag, 1); break; 34162607Sitojun FLAG('q', qflag, 1); break; 34262607Sitojun FLAG('s', sflag, 1); break; 34362607Sitojun FLAG('S', Sflag, 1); break; 34455163Sshin#undef FLAG 34555163Sshin default: 34655163Sshin fatal("Invalid option specified, terminating"); 34762607Sitojun /*NOTREACHED*/ 34855163Sshin } 34955163Sshin } 35055163Sshin argc -= optind; 35155163Sshin argv += optind; 35278064Sume if (argc > 0) { 35355163Sshin fatal("bogus extra arguments"); 35478064Sume /*NOTREACHED*/ 35578064Sume } 35655163Sshin 35755163Sshin if (geteuid()) { 35855163Sshin nflag = 1; 35955163Sshin fprintf(stderr, "No kernel update is allowed\n"); 36055163Sshin } 361119037Sume 362119037Sume if (dflag == 0) { 363119037Sume if (daemon(0, 0) < 0) { 364119037Sume fatal("daemon"); 365119037Sume /*NOTREACHED*/ 366119037Sume } 367119037Sume } 368119037Sume 36955163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 37055163Sshin logopened++; 37178064Sume 37278064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 37378064Sume fatal("malloc"); 37478064Sume memset(ripbuf, 0, RIP6_MAXMTU); 37578064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 37678064Sume ripbuf->rip6_vers = RIP6_VERSION; 37778064Sume ripbuf->rip6_res1[0] = 0; 37878064Sume ripbuf->rip6_res1[1] = 0; 37978064Sume 38055163Sshin init(); 38155163Sshin ifconfig(); 38255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 38355163Sshin if (ifcp->ifc_index < 0) { 38455163Sshin fprintf(stderr, 38555163Sshin"No ifindex found at %s (no link-local address?)\n", 38655163Sshin ifcp->ifc_name); 38755163Sshin error++; 38855163Sshin } 38955163Sshin } 39055163Sshin if (error) 39155163Sshin exit(1); 39278064Sume if (loopifcp == NULL) { 39355163Sshin fatal("No loopback found"); 39478064Sume /*NOTREACHED*/ 39578064Sume } 396110666Sache#ifdef __FreeBSD__ 397110666Sache sranddev(); 398110666Sache#else 399110666Sache srand((unsigned)(time(NULL)^(pid<<16))); 400110666Sache#endif 40155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 40255163Sshin ifrt(ifcp, 0); 40355163Sshin filterconfig(); 40455163Sshin krtread(0); 40555163Sshin if (dflag) 40655163Sshin ifrtdump(0); 40755163Sshin 40855163Sshin pid = getpid(); 40955163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 41055163Sshin fprintf(pidfile, "%d\n", pid); 41155163Sshin fclose(pidfile); 41255163Sshin } 41355163Sshin 41478064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 41555163Sshin fatal("malloc"); 41678064Sume /*NOTREACHED*/ 41778064Sume } 41862607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 41955163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 42055163Sshin ripbuf->rip6_vers = RIP6_VERSION; 42155163Sshin ripbuf->rip6_res1[0] = 0; 42255163Sshin ripbuf->rip6_res1[1] = 0; 42355163Sshin 42478064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 42578064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 42678064Sume signal(SIGTERM, sighandler) == SIG_ERR || 42778064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 42878064Sume signal(SIGHUP, sighandler) == SIG_ERR || 42978064Sume signal(SIGINT, sighandler) == SIG_ERR) { 43078064Sume fatal("signal"); 43178064Sume /*NOTREACHED*/ 43278064Sume } 43355163Sshin /* 43455163Sshin * To avoid rip packet congestion (not on a cable but in this 43555163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 43655163Sshin * packets. 43755163Sshin */ 43855163Sshin alarm(ripinterval(INIT_INTERVAL6)); 43955163Sshin 44055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 441119041Sume if (iff_find(ifcp, 'N')) 442119041Sume continue; 44355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 44455163Sshin sendrequest(ifcp); 44555163Sshin } 44655163Sshin 44755163Sshin syslog(LOG_INFO, "**** Started ****"); 44855163Sshin sigemptyset(&mask); 44955163Sshin sigaddset(&mask, SIGALRM); 45055163Sshin while (1) { 45178064Sume if (seenalrm) { 45278064Sume ripalarm(); 45378064Sume seenalrm = 0; 45478064Sume continue; 45578064Sume } 45678064Sume if (seenquit) { 45778064Sume rtdexit(); 45878064Sume seenquit = 0; 45978064Sume continue; 46078064Sume } 46178064Sume if (seenusr1) { 46278064Sume ifrtdump(SIGUSR1); 46378064Sume seenusr1 = 0; 46478064Sume continue; 46578064Sume } 46678064Sume 46778064Sume signo = 0; 468119076Sume#ifdef HAVE_POLL_H 469119076Sume switch (poll(set, 2, INFTIM)) 470119076Sume#else 471119070Sume memcpy(recvecp, sockvecp, fdmasks); 472119076Sume switch (select(maxfd + 1, recvecp, 0, 0, 0)) 473119076Sume#endif 474119076Sume { 47555163Sshin case -1: 47678064Sume if (errno != EINTR) { 47778064Sume fatal("select"); 47878064Sume /*NOTREACHED*/ 47978064Sume } 48078064Sume continue; 48155163Sshin case 0: 48255163Sshin continue; 48355163Sshin default: 484119076Sume#ifdef HAVE_POLL_H 485119076Sume if (set[0].revents & POLLIN) 486119076Sume#else 487119076Sume if (FD_ISSET(ripsock, recvecp)) 488119076Sume#endif 489119076Sume { 49055163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 49155163Sshin riprecv(); 49255163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 49355163Sshin } 494119076Sume#ifdef HAVE_POLL_H 495119076Sume if (set[1].revents & POLLIN) 496119076Sume#else 497119076Sume if (FD_ISSET(rtsock, recvecp)) 498119076Sume#endif 499119076Sume { 50055163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 50155163Sshin rtrecv(); 50255163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 50355163Sshin } 50455163Sshin } 50555163Sshin } 50655163Sshin} 50755163Sshin 50878064Sumevoid 50978064Sumesighandler(sig) 51078064Sume int sig; 51178064Sume{ 51278064Sume 51378064Sume signo = sig; 51478064Sume switch (signo) { 51578064Sume case SIGALRM: 51678064Sume seenalrm++; 51778064Sume break; 51878064Sume case SIGQUIT: 51978064Sume case SIGTERM: 52078064Sume seenquit++; 52178064Sume break; 52278064Sume case SIGUSR1: 52378064Sume case SIGHUP: 52478064Sume case SIGINT: 52578064Sume seenusr1++; 52678064Sume break; 52778064Sume } 52878064Sume} 52978064Sume 53055163Sshin/* 53155163Sshin * gracefully exits after resetting sockopts. 53255163Sshin */ 53355163Sshin/* ARGSUSED */ 53455163Sshinvoid 53578064Sumertdexit() 53655163Sshin{ 53755163Sshin struct riprt *rrt; 53855163Sshin 53955163Sshin alarm(0); 54055163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 54162607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 54255163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 54355163Sshin } 54455163Sshin } 54555163Sshin close(ripsock); 54655163Sshin close(rtsock); 54755163Sshin syslog(LOG_INFO, "**** Terminated ****"); 54855163Sshin closelog(); 54955163Sshin exit(1); 55055163Sshin} 55155163Sshin 55255163Sshin/* 55355163Sshin * Called periodically: 55455163Sshin * 1. age out the learned route. remove it if necessary. 55555163Sshin * 2. submit RIP6_RESPONSE packets. 55678064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 55755163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 55855163Sshin * routes more precisely. 55955163Sshin */ 56055163Sshin/* ARGSUSED */ 56155163Sshinvoid 56278064Sumeripalarm() 56355163Sshin{ 56455163Sshin struct ifc *ifcp; 56555163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 56655163Sshin time_t t_lifetime, t_holddown; 56755163Sshin 56855163Sshin /* age the RIP routes */ 56955163Sshin rrt_prev = 0; 57055163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 57155163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 57255163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 57355163Sshin rrt_next = rrt->rrt_next; 57455163Sshin 57555163Sshin if (rrt->rrt_t == 0) { 57655163Sshin rrt_prev = rrt; 57755163Sshin continue; 57855163Sshin } 57955163Sshin if (rrt->rrt_t < t_holddown) { 58055163Sshin if (rrt_prev) { 58155163Sshin rrt_prev->rrt_next = rrt->rrt_next; 58255163Sshin } else { 58355163Sshin riprt = rrt->rrt_next; 58455163Sshin } 58555163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 58655163Sshin free(rrt); 58755163Sshin continue; 58855163Sshin } 58955163Sshin if (rrt->rrt_t < t_lifetime) 59055163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 59155163Sshin rrt_prev = rrt; 59255163Sshin } 59355163Sshin /* Supply updates */ 59455163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 59555163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 59655163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 59755163Sshin } 59855163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 59955163Sshin} 60055163Sshin 60155163Sshinvoid 60255163Sshininit() 60355163Sshin{ 604119034Sume int error; 605119034Sume const int int0 = 0, int1 = 1, int255 = 255; 60655163Sshin struct addrinfo hints, *res; 60755163Sshin char port[10]; 60855163Sshin 60955163Sshin ifc = (struct ifc *)NULL; 61055163Sshin nifc = 0; 61155163Sshin nindex2ifc = 0; /*initial guess*/ 61255163Sshin index2ifc = NULL; 61355163Sshin snprintf(port, sizeof(port), "%d", RIP6_PORT); 61455163Sshin 61555163Sshin memset(&hints, 0, sizeof(hints)); 61655163Sshin hints.ai_family = PF_INET6; 61755163Sshin hints.ai_socktype = SOCK_DGRAM; 61855163Sshin hints.ai_flags = AI_PASSIVE; 61955163Sshin error = getaddrinfo(NULL, port, &hints, &res); 62078064Sume if (error) { 62166807Skris fatal("%s", gai_strerror(error)); 62278064Sume /*NOTREACHED*/ 62378064Sume } 62478064Sume if (res->ai_next) { 62555163Sshin fatal(":: resolved to multiple address"); 62678064Sume /*NOTREACHED*/ 62778064Sume } 62855163Sshin 62955163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 63078064Sume if (ripsock < 0) { 63155163Sshin fatal("rip socket"); 63278064Sume /*NOTREACHED*/ 63378064Sume } 634119034Sume#ifdef IPV6_V6ONLY 635119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 636119034Sume &int1, sizeof(int1)) < 0) { 637119034Sume fatal("rip IPV6_V6ONLY"); 638119034Sume /*NOTREACHED*/ 639119034Sume } 640119034Sume#endif 64178064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 64255163Sshin fatal("rip bind"); 64378064Sume /*NOTREACHED*/ 64478064Sume } 64555163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 64678064Sume &int255, sizeof(int255)) < 0) { 64755163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 64878064Sume /*NOTREACHED*/ 64978064Sume } 65055163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 65178064Sume &int0, sizeof(int0)) < 0) { 65255163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 65378064Sume /*NOTREACHED*/ 65478064Sume } 65562921Sume 65662607Sitojun#ifdef IPV6_RECVPKTINFO 657119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 658119034Sume &int1, sizeof(int1)) < 0) { 65962607Sitojun fatal("rip IPV6_RECVPKTINFO"); 66078064Sume /*NOTREACHED*/ 66178064Sume } 66262607Sitojun#else /* old adv. API */ 663119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 664119034Sume &int1, sizeof(int1)) < 0) { 66555163Sshin fatal("rip IPV6_PKTINFO"); 66678064Sume /*NOTREACHED*/ 66778064Sume } 66862607Sitojun#endif 66955163Sshin 67055163Sshin memset(&hints, 0, sizeof(hints)); 67155163Sshin hints.ai_family = PF_INET6; 67255163Sshin hints.ai_socktype = SOCK_DGRAM; 67355163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 67478064Sume if (error) { 67566807Skris fatal("%s", gai_strerror(error)); 67678064Sume /*NOTREACHED*/ 67778064Sume } 67878064Sume if (res->ai_next) { 67955163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 68078064Sume /*NOTREACHED*/ 68178064Sume } 68255163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 68355163Sshin 684119076Sume#ifdef HAVE_POLL_H 685119076Sume set[0].fd = ripsock; 686119076Sume set[0].events = POLLIN; 687119076Sume#else 688119070Sume maxfd = ripsock; 689119076Sume#endif 69055163Sshin 69155163Sshin if (nflag == 0) { 69278064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 69355163Sshin fatal("route socket"); 69478064Sume /*NOTREACHED*/ 69578064Sume } 696119076Sume#ifdef HAVE_POLL_H 697119076Sume set[1].fd = rtsock; 698119076Sume set[1].events = POLLIN; 699119076Sume#else 700119070Sume if (rtsock > maxfd) 701119070Sume maxfd = rtsock; 702119076Sume#endif 703119076Sume } else { 704119076Sume#ifdef HAVE_POLL_H 705119076Sume set[1].fd = -1; 706119076Sume#else 70755163Sshin rtsock = -1; /*just for safety */ 708119076Sume#endif 709119076Sume } 710119070Sume 711119076Sume#ifndef HAVE_POLL_H 712119070Sume fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 713119070Sume if ((sockvecp = malloc(fdmasks)) == NULL) { 714119070Sume fatal("malloc"); 715119070Sume /*NOTREACHED*/ 716119070Sume } 717119070Sume if ((recvecp = malloc(fdmasks)) == NULL) { 718119070Sume fatal("malloc"); 719119070Sume /*NOTREACHED*/ 720119070Sume } 721119070Sume memset(sockvecp, 0, fdmasks); 722119070Sume FD_SET(ripsock, sockvecp); 723119070Sume if (rtsock >= 0) 724119070Sume FD_SET(rtsock, sockvecp); 725119076Sume#endif 72655163Sshin} 72755163Sshin 72862607Sitojun#define RIPSIZE(n) \ 72962607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 73055163Sshin 73155163Sshin/* 73255163Sshin * ripflush flushes the rip datagram stored in the rip buffer 73355163Sshin */ 73455163Sshinstatic int nrt; 73555163Sshinstatic struct netinfo6 *np; 73655163Sshin 73755163Sshinvoid 738119031Sumeripflush(ifcp, sin6) 73955163Sshin struct ifc *ifcp; 740119031Sume struct sockaddr_in6 *sin6; 74155163Sshin{ 74255163Sshin int i; 74355163Sshin int error; 74455163Sshin 74555163Sshin if (ifcp) 74655163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 74755163Sshin ifcp->ifc_name, nrt, 748119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 74955163Sshin else 75055163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 751119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 75255163Sshin if (dflag >= 2) { 75355163Sshin np = ripbuf->rip6_nets; 75455163Sshin for (i = 0; i < nrt; i++, np++) { 75555163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 75655163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 75762607Sitojun trace(2, " NextHop reset"); 75855163Sshin else { 75955163Sshin trace(2, " NextHop %s", 76055163Sshin inet6_n2p(&np->rip6_dest)); 76155163Sshin } 76255163Sshin } else { 76355163Sshin trace(2, " %s/%d[%d]", 76455163Sshin inet6_n2p(&np->rip6_dest), 76555163Sshin np->rip6_plen, np->rip6_metric); 76655163Sshin } 76755163Sshin if (np->rip6_tag) { 76855163Sshin trace(2, " tag=0x%04x", 76955163Sshin ntohs(np->rip6_tag) & 0xffff); 77055163Sshin } 77155163Sshin trace(2, "\n"); 77255163Sshin } 77355163Sshin } 774119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 77555163Sshin if (error == EAFNOSUPPORT) { 77655163Sshin /* Protocol not supported */ 77755163Sshin tracet(1, "Could not send info to %s (%s): " 77855163Sshin "set IFF_UP to 0\n", 77955163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 78055163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 78155163Sshin } 78255163Sshin nrt = 0; np = ripbuf->rip6_nets; 78355163Sshin} 78455163Sshin 78555163Sshin/* 78655163Sshin * Generate RIP6_RESPONSE packets and send them. 78755163Sshin */ 78855163Sshinvoid 789119031Sumeripsend(ifcp, sin6, flag) 79055163Sshin struct ifc *ifcp; 791119031Sume struct sockaddr_in6 *sin6; 79255163Sshin int flag; 79355163Sshin{ 79455163Sshin struct riprt *rrt; 79555163Sshin struct in6_addr *nh; /* next hop */ 79678064Sume int maxrte; 79755163Sshin 79855163Sshin if (ifcp == NULL) { 79955163Sshin /* 80055163Sshin * Request from non-link local address is not 80155163Sshin * a regular route6d update. 80255163Sshin */ 80362607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 80462607Sitojun sizeof(struct udphdr) - 80555163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 80655163Sshin sizeof(struct netinfo6); 80755163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 80855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 80962607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 81055163Sshin continue; 81155163Sshin /* Put the route to the buffer */ 81255163Sshin *np = rrt->rrt_info; 81355163Sshin np++; nrt++; 81455163Sshin if (nrt == maxrte) { 815119031Sume ripflush(NULL, sin6); 81655163Sshin nh = NULL; 81755163Sshin } 81855163Sshin } 81955163Sshin if (nrt) /* Send last packet */ 820119031Sume ripflush(NULL, sin6); 82155163Sshin return; 82255163Sshin } 82355163Sshin 82462607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 82555163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 82655163Sshin return; 82778064Sume 82878064Sume /* -N: no use */ 82955163Sshin if (iff_find(ifcp, 'N') != NULL) 83055163Sshin return; 83178064Sume 83278064Sume /* -T: generate default route only */ 83355163Sshin if (iff_find(ifcp, 'T') != NULL) { 83455163Sshin struct netinfo6 rrt_info; 83555163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 83655163Sshin rrt_info.rip6_dest = in6addr_any; 83755163Sshin rrt_info.rip6_plen = 0; 83855163Sshin rrt_info.rip6_metric = 1; 83978064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 84055163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 84155163Sshin np = ripbuf->rip6_nets; 84255163Sshin *np = rrt_info; 84355163Sshin nrt = 1; 844119031Sume ripflush(ifcp, sin6); 84555163Sshin return; 84655163Sshin } 84778064Sume 84862607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 84962607Sitojun sizeof(struct udphdr) - 85055163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 85155163Sshin sizeof(struct netinfo6); 85278064Sume 85355163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 85455163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 85562607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 85655163Sshin continue; 85778064Sume 85878064Sume /* Need to check filter here */ 85978064Sume if (out_filter(rrt, ifcp) == 0) 86055163Sshin continue; 86178064Sume 86255163Sshin /* Check split horizon and other conditions */ 86355163Sshin if (tobeadv(rrt, ifcp) == 0) 86455163Sshin continue; 86578064Sume 86655163Sshin /* Only considers the routes with flag if specified */ 86762607Sitojun if ((flag & RRTF_CHANGED) && 86862607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 86955163Sshin continue; 87078064Sume 87155163Sshin /* Check nexthop */ 87255163Sshin if (rrt->rrt_index == ifcp->ifc_index && 87355163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 87462607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 87555163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 87655163Sshin if (nrt == maxrte - 2) 877119031Sume ripflush(ifcp, sin6); 87855163Sshin np->rip6_dest = rrt->rrt_gw; 87955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 88055163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 88155163Sshin np->rip6_plen = 0; 88255163Sshin np->rip6_tag = 0; 88355163Sshin np->rip6_metric = NEXTHOP_METRIC; 88455163Sshin nh = &rrt->rrt_gw; 88555163Sshin np++; nrt++; 88655163Sshin } 88755163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 88855163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 88962607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 89055163Sshin /* Reset nexthop */ 89155163Sshin if (nrt == maxrte - 2) 892119031Sume ripflush(ifcp, sin6); 89355163Sshin memset(np, 0, sizeof(struct netinfo6)); 89455163Sshin np->rip6_metric = NEXTHOP_METRIC; 89555163Sshin nh = NULL; 89655163Sshin np++; nrt++; 89755163Sshin } 89878064Sume 89955163Sshin /* Put the route to the buffer */ 90055163Sshin *np = rrt->rrt_info; 90155163Sshin np++; nrt++; 90255163Sshin if (nrt == maxrte) { 903119031Sume ripflush(ifcp, sin6); 90455163Sshin nh = NULL; 90555163Sshin } 90655163Sshin } 90755163Sshin if (nrt) /* Send last packet */ 908119031Sume ripflush(ifcp, sin6); 90955163Sshin} 91055163Sshin 91155163Sshin/* 91278064Sume * outbound filter logic, per-route/interface. 91378064Sume */ 91478064Sumeint 91578064Sumeout_filter(rrt, ifcp) 91678064Sume struct riprt *rrt; 91778064Sume struct ifc *ifcp; 91878064Sume{ 91978064Sume struct iff *iffp; 92078064Sume struct in6_addr ia; 92178064Sume int ok; 92278064Sume 92378064Sume /* 92478064Sume * -A: filter out less specific routes, if we have aggregated 92578064Sume * route configured. 92678064Sume */ 92778064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 92878064Sume if (iffp->iff_type != 'A') 92978064Sume continue; 93078064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 93178064Sume continue; 93278064Sume ia = rrt->rrt_info.rip6_dest; 93378064Sume applyplen(&ia, iffp->iff_plen); 93478064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 93578064Sume return 0; 93678064Sume } 93778064Sume 93878064Sume /* 93978064Sume * if it is an aggregated route, advertise it only to the 94078064Sume * interfaces specified on -A. 94178064Sume */ 94278064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 94378064Sume ok = 0; 94478064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 94578064Sume if (iffp->iff_type != 'A') 94678064Sume continue; 94778064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 94878064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 94978064Sume &iffp->iff_addr)) { 95078064Sume ok = 1; 95178064Sume break; 95278064Sume } 95378064Sume } 95478064Sume if (!ok) 95578064Sume return 0; 95678064Sume } 95778064Sume 95878064Sume /* 95978064Sume * -O: advertise only if prefix matches the configured prefix. 96078064Sume */ 96178064Sume if (iff_find(ifcp, 'O')) { 96278064Sume ok = 0; 96378064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 96478064Sume if (iffp->iff_type != 'O') 96578064Sume continue; 96678064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 96778064Sume continue; 96878064Sume ia = rrt->rrt_info.rip6_dest; 96978064Sume applyplen(&ia, iffp->iff_plen); 97078064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 97178064Sume ok = 1; 97278064Sume break; 97378064Sume } 97478064Sume } 97578064Sume if (!ok) 97678064Sume return 0; 97778064Sume } 97878064Sume 97978064Sume /* the prefix should be advertised */ 98078064Sume return 1; 98178064Sume} 98278064Sume 98378064Sume/* 98455163Sshin * Determine if the route is to be advertised on the specified interface. 98555163Sshin * It checks options specified in the arguments and the split horizon rule. 98655163Sshin */ 98755163Sshinint 98855163Sshintobeadv(rrt, ifcp) 98955163Sshin struct riprt *rrt; 99055163Sshin struct ifc *ifcp; 99155163Sshin{ 99255163Sshin 99355163Sshin /* Special care for static routes */ 99455163Sshin if (rrt->rrt_flags & RTF_STATIC) { 99562607Sitojun /* XXX don't advertise reject/blackhole routes */ 99662607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 99762607Sitojun return 0; 99862607Sitojun 99955163Sshin if (Sflag) /* Yes, advertise it anyway */ 100055163Sshin return 1; 100155163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 100255163Sshin return 1; 100355163Sshin return 0; 100455163Sshin } 100555163Sshin /* Regular split horizon */ 100655163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 100755163Sshin return 0; 100855163Sshin return 1; 100955163Sshin} 101055163Sshin 101155163Sshin/* 101255163Sshin * Send a rip packet actually. 101355163Sshin */ 101455163Sshinint 1015119031Sumesendpacket(sin6, len) 1016119031Sume struct sockaddr_in6 *sin6; 101755163Sshin int len; 101855163Sshin{ 101955163Sshin /* 102055163Sshin * MSG_DONTROUTE should not be specified when it responds with a 102178064Sume * RIP6_REQUEST message. SO_DONTROUTE has been specified to 102255163Sshin * other sockets. 102355163Sshin */ 102455163Sshin struct msghdr m; 102555163Sshin struct cmsghdr *cm; 102655163Sshin struct iovec iov[2]; 102755163Sshin u_char cmsgbuf[256]; 102855163Sshin struct in6_pktinfo *pi; 102978064Sume int idx; 103055163Sshin struct sockaddr_in6 sincopy; 103155163Sshin 103255163Sshin /* do not overwrite the given sin */ 1033119031Sume sincopy = *sin6; 1034119031Sume sin6 = &sincopy; 103555163Sshin 1036119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 1037119035Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 1038119031Sume idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 1039119031Sume SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 104055163Sshin } else 104178064Sume idx = 0; 104255163Sshin 1043119031Sume m.msg_name = (caddr_t)sin6; 1044119031Sume m.msg_namelen = sizeof(*sin6); 104555163Sshin iov[0].iov_base = (caddr_t)ripbuf; 104655163Sshin iov[0].iov_len = len; 104755163Sshin m.msg_iov = iov; 104855163Sshin m.msg_iovlen = 1; 104978064Sume if (!idx) { 105055163Sshin m.msg_control = NULL; 105155163Sshin m.msg_controllen = 0; 105255163Sshin } else { 105355163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 105455163Sshin cm = (struct cmsghdr *)cmsgbuf; 105555163Sshin m.msg_control = (caddr_t)cm; 105655163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 105755163Sshin 105855163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 105955163Sshin cm->cmsg_level = IPPROTO_IPV6; 106055163Sshin cm->cmsg_type = IPV6_PKTINFO; 106155163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 106255163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 106378064Sume pi->ipi6_ifindex = idx; 106455163Sshin } 106555163Sshin 106655163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 106755163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 106855163Sshin return errno; 106955163Sshin } 107062921Sume 107155163Sshin return 0; 107255163Sshin} 107355163Sshin 107455163Sshin/* 107578064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 107655163Sshin * table if necessary. 107755163Sshin */ 107855163Sshinvoid 107955163Sshinriprecv() 108055163Sshin{ 108155163Sshin struct ifc *ifcp, *ic; 108255163Sshin struct sockaddr_in6 fsock; 108355163Sshin struct in6_addr nh; /* next hop */ 108455163Sshin struct rip6 *rp; 108555163Sshin struct netinfo6 *np, *nq; 108655163Sshin struct riprt *rrt; 108778064Sume int len, nn, need_trigger, idx; 108855163Sshin char buf[4 * RIP6_MAXMTU]; 108955163Sshin time_t t; 109055163Sshin struct msghdr m; 109155163Sshin struct cmsghdr *cm; 109255163Sshin struct iovec iov[2]; 109355163Sshin u_char cmsgbuf[256]; 109455163Sshin struct in6_pktinfo *pi; 109555163Sshin struct iff *iffp; 109655163Sshin struct in6_addr ia; 109755163Sshin int ok; 109878064Sume time_t t_half_lifetime; 109955163Sshin 110055163Sshin need_trigger = 0; 110162921Sume 110255163Sshin m.msg_name = (caddr_t)&fsock; 110355163Sshin m.msg_namelen = sizeof(fsock); 110455163Sshin iov[0].iov_base = (caddr_t)buf; 110555163Sshin iov[0].iov_len = sizeof(buf); 110655163Sshin m.msg_iov = iov; 110755163Sshin m.msg_iovlen = 1; 110855163Sshin cm = (struct cmsghdr *)cmsgbuf; 110955163Sshin m.msg_control = (caddr_t)cm; 111055163Sshin m.msg_controllen = sizeof(cmsgbuf); 111178064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 111255163Sshin fatal("recvmsg"); 111378064Sume /*NOTREACHED*/ 111478064Sume } 111578064Sume idx = 0; 111655163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 111755163Sshin cm; 111855163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 111978064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 112078064Sume cm->cmsg_type == IPV6_PKTINFO) { 112155163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 112278064Sume idx = pi->ipi6_ifindex; 112355163Sshin break; 112455163Sshin } 112555163Sshin } 112678064Sume if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 112778064Sume SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 112855163Sshin 112955163Sshin nh = fsock.sin6_addr; 113055163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 113155163Sshin sizeof(struct netinfo6); 113255163Sshin rp = (struct rip6 *)buf; 113355163Sshin np = rp->rip6_nets; 113455163Sshin 1135119035Sume if (rp->rip6_vers != RIP6_VERSION) { 113655163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 113755163Sshin return; 113855163Sshin } 113955163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 114078064Sume if (idx && idx < nindex2ifc) { 114178064Sume ifcp = index2ifc[idx]; 114255163Sshin riprequest(ifcp, np, nn, &fsock); 114355163Sshin } else { 114455163Sshin riprequest(NULL, np, nn, &fsock); 114555163Sshin } 114662607Sitojun return; 114762607Sitojun } 114855163Sshin 114955163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 115055163Sshin trace(1, "Packets from non-ll addr: %s\n", 115178064Sume inet6_n2p(&fsock.sin6_addr)); 115255163Sshin return; /* Ignore packets from non-link-local addr */ 115355163Sshin } 115478064Sume idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 115578064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 115655163Sshin if (!ifcp) { 115778064Sume trace(1, "Packets to unknown interface index %d\n", idx); 115855163Sshin return; /* Ignore it */ 115955163Sshin } 116055163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 116155163Sshin return; /* The packet is from me; ignore */ 116255163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 116355163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 116462607Sitojun return; 116555163Sshin } 116678064Sume 116778064Sume /* -N: no use */ 116855163Sshin if (iff_find(ifcp, 'N') != NULL) 116955163Sshin return; 117078064Sume 117155163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 117278064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 117355163Sshin 117455163Sshin t = time(NULL); 117578064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 117655163Sshin for (; nn; nn--, np++) { 117755163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 117855163Sshin /* modify neighbor address */ 117955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 118055163Sshin nh = np->rip6_dest; 118178064Sume SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 118255163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 118355163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 118455163Sshin nh = fsock.sin6_addr; 118555163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 118655163Sshin } else { 118755163Sshin nh = fsock.sin6_addr; 118855163Sshin trace(1, "\tInvalid Nexthop: %s\n", 118978064Sume inet6_n2p(&np->rip6_dest)); 119055163Sshin } 119155163Sshin continue; 119255163Sshin } 119355163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 119455163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 119555163Sshin inet6_n2p(&np->rip6_dest), 119655163Sshin np->rip6_plen, np->rip6_metric); 119755163Sshin continue; 119855163Sshin } 119955163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 120055163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 120155163Sshin inet6_n2p(&np->rip6_dest), 120255163Sshin np->rip6_plen, np->rip6_metric); 120355163Sshin continue; 120455163Sshin } 120555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 120655163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 120755163Sshin inet6_n2p(&np->rip6_dest), 120855163Sshin np->rip6_plen, np->rip6_metric); 120955163Sshin continue; 121055163Sshin } 121155163Sshin /* may need to pass sitelocal prefix in some case, however*/ 121255163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 121355163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 121455163Sshin inet6_n2p(&np->rip6_dest), 121555163Sshin np->rip6_plen, np->rip6_metric); 121655163Sshin continue; 121755163Sshin } 121855163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 121955163Sshin inet6_n2p(&np->rip6_dest), 122055163Sshin np->rip6_plen, np->rip6_metric); 122155163Sshin if (np->rip6_tag) 122255163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 122362607Sitojun if (dflag >= 2) { 122462607Sitojun ia = np->rip6_dest; 122562607Sitojun applyplen(&ia, np->rip6_plen); 122662607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 122762607Sitojun trace(2, " [junk outside prefix]"); 122862607Sitojun } 122955163Sshin 123078064Sume /* 123178064Sume * -L: listen only if the prefix matches the configuration 123278064Sume */ 123355163Sshin ok = 1; /* if there's no L filter, it is ok */ 123455163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 123555163Sshin if (iffp->iff_type != 'L') 123655163Sshin continue; 123755163Sshin ok = 0; 123855163Sshin if (np->rip6_plen < iffp->iff_plen) 123955163Sshin continue; 124055163Sshin /* special rule: ::/0 means default, not "in /0" */ 124155163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 124255163Sshin continue; 124362607Sitojun ia = np->rip6_dest; 124455163Sshin applyplen(&ia, iffp->iff_plen); 124555163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 124655163Sshin ok = 1; 124755163Sshin break; 124855163Sshin } 124955163Sshin } 125055163Sshin if (!ok) { 125155163Sshin trace(2, " (filtered)\n"); 125255163Sshin continue; 125355163Sshin } 125455163Sshin 125555163Sshin trace(2, "\n"); 125655163Sshin np->rip6_metric++; 125755163Sshin np->rip6_metric += ifcp->ifc_metric; 125855163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 125955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 126055163Sshin 126155163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 126278064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 126355163Sshin if (rrt->rrt_t == 0) 126455163Sshin continue; /* Intf route has priority */ 126555163Sshin nq = &rrt->rrt_info; 126655163Sshin if (nq->rip6_metric > np->rip6_metric) { 126755163Sshin if (rrt->rrt_index == ifcp->ifc_index && 126855163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 126955163Sshin /* Small metric from the same gateway */ 127055163Sshin nq->rip6_metric = np->rip6_metric; 127155163Sshin } else { 127255163Sshin /* Better route found */ 127355163Sshin rrt->rrt_index = ifcp->ifc_index; 127455163Sshin /* Update routing table */ 127555163Sshin delroute(nq, &rrt->rrt_gw); 127655163Sshin rrt->rrt_gw = nh; 127755163Sshin *nq = *np; 127855163Sshin addroute(rrt, &nh, ifcp); 127955163Sshin } 128062607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 128155163Sshin rrt->rrt_t = t; 128255163Sshin need_trigger = 1; 128355163Sshin } else if (nq->rip6_metric < np->rip6_metric && 128455163Sshin rrt->rrt_index == ifcp->ifc_index && 128555163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 128655163Sshin /* Got worse route from same gw */ 128755163Sshin nq->rip6_metric = np->rip6_metric; 128855163Sshin rrt->rrt_t = t; 128962607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 129055163Sshin need_trigger = 1; 129155163Sshin } else if (nq->rip6_metric == np->rip6_metric && 129255163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 129378064Sume if (rrt->rrt_index == ifcp->ifc_index && 129478064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 129578064Sume /* same metric, same route from same gw */ 129678064Sume rrt->rrt_t = t; 129778064Sume } else if (rrt->rrt_t < t_half_lifetime) { 129878064Sume /* Better route found */ 129978064Sume rrt->rrt_index = ifcp->ifc_index; 130078064Sume /* Update routing table */ 130178064Sume delroute(nq, &rrt->rrt_gw); 130278064Sume rrt->rrt_gw = nh; 130378064Sume *nq = *np; 130478064Sume addroute(rrt, &nh, ifcp); 130578064Sume rrt->rrt_rflags |= RRTF_CHANGED; 130678064Sume rrt->rrt_t = t; 130778064Sume } 130855163Sshin } 130962607Sitojun /* 131055163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 131178064Sume * do not update age value. Do nothing. 131255163Sshin */ 131355163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 131455163Sshin /* Got a new valid route */ 131578064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 131655163Sshin fatal("malloc: struct riprt"); 131778064Sume /*NOTREACHED*/ 131878064Sume } 131962607Sitojun memset(rrt, 0, sizeof(*rrt)); 132055163Sshin nq = &rrt->rrt_info; 132155163Sshin 132255163Sshin rrt->rrt_same = NULL; 132355163Sshin rrt->rrt_index = ifcp->ifc_index; 132455163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 132555163Sshin rrt->rrt_gw = nh; 132655163Sshin *nq = *np; 132755163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 132855163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 132955163Sshin rrt->rrt_flags |= RTF_HOST; 133055163Sshin 133155163Sshin /* Put the route to the list */ 133255163Sshin rrt->rrt_next = riprt; 133355163Sshin riprt = rrt; 133455163Sshin /* Update routing table */ 133555163Sshin addroute(rrt, &nh, ifcp); 133662607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 133755163Sshin need_trigger = 1; 133855163Sshin rrt->rrt_t = t; 133955163Sshin } 134055163Sshin } 134155163Sshin /* XXX need to care the interval between triggered updates */ 134255163Sshin if (need_trigger) { 134355163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 134455163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 134555163Sshin if (ifcp->ifc_index == ic->ifc_index) 134655163Sshin continue; 134755163Sshin if (ic->ifc_flags & IFF_UP) 134855163Sshin ripsend(ic, &ic->ifc_ripsin, 134962607Sitojun RRTF_CHANGED); 135055163Sshin } 135155163Sshin } 135255163Sshin /* Reset the flag */ 135355163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 135462607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 135555163Sshin } 135655163Sshin} 135755163Sshin 135855163Sshin/* 135955163Sshin * Send all routes request packet to the specified interface. 136055163Sshin */ 136155163Sshinvoid 136255163Sshinsendrequest(ifcp) 136355163Sshin struct ifc *ifcp; 136455163Sshin{ 136555163Sshin struct netinfo6 *np; 136655163Sshin int error; 136755163Sshin 136855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 136955163Sshin return; 137055163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 137155163Sshin np = ripbuf->rip6_nets; 137255163Sshin memset(np, 0, sizeof(struct netinfo6)); 137355163Sshin np->rip6_metric = HOPCNT_INFINITY6; 137455163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 137555163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 137655163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 137755163Sshin if (error == EAFNOSUPPORT) { 137855163Sshin /* Protocol not supported */ 137955163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 138055163Sshin "set IFF_UP to 0\n", 138155163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 138255163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 138355163Sshin } 138455163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 138555163Sshin} 138655163Sshin 138755163Sshin/* 138855163Sshin * Process a RIP6_REQUEST packet. 138955163Sshin */ 139055163Sshinvoid 1391119031Sumeriprequest(ifcp, np, nn, sin6) 139255163Sshin struct ifc *ifcp; 139355163Sshin struct netinfo6 *np; 139455163Sshin int nn; 1395119031Sume struct sockaddr_in6 *sin6; 139655163Sshin{ 139755163Sshin int i; 139855163Sshin struct riprt *rrt; 139955163Sshin 140055163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 140155163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 140255163Sshin /* Specific response, don't split-horizon */ 140355163Sshin trace(1, "\tRIP Request\n"); 140455163Sshin for (i = 0; i < nn; i++, np++) { 140578064Sume rrt = rtsearch(np, NULL); 140655163Sshin if (rrt) 140755163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 140855163Sshin else 140955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 141055163Sshin } 1411119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 141255163Sshin return; 141355163Sshin } 141455163Sshin /* Whole routing table dump */ 141555163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1416119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 141755163Sshin} 141855163Sshin 141955163Sshin/* 142055163Sshin * Get information of each interface. 142155163Sshin */ 142255163Sshinvoid 142355163Sshinifconfig() 142455163Sshin{ 142562607Sitojun struct ifaddrs *ifap, *ifa; 142662607Sitojun struct ifc *ifcp; 142762607Sitojun struct ipv6_mreq mreq; 142862607Sitojun int s; 142962607Sitojun 143078064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 143162607Sitojun fatal("socket"); 143278064Sume /*NOTREACHED*/ 143378064Sume } 143462607Sitojun 143578064Sume if (getifaddrs(&ifap) != 0) { 143662607Sitojun fatal("getifaddrs"); 143778064Sume /*NOTREACHED*/ 143878064Sume } 143962607Sitojun 144062607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 144162607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 144262607Sitojun continue; 144362607Sitojun ifcp = ifc_find(ifa->ifa_name); 144462607Sitojun /* we are interested in multicast-capable interfaces */ 144562607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 144662607Sitojun continue; 144762607Sitojun if (!ifcp) { 144862607Sitojun /* new interface */ 144978064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 145062607Sitojun fatal("malloc: struct ifc"); 145178064Sume /*NOTREACHED*/ 145278064Sume } 145362607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 145462607Sitojun ifcp->ifc_index = -1; 145562607Sitojun ifcp->ifc_next = ifc; 145662607Sitojun ifc = ifcp; 145762607Sitojun nifc++; 145862607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 145962607Sitojun ifcp->ifc_addr = 0; 146062607Sitojun ifcp->ifc_filter = 0; 146162607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 146262607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 146362607Sitojun ifflags(ifcp->ifc_flags)); 146462607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 146562607Sitojun loopifcp = ifcp; 146662607Sitojun } else { 146762607Sitojun /* update flag, this may be up again */ 146862607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 146962607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 147062607Sitojun ifflags(ifcp->ifc_flags)); 147162607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 147278064Sume ifcp->ifc_cflags |= IFC_CHANGED; 147362607Sitojun } 147462607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 147562607Sitojun } 147662607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 147762607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 147862607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 147962607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 148062607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 148178064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 148278064Sume &mreq, sizeof(mreq)) < 0) { 148362607Sitojun fatal("IPV6_JOIN_GROUP"); 148478064Sume /*NOTREACHED*/ 148578064Sume } 148662607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 148762607Sitojun ifcp->ifc_joined++; 148862607Sitojun } 148962607Sitojun } 149062607Sitojun close(s); 149162607Sitojun freeifaddrs(ifap); 149255163Sshin} 149355163Sshin 149455163Sshinvoid 149562607Sitojunifconfig1(name, sa, ifcp, s) 149662607Sitojun const char *name; 149762607Sitojun const struct sockaddr *sa; 149855163Sshin struct ifc *ifcp; 149955163Sshin int s; 150055163Sshin{ 150155163Sshin struct in6_ifreq ifr; 1502119031Sume const struct sockaddr_in6 *sin6; 150355163Sshin struct ifac *ifa; 150455163Sshin int plen; 150555163Sshin char buf[BUFSIZ]; 150655163Sshin 1507119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1508119031Sume ifr.ifr_addr = *sin6; 1509119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 151078064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 151155163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 151278064Sume /*NOTREACHED*/ 151378064Sume } 151478064Sume plen = sin6mask2len(&ifr.ifr_addr); 1515119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 151655163Sshin /* same interface found */ 151755163Sshin /* need check if something changed */ 151855163Sshin /* XXX not yet implemented */ 151955163Sshin return; 152055163Sshin } 152155163Sshin /* 152255163Sshin * New address is found 152355163Sshin */ 152478064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 152555163Sshin fatal("malloc: struct ifac"); 152678064Sume /*NOTREACHED*/ 152778064Sume } 152862607Sitojun memset(ifa, 0, sizeof(*ifa)); 152955163Sshin ifa->ifa_conf = ifcp; 153055163Sshin ifa->ifa_next = ifcp->ifc_addr; 153155163Sshin ifcp->ifc_addr = ifa; 1532119031Sume ifa->ifa_addr = sin6->sin6_addr; 153355163Sshin ifa->ifa_plen = plen; 153455163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1535119031Sume ifr.ifr_addr = *sin6; 153678064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 153755163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 153878064Sume /*NOTREACHED*/ 153978064Sume } 154055163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 154155163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 154255163Sshin trace(1, "found address %s/%d -- %s\n", 154355163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 154455163Sshin } else { 154555163Sshin trace(1, "found address %s/%d\n", 154655163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 154755163Sshin } 154855163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 154955163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 155055163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 155155163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 155255163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 155355163Sshin ifcp->ifc_index); 155455163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 155555163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 155655163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 155755163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 155878064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 155955163Sshin fatal("ioctl: SIOCGIFMETRIC"); 156078064Sume /*NOTREACHED*/ 156178064Sume } 156255163Sshin ifcp->ifc_metric = ifr.ifr_metric; 156355163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 156455163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 156578064Sume } else 156678064Sume ifcp->ifc_cflags |= IFC_CHANGED; 156755163Sshin} 156855163Sshin 156955163Sshin/* 157055163Sshin * Receive and process routing messages. 157155163Sshin * Update interface information as necesssary. 157255163Sshin */ 157355163Sshinvoid 157455163Sshinrtrecv() 157555163Sshin{ 157655163Sshin char buf[BUFSIZ]; 157755163Sshin char *p, *q; 157855163Sshin struct rt_msghdr *rtm; 157955163Sshin struct ifa_msghdr *ifam; 158055163Sshin struct if_msghdr *ifm; 158155163Sshin int len; 158278064Sume struct ifc *ifcp, *ic; 158355163Sshin int iface = 0, rtable = 0; 158455163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 158578064Sume struct sockaddr_in6 mask; 158655163Sshin int i, addrs; 158778064Sume struct riprt *rrt; 158855163Sshin 158955163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 159055163Sshin perror("read from rtsock"); 159178064Sume exit(1); 159255163Sshin } 159355163Sshin if (len < sizeof(*rtm)) { 159469279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 159569279Sume len, (u_long)sizeof(*rtm)); 159655163Sshin return; 159755163Sshin } 1598119042Sume if (dflag >= 2) { 1599119042Sume fprintf(stderr, "rtmsg:\n"); 1600119042Sume for (i = 0; i < len; i++) { 1601119042Sume fprintf(stderr, "%02x ", buf[i] & 0xff); 1602119042Sume if (i % 16 == 15) fprintf(stderr, "\n"); 1603119042Sume } 1604119042Sume fprintf(stderr, "\n"); 1605119042Sume } 160655163Sshin 160755163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 160855163Sshin /* safety against bogus message */ 160955163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 161055163Sshin trace(1, "bogus rtmsg: length=%d\n", 161155163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 161255163Sshin break; 161355163Sshin } 161455163Sshin rtm = NULL; 161555163Sshin ifam = NULL; 161655163Sshin ifm = NULL; 161755163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 161855163Sshin case RTM_NEWADDR: 161955163Sshin case RTM_DELADDR: 162055163Sshin ifam = (struct ifa_msghdr *)p; 162155163Sshin addrs = ifam->ifam_addrs; 162255163Sshin q = (char *)(ifam + 1); 162355163Sshin break; 162455163Sshin case RTM_IFINFO: 162555163Sshin ifm = (struct if_msghdr *)p; 162655163Sshin addrs = ifm->ifm_addrs; 162755163Sshin q = (char *)(ifm + 1); 162855163Sshin break; 162955163Sshin default: 163055163Sshin rtm = (struct rt_msghdr *)p; 163155163Sshin addrs = rtm->rtm_addrs; 163255163Sshin q = (char *)(rtm + 1); 163355163Sshin if (rtm->rtm_version != RTM_VERSION) { 163455163Sshin trace(1, "unexpected rtmsg version %d " 163555163Sshin "(should be %d)\n", 163655163Sshin rtm->rtm_version, RTM_VERSION); 163755163Sshin continue; 163855163Sshin } 163955163Sshin if (rtm->rtm_pid == pid) { 164055163Sshin#if 0 164155163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 164255163Sshin#endif 164355163Sshin continue; 164455163Sshin } 164555163Sshin break; 164655163Sshin } 164755163Sshin memset(&rta, 0, sizeof(rta)); 164855163Sshin for (i = 0; i < RTAX_MAX; i++) { 164955163Sshin if (addrs & (1 << i)) { 165055163Sshin rta[i] = (struct sockaddr_in6 *)q; 165155163Sshin q += ROUNDUP(rta[i]->sin6_len); 165255163Sshin } 165355163Sshin } 165455163Sshin 165555163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 165655163Sshin rttypes((struct rt_msghdr *)p), addrs); 165755163Sshin if (dflag >= 2) { 165855163Sshin for (i = 0; 165955163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 166055163Sshin i++) { 166155163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 166255163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 166355163Sshin } 166455163Sshin fprintf(stderr, "\n"); 166555163Sshin } 166655163Sshin 166755163Sshin /* 166855163Sshin * Easy ones first. 166955163Sshin * 167055163Sshin * We may be able to optimize by using ifm->ifm_index or 167155163Sshin * ifam->ifam_index. For simplicity we don't do that here. 167255163Sshin */ 167355163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 167455163Sshin case RTM_NEWADDR: 167555163Sshin case RTM_IFINFO: 167655163Sshin iface++; 167755163Sshin continue; 167855163Sshin case RTM_ADD: 167955163Sshin rtable++; 168055163Sshin continue; 168155163Sshin case RTM_LOSING: 168255163Sshin case RTM_MISS: 168355163Sshin case RTM_RESOLVE: 168455163Sshin case RTM_GET: 168555163Sshin case RTM_LOCK: 168655163Sshin /* nothing to be done here */ 168755163Sshin trace(1, "\tnothing to be done, ignored\n"); 168855163Sshin continue; 168955163Sshin } 169055163Sshin 169155163Sshin#if 0 169255163Sshin if (rta[RTAX_DST] == NULL) { 169355163Sshin trace(1, "\tno destination, ignored\n"); 169462607Sitojun continue; 169555163Sshin } 169655163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 169755163Sshin trace(1, "\taf mismatch, ignored\n"); 169855163Sshin continue; 169955163Sshin } 170055163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 170155163Sshin trace(1, "\tlinklocal destination, ignored\n"); 170255163Sshin continue; 170355163Sshin } 170455163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 170555163Sshin trace(1, "\tloopback destination, ignored\n"); 170655163Sshin continue; /* Loopback */ 170755163Sshin } 170855163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 170955163Sshin trace(1, "\tmulticast destination, ignored\n"); 171055163Sshin continue; 171155163Sshin } 171255163Sshin#endif 171355163Sshin 171455163Sshin /* hard ones */ 171555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 171655163Sshin case RTM_NEWADDR: 171755163Sshin case RTM_IFINFO: 171855163Sshin case RTM_ADD: 171955163Sshin case RTM_LOSING: 172055163Sshin case RTM_MISS: 172155163Sshin case RTM_RESOLVE: 172255163Sshin case RTM_GET: 172355163Sshin case RTM_LOCK: 172455163Sshin /* should already be handled */ 172555163Sshin fatal("rtrecv: never reach here"); 172678064Sume /*NOTREACHED*/ 172755163Sshin case RTM_DELETE: 172878064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 172978064Sume trace(1, "\tsome of dst/gw/netamsk are " 173078064Sume "unavailable, ignored\n"); 173155163Sshin break; 173255163Sshin } 173378064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 173478064Sume mask.sin6_len = sizeof(mask); 173578064Sume memset(&mask.sin6_addr, 0xff, 173678064Sume sizeof(mask.sin6_addr)); 173778064Sume rta[RTAX_NETMASK] = &mask; 173878064Sume } else if (!rta[RTAX_NETMASK]) { 173978064Sume trace(1, "\tsome of dst/gw/netamsk are " 174078064Sume "unavailable, ignored\n"); 174178064Sume break; 174278064Sume } 174378064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 174478064Sume rta[RTAX_NETMASK]) == 0) { 174555163Sshin rtable++; /*just to be sure*/ 174655163Sshin } 174755163Sshin break; 174855163Sshin case RTM_CHANGE: 174955163Sshin case RTM_REDIRECT: 175055163Sshin trace(1, "\tnot supported yet, ignored\n"); 175155163Sshin break; 175255163Sshin case RTM_DELADDR: 175355163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 175455163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 175555163Sshin break; 175655163Sshin } 175755163Sshin if (ifam->ifam_index < nindex2ifc) 175855163Sshin ifcp = index2ifc[ifam->ifam_index]; 175955163Sshin else 176055163Sshin ifcp = NULL; 176155163Sshin if (!ifcp) { 176255163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 176355163Sshin ifam->ifam_index); 176455163Sshin break; 176555163Sshin } 176678064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 176778064Sume iface++; 176855163Sshin break; 176955163Sshin case RTM_OLDADD: 177055163Sshin case RTM_OLDDEL: 177155163Sshin trace(1, "\tnot supported yet, ignored\n"); 177255163Sshin break; 177355163Sshin } 177455163Sshin 177555163Sshin } 177655163Sshin 177755163Sshin if (iface) { 177855163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 177955163Sshin ifconfig(); 178055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 178178064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 178278064Sume if (ifrt(ifcp, 1)) { 178378064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 178478064Sume if (ifcp->ifc_index == ic->ifc_index) 178578064Sume continue; 178678064Sume if (ic->ifc_flags & IFF_UP) 178778064Sume ripsend(ic, &ic->ifc_ripsin, 178878064Sume RRTF_CHANGED); 178978064Sume } 179078064Sume /* Reset the flag */ 179178064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 179278064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 179378064Sume } 179478064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 179578064Sume } 179655163Sshin } 179755163Sshin if (rtable) { 179855163Sshin trace(1, "rtsock: read routing table again\n"); 179955163Sshin krtread(1); 180055163Sshin } 180155163Sshin} 180255163Sshin 180355163Sshin/* 180455163Sshin * remove specified route from the internal routing table. 180555163Sshin */ 180655163Sshinint 180755163Sshinrt_del(sdst, sgw, smask) 180855163Sshin const struct sockaddr_in6 *sdst; 180955163Sshin const struct sockaddr_in6 *sgw; 181055163Sshin const struct sockaddr_in6 *smask; 181155163Sshin{ 181255163Sshin const struct in6_addr *dst = NULL; 181355163Sshin const struct in6_addr *gw = NULL; 181455163Sshin int prefix; 181555163Sshin struct netinfo6 ni6; 181655163Sshin struct riprt *rrt = NULL; 181755163Sshin time_t t_lifetime; 181855163Sshin 181955163Sshin if (sdst->sin6_family != AF_INET6) { 182055163Sshin trace(1, "\tother AF, ignored\n"); 182155163Sshin return -1; 182255163Sshin } 182355163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 182455163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 182555163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 182655163Sshin trace(1, "\taddress %s not interesting, ignored\n", 182755163Sshin inet6_n2p(&sdst->sin6_addr)); 182855163Sshin return -1; 182955163Sshin } 183055163Sshin dst = &sdst->sin6_addr; 183178064Sume if (sgw->sin6_family == AF_INET6) { 183255163Sshin /* easy case */ 183355163Sshin gw = &sgw->sin6_addr; 183478064Sume prefix = sin6mask2len(smask); 183555163Sshin } else if (sgw->sin6_family == AF_LINK) { 183655163Sshin /* 183755163Sshin * Interface route... a hard case. We need to get the prefix 183855163Sshin * length from the kernel, but we now are parsing rtmsg. 183955163Sshin * We'll purge matching routes from my list, then get the 184055163Sshin * fresh list. 184155163Sshin */ 184255163Sshin struct riprt *longest; 1843108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 184455163Sshin inet6_n2p(dst)); 184555163Sshin longest = NULL; 184655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 184755163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 184855163Sshin &sdst->sin6_addr) 184955163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 185055163Sshin if (!longest 185155163Sshin || longest->rrt_info.rip6_plen < 185255163Sshin rrt->rrt_info.rip6_plen) { 185355163Sshin longest = rrt; 185455163Sshin } 185555163Sshin } 185655163Sshin } 185755163Sshin rrt = longest; 185855163Sshin if (!rrt) { 185955163Sshin trace(1, "\tno matching interface route found\n"); 186055163Sshin return -1; 186155163Sshin } 186255163Sshin gw = &in6addr_loopback; 186355163Sshin prefix = rrt->rrt_info.rip6_plen; 186455163Sshin } else { 186578064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 186655163Sshin return -1; 186755163Sshin } 186855163Sshin 186955163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 187055163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 187155163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 187255163Sshin /* age route for interface address */ 187355163Sshin memset(&ni6, 0, sizeof(ni6)); 187455163Sshin ni6.rip6_dest = *dst; 187555163Sshin ni6.rip6_plen = prefix; 187655163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 187755163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 187855163Sshin ni6.rip6_plen); 187978064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 188055163Sshin trace(1, "\tno route found\n"); 188155163Sshin return -1; 188255163Sshin } 188378064Sume#if 0 188455163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 188555163Sshin trace(1, "\tyou can delete static routes only\n"); 188678064Sume } else 188778064Sume#endif 188878064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 188955163Sshin trace(1, "\tgw mismatch: %s <-> ", 189055163Sshin inet6_n2p(&rrt->rrt_gw)); 189155163Sshin trace(1, "%s\n", inet6_n2p(gw)); 189255163Sshin } else { 189355163Sshin trace(1, "\troute found, age it\n"); 189455163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 189555163Sshin rrt->rrt_t = t_lifetime; 189655163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 189755163Sshin } 189855163Sshin } 189955163Sshin return 0; 190055163Sshin} 190155163Sshin 190255163Sshin/* 190355163Sshin * remove specified address from internal interface/routing table. 190455163Sshin */ 190555163Sshinint 190655163Sshinrt_deladdr(ifcp, sifa, smask) 190755163Sshin struct ifc *ifcp; 190855163Sshin const struct sockaddr_in6 *sifa; 190955163Sshin const struct sockaddr_in6 *smask; 191055163Sshin{ 191155163Sshin const struct in6_addr *addr = NULL; 191255163Sshin int prefix; 191355163Sshin struct ifac *ifa = NULL; 191455163Sshin struct netinfo6 ni6; 191555163Sshin struct riprt *rrt = NULL; 191655163Sshin time_t t_lifetime; 191755163Sshin int updated = 0; 191855163Sshin 191978064Sume if (sifa->sin6_family != AF_INET6) { 192055163Sshin trace(1, "\tother AF, ignored\n"); 192155163Sshin return -1; 192255163Sshin } 192355163Sshin addr = &sifa->sin6_addr; 192478064Sume prefix = sin6mask2len(smask); 192555163Sshin 192655163Sshin trace(1, "\tdeleting %s/%d from %s\n", 192755163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 192855163Sshin ifa = ifa_match(ifcp, addr, prefix); 192955163Sshin if (!ifa) { 193055163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 193155163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 193255163Sshin return -1; 193355163Sshin } 193455163Sshin if (ifa->ifa_conf != ifcp) { 193555163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 193655163Sshin "(%s != %s)\n", 193755163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 193855163Sshin return -1; 193955163Sshin } 194055163Sshin /* remove ifa from interface */ 194155163Sshin if (ifcp->ifc_addr == ifa) 194255163Sshin ifcp->ifc_addr = ifa->ifa_next; 194355163Sshin else { 194455163Sshin struct ifac *p; 194555163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 194655163Sshin if (p->ifa_next == ifa) { 194755163Sshin p->ifa_next = ifa->ifa_next; 194855163Sshin break; 194955163Sshin } 195055163Sshin } 195155163Sshin } 195255163Sshin ifa->ifa_next = NULL; 195355163Sshin ifa->ifa_conf = NULL; 195455163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 195555163Sshin /* age route for interface address */ 195655163Sshin memset(&ni6, 0, sizeof(ni6)); 195755163Sshin ni6.rip6_dest = ifa->ifa_addr; 195855163Sshin ni6.rip6_plen = ifa->ifa_plen; 195955163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 196055163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 196155163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 196278064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 196355163Sshin struct in6_addr none; 196455163Sshin memset(&none, 0, sizeof(none)); 196578064Sume if (rrt->rrt_index == ifcp->ifc_index && 196678064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 196778064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 196855163Sshin trace(1, "\troute found, age it\n"); 196955163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 197055163Sshin rrt->rrt_t = t_lifetime; 197155163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 197255163Sshin } 197355163Sshin updated++; 197455163Sshin } else { 197555163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 197655163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 197755163Sshin rrt->rrt_info.rip6_plen, 197855163Sshin rrt->rrt_index); 197955163Sshin } 198055163Sshin } else 198155163Sshin trace(1, "\tno interface route found\n"); 198255163Sshin /* age route for p2p destination */ 198355163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 198455163Sshin memset(&ni6, 0, sizeof(ni6)); 198555163Sshin ni6.rip6_dest = ifa->ifa_raddr; 198655163Sshin ni6.rip6_plen = 128; 198755163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 198855163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 198955163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 199055163Sshin ifcp->ifc_index); 199178064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 199278064Sume if (rrt->rrt_index == ifcp->ifc_index && 199378064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 199455163Sshin trace(1, "\troute found, age it\n"); 199555163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 199655163Sshin rrt->rrt_t = t_lifetime; 199755163Sshin rrt->rrt_info.rip6_metric = 199878064Sume HOPCNT_INFINITY6; 199955163Sshin updated++; 200055163Sshin } 200155163Sshin } else { 200255163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 200355163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 200455163Sshin rrt->rrt_info.rip6_plen, 200555163Sshin rrt->rrt_index); 200655163Sshin } 200755163Sshin } else 200855163Sshin trace(1, "\tno p2p route found\n"); 200955163Sshin } 201055163Sshin return updated ? 0 : -1; 201155163Sshin} 201255163Sshin 201355163Sshin/* 201455163Sshin * Get each interface address and put those interface routes to the route 201555163Sshin * list. 201655163Sshin */ 201778064Sumeint 201855163Sshinifrt(ifcp, again) 201962607Sitojun struct ifc *ifcp; 202055163Sshin int again; 202155163Sshin{ 202262607Sitojun struct ifac *ifa; 2023119042Sume struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; 202462607Sitojun struct netinfo6 *np; 202578064Sume time_t t_lifetime; 202678064Sume int need_trigger = 0; 202755163Sshin 202855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 202978064Sume return 0; /* ignore loopback */ 203062607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 203162607Sitojun ifrt_p2p(ifcp, again); 203278064Sume return 0; 203362607Sitojun } 203462607Sitojun 203555163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 203662607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 203762607Sitojun#if 0 203862607Sitojun trace(1, "route: %s on %s: " 203962607Sitojun "skip linklocal interface address\n", 204062607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 204162607Sitojun#endif 204262607Sitojun continue; 204362607Sitojun } 204462607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 204562607Sitojun#if 0 204662607Sitojun trace(1, "route: %s: skip unspec interface address\n", 204762607Sitojun ifcp->ifc_name); 204862607Sitojun#endif 204962607Sitojun continue; 205062607Sitojun } 205178064Sume if (ifcp->ifc_flags & IFF_UP) { 205278064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 205378064Sume fatal("malloc: struct riprt"); 205478064Sume memset(rrt, 0, sizeof(*rrt)); 205578064Sume rrt->rrt_same = NULL; 205678064Sume rrt->rrt_index = ifcp->ifc_index; 205778064Sume rrt->rrt_t = 0; /* don't age */ 205878064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 205978064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 206078064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 206178064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 206278064Sume rrt->rrt_flags = RTF_CLONING; 206378064Sume rrt->rrt_rflags |= RRTF_CHANGED; 206478064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 206578064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 206678064Sume rrt->rrt_gw = ifa->ifa_addr; 206778064Sume np = &rrt->rrt_info; 206878064Sume search_rrt = rtsearch(np, &prev_rrt); 206978064Sume if (search_rrt != NULL) { 2070119042Sume if (search_rrt->rrt_info.rip6_metric <= 207178064Sume rrt->rrt_info.rip6_metric) { 207278064Sume /* Already have better route */ 207378064Sume if (!again) { 207478064Sume trace(1, "route: %s/%d: " 207578064Sume "already registered (%s)\n", 207678064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 207778064Sume ifcp->ifc_name); 207878064Sume } 2079119042Sume goto next; 208078064Sume } 2081119042Sume 2082119042Sume if (prev_rrt) 2083119042Sume prev_rrt->rrt_next = rrt->rrt_next; 2084119042Sume else 2085119042Sume riprt = rrt->rrt_next; 2086119042Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 208778064Sume } 208855163Sshin /* Attach the route to the list */ 208962607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 209062607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 209162607Sitojun ifcp->ifc_name); 209255163Sshin rrt->rrt_next = riprt; 209355163Sshin riprt = rrt; 209478064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 2095119042Sume rrt = NULL; 209678064Sume sendrequest(ifcp); 209778064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 209878064Sume need_trigger = 1; 209955163Sshin } else { 210078064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 210178064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 210278064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 210378064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 210478064Sume loop_rrt->rrt_t = t_lifetime; 210578064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 210678064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 210778064Sume need_trigger = 1; 210878064Sume } 210978064Sume } 211055163Sshin } 211178064Sume } 2112119042Sume next: 2113119042Sume if (rrt) 2114119042Sume free(rrt); 211562607Sitojun } 211678064Sume return need_trigger; 211762607Sitojun} 211855163Sshin 211962607Sitojun/* 212062607Sitojun * there are couple of p2p interface routing models. "behavior" lets 212162607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2122119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 212362607Sitojun */ 212462607Sitojunvoid 212562607Sitojunifrt_p2p(ifcp, again) 212662607Sitojun struct ifc *ifcp; 212762607Sitojun int again; 212862607Sitojun{ 212962607Sitojun struct ifac *ifa; 213078064Sume struct riprt *rrt, *orrt, *prevrrt; 213162607Sitojun struct netinfo6 *np; 213262607Sitojun struct in6_addr addr, dest; 213362607Sitojun int advert, ignore, i; 213462607Sitojun#define P2PADVERT_NETWORK 1 213562607Sitojun#define P2PADVERT_ADDR 2 213662607Sitojun#define P2PADVERT_DEST 4 213762607Sitojun#define P2PADVERT_MAX 4 213862607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 213978064Sume const char *category = ""; 214062607Sitojun const char *noadv; 214162607Sitojun 214262607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 214362607Sitojun addr = ifa->ifa_addr; 214462607Sitojun dest = ifa->ifa_raddr; 214562607Sitojun applyplen(&addr, ifa->ifa_plen); 214662607Sitojun applyplen(&dest, ifa->ifa_plen); 214762607Sitojun advert = ignore = 0; 214862607Sitojun switch (behavior) { 214962607Sitojun case CISCO: 215062607Sitojun /* 215162607Sitojun * honor addr/plen, just like normal shared medium 215262607Sitojun * interface. this may cause trouble if you reuse 215362607Sitojun * addr/plen on other interfaces. 215462607Sitojun * 215562607Sitojun * advertise addr/plen. 215662607Sitojun */ 215762607Sitojun advert |= P2PADVERT_NETWORK; 215862607Sitojun break; 215962607Sitojun case GATED: 216062607Sitojun /* 216162607Sitojun * prefixlen on p2p interface is meaningless. 216262607Sitojun * advertise addr/128 and dest/128. 216362607Sitojun * 216462607Sitojun * do not install network route to route6d routing 216562607Sitojun * table (if we do, it would prevent route installation 216662607Sitojun * for other p2p interface that shares addr/plen). 216778064Sume * 216878064Sume * XXX what should we do if dest is ::? it will not 216978064Sume * get announced anyways (see following filter), 217078064Sume * but we need to think. 217162607Sitojun */ 217262607Sitojun advert |= P2PADVERT_ADDR; 217362607Sitojun advert |= P2PADVERT_DEST; 217462607Sitojun ignore |= P2PADVERT_NETWORK; 217562607Sitojun break; 217662607Sitojun case ROUTE6D: 217762607Sitojun /* 217878064Sume * just for testing. actually the code is redundant 217978064Sume * given the current p2p interface address assignment 218078064Sume * rule for kame kernel. 218178064Sume * 218278064Sume * intent: 218378064Sume * A/n -> announce A/n 218478064Sume * A B/n, A and B share prefix -> A/n (= B/n) 218578064Sume * A B/n, do not share prefix -> A/128 and B/128 218678064Sume * actually, A/64 and A B/128 are the only cases 218778064Sume * permitted by the kernel: 218878064Sume * A/64 -> A/64 218978064Sume * A B/128 -> A/128 and B/128 219062607Sitojun */ 219178064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 219278064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 219378064Sume advert |= P2PADVERT_NETWORK; 219478064Sume else { 219578064Sume advert |= P2PADVERT_ADDR; 219678064Sume advert |= P2PADVERT_DEST; 219778064Sume ignore |= P2PADVERT_NETWORK; 219878064Sume } 219978064Sume } else 220062607Sitojun advert |= P2PADVERT_NETWORK; 220162607Sitojun break; 220262607Sitojun } 220362607Sitojun 220462607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 220562607Sitojun if ((ignore & i) != 0) 220662607Sitojun continue; 220778064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 220855163Sshin fatal("malloc: struct riprt"); 220978064Sume /*NOTREACHED*/ 221078064Sume } 221162607Sitojun memset(rrt, 0, sizeof(*rrt)); 221255163Sshin rrt->rrt_same = NULL; 221355163Sshin rrt->rrt_index = ifcp->ifc_index; 221462607Sitojun rrt->rrt_t = 0; /* don't age */ 221562607Sitojun switch (i) { 221662607Sitojun case P2PADVERT_NETWORK: 221762607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 221862607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 221962607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 222062607Sitojun ifa->ifa_plen); 222162607Sitojun category = "network"; 222262607Sitojun break; 222362607Sitojun case P2PADVERT_ADDR: 222462607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 222562607Sitojun rrt->rrt_info.rip6_plen = 128; 222678064Sume rrt->rrt_gw = in6addr_loopback; 222762607Sitojun category = "addr"; 222862607Sitojun break; 222962607Sitojun case P2PADVERT_DEST: 223062607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 223162607Sitojun rrt->rrt_info.rip6_plen = 128; 223278064Sume rrt->rrt_gw = ifa->ifa_addr; 223362607Sitojun category = "dest"; 223462607Sitojun break; 223562607Sitojun } 223662607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 223762607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 223862607Sitojun#if 0 223962607Sitojun trace(1, "route: %s: skip unspec/linklocal " 224062607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 224162607Sitojun#endif 224262607Sitojun free(rrt); 224362607Sitojun continue; 224462607Sitojun } 224562607Sitojun if ((advert & i) == 0) { 224662607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 224762607Sitojun noadv = ", NO-ADV"; 224862607Sitojun } else 224962607Sitojun noadv = ""; 225055163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 225162607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 225255163Sshin np = &rrt->rrt_info; 225378064Sume orrt = rtsearch(np, &prevrrt); 225478064Sume if (!orrt) { 225555163Sshin /* Attach the route to the list */ 225662607Sitojun trace(1, "route: %s/%d: register route " 225762607Sitojun "(%s on %s%s)\n", 225862607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 225962607Sitojun category, ifcp->ifc_name, noadv); 226055163Sshin rrt->rrt_next = riprt; 226155163Sshin riprt = rrt; 226278064Sume } else if (rrt->rrt_index != orrt->rrt_index || 226378064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 226478064Sume /* swap route */ 226578064Sume rrt->rrt_next = orrt->rrt_next; 226678064Sume if (prevrrt) 226778064Sume prevrrt->rrt_next = rrt; 226878064Sume else 226978064Sume riprt = rrt; 227078064Sume free(orrt); 227178064Sume 227278064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 227378064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 227478064Sume category, ifcp->ifc_name, noadv); 227555163Sshin } else { 227655163Sshin /* Already found */ 227755163Sshin if (!again) { 227862607Sitojun trace(1, "route: %s/%d: " 227962607Sitojun "already registered (%s on %s%s)\n", 228062607Sitojun inet6_n2p(&np->rip6_dest), 228162607Sitojun np->rip6_plen, category, 228262607Sitojun ifcp->ifc_name, noadv); 228355163Sshin } 228455163Sshin free(rrt); 228555163Sshin } 228655163Sshin } 228755163Sshin } 228862607Sitojun#undef P2PADVERT_NETWORK 228962607Sitojun#undef P2PADVERT_ADDR 229062607Sitojun#undef P2PADVERT_DEST 229162607Sitojun#undef P2PADVERT_MAX 229255163Sshin} 229355163Sshin 229455163Sshinint 229555163Sshingetifmtu(ifindex) 229655163Sshin int ifindex; 229755163Sshin{ 229855163Sshin int mib[6]; 229955163Sshin char *buf; 230055163Sshin size_t msize; 230155163Sshin struct if_msghdr *ifm; 230255163Sshin int mtu; 230355163Sshin 230455163Sshin mib[0] = CTL_NET; 230555163Sshin mib[1] = PF_ROUTE; 230655163Sshin mib[2] = 0; 230755163Sshin mib[3] = AF_INET6; 230855163Sshin mib[4] = NET_RT_IFLIST; 230955163Sshin mib[5] = ifindex; 231078064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 231155163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 231278064Sume /*NOTREACHED*/ 231378064Sume } 231478064Sume if ((buf = malloc(msize)) == NULL) { 231555163Sshin fatal("malloc"); 231678064Sume /*NOTREACHED*/ 231778064Sume } 231878064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 231955163Sshin fatal("sysctl NET_RT_IFLIST"); 232078064Sume /*NOTREACHED*/ 232178064Sume } 232255163Sshin ifm = (struct if_msghdr *)buf; 232355163Sshin mtu = ifm->ifm_data.ifi_mtu; 232478064Sume#ifdef __FreeBSD__ 232578064Sume if (ifindex != ifm->ifm_index) { 232655163Sshin fatal("ifindex does not match with ifm_index"); 232778064Sume /*NOTREACHED*/ 232878064Sume } 232978064Sume#endif 233055163Sshin free(buf); 233155163Sshin return mtu; 233255163Sshin} 233355163Sshin 233455163Sshinconst char * 233555163Sshinrttypes(rtm) 233655163Sshin struct rt_msghdr *rtm; 233755163Sshin{ 233862607Sitojun#define RTTYPE(s, f) \ 233962607Sitojundo { \ 234062607Sitojun if (rtm->rtm_type == (f)) \ 234162607Sitojun return (s); \ 234262607Sitojun} while (0) 234355163Sshin RTTYPE("ADD", RTM_ADD); 234455163Sshin RTTYPE("DELETE", RTM_DELETE); 234555163Sshin RTTYPE("CHANGE", RTM_CHANGE); 234655163Sshin RTTYPE("GET", RTM_GET); 234755163Sshin RTTYPE("LOSING", RTM_LOSING); 234855163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 234955163Sshin RTTYPE("MISS", RTM_MISS); 235055163Sshin RTTYPE("LOCK", RTM_LOCK); 235155163Sshin RTTYPE("OLDADD", RTM_OLDADD); 235255163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 235355163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 235455163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 235555163Sshin RTTYPE("DELADDR", RTM_DELADDR); 235655163Sshin RTTYPE("IFINFO", RTM_IFINFO); 235778064Sume#ifdef RTM_OLDADD 235878064Sume RTTYPE("OLDADD", RTM_OLDADD); 235978064Sume#endif 236078064Sume#ifdef RTM_OLDDEL 236178064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 236278064Sume#endif 236378064Sume#ifdef RTM_OIFINFO 236478064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 236578064Sume#endif 236678064Sume#ifdef RTM_IFANNOUNCE 236778064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 236878064Sume#endif 236978064Sume#ifdef RTM_NEWMADDR 237078064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 237178064Sume#endif 237278064Sume#ifdef RTM_DELMADDR 237378064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 237478064Sume#endif 237555163Sshin#undef RTTYPE 237655163Sshin return NULL; 237755163Sshin} 237855163Sshin 237955163Sshinconst char * 238055163Sshinrtflags(rtm) 238155163Sshin struct rt_msghdr *rtm; 238255163Sshin{ 238355163Sshin static char buf[BUFSIZ]; 238455163Sshin 238578064Sume /* 238678064Sume * letter conflict should be okay. painful when *BSD diverges... 238778064Sume */ 238878064Sume strlcpy(buf, "", sizeof(buf)); 238962607Sitojun#define RTFLAG(s, f) \ 239062607Sitojundo { \ 239162607Sitojun if (rtm->rtm_flags & (f)) \ 239278064Sume strlcat(buf, (s), sizeof(buf)); \ 239362607Sitojun} while (0) 239455163Sshin RTFLAG("U", RTF_UP); 239555163Sshin RTFLAG("G", RTF_GATEWAY); 239655163Sshin RTFLAG("H", RTF_HOST); 239755163Sshin RTFLAG("R", RTF_REJECT); 239855163Sshin RTFLAG("D", RTF_DYNAMIC); 239955163Sshin RTFLAG("M", RTF_MODIFIED); 240055163Sshin RTFLAG("d", RTF_DONE); 240155163Sshin#ifdef RTF_MASK 240255163Sshin RTFLAG("m", RTF_MASK); 240355163Sshin#endif 240455163Sshin RTFLAG("C", RTF_CLONING); 240578064Sume#ifdef RTF_CLONED 240678064Sume RTFLAG("c", RTF_CLONED); 240778064Sume#endif 240878064Sume#ifdef RTF_PRCLONING 240978064Sume RTFLAG("c", RTF_PRCLONING); 241078064Sume#endif 241178064Sume#ifdef RTF_WASCLONED 241278064Sume RTFLAG("W", RTF_WASCLONED); 241378064Sume#endif 241455163Sshin RTFLAG("X", RTF_XRESOLVE); 241555163Sshin RTFLAG("L", RTF_LLINFO); 241655163Sshin RTFLAG("S", RTF_STATIC); 241755163Sshin RTFLAG("B", RTF_BLACKHOLE); 241878064Sume#ifdef RTF_PROTO3 241978064Sume RTFLAG("3", RTF_PROTO3); 242078064Sume#endif 242155163Sshin RTFLAG("2", RTF_PROTO2); 242255163Sshin RTFLAG("1", RTF_PROTO1); 242378064Sume#ifdef RTF_BROADCAST 242478064Sume RTFLAG("b", RTF_BROADCAST); 242578064Sume#endif 242678064Sume#ifdef RTF_DEFAULT 242778064Sume RTFLAG("d", RTF_DEFAULT); 242878064Sume#endif 242978064Sume#ifdef RTF_ISAROUTER 243078064Sume RTFLAG("r", RTF_ISAROUTER); 243178064Sume#endif 243278064Sume#ifdef RTF_TUNNEL 243378064Sume RTFLAG("T", RTF_TUNNEL); 243478064Sume#endif 243578064Sume#ifdef RTF_AUTH 243678064Sume RTFLAG("A", RTF_AUTH); 243778064Sume#endif 243878064Sume#ifdef RTF_CRYPT 243978064Sume RTFLAG("E", RTF_CRYPT); 244078064Sume#endif 244155163Sshin#undef RTFLAG 244255163Sshin return buf; 244355163Sshin} 244455163Sshin 244555163Sshinconst char * 244655163Sshinifflags(flags) 244755163Sshin int flags; 244855163Sshin{ 244955163Sshin static char buf[BUFSIZ]; 245055163Sshin 245178064Sume strlcpy(buf, "", sizeof(buf)); 245262607Sitojun#define IFFLAG(s, f) \ 245362607Sitojundo { \ 2454119040Sume if (flags & (f)) { \ 245562607Sitojun if (buf[0]) \ 245678064Sume strlcat(buf, ",", sizeof(buf)); \ 2457119040Sume strlcat(buf, (s), sizeof(buf)); \ 245862607Sitojun } \ 245962607Sitojun} while (0) 246055163Sshin IFFLAG("UP", IFF_UP); 246155163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 246255163Sshin IFFLAG("DEBUG", IFF_DEBUG); 246355163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 246455163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 246555163Sshin#ifdef IFF_NOTRAILERS 246655163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 246755163Sshin#endif 246878064Sume#ifdef IFF_SMART 246978064Sume IFFLAG("SMART", IFF_SMART); 247078064Sume#endif 247155163Sshin IFFLAG("RUNNING", IFF_RUNNING); 247255163Sshin IFFLAG("NOARP", IFF_NOARP); 247355163Sshin IFFLAG("PROMISC", IFF_PROMISC); 247455163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 247555163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 247655163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 247755163Sshin IFFLAG("LINK0", IFF_LINK0); 247855163Sshin IFFLAG("LINK1", IFF_LINK1); 247955163Sshin IFFLAG("LINK2", IFF_LINK2); 248055163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 248155163Sshin#undef IFFLAG 248255163Sshin return buf; 248355163Sshin} 248455163Sshin 248555163Sshinvoid 248655163Sshinkrtread(again) 248755163Sshin int again; 248855163Sshin{ 248955163Sshin int mib[6]; 249055163Sshin size_t msize; 249155163Sshin char *buf, *p, *lim; 249255163Sshin struct rt_msghdr *rtm; 249355163Sshin int retry; 249455163Sshin const char *errmsg; 249555163Sshin 249655163Sshin retry = 0; 249755163Sshin buf = NULL; 249855163Sshin mib[0] = CTL_NET; 249955163Sshin mib[1] = PF_ROUTE; 250055163Sshin mib[2] = 0; 250155163Sshin mib[3] = AF_INET6; /* Address family */ 250255163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 250355163Sshin mib[5] = 0; /* No flags */ 250455163Sshin do { 250555163Sshin retry++; 250655163Sshin errmsg = NULL; 250755163Sshin if (buf) 250855163Sshin free(buf); 250955163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 251055163Sshin errmsg = "sysctl estimate"; 251155163Sshin continue; 251255163Sshin } 251355163Sshin if ((buf = malloc(msize)) == NULL) { 251455163Sshin errmsg = "malloc"; 251555163Sshin continue; 251655163Sshin } 251755163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 251855163Sshin errmsg = "sysctl NET_RT_DUMP"; 251955163Sshin continue; 252055163Sshin } 252155163Sshin } while (retry < 5 && errmsg != NULL); 252278064Sume if (errmsg) { 252369279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 252469279Sume (u_long)msize); 252578064Sume /*NOTREACHED*/ 252678064Sume } else if (1 < retry) 252755163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 252855163Sshin 252955163Sshin lim = buf + msize; 253055163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 253155163Sshin rtm = (struct rt_msghdr *)p; 253255163Sshin rt_entry(rtm, again); 253355163Sshin } 253455163Sshin free(buf); 253555163Sshin} 253655163Sshin 253755163Sshinvoid 253855163Sshinrt_entry(rtm, again) 253955163Sshin struct rt_msghdr *rtm; 254055163Sshin int again; 254155163Sshin{ 254255163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 254355163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 254455163Sshin char *rtmp, *ifname = NULL; 254578064Sume struct riprt *rrt, *orrt; 254655163Sshin struct netinfo6 *np; 254755163Sshin int s; 254855163Sshin 254955163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 255055163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 255162607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 255255163Sshin return; /* not interested in the link route */ 255362607Sitojun } 255469279Sume /* do not look at cloned routes */ 255569279Sume#ifdef RTF_WASCLONED 255669279Sume if (rtm->rtm_flags & RTF_WASCLONED) 255769279Sume return; 255869279Sume#endif 255969279Sume#ifdef RTF_CLONED 256069279Sume if (rtm->rtm_flags & RTF_CLONED) 256169279Sume return; 256269279Sume#endif 256369279Sume /* 256469279Sume * do not look at dynamic routes. 256569279Sume * netbsd/openbsd cloned routes have UGHD. 256669279Sume */ 256769279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 256869279Sume return; 256955163Sshin rtmp = (char *)(rtm + 1); 257055163Sshin /* Destination */ 257155163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 257255163Sshin return; /* ignore routes without destination address */ 257355163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 257464631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 257555163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 257655163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 257755163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 257855163Sshin } 257955163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 258055163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 258155163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 258255163Sshin } 258355163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 258455163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 258555163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 258655163Sshin } 258755163Sshin if (rtm->rtm_addrs & RTA_IFP) { 258855163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 258955163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 259055163Sshin } 259155163Sshin 259255163Sshin /* Destination */ 259355163Sshin if (sin6_dst->sin6_family != AF_INET6) 259455163Sshin return; 259555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 259655163Sshin return; /* Link-local */ 259755163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 259855163Sshin return; /* Loopback */ 259955163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 260055163Sshin return; 260155163Sshin 260278064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 260355163Sshin fatal("malloc: struct riprt"); 260478064Sume /*NOTREACHED*/ 260578064Sume } 260662607Sitojun memset(rrt, 0, sizeof(*rrt)); 260755163Sshin np = &rrt->rrt_info; 260855163Sshin rrt->rrt_same = NULL; 260955163Sshin rrt->rrt_t = time(NULL); 261055163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 261155163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 261255163Sshin np->rip6_tag = 0; 261355163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 261455163Sshin if (np->rip6_metric < 1) 261555163Sshin np->rip6_metric = 1; 261655163Sshin rrt->rrt_flags = rtm->rtm_flags; 261755163Sshin np->rip6_dest = sin6_dst->sin6_addr; 261855163Sshin 261955163Sshin /* Mask or plen */ 262055163Sshin if (rtm->rtm_flags & RTF_HOST) 262155163Sshin np->rip6_plen = 128; /* Host route */ 262278064Sume else if (sin6_mask) 262378064Sume np->rip6_plen = sin6mask2len(sin6_mask); 262478064Sume else 262555163Sshin np->rip6_plen = 0; 262655163Sshin 262778064Sume orrt = rtsearch(np, NULL); 262878064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 262955163Sshin /* Already found */ 263055163Sshin if (!again) { 263155163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 263255163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 263355163Sshin rtflags(rtm)); 263455163Sshin } 263555163Sshin free(rrt); 263655163Sshin return; 263755163Sshin } 263855163Sshin /* Gateway */ 263955163Sshin if (!sin6_gw) 264055163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 264155163Sshin else { 264255163Sshin if (sin6_gw->sin6_family == AF_INET6) 264355163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 264455163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 264555163Sshin /* XXX in case ppp link? */ 264655163Sshin rrt->rrt_gw = in6addr_loopback; 264755163Sshin } else 264855163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 264955163Sshin } 265055163Sshin trace(1, "route: %s/%d flags %s", 265155163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 265255163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 265355163Sshin 265455163Sshin /* Interface */ 265555163Sshin s = rtm->rtm_index; 265655163Sshin if (s < nindex2ifc && index2ifc[s]) 265755163Sshin ifname = index2ifc[s]->ifc_name; 265858070Sshin else { 265958070Sshin trace(1, " not configured\n"); 266062607Sitojun free(rrt); 266158070Sshin return; 266258070Sshin } 266362607Sitojun trace(1, " if %s sock %d", ifname, s); 266455163Sshin rrt->rrt_index = s; 266555163Sshin 266662607Sitojun trace(1, "\n"); 266762607Sitojun 266855163Sshin /* Check gateway */ 266955163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 267055163Sshin !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 267155163Sshin#ifdef __FreeBSD__ 267255163Sshin && (rrt->rrt_flags & RTF_LOCAL) == 0 267355163Sshin#endif 267455163Sshin ) { 267555163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 267655163Sshin inet6_n2p(&rrt->rrt_gw)); 267755163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 267862607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 267962607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 268055163Sshin } 268155163Sshin 268255163Sshin /* Put it to the route list */ 268378064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 268478064Sume /* replace route list */ 268578064Sume rrt->rrt_next = orrt->rrt_next; 268678064Sume *orrt = *rrt; 268778064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 268878064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 268978064Sume rtflags(rtm)); 269078064Sume free(rrt); 269178064Sume } else { 269278064Sume rrt->rrt_next = riprt; 269378064Sume riprt = rrt; 269478064Sume } 269555163Sshin} 269655163Sshin 269755163Sshinint 269855163Sshinaddroute(rrt, gw, ifcp) 269955163Sshin struct riprt *rrt; 270055163Sshin const struct in6_addr *gw; 270155163Sshin struct ifc *ifcp; 270255163Sshin{ 270355163Sshin struct netinfo6 *np; 270455163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 270555163Sshin struct rt_msghdr *rtm; 2706119031Sume struct sockaddr_in6 *sin6; 270755163Sshin int len; 270855163Sshin 270955163Sshin np = &rrt->rrt_info; 271078064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 271155163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 271255163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 271355163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 271455163Sshin np->rip6_metric - 1, buf2); 271555163Sshin if (rtlog) 271655163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 271755163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 271855163Sshin np->rip6_metric - 1, buf2); 271955163Sshin if (nflag) 272055163Sshin return 0; 272155163Sshin 272255163Sshin memset(buf, 0, sizeof(buf)); 272355163Sshin rtm = (struct rt_msghdr *)buf; 272455163Sshin rtm->rtm_type = RTM_ADD; 272555163Sshin rtm->rtm_version = RTM_VERSION; 272655163Sshin rtm->rtm_seq = ++seq; 272755163Sshin rtm->rtm_pid = pid; 272862607Sitojun rtm->rtm_flags = rrt->rrt_flags; 272955163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 273055163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 273155163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2732119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 273355163Sshin /* Destination */ 2734119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2735119031Sume sin6->sin6_family = AF_INET6; 2736119031Sume sin6->sin6_addr = np->rip6_dest; 2737119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 273855163Sshin /* Gateway */ 2739119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2740119031Sume sin6->sin6_family = AF_INET6; 2741119031Sume sin6->sin6_addr = *gw; 2742119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 274355163Sshin /* Netmask */ 2744119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2745119031Sume sin6->sin6_family = AF_INET6; 2746119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2747119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 274855163Sshin 2749119031Sume len = (char *)sin6 - (char *)buf; 275055163Sshin rtm->rtm_msglen = len; 275155163Sshin if (write(rtsock, buf, len) > 0) 275255163Sshin return 0; 275355163Sshin 275455163Sshin if (errno == EEXIST) { 275555163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2756119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 275755163Sshin if (rtlog) 275855163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2759119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 276055163Sshin } else { 276155163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2762119035Sume strerror(errno)); 276355163Sshin if (rtlog) 276455163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2765119035Sume strerror(errno)); 276655163Sshin } 276755163Sshin return -1; 276855163Sshin} 276955163Sshin 277055163Sshinint 277155163Sshindelroute(np, gw) 277255163Sshin struct netinfo6 *np; 277355163Sshin struct in6_addr *gw; 277455163Sshin{ 277555163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 277655163Sshin struct rt_msghdr *rtm; 2777119031Sume struct sockaddr_in6 *sin6; 277855163Sshin int len; 277955163Sshin 278055163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 278155163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 278255163Sshin np->rip6_plen, buf2); 278355163Sshin if (rtlog) 278455163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 278555163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 278655163Sshin if (nflag) 278755163Sshin return 0; 278855163Sshin 278955163Sshin memset(buf, 0, sizeof(buf)); 279055163Sshin rtm = (struct rt_msghdr *)buf; 279155163Sshin rtm->rtm_type = RTM_DELETE; 279255163Sshin rtm->rtm_version = RTM_VERSION; 279355163Sshin rtm->rtm_seq = ++seq; 279455163Sshin rtm->rtm_pid = pid; 279555163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 279678064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 279778064Sume rtm->rtm_flags |= RTF_HOST; 279855163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2799119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 280055163Sshin /* Destination */ 2801119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2802119031Sume sin6->sin6_family = AF_INET6; 2803119031Sume sin6->sin6_addr = np->rip6_dest; 2804119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 280555163Sshin /* Gateway */ 2806119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2807119031Sume sin6->sin6_family = AF_INET6; 2808119031Sume sin6->sin6_addr = *gw; 2809119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 281055163Sshin /* Netmask */ 2811119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2812119031Sume sin6->sin6_family = AF_INET6; 2813119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2814119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 281555163Sshin 2816119031Sume len = (char *)sin6 - (char *)buf; 281755163Sshin rtm->rtm_msglen = len; 281855163Sshin if (write(rtsock, buf, len) >= 0) 281955163Sshin return 0; 282055163Sshin 282155163Sshin if (errno == ESRCH) { 282255163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2823119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 282455163Sshin if (rtlog) 282555163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2826119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 282755163Sshin } else { 282855163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2829119035Sume strerror(errno)); 283055163Sshin if (rtlog) 283155163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2832119035Sume strerror(errno)); 283355163Sshin } 283455163Sshin return -1; 283555163Sshin} 283655163Sshin 283755163Sshinstruct in6_addr * 283855163Sshingetroute(np, gw) 283955163Sshin struct netinfo6 *np; 284055163Sshin struct in6_addr *gw; 284155163Sshin{ 284255163Sshin u_char buf[BUFSIZ]; 284355163Sshin u_long myseq; 284455163Sshin int len; 284555163Sshin struct rt_msghdr *rtm; 2846119031Sume struct sockaddr_in6 *sin6; 284755163Sshin 284855163Sshin rtm = (struct rt_msghdr *)buf; 284955163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 285055163Sshin memset(rtm, 0, len); 285155163Sshin rtm->rtm_type = RTM_GET; 285255163Sshin rtm->rtm_version = RTM_VERSION; 285355163Sshin myseq = ++seq; 285455163Sshin rtm->rtm_seq = myseq; 285555163Sshin rtm->rtm_addrs = RTA_DST; 285655163Sshin rtm->rtm_msglen = len; 2857119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2858119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2859119031Sume sin6->sin6_family = AF_INET6; 2860119031Sume sin6->sin6_addr = np->rip6_dest; 286155163Sshin if (write(rtsock, buf, len) < 0) { 286255163Sshin if (errno == ESRCH) /* No such route found */ 286355163Sshin return NULL; 286455163Sshin perror("write to rtsock"); 286578064Sume exit(1); 286655163Sshin } 286755163Sshin do { 286855163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 286955163Sshin perror("read from rtsock"); 287078064Sume exit(1); 287155163Sshin } 287255163Sshin rtm = (struct rt_msghdr *)buf; 287355163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2874119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 287555163Sshin if (rtm->rtm_addrs & RTA_DST) { 2876119031Sume sin6 = (struct sockaddr_in6 *) 2877119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 287855163Sshin } 287955163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2880119031Sume *gw = sin6->sin6_addr; 288155163Sshin return gw; 288255163Sshin } 288355163Sshin return NULL; 288455163Sshin} 288555163Sshin 288655163Sshinconst char * 288755163Sshininet6_n2p(p) 288855163Sshin const struct in6_addr *p; 288955163Sshin{ 289055163Sshin static char buf[BUFSIZ]; 289155163Sshin 289278064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 289355163Sshin} 289455163Sshin 289555163Sshinvoid 289655163Sshinifrtdump(sig) 289755163Sshin int sig; 289855163Sshin{ 289955163Sshin 290055163Sshin ifdump(sig); 290155163Sshin rtdump(sig); 290255163Sshin} 290355163Sshin 290455163Sshinvoid 290555163Sshinifdump(sig) 290655163Sshin int sig; 290755163Sshin{ 290855163Sshin struct ifc *ifcp; 290955163Sshin FILE *dump; 291055163Sshin int i; 291155163Sshin 291255163Sshin if (sig == 0) 291355163Sshin dump = stderr; 291455163Sshin else 291555163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 291655163Sshin dump = stderr; 291755163Sshin 291855163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 291955163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 292055163Sshin for (i = 0; i < 2; i++) { 292155163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 292255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 292355163Sshin if (i == 0) { 292455163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 292555163Sshin continue; 292655163Sshin if (iff_find(ifcp, 'N') != NULL) 292755163Sshin continue; 292855163Sshin } else { 292955163Sshin if (ifcp->ifc_flags & IFF_UP) 293055163Sshin continue; 293155163Sshin } 293255163Sshin ifdump0(dump, ifcp); 293355163Sshin } 293455163Sshin } 293555163Sshin fprintf(dump, "\n"); 293655163Sshin if (dump != stderr) 293755163Sshin fclose(dump); 293855163Sshin} 293955163Sshin 294055163Sshinvoid 294155163Sshinifdump0(dump, ifcp) 294255163Sshin FILE *dump; 294355163Sshin const struct ifc *ifcp; 294455163Sshin{ 294555163Sshin struct ifac *ifa; 294655163Sshin struct iff *iffp; 294755163Sshin char buf[BUFSIZ]; 294855163Sshin const char *ft; 294955163Sshin int addr; 295055163Sshin 295155163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 295255163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 295355163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 295455163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 295555163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 295655163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 295755163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 295855163Sshin buf, sizeof(buf)); 295955163Sshin fprintf(dump, "\t%s/%d -- %s\n", 296055163Sshin inet6_n2p(&ifa->ifa_addr), 296155163Sshin ifa->ifa_plen, buf); 296255163Sshin } else { 296355163Sshin fprintf(dump, "\t%s/%d\n", 296455163Sshin inet6_n2p(&ifa->ifa_addr), 296555163Sshin ifa->ifa_plen); 296655163Sshin } 296755163Sshin } 296855163Sshin if (ifcp->ifc_filter) { 296955163Sshin fprintf(dump, "\tFilter:"); 297055163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 297155163Sshin addr = 0; 297255163Sshin switch (iffp->iff_type) { 297355163Sshin case 'A': 297455163Sshin ft = "Aggregate"; addr++; break; 297555163Sshin case 'N': 297678064Sume ft = "No-use"; break; 297755163Sshin case 'O': 297855163Sshin ft = "Advertise-only"; addr++; break; 297955163Sshin case 'T': 298055163Sshin ft = "Default-only"; break; 298155163Sshin case 'L': 298255163Sshin ft = "Listen-only"; addr++; break; 298355163Sshin default: 298455163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 298555163Sshin ft = buf; 298655163Sshin addr++; 298755163Sshin break; 298855163Sshin } 298955163Sshin fprintf(dump, " %s", ft); 299055163Sshin if (addr) { 299155163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 299255163Sshin iffp->iff_plen); 299355163Sshin } 299455163Sshin } 299555163Sshin fprintf(dump, "\n"); 299655163Sshin } 299755163Sshin} 299855163Sshin 299955163Sshinvoid 300055163Sshinrtdump(sig) 300155163Sshin int sig; 300255163Sshin{ 300355163Sshin struct riprt *rrt; 300455163Sshin char buf[BUFSIZ]; 300555163Sshin FILE *dump; 300655163Sshin time_t t, age; 300755163Sshin 300855163Sshin if (sig == 0) 300955163Sshin dump = stderr; 301055163Sshin else 301155163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 301255163Sshin dump = stderr; 301355163Sshin 301455163Sshin t = time(NULL); 301555163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 301655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 301755163Sshin if (rrt->rrt_t == 0) 301855163Sshin age = 0; 301955163Sshin else 302055163Sshin age = t - rrt->rrt_t; 302155163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 302255163Sshin buf, sizeof(buf)); 302355163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 302455163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 302555163Sshin index2ifc[rrt->rrt_index]->ifc_name, 302655163Sshin inet6_n2p(&rrt->rrt_gw), 302755163Sshin rrt->rrt_info.rip6_metric, (long)age); 302855163Sshin if (rrt->rrt_info.rip6_tag) { 302955163Sshin fprintf(dump, " tag(0x%04x)", 303055163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 303155163Sshin } 303262607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 303355163Sshin fprintf(dump, " NOT-LL"); 303462607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 303555163Sshin fprintf(dump, " NO-ADV"); 303655163Sshin fprintf(dump, "\n"); 303755163Sshin } 303855163Sshin fprintf(dump, "\n"); 303955163Sshin if (dump != stderr) 304055163Sshin fclose(dump); 304155163Sshin} 304255163Sshin 304355163Sshin/* 304455163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 304578064Sume * specified interface structures. Each of the -A/O option has the following 304655163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 304755163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 304855163Sshin */ 304955163Sshinvoid 305055163Sshinfilterconfig() 305155163Sshin{ 305255163Sshin int i; 305355163Sshin char *p, *ap, *iflp, *ifname; 305478064Sume struct iff ftmp, *iff_obj; 305578064Sume struct ifc *ifcp; 305678064Sume struct riprt *rrt; 305764631Sitojun#if 0 305878064Sume struct in6_addr gw; 305964631Sitojun#endif 306055163Sshin 306155163Sshin for (i = 0; i < nfilter; i++) { 306255163Sshin ap = filter[i]; 306355163Sshin iflp = NULL; 306455163Sshin ifcp = NULL; 306555163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 306655163Sshin iflp = ap; 306755163Sshin goto ifonly; 306855163Sshin } 3069119038Sume if ((p = strchr(ap, ',')) != NULL) { 307055163Sshin *p++ = '\0'; 307155163Sshin iflp = p; 307255163Sshin } 3073119038Sume if ((p = strchr(ap, '/')) == NULL) { 307455163Sshin fatal("no prefixlen specified for '%s'", ap); 307578064Sume /*NOTREACHED*/ 307678064Sume } 307755163Sshin *p++ = '\0'; 307878064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 307955163Sshin fatal("invalid prefix specified for '%s'", ap); 308078064Sume /*NOTREACHED*/ 308178064Sume } 308255163Sshin ftmp.iff_plen = atoi(p); 308355163Sshin ftmp.iff_next = NULL; 308455163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 308555163Sshinifonly: 308655163Sshin ftmp.iff_type = filtertype[i]; 308778064Sume if (iflp == NULL || *iflp == '\0') { 308855163Sshin fatal("no interface specified for '%s'", ap); 308978064Sume /*NOTREACHED*/ 309078064Sume } 309155163Sshin /* parse the interface listing portion */ 309255163Sshin while (iflp) { 309355163Sshin ifname = iflp; 3094119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 309555163Sshin *iflp++ = '\0'; 309655163Sshin ifcp = ifc_find(ifname); 309778064Sume if (ifcp == NULL) { 309855163Sshin fatal("no interface %s exists", ifname); 309978064Sume /*NOTREACHED*/ 310078064Sume } 310155163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 310278064Sume if (iff_obj == NULL) { 310355163Sshin fatal("malloc of iff_obj"); 310478064Sume /*NOTREACHED*/ 310578064Sume } 310655163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 310778064Sume sizeof(struct iff)); 310855163Sshin /* link it to the interface filter */ 310955163Sshin iff_obj->iff_next = ifcp->ifc_filter; 311055163Sshin ifcp->ifc_filter = iff_obj; 311155163Sshin } 311278064Sume 311378064Sume /* 311478064Sume * -A: aggregate configuration. 311578064Sume */ 311655163Sshin if (filtertype[i] != 'A') 311755163Sshin continue; 311855163Sshin /* put the aggregate to the kernel routing table */ 311955163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 312078064Sume if (rrt == NULL) { 312155163Sshin fatal("malloc: rrt"); 312278064Sume /*NOTREACHED*/ 312378064Sume } 312455163Sshin memset(rrt, 0, sizeof(struct riprt)); 312555163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 312655163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 312755163Sshin rrt->rrt_info.rip6_metric = 1; 312855163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 312955163Sshin rrt->rrt_gw = in6addr_loopback; 313062607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 313162607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 313255163Sshin rrt->rrt_t = 0; 3133119039Sume rrt->rrt_index = loopifcp->ifc_index; 313464631Sitojun#if 0 313564631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 313664631Sitojun#if 0 313764631Sitojun /* 313864631Sitojun * When the address has already been registered in the 313964631Sitojun * kernel routing table, it should be removed 314064631Sitojun */ 314164631Sitojun delroute(&rrt->rrt_info, &gw); 314264631Sitojun#else 314378064Sume /* it is safer behavior */ 314464631Sitojun errno = EINVAL; 314564631Sitojun fatal("%s/%u already in routing table, " 314664631Sitojun "cannot aggregate", 314764631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 314864631Sitojun rrt->rrt_info.rip6_plen); 314978064Sume /*NOTREACHED*/ 315064631Sitojun#endif 315164631Sitojun } 315264631Sitojun#endif 315355163Sshin /* Put the route to the list */ 315455163Sshin rrt->rrt_next = riprt; 315555163Sshin riprt = rrt; 315655163Sshin trace(1, "Aggregate: %s/%d for %s\n", 315755163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 315855163Sshin ifcp->ifc_name); 315955163Sshin /* Add this route to the kernel */ 316055163Sshin if (nflag) /* do not modify kernel routing table */ 316155163Sshin continue; 316255163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 316355163Sshin } 316455163Sshin} 316555163Sshin 316655163Sshin/***************** utility functions *****************/ 316755163Sshin 316855163Sshin/* 316955163Sshin * Returns a pointer to ifac whose address and prefix length matches 317055163Sshin * with the address and prefix length specified in the arguments. 317155163Sshin */ 317255163Sshinstruct ifac * 317355163Sshinifa_match(ifcp, ia, plen) 317455163Sshin const struct ifc *ifcp; 317555163Sshin const struct in6_addr *ia; 317655163Sshin int plen; 317755163Sshin{ 317855163Sshin struct ifac *ifa; 317955163Sshin 318055163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 318155163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 318255163Sshin ifa->ifa_plen == plen) 318355163Sshin break; 318455163Sshin } 318555163Sshin return ifa; 318655163Sshin} 318755163Sshin 318855163Sshin/* 318955163Sshin * Return a pointer to riprt structure whose address and prefix length 319055163Sshin * matches with the address and prefix length found in the argument. 319178064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 319255163Sshin */ 319355163Sshinstruct riprt * 319478064Sumertsearch(np, prev_rrt) 319555163Sshin struct netinfo6 *np; 319678064Sume struct riprt **prev_rrt; 319755163Sshin{ 319855163Sshin struct riprt *rrt; 319955163Sshin 320078064Sume if (prev_rrt) 320178064Sume *prev_rrt = NULL; 320255163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 320355163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 320455163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 320555163Sshin &np->rip6_dest)) 320655163Sshin return rrt; 320778064Sume if (prev_rrt) 320878064Sume *prev_rrt = rrt; 320955163Sshin } 321078064Sume if (prev_rrt) 321178064Sume *prev_rrt = NULL; 321255163Sshin return 0; 321355163Sshin} 321455163Sshin 321555163Sshinint 321678064Sumesin6mask2len(sin6) 321778064Sume const struct sockaddr_in6 *sin6; 321878064Sume{ 321978064Sume 322078064Sume return mask2len(&sin6->sin6_addr, 322178064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 322278064Sume} 322378064Sume 322478064Sumeint 322555163Sshinmask2len(addr, lenlim) 322655163Sshin const struct in6_addr *addr; 322755163Sshin int lenlim; 322855163Sshin{ 322955163Sshin int i = 0, j; 323078064Sume const u_char *p = (const u_char *)addr; 323162607Sitojun 323255163Sshin for (j = 0; j < lenlim; j++, p++) { 323355163Sshin if (*p != 0xff) 323455163Sshin break; 323555163Sshin i += 8; 323655163Sshin } 323755163Sshin if (j < lenlim) { 323855163Sshin switch (*p) { 323962607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 324062607Sitojun MASKLEN(0xfe, 7); break; 324162607Sitojun MASKLEN(0xfc, 6); break; 324262607Sitojun MASKLEN(0xf8, 5); break; 324362607Sitojun MASKLEN(0xf0, 4); break; 324462607Sitojun MASKLEN(0xe0, 3); break; 324562607Sitojun MASKLEN(0xc0, 2); break; 324662607Sitojun MASKLEN(0x80, 1); break; 324755163Sshin#undef MASKLEN 324855163Sshin } 324955163Sshin } 325055163Sshin return i; 325155163Sshin} 325255163Sshin 325355163Sshinvoid 325455163Sshinapplymask(addr, mask) 325555163Sshin struct in6_addr *addr, *mask; 325655163Sshin{ 325755163Sshin int i; 325855163Sshin u_long *p, *q; 325955163Sshin 326055163Sshin p = (u_long *)addr; q = (u_long *)mask; 326155163Sshin for (i = 0; i < 4; i++) 326255163Sshin *p++ &= *q++; 326355163Sshin} 326455163Sshin 326555163Sshinstatic const u_char plent[8] = { 326655163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 326755163Sshin}; 326855163Sshin 326955163Sshinvoid 327055163Sshinapplyplen(ia, plen) 327155163Sshin struct in6_addr *ia; 327255163Sshin int plen; 327355163Sshin{ 327455163Sshin u_char *p; 327555163Sshin int i; 327655163Sshin 327755163Sshin p = ia->s6_addr; 327855163Sshin for (i = 0; i < 16; i++) { 327955163Sshin if (plen <= 0) 328055163Sshin *p = 0; 328155163Sshin else if (plen < 8) 328255163Sshin *p &= plent[plen]; 328355163Sshin p++, plen -= 8; 328455163Sshin } 328555163Sshin} 328655163Sshin 328755163Sshinstatic const int pl2m[9] = { 328855163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 328955163Sshin}; 329055163Sshin 329155163Sshinstruct in6_addr * 329255163Sshinplen2mask(n) 329355163Sshin int n; 329455163Sshin{ 329555163Sshin static struct in6_addr ia; 329655163Sshin u_char *p; 329755163Sshin int i; 329855163Sshin 329955163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 330055163Sshin p = (u_char *)&ia; 330155163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 330255163Sshin if (n >= 8) { 330355163Sshin *p = 0xff; 330455163Sshin continue; 330555163Sshin } 330655163Sshin *p = pl2m[n]; 330755163Sshin break; 330855163Sshin } 330955163Sshin return &ia; 331055163Sshin} 331155163Sshin 331255163Sshinchar * 331355163Sshinallocopy(p) 331455163Sshin char *p; 331555163Sshin{ 3316119033Sume int len = strlen(p) + 1; 3317119033Sume char *q = (char *)malloc(len); 331855163Sshin 3319119033Sume if (!q) { 3320119033Sume fatal("malloc"); 3321119033Sume /*NOTREACHED*/ 3322119033Sume } 3323119033Sume 3324119033Sume strlcpy(q, p, len); 332555163Sshin return q; 332655163Sshin} 332755163Sshin 332855163Sshinchar * 332955163Sshinhms() 333055163Sshin{ 333155163Sshin static char buf[BUFSIZ]; 333255163Sshin time_t t; 333355163Sshin struct tm *tm; 333455163Sshin 333555163Sshin t = time(NULL); 333678064Sume if ((tm = localtime(&t)) == 0) { 333755163Sshin fatal("localtime"); 333878064Sume /*NOTREACHED*/ 333978064Sume } 334078064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 334178064Sume tm->tm_sec); 334255163Sshin return buf; 334355163Sshin} 334455163Sshin 334555163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 334655163Sshin 334755163Sshinint 334855163Sshinripinterval(timer) 334955163Sshin int timer; 335055163Sshin{ 335155163Sshin double r = rand(); 335255163Sshin 335355163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 335455163Sshin nextalarm = time(NULL) + interval; 335555163Sshin return interval; 335655163Sshin} 335755163Sshin 335855163Sshintime_t 335955163Sshinripsuptrig() 336055163Sshin{ 336155163Sshin time_t t; 336255163Sshin 336355163Sshin double r = rand(); 336462607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 336578064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 336655163Sshin sup_trig_update = time(NULL) + t; 336755163Sshin return t; 336855163Sshin} 336955163Sshin 337055163Sshinvoid 337155163Sshin#ifdef __STDC__ 337255163Sshinfatal(const char *fmt, ...) 337355163Sshin#else 337455163Sshinfatal(fmt, va_alist) 337555163Sshin char *fmt; 337655163Sshin va_dcl 337755163Sshin#endif 337855163Sshin{ 337955163Sshin va_list ap; 338055163Sshin char buf[1024]; 338155163Sshin 338255163Sshin#ifdef __STDC__ 338355163Sshin va_start(ap, fmt); 338455163Sshin#else 338555163Sshin va_start(ap); 338655163Sshin#endif 338755163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 3388119043Sume va_end(ap); 338955163Sshin perror(buf); 3390119043Sume if (errno) 3391119043Sume syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 3392119043Sume else 3393119043Sume syslog(LOG_ERR, "%s", buf); 339478064Sume rtdexit(); 339555163Sshin} 339655163Sshin 339755163Sshinvoid 339855163Sshin#ifdef __STDC__ 339955163Sshintracet(int level, const char *fmt, ...) 340055163Sshin#else 340155163Sshintracet(level, fmt, va_alist) 340255163Sshin int level; 340355163Sshin char *fmt; 340455163Sshin va_dcl 340555163Sshin#endif 340655163Sshin{ 340755163Sshin va_list ap; 340855163Sshin 3409119043Sume if (level <= dflag) { 341055163Sshin#ifdef __STDC__ 3411119043Sume va_start(ap, fmt); 341255163Sshin#else 3413119043Sume va_start(ap); 341455163Sshin#endif 341555163Sshin fprintf(stderr, "%s: ", hms()); 341655163Sshin vfprintf(stderr, fmt, ap); 3417119043Sume va_end(ap); 341855163Sshin } 341955163Sshin if (dflag) { 3420119043Sume#ifdef __STDC__ 3421119043Sume va_start(ap, fmt); 3422119043Sume#else 3423119043Sume va_start(ap); 3424119043Sume#endif 342555163Sshin if (level > 0) 342655163Sshin vsyslog(LOG_DEBUG, fmt, ap); 342755163Sshin else 342855163Sshin vsyslog(LOG_WARNING, fmt, ap); 3429119043Sume va_end(ap); 343055163Sshin } 343155163Sshin} 343255163Sshin 343355163Sshinvoid 343455163Sshin#ifdef __STDC__ 343555163Sshintrace(int level, const char *fmt, ...) 343655163Sshin#else 343755163Sshintrace(level, fmt, va_alist) 343855163Sshin int level; 343955163Sshin char *fmt; 344055163Sshin va_dcl 344155163Sshin#endif 344255163Sshin{ 344355163Sshin va_list ap; 344455163Sshin 3445119043Sume if (level <= dflag) { 344655163Sshin#ifdef __STDC__ 3447119043Sume va_start(ap, fmt); 344855163Sshin#else 3449119043Sume va_start(ap); 345055163Sshin#endif 345155163Sshin vfprintf(stderr, fmt, ap); 3452119043Sume va_end(ap); 3453119043Sume } 345455163Sshin if (dflag) { 3455119043Sume#ifdef __STDC__ 3456119043Sume va_start(ap, fmt); 3457119043Sume#else 3458119043Sume va_start(ap); 3459119043Sume#endif 346055163Sshin if (level > 0) 346155163Sshin vsyslog(LOG_DEBUG, fmt, ap); 346255163Sshin else 346355163Sshin vsyslog(LOG_WARNING, fmt, ap); 3464119043Sume va_end(ap); 346555163Sshin } 346655163Sshin} 346755163Sshin 346855163Sshinunsigned int 346955163Sshinif_maxindex() 347055163Sshin{ 347155163Sshin struct if_nameindex *p, *p0; 347255163Sshin unsigned int max = 0; 347355163Sshin 347455163Sshin p0 = if_nameindex(); 347555163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 347655163Sshin if (max < p->if_index) 347755163Sshin max = p->if_index; 347855163Sshin } 347955163Sshin if_freenameindex(p0); 348055163Sshin return max; 348155163Sshin} 348255163Sshin 348355163Sshinstruct ifc * 348455163Sshinifc_find(name) 348555163Sshin char *name; 348655163Sshin{ 348755163Sshin struct ifc *ifcp; 348855163Sshin 348955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 349055163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 349155163Sshin return ifcp; 349255163Sshin } 349355163Sshin return (struct ifc *)NULL; 349455163Sshin} 349555163Sshin 349655163Sshinstruct iff * 349755163Sshiniff_find(ifcp, type) 349855163Sshin struct ifc *ifcp; 349955163Sshin int type; 350055163Sshin{ 350155163Sshin struct iff *iffp; 350255163Sshin 350355163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 350455163Sshin if (iffp->iff_type == type) 350555163Sshin return iffp; 350655163Sshin } 350755163Sshin return NULL; 350855163Sshin} 350955163Sshin 351055163Sshinvoid 351178064Sumesetindex2ifc(idx, ifcp) 351278064Sume int idx; 351355163Sshin struct ifc *ifcp; 351455163Sshin{ 351555163Sshin int n; 351662607Sitojun struct ifc **p; 351755163Sshin 351855163Sshin if (!index2ifc) { 351955163Sshin nindex2ifc = 5; /*initial guess*/ 352055163Sshin index2ifc = (struct ifc **) 352155163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 352278064Sume if (index2ifc == NULL) { 352355163Sshin fatal("malloc"); 352478064Sume /*NOTREACHED*/ 352578064Sume } 352655163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 352755163Sshin } 352855163Sshin n = nindex2ifc; 352978064Sume while (nindex2ifc <= idx) 353055163Sshin nindex2ifc *= 2; 353155163Sshin if (n != nindex2ifc) { 353262607Sitojun p = (struct ifc **)realloc(index2ifc, 353362607Sitojun sizeof(*index2ifc) * nindex2ifc); 353478064Sume if (p == NULL) { 353555163Sshin fatal("realloc"); 353678064Sume /*NOTREACHED*/ 353778064Sume } 353878064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 353962607Sitojun index2ifc = p; 354055163Sshin } 354178064Sume index2ifc[idx] = ifcp; 354255163Sshin} 3543