route6d.c revision 119042
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 119042 2003-08-17 18:12:11Z 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> 5355163Sshin 5455163Sshin#include <sys/types.h> 5555163Sshin#include <sys/param.h> 5655163Sshin#include <sys/file.h> 5755163Sshin#include <sys/socket.h> 5855163Sshin#include <sys/ioctl.h> 5955163Sshin#include <sys/sysctl.h> 6055163Sshin#include <sys/uio.h> 6155163Sshin#include <net/if.h> 6262607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3 6355163Sshin#include <net/if_var.h> 6462607Sitojun#endif /* __FreeBSD__ >= 3 */ 6562607Sitojun#define KERNEL 1 6662607Sitojun#define _KERNEL 1 6755163Sshin#include <net/route.h> 6862607Sitojun#undef KERNEL 6962607Sitojun#undef _KERNEL 7055163Sshin#include <netinet/in.h> 7155163Sshin#include <netinet/in_var.h> 7255163Sshin#include <netinet/ip6.h> 7355163Sshin#include <netinet/udp.h> 7455163Sshin#include <netdb.h> 7562607Sitojun#include <ifaddrs.h> 7655163Sshin 7755163Sshin#include <arpa/inet.h> 7855163Sshin 7955163Sshin#include "route6d.h" 8055163Sshin 8155163Sshin#define MAXFILTER 40 8255163Sshin 8355163Sshin#ifdef DEBUG 8455163Sshin#define INIT_INTERVAL6 6 8555163Sshin#else 86119039Sume#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ 8755163Sshin#endif 8855163Sshin 8955163Sshin/* alignment constraint for routing socket */ 9062607Sitojun#define ROUNDUP(a) \ 9155163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9262607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9355163Sshin 9455163Sshin/* 9555163Sshin * Following two macros are highly depending on KAME Release 9655163Sshin */ 9755163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 9855163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 9955163Sshin 10055163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10155163Sshin do { \ 10255163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10355163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10455163Sshin } while (0) 10555163Sshin 10655163Sshinstruct ifc { /* Configuration of an interface */ 10755163Sshin char *ifc_name; /* if name */ 10855163Sshin struct ifc *ifc_next; 10955163Sshin int ifc_index; /* if index */ 11055163Sshin int ifc_mtu; /* if mtu */ 11155163Sshin int ifc_metric; /* if metric */ 11278064Sume u_int ifc_flags; /* flags */ 11378064Sume short ifc_cflags; /* IFC_XXX */ 11455163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11555163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11655163Sshin struct iff *ifc_filter; /* filter structure */ 11755163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 11855163Sshin int ifc_joined; /* joined to ff02::9 */ 11955163Sshin}; 12055163Sshin 12162607Sitojunstruct ifac { /* Adddress associated to an interface */ 12255163Sshin struct ifc *ifa_conf; /* back pointer */ 12355163Sshin struct ifac *ifa_next; 12455163Sshin struct in6_addr ifa_addr; /* address */ 12555163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12655163Sshin int ifa_plen; /* prefix length */ 12755163Sshin}; 12855163Sshin 12955163Sshinstruct iff { 13055163Sshin int iff_type; 13155163Sshin struct in6_addr iff_addr; 13255163Sshin int iff_plen; 13355163Sshin struct iff *iff_next; 13455163Sshin}; 13555163Sshin 13655163Sshinstruct ifc *ifc; 13755163Sshinint nifc; /* number of valid ifc's */ 13855163Sshinstruct ifc **index2ifc; 13955163Sshinint nindex2ifc; 14055163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 14155163Sshinfd_set sockvec; /* vector to select() for receiving */ 14255163Sshinint rtsock; /* the routing socket */ 14355163Sshinint ripsock; /* socket to send/receive RIP datagram */ 14455163Sshin 14555163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 14655163Sshin 14755163Sshin/* 14878064Sume * Maintain the routes in a linked list. When the number of the routes 14955163Sshin * grows, somebody would like to introduce a hash based or a radix tree 15078064Sume * based structure. I believe the number of routes handled by RIP is 15155163Sshin * limited and I don't have to manage a complex data structure, however. 15255163Sshin * 15355163Sshin * One of the major drawbacks of the linear linked list is the difficulty 15478064Sume * of representing the relationship between a couple of routes. This may 15555163Sshin * be a significant problem when we have to support route aggregation with 15655163Sshin * supressing the specifices covered by the aggregate. 15755163Sshin */ 15855163Sshin 15955163Sshinstruct riprt { 16055163Sshin struct riprt *rrt_next; /* next destination */ 16155163Sshin struct riprt *rrt_same; /* same destination - future use */ 16255163Sshin struct netinfo6 rrt_info; /* network info */ 16355163Sshin struct in6_addr rrt_gw; /* gateway */ 16462607Sitojun u_long rrt_flags; /* kernel routing table flags */ 16562607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 16655163Sshin time_t rrt_t; /* when the route validated */ 16755163Sshin int rrt_index; /* ifindex from which this route got */ 16855163Sshin}; 16955163Sshin 17055163Sshinstruct riprt *riprt = 0; 17155163Sshin 17255163Sshinint dflag = 0; /* debug flag */ 17355163Sshinint qflag = 0; /* quiet flag */ 17455163Sshinint nflag = 0; /* don't update kernel routing table */ 17555163Sshinint aflag = 0; /* age out even the statically defined routes */ 17655163Sshinint hflag = 0; /* don't split horizon */ 17755163Sshinint lflag = 0; /* exchange site local routes */ 17855163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 17955163Sshinint Sflag = 0; /* announce static routes to every interface */ 18062607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 18155163Sshin 18255163Sshinchar *filter[MAXFILTER]; 18355163Sshinint filtertype[MAXFILTER]; 18455163Sshinint nfilter = 0; 18555163Sshin 18655163Sshinpid_t pid; 18755163Sshin 18855163Sshinstruct sockaddr_storage ripsin; 18955163Sshin 19055163Sshinstruct rtentry rtentry; 19155163Sshin 19255163Sshinint interval = 1; 19355163Sshintime_t nextalarm = 0; 19455163Sshintime_t sup_trig_update = 0; 19555163Sshin 19655163SshinFILE *rtlog = NULL; 19755163Sshin 19855163Sshinint logopened = 0; 19955163Sshin 20055163Sshinstatic u_long seq = 0; 20155163Sshin 20278064Sumevolatile int signo; 20378064Sumevolatile sig_atomic_t seenalrm; 20478064Sumevolatile sig_atomic_t seenquit; 20578064Sumevolatile sig_atomic_t seenusr1; 20678064Sume 20762607Sitojun#define RRTF_AGGREGATE 0x08000000 20862607Sitojun#define RRTF_NOADVERTISE 0x10000000 20962607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 21062607Sitojun#define RRTF_SENDANYWAY 0x40000000 21162607Sitojun#define RRTF_CHANGED 0x80000000 21255163Sshin 21355163Sshinint main __P((int, char **)); 21478064Sumevoid sighandler __P((int)); 21578064Sumevoid ripalarm __P((void)); 21655163Sshinvoid riprecv __P((void)); 21755163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 21878064Sumeint out_filter __P((struct riprt *, struct ifc *)); 21955163Sshinvoid init __P((void)); 22055163Sshinvoid sockopt __P((struct ifc *)); 22155163Sshinvoid ifconfig __P((void)); 22262607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 22355163Sshinvoid rtrecv __P((void)); 22455163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 22555163Sshin const struct sockaddr_in6 *)); 22655163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 22755163Sshin const struct sockaddr_in6 *)); 22855163Sshinvoid filterconfig __P((void)); 22955163Sshinint getifmtu __P((int)); 23078064Sumeconst char *rttypes __P((struct rt_msghdr *)); 23178064Sumeconst char *rtflags __P((struct rt_msghdr *)); 23278064Sumeconst char *ifflags __P((int)); 23378064Sumeint ifrt __P((struct ifc *, int)); 23462607Sitojunvoid ifrt_p2p __P((struct ifc *, int)); 23555163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 23655163Sshinvoid applyplen __P((struct in6_addr *, int)); 23755163Sshinvoid ifrtdump __P((int)); 23855163Sshinvoid ifdump __P((int)); 23955163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 24055163Sshinvoid rtdump __P((int)); 24155163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 24278064Sumevoid rtdexit __P((void)); 24378064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int, 24478064Sume struct sockaddr_in6 *)); 24555163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 24655163Sshinvoid sendrequest __P((struct ifc *)); 24778064Sumeint sin6mask2len __P((const struct sockaddr_in6 *)); 24855163Sshinint mask2len __P((const struct in6_addr *, int)); 24955163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 25055163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 25155163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 25255163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 25355163Sshinvoid krtread __P((int)); 25455163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 25555163Sshinchar *allocopy __P((char *)); 25655163Sshinchar *hms __P((void)); 25755163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 25855163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 25955163Sshinstruct in6_addr *plen2mask __P((int)); 26078064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); 26155163Sshinint ripinterval __P((int)); 26255163Sshintime_t ripsuptrig __P((void)); 26366807Skrisvoid fatal __P((const char *, ...)) 26466807Skris __attribute__((__format__(__printf__, 1, 2))); 26566807Skrisvoid trace __P((int, const char *, ...)) 26666807Skris __attribute__((__format__(__printf__, 2, 3))); 26766807Skrisvoid tracet __P((int, const char *, ...)) 26866807Skris __attribute__((__format__(__printf__, 2, 3))); 26955163Sshinunsigned int if_maxindex __P((void)); 27055163Sshinstruct ifc *ifc_find __P((char *)); 27155163Sshinstruct iff *iff_find __P((struct ifc *, int)); 27255163Sshinvoid setindex2ifc __P((int, struct ifc *)); 27355163Sshin 27455163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 27555163Sshin 27655163Sshinint 27755163Sshinmain(argc, argv) 27855163Sshin int argc; 27955163Sshin char **argv; 28055163Sshin{ 28155163Sshin int ch; 28255163Sshin int error = 0; 28355163Sshin struct ifc *ifcp; 28455163Sshin sigset_t mask, omask; 28555163Sshin FILE *pidfile; 28655163Sshin char *progname; 28762607Sitojun char *ep; 28855163Sshin 28955163Sshin progname = strrchr(*argv, '/'); 29055163Sshin if (progname) 29155163Sshin progname++; 29255163Sshin else 29355163Sshin progname = *argv; 29455163Sshin 29555163Sshin pid = getpid(); 29678064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 29755163Sshin switch (ch) { 29855163Sshin case 'A': 29955163Sshin case 'N': 30055163Sshin case 'O': 30155163Sshin case 'T': 30255163Sshin case 'L': 30362607Sitojun if (nfilter >= MAXFILTER) { 30455163Sshin fatal("Exceeds MAXFILTER"); 30562607Sitojun /*NOTREACHED*/ 30662607Sitojun } 30755163Sshin filtertype[nfilter] = ch; 30855163Sshin filter[nfilter++] = allocopy(optarg); 30955163Sshin break; 31055163Sshin case 't': 31162607Sitojun ep = NULL; 31262607Sitojun routetag = strtoul(optarg, &ep, 0); 31362607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 31455163Sshin fatal("invalid route tag"); 31555163Sshin /*NOTREACHED*/ 31655163Sshin } 31755163Sshin break; 31855163Sshin case 'R': 31962607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 32055163Sshin fatal("Can not write to routelog"); 32162607Sitojun /*NOTREACHED*/ 32262607Sitojun } 32355163Sshin break; 32462607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 32562607Sitojun FLAG('a', aflag, 1); break; 32662607Sitojun FLAG('d', dflag, 1); break; 32762607Sitojun FLAG('D', dflag, 2); break; 32862607Sitojun FLAG('h', hflag, 1); break; 32962607Sitojun FLAG('l', lflag, 1); break; 33062607Sitojun FLAG('n', nflag, 1); break; 33162607Sitojun FLAG('q', qflag, 1); break; 33262607Sitojun FLAG('s', sflag, 1); break; 33362607Sitojun FLAG('S', Sflag, 1); break; 33455163Sshin#undef FLAG 33555163Sshin default: 33655163Sshin fatal("Invalid option specified, terminating"); 33762607Sitojun /*NOTREACHED*/ 33855163Sshin } 33955163Sshin } 34055163Sshin argc -= optind; 34155163Sshin argv += optind; 34278064Sume if (argc > 0) { 34355163Sshin fatal("bogus extra arguments"); 34478064Sume /*NOTREACHED*/ 34578064Sume } 34655163Sshin 34755163Sshin if (geteuid()) { 34855163Sshin nflag = 1; 34955163Sshin fprintf(stderr, "No kernel update is allowed\n"); 35055163Sshin } 351119037Sume 352119037Sume if (dflag == 0) { 353119037Sume if (daemon(0, 0) < 0) { 354119037Sume fatal("daemon"); 355119037Sume /*NOTREACHED*/ 356119037Sume } 357119037Sume } 358119037Sume 35955163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 36055163Sshin logopened++; 36178064Sume 36278064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 36378064Sume fatal("malloc"); 36478064Sume memset(ripbuf, 0, RIP6_MAXMTU); 36578064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 36678064Sume ripbuf->rip6_vers = RIP6_VERSION; 36778064Sume ripbuf->rip6_res1[0] = 0; 36878064Sume ripbuf->rip6_res1[1] = 0; 36978064Sume 37055163Sshin init(); 37155163Sshin ifconfig(); 37255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 37355163Sshin if (ifcp->ifc_index < 0) { 37455163Sshin fprintf(stderr, 37555163Sshin"No ifindex found at %s (no link-local address?)\n", 37655163Sshin ifcp->ifc_name); 37755163Sshin error++; 37855163Sshin } 37955163Sshin } 38055163Sshin if (error) 38155163Sshin exit(1); 38278064Sume if (loopifcp == NULL) { 38355163Sshin fatal("No loopback found"); 38478064Sume /*NOTREACHED*/ 38578064Sume } 386110666Sache#ifdef __FreeBSD__ 387110666Sache sranddev(); 388110666Sache#else 389110666Sache srand((unsigned)(time(NULL)^(pid<<16))); 390110666Sache#endif 39155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 39255163Sshin ifrt(ifcp, 0); 39355163Sshin filterconfig(); 39455163Sshin krtread(0); 39555163Sshin if (dflag) 39655163Sshin ifrtdump(0); 39755163Sshin 39855163Sshin pid = getpid(); 39955163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 40055163Sshin fprintf(pidfile, "%d\n", pid); 40155163Sshin fclose(pidfile); 40255163Sshin } 40355163Sshin 40478064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 40555163Sshin fatal("malloc"); 40678064Sume /*NOTREACHED*/ 40778064Sume } 40862607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 40955163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 41055163Sshin ripbuf->rip6_vers = RIP6_VERSION; 41155163Sshin ripbuf->rip6_res1[0] = 0; 41255163Sshin ripbuf->rip6_res1[1] = 0; 41355163Sshin 41478064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 41578064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 41678064Sume signal(SIGTERM, sighandler) == SIG_ERR || 41778064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 41878064Sume signal(SIGHUP, sighandler) == SIG_ERR || 41978064Sume signal(SIGINT, sighandler) == SIG_ERR) { 42078064Sume fatal("signal"); 42178064Sume /*NOTREACHED*/ 42278064Sume } 42355163Sshin /* 42455163Sshin * To avoid rip packet congestion (not on a cable but in this 42555163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 42655163Sshin * packets. 42755163Sshin */ 42855163Sshin alarm(ripinterval(INIT_INTERVAL6)); 42955163Sshin 43055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 431119041Sume if (iff_find(ifcp, 'N')) 432119041Sume continue; 43355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 43455163Sshin sendrequest(ifcp); 43555163Sshin } 43655163Sshin 43755163Sshin syslog(LOG_INFO, "**** Started ****"); 43855163Sshin sigemptyset(&mask); 43955163Sshin sigaddset(&mask, SIGALRM); 44055163Sshin while (1) { 44155163Sshin fd_set recvec; 44255163Sshin 44378064Sume if (seenalrm) { 44478064Sume ripalarm(); 44578064Sume seenalrm = 0; 44678064Sume continue; 44778064Sume } 44878064Sume if (seenquit) { 44978064Sume rtdexit(); 45078064Sume seenquit = 0; 45178064Sume continue; 45278064Sume } 45378064Sume if (seenusr1) { 45478064Sume ifrtdump(SIGUSR1); 45578064Sume seenusr1 = 0; 45678064Sume continue; 45778064Sume } 45878064Sume 45955163Sshin FD_COPY(&sockvec, &recvec); 46078064Sume signo = 0; 46155163Sshin switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { 46255163Sshin case -1: 46378064Sume if (errno != EINTR) { 46478064Sume fatal("select"); 46578064Sume /*NOTREACHED*/ 46678064Sume } 46778064Sume continue; 46855163Sshin case 0: 46955163Sshin continue; 47055163Sshin default: 47155163Sshin if (FD_ISSET(ripsock, &recvec)) { 47255163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47355163Sshin riprecv(); 47455163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 47555163Sshin } 47655163Sshin if (FD_ISSET(rtsock, &recvec)) { 47755163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47855163Sshin rtrecv(); 47955163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 48055163Sshin } 48155163Sshin } 48255163Sshin } 48355163Sshin} 48455163Sshin 48578064Sumevoid 48678064Sumesighandler(sig) 48778064Sume int sig; 48878064Sume{ 48978064Sume 49078064Sume signo = sig; 49178064Sume switch (signo) { 49278064Sume case SIGALRM: 49378064Sume seenalrm++; 49478064Sume break; 49578064Sume case SIGQUIT: 49678064Sume case SIGTERM: 49778064Sume seenquit++; 49878064Sume break; 49978064Sume case SIGUSR1: 50078064Sume case SIGHUP: 50178064Sume case SIGINT: 50278064Sume seenusr1++; 50378064Sume break; 50478064Sume } 50578064Sume} 50678064Sume 50755163Sshin/* 50855163Sshin * gracefully exits after resetting sockopts. 50955163Sshin */ 51055163Sshin/* ARGSUSED */ 51155163Sshinvoid 51278064Sumertdexit() 51355163Sshin{ 51455163Sshin struct riprt *rrt; 51555163Sshin 51655163Sshin alarm(0); 51755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 51862607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 51955163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 52055163Sshin } 52155163Sshin } 52255163Sshin close(ripsock); 52355163Sshin close(rtsock); 52455163Sshin syslog(LOG_INFO, "**** Terminated ****"); 52555163Sshin closelog(); 52655163Sshin exit(1); 52755163Sshin} 52855163Sshin 52955163Sshin/* 53055163Sshin * Called periodically: 53155163Sshin * 1. age out the learned route. remove it if necessary. 53255163Sshin * 2. submit RIP6_RESPONSE packets. 53378064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 53455163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 53555163Sshin * routes more precisely. 53655163Sshin */ 53755163Sshin/* ARGSUSED */ 53855163Sshinvoid 53978064Sumeripalarm() 54055163Sshin{ 54155163Sshin struct ifc *ifcp; 54255163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 54355163Sshin time_t t_lifetime, t_holddown; 54455163Sshin 54555163Sshin /* age the RIP routes */ 54655163Sshin rrt_prev = 0; 54755163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 54855163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 54955163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 55055163Sshin rrt_next = rrt->rrt_next; 55155163Sshin 55255163Sshin if (rrt->rrt_t == 0) { 55355163Sshin rrt_prev = rrt; 55455163Sshin continue; 55555163Sshin } 55655163Sshin if (rrt->rrt_t < t_holddown) { 55755163Sshin if (rrt_prev) { 55855163Sshin rrt_prev->rrt_next = rrt->rrt_next; 55955163Sshin } else { 56055163Sshin riprt = rrt->rrt_next; 56155163Sshin } 56255163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 56355163Sshin free(rrt); 56455163Sshin continue; 56555163Sshin } 56655163Sshin if (rrt->rrt_t < t_lifetime) 56755163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 56855163Sshin rrt_prev = rrt; 56955163Sshin } 57055163Sshin /* Supply updates */ 57155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 57255163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 57355163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 57455163Sshin } 57555163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 57655163Sshin} 57755163Sshin 57855163Sshinvoid 57955163Sshininit() 58055163Sshin{ 581119034Sume int error; 582119034Sume const int int0 = 0, int1 = 1, int255 = 255; 58355163Sshin struct addrinfo hints, *res; 58455163Sshin char port[10]; 58555163Sshin 58655163Sshin ifc = (struct ifc *)NULL; 58755163Sshin nifc = 0; 58855163Sshin nindex2ifc = 0; /*initial guess*/ 58955163Sshin index2ifc = NULL; 59055163Sshin snprintf(port, sizeof(port), "%d", RIP6_PORT); 59155163Sshin 59255163Sshin memset(&hints, 0, sizeof(hints)); 59355163Sshin hints.ai_family = PF_INET6; 59455163Sshin hints.ai_socktype = SOCK_DGRAM; 59555163Sshin hints.ai_flags = AI_PASSIVE; 59655163Sshin error = getaddrinfo(NULL, port, &hints, &res); 59778064Sume if (error) { 59866807Skris fatal("%s", gai_strerror(error)); 59978064Sume /*NOTREACHED*/ 60078064Sume } 60178064Sume if (res->ai_next) { 60255163Sshin fatal(":: resolved to multiple address"); 60378064Sume /*NOTREACHED*/ 60478064Sume } 60555163Sshin 60655163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 60778064Sume if (ripsock < 0) { 60855163Sshin fatal("rip socket"); 60978064Sume /*NOTREACHED*/ 61078064Sume } 611119034Sume#ifdef IPV6_V6ONLY 612119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 613119034Sume &int1, sizeof(int1)) < 0) { 614119034Sume fatal("rip IPV6_V6ONLY"); 615119034Sume /*NOTREACHED*/ 616119034Sume } 617119034Sume#endif 61878064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 61955163Sshin fatal("rip bind"); 62078064Sume /*NOTREACHED*/ 62178064Sume } 62255163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 62378064Sume &int255, sizeof(int255)) < 0) { 62455163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 62578064Sume /*NOTREACHED*/ 62678064Sume } 62755163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 62878064Sume &int0, sizeof(int0)) < 0) { 62955163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 63078064Sume /*NOTREACHED*/ 63178064Sume } 63262921Sume 63362607Sitojun#ifdef IPV6_RECVPKTINFO 634119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 635119034Sume &int1, sizeof(int1)) < 0) { 63662607Sitojun fatal("rip IPV6_RECVPKTINFO"); 63778064Sume /*NOTREACHED*/ 63878064Sume } 63962607Sitojun#else /* old adv. API */ 640119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 641119034Sume &int1, sizeof(int1)) < 0) { 64255163Sshin fatal("rip IPV6_PKTINFO"); 64378064Sume /*NOTREACHED*/ 64478064Sume } 64562607Sitojun#endif 64655163Sshin 64755163Sshin memset(&hints, 0, sizeof(hints)); 64855163Sshin hints.ai_family = PF_INET6; 64955163Sshin hints.ai_socktype = SOCK_DGRAM; 65055163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 65178064Sume if (error) { 65266807Skris fatal("%s", gai_strerror(error)); 65378064Sume /*NOTREACHED*/ 65478064Sume } 65578064Sume if (res->ai_next) { 65655163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 65778064Sume /*NOTREACHED*/ 65878064Sume } 65955163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 66055163Sshin 66155163Sshin#ifdef FD_ZERO 66255163Sshin FD_ZERO(&sockvec); 66355163Sshin#else 66455163Sshin memset(&sockvec, 0, sizeof(sockvec)); 66555163Sshin#endif 66655163Sshin FD_SET(ripsock, &sockvec); 66755163Sshin 66855163Sshin if (nflag == 0) { 66978064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 67055163Sshin fatal("route socket"); 67178064Sume /*NOTREACHED*/ 67278064Sume } 67355163Sshin FD_SET(rtsock, &sockvec); 67455163Sshin } else 67555163Sshin rtsock = -1; /*just for safety */ 67655163Sshin} 67755163Sshin 67862607Sitojun#define RIPSIZE(n) \ 67962607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 68055163Sshin 68155163Sshin/* 68255163Sshin * ripflush flushes the rip datagram stored in the rip buffer 68355163Sshin */ 68455163Sshinstatic int nrt; 68555163Sshinstatic struct netinfo6 *np; 68655163Sshin 68755163Sshinvoid 688119031Sumeripflush(ifcp, sin6) 68955163Sshin struct ifc *ifcp; 690119031Sume struct sockaddr_in6 *sin6; 69155163Sshin{ 69255163Sshin int i; 69355163Sshin int error; 69455163Sshin 69555163Sshin if (ifcp) 69655163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 69755163Sshin ifcp->ifc_name, nrt, 698119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 69955163Sshin else 70055163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 701119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 70255163Sshin if (dflag >= 2) { 70355163Sshin np = ripbuf->rip6_nets; 70455163Sshin for (i = 0; i < nrt; i++, np++) { 70555163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 70655163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 70762607Sitojun trace(2, " NextHop reset"); 70855163Sshin else { 70955163Sshin trace(2, " NextHop %s", 71055163Sshin inet6_n2p(&np->rip6_dest)); 71155163Sshin } 71255163Sshin } else { 71355163Sshin trace(2, " %s/%d[%d]", 71455163Sshin inet6_n2p(&np->rip6_dest), 71555163Sshin np->rip6_plen, np->rip6_metric); 71655163Sshin } 71755163Sshin if (np->rip6_tag) { 71855163Sshin trace(2, " tag=0x%04x", 71955163Sshin ntohs(np->rip6_tag) & 0xffff); 72055163Sshin } 72155163Sshin trace(2, "\n"); 72255163Sshin } 72355163Sshin } 724119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 72555163Sshin if (error == EAFNOSUPPORT) { 72655163Sshin /* Protocol not supported */ 72755163Sshin tracet(1, "Could not send info to %s (%s): " 72855163Sshin "set IFF_UP to 0\n", 72955163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 73055163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 73155163Sshin } 73255163Sshin nrt = 0; np = ripbuf->rip6_nets; 73355163Sshin} 73455163Sshin 73555163Sshin/* 73655163Sshin * Generate RIP6_RESPONSE packets and send them. 73755163Sshin */ 73855163Sshinvoid 739119031Sumeripsend(ifcp, sin6, flag) 74055163Sshin struct ifc *ifcp; 741119031Sume struct sockaddr_in6 *sin6; 74255163Sshin int flag; 74355163Sshin{ 74455163Sshin struct riprt *rrt; 74555163Sshin struct in6_addr *nh; /* next hop */ 74678064Sume int maxrte; 74755163Sshin 74855163Sshin if (ifcp == NULL) { 74955163Sshin /* 75055163Sshin * Request from non-link local address is not 75155163Sshin * a regular route6d update. 75255163Sshin */ 75362607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 75462607Sitojun sizeof(struct udphdr) - 75555163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 75655163Sshin sizeof(struct netinfo6); 75755163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 75855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 75962607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 76055163Sshin continue; 76155163Sshin /* Put the route to the buffer */ 76255163Sshin *np = rrt->rrt_info; 76355163Sshin np++; nrt++; 76455163Sshin if (nrt == maxrte) { 765119031Sume ripflush(NULL, sin6); 76655163Sshin nh = NULL; 76755163Sshin } 76855163Sshin } 76955163Sshin if (nrt) /* Send last packet */ 770119031Sume ripflush(NULL, sin6); 77155163Sshin return; 77255163Sshin } 77355163Sshin 77462607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 77555163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 77655163Sshin return; 77778064Sume 77878064Sume /* -N: no use */ 77955163Sshin if (iff_find(ifcp, 'N') != NULL) 78055163Sshin return; 78178064Sume 78278064Sume /* -T: generate default route only */ 78355163Sshin if (iff_find(ifcp, 'T') != NULL) { 78455163Sshin struct netinfo6 rrt_info; 78555163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 78655163Sshin rrt_info.rip6_dest = in6addr_any; 78755163Sshin rrt_info.rip6_plen = 0; 78855163Sshin rrt_info.rip6_metric = 1; 78978064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 79055163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 79155163Sshin np = ripbuf->rip6_nets; 79255163Sshin *np = rrt_info; 79355163Sshin nrt = 1; 794119031Sume ripflush(ifcp, sin6); 79555163Sshin return; 79655163Sshin } 79778064Sume 79862607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 79962607Sitojun sizeof(struct udphdr) - 80055163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 80155163Sshin sizeof(struct netinfo6); 80278064Sume 80355163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 80455163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 80562607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 80655163Sshin continue; 80778064Sume 80878064Sume /* Need to check filter here */ 80978064Sume if (out_filter(rrt, ifcp) == 0) 81055163Sshin continue; 81178064Sume 81255163Sshin /* Check split horizon and other conditions */ 81355163Sshin if (tobeadv(rrt, ifcp) == 0) 81455163Sshin continue; 81578064Sume 81655163Sshin /* Only considers the routes with flag if specified */ 81762607Sitojun if ((flag & RRTF_CHANGED) && 81862607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 81955163Sshin continue; 82078064Sume 82155163Sshin /* Check nexthop */ 82255163Sshin if (rrt->rrt_index == ifcp->ifc_index && 82355163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 82462607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 82555163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 82655163Sshin if (nrt == maxrte - 2) 827119031Sume ripflush(ifcp, sin6); 82855163Sshin np->rip6_dest = rrt->rrt_gw; 82955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 83055163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 83155163Sshin np->rip6_plen = 0; 83255163Sshin np->rip6_tag = 0; 83355163Sshin np->rip6_metric = NEXTHOP_METRIC; 83455163Sshin nh = &rrt->rrt_gw; 83555163Sshin np++; nrt++; 83655163Sshin } 83755163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 83855163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 83962607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 84055163Sshin /* Reset nexthop */ 84155163Sshin if (nrt == maxrte - 2) 842119031Sume ripflush(ifcp, sin6); 84355163Sshin memset(np, 0, sizeof(struct netinfo6)); 84455163Sshin np->rip6_metric = NEXTHOP_METRIC; 84555163Sshin nh = NULL; 84655163Sshin np++; nrt++; 84755163Sshin } 84878064Sume 84955163Sshin /* Put the route to the buffer */ 85055163Sshin *np = rrt->rrt_info; 85155163Sshin np++; nrt++; 85255163Sshin if (nrt == maxrte) { 853119031Sume ripflush(ifcp, sin6); 85455163Sshin nh = NULL; 85555163Sshin } 85655163Sshin } 85755163Sshin if (nrt) /* Send last packet */ 858119031Sume ripflush(ifcp, sin6); 85955163Sshin} 86055163Sshin 86155163Sshin/* 86278064Sume * outbound filter logic, per-route/interface. 86378064Sume */ 86478064Sumeint 86578064Sumeout_filter(rrt, ifcp) 86678064Sume struct riprt *rrt; 86778064Sume struct ifc *ifcp; 86878064Sume{ 86978064Sume struct iff *iffp; 87078064Sume struct in6_addr ia; 87178064Sume int ok; 87278064Sume 87378064Sume /* 87478064Sume * -A: filter out less specific routes, if we have aggregated 87578064Sume * route configured. 87678064Sume */ 87778064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 87878064Sume if (iffp->iff_type != 'A') 87978064Sume continue; 88078064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 88178064Sume continue; 88278064Sume ia = rrt->rrt_info.rip6_dest; 88378064Sume applyplen(&ia, iffp->iff_plen); 88478064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 88578064Sume return 0; 88678064Sume } 88778064Sume 88878064Sume /* 88978064Sume * if it is an aggregated route, advertise it only to the 89078064Sume * interfaces specified on -A. 89178064Sume */ 89278064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 89378064Sume ok = 0; 89478064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 89578064Sume if (iffp->iff_type != 'A') 89678064Sume continue; 89778064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 89878064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 89978064Sume &iffp->iff_addr)) { 90078064Sume ok = 1; 90178064Sume break; 90278064Sume } 90378064Sume } 90478064Sume if (!ok) 90578064Sume return 0; 90678064Sume } 90778064Sume 90878064Sume /* 90978064Sume * -O: advertise only if prefix matches the configured prefix. 91078064Sume */ 91178064Sume if (iff_find(ifcp, 'O')) { 91278064Sume ok = 0; 91378064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 91478064Sume if (iffp->iff_type != 'O') 91578064Sume continue; 91678064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 91778064Sume continue; 91878064Sume ia = rrt->rrt_info.rip6_dest; 91978064Sume applyplen(&ia, iffp->iff_plen); 92078064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 92178064Sume ok = 1; 92278064Sume break; 92378064Sume } 92478064Sume } 92578064Sume if (!ok) 92678064Sume return 0; 92778064Sume } 92878064Sume 92978064Sume /* the prefix should be advertised */ 93078064Sume return 1; 93178064Sume} 93278064Sume 93378064Sume/* 93455163Sshin * Determine if the route is to be advertised on the specified interface. 93555163Sshin * It checks options specified in the arguments and the split horizon rule. 93655163Sshin */ 93755163Sshinint 93855163Sshintobeadv(rrt, ifcp) 93955163Sshin struct riprt *rrt; 94055163Sshin struct ifc *ifcp; 94155163Sshin{ 94255163Sshin 94355163Sshin /* Special care for static routes */ 94455163Sshin if (rrt->rrt_flags & RTF_STATIC) { 94562607Sitojun /* XXX don't advertise reject/blackhole routes */ 94662607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 94762607Sitojun return 0; 94862607Sitojun 94955163Sshin if (Sflag) /* Yes, advertise it anyway */ 95055163Sshin return 1; 95155163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 95255163Sshin return 1; 95355163Sshin return 0; 95455163Sshin } 95555163Sshin /* Regular split horizon */ 95655163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 95755163Sshin return 0; 95855163Sshin return 1; 95955163Sshin} 96055163Sshin 96155163Sshin/* 96255163Sshin * Send a rip packet actually. 96355163Sshin */ 96455163Sshinint 965119031Sumesendpacket(sin6, len) 966119031Sume struct sockaddr_in6 *sin6; 96755163Sshin int len; 96855163Sshin{ 96955163Sshin /* 97055163Sshin * MSG_DONTROUTE should not be specified when it responds with a 97178064Sume * RIP6_REQUEST message. SO_DONTROUTE has been specified to 97255163Sshin * other sockets. 97355163Sshin */ 97455163Sshin struct msghdr m; 97555163Sshin struct cmsghdr *cm; 97655163Sshin struct iovec iov[2]; 97755163Sshin u_char cmsgbuf[256]; 97855163Sshin struct in6_pktinfo *pi; 97978064Sume int idx; 98055163Sshin struct sockaddr_in6 sincopy; 98155163Sshin 98255163Sshin /* do not overwrite the given sin */ 983119031Sume sincopy = *sin6; 984119031Sume sin6 = &sincopy; 98555163Sshin 986119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 987119035Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 988119031Sume idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 989119031Sume SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 99055163Sshin } else 99178064Sume idx = 0; 99255163Sshin 993119031Sume m.msg_name = (caddr_t)sin6; 994119031Sume m.msg_namelen = sizeof(*sin6); 99555163Sshin iov[0].iov_base = (caddr_t)ripbuf; 99655163Sshin iov[0].iov_len = len; 99755163Sshin m.msg_iov = iov; 99855163Sshin m.msg_iovlen = 1; 99978064Sume if (!idx) { 100055163Sshin m.msg_control = NULL; 100155163Sshin m.msg_controllen = 0; 100255163Sshin } else { 100355163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 100455163Sshin cm = (struct cmsghdr *)cmsgbuf; 100555163Sshin m.msg_control = (caddr_t)cm; 100655163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 100755163Sshin 100855163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 100955163Sshin cm->cmsg_level = IPPROTO_IPV6; 101055163Sshin cm->cmsg_type = IPV6_PKTINFO; 101155163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 101255163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 101378064Sume pi->ipi6_ifindex = idx; 101455163Sshin } 101555163Sshin 101655163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 101755163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 101855163Sshin return errno; 101955163Sshin } 102062921Sume 102155163Sshin return 0; 102255163Sshin} 102355163Sshin 102455163Sshin/* 102578064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 102655163Sshin * table if necessary. 102755163Sshin */ 102855163Sshinvoid 102955163Sshinriprecv() 103055163Sshin{ 103155163Sshin struct ifc *ifcp, *ic; 103255163Sshin struct sockaddr_in6 fsock; 103355163Sshin struct in6_addr nh; /* next hop */ 103455163Sshin struct rip6 *rp; 103555163Sshin struct netinfo6 *np, *nq; 103655163Sshin struct riprt *rrt; 103778064Sume int len, nn, need_trigger, idx; 103855163Sshin char buf[4 * RIP6_MAXMTU]; 103955163Sshin time_t t; 104055163Sshin struct msghdr m; 104155163Sshin struct cmsghdr *cm; 104255163Sshin struct iovec iov[2]; 104355163Sshin u_char cmsgbuf[256]; 104455163Sshin struct in6_pktinfo *pi; 104555163Sshin struct iff *iffp; 104655163Sshin struct in6_addr ia; 104755163Sshin int ok; 104878064Sume time_t t_half_lifetime; 104955163Sshin 105055163Sshin need_trigger = 0; 105162921Sume 105255163Sshin m.msg_name = (caddr_t)&fsock; 105355163Sshin m.msg_namelen = sizeof(fsock); 105455163Sshin iov[0].iov_base = (caddr_t)buf; 105555163Sshin iov[0].iov_len = sizeof(buf); 105655163Sshin m.msg_iov = iov; 105755163Sshin m.msg_iovlen = 1; 105855163Sshin cm = (struct cmsghdr *)cmsgbuf; 105955163Sshin m.msg_control = (caddr_t)cm; 106055163Sshin m.msg_controllen = sizeof(cmsgbuf); 106178064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 106255163Sshin fatal("recvmsg"); 106378064Sume /*NOTREACHED*/ 106478064Sume } 106578064Sume idx = 0; 106655163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 106755163Sshin cm; 106855163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 106978064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 107078064Sume cm->cmsg_type == IPV6_PKTINFO) { 107155163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 107278064Sume idx = pi->ipi6_ifindex; 107355163Sshin break; 107455163Sshin } 107555163Sshin } 107678064Sume if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 107778064Sume SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 107855163Sshin 107955163Sshin nh = fsock.sin6_addr; 108055163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 108155163Sshin sizeof(struct netinfo6); 108255163Sshin rp = (struct rip6 *)buf; 108355163Sshin np = rp->rip6_nets; 108455163Sshin 1085119035Sume if (rp->rip6_vers != RIP6_VERSION) { 108655163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 108755163Sshin return; 108855163Sshin } 108955163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 109078064Sume if (idx && idx < nindex2ifc) { 109178064Sume ifcp = index2ifc[idx]; 109255163Sshin riprequest(ifcp, np, nn, &fsock); 109355163Sshin } else { 109455163Sshin riprequest(NULL, np, nn, &fsock); 109555163Sshin } 109662607Sitojun return; 109762607Sitojun } 109855163Sshin 109955163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 110055163Sshin trace(1, "Packets from non-ll addr: %s\n", 110178064Sume inet6_n2p(&fsock.sin6_addr)); 110255163Sshin return; /* Ignore packets from non-link-local addr */ 110355163Sshin } 110478064Sume idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 110578064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 110655163Sshin if (!ifcp) { 110778064Sume trace(1, "Packets to unknown interface index %d\n", idx); 110855163Sshin return; /* Ignore it */ 110955163Sshin } 111055163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 111155163Sshin return; /* The packet is from me; ignore */ 111255163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 111355163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 111462607Sitojun return; 111555163Sshin } 111678064Sume 111778064Sume /* -N: no use */ 111855163Sshin if (iff_find(ifcp, 'N') != NULL) 111955163Sshin return; 112078064Sume 112155163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 112278064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 112355163Sshin 112455163Sshin t = time(NULL); 112578064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 112655163Sshin for (; nn; nn--, np++) { 112755163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 112855163Sshin /* modify neighbor address */ 112955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 113055163Sshin nh = np->rip6_dest; 113178064Sume SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 113255163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 113355163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 113455163Sshin nh = fsock.sin6_addr; 113555163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 113655163Sshin } else { 113755163Sshin nh = fsock.sin6_addr; 113855163Sshin trace(1, "\tInvalid Nexthop: %s\n", 113978064Sume inet6_n2p(&np->rip6_dest)); 114055163Sshin } 114155163Sshin continue; 114255163Sshin } 114355163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 114455163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 114555163Sshin inet6_n2p(&np->rip6_dest), 114655163Sshin np->rip6_plen, np->rip6_metric); 114755163Sshin continue; 114855163Sshin } 114955163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 115055163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 115155163Sshin inet6_n2p(&np->rip6_dest), 115255163Sshin np->rip6_plen, np->rip6_metric); 115355163Sshin continue; 115455163Sshin } 115555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 115655163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 115755163Sshin inet6_n2p(&np->rip6_dest), 115855163Sshin np->rip6_plen, np->rip6_metric); 115955163Sshin continue; 116055163Sshin } 116155163Sshin /* may need to pass sitelocal prefix in some case, however*/ 116255163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 116355163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 116455163Sshin inet6_n2p(&np->rip6_dest), 116555163Sshin np->rip6_plen, np->rip6_metric); 116655163Sshin continue; 116755163Sshin } 116855163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 116955163Sshin inet6_n2p(&np->rip6_dest), 117055163Sshin np->rip6_plen, np->rip6_metric); 117155163Sshin if (np->rip6_tag) 117255163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 117362607Sitojun if (dflag >= 2) { 117462607Sitojun ia = np->rip6_dest; 117562607Sitojun applyplen(&ia, np->rip6_plen); 117662607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 117762607Sitojun trace(2, " [junk outside prefix]"); 117862607Sitojun } 117955163Sshin 118078064Sume /* 118178064Sume * -L: listen only if the prefix matches the configuration 118278064Sume */ 118355163Sshin ok = 1; /* if there's no L filter, it is ok */ 118455163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 118555163Sshin if (iffp->iff_type != 'L') 118655163Sshin continue; 118755163Sshin ok = 0; 118855163Sshin if (np->rip6_plen < iffp->iff_plen) 118955163Sshin continue; 119055163Sshin /* special rule: ::/0 means default, not "in /0" */ 119155163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 119255163Sshin continue; 119362607Sitojun ia = np->rip6_dest; 119455163Sshin applyplen(&ia, iffp->iff_plen); 119555163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 119655163Sshin ok = 1; 119755163Sshin break; 119855163Sshin } 119955163Sshin } 120055163Sshin if (!ok) { 120155163Sshin trace(2, " (filtered)\n"); 120255163Sshin continue; 120355163Sshin } 120455163Sshin 120555163Sshin trace(2, "\n"); 120655163Sshin np->rip6_metric++; 120755163Sshin np->rip6_metric += ifcp->ifc_metric; 120855163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 120955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 121055163Sshin 121155163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 121278064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 121355163Sshin if (rrt->rrt_t == 0) 121455163Sshin continue; /* Intf route has priority */ 121555163Sshin nq = &rrt->rrt_info; 121655163Sshin if (nq->rip6_metric > np->rip6_metric) { 121755163Sshin if (rrt->rrt_index == ifcp->ifc_index && 121855163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 121955163Sshin /* Small metric from the same gateway */ 122055163Sshin nq->rip6_metric = np->rip6_metric; 122155163Sshin } else { 122255163Sshin /* Better route found */ 122355163Sshin rrt->rrt_index = ifcp->ifc_index; 122455163Sshin /* Update routing table */ 122555163Sshin delroute(nq, &rrt->rrt_gw); 122655163Sshin rrt->rrt_gw = nh; 122755163Sshin *nq = *np; 122855163Sshin addroute(rrt, &nh, ifcp); 122955163Sshin } 123062607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 123155163Sshin rrt->rrt_t = t; 123255163Sshin need_trigger = 1; 123355163Sshin } else if (nq->rip6_metric < np->rip6_metric && 123455163Sshin rrt->rrt_index == ifcp->ifc_index && 123555163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 123655163Sshin /* Got worse route from same gw */ 123755163Sshin nq->rip6_metric = np->rip6_metric; 123855163Sshin rrt->rrt_t = t; 123962607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 124055163Sshin need_trigger = 1; 124155163Sshin } else if (nq->rip6_metric == np->rip6_metric && 124255163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 124378064Sume if (rrt->rrt_index == ifcp->ifc_index && 124478064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 124578064Sume /* same metric, same route from same gw */ 124678064Sume rrt->rrt_t = t; 124778064Sume } else if (rrt->rrt_t < t_half_lifetime) { 124878064Sume /* Better route found */ 124978064Sume rrt->rrt_index = ifcp->ifc_index; 125078064Sume /* Update routing table */ 125178064Sume delroute(nq, &rrt->rrt_gw); 125278064Sume rrt->rrt_gw = nh; 125378064Sume *nq = *np; 125478064Sume addroute(rrt, &nh, ifcp); 125578064Sume rrt->rrt_rflags |= RRTF_CHANGED; 125678064Sume rrt->rrt_t = t; 125778064Sume } 125855163Sshin } 125962607Sitojun /* 126055163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 126178064Sume * do not update age value. Do nothing. 126255163Sshin */ 126355163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 126455163Sshin /* Got a new valid route */ 126578064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 126655163Sshin fatal("malloc: struct riprt"); 126778064Sume /*NOTREACHED*/ 126878064Sume } 126962607Sitojun memset(rrt, 0, sizeof(*rrt)); 127055163Sshin nq = &rrt->rrt_info; 127155163Sshin 127255163Sshin rrt->rrt_same = NULL; 127355163Sshin rrt->rrt_index = ifcp->ifc_index; 127455163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 127555163Sshin rrt->rrt_gw = nh; 127655163Sshin *nq = *np; 127755163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 127855163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 127955163Sshin rrt->rrt_flags |= RTF_HOST; 128055163Sshin 128155163Sshin /* Put the route to the list */ 128255163Sshin rrt->rrt_next = riprt; 128355163Sshin riprt = rrt; 128455163Sshin /* Update routing table */ 128555163Sshin addroute(rrt, &nh, ifcp); 128662607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 128755163Sshin need_trigger = 1; 128855163Sshin rrt->rrt_t = t; 128955163Sshin } 129055163Sshin } 129155163Sshin /* XXX need to care the interval between triggered updates */ 129255163Sshin if (need_trigger) { 129355163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 129455163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 129555163Sshin if (ifcp->ifc_index == ic->ifc_index) 129655163Sshin continue; 129755163Sshin if (ic->ifc_flags & IFF_UP) 129855163Sshin ripsend(ic, &ic->ifc_ripsin, 129962607Sitojun RRTF_CHANGED); 130055163Sshin } 130155163Sshin } 130255163Sshin /* Reset the flag */ 130355163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 130462607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 130555163Sshin } 130655163Sshin} 130755163Sshin 130855163Sshin/* 130955163Sshin * Send all routes request packet to the specified interface. 131055163Sshin */ 131155163Sshinvoid 131255163Sshinsendrequest(ifcp) 131355163Sshin struct ifc *ifcp; 131455163Sshin{ 131555163Sshin struct netinfo6 *np; 131655163Sshin int error; 131755163Sshin 131855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 131955163Sshin return; 132055163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 132155163Sshin np = ripbuf->rip6_nets; 132255163Sshin memset(np, 0, sizeof(struct netinfo6)); 132355163Sshin np->rip6_metric = HOPCNT_INFINITY6; 132455163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 132555163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 132655163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 132755163Sshin if (error == EAFNOSUPPORT) { 132855163Sshin /* Protocol not supported */ 132955163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 133055163Sshin "set IFF_UP to 0\n", 133155163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 133255163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 133355163Sshin } 133455163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 133555163Sshin} 133655163Sshin 133755163Sshin/* 133855163Sshin * Process a RIP6_REQUEST packet. 133955163Sshin */ 134055163Sshinvoid 1341119031Sumeriprequest(ifcp, np, nn, sin6) 134255163Sshin struct ifc *ifcp; 134355163Sshin struct netinfo6 *np; 134455163Sshin int nn; 1345119031Sume struct sockaddr_in6 *sin6; 134655163Sshin{ 134755163Sshin int i; 134855163Sshin struct riprt *rrt; 134955163Sshin 135055163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 135155163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 135255163Sshin /* Specific response, don't split-horizon */ 135355163Sshin trace(1, "\tRIP Request\n"); 135455163Sshin for (i = 0; i < nn; i++, np++) { 135578064Sume rrt = rtsearch(np, NULL); 135655163Sshin if (rrt) 135755163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 135855163Sshin else 135955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 136055163Sshin } 1361119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 136255163Sshin return; 136355163Sshin } 136455163Sshin /* Whole routing table dump */ 136555163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1366119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 136755163Sshin} 136855163Sshin 136955163Sshin/* 137055163Sshin * Get information of each interface. 137155163Sshin */ 137255163Sshinvoid 137355163Sshinifconfig() 137455163Sshin{ 137562607Sitojun struct ifaddrs *ifap, *ifa; 137662607Sitojun struct ifc *ifcp; 137762607Sitojun struct ipv6_mreq mreq; 137862607Sitojun int s; 137962607Sitojun 138078064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 138162607Sitojun fatal("socket"); 138278064Sume /*NOTREACHED*/ 138378064Sume } 138462607Sitojun 138578064Sume if (getifaddrs(&ifap) != 0) { 138662607Sitojun fatal("getifaddrs"); 138778064Sume /*NOTREACHED*/ 138878064Sume } 138962607Sitojun 139062607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 139162607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 139262607Sitojun continue; 139362607Sitojun ifcp = ifc_find(ifa->ifa_name); 139462607Sitojun /* we are interested in multicast-capable interfaces */ 139562607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 139662607Sitojun continue; 139762607Sitojun if (!ifcp) { 139862607Sitojun /* new interface */ 139978064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 140062607Sitojun fatal("malloc: struct ifc"); 140178064Sume /*NOTREACHED*/ 140278064Sume } 140362607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 140462607Sitojun ifcp->ifc_index = -1; 140562607Sitojun ifcp->ifc_next = ifc; 140662607Sitojun ifc = ifcp; 140762607Sitojun nifc++; 140862607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 140962607Sitojun ifcp->ifc_addr = 0; 141062607Sitojun ifcp->ifc_filter = 0; 141162607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 141262607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 141362607Sitojun ifflags(ifcp->ifc_flags)); 141462607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 141562607Sitojun loopifcp = ifcp; 141662607Sitojun } else { 141762607Sitojun /* update flag, this may be up again */ 141862607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 141962607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 142062607Sitojun ifflags(ifcp->ifc_flags)); 142162607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 142278064Sume ifcp->ifc_cflags |= IFC_CHANGED; 142362607Sitojun } 142462607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 142562607Sitojun } 142662607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 142762607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 142862607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 142962607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 143062607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 143178064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 143278064Sume &mreq, sizeof(mreq)) < 0) { 143362607Sitojun fatal("IPV6_JOIN_GROUP"); 143478064Sume /*NOTREACHED*/ 143578064Sume } 143662607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 143762607Sitojun ifcp->ifc_joined++; 143862607Sitojun } 143962607Sitojun } 144062607Sitojun close(s); 144162607Sitojun freeifaddrs(ifap); 144255163Sshin} 144355163Sshin 144455163Sshinvoid 144562607Sitojunifconfig1(name, sa, ifcp, s) 144662607Sitojun const char *name; 144762607Sitojun const struct sockaddr *sa; 144855163Sshin struct ifc *ifcp; 144955163Sshin int s; 145055163Sshin{ 145155163Sshin struct in6_ifreq ifr; 1452119031Sume const struct sockaddr_in6 *sin6; 145355163Sshin struct ifac *ifa; 145455163Sshin int plen; 145555163Sshin char buf[BUFSIZ]; 145655163Sshin 1457119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1458119031Sume ifr.ifr_addr = *sin6; 1459119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 146078064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 146155163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 146278064Sume /*NOTREACHED*/ 146378064Sume } 146478064Sume plen = sin6mask2len(&ifr.ifr_addr); 1465119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 146655163Sshin /* same interface found */ 146755163Sshin /* need check if something changed */ 146855163Sshin /* XXX not yet implemented */ 146955163Sshin return; 147055163Sshin } 147155163Sshin /* 147255163Sshin * New address is found 147355163Sshin */ 147478064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 147555163Sshin fatal("malloc: struct ifac"); 147678064Sume /*NOTREACHED*/ 147778064Sume } 147862607Sitojun memset(ifa, 0, sizeof(*ifa)); 147955163Sshin ifa->ifa_conf = ifcp; 148055163Sshin ifa->ifa_next = ifcp->ifc_addr; 148155163Sshin ifcp->ifc_addr = ifa; 1482119031Sume ifa->ifa_addr = sin6->sin6_addr; 148355163Sshin ifa->ifa_plen = plen; 148455163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1485119031Sume ifr.ifr_addr = *sin6; 148678064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 148755163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 148878064Sume /*NOTREACHED*/ 148978064Sume } 149055163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 149155163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 149255163Sshin trace(1, "found address %s/%d -- %s\n", 149355163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 149455163Sshin } else { 149555163Sshin trace(1, "found address %s/%d\n", 149655163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 149755163Sshin } 149855163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 149955163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 150055163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 150155163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 150255163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 150355163Sshin ifcp->ifc_index); 150455163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 150555163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 150655163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 150755163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 150878064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 150955163Sshin fatal("ioctl: SIOCGIFMETRIC"); 151078064Sume /*NOTREACHED*/ 151178064Sume } 151255163Sshin ifcp->ifc_metric = ifr.ifr_metric; 151355163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 151455163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 151578064Sume } else 151678064Sume ifcp->ifc_cflags |= IFC_CHANGED; 151755163Sshin} 151855163Sshin 151955163Sshin/* 152055163Sshin * Receive and process routing messages. 152155163Sshin * Update interface information as necesssary. 152255163Sshin */ 152355163Sshinvoid 152455163Sshinrtrecv() 152555163Sshin{ 152655163Sshin char buf[BUFSIZ]; 152755163Sshin char *p, *q; 152855163Sshin struct rt_msghdr *rtm; 152955163Sshin struct ifa_msghdr *ifam; 153055163Sshin struct if_msghdr *ifm; 153155163Sshin int len; 153278064Sume struct ifc *ifcp, *ic; 153355163Sshin int iface = 0, rtable = 0; 153455163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 153578064Sume struct sockaddr_in6 mask; 153655163Sshin int i, addrs; 153778064Sume struct riprt *rrt; 153855163Sshin 153955163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 154055163Sshin perror("read from rtsock"); 154178064Sume exit(1); 154255163Sshin } 154355163Sshin if (len < sizeof(*rtm)) { 154469279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 154569279Sume len, (u_long)sizeof(*rtm)); 154655163Sshin return; 154755163Sshin } 1548119042Sume if (dflag >= 2) { 1549119042Sume fprintf(stderr, "rtmsg:\n"); 1550119042Sume for (i = 0; i < len; i++) { 1551119042Sume fprintf(stderr, "%02x ", buf[i] & 0xff); 1552119042Sume if (i % 16 == 15) fprintf(stderr, "\n"); 1553119042Sume } 1554119042Sume fprintf(stderr, "\n"); 1555119042Sume } 155655163Sshin 155755163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 155855163Sshin /* safety against bogus message */ 155955163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 156055163Sshin trace(1, "bogus rtmsg: length=%d\n", 156155163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 156255163Sshin break; 156355163Sshin } 156455163Sshin rtm = NULL; 156555163Sshin ifam = NULL; 156655163Sshin ifm = NULL; 156755163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 156855163Sshin case RTM_NEWADDR: 156955163Sshin case RTM_DELADDR: 157055163Sshin ifam = (struct ifa_msghdr *)p; 157155163Sshin addrs = ifam->ifam_addrs; 157255163Sshin q = (char *)(ifam + 1); 157355163Sshin break; 157455163Sshin case RTM_IFINFO: 157555163Sshin ifm = (struct if_msghdr *)p; 157655163Sshin addrs = ifm->ifm_addrs; 157755163Sshin q = (char *)(ifm + 1); 157855163Sshin break; 157955163Sshin default: 158055163Sshin rtm = (struct rt_msghdr *)p; 158155163Sshin addrs = rtm->rtm_addrs; 158255163Sshin q = (char *)(rtm + 1); 158355163Sshin if (rtm->rtm_version != RTM_VERSION) { 158455163Sshin trace(1, "unexpected rtmsg version %d " 158555163Sshin "(should be %d)\n", 158655163Sshin rtm->rtm_version, RTM_VERSION); 158755163Sshin continue; 158855163Sshin } 158955163Sshin if (rtm->rtm_pid == pid) { 159055163Sshin#if 0 159155163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 159255163Sshin#endif 159355163Sshin continue; 159455163Sshin } 159555163Sshin break; 159655163Sshin } 159755163Sshin memset(&rta, 0, sizeof(rta)); 159855163Sshin for (i = 0; i < RTAX_MAX; i++) { 159955163Sshin if (addrs & (1 << i)) { 160055163Sshin rta[i] = (struct sockaddr_in6 *)q; 160155163Sshin q += ROUNDUP(rta[i]->sin6_len); 160255163Sshin } 160355163Sshin } 160455163Sshin 160555163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 160655163Sshin rttypes((struct rt_msghdr *)p), addrs); 160755163Sshin if (dflag >= 2) { 160855163Sshin for (i = 0; 160955163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 161055163Sshin i++) { 161155163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 161255163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 161355163Sshin } 161455163Sshin fprintf(stderr, "\n"); 161555163Sshin } 161655163Sshin 161755163Sshin /* 161855163Sshin * Easy ones first. 161955163Sshin * 162055163Sshin * We may be able to optimize by using ifm->ifm_index or 162155163Sshin * ifam->ifam_index. For simplicity we don't do that here. 162255163Sshin */ 162355163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 162455163Sshin case RTM_NEWADDR: 162555163Sshin case RTM_IFINFO: 162655163Sshin iface++; 162755163Sshin continue; 162855163Sshin case RTM_ADD: 162955163Sshin rtable++; 163055163Sshin continue; 163155163Sshin case RTM_LOSING: 163255163Sshin case RTM_MISS: 163355163Sshin case RTM_RESOLVE: 163455163Sshin case RTM_GET: 163555163Sshin case RTM_LOCK: 163655163Sshin /* nothing to be done here */ 163755163Sshin trace(1, "\tnothing to be done, ignored\n"); 163855163Sshin continue; 163955163Sshin } 164055163Sshin 164155163Sshin#if 0 164255163Sshin if (rta[RTAX_DST] == NULL) { 164355163Sshin trace(1, "\tno destination, ignored\n"); 164462607Sitojun continue; 164555163Sshin } 164655163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 164755163Sshin trace(1, "\taf mismatch, ignored\n"); 164855163Sshin continue; 164955163Sshin } 165055163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 165155163Sshin trace(1, "\tlinklocal destination, ignored\n"); 165255163Sshin continue; 165355163Sshin } 165455163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 165555163Sshin trace(1, "\tloopback destination, ignored\n"); 165655163Sshin continue; /* Loopback */ 165755163Sshin } 165855163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 165955163Sshin trace(1, "\tmulticast destination, ignored\n"); 166055163Sshin continue; 166155163Sshin } 166255163Sshin#endif 166355163Sshin 166455163Sshin /* hard ones */ 166555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 166655163Sshin case RTM_NEWADDR: 166755163Sshin case RTM_IFINFO: 166855163Sshin case RTM_ADD: 166955163Sshin case RTM_LOSING: 167055163Sshin case RTM_MISS: 167155163Sshin case RTM_RESOLVE: 167255163Sshin case RTM_GET: 167355163Sshin case RTM_LOCK: 167455163Sshin /* should already be handled */ 167555163Sshin fatal("rtrecv: never reach here"); 167678064Sume /*NOTREACHED*/ 167755163Sshin case RTM_DELETE: 167878064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 167978064Sume trace(1, "\tsome of dst/gw/netamsk are " 168078064Sume "unavailable, ignored\n"); 168155163Sshin break; 168255163Sshin } 168378064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 168478064Sume mask.sin6_len = sizeof(mask); 168578064Sume memset(&mask.sin6_addr, 0xff, 168678064Sume sizeof(mask.sin6_addr)); 168778064Sume rta[RTAX_NETMASK] = &mask; 168878064Sume } else if (!rta[RTAX_NETMASK]) { 168978064Sume trace(1, "\tsome of dst/gw/netamsk are " 169078064Sume "unavailable, ignored\n"); 169178064Sume break; 169278064Sume } 169378064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 169478064Sume rta[RTAX_NETMASK]) == 0) { 169555163Sshin rtable++; /*just to be sure*/ 169655163Sshin } 169755163Sshin break; 169855163Sshin case RTM_CHANGE: 169955163Sshin case RTM_REDIRECT: 170055163Sshin trace(1, "\tnot supported yet, ignored\n"); 170155163Sshin break; 170255163Sshin case RTM_DELADDR: 170355163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 170455163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 170555163Sshin break; 170655163Sshin } 170755163Sshin if (ifam->ifam_index < nindex2ifc) 170855163Sshin ifcp = index2ifc[ifam->ifam_index]; 170955163Sshin else 171055163Sshin ifcp = NULL; 171155163Sshin if (!ifcp) { 171255163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 171355163Sshin ifam->ifam_index); 171455163Sshin break; 171555163Sshin } 171678064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 171778064Sume iface++; 171855163Sshin break; 171955163Sshin case RTM_OLDADD: 172055163Sshin case RTM_OLDDEL: 172155163Sshin trace(1, "\tnot supported yet, ignored\n"); 172255163Sshin break; 172355163Sshin } 172455163Sshin 172555163Sshin } 172655163Sshin 172755163Sshin if (iface) { 172855163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 172955163Sshin ifconfig(); 173055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 173178064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 173278064Sume if (ifrt(ifcp, 1)) { 173378064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 173478064Sume if (ifcp->ifc_index == ic->ifc_index) 173578064Sume continue; 173678064Sume if (ic->ifc_flags & IFF_UP) 173778064Sume ripsend(ic, &ic->ifc_ripsin, 173878064Sume RRTF_CHANGED); 173978064Sume } 174078064Sume /* Reset the flag */ 174178064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 174278064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 174378064Sume } 174478064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 174578064Sume } 174655163Sshin } 174755163Sshin if (rtable) { 174855163Sshin trace(1, "rtsock: read routing table again\n"); 174955163Sshin krtread(1); 175055163Sshin } 175155163Sshin} 175255163Sshin 175355163Sshin/* 175455163Sshin * remove specified route from the internal routing table. 175555163Sshin */ 175655163Sshinint 175755163Sshinrt_del(sdst, sgw, smask) 175855163Sshin const struct sockaddr_in6 *sdst; 175955163Sshin const struct sockaddr_in6 *sgw; 176055163Sshin const struct sockaddr_in6 *smask; 176155163Sshin{ 176255163Sshin const struct in6_addr *dst = NULL; 176355163Sshin const struct in6_addr *gw = NULL; 176455163Sshin int prefix; 176555163Sshin struct netinfo6 ni6; 176655163Sshin struct riprt *rrt = NULL; 176755163Sshin time_t t_lifetime; 176855163Sshin 176955163Sshin if (sdst->sin6_family != AF_INET6) { 177055163Sshin trace(1, "\tother AF, ignored\n"); 177155163Sshin return -1; 177255163Sshin } 177355163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 177455163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 177555163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 177655163Sshin trace(1, "\taddress %s not interesting, ignored\n", 177755163Sshin inet6_n2p(&sdst->sin6_addr)); 177855163Sshin return -1; 177955163Sshin } 178055163Sshin dst = &sdst->sin6_addr; 178178064Sume if (sgw->sin6_family == AF_INET6) { 178255163Sshin /* easy case */ 178355163Sshin gw = &sgw->sin6_addr; 178478064Sume prefix = sin6mask2len(smask); 178555163Sshin } else if (sgw->sin6_family == AF_LINK) { 178655163Sshin /* 178755163Sshin * Interface route... a hard case. We need to get the prefix 178855163Sshin * length from the kernel, but we now are parsing rtmsg. 178955163Sshin * We'll purge matching routes from my list, then get the 179055163Sshin * fresh list. 179155163Sshin */ 179255163Sshin struct riprt *longest; 1793108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 179455163Sshin inet6_n2p(dst)); 179555163Sshin longest = NULL; 179655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 179755163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 179855163Sshin &sdst->sin6_addr) 179955163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 180055163Sshin if (!longest 180155163Sshin || longest->rrt_info.rip6_plen < 180255163Sshin rrt->rrt_info.rip6_plen) { 180355163Sshin longest = rrt; 180455163Sshin } 180555163Sshin } 180655163Sshin } 180755163Sshin rrt = longest; 180855163Sshin if (!rrt) { 180955163Sshin trace(1, "\tno matching interface route found\n"); 181055163Sshin return -1; 181155163Sshin } 181255163Sshin gw = &in6addr_loopback; 181355163Sshin prefix = rrt->rrt_info.rip6_plen; 181455163Sshin } else { 181578064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 181655163Sshin return -1; 181755163Sshin } 181855163Sshin 181955163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 182055163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 182155163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 182255163Sshin /* age route for interface address */ 182355163Sshin memset(&ni6, 0, sizeof(ni6)); 182455163Sshin ni6.rip6_dest = *dst; 182555163Sshin ni6.rip6_plen = prefix; 182655163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 182755163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 182855163Sshin ni6.rip6_plen); 182978064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 183055163Sshin trace(1, "\tno route found\n"); 183155163Sshin return -1; 183255163Sshin } 183378064Sume#if 0 183455163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 183555163Sshin trace(1, "\tyou can delete static routes only\n"); 183678064Sume } else 183778064Sume#endif 183878064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 183955163Sshin trace(1, "\tgw mismatch: %s <-> ", 184055163Sshin inet6_n2p(&rrt->rrt_gw)); 184155163Sshin trace(1, "%s\n", inet6_n2p(gw)); 184255163Sshin } else { 184355163Sshin trace(1, "\troute found, age it\n"); 184455163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 184555163Sshin rrt->rrt_t = t_lifetime; 184655163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 184755163Sshin } 184855163Sshin } 184955163Sshin return 0; 185055163Sshin} 185155163Sshin 185255163Sshin/* 185355163Sshin * remove specified address from internal interface/routing table. 185455163Sshin */ 185555163Sshinint 185655163Sshinrt_deladdr(ifcp, sifa, smask) 185755163Sshin struct ifc *ifcp; 185855163Sshin const struct sockaddr_in6 *sifa; 185955163Sshin const struct sockaddr_in6 *smask; 186055163Sshin{ 186155163Sshin const struct in6_addr *addr = NULL; 186255163Sshin int prefix; 186355163Sshin struct ifac *ifa = NULL; 186455163Sshin struct netinfo6 ni6; 186555163Sshin struct riprt *rrt = NULL; 186655163Sshin time_t t_lifetime; 186755163Sshin int updated = 0; 186855163Sshin 186978064Sume if (sifa->sin6_family != AF_INET6) { 187055163Sshin trace(1, "\tother AF, ignored\n"); 187155163Sshin return -1; 187255163Sshin } 187355163Sshin addr = &sifa->sin6_addr; 187478064Sume prefix = sin6mask2len(smask); 187555163Sshin 187655163Sshin trace(1, "\tdeleting %s/%d from %s\n", 187755163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 187855163Sshin ifa = ifa_match(ifcp, addr, prefix); 187955163Sshin if (!ifa) { 188055163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 188155163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 188255163Sshin return -1; 188355163Sshin } 188455163Sshin if (ifa->ifa_conf != ifcp) { 188555163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 188655163Sshin "(%s != %s)\n", 188755163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 188855163Sshin return -1; 188955163Sshin } 189055163Sshin /* remove ifa from interface */ 189155163Sshin if (ifcp->ifc_addr == ifa) 189255163Sshin ifcp->ifc_addr = ifa->ifa_next; 189355163Sshin else { 189455163Sshin struct ifac *p; 189555163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 189655163Sshin if (p->ifa_next == ifa) { 189755163Sshin p->ifa_next = ifa->ifa_next; 189855163Sshin break; 189955163Sshin } 190055163Sshin } 190155163Sshin } 190255163Sshin ifa->ifa_next = NULL; 190355163Sshin ifa->ifa_conf = NULL; 190455163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 190555163Sshin /* age route for interface address */ 190655163Sshin memset(&ni6, 0, sizeof(ni6)); 190755163Sshin ni6.rip6_dest = ifa->ifa_addr; 190855163Sshin ni6.rip6_plen = ifa->ifa_plen; 190955163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 191055163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 191155163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 191278064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 191355163Sshin struct in6_addr none; 191455163Sshin memset(&none, 0, sizeof(none)); 191578064Sume if (rrt->rrt_index == ifcp->ifc_index && 191678064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 191778064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 191855163Sshin trace(1, "\troute found, age it\n"); 191955163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 192055163Sshin rrt->rrt_t = t_lifetime; 192155163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 192255163Sshin } 192355163Sshin updated++; 192455163Sshin } else { 192555163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 192655163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 192755163Sshin rrt->rrt_info.rip6_plen, 192855163Sshin rrt->rrt_index); 192955163Sshin } 193055163Sshin } else 193155163Sshin trace(1, "\tno interface route found\n"); 193255163Sshin /* age route for p2p destination */ 193355163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 193455163Sshin memset(&ni6, 0, sizeof(ni6)); 193555163Sshin ni6.rip6_dest = ifa->ifa_raddr; 193655163Sshin ni6.rip6_plen = 128; 193755163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 193855163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 193955163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 194055163Sshin ifcp->ifc_index); 194178064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 194278064Sume if (rrt->rrt_index == ifcp->ifc_index && 194378064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 194455163Sshin trace(1, "\troute found, age it\n"); 194555163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 194655163Sshin rrt->rrt_t = t_lifetime; 194755163Sshin rrt->rrt_info.rip6_metric = 194878064Sume HOPCNT_INFINITY6; 194955163Sshin updated++; 195055163Sshin } 195155163Sshin } else { 195255163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 195355163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 195455163Sshin rrt->rrt_info.rip6_plen, 195555163Sshin rrt->rrt_index); 195655163Sshin } 195755163Sshin } else 195855163Sshin trace(1, "\tno p2p route found\n"); 195955163Sshin } 196055163Sshin return updated ? 0 : -1; 196155163Sshin} 196255163Sshin 196355163Sshin/* 196455163Sshin * Get each interface address and put those interface routes to the route 196555163Sshin * list. 196655163Sshin */ 196778064Sumeint 196855163Sshinifrt(ifcp, again) 196962607Sitojun struct ifc *ifcp; 197055163Sshin int again; 197155163Sshin{ 197262607Sitojun struct ifac *ifa; 1973119042Sume struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; 197462607Sitojun struct netinfo6 *np; 197578064Sume time_t t_lifetime; 197678064Sume int need_trigger = 0; 197755163Sshin 197855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 197978064Sume return 0; /* ignore loopback */ 198062607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 198162607Sitojun ifrt_p2p(ifcp, again); 198278064Sume return 0; 198362607Sitojun } 198462607Sitojun 198555163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 198662607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 198762607Sitojun#if 0 198862607Sitojun trace(1, "route: %s on %s: " 198962607Sitojun "skip linklocal interface address\n", 199062607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 199162607Sitojun#endif 199262607Sitojun continue; 199362607Sitojun } 199462607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 199562607Sitojun#if 0 199662607Sitojun trace(1, "route: %s: skip unspec interface address\n", 199762607Sitojun ifcp->ifc_name); 199862607Sitojun#endif 199962607Sitojun continue; 200062607Sitojun } 200178064Sume if (ifcp->ifc_flags & IFF_UP) { 200278064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 200378064Sume fatal("malloc: struct riprt"); 200478064Sume memset(rrt, 0, sizeof(*rrt)); 200578064Sume rrt->rrt_same = NULL; 200678064Sume rrt->rrt_index = ifcp->ifc_index; 200778064Sume rrt->rrt_t = 0; /* don't age */ 200878064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 200978064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 201078064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 201178064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 201278064Sume rrt->rrt_flags = RTF_CLONING; 201378064Sume rrt->rrt_rflags |= RRTF_CHANGED; 201478064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 201578064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 201678064Sume rrt->rrt_gw = ifa->ifa_addr; 201778064Sume np = &rrt->rrt_info; 201878064Sume search_rrt = rtsearch(np, &prev_rrt); 201978064Sume if (search_rrt != NULL) { 2020119042Sume if (search_rrt->rrt_info.rip6_metric <= 202178064Sume rrt->rrt_info.rip6_metric) { 202278064Sume /* Already have better route */ 202378064Sume if (!again) { 202478064Sume trace(1, "route: %s/%d: " 202578064Sume "already registered (%s)\n", 202678064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 202778064Sume ifcp->ifc_name); 202878064Sume } 2029119042Sume goto next; 203078064Sume } 2031119042Sume 2032119042Sume if (prev_rrt) 2033119042Sume prev_rrt->rrt_next = rrt->rrt_next; 2034119042Sume else 2035119042Sume riprt = rrt->rrt_next; 2036119042Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 203778064Sume } 203855163Sshin /* Attach the route to the list */ 203962607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 204062607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 204162607Sitojun ifcp->ifc_name); 204255163Sshin rrt->rrt_next = riprt; 204355163Sshin riprt = rrt; 204478064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 2045119042Sume rrt = NULL; 204678064Sume sendrequest(ifcp); 204778064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 204878064Sume need_trigger = 1; 204955163Sshin } else { 205078064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 205178064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 205278064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 205378064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 205478064Sume loop_rrt->rrt_t = t_lifetime; 205578064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 205678064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 205778064Sume need_trigger = 1; 205878064Sume } 205978064Sume } 206055163Sshin } 206178064Sume } 2062119042Sume next: 2063119042Sume if (rrt) 2064119042Sume free(rrt); 206562607Sitojun } 206678064Sume return need_trigger; 206762607Sitojun} 206855163Sshin 206962607Sitojun/* 207062607Sitojun * there are couple of p2p interface routing models. "behavior" lets 207162607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2072119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 207362607Sitojun */ 207462607Sitojunvoid 207562607Sitojunifrt_p2p(ifcp, again) 207662607Sitojun struct ifc *ifcp; 207762607Sitojun int again; 207862607Sitojun{ 207962607Sitojun struct ifac *ifa; 208078064Sume struct riprt *rrt, *orrt, *prevrrt; 208162607Sitojun struct netinfo6 *np; 208262607Sitojun struct in6_addr addr, dest; 208362607Sitojun int advert, ignore, i; 208462607Sitojun#define P2PADVERT_NETWORK 1 208562607Sitojun#define P2PADVERT_ADDR 2 208662607Sitojun#define P2PADVERT_DEST 4 208762607Sitojun#define P2PADVERT_MAX 4 208862607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 208978064Sume const char *category = ""; 209062607Sitojun const char *noadv; 209162607Sitojun 209262607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 209362607Sitojun addr = ifa->ifa_addr; 209462607Sitojun dest = ifa->ifa_raddr; 209562607Sitojun applyplen(&addr, ifa->ifa_plen); 209662607Sitojun applyplen(&dest, ifa->ifa_plen); 209762607Sitojun advert = ignore = 0; 209862607Sitojun switch (behavior) { 209962607Sitojun case CISCO: 210062607Sitojun /* 210162607Sitojun * honor addr/plen, just like normal shared medium 210262607Sitojun * interface. this may cause trouble if you reuse 210362607Sitojun * addr/plen on other interfaces. 210462607Sitojun * 210562607Sitojun * advertise addr/plen. 210662607Sitojun */ 210762607Sitojun advert |= P2PADVERT_NETWORK; 210862607Sitojun break; 210962607Sitojun case GATED: 211062607Sitojun /* 211162607Sitojun * prefixlen on p2p interface is meaningless. 211262607Sitojun * advertise addr/128 and dest/128. 211362607Sitojun * 211462607Sitojun * do not install network route to route6d routing 211562607Sitojun * table (if we do, it would prevent route installation 211662607Sitojun * for other p2p interface that shares addr/plen). 211778064Sume * 211878064Sume * XXX what should we do if dest is ::? it will not 211978064Sume * get announced anyways (see following filter), 212078064Sume * but we need to think. 212162607Sitojun */ 212262607Sitojun advert |= P2PADVERT_ADDR; 212362607Sitojun advert |= P2PADVERT_DEST; 212462607Sitojun ignore |= P2PADVERT_NETWORK; 212562607Sitojun break; 212662607Sitojun case ROUTE6D: 212762607Sitojun /* 212878064Sume * just for testing. actually the code is redundant 212978064Sume * given the current p2p interface address assignment 213078064Sume * rule for kame kernel. 213178064Sume * 213278064Sume * intent: 213378064Sume * A/n -> announce A/n 213478064Sume * A B/n, A and B share prefix -> A/n (= B/n) 213578064Sume * A B/n, do not share prefix -> A/128 and B/128 213678064Sume * actually, A/64 and A B/128 are the only cases 213778064Sume * permitted by the kernel: 213878064Sume * A/64 -> A/64 213978064Sume * A B/128 -> A/128 and B/128 214062607Sitojun */ 214178064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 214278064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 214378064Sume advert |= P2PADVERT_NETWORK; 214478064Sume else { 214578064Sume advert |= P2PADVERT_ADDR; 214678064Sume advert |= P2PADVERT_DEST; 214778064Sume ignore |= P2PADVERT_NETWORK; 214878064Sume } 214978064Sume } else 215062607Sitojun advert |= P2PADVERT_NETWORK; 215162607Sitojun break; 215262607Sitojun } 215362607Sitojun 215462607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 215562607Sitojun if ((ignore & i) != 0) 215662607Sitojun continue; 215778064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 215855163Sshin fatal("malloc: struct riprt"); 215978064Sume /*NOTREACHED*/ 216078064Sume } 216162607Sitojun memset(rrt, 0, sizeof(*rrt)); 216255163Sshin rrt->rrt_same = NULL; 216355163Sshin rrt->rrt_index = ifcp->ifc_index; 216462607Sitojun rrt->rrt_t = 0; /* don't age */ 216562607Sitojun switch (i) { 216662607Sitojun case P2PADVERT_NETWORK: 216762607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 216862607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 216962607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 217062607Sitojun ifa->ifa_plen); 217162607Sitojun category = "network"; 217262607Sitojun break; 217362607Sitojun case P2PADVERT_ADDR: 217462607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 217562607Sitojun rrt->rrt_info.rip6_plen = 128; 217678064Sume rrt->rrt_gw = in6addr_loopback; 217762607Sitojun category = "addr"; 217862607Sitojun break; 217962607Sitojun case P2PADVERT_DEST: 218062607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 218162607Sitojun rrt->rrt_info.rip6_plen = 128; 218278064Sume rrt->rrt_gw = ifa->ifa_addr; 218362607Sitojun category = "dest"; 218462607Sitojun break; 218562607Sitojun } 218662607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 218762607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 218862607Sitojun#if 0 218962607Sitojun trace(1, "route: %s: skip unspec/linklocal " 219062607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 219162607Sitojun#endif 219262607Sitojun free(rrt); 219362607Sitojun continue; 219462607Sitojun } 219562607Sitojun if ((advert & i) == 0) { 219662607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 219762607Sitojun noadv = ", NO-ADV"; 219862607Sitojun } else 219962607Sitojun noadv = ""; 220055163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 220162607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 220255163Sshin np = &rrt->rrt_info; 220378064Sume orrt = rtsearch(np, &prevrrt); 220478064Sume if (!orrt) { 220555163Sshin /* Attach the route to the list */ 220662607Sitojun trace(1, "route: %s/%d: register route " 220762607Sitojun "(%s on %s%s)\n", 220862607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 220962607Sitojun category, ifcp->ifc_name, noadv); 221055163Sshin rrt->rrt_next = riprt; 221155163Sshin riprt = rrt; 221278064Sume } else if (rrt->rrt_index != orrt->rrt_index || 221378064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 221478064Sume /* swap route */ 221578064Sume rrt->rrt_next = orrt->rrt_next; 221678064Sume if (prevrrt) 221778064Sume prevrrt->rrt_next = rrt; 221878064Sume else 221978064Sume riprt = rrt; 222078064Sume free(orrt); 222178064Sume 222278064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 222378064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 222478064Sume category, ifcp->ifc_name, noadv); 222555163Sshin } else { 222655163Sshin /* Already found */ 222755163Sshin if (!again) { 222862607Sitojun trace(1, "route: %s/%d: " 222962607Sitojun "already registered (%s on %s%s)\n", 223062607Sitojun inet6_n2p(&np->rip6_dest), 223162607Sitojun np->rip6_plen, category, 223262607Sitojun ifcp->ifc_name, noadv); 223355163Sshin } 223455163Sshin free(rrt); 223555163Sshin } 223655163Sshin } 223755163Sshin } 223862607Sitojun#undef P2PADVERT_NETWORK 223962607Sitojun#undef P2PADVERT_ADDR 224062607Sitojun#undef P2PADVERT_DEST 224162607Sitojun#undef P2PADVERT_MAX 224255163Sshin} 224355163Sshin 224455163Sshinint 224555163Sshingetifmtu(ifindex) 224655163Sshin int ifindex; 224755163Sshin{ 224855163Sshin int mib[6]; 224955163Sshin char *buf; 225055163Sshin size_t msize; 225155163Sshin struct if_msghdr *ifm; 225255163Sshin int mtu; 225355163Sshin 225455163Sshin mib[0] = CTL_NET; 225555163Sshin mib[1] = PF_ROUTE; 225655163Sshin mib[2] = 0; 225755163Sshin mib[3] = AF_INET6; 225855163Sshin mib[4] = NET_RT_IFLIST; 225955163Sshin mib[5] = ifindex; 226078064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 226155163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 226278064Sume /*NOTREACHED*/ 226378064Sume } 226478064Sume if ((buf = malloc(msize)) == NULL) { 226555163Sshin fatal("malloc"); 226678064Sume /*NOTREACHED*/ 226778064Sume } 226878064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 226955163Sshin fatal("sysctl NET_RT_IFLIST"); 227078064Sume /*NOTREACHED*/ 227178064Sume } 227255163Sshin ifm = (struct if_msghdr *)buf; 227355163Sshin mtu = ifm->ifm_data.ifi_mtu; 227478064Sume#ifdef __FreeBSD__ 227578064Sume if (ifindex != ifm->ifm_index) { 227655163Sshin fatal("ifindex does not match with ifm_index"); 227778064Sume /*NOTREACHED*/ 227878064Sume } 227978064Sume#endif 228055163Sshin free(buf); 228155163Sshin return mtu; 228255163Sshin} 228355163Sshin 228455163Sshinconst char * 228555163Sshinrttypes(rtm) 228655163Sshin struct rt_msghdr *rtm; 228755163Sshin{ 228862607Sitojun#define RTTYPE(s, f) \ 228962607Sitojundo { \ 229062607Sitojun if (rtm->rtm_type == (f)) \ 229162607Sitojun return (s); \ 229262607Sitojun} while (0) 229355163Sshin RTTYPE("ADD", RTM_ADD); 229455163Sshin RTTYPE("DELETE", RTM_DELETE); 229555163Sshin RTTYPE("CHANGE", RTM_CHANGE); 229655163Sshin RTTYPE("GET", RTM_GET); 229755163Sshin RTTYPE("LOSING", RTM_LOSING); 229855163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 229955163Sshin RTTYPE("MISS", RTM_MISS); 230055163Sshin RTTYPE("LOCK", RTM_LOCK); 230155163Sshin RTTYPE("OLDADD", RTM_OLDADD); 230255163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 230355163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 230455163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 230555163Sshin RTTYPE("DELADDR", RTM_DELADDR); 230655163Sshin RTTYPE("IFINFO", RTM_IFINFO); 230778064Sume#ifdef RTM_OLDADD 230878064Sume RTTYPE("OLDADD", RTM_OLDADD); 230978064Sume#endif 231078064Sume#ifdef RTM_OLDDEL 231178064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 231278064Sume#endif 231378064Sume#ifdef RTM_OIFINFO 231478064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 231578064Sume#endif 231678064Sume#ifdef RTM_IFANNOUNCE 231778064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 231878064Sume#endif 231978064Sume#ifdef RTM_NEWMADDR 232078064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 232178064Sume#endif 232278064Sume#ifdef RTM_DELMADDR 232378064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 232478064Sume#endif 232555163Sshin#undef RTTYPE 232655163Sshin return NULL; 232755163Sshin} 232855163Sshin 232955163Sshinconst char * 233055163Sshinrtflags(rtm) 233155163Sshin struct rt_msghdr *rtm; 233255163Sshin{ 233355163Sshin static char buf[BUFSIZ]; 233455163Sshin 233578064Sume /* 233678064Sume * letter conflict should be okay. painful when *BSD diverges... 233778064Sume */ 233878064Sume strlcpy(buf, "", sizeof(buf)); 233962607Sitojun#define RTFLAG(s, f) \ 234062607Sitojundo { \ 234162607Sitojun if (rtm->rtm_flags & (f)) \ 234278064Sume strlcat(buf, (s), sizeof(buf)); \ 234362607Sitojun} while (0) 234455163Sshin RTFLAG("U", RTF_UP); 234555163Sshin RTFLAG("G", RTF_GATEWAY); 234655163Sshin RTFLAG("H", RTF_HOST); 234755163Sshin RTFLAG("R", RTF_REJECT); 234855163Sshin RTFLAG("D", RTF_DYNAMIC); 234955163Sshin RTFLAG("M", RTF_MODIFIED); 235055163Sshin RTFLAG("d", RTF_DONE); 235155163Sshin#ifdef RTF_MASK 235255163Sshin RTFLAG("m", RTF_MASK); 235355163Sshin#endif 235455163Sshin RTFLAG("C", RTF_CLONING); 235578064Sume#ifdef RTF_CLONED 235678064Sume RTFLAG("c", RTF_CLONED); 235778064Sume#endif 235878064Sume#ifdef RTF_PRCLONING 235978064Sume RTFLAG("c", RTF_PRCLONING); 236078064Sume#endif 236178064Sume#ifdef RTF_WASCLONED 236278064Sume RTFLAG("W", RTF_WASCLONED); 236378064Sume#endif 236455163Sshin RTFLAG("X", RTF_XRESOLVE); 236555163Sshin RTFLAG("L", RTF_LLINFO); 236655163Sshin RTFLAG("S", RTF_STATIC); 236755163Sshin RTFLAG("B", RTF_BLACKHOLE); 236878064Sume#ifdef RTF_PROTO3 236978064Sume RTFLAG("3", RTF_PROTO3); 237078064Sume#endif 237155163Sshin RTFLAG("2", RTF_PROTO2); 237255163Sshin RTFLAG("1", RTF_PROTO1); 237378064Sume#ifdef RTF_BROADCAST 237478064Sume RTFLAG("b", RTF_BROADCAST); 237578064Sume#endif 237678064Sume#ifdef RTF_DEFAULT 237778064Sume RTFLAG("d", RTF_DEFAULT); 237878064Sume#endif 237978064Sume#ifdef RTF_ISAROUTER 238078064Sume RTFLAG("r", RTF_ISAROUTER); 238178064Sume#endif 238278064Sume#ifdef RTF_TUNNEL 238378064Sume RTFLAG("T", RTF_TUNNEL); 238478064Sume#endif 238578064Sume#ifdef RTF_AUTH 238678064Sume RTFLAG("A", RTF_AUTH); 238778064Sume#endif 238878064Sume#ifdef RTF_CRYPT 238978064Sume RTFLAG("E", RTF_CRYPT); 239078064Sume#endif 239155163Sshin#undef RTFLAG 239255163Sshin return buf; 239355163Sshin} 239455163Sshin 239555163Sshinconst char * 239655163Sshinifflags(flags) 239755163Sshin int flags; 239855163Sshin{ 239955163Sshin static char buf[BUFSIZ]; 240055163Sshin 240178064Sume strlcpy(buf, "", sizeof(buf)); 240262607Sitojun#define IFFLAG(s, f) \ 240362607Sitojundo { \ 2404119040Sume if (flags & (f)) { \ 240562607Sitojun if (buf[0]) \ 240678064Sume strlcat(buf, ",", sizeof(buf)); \ 2407119040Sume strlcat(buf, (s), sizeof(buf)); \ 240862607Sitojun } \ 240962607Sitojun} while (0) 241055163Sshin IFFLAG("UP", IFF_UP); 241155163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 241255163Sshin IFFLAG("DEBUG", IFF_DEBUG); 241355163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 241455163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 241555163Sshin#ifdef IFF_NOTRAILERS 241655163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 241755163Sshin#endif 241878064Sume#ifdef IFF_SMART 241978064Sume IFFLAG("SMART", IFF_SMART); 242078064Sume#endif 242155163Sshin IFFLAG("RUNNING", IFF_RUNNING); 242255163Sshin IFFLAG("NOARP", IFF_NOARP); 242355163Sshin IFFLAG("PROMISC", IFF_PROMISC); 242455163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 242555163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 242655163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 242755163Sshin IFFLAG("LINK0", IFF_LINK0); 242855163Sshin IFFLAG("LINK1", IFF_LINK1); 242955163Sshin IFFLAG("LINK2", IFF_LINK2); 243055163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 243155163Sshin#undef IFFLAG 243255163Sshin return buf; 243355163Sshin} 243455163Sshin 243555163Sshinvoid 243655163Sshinkrtread(again) 243755163Sshin int again; 243855163Sshin{ 243955163Sshin int mib[6]; 244055163Sshin size_t msize; 244155163Sshin char *buf, *p, *lim; 244255163Sshin struct rt_msghdr *rtm; 244355163Sshin int retry; 244455163Sshin const char *errmsg; 244555163Sshin 244655163Sshin retry = 0; 244755163Sshin buf = NULL; 244855163Sshin mib[0] = CTL_NET; 244955163Sshin mib[1] = PF_ROUTE; 245055163Sshin mib[2] = 0; 245155163Sshin mib[3] = AF_INET6; /* Address family */ 245255163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 245355163Sshin mib[5] = 0; /* No flags */ 245455163Sshin do { 245555163Sshin retry++; 245655163Sshin errmsg = NULL; 245755163Sshin if (buf) 245855163Sshin free(buf); 245955163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 246055163Sshin errmsg = "sysctl estimate"; 246155163Sshin continue; 246255163Sshin } 246355163Sshin if ((buf = malloc(msize)) == NULL) { 246455163Sshin errmsg = "malloc"; 246555163Sshin continue; 246655163Sshin } 246755163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 246855163Sshin errmsg = "sysctl NET_RT_DUMP"; 246955163Sshin continue; 247055163Sshin } 247155163Sshin } while (retry < 5 && errmsg != NULL); 247278064Sume if (errmsg) { 247369279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 247469279Sume (u_long)msize); 247578064Sume /*NOTREACHED*/ 247678064Sume } else if (1 < retry) 247755163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 247855163Sshin 247955163Sshin lim = buf + msize; 248055163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 248155163Sshin rtm = (struct rt_msghdr *)p; 248255163Sshin rt_entry(rtm, again); 248355163Sshin } 248455163Sshin free(buf); 248555163Sshin} 248655163Sshin 248755163Sshinvoid 248855163Sshinrt_entry(rtm, again) 248955163Sshin struct rt_msghdr *rtm; 249055163Sshin int again; 249155163Sshin{ 249255163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 249355163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 249455163Sshin char *rtmp, *ifname = NULL; 249578064Sume struct riprt *rrt, *orrt; 249655163Sshin struct netinfo6 *np; 249755163Sshin int s; 249855163Sshin 249955163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 250055163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 250162607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 250255163Sshin return; /* not interested in the link route */ 250362607Sitojun } 250469279Sume /* do not look at cloned routes */ 250569279Sume#ifdef RTF_WASCLONED 250669279Sume if (rtm->rtm_flags & RTF_WASCLONED) 250769279Sume return; 250869279Sume#endif 250969279Sume#ifdef RTF_CLONED 251069279Sume if (rtm->rtm_flags & RTF_CLONED) 251169279Sume return; 251269279Sume#endif 251369279Sume /* 251469279Sume * do not look at dynamic routes. 251569279Sume * netbsd/openbsd cloned routes have UGHD. 251669279Sume */ 251769279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 251869279Sume return; 251955163Sshin rtmp = (char *)(rtm + 1); 252055163Sshin /* Destination */ 252155163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 252255163Sshin return; /* ignore routes without destination address */ 252355163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 252464631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 252555163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 252655163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 252755163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 252855163Sshin } 252955163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 253055163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 253155163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 253255163Sshin } 253355163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 253455163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 253555163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 253655163Sshin } 253755163Sshin if (rtm->rtm_addrs & RTA_IFP) { 253855163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 253955163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 254055163Sshin } 254155163Sshin 254255163Sshin /* Destination */ 254355163Sshin if (sin6_dst->sin6_family != AF_INET6) 254455163Sshin return; 254555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 254655163Sshin return; /* Link-local */ 254755163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 254855163Sshin return; /* Loopback */ 254955163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 255055163Sshin return; 255155163Sshin 255278064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 255355163Sshin fatal("malloc: struct riprt"); 255478064Sume /*NOTREACHED*/ 255578064Sume } 255662607Sitojun memset(rrt, 0, sizeof(*rrt)); 255755163Sshin np = &rrt->rrt_info; 255855163Sshin rrt->rrt_same = NULL; 255955163Sshin rrt->rrt_t = time(NULL); 256055163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 256155163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 256255163Sshin np->rip6_tag = 0; 256355163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 256455163Sshin if (np->rip6_metric < 1) 256555163Sshin np->rip6_metric = 1; 256655163Sshin rrt->rrt_flags = rtm->rtm_flags; 256755163Sshin np->rip6_dest = sin6_dst->sin6_addr; 256855163Sshin 256955163Sshin /* Mask or plen */ 257055163Sshin if (rtm->rtm_flags & RTF_HOST) 257155163Sshin np->rip6_plen = 128; /* Host route */ 257278064Sume else if (sin6_mask) 257378064Sume np->rip6_plen = sin6mask2len(sin6_mask); 257478064Sume else 257555163Sshin np->rip6_plen = 0; 257655163Sshin 257778064Sume orrt = rtsearch(np, NULL); 257878064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 257955163Sshin /* Already found */ 258055163Sshin if (!again) { 258155163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 258255163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 258355163Sshin rtflags(rtm)); 258455163Sshin } 258555163Sshin free(rrt); 258655163Sshin return; 258755163Sshin } 258855163Sshin /* Gateway */ 258955163Sshin if (!sin6_gw) 259055163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 259155163Sshin else { 259255163Sshin if (sin6_gw->sin6_family == AF_INET6) 259355163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 259455163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 259555163Sshin /* XXX in case ppp link? */ 259655163Sshin rrt->rrt_gw = in6addr_loopback; 259755163Sshin } else 259855163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 259955163Sshin } 260055163Sshin trace(1, "route: %s/%d flags %s", 260155163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 260255163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 260355163Sshin 260455163Sshin /* Interface */ 260555163Sshin s = rtm->rtm_index; 260655163Sshin if (s < nindex2ifc && index2ifc[s]) 260755163Sshin ifname = index2ifc[s]->ifc_name; 260858070Sshin else { 260958070Sshin trace(1, " not configured\n"); 261062607Sitojun free(rrt); 261158070Sshin return; 261258070Sshin } 261362607Sitojun trace(1, " if %s sock %d", ifname, s); 261455163Sshin rrt->rrt_index = s; 261555163Sshin 261662607Sitojun trace(1, "\n"); 261762607Sitojun 261855163Sshin /* Check gateway */ 261955163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 262055163Sshin !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 262155163Sshin#ifdef __FreeBSD__ 262255163Sshin && (rrt->rrt_flags & RTF_LOCAL) == 0 262355163Sshin#endif 262455163Sshin ) { 262555163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 262655163Sshin inet6_n2p(&rrt->rrt_gw)); 262755163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 262862607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 262962607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 263055163Sshin } 263155163Sshin 263255163Sshin /* Put it to the route list */ 263378064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 263478064Sume /* replace route list */ 263578064Sume rrt->rrt_next = orrt->rrt_next; 263678064Sume *orrt = *rrt; 263778064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 263878064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 263978064Sume rtflags(rtm)); 264078064Sume free(rrt); 264178064Sume } else { 264278064Sume rrt->rrt_next = riprt; 264378064Sume riprt = rrt; 264478064Sume } 264555163Sshin} 264655163Sshin 264755163Sshinint 264855163Sshinaddroute(rrt, gw, ifcp) 264955163Sshin struct riprt *rrt; 265055163Sshin const struct in6_addr *gw; 265155163Sshin struct ifc *ifcp; 265255163Sshin{ 265355163Sshin struct netinfo6 *np; 265455163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 265555163Sshin struct rt_msghdr *rtm; 2656119031Sume struct sockaddr_in6 *sin6; 265755163Sshin int len; 265855163Sshin 265955163Sshin np = &rrt->rrt_info; 266078064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 266155163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 266255163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 266355163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 266455163Sshin np->rip6_metric - 1, buf2); 266555163Sshin if (rtlog) 266655163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 266755163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 266855163Sshin np->rip6_metric - 1, buf2); 266955163Sshin if (nflag) 267055163Sshin return 0; 267155163Sshin 267255163Sshin memset(buf, 0, sizeof(buf)); 267355163Sshin rtm = (struct rt_msghdr *)buf; 267455163Sshin rtm->rtm_type = RTM_ADD; 267555163Sshin rtm->rtm_version = RTM_VERSION; 267655163Sshin rtm->rtm_seq = ++seq; 267755163Sshin rtm->rtm_pid = pid; 267862607Sitojun rtm->rtm_flags = rrt->rrt_flags; 267955163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 268055163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 268155163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2682119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 268355163Sshin /* Destination */ 2684119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2685119031Sume sin6->sin6_family = AF_INET6; 2686119031Sume sin6->sin6_addr = np->rip6_dest; 2687119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 268855163Sshin /* Gateway */ 2689119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2690119031Sume sin6->sin6_family = AF_INET6; 2691119031Sume sin6->sin6_addr = *gw; 2692119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 269355163Sshin /* Netmask */ 2694119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2695119031Sume sin6->sin6_family = AF_INET6; 2696119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2697119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 269855163Sshin 2699119031Sume len = (char *)sin6 - (char *)buf; 270055163Sshin rtm->rtm_msglen = len; 270155163Sshin if (write(rtsock, buf, len) > 0) 270255163Sshin return 0; 270355163Sshin 270455163Sshin if (errno == EEXIST) { 270555163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2706119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 270755163Sshin if (rtlog) 270855163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2709119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 271055163Sshin } else { 271155163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2712119035Sume strerror(errno)); 271355163Sshin if (rtlog) 271455163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2715119035Sume strerror(errno)); 271655163Sshin } 271755163Sshin return -1; 271855163Sshin} 271955163Sshin 272055163Sshinint 272155163Sshindelroute(np, gw) 272255163Sshin struct netinfo6 *np; 272355163Sshin struct in6_addr *gw; 272455163Sshin{ 272555163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 272655163Sshin struct rt_msghdr *rtm; 2727119031Sume struct sockaddr_in6 *sin6; 272855163Sshin int len; 272955163Sshin 273055163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 273155163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 273255163Sshin np->rip6_plen, buf2); 273355163Sshin if (rtlog) 273455163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 273555163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 273655163Sshin if (nflag) 273755163Sshin return 0; 273855163Sshin 273955163Sshin memset(buf, 0, sizeof(buf)); 274055163Sshin rtm = (struct rt_msghdr *)buf; 274155163Sshin rtm->rtm_type = RTM_DELETE; 274255163Sshin rtm->rtm_version = RTM_VERSION; 274355163Sshin rtm->rtm_seq = ++seq; 274455163Sshin rtm->rtm_pid = pid; 274555163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 274678064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 274778064Sume rtm->rtm_flags |= RTF_HOST; 274855163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2749119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 275055163Sshin /* Destination */ 2751119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2752119031Sume sin6->sin6_family = AF_INET6; 2753119031Sume sin6->sin6_addr = np->rip6_dest; 2754119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275555163Sshin /* Gateway */ 2756119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2757119031Sume sin6->sin6_family = AF_INET6; 2758119031Sume sin6->sin6_addr = *gw; 2759119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 276055163Sshin /* Netmask */ 2761119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2762119031Sume sin6->sin6_family = AF_INET6; 2763119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2764119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 276555163Sshin 2766119031Sume len = (char *)sin6 - (char *)buf; 276755163Sshin rtm->rtm_msglen = len; 276855163Sshin if (write(rtsock, buf, len) >= 0) 276955163Sshin return 0; 277055163Sshin 277155163Sshin if (errno == ESRCH) { 277255163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2773119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 277455163Sshin if (rtlog) 277555163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2776119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 277755163Sshin } else { 277855163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2779119035Sume strerror(errno)); 278055163Sshin if (rtlog) 278155163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2782119035Sume strerror(errno)); 278355163Sshin } 278455163Sshin return -1; 278555163Sshin} 278655163Sshin 278755163Sshinstruct in6_addr * 278855163Sshingetroute(np, gw) 278955163Sshin struct netinfo6 *np; 279055163Sshin struct in6_addr *gw; 279155163Sshin{ 279255163Sshin u_char buf[BUFSIZ]; 279355163Sshin u_long myseq; 279455163Sshin int len; 279555163Sshin struct rt_msghdr *rtm; 2796119031Sume struct sockaddr_in6 *sin6; 279755163Sshin 279855163Sshin rtm = (struct rt_msghdr *)buf; 279955163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 280055163Sshin memset(rtm, 0, len); 280155163Sshin rtm->rtm_type = RTM_GET; 280255163Sshin rtm->rtm_version = RTM_VERSION; 280355163Sshin myseq = ++seq; 280455163Sshin rtm->rtm_seq = myseq; 280555163Sshin rtm->rtm_addrs = RTA_DST; 280655163Sshin rtm->rtm_msglen = len; 2807119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2808119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2809119031Sume sin6->sin6_family = AF_INET6; 2810119031Sume sin6->sin6_addr = np->rip6_dest; 281155163Sshin if (write(rtsock, buf, len) < 0) { 281255163Sshin if (errno == ESRCH) /* No such route found */ 281355163Sshin return NULL; 281455163Sshin perror("write to rtsock"); 281578064Sume exit(1); 281655163Sshin } 281755163Sshin do { 281855163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 281955163Sshin perror("read from rtsock"); 282078064Sume exit(1); 282155163Sshin } 282255163Sshin rtm = (struct rt_msghdr *)buf; 282355163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2824119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 282555163Sshin if (rtm->rtm_addrs & RTA_DST) { 2826119031Sume sin6 = (struct sockaddr_in6 *) 2827119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 282855163Sshin } 282955163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2830119031Sume *gw = sin6->sin6_addr; 283155163Sshin return gw; 283255163Sshin } 283355163Sshin return NULL; 283455163Sshin} 283555163Sshin 283655163Sshinconst char * 283755163Sshininet6_n2p(p) 283855163Sshin const struct in6_addr *p; 283955163Sshin{ 284055163Sshin static char buf[BUFSIZ]; 284155163Sshin 284278064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 284355163Sshin} 284455163Sshin 284555163Sshinvoid 284655163Sshinifrtdump(sig) 284755163Sshin int sig; 284855163Sshin{ 284955163Sshin 285055163Sshin ifdump(sig); 285155163Sshin rtdump(sig); 285255163Sshin} 285355163Sshin 285455163Sshinvoid 285555163Sshinifdump(sig) 285655163Sshin int sig; 285755163Sshin{ 285855163Sshin struct ifc *ifcp; 285955163Sshin FILE *dump; 286055163Sshin int i; 286155163Sshin 286255163Sshin if (sig == 0) 286355163Sshin dump = stderr; 286455163Sshin else 286555163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 286655163Sshin dump = stderr; 286755163Sshin 286855163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 286955163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 287055163Sshin for (i = 0; i < 2; i++) { 287155163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 287255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 287355163Sshin if (i == 0) { 287455163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 287555163Sshin continue; 287655163Sshin if (iff_find(ifcp, 'N') != NULL) 287755163Sshin continue; 287855163Sshin } else { 287955163Sshin if (ifcp->ifc_flags & IFF_UP) 288055163Sshin continue; 288155163Sshin } 288255163Sshin ifdump0(dump, ifcp); 288355163Sshin } 288455163Sshin } 288555163Sshin fprintf(dump, "\n"); 288655163Sshin if (dump != stderr) 288755163Sshin fclose(dump); 288855163Sshin} 288955163Sshin 289055163Sshinvoid 289155163Sshinifdump0(dump, ifcp) 289255163Sshin FILE *dump; 289355163Sshin const struct ifc *ifcp; 289455163Sshin{ 289555163Sshin struct ifac *ifa; 289655163Sshin struct iff *iffp; 289755163Sshin char buf[BUFSIZ]; 289855163Sshin const char *ft; 289955163Sshin int addr; 290055163Sshin 290155163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 290255163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 290355163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 290455163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 290555163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 290655163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 290755163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 290855163Sshin buf, sizeof(buf)); 290955163Sshin fprintf(dump, "\t%s/%d -- %s\n", 291055163Sshin inet6_n2p(&ifa->ifa_addr), 291155163Sshin ifa->ifa_plen, buf); 291255163Sshin } else { 291355163Sshin fprintf(dump, "\t%s/%d\n", 291455163Sshin inet6_n2p(&ifa->ifa_addr), 291555163Sshin ifa->ifa_plen); 291655163Sshin } 291755163Sshin } 291855163Sshin if (ifcp->ifc_filter) { 291955163Sshin fprintf(dump, "\tFilter:"); 292055163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 292155163Sshin addr = 0; 292255163Sshin switch (iffp->iff_type) { 292355163Sshin case 'A': 292455163Sshin ft = "Aggregate"; addr++; break; 292555163Sshin case 'N': 292678064Sume ft = "No-use"; break; 292755163Sshin case 'O': 292855163Sshin ft = "Advertise-only"; addr++; break; 292955163Sshin case 'T': 293055163Sshin ft = "Default-only"; break; 293155163Sshin case 'L': 293255163Sshin ft = "Listen-only"; addr++; break; 293355163Sshin default: 293455163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 293555163Sshin ft = buf; 293655163Sshin addr++; 293755163Sshin break; 293855163Sshin } 293955163Sshin fprintf(dump, " %s", ft); 294055163Sshin if (addr) { 294155163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 294255163Sshin iffp->iff_plen); 294355163Sshin } 294455163Sshin } 294555163Sshin fprintf(dump, "\n"); 294655163Sshin } 294755163Sshin} 294855163Sshin 294955163Sshinvoid 295055163Sshinrtdump(sig) 295155163Sshin int sig; 295255163Sshin{ 295355163Sshin struct riprt *rrt; 295455163Sshin char buf[BUFSIZ]; 295555163Sshin FILE *dump; 295655163Sshin time_t t, age; 295755163Sshin 295855163Sshin if (sig == 0) 295955163Sshin dump = stderr; 296055163Sshin else 296155163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 296255163Sshin dump = stderr; 296355163Sshin 296455163Sshin t = time(NULL); 296555163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 296655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 296755163Sshin if (rrt->rrt_t == 0) 296855163Sshin age = 0; 296955163Sshin else 297055163Sshin age = t - rrt->rrt_t; 297155163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 297255163Sshin buf, sizeof(buf)); 297355163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 297455163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 297555163Sshin index2ifc[rrt->rrt_index]->ifc_name, 297655163Sshin inet6_n2p(&rrt->rrt_gw), 297755163Sshin rrt->rrt_info.rip6_metric, (long)age); 297855163Sshin if (rrt->rrt_info.rip6_tag) { 297955163Sshin fprintf(dump, " tag(0x%04x)", 298055163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 298155163Sshin } 298262607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 298355163Sshin fprintf(dump, " NOT-LL"); 298462607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 298555163Sshin fprintf(dump, " NO-ADV"); 298655163Sshin fprintf(dump, "\n"); 298755163Sshin } 298855163Sshin fprintf(dump, "\n"); 298955163Sshin if (dump != stderr) 299055163Sshin fclose(dump); 299155163Sshin} 299255163Sshin 299355163Sshin/* 299455163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 299578064Sume * specified interface structures. Each of the -A/O option has the following 299655163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 299755163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 299855163Sshin */ 299955163Sshinvoid 300055163Sshinfilterconfig() 300155163Sshin{ 300255163Sshin int i; 300355163Sshin char *p, *ap, *iflp, *ifname; 300478064Sume struct iff ftmp, *iff_obj; 300578064Sume struct ifc *ifcp; 300678064Sume struct riprt *rrt; 300764631Sitojun#if 0 300878064Sume struct in6_addr gw; 300964631Sitojun#endif 301055163Sshin 301155163Sshin for (i = 0; i < nfilter; i++) { 301255163Sshin ap = filter[i]; 301355163Sshin iflp = NULL; 301455163Sshin ifcp = NULL; 301555163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 301655163Sshin iflp = ap; 301755163Sshin goto ifonly; 301855163Sshin } 3019119038Sume if ((p = strchr(ap, ',')) != NULL) { 302055163Sshin *p++ = '\0'; 302155163Sshin iflp = p; 302255163Sshin } 3023119038Sume if ((p = strchr(ap, '/')) == NULL) { 302455163Sshin fatal("no prefixlen specified for '%s'", ap); 302578064Sume /*NOTREACHED*/ 302678064Sume } 302755163Sshin *p++ = '\0'; 302878064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 302955163Sshin fatal("invalid prefix specified for '%s'", ap); 303078064Sume /*NOTREACHED*/ 303178064Sume } 303255163Sshin ftmp.iff_plen = atoi(p); 303355163Sshin ftmp.iff_next = NULL; 303455163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 303555163Sshinifonly: 303655163Sshin ftmp.iff_type = filtertype[i]; 303778064Sume if (iflp == NULL || *iflp == '\0') { 303855163Sshin fatal("no interface specified for '%s'", ap); 303978064Sume /*NOTREACHED*/ 304078064Sume } 304155163Sshin /* parse the interface listing portion */ 304255163Sshin while (iflp) { 304355163Sshin ifname = iflp; 3044119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 304555163Sshin *iflp++ = '\0'; 304655163Sshin ifcp = ifc_find(ifname); 304778064Sume if (ifcp == NULL) { 304855163Sshin fatal("no interface %s exists", ifname); 304978064Sume /*NOTREACHED*/ 305078064Sume } 305155163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 305278064Sume if (iff_obj == NULL) { 305355163Sshin fatal("malloc of iff_obj"); 305478064Sume /*NOTREACHED*/ 305578064Sume } 305655163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 305778064Sume sizeof(struct iff)); 305855163Sshin /* link it to the interface filter */ 305955163Sshin iff_obj->iff_next = ifcp->ifc_filter; 306055163Sshin ifcp->ifc_filter = iff_obj; 306155163Sshin } 306278064Sume 306378064Sume /* 306478064Sume * -A: aggregate configuration. 306578064Sume */ 306655163Sshin if (filtertype[i] != 'A') 306755163Sshin continue; 306855163Sshin /* put the aggregate to the kernel routing table */ 306955163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 307078064Sume if (rrt == NULL) { 307155163Sshin fatal("malloc: rrt"); 307278064Sume /*NOTREACHED*/ 307378064Sume } 307455163Sshin memset(rrt, 0, sizeof(struct riprt)); 307555163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 307655163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 307755163Sshin rrt->rrt_info.rip6_metric = 1; 307855163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 307955163Sshin rrt->rrt_gw = in6addr_loopback; 308062607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 308162607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 308255163Sshin rrt->rrt_t = 0; 3083119039Sume rrt->rrt_index = loopifcp->ifc_index; 308464631Sitojun#if 0 308564631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 308664631Sitojun#if 0 308764631Sitojun /* 308864631Sitojun * When the address has already been registered in the 308964631Sitojun * kernel routing table, it should be removed 309064631Sitojun */ 309164631Sitojun delroute(&rrt->rrt_info, &gw); 309264631Sitojun#else 309378064Sume /* it is safer behavior */ 309464631Sitojun errno = EINVAL; 309564631Sitojun fatal("%s/%u already in routing table, " 309664631Sitojun "cannot aggregate", 309764631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 309864631Sitojun rrt->rrt_info.rip6_plen); 309978064Sume /*NOTREACHED*/ 310064631Sitojun#endif 310164631Sitojun } 310264631Sitojun#endif 310355163Sshin /* Put the route to the list */ 310455163Sshin rrt->rrt_next = riprt; 310555163Sshin riprt = rrt; 310655163Sshin trace(1, "Aggregate: %s/%d for %s\n", 310755163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 310855163Sshin ifcp->ifc_name); 310955163Sshin /* Add this route to the kernel */ 311055163Sshin if (nflag) /* do not modify kernel routing table */ 311155163Sshin continue; 311255163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 311355163Sshin } 311455163Sshin} 311555163Sshin 311655163Sshin/***************** utility functions *****************/ 311755163Sshin 311855163Sshin/* 311955163Sshin * Returns a pointer to ifac whose address and prefix length matches 312055163Sshin * with the address and prefix length specified in the arguments. 312155163Sshin */ 312255163Sshinstruct ifac * 312355163Sshinifa_match(ifcp, ia, plen) 312455163Sshin const struct ifc *ifcp; 312555163Sshin const struct in6_addr *ia; 312655163Sshin int plen; 312755163Sshin{ 312855163Sshin struct ifac *ifa; 312955163Sshin 313055163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 313155163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 313255163Sshin ifa->ifa_plen == plen) 313355163Sshin break; 313455163Sshin } 313555163Sshin return ifa; 313655163Sshin} 313755163Sshin 313855163Sshin/* 313955163Sshin * Return a pointer to riprt structure whose address and prefix length 314055163Sshin * matches with the address and prefix length found in the argument. 314178064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 314255163Sshin */ 314355163Sshinstruct riprt * 314478064Sumertsearch(np, prev_rrt) 314555163Sshin struct netinfo6 *np; 314678064Sume struct riprt **prev_rrt; 314755163Sshin{ 314855163Sshin struct riprt *rrt; 314955163Sshin 315078064Sume if (prev_rrt) 315178064Sume *prev_rrt = NULL; 315255163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 315355163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 315455163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 315555163Sshin &np->rip6_dest)) 315655163Sshin return rrt; 315778064Sume if (prev_rrt) 315878064Sume *prev_rrt = rrt; 315955163Sshin } 316078064Sume if (prev_rrt) 316178064Sume *prev_rrt = NULL; 316255163Sshin return 0; 316355163Sshin} 316455163Sshin 316555163Sshinint 316678064Sumesin6mask2len(sin6) 316778064Sume const struct sockaddr_in6 *sin6; 316878064Sume{ 316978064Sume 317078064Sume return mask2len(&sin6->sin6_addr, 317178064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 317278064Sume} 317378064Sume 317478064Sumeint 317555163Sshinmask2len(addr, lenlim) 317655163Sshin const struct in6_addr *addr; 317755163Sshin int lenlim; 317855163Sshin{ 317955163Sshin int i = 0, j; 318078064Sume const u_char *p = (const u_char *)addr; 318162607Sitojun 318255163Sshin for (j = 0; j < lenlim; j++, p++) { 318355163Sshin if (*p != 0xff) 318455163Sshin break; 318555163Sshin i += 8; 318655163Sshin } 318755163Sshin if (j < lenlim) { 318855163Sshin switch (*p) { 318962607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 319062607Sitojun MASKLEN(0xfe, 7); break; 319162607Sitojun MASKLEN(0xfc, 6); break; 319262607Sitojun MASKLEN(0xf8, 5); break; 319362607Sitojun MASKLEN(0xf0, 4); break; 319462607Sitojun MASKLEN(0xe0, 3); break; 319562607Sitojun MASKLEN(0xc0, 2); break; 319662607Sitojun MASKLEN(0x80, 1); break; 319755163Sshin#undef MASKLEN 319855163Sshin } 319955163Sshin } 320055163Sshin return i; 320155163Sshin} 320255163Sshin 320355163Sshinvoid 320455163Sshinapplymask(addr, mask) 320555163Sshin struct in6_addr *addr, *mask; 320655163Sshin{ 320755163Sshin int i; 320855163Sshin u_long *p, *q; 320955163Sshin 321055163Sshin p = (u_long *)addr; q = (u_long *)mask; 321155163Sshin for (i = 0; i < 4; i++) 321255163Sshin *p++ &= *q++; 321355163Sshin} 321455163Sshin 321555163Sshinstatic const u_char plent[8] = { 321655163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 321755163Sshin}; 321855163Sshin 321955163Sshinvoid 322055163Sshinapplyplen(ia, plen) 322155163Sshin struct in6_addr *ia; 322255163Sshin int plen; 322355163Sshin{ 322455163Sshin u_char *p; 322555163Sshin int i; 322655163Sshin 322755163Sshin p = ia->s6_addr; 322855163Sshin for (i = 0; i < 16; i++) { 322955163Sshin if (plen <= 0) 323055163Sshin *p = 0; 323155163Sshin else if (plen < 8) 323255163Sshin *p &= plent[plen]; 323355163Sshin p++, plen -= 8; 323455163Sshin } 323555163Sshin} 323655163Sshin 323755163Sshinstatic const int pl2m[9] = { 323855163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 323955163Sshin}; 324055163Sshin 324155163Sshinstruct in6_addr * 324255163Sshinplen2mask(n) 324355163Sshin int n; 324455163Sshin{ 324555163Sshin static struct in6_addr ia; 324655163Sshin u_char *p; 324755163Sshin int i; 324855163Sshin 324955163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 325055163Sshin p = (u_char *)&ia; 325155163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 325255163Sshin if (n >= 8) { 325355163Sshin *p = 0xff; 325455163Sshin continue; 325555163Sshin } 325655163Sshin *p = pl2m[n]; 325755163Sshin break; 325855163Sshin } 325955163Sshin return &ia; 326055163Sshin} 326155163Sshin 326255163Sshinchar * 326355163Sshinallocopy(p) 326455163Sshin char *p; 326555163Sshin{ 3266119033Sume int len = strlen(p) + 1; 3267119033Sume char *q = (char *)malloc(len); 326855163Sshin 3269119033Sume if (!q) { 3270119033Sume fatal("malloc"); 3271119033Sume /*NOTREACHED*/ 3272119033Sume } 3273119033Sume 3274119033Sume strlcpy(q, p, len); 327555163Sshin return q; 327655163Sshin} 327755163Sshin 327855163Sshinchar * 327955163Sshinhms() 328055163Sshin{ 328155163Sshin static char buf[BUFSIZ]; 328255163Sshin time_t t; 328355163Sshin struct tm *tm; 328455163Sshin 328555163Sshin t = time(NULL); 328678064Sume if ((tm = localtime(&t)) == 0) { 328755163Sshin fatal("localtime"); 328878064Sume /*NOTREACHED*/ 328978064Sume } 329078064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 329178064Sume tm->tm_sec); 329255163Sshin return buf; 329355163Sshin} 329455163Sshin 329555163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 329655163Sshin 329755163Sshinint 329855163Sshinripinterval(timer) 329955163Sshin int timer; 330055163Sshin{ 330155163Sshin double r = rand(); 330255163Sshin 330355163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 330455163Sshin nextalarm = time(NULL) + interval; 330555163Sshin return interval; 330655163Sshin} 330755163Sshin 330855163Sshintime_t 330955163Sshinripsuptrig() 331055163Sshin{ 331155163Sshin time_t t; 331255163Sshin 331355163Sshin double r = rand(); 331462607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 331578064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 331655163Sshin sup_trig_update = time(NULL) + t; 331755163Sshin return t; 331855163Sshin} 331955163Sshin 332055163Sshinvoid 332155163Sshin#ifdef __STDC__ 332255163Sshinfatal(const char *fmt, ...) 332355163Sshin#else 332455163Sshinfatal(fmt, va_alist) 332555163Sshin char *fmt; 332655163Sshin va_dcl 332755163Sshin#endif 332855163Sshin{ 332955163Sshin va_list ap; 333055163Sshin char buf[1024]; 333155163Sshin 333255163Sshin#ifdef __STDC__ 333355163Sshin va_start(ap, fmt); 333455163Sshin#else 333555163Sshin va_start(ap); 333655163Sshin#endif 333755163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 333855163Sshin perror(buf); 333955163Sshin syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 334078064Sume rtdexit(); 334155163Sshin va_end(ap); 334255163Sshin} 334355163Sshin 334455163Sshinvoid 334555163Sshin#ifdef __STDC__ 334655163Sshintracet(int level, const char *fmt, ...) 334755163Sshin#else 334855163Sshintracet(level, fmt, va_alist) 334955163Sshin int level; 335055163Sshin char *fmt; 335155163Sshin va_dcl 335255163Sshin#endif 335355163Sshin{ 335455163Sshin va_list ap; 335555163Sshin 335655163Sshin#ifdef __STDC__ 335755163Sshin va_start(ap, fmt); 335855163Sshin#else 335955163Sshin va_start(ap); 336055163Sshin#endif 336155163Sshin if (level <= dflag) { 336255163Sshin fprintf(stderr, "%s: ", hms()); 336355163Sshin vfprintf(stderr, fmt, ap); 336455163Sshin } 336555163Sshin if (dflag) { 336655163Sshin if (level > 0) 336755163Sshin vsyslog(LOG_DEBUG, fmt, ap); 336855163Sshin else 336955163Sshin vsyslog(LOG_WARNING, fmt, ap); 337055163Sshin } 337155163Sshin va_end(ap); 337255163Sshin} 337355163Sshin 337455163Sshinvoid 337555163Sshin#ifdef __STDC__ 337655163Sshintrace(int level, const char *fmt, ...) 337755163Sshin#else 337855163Sshintrace(level, fmt, va_alist) 337955163Sshin int level; 338055163Sshin char *fmt; 338155163Sshin va_dcl 338255163Sshin#endif 338355163Sshin{ 338455163Sshin va_list ap; 338555163Sshin 338655163Sshin#ifdef __STDC__ 338755163Sshin va_start(ap, fmt); 338855163Sshin#else 338955163Sshin va_start(ap); 339055163Sshin#endif 339155163Sshin if (level <= dflag) 339255163Sshin vfprintf(stderr, fmt, ap); 339355163Sshin if (dflag) { 339455163Sshin if (level > 0) 339555163Sshin vsyslog(LOG_DEBUG, fmt, ap); 339655163Sshin else 339755163Sshin vsyslog(LOG_WARNING, fmt, ap); 339855163Sshin } 339955163Sshin va_end(ap); 340055163Sshin} 340155163Sshin 340255163Sshinunsigned int 340355163Sshinif_maxindex() 340455163Sshin{ 340555163Sshin struct if_nameindex *p, *p0; 340655163Sshin unsigned int max = 0; 340755163Sshin 340855163Sshin p0 = if_nameindex(); 340955163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 341055163Sshin if (max < p->if_index) 341155163Sshin max = p->if_index; 341255163Sshin } 341355163Sshin if_freenameindex(p0); 341455163Sshin return max; 341555163Sshin} 341655163Sshin 341755163Sshinstruct ifc * 341855163Sshinifc_find(name) 341955163Sshin char *name; 342055163Sshin{ 342155163Sshin struct ifc *ifcp; 342255163Sshin 342355163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 342455163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 342555163Sshin return ifcp; 342655163Sshin } 342755163Sshin return (struct ifc *)NULL; 342855163Sshin} 342955163Sshin 343055163Sshinstruct iff * 343155163Sshiniff_find(ifcp, type) 343255163Sshin struct ifc *ifcp; 343355163Sshin int type; 343455163Sshin{ 343555163Sshin struct iff *iffp; 343655163Sshin 343755163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 343855163Sshin if (iffp->iff_type == type) 343955163Sshin return iffp; 344055163Sshin } 344155163Sshin return NULL; 344255163Sshin} 344355163Sshin 344455163Sshinvoid 344578064Sumesetindex2ifc(idx, ifcp) 344678064Sume int idx; 344755163Sshin struct ifc *ifcp; 344855163Sshin{ 344955163Sshin int n; 345062607Sitojun struct ifc **p; 345155163Sshin 345255163Sshin if (!index2ifc) { 345355163Sshin nindex2ifc = 5; /*initial guess*/ 345455163Sshin index2ifc = (struct ifc **) 345555163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 345678064Sume if (index2ifc == NULL) { 345755163Sshin fatal("malloc"); 345878064Sume /*NOTREACHED*/ 345978064Sume } 346055163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 346155163Sshin } 346255163Sshin n = nindex2ifc; 346378064Sume while (nindex2ifc <= idx) 346455163Sshin nindex2ifc *= 2; 346555163Sshin if (n != nindex2ifc) { 346662607Sitojun p = (struct ifc **)realloc(index2ifc, 346762607Sitojun sizeof(*index2ifc) * nindex2ifc); 346878064Sume if (p == NULL) { 346955163Sshin fatal("realloc"); 347078064Sume /*NOTREACHED*/ 347178064Sume } 347278064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 347362607Sitojun index2ifc = p; 347455163Sshin } 347578064Sume index2ifc[idx] = ifcp; 347655163Sshin} 3477