route6d.c revision 55163
155163Sshin/* 255163Sshin * $Header: /cvsroot/kame/kame/kame/kame/route6d/route6d.c,v 1.6 1999/09/10 08:20:59 itojun Exp $ 355163Sshin */ 455163Sshin 555163Sshin/* 655163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 755163Sshin * All rights reserved. 855163Sshin * 955163Sshin * Redistribution and use in source and binary forms, with or without 1055163Sshin * modification, are permitted provided that the following conditions 1155163Sshin * are met: 1255163Sshin * 1. Redistributions of source code must retain the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer. 1455163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1555163Sshin * notice, this list of conditions and the following disclaimer in the 1655163Sshin * documentation and/or other materials provided with the distribution. 1755163Sshin * 3. Neither the name of the project nor the names of its contributors 1855163Sshin * may be used to endorse or promote products derived from this software 1955163Sshin * without specific prior written permission. 2055163Sshin * 2155163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2255163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2555163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155163Sshin * SUCH DAMAGE. 3255163Sshin * 3355163Sshin * $FreeBSD: head/usr.sbin/route6d/route6d.c 55163 1999-12-28 02:37:14Z shin $ 3455163Sshin */ 3555163Sshin 3655163Sshin#ifndef lint 3755163Sshinstatic char _rcsid[] = "$Id: route6d.c,v 1.6 1999/09/10 08:20:59 itojun Exp $"; 3855163Sshin#endif 3955163Sshin 4055163Sshin#include <stdio.h> 4155163Sshin 4255163Sshin#include <time.h> 4355163Sshin#include <unistd.h> 4455163Sshin#include <stdlib.h> 4555163Sshin#include <string.h> 4655163Sshin#include <signal.h> 4755163Sshin#ifdef __STDC__ 4855163Sshin#include <stdarg.h> 4955163Sshin#else 5055163Sshin#include <varargs.h> 5155163Sshin#endif 5255163Sshin#include <syslog.h> 5355163Sshin#include <stddef.h> 5455163Sshin#include <err.h> 5555163Sshin 5655163Sshin#include <sys/types.h> 5755163Sshin#include <sys/param.h> 5855163Sshin#include <sys/file.h> 5955163Sshin#include <sys/socket.h> 6055163Sshin#include <sys/ioctl.h> 6155163Sshin#include <sys/sysctl.h> 6255163Sshin#include <sys/errno.h> 6355163Sshin#ifdef ADVAPI 6455163Sshin#include <sys/uio.h> 6555163Sshin#endif 6655163Sshin#include <net/if.h> 6755163Sshin#if defined(__FreeBSD__) && __FreeBSD__ >= 3 6855163Sshin#include <net/if_var.h> 6955163Sshin#endif /* __FreeBSD__ >= 3 */ 7055163Sshin#define KERNEL 1 7155163Sshin#include <net/route.h> 7255163Sshin#undef KERNEL 7355163Sshin#include <netinet/in.h> 7455163Sshin#include <netinet/in_var.h> 7555163Sshin#include <netinet/ip6.h> 7655163Sshin#include <netinet/udp.h> 7755163Sshin#include <netdb.h> 7855163Sshin 7955163Sshin#include <arpa/inet.h> 8055163Sshin 8155163Sshin#include "route6d.h" 8255163Sshin 8355163Sshin#define MAXFILTER 40 8455163Sshin 8555163Sshin#ifdef DEBUG 8655163Sshin#define INIT_INTERVAL6 6 8755163Sshin#else 8855163Sshin#define INIT_INTERVAL6 10 /* Wait to submit a initial riprequest */ 8955163Sshin#endif 9055163Sshin 9155163Sshin/* alignment constraint for routing socket */ 9255163Sshin#define ROUNDUP(a) \ 9355163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9455163Sshin#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9555163Sshin 9655163Sshin/* 9755163Sshin * Following two macros are highly depending on KAME Release 9855163Sshin */ 9955163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 10055163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 10155163Sshin 10255163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10355163Sshin do { \ 10455163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10555163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10655163Sshin } while (0) 10755163Sshin 10855163Sshinstruct ifc { /* Configuration of an interface */ 10955163Sshin char *ifc_name; /* if name */ 11055163Sshin struct ifc *ifc_next; 11155163Sshin int ifc_index; /* if index */ 11255163Sshin int ifc_mtu; /* if mtu */ 11355163Sshin int ifc_metric; /* if metric */ 11455163Sshin short ifc_flags; /* flags */ 11555163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11655163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11755163Sshin struct iff *ifc_filter; /* filter structure */ 11855163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 11955163Sshin int ifc_joined; /* joined to ff02::9 */ 12055163Sshin}; 12155163Sshin 12255163Sshinstruct ifac { /* Adddress associated to an interface */ 12355163Sshin struct ifc *ifa_conf; /* back pointer */ 12455163Sshin struct ifac *ifa_next; 12555163Sshin struct in6_addr ifa_addr; /* address */ 12655163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12755163Sshin int ifa_plen; /* prefix length */ 12855163Sshin}; 12955163Sshin 13055163Sshinstruct iff { 13155163Sshin int iff_type; 13255163Sshin struct in6_addr iff_addr; 13355163Sshin int iff_plen; 13455163Sshin struct iff *iff_next; 13555163Sshin}; 13655163Sshin 13755163Sshinstruct ifc *ifc; 13855163Sshinint nifc; /* number of valid ifc's */ 13955163Sshinstruct ifc **index2ifc; 14055163Sshinint nindex2ifc; 14155163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 14255163Sshinint loopifindex = 0; /* ditto */ 14355163Sshinfd_set sockvec; /* vector to select() for receiving */ 14455163Sshinint rtsock; /* the routing socket */ 14555163Sshinint ripsock; /* socket to send/receive RIP datagram */ 14655163Sshin 14755163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 14855163Sshin 14955163Sshin/* 15055163Sshin * Maintain the routes in a linked list. When the number of the routes 15155163Sshin * grows, somebody would like to introduce a hash based or a radix tree 15255163Sshin * based strucutre. I believe the number of routes handled by RIP is 15355163Sshin * limited and I don't have to manage a complex data structure, however. 15455163Sshin * 15555163Sshin * One of the major drawbacks of the linear linked list is the difficulty 15655163Sshin * of representing the relationship between a couple of routes. This may 15755163Sshin * be a significant problem when we have to support route aggregation with 15855163Sshin * supressing the specifices covered by the aggregate. 15955163Sshin */ 16055163Sshin 16155163Sshinstruct riprt { 16255163Sshin struct riprt *rrt_next; /* next destination */ 16355163Sshin struct riprt *rrt_same; /* same destination - future use */ 16455163Sshin struct netinfo6 rrt_info; /* network info */ 16555163Sshin struct in6_addr rrt_gw; /* gateway */ 16655163Sshin u_long rrt_flags; 16755163Sshin time_t rrt_t; /* when the route validated */ 16855163Sshin int rrt_index; /* ifindex from which this route got */ 16955163Sshin}; 17055163Sshin 17155163Sshinstruct riprt *riprt = 0; 17255163Sshin 17355163Sshinint dflag = 0; /* debug flag */ 17455163Sshinint qflag = 0; /* quiet flag */ 17555163Sshinint nflag = 0; /* don't update kernel routing table */ 17655163Sshinint aflag = 0; /* age out even the statically defined routes */ 17755163Sshinint hflag = 0; /* don't split horizon */ 17855163Sshinint lflag = 0; /* exchange site local routes */ 17955163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 18055163Sshinint Sflag = 0; /* announce static routes to every interface */ 18155163Sshinint routetag = 0; /* route tag attached on originating case */ 18255163Sshin 18355163Sshinchar *filter[MAXFILTER]; 18455163Sshinint filtertype[MAXFILTER]; 18555163Sshinint nfilter = 0; 18655163Sshin 18755163Sshinpid_t pid; 18855163Sshin 18955163Sshinstruct sockaddr_storage ripsin; 19055163Sshin 19155163Sshinstruct rtentry rtentry; 19255163Sshin 19355163Sshinint interval = 1; 19455163Sshintime_t nextalarm = 0; 19555163Sshintime_t sup_trig_update = 0; 19655163Sshin 19755163SshinFILE *rtlog = NULL; 19855163Sshin 19955163Sshinint logopened = 0; 20055163Sshin 20155163Sshinstatic u_long seq = 0; 20255163Sshin 20355163Sshin#define RTF_AGGREGATE 0x08000000 20455163Sshin#define RTF_NOADVERTISE 0x10000000 20555163Sshin#define RTF_NH_NOT_LLADDR 0x20000000 20655163Sshin#define RTF_SENDANYWAY 0x40000000 20755163Sshin#define RTF_CHANGED 0x80000000 20855163Sshin#define RTF_ROUTE_H 0xffff 20955163Sshin 21055163Sshinextern int errno; 21155163Sshin 21255163Sshinint main __P((int, char **)); 21355163Sshinvoid ripalarm __P((int)); 21455163Sshinvoid riprecv __P((void)); 21555163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 21655163Sshinvoid init __P((void)); 21755163Sshinvoid sockopt __P((struct ifc *)); 21855163Sshinvoid ifconfig __P((void)); 21955163Sshinvoid ifconfig1 __P((struct ifreq *, struct ifc *, int)); 22055163Sshinvoid rtrecv __P((void)); 22155163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 22255163Sshin const struct sockaddr_in6 *)); 22355163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 22455163Sshin const struct sockaddr_in6 *)); 22555163Sshinvoid filterconfig __P((void)); 22655163Sshinint getifmtu __P((int)); 22755163Sshinconst char *rttypes __P((struct rt_msghdr *rtm)); 22855163Sshinconst char *rtflags __P((struct rt_msghdr *rtm)); 22955163Sshinconst char *ifflags __P((int flags)); 23055163Sshinvoid ifrt __P((struct ifc *, int)); 23155163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 23255163Sshinvoid applyplen __P((struct in6_addr *, int)); 23355163Sshinvoid ifrtdump __P((int)); 23455163Sshinvoid ifdump __P((int)); 23555163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 23655163Sshinvoid rtdump __P((int)); 23755163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 23855163Sshinvoid rtdexit __P((int)); 23955163Sshinvoid riprequest __P((struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *)); 24055163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 24155163Sshinvoid sendrequest __P((struct ifc *)); 24255163Sshinint mask2len __P((const struct in6_addr *, int)); 24355163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 24455163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 24555163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 24655163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 24755163Sshinvoid krtread __P((int)); 24855163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 24955163Sshinchar *allocopy __P((char *)); 25055163Sshinchar *hms __P((void)); 25155163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 25255163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 25355163Sshinstruct in6_addr *plen2mask __P((int)); 25455163Sshinstruct riprt *rtsearch __P((struct netinfo6 *)); 25555163Sshinint ripinterval __P((int)); 25655163Sshintime_t ripsuptrig __P((void)); 25755163Sshinvoid fatal __P((const char *, ...)); 25855163Sshinvoid trace __P((int, const char *, ...)); 25955163Sshinvoid tracet __P((int, const char *, ...)); 26055163Sshinunsigned int if_maxindex __P((void)); 26155163Sshinstruct ifc *ifc_find __P((char *)); 26255163Sshinstruct iff *iff_find __P((struct ifc *, int)); 26355163Sshinvoid setindex2ifc __P((int, struct ifc *)); 26455163Sshin 26555163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 26655163Sshin 26755163Sshinint 26855163Sshinmain(argc, argv) 26955163Sshin int argc; 27055163Sshin char **argv; 27155163Sshin{ 27255163Sshin int ch; 27355163Sshin int error = 0; 27455163Sshin struct ifc *ifcp; 27555163Sshin sigset_t mask, omask; 27655163Sshin FILE *pidfile; 27755163Sshin extern char *optarg; 27855163Sshin extern int optind; 27955163Sshin char *progname; 28055163Sshin 28155163Sshin progname = strrchr(*argv, '/'); 28255163Sshin if (progname) 28355163Sshin progname++; 28455163Sshin else 28555163Sshin progname = *argv; 28655163Sshin 28755163Sshin pid = getpid(); 28855163Sshin while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != EOF) { 28955163Sshin switch (ch) { 29055163Sshin case 'A': 29155163Sshin case 'N': 29255163Sshin case 'O': 29355163Sshin case 'T': 29455163Sshin case 'L': 29555163Sshin if (nfilter >= MAXFILTER) 29655163Sshin fatal("Exceeds MAXFILTER"); 29755163Sshin filtertype[nfilter] = ch; 29855163Sshin filter[nfilter++] = allocopy(optarg); 29955163Sshin break; 30055163Sshin case 't': 30155163Sshin sscanf(optarg, "%i", &routetag); 30255163Sshin if (routetag & ~0xffff) { 30355163Sshin fatal("invalid route tag"); 30455163Sshin /*NOTREACHED*/ 30555163Sshin } 30655163Sshin break; 30755163Sshin case 'R': 30855163Sshin if ((rtlog = fopen(optarg, "w")) == NULL) 30955163Sshin fatal("Can not write to routelog"); 31055163Sshin break; 31155163Sshin#define FLAG(c, flag, n) case c: flag = n; break 31255163Sshin FLAG('a', aflag, 1); 31355163Sshin FLAG('d', dflag, 1); 31455163Sshin FLAG('D', dflag, 2); 31555163Sshin FLAG('h', hflag, 1); 31655163Sshin FLAG('l', lflag, 1); 31755163Sshin FLAG('n', nflag, 1); 31855163Sshin FLAG('q', qflag, 1); 31955163Sshin FLAG('s', sflag, 1); 32055163Sshin FLAG('S', Sflag, 1); 32155163Sshin#undef FLAG 32255163Sshin default: 32355163Sshin fatal("Invalid option specified, terminating"); 32455163Sshin } 32555163Sshin } 32655163Sshin argc -= optind; 32755163Sshin argv += optind; 32855163Sshin if (argc > 0) 32955163Sshin fatal("bogus extra arguments"); 33055163Sshin 33155163Sshin if (geteuid()) { 33255163Sshin nflag = 1; 33355163Sshin fprintf(stderr, "No kernel update is allowed\n"); 33455163Sshin } 33555163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 33655163Sshin logopened++; 33755163Sshin init(); 33855163Sshin ifconfig(); 33955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 34055163Sshin if (ifcp->ifc_index < 0) { 34155163Sshin fprintf(stderr, 34255163Sshin"No ifindex found at %s (no link-local address?)\n", 34355163Sshin ifcp->ifc_name); 34455163Sshin error++; 34555163Sshin } 34655163Sshin } 34755163Sshin if (error) 34855163Sshin exit(1); 34955163Sshin if (loopifcp == NULL) 35055163Sshin fatal("No loopback found"); 35155163Sshin loopifindex = loopifcp->ifc_index; 35255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 35355163Sshin ifrt(ifcp, 0); 35455163Sshin filterconfig(); 35555163Sshin krtread(0); 35655163Sshin if (dflag) 35755163Sshin ifrtdump(0); 35855163Sshin 35955163Sshin if (dflag == 0) { 36055163Sshin#if 1 36155163Sshin if (daemon(0, 0) < 0) 36255163Sshin fatal("daemon"); 36355163Sshin#else 36455163Sshin if (fork()) 36555163Sshin exit(0); 36655163Sshin if (setsid() < 0) 36755163Sshin fatal("setid"); 36855163Sshin#endif 36955163Sshin } 37055163Sshin pid = getpid(); 37155163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 37255163Sshin fprintf(pidfile, "%d\n", pid); 37355163Sshin fclose(pidfile); 37455163Sshin } 37555163Sshin 37655163Sshin if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 37755163Sshin fatal("malloc"); 37855163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 37955163Sshin ripbuf->rip6_vers = RIP6_VERSION; 38055163Sshin ripbuf->rip6_res1[0] = 0; 38155163Sshin ripbuf->rip6_res1[1] = 0; 38255163Sshin 38355163Sshin if (signal(SIGALRM, ripalarm) == SIG_ERR) 38455163Sshin fatal("signal: SIGALRM"); 38555163Sshin if (signal(SIGQUIT, rtdexit) == SIG_ERR) 38655163Sshin fatal("signal: SIGQUIT"); 38755163Sshin if (signal(SIGTERM, rtdexit) == SIG_ERR) 38855163Sshin fatal("signal: SIGTERM"); 38955163Sshin if (signal(SIGUSR1, ifrtdump) == SIG_ERR) 39055163Sshin fatal("signal: SIGUSR1"); 39155163Sshin if (signal(SIGHUP, ifrtdump) == SIG_ERR) 39255163Sshin fatal("signal: SIGHUP"); 39355163Sshin if (signal(SIGINT, ifrtdump) == SIG_ERR) 39455163Sshin fatal("signal: SIGINT"); 39555163Sshin /* 39655163Sshin * To avoid rip packet congestion (not on a cable but in this 39755163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 39855163Sshin * packets. 39955163Sshin */ 40055163Sshin alarm(ripinterval(INIT_INTERVAL6)); 40155163Sshin 40255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 40355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 40455163Sshin sendrequest(ifcp); 40555163Sshin } 40655163Sshin 40755163Sshin syslog(LOG_INFO, "**** Started ****"); 40855163Sshin sigemptyset(&mask); 40955163Sshin sigaddset(&mask, SIGALRM); 41055163Sshin while (1) { 41155163Sshin fd_set recvec; 41255163Sshin 41355163Sshin FD_COPY(&sockvec, &recvec); 41455163Sshin switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { 41555163Sshin case -1: 41655163Sshin if (errno == EINTR) 41755163Sshin continue; 41855163Sshin fatal("select"); 41955163Sshin case 0: 42055163Sshin continue; 42155163Sshin default: 42255163Sshin if (FD_ISSET(ripsock, &recvec)) { 42355163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 42455163Sshin riprecv(); 42555163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 42655163Sshin } 42755163Sshin if (FD_ISSET(rtsock, &recvec)) { 42855163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 42955163Sshin rtrecv(); 43055163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 43155163Sshin } 43255163Sshin } 43355163Sshin } 43455163Sshin} 43555163Sshin 43655163Sshin/* 43755163Sshin * gracefully exits after resetting sockopts. 43855163Sshin */ 43955163Sshin/* ARGSUSED */ 44055163Sshinvoid 44155163Sshinrtdexit(sig) 44255163Sshin int sig; 44355163Sshin{ 44455163Sshin struct riprt *rrt; 44555163Sshin 44655163Sshin alarm(0); 44755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 44855163Sshin if (rrt->rrt_flags & RTF_AGGREGATE) { 44955163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 45055163Sshin } 45155163Sshin } 45255163Sshin close(ripsock); 45355163Sshin close(rtsock); 45455163Sshin syslog(LOG_INFO, "**** Terminated ****"); 45555163Sshin closelog(); 45655163Sshin exit(1); 45755163Sshin} 45855163Sshin 45955163Sshin/* 46055163Sshin * Called periodically: 46155163Sshin * 1. age out the learned route. remove it if necessary. 46255163Sshin * 2. submit RIP6_RESPONSE packets. 46355163Sshin * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 46455163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 46555163Sshin * routes more precisely. 46655163Sshin */ 46755163Sshin/* ARGSUSED */ 46855163Sshinvoid 46955163Sshinripalarm(sig) 47055163Sshin int sig; 47155163Sshin{ 47255163Sshin struct ifc *ifcp; 47355163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 47455163Sshin time_t t_lifetime, t_holddown; 47555163Sshin 47655163Sshin /* age the RIP routes */ 47755163Sshin rrt_prev = 0; 47855163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 47955163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 48055163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 48155163Sshin rrt_next = rrt->rrt_next; 48255163Sshin 48355163Sshin if (rrt->rrt_t == 0) { 48455163Sshin rrt_prev = rrt; 48555163Sshin continue; 48655163Sshin } 48755163Sshin if (rrt->rrt_t < t_holddown) { 48855163Sshin if (rrt_prev) { 48955163Sshin rrt_prev->rrt_next = rrt->rrt_next; 49055163Sshin } else { 49155163Sshin riprt = rrt->rrt_next; 49255163Sshin } 49355163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 49455163Sshin free(rrt); 49555163Sshin continue; 49655163Sshin } 49755163Sshin if (rrt->rrt_t < t_lifetime) 49855163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 49955163Sshin rrt_prev = rrt; 50055163Sshin } 50155163Sshin /* Supply updates */ 50255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 50355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 50455163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 50555163Sshin } 50655163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 50755163Sshin} 50855163Sshin 50955163Sshinvoid 51055163Sshininit() 51155163Sshin{ 51255163Sshin#ifdef ADVAPI 51355163Sshin int i; 51455163Sshin#endif 51555163Sshin int int0, int255, error; 51655163Sshin struct addrinfo hints, *res; 51755163Sshin char port[10]; 51855163Sshin 51955163Sshin ifc = (struct ifc *)NULL; 52055163Sshin nifc = 0; 52155163Sshin nindex2ifc = 0; /*initial guess*/ 52255163Sshin index2ifc = NULL; 52355163Sshin snprintf(port, sizeof(port), "%d", RIP6_PORT); 52455163Sshin 52555163Sshin memset(&hints, 0, sizeof(hints)); 52655163Sshin hints.ai_family = PF_INET6; 52755163Sshin hints.ai_socktype = SOCK_DGRAM; 52855163Sshin hints.ai_flags = AI_PASSIVE; 52955163Sshin error = getaddrinfo(NULL, port, &hints, &res); 53055163Sshin if (error) 53155163Sshin fatal(gai_strerror(error)); 53255163Sshin if (res->ai_next) 53355163Sshin fatal(":: resolved to multiple address"); 53455163Sshin 53555163Sshin int0 = 0; int255 = 255; 53655163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 53755163Sshin if (ripsock < 0) 53855163Sshin fatal("rip socket"); 53955163Sshin if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) 54055163Sshin fatal("rip bind"); 54155163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 54255163Sshin &int255, sizeof(int255)) < 0) 54355163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 54455163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 54555163Sshin &int0, sizeof(int0)) < 0) 54655163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 54755163Sshin#ifdef ADVAPI 54855163Sshin i = 1; 54955163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i, sizeof(i)) < 0) 55055163Sshin fatal("rip IPV6_PKTINFO"); 55155163Sshin#endif /*ADVAPI*/ 55255163Sshin 55355163Sshin memset(&hints, 0, sizeof(hints)); 55455163Sshin hints.ai_family = PF_INET6; 55555163Sshin hints.ai_socktype = SOCK_DGRAM; 55655163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 55755163Sshin if (error) 55855163Sshin fatal(gai_strerror(error)); 55955163Sshin if (res->ai_next) 56055163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 56155163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 56255163Sshin 56355163Sshin#ifdef FD_ZERO 56455163Sshin FD_ZERO(&sockvec); 56555163Sshin#else 56655163Sshin memset(&sockvec, 0, sizeof(sockvec)); 56755163Sshin#endif 56855163Sshin FD_SET(ripsock, &sockvec); 56955163Sshin 57055163Sshin if (nflag == 0) { 57155163Sshin if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) 57255163Sshin fatal("route socket"); 57355163Sshin FD_SET(rtsock, &sockvec); 57455163Sshin } else 57555163Sshin rtsock = -1; /*just for safety */ 57655163Sshin} 57755163Sshin 57855163Sshin#define RIPSIZE(n) (sizeof(struct rip6) + (n-1) * sizeof(struct netinfo6)) 57955163Sshin 58055163Sshin/* 58155163Sshin * ripflush flushes the rip datagram stored in the rip buffer 58255163Sshin */ 58355163Sshinstatic int nrt; 58455163Sshinstatic struct netinfo6 *np; 58555163Sshin 58655163Sshinvoid 58755163Sshinripflush(ifcp, sin) 58855163Sshin struct ifc *ifcp; 58955163Sshin struct sockaddr_in6 *sin; 59055163Sshin{ 59155163Sshin int i; 59255163Sshin int error; 59355163Sshin 59455163Sshin if (ifcp) 59555163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 59655163Sshin ifcp->ifc_name, nrt, 59755163Sshin inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port)); 59855163Sshin else 59955163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 60055163Sshin nrt, inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port)); 60155163Sshin if (dflag >= 2) { 60255163Sshin np = ripbuf->rip6_nets; 60355163Sshin for (i = 0; i < nrt; i++, np++) { 60455163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 60555163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 60655163Sshin trace(2, " NextHop reset"); 60755163Sshin else { 60855163Sshin trace(2, " NextHop %s", 60955163Sshin inet6_n2p(&np->rip6_dest)); 61055163Sshin } 61155163Sshin } else { 61255163Sshin trace(2, " %s/%d[%d]", 61355163Sshin inet6_n2p(&np->rip6_dest), 61455163Sshin np->rip6_plen, np->rip6_metric); 61555163Sshin } 61655163Sshin if (np->rip6_tag) { 61755163Sshin trace(2, " tag=0x%04x", 61855163Sshin ntohs(np->rip6_tag) & 0xffff); 61955163Sshin } 62055163Sshin trace(2, "\n"); 62155163Sshin } 62255163Sshin } 62355163Sshin error = sendpacket(sin, RIPSIZE(nrt)); 62455163Sshin if (error == EAFNOSUPPORT) { 62555163Sshin /* Protocol not supported */ 62655163Sshin tracet(1, "Could not send info to %s (%s): " 62755163Sshin "set IFF_UP to 0\n", 62855163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 62955163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 63055163Sshin } 63155163Sshin nrt = 0; np = ripbuf->rip6_nets; 63255163Sshin} 63355163Sshin 63455163Sshin/* 63555163Sshin * Generate RIP6_RESPONSE packets and send them. 63655163Sshin */ 63755163Sshinvoid 63855163Sshinripsend(ifcp, sin, flag) 63955163Sshin struct ifc *ifcp; 64055163Sshin struct sockaddr_in6 *sin; 64155163Sshin int flag; 64255163Sshin{ 64355163Sshin struct riprt *rrt; 64455163Sshin struct in6_addr *nh; /* next hop */ 64555163Sshin struct in6_addr ia; 64655163Sshin struct iff *iffp; 64755163Sshin int maxrte, ok; 64855163Sshin 64955163Sshin if (ifcp == NULL) { 65055163Sshin /* 65155163Sshin * Request from non-link local address is not 65255163Sshin * a regular route6d update. 65355163Sshin */ 65455163Sshin maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 65555163Sshin sizeof(struct udphdr) - 65655163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 65755163Sshin sizeof(struct netinfo6); 65855163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 65955163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 66055163Sshin if (rrt->rrt_flags & RTF_NOADVERTISE) 66155163Sshin continue; 66255163Sshin /* Put the route to the buffer */ 66355163Sshin *np = rrt->rrt_info; 66455163Sshin np++; nrt++; 66555163Sshin if (nrt == maxrte) { 66655163Sshin ripflush(NULL, sin); 66755163Sshin nh = NULL; 66855163Sshin } 66955163Sshin } 67055163Sshin if (nrt) /* Send last packet */ 67155163Sshin ripflush(NULL, sin); 67255163Sshin return; 67355163Sshin } 67455163Sshin 67555163Sshin if ((flag & RTF_SENDANYWAY) == 0 && 67655163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 67755163Sshin return; 67855163Sshin if (iff_find(ifcp, 'N') != NULL) 67955163Sshin return; 68055163Sshin if (iff_find(ifcp, 'T') != NULL) { 68155163Sshin struct netinfo6 rrt_info; 68255163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 68355163Sshin rrt_info.rip6_dest = in6addr_any; 68455163Sshin rrt_info.rip6_plen = 0; 68555163Sshin rrt_info.rip6_metric = 1; 68655163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 68755163Sshin np = ripbuf->rip6_nets; 68855163Sshin *np = rrt_info; 68955163Sshin nrt = 1; 69055163Sshin ripflush(ifcp, sin); 69155163Sshin return; 69255163Sshin } 69355163Sshin maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 69455163Sshin sizeof(struct udphdr) - 69555163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 69655163Sshin sizeof(struct netinfo6); 69755163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 69855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 69955163Sshin if (rrt->rrt_flags & RTF_NOADVERTISE) 70055163Sshin continue; 70155163Sshin /* Need to check filer here */ 70255163Sshin ok = 1; 70355163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 70455163Sshin if (iffp->iff_type != 'A') 70555163Sshin continue; 70655163Sshin if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 70755163Sshin continue; 70855163Sshin ia = rrt->rrt_info.rip6_dest; 70955163Sshin applyplen(&ia, iffp->iff_plen); 71055163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 71155163Sshin ok = 0; 71255163Sshin break; 71355163Sshin } 71455163Sshin } 71555163Sshin if (!ok) 71655163Sshin continue; 71755163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 71855163Sshin if (iffp->iff_type != 'O') 71955163Sshin continue; 72055163Sshin ok = 0; 72155163Sshin if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 72255163Sshin continue; 72355163Sshin ia = rrt->rrt_info.rip6_dest; 72455163Sshin applyplen(&ia, iffp->iff_plen); 72555163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 72655163Sshin ok = 1; 72755163Sshin break; 72855163Sshin } 72955163Sshin } 73055163Sshin if (!ok) 73155163Sshin continue; 73255163Sshin /* Check split horizon and other conditions */ 73355163Sshin if (tobeadv(rrt, ifcp) == 0) 73455163Sshin continue; 73555163Sshin /* Only considers the routes with flag if specified */ 73655163Sshin if ((flag & RTF_CHANGED) && (rrt->rrt_flags & RTF_CHANGED) == 0) 73755163Sshin continue; 73855163Sshin /* Check nexthop */ 73955163Sshin if (rrt->rrt_index == ifcp->ifc_index && 74055163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 74155163Sshin (rrt->rrt_flags & RTF_NH_NOT_LLADDR) == 0) { 74255163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 74355163Sshin if (nrt == maxrte - 2) 74455163Sshin ripflush(ifcp, sin); 74555163Sshin np->rip6_dest = rrt->rrt_gw; 74655163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 74755163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 74855163Sshin np->rip6_plen = 0; 74955163Sshin np->rip6_tag = 0; 75055163Sshin np->rip6_metric = NEXTHOP_METRIC; 75155163Sshin nh = &rrt->rrt_gw; 75255163Sshin np++; nrt++; 75355163Sshin } 75455163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 75555163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 75655163Sshin rrt->rrt_flags & RTF_NH_NOT_LLADDR)) { 75755163Sshin /* Reset nexthop */ 75855163Sshin if (nrt == maxrte - 2) 75955163Sshin ripflush(ifcp, sin); 76055163Sshin memset(np, 0, sizeof(struct netinfo6)); 76155163Sshin np->rip6_metric = NEXTHOP_METRIC; 76255163Sshin nh = NULL; 76355163Sshin np++; nrt++; 76455163Sshin } 76555163Sshin /* Put the route to the buffer */ 76655163Sshin *np = rrt->rrt_info; 76755163Sshin np++; nrt++; 76855163Sshin if (nrt == maxrte) { 76955163Sshin ripflush(ifcp, sin); 77055163Sshin nh = NULL; 77155163Sshin } 77255163Sshin } 77355163Sshin if (nrt) /* Send last packet */ 77455163Sshin ripflush(ifcp, sin); 77555163Sshin} 77655163Sshin 77755163Sshin/* 77855163Sshin * Determine if the route is to be advertised on the specified interface. 77955163Sshin * It checks options specified in the arguments and the split horizon rule. 78055163Sshin */ 78155163Sshinint 78255163Sshintobeadv(rrt, ifcp) 78355163Sshin struct riprt *rrt; 78455163Sshin struct ifc *ifcp; 78555163Sshin{ 78655163Sshin 78755163Sshin /* Special care for static routes */ 78855163Sshin if (rrt->rrt_flags & RTF_STATIC) { 78955163Sshin if (Sflag) /* Yes, advertise it anyway */ 79055163Sshin return 1; 79155163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 79255163Sshin return 1; 79355163Sshin return 0; 79455163Sshin } 79555163Sshin /* Regular split horizon */ 79655163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 79755163Sshin return 0; 79855163Sshin return 1; 79955163Sshin} 80055163Sshin 80155163Sshin/* 80255163Sshin * Send a rip packet actually. 80355163Sshin */ 80455163Sshinint 80555163Sshinsendpacket(sin, len) 80655163Sshin struct sockaddr_in6 *sin; 80755163Sshin int len; 80855163Sshin{ 80955163Sshin /* 81055163Sshin * MSG_DONTROUTE should not be specified when it responds with a 81155163Sshin * RIP6_REQUEST message. SO_DONTROUTE has been specified to 81255163Sshin * other sockets. 81355163Sshin */ 81455163Sshin#ifdef ADVAPI 81555163Sshin struct msghdr m; 81655163Sshin struct cmsghdr *cm; 81755163Sshin struct iovec iov[2]; 81855163Sshin u_char cmsgbuf[256]; 81955163Sshin struct in6_pktinfo *pi; 82055163Sshin int index; 82155163Sshin struct sockaddr_in6 sincopy; 82255163Sshin 82355163Sshin /* do not overwrite the given sin */ 82455163Sshin sincopy = *sin; 82555163Sshin sin = &sincopy; 82655163Sshin 82755163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) 82855163Sshin || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) { 82955163Sshin index = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr); 83055163Sshin SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0); 83155163Sshin } else 83255163Sshin index = 0; 83355163Sshin 83455163Sshin m.msg_name = (caddr_t)sin; 83555163Sshin m.msg_namelen = sizeof(*sin); 83655163Sshin iov[0].iov_base = (caddr_t)ripbuf; 83755163Sshin iov[0].iov_len = len; 83855163Sshin m.msg_iov = iov; 83955163Sshin m.msg_iovlen = 1; 84055163Sshin if (!index) { 84155163Sshin m.msg_control = NULL; 84255163Sshin m.msg_controllen = 0; 84355163Sshin } else { 84455163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 84555163Sshin cm = (struct cmsghdr *)cmsgbuf; 84655163Sshin m.msg_control = (caddr_t)cm; 84755163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 84855163Sshin 84955163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 85055163Sshin cm->cmsg_level = IPPROTO_IPV6; 85155163Sshin cm->cmsg_type = IPV6_PKTINFO; 85255163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 85355163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 85455163Sshin pi->ipi6_ifindex = index; 85555163Sshin } 85655163Sshin 85755163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 85855163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 85955163Sshin return errno; 86055163Sshin } 86155163Sshin#else 86255163Sshin if (sendto(ripsock, ripbuf, len, 0 /*MSG_DONTROUTE*/, 86355163Sshin (struct sockaddr *)sin, sizeof(struct sockaddr_in6)) < 0) { 86455163Sshin trace(1, "sendto: %s\n", strerror(errno)); 86555163Sshin return errno; 86655163Sshin } 86755163Sshin#endif 86855163Sshin return 0; 86955163Sshin} 87055163Sshin 87155163Sshin/* 87255163Sshin * Receive and process RIP packets. Update the routes/kernel forwarding 87355163Sshin * table if necessary. 87455163Sshin */ 87555163Sshinvoid 87655163Sshinriprecv() 87755163Sshin{ 87855163Sshin struct ifc *ifcp, *ic; 87955163Sshin struct sockaddr_in6 fsock; 88055163Sshin struct in6_addr nh; /* next hop */ 88155163Sshin struct rip6 *rp; 88255163Sshin struct netinfo6 *np, *nq; 88355163Sshin struct riprt *rrt; 88455163Sshin int len, nn, need_trigger, index; 88555163Sshin#ifndef ADVAPI 88655163Sshin int flen; 88755163Sshin#endif 88855163Sshin char buf[4 * RIP6_MAXMTU]; 88955163Sshin time_t t; 89055163Sshin#ifdef ADVAPI 89155163Sshin struct msghdr m; 89255163Sshin struct cmsghdr *cm; 89355163Sshin struct iovec iov[2]; 89455163Sshin u_char cmsgbuf[256]; 89555163Sshin struct in6_pktinfo *pi; 89655163Sshin#endif /*ADVAPI*/ 89755163Sshin struct iff *iffp; 89855163Sshin struct in6_addr ia; 89955163Sshin int ok; 90055163Sshin 90155163Sshin need_trigger = 0; 90255163Sshin#ifdef ADVAPI 90355163Sshin m.msg_name = (caddr_t)&fsock; 90455163Sshin m.msg_namelen = sizeof(fsock); 90555163Sshin iov[0].iov_base = (caddr_t)buf; 90655163Sshin iov[0].iov_len = sizeof(buf); 90755163Sshin m.msg_iov = iov; 90855163Sshin m.msg_iovlen = 1; 90955163Sshin cm = (struct cmsghdr *)cmsgbuf; 91055163Sshin m.msg_control = (caddr_t)cm; 91155163Sshin m.msg_controllen = sizeof(cmsgbuf); 91255163Sshin if ((len = recvmsg(ripsock, &m, 0)) < 0) 91355163Sshin fatal("recvmsg"); 91455163Sshin index = 0; 91555163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 91655163Sshin cm; 91755163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 91855163Sshin if (cm->cmsg_level == IPPROTO_IPV6 91955163Sshin && cm->cmsg_type == IPV6_PKTINFO) { 92055163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 92155163Sshin index = pi->ipi6_ifindex; 92255163Sshin break; 92355163Sshin } 92455163Sshin } 92555163Sshin if (index && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 92655163Sshin SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, index); 92755163Sshin#else 92855163Sshin flen = sizeof(struct sockaddr_in6); 92955163Sshin if ((len = recvfrom(ripsock, buf, sizeof(buf), 0, 93055163Sshin (struct sockaddr *)&fsock, &flen)) < 0) 93155163Sshin fatal("recvfrom"); 93255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 93355163Sshin index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 93455163Sshin else 93555163Sshin index = 0; 93655163Sshin#endif /*ADVAPI*/ 93755163Sshin 93855163Sshin nh = fsock.sin6_addr; 93955163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 94055163Sshin sizeof(struct netinfo6); 94155163Sshin rp = (struct rip6 *)buf; 94255163Sshin np = rp->rip6_nets; 94355163Sshin 94455163Sshin if (rp->rip6_vers != RIP6_VERSION) { 94555163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 94655163Sshin return; 94755163Sshin } 94855163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 94955163Sshin if (index && index < nindex2ifc) { 95055163Sshin ifcp = index2ifc[index]; 95155163Sshin riprequest(ifcp, np, nn, &fsock); 95255163Sshin } else { 95355163Sshin riprequest(NULL, np, nn, &fsock); 95455163Sshin } 95555163Sshin return; 95655163Sshin } 95755163Sshin 95855163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 95955163Sshin trace(1, "Packets from non-ll addr: %s\n", 96055163Sshin inet6_n2p(&fsock.sin6_addr)); 96155163Sshin return; /* Ignore packets from non-link-local addr */ 96255163Sshin } 96355163Sshin index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 96455163Sshin ifcp = (index < nindex2ifc) ? index2ifc[index] : NULL; 96555163Sshin if (!ifcp) { 96655163Sshin trace(1, "Packets to unknown interface index %d\n", index); 96755163Sshin return; /* Ignore it */ 96855163Sshin } 96955163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 97055163Sshin return; /* The packet is from me; ignore */ 97155163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 97255163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 97355163Sshin return; 97455163Sshin } 97555163Sshin if (iff_find(ifcp, 'N') != NULL) 97655163Sshin return; 97755163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 97855163Sshin ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 97955163Sshin 98055163Sshin t = time(NULL); 98155163Sshin for (; nn; nn--, np++) { 98255163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 98355163Sshin /* modify neighbor address */ 98455163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 98555163Sshin nh = np->rip6_dest; 98655163Sshin SET_IN6_LINKLOCAL_IFINDEX(nh, index); 98755163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 98855163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 98955163Sshin nh = fsock.sin6_addr; 99055163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 99155163Sshin } else { 99255163Sshin nh = fsock.sin6_addr; 99355163Sshin trace(1, "\tInvalid Nexthop: %s\n", 99455163Sshin inet6_n2p(&np->rip6_dest)); 99555163Sshin } 99655163Sshin continue; 99755163Sshin } 99855163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 99955163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 100055163Sshin inet6_n2p(&np->rip6_dest), 100155163Sshin np->rip6_plen, np->rip6_metric); 100255163Sshin continue; 100355163Sshin } 100455163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 100555163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 100655163Sshin inet6_n2p(&np->rip6_dest), 100755163Sshin np->rip6_plen, np->rip6_metric); 100855163Sshin continue; 100955163Sshin } 101055163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 101155163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 101255163Sshin inet6_n2p(&np->rip6_dest), 101355163Sshin np->rip6_plen, np->rip6_metric); 101455163Sshin continue; 101555163Sshin } 101655163Sshin /* may need to pass sitelocal prefix in some case, however*/ 101755163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 101855163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 101955163Sshin inet6_n2p(&np->rip6_dest), 102055163Sshin np->rip6_plen, np->rip6_metric); 102155163Sshin continue; 102255163Sshin } 102355163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 102455163Sshin inet6_n2p(&np->rip6_dest), 102555163Sshin np->rip6_plen, np->rip6_metric); 102655163Sshin if (np->rip6_tag) 102755163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 102855163Sshin 102955163Sshin /* Listen-only filter */ 103055163Sshin ok = 1; /* if there's no L filter, it is ok */ 103155163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 103255163Sshin if (iffp->iff_type != 'L') 103355163Sshin continue; 103455163Sshin ok = 0; 103555163Sshin if (np->rip6_plen < iffp->iff_plen) 103655163Sshin continue; 103755163Sshin /* special rule: ::/0 means default, not "in /0" */ 103855163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 103955163Sshin continue; 104055163Sshin ia = np->rip6_dest; 104155163Sshin applyplen(&ia, iffp->iff_plen); 104255163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 104355163Sshin ok = 1; 104455163Sshin break; 104555163Sshin } 104655163Sshin } 104755163Sshin if (!ok) { 104855163Sshin trace(2, " (filtered)\n"); 104955163Sshin continue; 105055163Sshin } 105155163Sshin 105255163Sshin trace(2, "\n"); 105355163Sshin np->rip6_metric++; 105455163Sshin np->rip6_metric += ifcp->ifc_metric; 105555163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 105655163Sshin np->rip6_metric = HOPCNT_INFINITY6; 105755163Sshin 105855163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 105955163Sshin if ((rrt = rtsearch(np)) != NULL) { 106055163Sshin if (rrt->rrt_t == 0) 106155163Sshin continue; /* Intf route has priority */ 106255163Sshin nq = &rrt->rrt_info; 106355163Sshin if (nq->rip6_metric > np->rip6_metric) { 106455163Sshin if (rrt->rrt_index == ifcp->ifc_index && 106555163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 106655163Sshin /* Small metric from the same gateway */ 106755163Sshin nq->rip6_metric = np->rip6_metric; 106855163Sshin } else { 106955163Sshin /* Better route found */ 107055163Sshin rrt->rrt_index = ifcp->ifc_index; 107155163Sshin /* Update routing table */ 107255163Sshin delroute(nq, &rrt->rrt_gw); 107355163Sshin rrt->rrt_gw = nh; 107455163Sshin *nq = *np; 107555163Sshin addroute(rrt, &nh, ifcp); 107655163Sshin } 107755163Sshin rrt->rrt_flags |= RTF_CHANGED; 107855163Sshin rrt->rrt_t = t; 107955163Sshin need_trigger = 1; 108055163Sshin } else if (nq->rip6_metric < np->rip6_metric && 108155163Sshin rrt->rrt_index == ifcp->ifc_index && 108255163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 108355163Sshin /* Got worse route from same gw */ 108455163Sshin nq->rip6_metric = np->rip6_metric; 108555163Sshin rrt->rrt_t = t; 108655163Sshin rrt->rrt_flags |= RTF_CHANGED; 108755163Sshin need_trigger = 1; 108855163Sshin } else if (nq->rip6_metric == np->rip6_metric && 108955163Sshin rrt->rrt_index == ifcp->ifc_index && 109055163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw) && 109155163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 109255163Sshin /* same metric, same route from same gw */ 109355163Sshin rrt->rrt_t = t; 109455163Sshin } 109555163Sshin /* 109655163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 109755163Sshin * do not update age value. Do nothing. 109855163Sshin */ 109955163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 110055163Sshin /* Got a new valid route */ 110155163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 110255163Sshin fatal("malloc: struct riprt"); 110355163Sshin nq = &rrt->rrt_info; 110455163Sshin 110555163Sshin rrt->rrt_same = NULL; 110655163Sshin rrt->rrt_index = ifcp->ifc_index; 110755163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 110855163Sshin rrt->rrt_gw = nh; 110955163Sshin *nq = *np; 111055163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 111155163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 111255163Sshin rrt->rrt_flags |= RTF_HOST; 111355163Sshin 111455163Sshin /* Put the route to the list */ 111555163Sshin rrt->rrt_next = riprt; 111655163Sshin riprt = rrt; 111755163Sshin /* Update routing table */ 111855163Sshin addroute(rrt, &nh, ifcp); 111955163Sshin rrt->rrt_flags |= RTF_CHANGED; 112055163Sshin need_trigger = 1; 112155163Sshin rrt->rrt_t = t; 112255163Sshin } 112355163Sshin } 112455163Sshin /* XXX need to care the interval between triggered updates */ 112555163Sshin if (need_trigger) { 112655163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 112755163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 112855163Sshin if (ifcp->ifc_index == ic->ifc_index) 112955163Sshin continue; 113055163Sshin if (ic->ifc_flags & IFF_UP) 113155163Sshin ripsend(ic, &ic->ifc_ripsin, 113255163Sshin RTF_CHANGED); 113355163Sshin } 113455163Sshin } 113555163Sshin /* Reset the flag */ 113655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 113755163Sshin rrt->rrt_flags &= ~RTF_CHANGED; 113855163Sshin } 113955163Sshin} 114055163Sshin 114155163Sshin/* 114255163Sshin * Send all routes request packet to the specified interface. 114355163Sshin */ 114455163Sshinvoid 114555163Sshinsendrequest(ifcp) 114655163Sshin struct ifc *ifcp; 114755163Sshin{ 114855163Sshin struct netinfo6 *np; 114955163Sshin int error; 115055163Sshin 115155163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 115255163Sshin return; 115355163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 115455163Sshin np = ripbuf->rip6_nets; 115555163Sshin memset(np, 0, sizeof(struct netinfo6)); 115655163Sshin np->rip6_metric = HOPCNT_INFINITY6; 115755163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 115855163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 115955163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 116055163Sshin if (error == EAFNOSUPPORT) { 116155163Sshin /* Protocol not supported */ 116255163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 116355163Sshin "set IFF_UP to 0\n", 116455163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 116555163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 116655163Sshin } 116755163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 116855163Sshin} 116955163Sshin 117055163Sshin/* 117155163Sshin * Process a RIP6_REQUEST packet. 117255163Sshin */ 117355163Sshinvoid 117455163Sshinriprequest(ifcp, np, nn, sin) 117555163Sshin struct ifc *ifcp; 117655163Sshin struct netinfo6 *np; 117755163Sshin int nn; 117855163Sshin struct sockaddr_in6 *sin; 117955163Sshin{ 118055163Sshin int i; 118155163Sshin struct riprt *rrt; 118255163Sshin 118355163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 118455163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 118555163Sshin /* Specific response, don't split-horizon */ 118655163Sshin trace(1, "\tRIP Request\n"); 118755163Sshin for (i = 0; i < nn; i++, np++) { 118855163Sshin rrt = rtsearch(np); 118955163Sshin if (rrt) 119055163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 119155163Sshin else 119255163Sshin np->rip6_metric = HOPCNT_INFINITY6; 119355163Sshin } 119455163Sshin (void)sendpacket(sin, RIPSIZE(nn)); 119555163Sshin return; 119655163Sshin } 119755163Sshin /* Whole routing table dump */ 119855163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 119955163Sshin ripsend(ifcp, sin, RTF_SENDANYWAY); 120055163Sshin} 120155163Sshin 120255163Sshin/* 120355163Sshin * Get information of each interface. 120455163Sshin */ 120555163Sshinvoid 120655163Sshinifconfig() 120755163Sshin{ 120855163Sshin int s, i; 120955163Sshin char *buf; 121055163Sshin struct ifconf ifconf; 121155163Sshin struct ifreq *ifrp, ifr; 121255163Sshin struct ifc *ifcp; 121355163Sshin struct ipv6_mreq mreq; 121455163Sshin int bufsiz; 121555163Sshin 121655163Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 121755163Sshin fatal("socket"); 121855163Sshin 121955163Sshin /* wild guess - v4, media, link, v6 * 3 */ 122055163Sshin bufsiz = if_maxindex() * sizeof(struct ifreq) * 6; 122155163Sshin if ((buf = (char *)malloc(bufsiz)) == NULL) 122255163Sshin fatal("malloc"); 122355163Sshin 122455163Sshin /* 122555163Sshin * ioctl(SIOCGIFCONF) does not return error on buffer size. 122655163Sshin * we'll try to guess the buffer size by trying it twice, with 122755163Sshin * different buffer size. 122855163Sshin */ 122955163Sshin ifconf.ifc_buf = buf; 123055163Sshin ifconf.ifc_len = bufsiz / 2; 123155163Sshin if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0) 123255163Sshin fatal("ioctl: SIOCGIFCONF"); 123355163Sshin i = ifconf.ifc_len; 123455163Sshin while (1) { 123555163Sshin ifconf.ifc_buf = buf; 123655163Sshin ifconf.ifc_len = bufsiz; 123755163Sshin if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0) 123855163Sshin fatal("ioctl: SIOCGIFCONF"); 123955163Sshin if (i == ifconf.ifc_len) 124055163Sshin break; 124155163Sshin i = ifconf.ifc_len; 124255163Sshin bufsiz *= 2; 124355163Sshin if ((buf = (char *)realloc(buf, bufsiz)) == NULL) 124455163Sshin fatal("realloc"); 124555163Sshin } 124655163Sshin for (i = 0; i < ifconf.ifc_len; ) { 124755163Sshin ifrp = (struct ifreq *)(buf + i); 124855163Sshin if (ifrp->ifr_addr.sa_family != AF_INET6) 124955163Sshin goto skip; 125055163Sshin ifcp = ifc_find(ifrp->ifr_name); 125155163Sshin strcpy(ifr.ifr_name, ifrp->ifr_name); 125255163Sshin if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0) 125355163Sshin fatal("ioctl: SIOCGIFFLAGS"); 125455163Sshin /* we are interested in multicast-capable interfaces */ 125555163Sshin if ((ifr.ifr_flags & IFF_MULTICAST) == 0) 125655163Sshin goto skip; 125755163Sshin if (!ifcp) { 125855163Sshin /* new interface */ 125955163Sshin ifcp = (struct ifc *)malloc(sizeof(*ifcp)); 126055163Sshin memset(ifcp, 0, sizeof(*ifcp)); 126155163Sshin ifcp->ifc_index = -1; 126255163Sshin ifcp->ifc_next = ifc; 126355163Sshin ifc = ifcp; 126455163Sshin nifc++; 126555163Sshin ifcp->ifc_name = allocopy(ifrp->ifr_name); 126655163Sshin ifcp->ifc_addr = 0; 126755163Sshin ifcp->ifc_filter = 0; 126855163Sshin ifcp->ifc_flags = ifr.ifr_flags; 126955163Sshin trace(1, "newif %s <%s>\n", ifcp->ifc_name, 127055163Sshin ifflags(ifcp->ifc_flags)); 127155163Sshin if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 127255163Sshin loopifcp = ifcp; 127355163Sshin } else { 127455163Sshin /* update flag, this may be up again */ 127555163Sshin if (ifcp->ifc_flags != ifr.ifr_flags) { 127655163Sshin trace(1, "%s: <%s> -> ", ifcp->ifc_name, 127755163Sshin ifflags(ifcp->ifc_flags)); 127855163Sshin trace(1, "<%s>\n", ifflags(ifr.ifr_flags)); 127955163Sshin } 128055163Sshin ifcp->ifc_flags = ifr.ifr_flags; 128155163Sshin } 128255163Sshin ifconfig1(ifrp, ifcp, s); 128355163Sshin if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 128455163Sshin && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 128555163Sshin mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 128655163Sshin mreq.ipv6mr_interface = ifcp->ifc_index; 128755163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, 128855163Sshin IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) 128955163Sshin fatal("IPV6_JOIN_GROUP"); 129055163Sshin trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 129155163Sshin ifcp->ifc_joined++; 129255163Sshin } 129355163Sshinskip: 129455163Sshin i += IFNAMSIZ; 129555163Sshin if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) 129655163Sshin i += ifrp->ifr_addr.sa_len; 129755163Sshin else 129855163Sshin i += sizeof(struct sockaddr); 129955163Sshin } 130055163Sshin close(s); 130155163Sshin free(buf); 130255163Sshin} 130355163Sshin 130455163Sshinvoid 130555163Sshinifconfig1(ifrp, ifcp, s) 130655163Sshin struct ifreq *ifrp; 130755163Sshin struct ifc *ifcp; 130855163Sshin int s; 130955163Sshin{ 131055163Sshin struct in6_ifreq ifr; 131155163Sshin struct sockaddr_in6 *sin; 131255163Sshin struct ifac *ifa; 131355163Sshin int plen; 131455163Sshin char buf[BUFSIZ]; 131555163Sshin 131655163Sshin sin = (struct sockaddr_in6 *)&ifrp->ifr_addr; 131755163Sshin ifr.ifr_addr = *sin; 131855163Sshin strcpy(ifr.ifr_name, ifrp->ifr_name); 131955163Sshin if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) 132055163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 132155163Sshin plen = mask2len(&ifr.ifr_addr.sin6_addr, 16); 132255163Sshin if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) { 132355163Sshin /* same interface found */ 132455163Sshin /* need check if something changed */ 132555163Sshin /* XXX not yet implemented */ 132655163Sshin return; 132755163Sshin } 132855163Sshin /* 132955163Sshin * New address is found 133055163Sshin */ 133155163Sshin if ((ifa = MALLOC(struct ifac)) == NULL) 133255163Sshin fatal("malloc: struct ifac"); 133355163Sshin ifa->ifa_conf = ifcp; 133455163Sshin ifa->ifa_next = ifcp->ifc_addr; 133555163Sshin ifcp->ifc_addr = ifa; 133655163Sshin ifa->ifa_addr = sin->sin6_addr; 133755163Sshin ifa->ifa_plen = plen; 133855163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 133955163Sshin ifr.ifr_addr = *sin; 134055163Sshin if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) 134155163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 134255163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 134355163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 134455163Sshin trace(1, "found address %s/%d -- %s\n", 134555163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 134655163Sshin } else { 134755163Sshin trace(1, "found address %s/%d\n", 134855163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 134955163Sshin } 135055163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 135155163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 135255163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 135355163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 135455163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 135555163Sshin ifcp->ifc_index); 135655163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 135755163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 135855163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 135955163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 136055163Sshin if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) 136155163Sshin fatal("ioctl: SIOCGIFMETRIC"); 136255163Sshin ifcp->ifc_metric = ifr.ifr_metric; 136355163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 136455163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 136555163Sshin } 136655163Sshin} 136755163Sshin 136855163Sshin/* 136955163Sshin * Receive and process routing messages. 137055163Sshin * Update interface information as necesssary. 137155163Sshin */ 137255163Sshinvoid 137355163Sshinrtrecv() 137455163Sshin{ 137555163Sshin char buf[BUFSIZ]; 137655163Sshin char *p, *q; 137755163Sshin struct rt_msghdr *rtm; 137855163Sshin struct ifa_msghdr *ifam; 137955163Sshin struct if_msghdr *ifm; 138055163Sshin int len; 138155163Sshin struct ifc *ifcp; 138255163Sshin int iface = 0, rtable = 0; 138355163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 138455163Sshin int i, addrs; 138555163Sshin 138655163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 138755163Sshin perror("read from rtsock"); 138855163Sshin exit(-1); 138955163Sshin } 139055163Sshin if (len < sizeof(*rtm)) { 139155163Sshin trace(1, "short read from rtsock: %d (should be > %d)\n", 139255163Sshin len, sizeof(*rtm)); 139355163Sshin return; 139455163Sshin } 139555163Sshin 139655163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 139755163Sshin /* safety against bogus message */ 139855163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 139955163Sshin trace(1, "bogus rtmsg: length=%d\n", 140055163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 140155163Sshin break; 140255163Sshin } 140355163Sshin rtm = NULL; 140455163Sshin ifam = NULL; 140555163Sshin ifm = NULL; 140655163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 140755163Sshin case RTM_NEWADDR: 140855163Sshin case RTM_DELADDR: 140955163Sshin ifam = (struct ifa_msghdr *)p; 141055163Sshin addrs = ifam->ifam_addrs; 141155163Sshin q = (char *)(ifam + 1); 141255163Sshin break; 141355163Sshin case RTM_IFINFO: 141455163Sshin ifm = (struct if_msghdr *)p; 141555163Sshin addrs = ifm->ifm_addrs; 141655163Sshin q = (char *)(ifm + 1); 141755163Sshin break; 141855163Sshin default: 141955163Sshin rtm = (struct rt_msghdr *)p; 142055163Sshin addrs = rtm->rtm_addrs; 142155163Sshin q = (char *)(rtm + 1); 142255163Sshin if (rtm->rtm_version != RTM_VERSION) { 142355163Sshin trace(1, "unexpected rtmsg version %d " 142455163Sshin "(should be %d)\n", 142555163Sshin rtm->rtm_version, RTM_VERSION); 142655163Sshin continue; 142755163Sshin } 142855163Sshin if (rtm->rtm_pid == pid) { 142955163Sshin#if 0 143055163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 143155163Sshin#endif 143255163Sshin continue; 143355163Sshin } 143455163Sshin break; 143555163Sshin } 143655163Sshin memset(&rta, 0, sizeof(rta)); 143755163Sshin for (i = 0; i < RTAX_MAX; i++) { 143855163Sshin if (addrs & (1 << i)) { 143955163Sshin rta[i] = (struct sockaddr_in6 *)q; 144055163Sshin q += ROUNDUP(rta[i]->sin6_len); 144155163Sshin } 144255163Sshin } 144355163Sshin 144455163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 144555163Sshin rttypes((struct rt_msghdr *)p), addrs); 144655163Sshin if (dflag >= 2) { 144755163Sshin int i; 144855163Sshin for (i = 0; 144955163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 145055163Sshin i++) { 145155163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 145255163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 145355163Sshin } 145455163Sshin fprintf(stderr, "\n"); 145555163Sshin } 145655163Sshin 145755163Sshin /* 145855163Sshin * Easy ones first. 145955163Sshin * 146055163Sshin * We may be able to optimize by using ifm->ifm_index or 146155163Sshin * ifam->ifam_index. For simplicity we don't do that here. 146255163Sshin */ 146355163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 146455163Sshin case RTM_NEWADDR: 146555163Sshin case RTM_IFINFO: 146655163Sshin iface++; 146755163Sshin continue; 146855163Sshin case RTM_ADD: 146955163Sshin rtable++; 147055163Sshin continue; 147155163Sshin case RTM_LOSING: 147255163Sshin case RTM_MISS: 147355163Sshin case RTM_RESOLVE: 147455163Sshin case RTM_GET: 147555163Sshin case RTM_LOCK: 147655163Sshin /* nothing to be done here */ 147755163Sshin trace(1, "\tnothing to be done, ignored\n"); 147855163Sshin continue; 147955163Sshin } 148055163Sshin 148155163Sshin#if 0 148255163Sshin if (rta[RTAX_DST] == NULL) { 148355163Sshin trace(1, "\tno destination, ignored\n"); 148455163Sshin continue; 148555163Sshin } 148655163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 148755163Sshin trace(1, "\taf mismatch, ignored\n"); 148855163Sshin continue; 148955163Sshin } 149055163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 149155163Sshin trace(1, "\tlinklocal destination, ignored\n"); 149255163Sshin continue; 149355163Sshin } 149455163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 149555163Sshin trace(1, "\tloopback destination, ignored\n"); 149655163Sshin continue; /* Loopback */ 149755163Sshin } 149855163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 149955163Sshin trace(1, "\tmulticast destination, ignored\n"); 150055163Sshin continue; 150155163Sshin } 150255163Sshin#endif 150355163Sshin 150455163Sshin /* hard ones */ 150555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 150655163Sshin case RTM_NEWADDR: 150755163Sshin case RTM_IFINFO: 150855163Sshin case RTM_ADD: 150955163Sshin case RTM_LOSING: 151055163Sshin case RTM_MISS: 151155163Sshin case RTM_RESOLVE: 151255163Sshin case RTM_GET: 151355163Sshin case RTM_LOCK: 151455163Sshin /* should already be handled */ 151555163Sshin fatal("rtrecv: never reach here"); 151655163Sshin case RTM_DELETE: 151755163Sshin if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY] 151855163Sshin || !rta[RTAX_NETMASK]) { 151955163Sshin trace(1, "\tsome of dst/gw/netamsk are unavailable, ignored\n"); 152055163Sshin break; 152155163Sshin } 152255163Sshin if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], rta[RTAX_NETMASK]) == 0) { 152355163Sshin rtable++; /*just to be sure*/ 152455163Sshin } 152555163Sshin break; 152655163Sshin case RTM_CHANGE: 152755163Sshin case RTM_REDIRECT: 152855163Sshin trace(1, "\tnot supported yet, ignored\n"); 152955163Sshin break; 153055163Sshin case RTM_DELADDR: 153155163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 153255163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 153355163Sshin break; 153455163Sshin } 153555163Sshin if (ifam->ifam_index < nindex2ifc) 153655163Sshin ifcp = index2ifc[ifam->ifam_index]; 153755163Sshin else 153855163Sshin ifcp = NULL; 153955163Sshin if (!ifcp) { 154055163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 154155163Sshin ifam->ifam_index); 154255163Sshin break; 154355163Sshin } 154455163Sshin rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]); 154555163Sshin iface++; 154655163Sshin break; 154755163Sshin case RTM_OLDADD: 154855163Sshin case RTM_OLDDEL: 154955163Sshin trace(1, "\tnot supported yet, ignored\n"); 155055163Sshin break; 155155163Sshin } 155255163Sshin 155355163Sshin } 155455163Sshin 155555163Sshin if (iface) { 155655163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 155755163Sshin ifconfig(); 155855163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 155955163Sshin ifrt(ifcp, 1); 156055163Sshin } 156155163Sshin if (rtable) { 156255163Sshin trace(1, "rtsock: read routing table again\n"); 156355163Sshin krtread(1); 156455163Sshin } 156555163Sshin} 156655163Sshin 156755163Sshin/* 156855163Sshin * remove specified route from the internal routing table. 156955163Sshin */ 157055163Sshinint 157155163Sshinrt_del(sdst, sgw, smask) 157255163Sshin const struct sockaddr_in6 *sdst; 157355163Sshin const struct sockaddr_in6 *sgw; 157455163Sshin const struct sockaddr_in6 *smask; 157555163Sshin{ 157655163Sshin const struct in6_addr *dst = NULL; 157755163Sshin const struct in6_addr *gw = NULL; 157855163Sshin int prefix; 157955163Sshin struct netinfo6 ni6; 158055163Sshin struct riprt *rrt = NULL; 158155163Sshin time_t t_lifetime; 158255163Sshin 158355163Sshin if (sdst->sin6_family != AF_INET6) { 158455163Sshin trace(1, "\tother AF, ignored\n"); 158555163Sshin return -1; 158655163Sshin } 158755163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 158855163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 158955163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 159055163Sshin trace(1, "\taddress %s not interesting, ignored\n", 159155163Sshin inet6_n2p(&sdst->sin6_addr)); 159255163Sshin return -1; 159355163Sshin } 159455163Sshin dst = &sdst->sin6_addr; 159555163Sshin if (sgw->sin6_family == AF_INET6 159655163Sshin && smask->sin6_family == AF_INET6) { 159755163Sshin /* easy case */ 159855163Sshin gw = &sgw->sin6_addr; 159955163Sshin prefix = mask2len(&smask->sin6_addr, 16); 160055163Sshin } else if (sgw->sin6_family == AF_LINK) { 160155163Sshin /* 160255163Sshin * Interface route... a hard case. We need to get the prefix 160355163Sshin * length from the kernel, but we now are parsing rtmsg. 160455163Sshin * We'll purge matching routes from my list, then get the 160555163Sshin * fresh list. 160655163Sshin */ 160755163Sshin struct riprt *longest; 160855163Sshin trace(1, "\t%s is a interface route, guessing prefixlen\n", 160955163Sshin inet6_n2p(dst)); 161055163Sshin longest = NULL; 161155163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 161255163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 161355163Sshin &sdst->sin6_addr) 161455163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 161555163Sshin if (!longest 161655163Sshin || longest->rrt_info.rip6_plen < 161755163Sshin rrt->rrt_info.rip6_plen) { 161855163Sshin longest = rrt; 161955163Sshin } 162055163Sshin } 162155163Sshin } 162255163Sshin rrt = longest; 162355163Sshin if (!rrt) { 162455163Sshin trace(1, "\tno matching interface route found\n"); 162555163Sshin return -1; 162655163Sshin } 162755163Sshin gw = &in6addr_loopback; 162855163Sshin prefix = rrt->rrt_info.rip6_plen; 162955163Sshin } else { 163055163Sshin trace(1, "\tunsupported af: (gw=%d, mask=%d)\n", 163155163Sshin sgw->sin6_family, smask->sin6_family); 163255163Sshin return -1; 163355163Sshin } 163455163Sshin 163555163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 163655163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 163755163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 163855163Sshin /* age route for interface address */ 163955163Sshin memset(&ni6, 0, sizeof(ni6)); 164055163Sshin ni6.rip6_dest = *dst; 164155163Sshin ni6.rip6_plen = prefix; 164255163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 164355163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 164455163Sshin ni6.rip6_plen); 164555163Sshin if (!rrt && (rrt = rtsearch(&ni6)) == NULL) { 164655163Sshin trace(1, "\tno route found\n"); 164755163Sshin return -1; 164855163Sshin } 164955163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 165055163Sshin trace(1, "\tyou can delete static routes only\n"); 165155163Sshin } else if (memcmp(&rrt->rrt_gw, gw, sizeof(rrt->rrt_gw)) != 0) { 165255163Sshin trace(1, "\tgw mismatch: %s <-> ", 165355163Sshin inet6_n2p(&rrt->rrt_gw)); 165455163Sshin trace(1, "%s\n", inet6_n2p(gw)); 165555163Sshin } else { 165655163Sshin trace(1, "\troute found, age it\n"); 165755163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 165855163Sshin rrt->rrt_t = t_lifetime; 165955163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 166055163Sshin } 166155163Sshin } 166255163Sshin return 0; 166355163Sshin} 166455163Sshin 166555163Sshin/* 166655163Sshin * remove specified address from internal interface/routing table. 166755163Sshin */ 166855163Sshinint 166955163Sshinrt_deladdr(ifcp, sifa, smask) 167055163Sshin struct ifc *ifcp; 167155163Sshin const struct sockaddr_in6 *sifa; 167255163Sshin const struct sockaddr_in6 *smask; 167355163Sshin{ 167455163Sshin const struct in6_addr *addr = NULL; 167555163Sshin int prefix; 167655163Sshin struct ifac *ifa = NULL; 167755163Sshin struct netinfo6 ni6; 167855163Sshin struct riprt *rrt = NULL; 167955163Sshin time_t t_lifetime; 168055163Sshin int updated = 0; 168155163Sshin 168255163Sshin if (sifa->sin6_family != AF_INET6 || smask->sin6_family != AF_INET6) { 168355163Sshin trace(1, "\tother AF, ignored\n"); 168455163Sshin return -1; 168555163Sshin } 168655163Sshin addr = &sifa->sin6_addr; 168755163Sshin prefix = mask2len(&smask->sin6_addr, 16); 168855163Sshin 168955163Sshin trace(1, "\tdeleting %s/%d from %s\n", 169055163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 169155163Sshin ifa = ifa_match(ifcp, addr, prefix); 169255163Sshin if (!ifa) { 169355163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 169455163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 169555163Sshin return -1; 169655163Sshin } 169755163Sshin if (ifa->ifa_conf != ifcp) { 169855163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 169955163Sshin "(%s != %s)\n", 170055163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 170155163Sshin return -1; 170255163Sshin } 170355163Sshin /* remove ifa from interface */ 170455163Sshin if (ifcp->ifc_addr == ifa) 170555163Sshin ifcp->ifc_addr = ifa->ifa_next; 170655163Sshin else { 170755163Sshin struct ifac *p; 170855163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 170955163Sshin if (p->ifa_next == ifa) { 171055163Sshin p->ifa_next = ifa->ifa_next; 171155163Sshin break; 171255163Sshin } 171355163Sshin } 171455163Sshin } 171555163Sshin ifa->ifa_next = NULL; 171655163Sshin ifa->ifa_conf = NULL; 171755163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 171855163Sshin /* age route for interface address */ 171955163Sshin memset(&ni6, 0, sizeof(ni6)); 172055163Sshin ni6.rip6_dest = ifa->ifa_addr; 172155163Sshin ni6.rip6_plen = ifa->ifa_plen; 172255163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 172355163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 172455163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 172555163Sshin if ((rrt = rtsearch(&ni6)) != NULL) { 172655163Sshin struct in6_addr none; 172755163Sshin memset(&none, 0, sizeof(none)); 172855163Sshin if (rrt->rrt_index == ifcp->ifc_index 172955163Sshin && memcmp(&rrt->rrt_gw, &none, sizeof(rrt->rrt_gw)) == 0) { 173055163Sshin trace(1, "\troute found, age it\n"); 173155163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 173255163Sshin rrt->rrt_t = t_lifetime; 173355163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 173455163Sshin } 173555163Sshin updated++; 173655163Sshin } else { 173755163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 173855163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 173955163Sshin rrt->rrt_info.rip6_plen, 174055163Sshin rrt->rrt_index); 174155163Sshin } 174255163Sshin } else 174355163Sshin trace(1, "\tno interface route found\n"); 174455163Sshin /* age route for p2p destination */ 174555163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 174655163Sshin memset(&ni6, 0, sizeof(ni6)); 174755163Sshin ni6.rip6_dest = ifa->ifa_raddr; 174855163Sshin ni6.rip6_plen = 128; 174955163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 175055163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 175155163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 175255163Sshin ifcp->ifc_index); 175355163Sshin if ((rrt = rtsearch(&ni6)) != NULL) { 175455163Sshin if (rrt->rrt_index == ifcp->ifc_index 175555163Sshin && memcmp(&rrt->rrt_gw, &ifa->ifa_addr, 175655163Sshin sizeof(rrt->rrt_gw)) == 0) { 175755163Sshin trace(1, "\troute found, age it\n"); 175855163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 175955163Sshin rrt->rrt_t = t_lifetime; 176055163Sshin rrt->rrt_info.rip6_metric = 176155163Sshin HOPCNT_INFINITY6; 176255163Sshin updated++; 176355163Sshin } 176455163Sshin } else { 176555163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 176655163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 176755163Sshin rrt->rrt_info.rip6_plen, 176855163Sshin rrt->rrt_index); 176955163Sshin } 177055163Sshin } else 177155163Sshin trace(1, "\tno p2p route found\n"); 177255163Sshin } 177355163Sshin return updated ? 0 : -1; 177455163Sshin} 177555163Sshin 177655163Sshin/* 177755163Sshin * Get each interface address and put those interface routes to the route 177855163Sshin * list. 177955163Sshin */ 178055163Sshinvoid 178155163Sshinifrt(ifcp, again) 178255163Sshin struct ifc *ifcp; 178355163Sshin int again; 178455163Sshin{ 178555163Sshin struct ifac *ifa; 178655163Sshin struct riprt *rrt; 178755163Sshin struct netinfo6 *np; 178855163Sshin 178955163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 179055163Sshin return; /* ignore loopback */ 179155163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 179255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) 179355163Sshin continue; /* don't advertise link local addr */ 179455163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 179555163Sshin fatal("malloc: struct riprt"); 179655163Sshin rrt->rrt_same = NULL; 179755163Sshin rrt->rrt_index = ifcp->ifc_index; 179855163Sshin rrt->rrt_t = 0; /* don't age */ 179955163Sshin rrt->rrt_info.rip6_dest = ifa->ifa_addr; 180055163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 180155163Sshin rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 180255163Sshin rrt->rrt_info.rip6_plen = ifa->ifa_plen; 180355163Sshin applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 180455163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 180555163Sshin np = &rrt->rrt_info; 180655163Sshin if (rtsearch(np) == NULL) { 180755163Sshin /* Attach the route to the list */ 180855163Sshin rrt->rrt_next = riprt; 180955163Sshin riprt = rrt; 181055163Sshin } else { 181155163Sshin /* Already found */ 181255163Sshin if (!again) { 181355163Sshin trace(1, "route: %s/%d: already registered\n", 181455163Sshin inet6_n2p(&np->rip6_dest), 181555163Sshin np->rip6_plen); 181655163Sshin } 181755163Sshin free(rrt); 181855163Sshin } 181955163Sshin 182055163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 182155163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 182255163Sshin fatal("malloc: struct riprt"); 182355163Sshin rrt->rrt_same = NULL; 182455163Sshin rrt->rrt_index = ifcp->ifc_index; 182555163Sshin rrt->rrt_t = 0; /* Don't age */ 182655163Sshin rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 182755163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 182855163Sshin rrt->rrt_info.rip6_metric = 1; 182955163Sshin rrt->rrt_info.rip6_plen = 128; 183055163Sshin rrt->rrt_gw = ifa->ifa_addr; 183155163Sshin rrt->rrt_flags |= RTF_NOADVERTISE; 183255163Sshin np = &rrt->rrt_info; 183355163Sshin if (rtsearch(np) == NULL) { 183455163Sshin /* Attach the route to the list */ 183555163Sshin rrt->rrt_next = riprt; 183655163Sshin riprt = rrt; 183755163Sshin } else { 183855163Sshin /* Already found */ 183955163Sshin if (!again) { 184055163Sshin trace(1, "route: %s/%d: already registered\n", 184155163Sshin inet6_n2p(&np->rip6_dest), 184255163Sshin np->rip6_plen); 184355163Sshin } 184455163Sshin free(rrt); 184555163Sshin } 184655163Sshin } 184755163Sshin } 184855163Sshin} 184955163Sshin 185055163Sshinint 185155163Sshingetifmtu(ifindex) 185255163Sshin int ifindex; 185355163Sshin{ 185455163Sshin int mib[6]; 185555163Sshin char *buf; 185655163Sshin size_t msize; 185755163Sshin struct if_msghdr *ifm; 185855163Sshin int mtu; 185955163Sshin 186055163Sshin mib[0] = CTL_NET; 186155163Sshin mib[1] = PF_ROUTE; 186255163Sshin mib[2] = 0; 186355163Sshin mib[3] = AF_INET6; 186455163Sshin mib[4] = NET_RT_IFLIST; 186555163Sshin mib[5] = ifindex; 186655163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) 186755163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 186855163Sshin if ((buf = malloc(msize)) == NULL) 186955163Sshin fatal("malloc"); 187055163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) 187155163Sshin fatal("sysctl NET_RT_IFLIST"); 187255163Sshin ifm = (struct if_msghdr *)buf; 187355163Sshin mtu = ifm->ifm_data.ifi_mtu; 187455163Sshin#ifdef __FREEBSD__ 187555163Sshin if (ifindex != ifm->ifm_index) 187655163Sshin fatal("ifindex does not match with ifm_index"); 187755163Sshin#endif /* __FREEBSD__ */ 187855163Sshin free(buf); 187955163Sshin return mtu; 188055163Sshin} 188155163Sshin 188255163Sshinconst char * 188355163Sshinrttypes(rtm) 188455163Sshin struct rt_msghdr *rtm; 188555163Sshin{ 188655163Sshin#define RTTYPE(s, f) if (rtm->rtm_type == (f)) return (s) 188755163Sshin RTTYPE("ADD", RTM_ADD); 188855163Sshin RTTYPE("DELETE", RTM_DELETE); 188955163Sshin RTTYPE("CHANGE", RTM_CHANGE); 189055163Sshin RTTYPE("GET", RTM_GET); 189155163Sshin RTTYPE("LOSING", RTM_LOSING); 189255163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 189355163Sshin RTTYPE("MISS", RTM_MISS); 189455163Sshin RTTYPE("LOCK", RTM_LOCK); 189555163Sshin RTTYPE("OLDADD", RTM_OLDADD); 189655163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 189755163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 189855163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 189955163Sshin RTTYPE("DELADDR", RTM_DELADDR); 190055163Sshin RTTYPE("IFINFO", RTM_IFINFO); 190155163Sshin#undef RTTYPE 190255163Sshin return NULL; 190355163Sshin} 190455163Sshin 190555163Sshinconst char * 190655163Sshinrtflags(rtm) 190755163Sshin struct rt_msghdr *rtm; 190855163Sshin{ 190955163Sshin static char buf[BUFSIZ]; 191055163Sshin 191155163Sshin strcpy(buf, ""); 191255163Sshin#define RTFLAG(s, f) if (rtm->rtm_flags & (f)) strcat(buf, (s)) 191355163Sshin RTFLAG("U", RTF_UP); 191455163Sshin RTFLAG("G", RTF_GATEWAY); 191555163Sshin RTFLAG("H", RTF_HOST); 191655163Sshin RTFLAG("R", RTF_REJECT); 191755163Sshin RTFLAG("D", RTF_DYNAMIC); 191855163Sshin RTFLAG("M", RTF_MODIFIED); 191955163Sshin RTFLAG("d", RTF_DONE); 192055163Sshin#ifdef RTF_MASK 192155163Sshin RTFLAG("m", RTF_MASK); 192255163Sshin#endif 192355163Sshin RTFLAG("C", RTF_CLONING); 192455163Sshin RTFLAG("X", RTF_XRESOLVE); 192555163Sshin RTFLAG("L", RTF_LLINFO); 192655163Sshin RTFLAG("S", RTF_STATIC); 192755163Sshin RTFLAG("B", RTF_BLACKHOLE); 192855163Sshin RTFLAG("2", RTF_PROTO2); 192955163Sshin RTFLAG("1", RTF_PROTO1); 193055163Sshin#undef RTFLAG 193155163Sshin return buf; 193255163Sshin} 193355163Sshin 193455163Sshinconst char * 193555163Sshinifflags(flags) 193655163Sshin int flags; 193755163Sshin{ 193855163Sshin static char buf[BUFSIZ]; 193955163Sshin 194055163Sshin strcpy(buf, ""); 194155163Sshin#define IFFLAG(s, f) \ 194255163Sshin if (flags & f) { if (buf[0]) strcat(buf, ","); strcat(buf, s); } 194355163Sshin IFFLAG("UP", IFF_UP); 194455163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 194555163Sshin IFFLAG("DEBUG", IFF_DEBUG); 194655163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 194755163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 194855163Sshin#ifdef IFF_NOTRAILERS 194955163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 195055163Sshin#endif 195155163Sshin IFFLAG("RUNNING", IFF_RUNNING); 195255163Sshin IFFLAG("NOARP", IFF_NOARP); 195355163Sshin IFFLAG("PROMISC", IFF_PROMISC); 195455163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 195555163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 195655163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 195755163Sshin IFFLAG("LINK0", IFF_LINK0); 195855163Sshin IFFLAG("LINK1", IFF_LINK1); 195955163Sshin IFFLAG("LINK2", IFF_LINK2); 196055163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 196155163Sshin#undef IFFLAG 196255163Sshin return buf; 196355163Sshin} 196455163Sshin 196555163Sshinvoid 196655163Sshinkrtread(again) 196755163Sshin int again; 196855163Sshin{ 196955163Sshin int mib[6]; 197055163Sshin size_t msize; 197155163Sshin char *buf, *p, *lim; 197255163Sshin struct rt_msghdr *rtm; 197355163Sshin int retry; 197455163Sshin const char *errmsg; 197555163Sshin 197655163Sshin retry = 0; 197755163Sshin buf = NULL; 197855163Sshin mib[0] = CTL_NET; 197955163Sshin mib[1] = PF_ROUTE; 198055163Sshin mib[2] = 0; 198155163Sshin mib[3] = AF_INET6; /* Address family */ 198255163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 198355163Sshin mib[5] = 0; /* No flags */ 198455163Sshin do { 198555163Sshin retry++; 198655163Sshin errmsg = NULL; 198755163Sshin if (buf) 198855163Sshin free(buf); 198955163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 199055163Sshin errmsg = "sysctl estimate"; 199155163Sshin continue; 199255163Sshin } 199355163Sshin if ((buf = malloc(msize)) == NULL) { 199455163Sshin errmsg = "malloc"; 199555163Sshin continue; 199655163Sshin } 199755163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 199855163Sshin errmsg = "sysctl NET_RT_DUMP"; 199955163Sshin continue; 200055163Sshin } 200155163Sshin } while (retry < 5 && errmsg != NULL); 200255163Sshin if (errmsg) 200355163Sshin fatal("%s (with %d retries, msize=%d)", errmsg, retry, msize); 200455163Sshin else if (1 < retry) 200555163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 200655163Sshin 200755163Sshin lim = buf + msize; 200855163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 200955163Sshin rtm = (struct rt_msghdr *)p; 201055163Sshin rt_entry(rtm, again); 201155163Sshin } 201255163Sshin free(buf); 201355163Sshin} 201455163Sshin 201555163Sshinvoid 201655163Sshinrt_entry(rtm, again) 201755163Sshin struct rt_msghdr *rtm; 201855163Sshin int again; 201955163Sshin{ 202055163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 202155163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 202255163Sshin char *rtmp, *ifname = NULL; 202355163Sshin char buf[BUFSIZ]; 202455163Sshin struct riprt *rrt; 202555163Sshin struct netinfo6 *np; 202655163Sshin int s; 202755163Sshin 202855163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 202955163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 203055163Sshin (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) 203155163Sshin return; /* not interested in the link route */ 203255163Sshin rtmp = (char *)(rtm + 1); 203355163Sshin /* Destination */ 203455163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 203555163Sshin return; /* ignore routes without destination address */ 203655163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 203755163Sshin rtmp += sin6_dst->sin6_len; 203855163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 203955163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 204055163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 204155163Sshin } 204255163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 204355163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 204455163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 204555163Sshin } 204655163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 204755163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 204855163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 204955163Sshin } 205055163Sshin if (rtm->rtm_addrs & RTA_IFP) { 205155163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 205255163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 205355163Sshin } 205455163Sshin 205555163Sshin /* Destination */ 205655163Sshin if (sin6_dst->sin6_family != AF_INET6) 205755163Sshin return; 205855163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 205955163Sshin return; /* Link-local */ 206055163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 206155163Sshin return; /* Loopback */ 206255163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 206355163Sshin return; 206455163Sshin 206555163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 206655163Sshin fatal("malloc: struct riprt"); 206755163Sshin np = &rrt->rrt_info; 206855163Sshin rrt->rrt_same = NULL; 206955163Sshin rrt->rrt_t = time(NULL); 207055163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 207155163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 207255163Sshin#if 0 207355163Sshin np->rip6_tag = htons(routetag & 0xffff); 207455163Sshin#else 207555163Sshin np->rip6_tag = 0; 207655163Sshin#endif 207755163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 207855163Sshin if (np->rip6_metric < 1) 207955163Sshin np->rip6_metric = 1; 208055163Sshin rrt->rrt_flags = rtm->rtm_flags; 208155163Sshin np->rip6_dest = sin6_dst->sin6_addr; 208255163Sshin 208355163Sshin /* Mask or plen */ 208455163Sshin if (rtm->rtm_flags & RTF_HOST) 208555163Sshin np->rip6_plen = 128; /* Host route */ 208655163Sshin else if (sin6_mask) { 208755163Sshin np->rip6_plen = mask2len(&sin6_mask->sin6_addr, 208855163Sshin sin6_mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 208955163Sshin } else 209055163Sshin np->rip6_plen = 0; 209155163Sshin 209255163Sshin if (rtsearch(np)) { 209355163Sshin /* Already found */ 209455163Sshin if (!again) { 209555163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 209655163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 209755163Sshin rtflags(rtm)); 209855163Sshin } 209955163Sshin free(rrt); 210055163Sshin return; 210155163Sshin } 210255163Sshin /* Gateway */ 210355163Sshin if (!sin6_gw) 210455163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 210555163Sshin else { 210655163Sshin if (sin6_gw->sin6_family == AF_INET6) 210755163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 210855163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 210955163Sshin /* XXX in case ppp link? */ 211055163Sshin rrt->rrt_gw = in6addr_loopback; 211155163Sshin } else 211255163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 211355163Sshin } 211455163Sshin trace(1, "route: %s/%d flags %s", 211555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 211655163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 211755163Sshin 211855163Sshin /* Interface */ 211955163Sshin s = rtm->rtm_index; 212055163Sshin if (s < nindex2ifc && index2ifc[s]) 212155163Sshin ifname = index2ifc[s]->ifc_name; 212255163Sshin else 212355163Sshin fatal("Unknown interface %d", s); 212455163Sshin trace(1, " if %s sock %d\n", ifname, s); 212555163Sshin rrt->rrt_index = s; 212655163Sshin 212755163Sshin /* Check gateway */ 212855163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 212955163Sshin !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 213055163Sshin#ifdef __FreeBSD__ 213155163Sshin && (rrt->rrt_flags & RTF_LOCAL) == 0 213255163Sshin#endif 213355163Sshin ) { 213455163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 213555163Sshin buf, sizeof(buf)); 213655163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 213755163Sshin inet6_n2p(&rrt->rrt_gw)); 213855163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 213955163Sshin buf, ifname); 214055163Sshin rrt->rrt_flags |= RTF_NH_NOT_LLADDR; 214155163Sshin } 214255163Sshin 214355163Sshin /* Put it to the route list */ 214455163Sshin rrt->rrt_next = riprt; 214555163Sshin riprt = rrt; 214655163Sshin} 214755163Sshin 214855163Sshinint 214955163Sshinaddroute(rrt, gw, ifcp) 215055163Sshin struct riprt *rrt; 215155163Sshin const struct in6_addr *gw; 215255163Sshin struct ifc *ifcp; 215355163Sshin{ 215455163Sshin struct netinfo6 *np; 215555163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 215655163Sshin struct rt_msghdr *rtm; 215755163Sshin struct sockaddr_in6 *sin; 215855163Sshin int len; 215955163Sshin 216055163Sshin np = &rrt->rrt_info; 216155163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf1, sizeof(buf1)); 216255163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 216355163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 216455163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 216555163Sshin np->rip6_metric - 1, buf2); 216655163Sshin if (rtlog) 216755163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 216855163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 216955163Sshin np->rip6_metric - 1, buf2); 217055163Sshin if (nflag) 217155163Sshin return 0; 217255163Sshin 217355163Sshin memset(buf, 0, sizeof(buf)); 217455163Sshin rtm = (struct rt_msghdr *)buf; 217555163Sshin rtm->rtm_type = RTM_ADD; 217655163Sshin rtm->rtm_version = RTM_VERSION; 217755163Sshin rtm->rtm_seq = ++seq; 217855163Sshin rtm->rtm_pid = pid; 217955163Sshin rtm->rtm_flags = rrt->rrt_flags & RTF_ROUTE_H; 218055163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 218155163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 218255163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 218355163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 218455163Sshin /* Destination */ 218555163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 218655163Sshin sin->sin6_family = AF_INET6; 218755163Sshin sin->sin6_addr = np->rip6_dest; 218855163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 218955163Sshin /* Gateway */ 219055163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 219155163Sshin sin->sin6_family = AF_INET6; 219255163Sshin sin->sin6_addr = *gw; 219355163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 219455163Sshin /* Netmask */ 219555163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 219655163Sshin sin->sin6_family = AF_INET6; 219755163Sshin sin->sin6_addr = *(plen2mask(np->rip6_plen)); 219855163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 219955163Sshin 220055163Sshin len = (char *)sin - (char *)buf; 220155163Sshin rtm->rtm_msglen = len; 220255163Sshin if (write(rtsock, buf, len) > 0) 220355163Sshin return 0; 220455163Sshin 220555163Sshin if (errno == EEXIST) { 220655163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 220755163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 220855163Sshin if (rtlog) 220955163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 221055163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 221155163Sshin } else { 221255163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 221355163Sshin strerror(errno)); 221455163Sshin if (rtlog) 221555163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 221655163Sshin strerror(errno)); 221755163Sshin } 221855163Sshin return -1; 221955163Sshin} 222055163Sshin 222155163Sshinint 222255163Sshindelroute(np, gw) 222355163Sshin struct netinfo6 *np; 222455163Sshin struct in6_addr *gw; 222555163Sshin{ 222655163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 222755163Sshin struct rt_msghdr *rtm; 222855163Sshin struct sockaddr_in6 *sin; 222955163Sshin int len; 223055163Sshin 223155163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 223255163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 223355163Sshin np->rip6_plen, buf2); 223455163Sshin if (rtlog) 223555163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 223655163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 223755163Sshin if (nflag) 223855163Sshin return 0; 223955163Sshin 224055163Sshin memset(buf, 0, sizeof(buf)); 224155163Sshin rtm = (struct rt_msghdr *)buf; 224255163Sshin rtm->rtm_type = RTM_DELETE; 224355163Sshin rtm->rtm_version = RTM_VERSION; 224455163Sshin rtm->rtm_seq = ++seq; 224555163Sshin rtm->rtm_pid = pid; 224655163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 224755163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 224855163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 224955163Sshin /* Destination */ 225055163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 225155163Sshin sin->sin6_family = AF_INET6; 225255163Sshin sin->sin6_addr = np->rip6_dest; 225355163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 225455163Sshin /* Gateway */ 225555163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 225655163Sshin sin->sin6_family = AF_INET6; 225755163Sshin sin->sin6_addr = *gw; 225855163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 225955163Sshin /* Netmask */ 226055163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 226155163Sshin sin->sin6_family = AF_INET6; 226255163Sshin sin->sin6_addr = *(plen2mask(np->rip6_plen)); 226355163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 226455163Sshin 226555163Sshin len = (char *)sin - (char *)buf; 226655163Sshin rtm->rtm_msglen = len; 226755163Sshin if (write(rtsock, buf, len) >= 0) 226855163Sshin return 0; 226955163Sshin 227055163Sshin if (errno == ESRCH) { 227155163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 227255163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 227355163Sshin if (rtlog) 227455163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 227555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 227655163Sshin } else { 227755163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 227855163Sshin strerror(errno)); 227955163Sshin if (rtlog) 228055163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 228155163Sshin strerror(errno)); 228255163Sshin } 228355163Sshin return -1; 228455163Sshin} 228555163Sshin 228655163Sshinstruct in6_addr * 228755163Sshingetroute(np, gw) 228855163Sshin struct netinfo6 *np; 228955163Sshin struct in6_addr *gw; 229055163Sshin{ 229155163Sshin u_char buf[BUFSIZ]; 229255163Sshin u_long myseq; 229355163Sshin int len; 229455163Sshin struct rt_msghdr *rtm; 229555163Sshin struct sockaddr_in6 *sin; 229655163Sshin 229755163Sshin rtm = (struct rt_msghdr *)buf; 229855163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 229955163Sshin memset(rtm, 0, len); 230055163Sshin rtm->rtm_type = RTM_GET; 230155163Sshin rtm->rtm_version = RTM_VERSION; 230255163Sshin myseq = ++seq; 230355163Sshin rtm->rtm_seq = myseq; 230455163Sshin rtm->rtm_addrs = RTA_DST; 230555163Sshin rtm->rtm_msglen = len; 230655163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 230755163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 230855163Sshin sin->sin6_family = AF_INET6; 230955163Sshin sin->sin6_addr = np->rip6_dest; 231055163Sshin if (write(rtsock, buf, len) < 0) { 231155163Sshin if (errno == ESRCH) /* No such route found */ 231255163Sshin return NULL; 231355163Sshin perror("write to rtsock"); 231455163Sshin exit(-1); 231555163Sshin } 231655163Sshin do { 231755163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 231855163Sshin perror("read from rtsock"); 231955163Sshin exit(-1); 232055163Sshin } 232155163Sshin rtm = (struct rt_msghdr *)buf; 232255163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 232355163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 232455163Sshin if (rtm->rtm_addrs & RTA_DST) { 232555163Sshin sin = (struct sockaddr_in6 *) 232655163Sshin ((char *)sin + ROUNDUP(sin->sin6_len)); 232755163Sshin } 232855163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 232955163Sshin *gw = sin->sin6_addr; 233055163Sshin return gw; 233155163Sshin } 233255163Sshin return NULL; 233355163Sshin} 233455163Sshin 233555163Sshinconst char * 233655163Sshininet6_n2p(p) 233755163Sshin const struct in6_addr *p; 233855163Sshin{ 233955163Sshin static char buf[BUFSIZ]; 234055163Sshin 234155163Sshin return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf)); 234255163Sshin} 234355163Sshin 234455163Sshinvoid 234555163Sshinifrtdump(sig) 234655163Sshin int sig; 234755163Sshin{ 234855163Sshin 234955163Sshin ifdump(sig); 235055163Sshin rtdump(sig); 235155163Sshin} 235255163Sshin 235355163Sshinvoid 235455163Sshinifdump(sig) 235555163Sshin int sig; 235655163Sshin{ 235755163Sshin struct ifc *ifcp; 235855163Sshin FILE *dump; 235955163Sshin int i; 236055163Sshin 236155163Sshin if (sig == 0) 236255163Sshin dump = stderr; 236355163Sshin else 236455163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 236555163Sshin dump = stderr; 236655163Sshin 236755163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 236855163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 236955163Sshin for (i = 0; i < 2; i++) { 237055163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 237155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 237255163Sshin if (i == 0) { 237355163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 237455163Sshin continue; 237555163Sshin if (iff_find(ifcp, 'N') != NULL) 237655163Sshin continue; 237755163Sshin } else { 237855163Sshin if (ifcp->ifc_flags & IFF_UP) 237955163Sshin continue; 238055163Sshin } 238155163Sshin ifdump0(dump, ifcp); 238255163Sshin } 238355163Sshin } 238455163Sshin fprintf(dump, "\n"); 238555163Sshin if (dump != stderr) 238655163Sshin fclose(dump); 238755163Sshin} 238855163Sshin 238955163Sshinvoid 239055163Sshinifdump0(dump, ifcp) 239155163Sshin FILE *dump; 239255163Sshin const struct ifc *ifcp; 239355163Sshin{ 239455163Sshin struct ifac *ifa; 239555163Sshin struct iff *iffp; 239655163Sshin char buf[BUFSIZ]; 239755163Sshin const char *ft; 239855163Sshin int addr; 239955163Sshin 240055163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 240155163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 240255163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 240355163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 240455163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 240555163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 240655163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 240755163Sshin buf, sizeof(buf)); 240855163Sshin fprintf(dump, "\t%s/%d -- %s\n", 240955163Sshin inet6_n2p(&ifa->ifa_addr), 241055163Sshin ifa->ifa_plen, buf); 241155163Sshin } else { 241255163Sshin fprintf(dump, "\t%s/%d\n", 241355163Sshin inet6_n2p(&ifa->ifa_addr), 241455163Sshin ifa->ifa_plen); 241555163Sshin } 241655163Sshin } 241755163Sshin if (ifcp->ifc_filter) { 241855163Sshin fprintf(dump, "\tFilter:"); 241955163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 242055163Sshin addr = 0; 242155163Sshin switch (iffp->iff_type) { 242255163Sshin case 'A': 242355163Sshin ft = "Aggregate"; addr++; break; 242455163Sshin case 'N': 242555163Sshin ft = "No-advertise"; break; 242655163Sshin case 'O': 242755163Sshin ft = "Advertise-only"; addr++; break; 242855163Sshin case 'T': 242955163Sshin ft = "Default-only"; break; 243055163Sshin case 'L': 243155163Sshin ft = "Listen-only"; addr++; break; 243255163Sshin default: 243355163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 243455163Sshin ft = buf; 243555163Sshin addr++; 243655163Sshin break; 243755163Sshin } 243855163Sshin fprintf(dump, " %s", ft); 243955163Sshin if (addr) { 244055163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 244155163Sshin iffp->iff_plen); 244255163Sshin } 244355163Sshin } 244455163Sshin fprintf(dump, "\n"); 244555163Sshin } 244655163Sshin} 244755163Sshin 244855163Sshinvoid 244955163Sshinrtdump(sig) 245055163Sshin int sig; 245155163Sshin{ 245255163Sshin struct riprt *rrt; 245355163Sshin char buf[BUFSIZ]; 245455163Sshin FILE *dump; 245555163Sshin time_t t, age; 245655163Sshin 245755163Sshin if (sig == 0) 245855163Sshin dump = stderr; 245955163Sshin else 246055163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 246155163Sshin dump = stderr; 246255163Sshin 246355163Sshin t = time(NULL); 246455163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 246555163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 246655163Sshin if (rrt->rrt_t == 0) 246755163Sshin age = 0; 246855163Sshin else 246955163Sshin age = t - rrt->rrt_t; 247055163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 247155163Sshin buf, sizeof(buf)); 247255163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 247355163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 247455163Sshin index2ifc[rrt->rrt_index]->ifc_name, 247555163Sshin inet6_n2p(&rrt->rrt_gw), 247655163Sshin rrt->rrt_info.rip6_metric, (long)age); 247755163Sshin if (rrt->rrt_info.rip6_tag) { 247855163Sshin fprintf(dump, " tag(0x%04x)", 247955163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 248055163Sshin } 248155163Sshin if (rrt->rrt_flags & RTF_NH_NOT_LLADDR) 248255163Sshin fprintf(dump, " NOT-LL"); 248355163Sshin if (rrt->rrt_flags & RTF_NOADVERTISE) 248455163Sshin fprintf(dump, " NO-ADV"); 248555163Sshin fprintf(dump, "\n"); 248655163Sshin } 248755163Sshin fprintf(dump, "\n"); 248855163Sshin if (dump != stderr) 248955163Sshin fclose(dump); 249055163Sshin} 249155163Sshin 249255163Sshin/* 249355163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 249455163Sshin * specified interface structures. Each of the -A/O option has the following 249555163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 249655163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 249755163Sshin */ 249855163Sshinvoid 249955163Sshinfilterconfig() 250055163Sshin{ 250155163Sshin int i; 250255163Sshin char *p, *ap, *iflp, *ifname; 250355163Sshin struct iff ftmp, *iff_obj; 250455163Sshin struct ifc *ifcp; 250555163Sshin struct riprt *rrt; 250655163Sshin struct in6_addr gw; 250755163Sshin 250855163Sshin for (i = 0; i < nfilter; i++) { 250955163Sshin ap = filter[i]; 251055163Sshin iflp = NULL; 251155163Sshin ifcp = NULL; 251255163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 251355163Sshin iflp = ap; 251455163Sshin goto ifonly; 251555163Sshin } 251655163Sshin if ((p = index(ap, ',')) != NULL) { 251755163Sshin *p++ = '\0'; 251855163Sshin iflp = p; 251955163Sshin } 252055163Sshin if ((p = index(ap, '/')) == NULL) 252155163Sshin fatal("no prefixlen specified for '%s'", ap); 252255163Sshin *p++ = '\0'; 252355163Sshin if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) 252455163Sshin fatal("invalid prefix specified for '%s'", ap); 252555163Sshin ftmp.iff_plen = atoi(p); 252655163Sshin ftmp.iff_next = NULL; 252755163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 252855163Sshinifonly: 252955163Sshin ftmp.iff_type = filtertype[i]; 253055163Sshin if (iflp == NULL || *iflp == '\0') 253155163Sshin fatal("no interface specified for '%s'", ap); 253255163Sshin /* parse the interface listing portion */ 253355163Sshin while (iflp) { 253455163Sshin ifname = iflp; 253555163Sshin if ((iflp = index(iflp, ',')) != NULL) 253655163Sshin *iflp++ = '\0'; 253755163Sshin ifcp = ifc_find(ifname); 253855163Sshin if (ifcp == NULL) 253955163Sshin fatal("no interface %s exists", ifname); 254055163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 254155163Sshin if (iff_obj == NULL) 254255163Sshin fatal("malloc of iff_obj"); 254355163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 254455163Sshin sizeof(struct iff)); 254555163Sshin /* link it to the interface filter */ 254655163Sshin iff_obj->iff_next = ifcp->ifc_filter; 254755163Sshin ifcp->ifc_filter = iff_obj; 254855163Sshin } 254955163Sshin if (filtertype[i] != 'A') 255055163Sshin continue; 255155163Sshin /* put the aggregate to the kernel routing table */ 255255163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 255355163Sshin if (rrt == NULL) 255455163Sshin fatal("malloc: rrt"); 255555163Sshin memset(rrt, 0, sizeof(struct riprt)); 255655163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 255755163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 255855163Sshin rrt->rrt_info.rip6_metric = 1; 255955163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 256055163Sshin rrt->rrt_gw = in6addr_loopback; 256155163Sshin rrt->rrt_flags = RTF_UP | RTF_REJECT | RTF_AGGREGATE; 256255163Sshin rrt->rrt_t = 0; 256355163Sshin rrt->rrt_index = loopifindex; 256455163Sshin /* Put the route to the list */ 256555163Sshin rrt->rrt_next = riprt; 256655163Sshin riprt = rrt; 256755163Sshin trace(1, "Aggregate: %s/%d for %s\n", 256855163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 256955163Sshin ifcp->ifc_name); 257055163Sshin /* Add this route to the kernel */ 257155163Sshin if (nflag) /* do not modify kernel routing table */ 257255163Sshin continue; 257355163Sshin if (getroute(&rrt->rrt_info, &gw)) { 257455163Sshin /* 257555163Sshin * When the address has already been registered in the 257655163Sshin * kernel routing table, it should be removed 257755163Sshin */ 257855163Sshin delroute(&rrt->rrt_info, &gw); 257955163Sshin } 258055163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 258155163Sshin } 258255163Sshin} 258355163Sshin 258455163Sshin/***************** utility functions *****************/ 258555163Sshin 258655163Sshin/* 258755163Sshin * Returns a pointer to ifac whose address and prefix length matches 258855163Sshin * with the address and prefix length specified in the arguments. 258955163Sshin */ 259055163Sshinstruct ifac * 259155163Sshinifa_match(ifcp, ia, plen) 259255163Sshin const struct ifc *ifcp; 259355163Sshin const struct in6_addr *ia; 259455163Sshin int plen; 259555163Sshin{ 259655163Sshin struct ifac *ifa; 259755163Sshin 259855163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 259955163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 260055163Sshin ifa->ifa_plen == plen) 260155163Sshin break; 260255163Sshin } 260355163Sshin return ifa; 260455163Sshin} 260555163Sshin 260655163Sshin/* 260755163Sshin * Return a pointer to riprt structure whose address and prefix length 260855163Sshin * matches with the address and prefix length found in the argument. 260955163Sshin * Note: This is not a rtalloc(). Therefore exact match is necessary. 261055163Sshin */ 261155163Sshin 261255163Sshinstruct riprt * 261355163Sshinrtsearch(np) 261455163Sshin struct netinfo6 *np; 261555163Sshin{ 261655163Sshin struct riprt *rrt; 261755163Sshin 261855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 261955163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 262055163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 262155163Sshin &np->rip6_dest)) 262255163Sshin return rrt; 262355163Sshin } 262455163Sshin return 0; 262555163Sshin} 262655163Sshin 262755163Sshinint 262855163Sshinmask2len(addr, lenlim) 262955163Sshin const struct in6_addr *addr; 263055163Sshin int lenlim; 263155163Sshin{ 263255163Sshin int i = 0, j; 263355163Sshin u_char *p = (u_char *)addr; 263455163Sshin 263555163Sshin for (j = 0; j < lenlim; j++, p++) { 263655163Sshin if (*p != 0xff) 263755163Sshin break; 263855163Sshin i += 8; 263955163Sshin } 264055163Sshin if (j < lenlim) { 264155163Sshin switch (*p) { 264255163Sshin#define MASKLEN(m, l) case m: i += l; break 264355163Sshin MASKLEN(0xfe, 7); 264455163Sshin MASKLEN(0xfc, 6); 264555163Sshin MASKLEN(0xf8, 5); 264655163Sshin MASKLEN(0xf0, 4); 264755163Sshin MASKLEN(0xe0, 3); 264855163Sshin MASKLEN(0xc0, 2); 264955163Sshin MASKLEN(0x80, 1); 265055163Sshin#undef MASKLEN 265155163Sshin } 265255163Sshin } 265355163Sshin return i; 265455163Sshin} 265555163Sshin 265655163Sshinvoid 265755163Sshinapplymask(addr, mask) 265855163Sshin struct in6_addr *addr, *mask; 265955163Sshin{ 266055163Sshin int i; 266155163Sshin u_long *p, *q; 266255163Sshin 266355163Sshin p = (u_long *)addr; q = (u_long *)mask; 266455163Sshin for (i = 0; i < 4; i++) 266555163Sshin *p++ &= *q++; 266655163Sshin} 266755163Sshin 266855163Sshinstatic const u_char plent[8] = { 266955163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 267055163Sshin}; 267155163Sshin 267255163Sshinvoid 267355163Sshinapplyplen(ia, plen) 267455163Sshin struct in6_addr *ia; 267555163Sshin int plen; 267655163Sshin{ 267755163Sshin u_char *p; 267855163Sshin int i; 267955163Sshin 268055163Sshin p = ia->s6_addr; 268155163Sshin for (i = 0; i < 16; i++) { 268255163Sshin if (plen <= 0) 268355163Sshin *p = 0; 268455163Sshin else if (plen < 8) 268555163Sshin *p &= plent[plen]; 268655163Sshin p++, plen -= 8; 268755163Sshin } 268855163Sshin} 268955163Sshin 269055163Sshinstatic const int pl2m[9] = { 269155163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 269255163Sshin}; 269355163Sshin 269455163Sshinstruct in6_addr * 269555163Sshinplen2mask(n) 269655163Sshin int n; 269755163Sshin{ 269855163Sshin static struct in6_addr ia; 269955163Sshin u_char *p; 270055163Sshin int i; 270155163Sshin 270255163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 270355163Sshin p = (u_char *)&ia; 270455163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 270555163Sshin if (n >= 8) { 270655163Sshin *p = 0xff; 270755163Sshin continue; 270855163Sshin } 270955163Sshin *p = pl2m[n]; 271055163Sshin break; 271155163Sshin } 271255163Sshin return &ia; 271355163Sshin} 271455163Sshin 271555163Sshinchar * 271655163Sshinallocopy(p) 271755163Sshin char *p; 271855163Sshin{ 271955163Sshin char *q = (char *)malloc(strlen(p) + 1); 272055163Sshin 272155163Sshin strcpy(q, p); 272255163Sshin return q; 272355163Sshin} 272455163Sshin 272555163Sshinchar * 272655163Sshinhms() 272755163Sshin{ 272855163Sshin static char buf[BUFSIZ]; 272955163Sshin time_t t; 273055163Sshin struct tm *tm; 273155163Sshin 273255163Sshin t = time(NULL); 273355163Sshin if ((tm = localtime(&t)) == 0) 273455163Sshin fatal("localtime"); 273555163Sshin snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); 273655163Sshin return buf; 273755163Sshin} 273855163Sshin 273955163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 274055163Sshin 274155163Sshinint 274255163Sshinripinterval(timer) 274355163Sshin int timer; 274455163Sshin{ 274555163Sshin double r = rand(); 274655163Sshin 274755163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 274855163Sshin nextalarm = time(NULL) + interval; 274955163Sshin return interval; 275055163Sshin} 275155163Sshin 275255163Sshintime_t 275355163Sshinripsuptrig() 275455163Sshin{ 275555163Sshin time_t t; 275655163Sshin 275755163Sshin double r = rand(); 275855163Sshin t = (int)(RIP_TRIG_INT6_MIN + 275955163Sshin (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX )); 276055163Sshin sup_trig_update = time(NULL) + t; 276155163Sshin return t; 276255163Sshin} 276355163Sshin 276455163Sshinvoid 276555163Sshin#ifdef __STDC__ 276655163Sshinfatal(const char *fmt, ...) 276755163Sshin#else 276855163Sshinfatal(fmt, va_alist) 276955163Sshin char *fmt; 277055163Sshin va_dcl 277155163Sshin#endif 277255163Sshin{ 277355163Sshin va_list ap; 277455163Sshin char buf[1024]; 277555163Sshin 277655163Sshin#ifdef __STDC__ 277755163Sshin va_start(ap, fmt); 277855163Sshin#else 277955163Sshin va_start(ap); 278055163Sshin#endif 278155163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 278255163Sshin perror(buf); 278355163Sshin syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 278455163Sshin rtdexit(0); 278555163Sshin va_end(ap); 278655163Sshin} 278755163Sshin 278855163Sshinvoid 278955163Sshin#ifdef __STDC__ 279055163Sshintracet(int level, const char *fmt, ...) 279155163Sshin#else 279255163Sshintracet(level, fmt, va_alist) 279355163Sshin int level; 279455163Sshin char *fmt; 279555163Sshin va_dcl 279655163Sshin#endif 279755163Sshin{ 279855163Sshin va_list ap; 279955163Sshin 280055163Sshin#ifdef __STDC__ 280155163Sshin va_start(ap, fmt); 280255163Sshin#else 280355163Sshin va_start(ap); 280455163Sshin#endif 280555163Sshin if (level <= dflag) { 280655163Sshin fprintf(stderr, "%s: ", hms()); 280755163Sshin vfprintf(stderr, fmt, ap); 280855163Sshin } 280955163Sshin if (dflag) { 281055163Sshin if (level > 0) 281155163Sshin vsyslog(LOG_DEBUG, fmt, ap); 281255163Sshin else 281355163Sshin vsyslog(LOG_WARNING, fmt, ap); 281455163Sshin } 281555163Sshin va_end(ap); 281655163Sshin} 281755163Sshin 281855163Sshinvoid 281955163Sshin#ifdef __STDC__ 282055163Sshintrace(int level, const char *fmt, ...) 282155163Sshin#else 282255163Sshintrace(level, fmt, va_alist) 282355163Sshin int level; 282455163Sshin char *fmt; 282555163Sshin va_dcl 282655163Sshin#endif 282755163Sshin{ 282855163Sshin va_list ap; 282955163Sshin 283055163Sshin#ifdef __STDC__ 283155163Sshin va_start(ap, fmt); 283255163Sshin#else 283355163Sshin va_start(ap); 283455163Sshin#endif 283555163Sshin if (level <= dflag) 283655163Sshin vfprintf(stderr, fmt, ap); 283755163Sshin if (dflag) { 283855163Sshin if (level > 0) 283955163Sshin vsyslog(LOG_DEBUG, fmt, ap); 284055163Sshin else 284155163Sshin vsyslog(LOG_WARNING, fmt, ap); 284255163Sshin } 284355163Sshin va_end(ap); 284455163Sshin} 284555163Sshin 284655163Sshinunsigned int 284755163Sshinif_maxindex() 284855163Sshin{ 284955163Sshin struct if_nameindex *p, *p0; 285055163Sshin unsigned int max = 0; 285155163Sshin 285255163Sshin p0 = if_nameindex(); 285355163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 285455163Sshin if (max < p->if_index) 285555163Sshin max = p->if_index; 285655163Sshin } 285755163Sshin if_freenameindex(p0); 285855163Sshin return max; 285955163Sshin} 286055163Sshin 286155163Sshinstruct ifc * 286255163Sshinifc_find(name) 286355163Sshin char *name; 286455163Sshin{ 286555163Sshin struct ifc *ifcp; 286655163Sshin 286755163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 286855163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 286955163Sshin return ifcp; 287055163Sshin } 287155163Sshin return (struct ifc *)NULL; 287255163Sshin} 287355163Sshin 287455163Sshinstruct iff * 287555163Sshiniff_find(ifcp, type) 287655163Sshin struct ifc *ifcp; 287755163Sshin int type; 287855163Sshin{ 287955163Sshin struct iff *iffp; 288055163Sshin 288155163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 288255163Sshin if (iffp->iff_type == type) 288355163Sshin return iffp; 288455163Sshin } 288555163Sshin return NULL; 288655163Sshin} 288755163Sshin 288855163Sshinvoid 288955163Sshinsetindex2ifc(index, ifcp) 289055163Sshin int index; 289155163Sshin struct ifc *ifcp; 289255163Sshin{ 289355163Sshin int n; 289455163Sshin 289555163Sshin if (!index2ifc) { 289655163Sshin nindex2ifc = 5; /*initial guess*/ 289755163Sshin index2ifc = (struct ifc **) 289855163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 289955163Sshin if (index2ifc == NULL) 290055163Sshin fatal("malloc"); 290155163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 290255163Sshin } 290355163Sshin n = nindex2ifc; 290455163Sshin while (nindex2ifc <= index) 290555163Sshin nindex2ifc *= 2; 290655163Sshin if (n != nindex2ifc) { 290755163Sshin index2ifc = (struct ifc **) 290855163Sshin realloc(index2ifc, sizeof(*index2ifc) * nindex2ifc); 290955163Sshin if (index2ifc == NULL) 291055163Sshin fatal("realloc"); 291155163Sshin } 291255163Sshin index2ifc[index] = ifcp; 291355163Sshin} 2914