route6d.c revision 62921
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 62921 2000-07-10 18:27:55Z ume $ */ 262607Sitojun/* $KAME: route6d.c,v 1.30 2000/06/04 06:48:03 itojun Exp $ */ 355163Sshin 455163Sshin/* 555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 655163Sshin * All rights reserved. 762607Sitojun * 855163Sshin * Redistribution and use in source and binary forms, with or without 955163Sshin * modification, are permitted provided that the following conditions 1055163Sshin * are met: 1155163Sshin * 1. Redistributions of source code must retain the above copyright 1255163Sshin * notice, this list of conditions and the following disclaimer. 1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455163Sshin * notice, this list of conditions and the following disclaimer in the 1555163Sshin * documentation and/or other materials provided with the distribution. 1655163Sshin * 3. Neither the name of the project nor the names of its contributors 1755163Sshin * may be used to endorse or promote products derived from this software 1855163Sshin * without specific prior written permission. 1962607Sitojun * 2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055163Sshin * SUCH DAMAGE. 3155163Sshin */ 3255163Sshin 3355163Sshin#ifndef lint 3462607Sitojunstatic char _rcsid[] = "$KAME: route6d.c,v 1.30 2000/06/04 06:48:03 itojun Exp $"; 3555163Sshin#endif 3655163Sshin 3755163Sshin#include <stdio.h> 3855163Sshin 3955163Sshin#include <time.h> 4055163Sshin#include <unistd.h> 4155163Sshin#include <stdlib.h> 4255163Sshin#include <string.h> 4355163Sshin#include <signal.h> 4455163Sshin#ifdef __STDC__ 4555163Sshin#include <stdarg.h> 4655163Sshin#else 4755163Sshin#include <varargs.h> 4855163Sshin#endif 4955163Sshin#include <syslog.h> 5055163Sshin#include <stddef.h> 5162607Sitojun#include <errno.h> 5255163Sshin#include <err.h> 5355163Sshin 5455163Sshin#include <sys/types.h> 5555163Sshin#include <sys/param.h> 5655163Sshin#include <sys/file.h> 5755163Sshin#include <sys/socket.h> 5855163Sshin#include <sys/ioctl.h> 5955163Sshin#include <sys/sysctl.h> 6055163Sshin#include <sys/uio.h> 6155163Sshin#include <net/if.h> 6262607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3 6355163Sshin#include <net/if_var.h> 6462607Sitojun#endif /* __FreeBSD__ >= 3 */ 6562607Sitojun#define KERNEL 1 6662607Sitojun#define _KERNEL 1 6755163Sshin#include <net/route.h> 6862607Sitojun#undef KERNEL 6962607Sitojun#undef _KERNEL 7055163Sshin#include <netinet/in.h> 7155163Sshin#include <netinet/in_var.h> 7255163Sshin#include <netinet/ip6.h> 7355163Sshin#include <netinet/udp.h> 7455163Sshin#include <netdb.h> 7562607Sitojun#ifdef HAVE_GETIFADDRS 7662607Sitojun#include <ifaddrs.h> 7762607Sitojun#endif 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 */ 9262607Sitojun#define ROUNDUP(a) \ 9355163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9462607Sitojun#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 12262607Sitojunstruct 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 */ 16662607Sitojun u_long rrt_flags; /* kernel routing table flags */ 16762607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 16855163Sshin time_t rrt_t; /* when the route validated */ 16955163Sshin int rrt_index; /* ifindex from which this route got */ 17055163Sshin}; 17155163Sshin 17255163Sshinstruct riprt *riprt = 0; 17355163Sshin 17455163Sshinint dflag = 0; /* debug flag */ 17555163Sshinint qflag = 0; /* quiet flag */ 17655163Sshinint nflag = 0; /* don't update kernel routing table */ 17755163Sshinint aflag = 0; /* age out even the statically defined routes */ 17855163Sshinint hflag = 0; /* don't split horizon */ 17955163Sshinint lflag = 0; /* exchange site local routes */ 18055163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 18155163Sshinint Sflag = 0; /* announce static routes to every interface */ 18262607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 18355163Sshin 18455163Sshinchar *filter[MAXFILTER]; 18555163Sshinint filtertype[MAXFILTER]; 18655163Sshinint nfilter = 0; 18755163Sshin 18855163Sshinpid_t pid; 18955163Sshin 19055163Sshinstruct sockaddr_storage ripsin; 19155163Sshin 19255163Sshinstruct rtentry rtentry; 19355163Sshin 19455163Sshinint interval = 1; 19555163Sshintime_t nextalarm = 0; 19655163Sshintime_t sup_trig_update = 0; 19755163Sshin 19855163SshinFILE *rtlog = NULL; 19955163Sshin 20055163Sshinint logopened = 0; 20155163Sshin 20255163Sshinstatic u_long seq = 0; 20355163Sshin 20462607Sitojun#define RRTF_AGGREGATE 0x08000000 20562607Sitojun#define RRTF_NOADVERTISE 0x10000000 20662607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 20762607Sitojun#define RRTF_SENDANYWAY 0x40000000 20862607Sitojun#define RRTF_CHANGED 0x80000000 20955163Sshin 21055163Sshinint main __P((int, char **)); 21155163Sshinvoid ripalarm __P((int)); 21255163Sshinvoid riprecv __P((void)); 21355163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 21455163Sshinvoid init __P((void)); 21555163Sshinvoid sockopt __P((struct ifc *)); 21655163Sshinvoid ifconfig __P((void)); 21762607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 21855163Sshinvoid rtrecv __P((void)); 21955163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 22055163Sshin const struct sockaddr_in6 *)); 22155163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 22255163Sshin const struct sockaddr_in6 *)); 22355163Sshinvoid filterconfig __P((void)); 22455163Sshinint getifmtu __P((int)); 22555163Sshinconst char *rttypes __P((struct rt_msghdr *rtm)); 22655163Sshinconst char *rtflags __P((struct rt_msghdr *rtm)); 22755163Sshinconst char *ifflags __P((int flags)); 22855163Sshinvoid ifrt __P((struct ifc *, int)); 22962607Sitojunvoid ifrt_p2p __P((struct ifc *, int)); 23055163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 23155163Sshinvoid applyplen __P((struct in6_addr *, int)); 23255163Sshinvoid ifrtdump __P((int)); 23355163Sshinvoid ifdump __P((int)); 23455163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 23555163Sshinvoid rtdump __P((int)); 23655163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 23755163Sshinvoid rtdexit __P((int)); 23855163Sshinvoid riprequest __P((struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *)); 23955163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 24055163Sshinvoid sendrequest __P((struct ifc *)); 24155163Sshinint mask2len __P((const struct in6_addr *, int)); 24255163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 24355163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 24455163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 24555163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 24655163Sshinvoid krtread __P((int)); 24755163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 24855163Sshinchar *allocopy __P((char *)); 24955163Sshinchar *hms __P((void)); 25055163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 25155163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 25255163Sshinstruct in6_addr *plen2mask __P((int)); 25355163Sshinstruct riprt *rtsearch __P((struct netinfo6 *)); 25455163Sshinint ripinterval __P((int)); 25555163Sshintime_t ripsuptrig __P((void)); 25655163Sshinvoid fatal __P((const char *, ...)); 25755163Sshinvoid trace __P((int, const char *, ...)); 25855163Sshinvoid tracet __P((int, const char *, ...)); 25955163Sshinunsigned int if_maxindex __P((void)); 26055163Sshinstruct ifc *ifc_find __P((char *)); 26155163Sshinstruct iff *iff_find __P((struct ifc *, int)); 26255163Sshinvoid setindex2ifc __P((int, struct ifc *)); 26355163Sshin 26455163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 26555163Sshin 26655163Sshinint 26755163Sshinmain(argc, argv) 26855163Sshin int argc; 26955163Sshin char **argv; 27055163Sshin{ 27155163Sshin int ch; 27255163Sshin int error = 0; 27355163Sshin struct ifc *ifcp; 27455163Sshin sigset_t mask, omask; 27555163Sshin FILE *pidfile; 27655163Sshin char *progname; 27762607Sitojun char *ep; 27855163Sshin 27955163Sshin progname = strrchr(*argv, '/'); 28055163Sshin if (progname) 28155163Sshin progname++; 28255163Sshin else 28355163Sshin progname = *argv; 28455163Sshin 28555163Sshin pid = getpid(); 28655163Sshin while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != EOF) { 28755163Sshin switch (ch) { 28855163Sshin case 'A': 28955163Sshin case 'N': 29055163Sshin case 'O': 29155163Sshin case 'T': 29255163Sshin case 'L': 29362607Sitojun if (nfilter >= MAXFILTER) { 29455163Sshin fatal("Exceeds MAXFILTER"); 29562607Sitojun /*NOTREACHED*/ 29662607Sitojun } 29755163Sshin filtertype[nfilter] = ch; 29855163Sshin filter[nfilter++] = allocopy(optarg); 29955163Sshin break; 30055163Sshin case 't': 30162607Sitojun ep = NULL; 30262607Sitojun routetag = strtoul(optarg, &ep, 0); 30362607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 30455163Sshin fatal("invalid route tag"); 30555163Sshin /*NOTREACHED*/ 30655163Sshin } 30755163Sshin break; 30855163Sshin case 'R': 30962607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 31055163Sshin fatal("Can not write to routelog"); 31162607Sitojun /*NOTREACHED*/ 31262607Sitojun } 31355163Sshin break; 31462607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 31562607Sitojun FLAG('a', aflag, 1); break; 31662607Sitojun FLAG('d', dflag, 1); break; 31762607Sitojun FLAG('D', dflag, 2); break; 31862607Sitojun FLAG('h', hflag, 1); break; 31962607Sitojun FLAG('l', lflag, 1); break; 32062607Sitojun FLAG('n', nflag, 1); break; 32162607Sitojun FLAG('q', qflag, 1); break; 32262607Sitojun FLAG('s', sflag, 1); break; 32362607Sitojun FLAG('S', Sflag, 1); break; 32455163Sshin#undef FLAG 32555163Sshin default: 32655163Sshin fatal("Invalid option specified, terminating"); 32762607Sitojun /*NOTREACHED*/ 32855163Sshin } 32955163Sshin } 33055163Sshin argc -= optind; 33155163Sshin argv += optind; 33255163Sshin if (argc > 0) 33355163Sshin fatal("bogus extra arguments"); 33455163Sshin 33555163Sshin if (geteuid()) { 33655163Sshin nflag = 1; 33755163Sshin fprintf(stderr, "No kernel update is allowed\n"); 33855163Sshin } 33955163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 34055163Sshin logopened++; 34155163Sshin init(); 34255163Sshin ifconfig(); 34355163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 34455163Sshin if (ifcp->ifc_index < 0) { 34555163Sshin fprintf(stderr, 34655163Sshin"No ifindex found at %s (no link-local address?)\n", 34755163Sshin ifcp->ifc_name); 34855163Sshin error++; 34955163Sshin } 35055163Sshin } 35155163Sshin if (error) 35255163Sshin exit(1); 35355163Sshin if (loopifcp == NULL) 35455163Sshin fatal("No loopback found"); 35555163Sshin loopifindex = loopifcp->ifc_index; 35655163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 35755163Sshin ifrt(ifcp, 0); 35855163Sshin filterconfig(); 35955163Sshin krtread(0); 36055163Sshin if (dflag) 36155163Sshin ifrtdump(0); 36255163Sshin 36355163Sshin if (dflag == 0) { 36462607Sitojun#if 1 36555163Sshin if (daemon(0, 0) < 0) 36655163Sshin fatal("daemon"); 36762607Sitojun#else 36862607Sitojun if (fork()) 36962607Sitojun exit(0); 37062607Sitojun if (setsid() < 0) 37162607Sitojun fatal("setid"); 37262607Sitojun#endif 37355163Sshin } 37455163Sshin pid = getpid(); 37555163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 37655163Sshin fprintf(pidfile, "%d\n", pid); 37755163Sshin fclose(pidfile); 37855163Sshin } 37955163Sshin 38055163Sshin if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 38155163Sshin fatal("malloc"); 38262607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 38355163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 38455163Sshin ripbuf->rip6_vers = RIP6_VERSION; 38555163Sshin ripbuf->rip6_res1[0] = 0; 38655163Sshin ripbuf->rip6_res1[1] = 0; 38755163Sshin 38855163Sshin if (signal(SIGALRM, ripalarm) == SIG_ERR) 38955163Sshin fatal("signal: SIGALRM"); 39055163Sshin if (signal(SIGQUIT, rtdexit) == SIG_ERR) 39155163Sshin fatal("signal: SIGQUIT"); 39255163Sshin if (signal(SIGTERM, rtdexit) == SIG_ERR) 39355163Sshin fatal("signal: SIGTERM"); 39455163Sshin if (signal(SIGUSR1, ifrtdump) == SIG_ERR) 39555163Sshin fatal("signal: SIGUSR1"); 39655163Sshin if (signal(SIGHUP, ifrtdump) == SIG_ERR) 39755163Sshin fatal("signal: SIGHUP"); 39855163Sshin if (signal(SIGINT, ifrtdump) == SIG_ERR) 39955163Sshin fatal("signal: SIGINT"); 40055163Sshin /* 40155163Sshin * To avoid rip packet congestion (not on a cable but in this 40255163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 40355163Sshin * packets. 40455163Sshin */ 40555163Sshin alarm(ripinterval(INIT_INTERVAL6)); 40655163Sshin 40755163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 40855163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 40955163Sshin sendrequest(ifcp); 41055163Sshin } 41155163Sshin 41255163Sshin syslog(LOG_INFO, "**** Started ****"); 41355163Sshin sigemptyset(&mask); 41455163Sshin sigaddset(&mask, SIGALRM); 41555163Sshin while (1) { 41655163Sshin fd_set recvec; 41755163Sshin 41855163Sshin FD_COPY(&sockvec, &recvec); 41955163Sshin switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { 42055163Sshin case -1: 42155163Sshin if (errno == EINTR) 42255163Sshin continue; 42355163Sshin fatal("select"); 42455163Sshin case 0: 42555163Sshin continue; 42655163Sshin default: 42755163Sshin if (FD_ISSET(ripsock, &recvec)) { 42855163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 42955163Sshin riprecv(); 43055163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 43155163Sshin } 43255163Sshin if (FD_ISSET(rtsock, &recvec)) { 43355163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 43455163Sshin rtrecv(); 43555163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 43655163Sshin } 43755163Sshin } 43855163Sshin } 43955163Sshin} 44055163Sshin 44155163Sshin/* 44255163Sshin * gracefully exits after resetting sockopts. 44355163Sshin */ 44455163Sshin/* ARGSUSED */ 44555163Sshinvoid 44655163Sshinrtdexit(sig) 44755163Sshin int sig; 44855163Sshin{ 44955163Sshin struct riprt *rrt; 45055163Sshin 45155163Sshin alarm(0); 45255163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 45362607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 45455163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 45555163Sshin } 45655163Sshin } 45755163Sshin close(ripsock); 45855163Sshin close(rtsock); 45955163Sshin syslog(LOG_INFO, "**** Terminated ****"); 46055163Sshin closelog(); 46155163Sshin exit(1); 46255163Sshin} 46355163Sshin 46455163Sshin/* 46555163Sshin * Called periodically: 46655163Sshin * 1. age out the learned route. remove it if necessary. 46755163Sshin * 2. submit RIP6_RESPONSE packets. 46855163Sshin * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 46955163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 47055163Sshin * routes more precisely. 47155163Sshin */ 47255163Sshin/* ARGSUSED */ 47355163Sshinvoid 47455163Sshinripalarm(sig) 47555163Sshin int sig; 47655163Sshin{ 47755163Sshin struct ifc *ifcp; 47855163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 47955163Sshin time_t t_lifetime, t_holddown; 48055163Sshin 48155163Sshin /* age the RIP routes */ 48255163Sshin rrt_prev = 0; 48355163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 48455163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 48555163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 48655163Sshin rrt_next = rrt->rrt_next; 48755163Sshin 48855163Sshin if (rrt->rrt_t == 0) { 48955163Sshin rrt_prev = rrt; 49055163Sshin continue; 49155163Sshin } 49255163Sshin if (rrt->rrt_t < t_holddown) { 49355163Sshin if (rrt_prev) { 49455163Sshin rrt_prev->rrt_next = rrt->rrt_next; 49555163Sshin } else { 49655163Sshin riprt = rrt->rrt_next; 49755163Sshin } 49855163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 49955163Sshin free(rrt); 50055163Sshin continue; 50155163Sshin } 50255163Sshin if (rrt->rrt_t < t_lifetime) 50355163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 50455163Sshin rrt_prev = rrt; 50555163Sshin } 50655163Sshin /* Supply updates */ 50755163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 50855163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 50955163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 51055163Sshin } 51155163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 51255163Sshin} 51355163Sshin 51455163Sshinvoid 51555163Sshininit() 51655163Sshin{ 51762921Sume int i, int0, int255, error; 51855163Sshin struct addrinfo hints, *res; 51955163Sshin char port[10]; 52055163Sshin 52155163Sshin ifc = (struct ifc *)NULL; 52255163Sshin nifc = 0; 52355163Sshin nindex2ifc = 0; /*initial guess*/ 52455163Sshin index2ifc = NULL; 52555163Sshin snprintf(port, sizeof(port), "%d", RIP6_PORT); 52655163Sshin 52755163Sshin memset(&hints, 0, sizeof(hints)); 52855163Sshin hints.ai_family = PF_INET6; 52955163Sshin hints.ai_socktype = SOCK_DGRAM; 53055163Sshin hints.ai_flags = AI_PASSIVE; 53155163Sshin error = getaddrinfo(NULL, port, &hints, &res); 53255163Sshin if (error) 53355163Sshin fatal(gai_strerror(error)); 53455163Sshin if (res->ai_next) 53555163Sshin fatal(":: resolved to multiple address"); 53655163Sshin 53755163Sshin int0 = 0; int255 = 255; 53855163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 53955163Sshin if (ripsock < 0) 54055163Sshin fatal("rip socket"); 54155163Sshin if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) 54255163Sshin fatal("rip bind"); 54355163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 54455163Sshin &int255, sizeof(int255)) < 0) 54555163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 54655163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 54755163Sshin &int0, sizeof(int0)) < 0) 54855163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 54962921Sume 55055163Sshin i = 1; 55162607Sitojun#ifdef IPV6_RECVPKTINFO 55262607Sitojun if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i, 55362607Sitojun sizeof(i)) < 0) 55462607Sitojun fatal("rip IPV6_RECVPKTINFO"); 55562607Sitojun#else /* old adv. API */ 55662607Sitojun if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i, 55762607Sitojun sizeof(i)) < 0) 55855163Sshin fatal("rip IPV6_PKTINFO"); 55962607Sitojun#endif 56055163Sshin 56155163Sshin memset(&hints, 0, sizeof(hints)); 56255163Sshin hints.ai_family = PF_INET6; 56355163Sshin hints.ai_socktype = SOCK_DGRAM; 56455163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 56555163Sshin if (error) 56655163Sshin fatal(gai_strerror(error)); 56755163Sshin if (res->ai_next) 56855163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 56955163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 57055163Sshin 57155163Sshin#ifdef FD_ZERO 57255163Sshin FD_ZERO(&sockvec); 57355163Sshin#else 57455163Sshin memset(&sockvec, 0, sizeof(sockvec)); 57555163Sshin#endif 57655163Sshin FD_SET(ripsock, &sockvec); 57755163Sshin 57855163Sshin if (nflag == 0) { 57955163Sshin if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) 58055163Sshin fatal("route socket"); 58155163Sshin FD_SET(rtsock, &sockvec); 58255163Sshin } else 58355163Sshin rtsock = -1; /*just for safety */ 58455163Sshin} 58555163Sshin 58662607Sitojun#define RIPSIZE(n) \ 58762607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 58855163Sshin 58955163Sshin/* 59055163Sshin * ripflush flushes the rip datagram stored in the rip buffer 59155163Sshin */ 59255163Sshinstatic int nrt; 59355163Sshinstatic struct netinfo6 *np; 59455163Sshin 59555163Sshinvoid 59655163Sshinripflush(ifcp, sin) 59755163Sshin struct ifc *ifcp; 59855163Sshin struct sockaddr_in6 *sin; 59955163Sshin{ 60055163Sshin int i; 60155163Sshin int error; 60255163Sshin 60355163Sshin if (ifcp) 60455163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 60555163Sshin ifcp->ifc_name, nrt, 60655163Sshin inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port)); 60755163Sshin else 60855163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 60955163Sshin nrt, inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port)); 61055163Sshin if (dflag >= 2) { 61155163Sshin np = ripbuf->rip6_nets; 61255163Sshin for (i = 0; i < nrt; i++, np++) { 61355163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 61455163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 61562607Sitojun trace(2, " NextHop reset"); 61655163Sshin else { 61755163Sshin trace(2, " NextHop %s", 61855163Sshin inet6_n2p(&np->rip6_dest)); 61955163Sshin } 62055163Sshin } else { 62155163Sshin trace(2, " %s/%d[%d]", 62255163Sshin inet6_n2p(&np->rip6_dest), 62355163Sshin np->rip6_plen, np->rip6_metric); 62455163Sshin } 62555163Sshin if (np->rip6_tag) { 62655163Sshin trace(2, " tag=0x%04x", 62755163Sshin ntohs(np->rip6_tag) & 0xffff); 62855163Sshin } 62955163Sshin trace(2, "\n"); 63055163Sshin } 63155163Sshin } 63255163Sshin error = sendpacket(sin, RIPSIZE(nrt)); 63355163Sshin if (error == EAFNOSUPPORT) { 63455163Sshin /* Protocol not supported */ 63555163Sshin tracet(1, "Could not send info to %s (%s): " 63655163Sshin "set IFF_UP to 0\n", 63755163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 63855163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 63955163Sshin } 64055163Sshin nrt = 0; np = ripbuf->rip6_nets; 64155163Sshin} 64255163Sshin 64355163Sshin/* 64455163Sshin * Generate RIP6_RESPONSE packets and send them. 64555163Sshin */ 64655163Sshinvoid 64755163Sshinripsend(ifcp, sin, flag) 64855163Sshin struct ifc *ifcp; 64955163Sshin struct sockaddr_in6 *sin; 65055163Sshin int flag; 65155163Sshin{ 65255163Sshin struct riprt *rrt; 65355163Sshin struct in6_addr *nh; /* next hop */ 65455163Sshin struct in6_addr ia; 65555163Sshin struct iff *iffp; 65655163Sshin int maxrte, ok; 65755163Sshin 65855163Sshin if (ifcp == NULL) { 65955163Sshin /* 66055163Sshin * Request from non-link local address is not 66155163Sshin * a regular route6d update. 66255163Sshin */ 66362607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 66462607Sitojun sizeof(struct udphdr) - 66555163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 66655163Sshin sizeof(struct netinfo6); 66755163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 66855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 66962607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 67055163Sshin continue; 67155163Sshin /* Put the route to the buffer */ 67255163Sshin *np = rrt->rrt_info; 67355163Sshin np++; nrt++; 67455163Sshin if (nrt == maxrte) { 67555163Sshin ripflush(NULL, sin); 67655163Sshin nh = NULL; 67755163Sshin } 67855163Sshin } 67955163Sshin if (nrt) /* Send last packet */ 68055163Sshin ripflush(NULL, sin); 68155163Sshin return; 68255163Sshin } 68355163Sshin 68462607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 68555163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 68655163Sshin return; 68755163Sshin if (iff_find(ifcp, 'N') != NULL) 68855163Sshin return; 68955163Sshin if (iff_find(ifcp, 'T') != NULL) { 69055163Sshin struct netinfo6 rrt_info; 69155163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 69255163Sshin rrt_info.rip6_dest = in6addr_any; 69355163Sshin rrt_info.rip6_plen = 0; 69455163Sshin rrt_info.rip6_metric = 1; 69555163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 69655163Sshin np = ripbuf->rip6_nets; 69755163Sshin *np = rrt_info; 69855163Sshin nrt = 1; 69955163Sshin ripflush(ifcp, sin); 70055163Sshin return; 70155163Sshin } 70262607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 70362607Sitojun sizeof(struct udphdr) - 70455163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 70555163Sshin sizeof(struct netinfo6); 70655163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 70755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 70862607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 70955163Sshin continue; 71055163Sshin /* Need to check filer here */ 71155163Sshin ok = 1; 71255163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 71355163Sshin if (iffp->iff_type != 'A') 71455163Sshin continue; 71555163Sshin if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 71655163Sshin continue; 71762607Sitojun ia = rrt->rrt_info.rip6_dest; 71855163Sshin applyplen(&ia, iffp->iff_plen); 71955163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 72055163Sshin ok = 0; 72155163Sshin break; 72255163Sshin } 72355163Sshin } 72455163Sshin if (!ok) 72555163Sshin continue; 72655163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 72755163Sshin if (iffp->iff_type != 'O') 72855163Sshin continue; 72955163Sshin ok = 0; 73055163Sshin if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 73155163Sshin continue; 73262607Sitojun ia = rrt->rrt_info.rip6_dest; 73355163Sshin applyplen(&ia, iffp->iff_plen); 73455163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 73555163Sshin ok = 1; 73655163Sshin break; 73755163Sshin } 73855163Sshin } 73955163Sshin if (!ok) 74055163Sshin continue; 74155163Sshin /* Check split horizon and other conditions */ 74255163Sshin if (tobeadv(rrt, ifcp) == 0) 74355163Sshin continue; 74455163Sshin /* Only considers the routes with flag if specified */ 74562607Sitojun if ((flag & RRTF_CHANGED) && 74662607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 74755163Sshin continue; 74855163Sshin /* Check nexthop */ 74955163Sshin if (rrt->rrt_index == ifcp->ifc_index && 75055163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 75162607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 75255163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 75355163Sshin if (nrt == maxrte - 2) 75455163Sshin ripflush(ifcp, sin); 75555163Sshin np->rip6_dest = rrt->rrt_gw; 75655163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 75755163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 75855163Sshin np->rip6_plen = 0; 75955163Sshin np->rip6_tag = 0; 76055163Sshin np->rip6_metric = NEXTHOP_METRIC; 76155163Sshin nh = &rrt->rrt_gw; 76255163Sshin np++; nrt++; 76355163Sshin } 76455163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 76555163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 76662607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 76755163Sshin /* Reset nexthop */ 76855163Sshin if (nrt == maxrte - 2) 76955163Sshin ripflush(ifcp, sin); 77055163Sshin memset(np, 0, sizeof(struct netinfo6)); 77155163Sshin np->rip6_metric = NEXTHOP_METRIC; 77255163Sshin nh = NULL; 77355163Sshin np++; nrt++; 77455163Sshin } 77555163Sshin /* Put the route to the buffer */ 77655163Sshin *np = rrt->rrt_info; 77755163Sshin np++; nrt++; 77855163Sshin if (nrt == maxrte) { 77955163Sshin ripflush(ifcp, sin); 78055163Sshin nh = NULL; 78155163Sshin } 78255163Sshin } 78355163Sshin if (nrt) /* Send last packet */ 78455163Sshin ripflush(ifcp, sin); 78555163Sshin} 78655163Sshin 78755163Sshin/* 78855163Sshin * Determine if the route is to be advertised on the specified interface. 78955163Sshin * It checks options specified in the arguments and the split horizon rule. 79055163Sshin */ 79155163Sshinint 79255163Sshintobeadv(rrt, ifcp) 79355163Sshin struct riprt *rrt; 79455163Sshin struct ifc *ifcp; 79555163Sshin{ 79655163Sshin 79755163Sshin /* Special care for static routes */ 79855163Sshin if (rrt->rrt_flags & RTF_STATIC) { 79962607Sitojun /* XXX don't advertise reject/blackhole routes */ 80062607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 80162607Sitojun return 0; 80262607Sitojun 80355163Sshin if (Sflag) /* Yes, advertise it anyway */ 80455163Sshin return 1; 80555163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 80655163Sshin return 1; 80755163Sshin return 0; 80855163Sshin } 80955163Sshin /* Regular split horizon */ 81055163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 81155163Sshin return 0; 81255163Sshin return 1; 81355163Sshin} 81455163Sshin 81555163Sshin/* 81655163Sshin * Send a rip packet actually. 81755163Sshin */ 81855163Sshinint 81955163Sshinsendpacket(sin, len) 82055163Sshin struct sockaddr_in6 *sin; 82155163Sshin int len; 82255163Sshin{ 82355163Sshin /* 82455163Sshin * MSG_DONTROUTE should not be specified when it responds with a 82555163Sshin * RIP6_REQUEST message. SO_DONTROUTE has been specified to 82655163Sshin * other sockets. 82755163Sshin */ 82855163Sshin struct msghdr m; 82955163Sshin struct cmsghdr *cm; 83055163Sshin struct iovec iov[2]; 83155163Sshin u_char cmsgbuf[256]; 83255163Sshin struct in6_pktinfo *pi; 83355163Sshin int index; 83455163Sshin struct sockaddr_in6 sincopy; 83555163Sshin 83655163Sshin /* do not overwrite the given sin */ 83755163Sshin sincopy = *sin; 83855163Sshin sin = &sincopy; 83955163Sshin 84055163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) 84155163Sshin || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) { 84255163Sshin index = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr); 84355163Sshin SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0); 84455163Sshin } else 84555163Sshin index = 0; 84655163Sshin 84755163Sshin m.msg_name = (caddr_t)sin; 84855163Sshin m.msg_namelen = sizeof(*sin); 84955163Sshin iov[0].iov_base = (caddr_t)ripbuf; 85055163Sshin iov[0].iov_len = len; 85155163Sshin m.msg_iov = iov; 85255163Sshin m.msg_iovlen = 1; 85355163Sshin if (!index) { 85455163Sshin m.msg_control = NULL; 85555163Sshin m.msg_controllen = 0; 85655163Sshin } else { 85755163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 85855163Sshin cm = (struct cmsghdr *)cmsgbuf; 85955163Sshin m.msg_control = (caddr_t)cm; 86055163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 86155163Sshin 86255163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 86355163Sshin cm->cmsg_level = IPPROTO_IPV6; 86455163Sshin cm->cmsg_type = IPV6_PKTINFO; 86555163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 86655163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 86755163Sshin pi->ipi6_ifindex = index; 86855163Sshin } 86955163Sshin 87055163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 87155163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 87255163Sshin return errno; 87355163Sshin } 87462921Sume 87555163Sshin return 0; 87655163Sshin} 87755163Sshin 87855163Sshin/* 87955163Sshin * Receive and process RIP packets. Update the routes/kernel forwarding 88055163Sshin * table if necessary. 88155163Sshin */ 88255163Sshinvoid 88355163Sshinriprecv() 88455163Sshin{ 88555163Sshin struct ifc *ifcp, *ic; 88655163Sshin struct sockaddr_in6 fsock; 88755163Sshin struct in6_addr nh; /* next hop */ 88855163Sshin struct rip6 *rp; 88955163Sshin struct netinfo6 *np, *nq; 89055163Sshin struct riprt *rrt; 89155163Sshin int len, nn, need_trigger, index; 89255163Sshin char buf[4 * RIP6_MAXMTU]; 89355163Sshin time_t t; 89455163Sshin struct msghdr m; 89555163Sshin struct cmsghdr *cm; 89655163Sshin struct iovec iov[2]; 89755163Sshin u_char cmsgbuf[256]; 89855163Sshin struct in6_pktinfo *pi; 89955163Sshin struct iff *iffp; 90055163Sshin struct in6_addr ia; 90155163Sshin int ok; 90255163Sshin 90355163Sshin need_trigger = 0; 90462921Sume 90555163Sshin m.msg_name = (caddr_t)&fsock; 90655163Sshin m.msg_namelen = sizeof(fsock); 90755163Sshin iov[0].iov_base = (caddr_t)buf; 90855163Sshin iov[0].iov_len = sizeof(buf); 90955163Sshin m.msg_iov = iov; 91055163Sshin m.msg_iovlen = 1; 91155163Sshin cm = (struct cmsghdr *)cmsgbuf; 91255163Sshin m.msg_control = (caddr_t)cm; 91355163Sshin m.msg_controllen = sizeof(cmsgbuf); 91455163Sshin if ((len = recvmsg(ripsock, &m, 0)) < 0) 91555163Sshin fatal("recvmsg"); 91655163Sshin index = 0; 91755163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 91855163Sshin cm; 91955163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 92055163Sshin if (cm->cmsg_level == IPPROTO_IPV6 92155163Sshin && cm->cmsg_type == IPV6_PKTINFO) { 92255163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 92355163Sshin index = pi->ipi6_ifindex; 92455163Sshin break; 92555163Sshin } 92655163Sshin } 92755163Sshin if (index && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 92855163Sshin SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, index); 92955163Sshin 93055163Sshin nh = fsock.sin6_addr; 93155163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 93255163Sshin sizeof(struct netinfo6); 93355163Sshin rp = (struct rip6 *)buf; 93455163Sshin np = rp->rip6_nets; 93555163Sshin 93655163Sshin if (rp->rip6_vers != RIP6_VERSION) { 93755163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 93855163Sshin return; 93955163Sshin } 94055163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 94155163Sshin if (index && index < nindex2ifc) { 94255163Sshin ifcp = index2ifc[index]; 94355163Sshin riprequest(ifcp, np, nn, &fsock); 94455163Sshin } else { 94555163Sshin riprequest(NULL, np, nn, &fsock); 94655163Sshin } 94762607Sitojun return; 94862607Sitojun } 94955163Sshin 95055163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 95155163Sshin trace(1, "Packets from non-ll addr: %s\n", 95255163Sshin inet6_n2p(&fsock.sin6_addr)); 95355163Sshin return; /* Ignore packets from non-link-local addr */ 95455163Sshin } 95555163Sshin index = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 95655163Sshin ifcp = (index < nindex2ifc) ? index2ifc[index] : NULL; 95755163Sshin if (!ifcp) { 95855163Sshin trace(1, "Packets to unknown interface index %d\n", index); 95955163Sshin return; /* Ignore it */ 96055163Sshin } 96155163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 96255163Sshin return; /* The packet is from me; ignore */ 96355163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 96455163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 96562607Sitojun return; 96655163Sshin } 96755163Sshin if (iff_find(ifcp, 'N') != NULL) 96855163Sshin return; 96955163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 97055163Sshin ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 97155163Sshin 97255163Sshin t = time(NULL); 97355163Sshin for (; nn; nn--, np++) { 97455163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 97555163Sshin /* modify neighbor address */ 97655163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 97755163Sshin nh = np->rip6_dest; 97855163Sshin SET_IN6_LINKLOCAL_IFINDEX(nh, index); 97955163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 98055163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 98155163Sshin nh = fsock.sin6_addr; 98255163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 98355163Sshin } else { 98455163Sshin nh = fsock.sin6_addr; 98555163Sshin trace(1, "\tInvalid Nexthop: %s\n", 98655163Sshin inet6_n2p(&np->rip6_dest)); 98755163Sshin } 98855163Sshin continue; 98955163Sshin } 99055163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 99155163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 99255163Sshin inet6_n2p(&np->rip6_dest), 99355163Sshin np->rip6_plen, np->rip6_metric); 99455163Sshin continue; 99555163Sshin } 99655163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 99755163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 99855163Sshin inet6_n2p(&np->rip6_dest), 99955163Sshin np->rip6_plen, np->rip6_metric); 100055163Sshin continue; 100155163Sshin } 100255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 100355163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 100455163Sshin inet6_n2p(&np->rip6_dest), 100555163Sshin np->rip6_plen, np->rip6_metric); 100655163Sshin continue; 100755163Sshin } 100855163Sshin /* may need to pass sitelocal prefix in some case, however*/ 100955163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 101055163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 101155163Sshin inet6_n2p(&np->rip6_dest), 101255163Sshin np->rip6_plen, np->rip6_metric); 101355163Sshin continue; 101455163Sshin } 101555163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 101655163Sshin inet6_n2p(&np->rip6_dest), 101755163Sshin np->rip6_plen, np->rip6_metric); 101855163Sshin if (np->rip6_tag) 101955163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 102062607Sitojun if (dflag >= 2) { 102162607Sitojun ia = np->rip6_dest; 102262607Sitojun applyplen(&ia, np->rip6_plen); 102362607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 102462607Sitojun trace(2, " [junk outside prefix]"); 102562607Sitojun } 102655163Sshin 102755163Sshin /* Listen-only filter */ 102855163Sshin ok = 1; /* if there's no L filter, it is ok */ 102955163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 103055163Sshin if (iffp->iff_type != 'L') 103155163Sshin continue; 103255163Sshin ok = 0; 103355163Sshin if (np->rip6_plen < iffp->iff_plen) 103455163Sshin continue; 103555163Sshin /* special rule: ::/0 means default, not "in /0" */ 103655163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 103755163Sshin continue; 103862607Sitojun ia = np->rip6_dest; 103955163Sshin applyplen(&ia, iffp->iff_plen); 104055163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 104155163Sshin ok = 1; 104255163Sshin break; 104355163Sshin } 104455163Sshin } 104555163Sshin if (!ok) { 104655163Sshin trace(2, " (filtered)\n"); 104755163Sshin continue; 104855163Sshin } 104955163Sshin 105055163Sshin trace(2, "\n"); 105155163Sshin np->rip6_metric++; 105255163Sshin np->rip6_metric += ifcp->ifc_metric; 105355163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 105455163Sshin np->rip6_metric = HOPCNT_INFINITY6; 105555163Sshin 105655163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 105755163Sshin if ((rrt = rtsearch(np)) != NULL) { 105855163Sshin if (rrt->rrt_t == 0) 105955163Sshin continue; /* Intf route has priority */ 106055163Sshin nq = &rrt->rrt_info; 106155163Sshin if (nq->rip6_metric > np->rip6_metric) { 106255163Sshin if (rrt->rrt_index == ifcp->ifc_index && 106355163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 106455163Sshin /* Small metric from the same gateway */ 106555163Sshin nq->rip6_metric = np->rip6_metric; 106655163Sshin } else { 106755163Sshin /* Better route found */ 106855163Sshin rrt->rrt_index = ifcp->ifc_index; 106955163Sshin /* Update routing table */ 107055163Sshin delroute(nq, &rrt->rrt_gw); 107155163Sshin rrt->rrt_gw = nh; 107255163Sshin *nq = *np; 107355163Sshin addroute(rrt, &nh, ifcp); 107455163Sshin } 107562607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 107655163Sshin rrt->rrt_t = t; 107755163Sshin need_trigger = 1; 107855163Sshin } else if (nq->rip6_metric < np->rip6_metric && 107955163Sshin rrt->rrt_index == ifcp->ifc_index && 108055163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 108155163Sshin /* Got worse route from same gw */ 108255163Sshin nq->rip6_metric = np->rip6_metric; 108355163Sshin rrt->rrt_t = t; 108462607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 108555163Sshin need_trigger = 1; 108655163Sshin } else if (nq->rip6_metric == np->rip6_metric && 108755163Sshin rrt->rrt_index == ifcp->ifc_index && 108855163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw) && 108955163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 109055163Sshin /* same metric, same route from same gw */ 109155163Sshin rrt->rrt_t = t; 109255163Sshin } 109362607Sitojun /* 109455163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 109555163Sshin * do not update age value. Do nothing. 109655163Sshin */ 109755163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 109855163Sshin /* Got a new valid route */ 109955163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 110055163Sshin fatal("malloc: struct riprt"); 110162607Sitojun memset(rrt, 0, sizeof(*rrt)); 110255163Sshin nq = &rrt->rrt_info; 110355163Sshin 110455163Sshin rrt->rrt_same = NULL; 110555163Sshin rrt->rrt_index = ifcp->ifc_index; 110655163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 110755163Sshin rrt->rrt_gw = nh; 110855163Sshin *nq = *np; 110955163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 111055163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 111155163Sshin rrt->rrt_flags |= RTF_HOST; 111255163Sshin 111355163Sshin /* Put the route to the list */ 111455163Sshin rrt->rrt_next = riprt; 111555163Sshin riprt = rrt; 111655163Sshin /* Update routing table */ 111755163Sshin addroute(rrt, &nh, ifcp); 111862607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 111955163Sshin need_trigger = 1; 112055163Sshin rrt->rrt_t = t; 112155163Sshin } 112255163Sshin } 112355163Sshin /* XXX need to care the interval between triggered updates */ 112455163Sshin if (need_trigger) { 112555163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 112655163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 112755163Sshin if (ifcp->ifc_index == ic->ifc_index) 112855163Sshin continue; 112955163Sshin if (ic->ifc_flags & IFF_UP) 113055163Sshin ripsend(ic, &ic->ifc_ripsin, 113162607Sitojun RRTF_CHANGED); 113255163Sshin } 113355163Sshin } 113455163Sshin /* Reset the flag */ 113555163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 113662607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 113755163Sshin } 113855163Sshin} 113955163Sshin 114055163Sshin/* 114155163Sshin * Send all routes request packet to the specified interface. 114255163Sshin */ 114355163Sshinvoid 114455163Sshinsendrequest(ifcp) 114555163Sshin struct ifc *ifcp; 114655163Sshin{ 114755163Sshin struct netinfo6 *np; 114855163Sshin int error; 114955163Sshin 115055163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 115155163Sshin return; 115255163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 115355163Sshin np = ripbuf->rip6_nets; 115455163Sshin memset(np, 0, sizeof(struct netinfo6)); 115555163Sshin np->rip6_metric = HOPCNT_INFINITY6; 115655163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 115755163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 115855163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 115955163Sshin if (error == EAFNOSUPPORT) { 116055163Sshin /* Protocol not supported */ 116155163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 116255163Sshin "set IFF_UP to 0\n", 116355163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 116455163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 116555163Sshin } 116655163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 116755163Sshin} 116855163Sshin 116955163Sshin/* 117055163Sshin * Process a RIP6_REQUEST packet. 117155163Sshin */ 117255163Sshinvoid 117355163Sshinriprequest(ifcp, np, nn, sin) 117455163Sshin struct ifc *ifcp; 117555163Sshin struct netinfo6 *np; 117655163Sshin int nn; 117755163Sshin struct sockaddr_in6 *sin; 117855163Sshin{ 117955163Sshin int i; 118055163Sshin struct riprt *rrt; 118155163Sshin 118255163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 118355163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 118455163Sshin /* Specific response, don't split-horizon */ 118555163Sshin trace(1, "\tRIP Request\n"); 118655163Sshin for (i = 0; i < nn; i++, np++) { 118755163Sshin rrt = rtsearch(np); 118855163Sshin if (rrt) 118955163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 119055163Sshin else 119155163Sshin np->rip6_metric = HOPCNT_INFINITY6; 119255163Sshin } 119355163Sshin (void)sendpacket(sin, RIPSIZE(nn)); 119455163Sshin return; 119555163Sshin } 119655163Sshin /* Whole routing table dump */ 119755163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 119862607Sitojun ripsend(ifcp, sin, RRTF_SENDANYWAY); 119955163Sshin} 120055163Sshin 120155163Sshin/* 120255163Sshin * Get information of each interface. 120355163Sshin */ 120455163Sshinvoid 120555163Sshinifconfig() 120655163Sshin{ 120762607Sitojun#ifdef HAVE_GETIFADDRS 120862607Sitojun struct ifaddrs *ifap, *ifa; 120962607Sitojun struct ifc *ifcp; 121062607Sitojun struct ipv6_mreq mreq; 121162607Sitojun int s; 121262607Sitojun 121362607Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 121462607Sitojun fatal("socket"); 121562607Sitojun 121662607Sitojun if (getifaddrs(&ifap) != 0) 121762607Sitojun fatal("getifaddrs"); 121862607Sitojun 121962607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 122062607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 122162607Sitojun continue; 122262607Sitojun ifcp = ifc_find(ifa->ifa_name); 122362607Sitojun /* we are interested in multicast-capable interfaces */ 122462607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 122562607Sitojun continue; 122662607Sitojun if (!ifcp) { 122762607Sitojun /* new interface */ 122862607Sitojun if ((ifcp = MALLOC(struct ifc)) == NULL) 122962607Sitojun fatal("malloc: struct ifc"); 123062607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 123162607Sitojun ifcp->ifc_index = -1; 123262607Sitojun ifcp->ifc_next = ifc; 123362607Sitojun ifc = ifcp; 123462607Sitojun nifc++; 123562607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 123662607Sitojun ifcp->ifc_addr = 0; 123762607Sitojun ifcp->ifc_filter = 0; 123862607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 123962607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 124062607Sitojun ifflags(ifcp->ifc_flags)); 124162607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 124262607Sitojun loopifcp = ifcp; 124362607Sitojun } else { 124462607Sitojun /* update flag, this may be up again */ 124562607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 124662607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 124762607Sitojun ifflags(ifcp->ifc_flags)); 124862607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 124962607Sitojun } 125062607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 125162607Sitojun } 125262607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 125362607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 125462607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 125562607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 125662607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 125762607Sitojun if (setsockopt(ripsock, IPPROTO_IPV6, 125862607Sitojun IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) 125962607Sitojun fatal("IPV6_JOIN_GROUP"); 126062607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 126162607Sitojun ifcp->ifc_joined++; 126262607Sitojun } 126362607Sitojun } 126462607Sitojun close(s); 126562607Sitojun freeifaddrs(ifap); 126662607Sitojun#else 126755163Sshin int s, i; 126855163Sshin char *buf; 126955163Sshin struct ifconf ifconf; 127055163Sshin struct ifreq *ifrp, ifr; 127155163Sshin struct ifc *ifcp; 127255163Sshin struct ipv6_mreq mreq; 127355163Sshin int bufsiz; 127455163Sshin 127555163Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 127655163Sshin fatal("socket"); 127755163Sshin 127855163Sshin /* wild guess - v4, media, link, v6 * 3 */ 127955163Sshin bufsiz = if_maxindex() * sizeof(struct ifreq) * 6; 128055163Sshin if ((buf = (char *)malloc(bufsiz)) == NULL) 128155163Sshin fatal("malloc"); 128255163Sshin 128355163Sshin /* 128455163Sshin * ioctl(SIOCGIFCONF) does not return error on buffer size. 128555163Sshin * we'll try to guess the buffer size by trying it twice, with 128655163Sshin * different buffer size. 128755163Sshin */ 128855163Sshin ifconf.ifc_buf = buf; 128955163Sshin ifconf.ifc_len = bufsiz / 2; 129055163Sshin if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0) 129155163Sshin fatal("ioctl: SIOCGIFCONF"); 129255163Sshin i = ifconf.ifc_len; 129355163Sshin while (1) { 129462607Sitojun char *newbuf; 129562607Sitojun 129655163Sshin ifconf.ifc_buf = buf; 129755163Sshin ifconf.ifc_len = bufsiz; 129855163Sshin if (ioctl(s, SIOCGIFCONF, (char *)&ifconf) < 0) 129955163Sshin fatal("ioctl: SIOCGIFCONF"); 130055163Sshin if (i == ifconf.ifc_len) 130155163Sshin break; 130255163Sshin i = ifconf.ifc_len; 130355163Sshin bufsiz *= 2; 130462607Sitojun if ((newbuf = (char *)realloc(buf, bufsiz)) == NULL) { 130562607Sitojun free(buf); 130655163Sshin fatal("realloc"); 130762607Sitojun } 130862607Sitojun buf = newbuf; 130955163Sshin } 131055163Sshin for (i = 0; i < ifconf.ifc_len; ) { 131155163Sshin ifrp = (struct ifreq *)(buf + i); 131255163Sshin if (ifrp->ifr_addr.sa_family != AF_INET6) 131355163Sshin goto skip; 131455163Sshin ifcp = ifc_find(ifrp->ifr_name); 131555163Sshin strcpy(ifr.ifr_name, ifrp->ifr_name); 131655163Sshin if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0) 131755163Sshin fatal("ioctl: SIOCGIFFLAGS"); 131855163Sshin /* we are interested in multicast-capable interfaces */ 131955163Sshin if ((ifr.ifr_flags & IFF_MULTICAST) == 0) 132055163Sshin goto skip; 132155163Sshin if (!ifcp) { 132255163Sshin /* new interface */ 132362607Sitojun if ((ifcp = MALLOC(struct ifc)) == NULL) 132462607Sitojun fatal("malloc: struct ifc"); 132555163Sshin memset(ifcp, 0, sizeof(*ifcp)); 132655163Sshin ifcp->ifc_index = -1; 132755163Sshin ifcp->ifc_next = ifc; 132855163Sshin ifc = ifcp; 132955163Sshin nifc++; 133055163Sshin ifcp->ifc_name = allocopy(ifrp->ifr_name); 133155163Sshin ifcp->ifc_addr = 0; 133255163Sshin ifcp->ifc_filter = 0; 133355163Sshin ifcp->ifc_flags = ifr.ifr_flags; 133455163Sshin trace(1, "newif %s <%s>\n", ifcp->ifc_name, 133555163Sshin ifflags(ifcp->ifc_flags)); 133655163Sshin if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 133755163Sshin loopifcp = ifcp; 133855163Sshin } else { 133955163Sshin /* update flag, this may be up again */ 134055163Sshin if (ifcp->ifc_flags != ifr.ifr_flags) { 134155163Sshin trace(1, "%s: <%s> -> ", ifcp->ifc_name, 134255163Sshin ifflags(ifcp->ifc_flags)); 134355163Sshin trace(1, "<%s>\n", ifflags(ifr.ifr_flags)); 134455163Sshin } 134555163Sshin ifcp->ifc_flags = ifr.ifr_flags; 134655163Sshin } 134762607Sitojun ifconfig1(ifrp->ifr_name, &ifrp->ifr_addr, ifcp, s); 134855163Sshin if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 134955163Sshin && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 135055163Sshin mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 135155163Sshin mreq.ipv6mr_interface = ifcp->ifc_index; 135255163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, 135355163Sshin IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) 135455163Sshin fatal("IPV6_JOIN_GROUP"); 135555163Sshin trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 135655163Sshin ifcp->ifc_joined++; 135755163Sshin } 135855163Sshinskip: 135955163Sshin i += IFNAMSIZ; 136055163Sshin if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) 136155163Sshin i += ifrp->ifr_addr.sa_len; 136255163Sshin else 136355163Sshin i += sizeof(struct sockaddr); 136455163Sshin } 136555163Sshin close(s); 136655163Sshin free(buf); 136762607Sitojun#endif 136855163Sshin} 136955163Sshin 137055163Sshinvoid 137162607Sitojunifconfig1(name, sa, ifcp, s) 137262607Sitojun const char *name; 137362607Sitojun const struct sockaddr *sa; 137455163Sshin struct ifc *ifcp; 137555163Sshin int s; 137655163Sshin{ 137755163Sshin struct in6_ifreq ifr; 137855163Sshin struct sockaddr_in6 *sin; 137955163Sshin struct ifac *ifa; 138055163Sshin int plen; 138155163Sshin char buf[BUFSIZ]; 138255163Sshin 138362607Sitojun sin = (struct sockaddr_in6 *)sa; 138455163Sshin ifr.ifr_addr = *sin; 138562607Sitojun strcpy(ifr.ifr_name, name); 138655163Sshin if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) 138755163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 138855163Sshin plen = mask2len(&ifr.ifr_addr.sin6_addr, 16); 138955163Sshin if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) { 139055163Sshin /* same interface found */ 139155163Sshin /* need check if something changed */ 139255163Sshin /* XXX not yet implemented */ 139355163Sshin return; 139455163Sshin } 139555163Sshin /* 139655163Sshin * New address is found 139755163Sshin */ 139855163Sshin if ((ifa = MALLOC(struct ifac)) == NULL) 139955163Sshin fatal("malloc: struct ifac"); 140062607Sitojun memset(ifa, 0, sizeof(*ifa)); 140155163Sshin ifa->ifa_conf = ifcp; 140255163Sshin ifa->ifa_next = ifcp->ifc_addr; 140355163Sshin ifcp->ifc_addr = ifa; 140455163Sshin ifa->ifa_addr = sin->sin6_addr; 140555163Sshin ifa->ifa_plen = plen; 140655163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 140755163Sshin ifr.ifr_addr = *sin; 140855163Sshin if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) 140955163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 141055163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 141155163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 141255163Sshin trace(1, "found address %s/%d -- %s\n", 141355163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 141455163Sshin } else { 141555163Sshin trace(1, "found address %s/%d\n", 141655163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 141755163Sshin } 141855163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 141955163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 142055163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 142155163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 142255163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 142355163Sshin ifcp->ifc_index); 142455163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 142555163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 142655163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 142755163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 142855163Sshin if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) 142955163Sshin fatal("ioctl: SIOCGIFMETRIC"); 143055163Sshin ifcp->ifc_metric = ifr.ifr_metric; 143155163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 143255163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 143355163Sshin } 143455163Sshin} 143555163Sshin 143655163Sshin/* 143755163Sshin * Receive and process routing messages. 143855163Sshin * Update interface information as necesssary. 143955163Sshin */ 144055163Sshinvoid 144155163Sshinrtrecv() 144255163Sshin{ 144355163Sshin char buf[BUFSIZ]; 144455163Sshin char *p, *q; 144555163Sshin struct rt_msghdr *rtm; 144655163Sshin struct ifa_msghdr *ifam; 144755163Sshin struct if_msghdr *ifm; 144855163Sshin int len; 144955163Sshin struct ifc *ifcp; 145055163Sshin int iface = 0, rtable = 0; 145155163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 145255163Sshin int i, addrs; 145355163Sshin 145455163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 145555163Sshin perror("read from rtsock"); 145655163Sshin exit(-1); 145755163Sshin } 145855163Sshin if (len < sizeof(*rtm)) { 145955163Sshin trace(1, "short read from rtsock: %d (should be > %d)\n", 146055163Sshin len, sizeof(*rtm)); 146155163Sshin return; 146255163Sshin } 146355163Sshin 146455163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 146555163Sshin /* safety against bogus message */ 146655163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 146755163Sshin trace(1, "bogus rtmsg: length=%d\n", 146855163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 146955163Sshin break; 147055163Sshin } 147155163Sshin rtm = NULL; 147255163Sshin ifam = NULL; 147355163Sshin ifm = NULL; 147455163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 147555163Sshin case RTM_NEWADDR: 147655163Sshin case RTM_DELADDR: 147755163Sshin ifam = (struct ifa_msghdr *)p; 147855163Sshin addrs = ifam->ifam_addrs; 147955163Sshin q = (char *)(ifam + 1); 148055163Sshin break; 148155163Sshin case RTM_IFINFO: 148255163Sshin ifm = (struct if_msghdr *)p; 148355163Sshin addrs = ifm->ifm_addrs; 148455163Sshin q = (char *)(ifm + 1); 148555163Sshin break; 148655163Sshin default: 148755163Sshin rtm = (struct rt_msghdr *)p; 148855163Sshin addrs = rtm->rtm_addrs; 148955163Sshin q = (char *)(rtm + 1); 149055163Sshin if (rtm->rtm_version != RTM_VERSION) { 149155163Sshin trace(1, "unexpected rtmsg version %d " 149255163Sshin "(should be %d)\n", 149355163Sshin rtm->rtm_version, RTM_VERSION); 149455163Sshin continue; 149555163Sshin } 149655163Sshin if (rtm->rtm_pid == pid) { 149755163Sshin#if 0 149855163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 149955163Sshin#endif 150055163Sshin continue; 150155163Sshin } 150255163Sshin break; 150355163Sshin } 150455163Sshin memset(&rta, 0, sizeof(rta)); 150555163Sshin for (i = 0; i < RTAX_MAX; i++) { 150655163Sshin if (addrs & (1 << i)) { 150755163Sshin rta[i] = (struct sockaddr_in6 *)q; 150855163Sshin q += ROUNDUP(rta[i]->sin6_len); 150955163Sshin } 151055163Sshin } 151155163Sshin 151255163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 151355163Sshin rttypes((struct rt_msghdr *)p), addrs); 151455163Sshin if (dflag >= 2) { 151555163Sshin int i; 151655163Sshin for (i = 0; 151755163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 151855163Sshin i++) { 151955163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 152055163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 152155163Sshin } 152255163Sshin fprintf(stderr, "\n"); 152355163Sshin } 152455163Sshin 152555163Sshin /* 152655163Sshin * Easy ones first. 152755163Sshin * 152855163Sshin * We may be able to optimize by using ifm->ifm_index or 152955163Sshin * ifam->ifam_index. For simplicity we don't do that here. 153055163Sshin */ 153155163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 153255163Sshin case RTM_NEWADDR: 153355163Sshin case RTM_IFINFO: 153455163Sshin iface++; 153555163Sshin continue; 153655163Sshin case RTM_ADD: 153755163Sshin rtable++; 153855163Sshin continue; 153955163Sshin case RTM_LOSING: 154055163Sshin case RTM_MISS: 154155163Sshin case RTM_RESOLVE: 154255163Sshin case RTM_GET: 154355163Sshin case RTM_LOCK: 154455163Sshin /* nothing to be done here */ 154555163Sshin trace(1, "\tnothing to be done, ignored\n"); 154655163Sshin continue; 154755163Sshin } 154855163Sshin 154955163Sshin#if 0 155055163Sshin if (rta[RTAX_DST] == NULL) { 155155163Sshin trace(1, "\tno destination, ignored\n"); 155262607Sitojun continue; 155355163Sshin } 155455163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 155555163Sshin trace(1, "\taf mismatch, ignored\n"); 155655163Sshin continue; 155755163Sshin } 155855163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 155955163Sshin trace(1, "\tlinklocal destination, ignored\n"); 156055163Sshin continue; 156155163Sshin } 156255163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 156355163Sshin trace(1, "\tloopback destination, ignored\n"); 156455163Sshin continue; /* Loopback */ 156555163Sshin } 156655163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 156755163Sshin trace(1, "\tmulticast destination, ignored\n"); 156855163Sshin continue; 156955163Sshin } 157055163Sshin#endif 157155163Sshin 157255163Sshin /* hard ones */ 157355163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 157455163Sshin case RTM_NEWADDR: 157555163Sshin case RTM_IFINFO: 157655163Sshin case RTM_ADD: 157755163Sshin case RTM_LOSING: 157855163Sshin case RTM_MISS: 157955163Sshin case RTM_RESOLVE: 158055163Sshin case RTM_GET: 158155163Sshin case RTM_LOCK: 158255163Sshin /* should already be handled */ 158355163Sshin fatal("rtrecv: never reach here"); 158455163Sshin case RTM_DELETE: 158555163Sshin if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY] 158655163Sshin || !rta[RTAX_NETMASK]) { 158755163Sshin trace(1, "\tsome of dst/gw/netamsk are unavailable, ignored\n"); 158855163Sshin break; 158955163Sshin } 159055163Sshin if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], rta[RTAX_NETMASK]) == 0) { 159155163Sshin rtable++; /*just to be sure*/ 159255163Sshin } 159355163Sshin break; 159455163Sshin case RTM_CHANGE: 159555163Sshin case RTM_REDIRECT: 159655163Sshin trace(1, "\tnot supported yet, ignored\n"); 159755163Sshin break; 159855163Sshin case RTM_DELADDR: 159955163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 160055163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 160155163Sshin break; 160255163Sshin } 160355163Sshin if (ifam->ifam_index < nindex2ifc) 160455163Sshin ifcp = index2ifc[ifam->ifam_index]; 160555163Sshin else 160655163Sshin ifcp = NULL; 160755163Sshin if (!ifcp) { 160855163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 160955163Sshin ifam->ifam_index); 161055163Sshin break; 161155163Sshin } 161255163Sshin rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]); 161355163Sshin iface++; 161455163Sshin break; 161555163Sshin case RTM_OLDADD: 161655163Sshin case RTM_OLDDEL: 161755163Sshin trace(1, "\tnot supported yet, ignored\n"); 161855163Sshin break; 161955163Sshin } 162055163Sshin 162155163Sshin } 162255163Sshin 162355163Sshin if (iface) { 162455163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 162555163Sshin ifconfig(); 162655163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 162755163Sshin ifrt(ifcp, 1); 162855163Sshin } 162955163Sshin if (rtable) { 163055163Sshin trace(1, "rtsock: read routing table again\n"); 163155163Sshin krtread(1); 163255163Sshin } 163355163Sshin} 163455163Sshin 163555163Sshin/* 163655163Sshin * remove specified route from the internal routing table. 163755163Sshin */ 163855163Sshinint 163955163Sshinrt_del(sdst, sgw, smask) 164055163Sshin const struct sockaddr_in6 *sdst; 164155163Sshin const struct sockaddr_in6 *sgw; 164255163Sshin const struct sockaddr_in6 *smask; 164355163Sshin{ 164455163Sshin const struct in6_addr *dst = NULL; 164555163Sshin const struct in6_addr *gw = NULL; 164655163Sshin int prefix; 164755163Sshin struct netinfo6 ni6; 164855163Sshin struct riprt *rrt = NULL; 164955163Sshin time_t t_lifetime; 165055163Sshin 165155163Sshin if (sdst->sin6_family != AF_INET6) { 165255163Sshin trace(1, "\tother AF, ignored\n"); 165355163Sshin return -1; 165455163Sshin } 165555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 165655163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 165755163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 165855163Sshin trace(1, "\taddress %s not interesting, ignored\n", 165955163Sshin inet6_n2p(&sdst->sin6_addr)); 166055163Sshin return -1; 166155163Sshin } 166255163Sshin dst = &sdst->sin6_addr; 166355163Sshin if (sgw->sin6_family == AF_INET6 166455163Sshin && smask->sin6_family == AF_INET6) { 166555163Sshin /* easy case */ 166655163Sshin gw = &sgw->sin6_addr; 166755163Sshin prefix = mask2len(&smask->sin6_addr, 16); 166855163Sshin } else if (sgw->sin6_family == AF_LINK) { 166955163Sshin /* 167055163Sshin * Interface route... a hard case. We need to get the prefix 167155163Sshin * length from the kernel, but we now are parsing rtmsg. 167255163Sshin * We'll purge matching routes from my list, then get the 167355163Sshin * fresh list. 167455163Sshin */ 167555163Sshin struct riprt *longest; 167655163Sshin trace(1, "\t%s is a interface route, guessing prefixlen\n", 167755163Sshin inet6_n2p(dst)); 167855163Sshin longest = NULL; 167955163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 168055163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 168155163Sshin &sdst->sin6_addr) 168255163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 168355163Sshin if (!longest 168455163Sshin || longest->rrt_info.rip6_plen < 168555163Sshin rrt->rrt_info.rip6_plen) { 168655163Sshin longest = rrt; 168755163Sshin } 168855163Sshin } 168955163Sshin } 169055163Sshin rrt = longest; 169155163Sshin if (!rrt) { 169255163Sshin trace(1, "\tno matching interface route found\n"); 169355163Sshin return -1; 169455163Sshin } 169555163Sshin gw = &in6addr_loopback; 169655163Sshin prefix = rrt->rrt_info.rip6_plen; 169755163Sshin } else { 169862607Sitojun trace(1, "\tunsupported af: (gw=%d, mask=%d)\n", 169955163Sshin sgw->sin6_family, smask->sin6_family); 170055163Sshin return -1; 170155163Sshin } 170255163Sshin 170355163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 170455163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 170555163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 170655163Sshin /* age route for interface address */ 170755163Sshin memset(&ni6, 0, sizeof(ni6)); 170855163Sshin ni6.rip6_dest = *dst; 170955163Sshin ni6.rip6_plen = prefix; 171055163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 171155163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 171255163Sshin ni6.rip6_plen); 171355163Sshin if (!rrt && (rrt = rtsearch(&ni6)) == NULL) { 171455163Sshin trace(1, "\tno route found\n"); 171555163Sshin return -1; 171655163Sshin } 171755163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 171855163Sshin trace(1, "\tyou can delete static routes only\n"); 171955163Sshin } else if (memcmp(&rrt->rrt_gw, gw, sizeof(rrt->rrt_gw)) != 0) { 172055163Sshin trace(1, "\tgw mismatch: %s <-> ", 172155163Sshin inet6_n2p(&rrt->rrt_gw)); 172255163Sshin trace(1, "%s\n", inet6_n2p(gw)); 172355163Sshin } else { 172455163Sshin trace(1, "\troute found, age it\n"); 172555163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 172655163Sshin rrt->rrt_t = t_lifetime; 172755163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 172855163Sshin } 172955163Sshin } 173055163Sshin return 0; 173155163Sshin} 173255163Sshin 173355163Sshin/* 173455163Sshin * remove specified address from internal interface/routing table. 173555163Sshin */ 173655163Sshinint 173755163Sshinrt_deladdr(ifcp, sifa, smask) 173855163Sshin struct ifc *ifcp; 173955163Sshin const struct sockaddr_in6 *sifa; 174055163Sshin const struct sockaddr_in6 *smask; 174155163Sshin{ 174255163Sshin const struct in6_addr *addr = NULL; 174355163Sshin int prefix; 174455163Sshin struct ifac *ifa = NULL; 174555163Sshin struct netinfo6 ni6; 174655163Sshin struct riprt *rrt = NULL; 174755163Sshin time_t t_lifetime; 174855163Sshin int updated = 0; 174955163Sshin 175055163Sshin if (sifa->sin6_family != AF_INET6 || smask->sin6_family != AF_INET6) { 175155163Sshin trace(1, "\tother AF, ignored\n"); 175255163Sshin return -1; 175355163Sshin } 175455163Sshin addr = &sifa->sin6_addr; 175555163Sshin prefix = mask2len(&smask->sin6_addr, 16); 175655163Sshin 175755163Sshin trace(1, "\tdeleting %s/%d from %s\n", 175855163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 175955163Sshin ifa = ifa_match(ifcp, addr, prefix); 176055163Sshin if (!ifa) { 176155163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 176255163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 176355163Sshin return -1; 176455163Sshin } 176555163Sshin if (ifa->ifa_conf != ifcp) { 176655163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 176755163Sshin "(%s != %s)\n", 176855163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 176955163Sshin return -1; 177055163Sshin } 177155163Sshin /* remove ifa from interface */ 177255163Sshin if (ifcp->ifc_addr == ifa) 177355163Sshin ifcp->ifc_addr = ifa->ifa_next; 177455163Sshin else { 177555163Sshin struct ifac *p; 177655163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 177755163Sshin if (p->ifa_next == ifa) { 177855163Sshin p->ifa_next = ifa->ifa_next; 177955163Sshin break; 178055163Sshin } 178155163Sshin } 178255163Sshin } 178355163Sshin ifa->ifa_next = NULL; 178455163Sshin ifa->ifa_conf = NULL; 178555163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 178655163Sshin /* age route for interface address */ 178755163Sshin memset(&ni6, 0, sizeof(ni6)); 178855163Sshin ni6.rip6_dest = ifa->ifa_addr; 178955163Sshin ni6.rip6_plen = ifa->ifa_plen; 179055163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 179155163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 179255163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 179355163Sshin if ((rrt = rtsearch(&ni6)) != NULL) { 179455163Sshin struct in6_addr none; 179555163Sshin memset(&none, 0, sizeof(none)); 179655163Sshin if (rrt->rrt_index == ifcp->ifc_index 179755163Sshin && memcmp(&rrt->rrt_gw, &none, sizeof(rrt->rrt_gw)) == 0) { 179855163Sshin trace(1, "\troute found, age it\n"); 179955163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 180055163Sshin rrt->rrt_t = t_lifetime; 180155163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 180255163Sshin } 180355163Sshin updated++; 180455163Sshin } else { 180555163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 180655163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 180755163Sshin rrt->rrt_info.rip6_plen, 180855163Sshin rrt->rrt_index); 180955163Sshin } 181055163Sshin } else 181155163Sshin trace(1, "\tno interface route found\n"); 181255163Sshin /* age route for p2p destination */ 181355163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 181455163Sshin memset(&ni6, 0, sizeof(ni6)); 181555163Sshin ni6.rip6_dest = ifa->ifa_raddr; 181655163Sshin ni6.rip6_plen = 128; 181755163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 181855163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 181955163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 182055163Sshin ifcp->ifc_index); 182155163Sshin if ((rrt = rtsearch(&ni6)) != NULL) { 182255163Sshin if (rrt->rrt_index == ifcp->ifc_index 182355163Sshin && memcmp(&rrt->rrt_gw, &ifa->ifa_addr, 182455163Sshin sizeof(rrt->rrt_gw)) == 0) { 182555163Sshin trace(1, "\troute found, age it\n"); 182655163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 182755163Sshin rrt->rrt_t = t_lifetime; 182855163Sshin rrt->rrt_info.rip6_metric = 182955163Sshin HOPCNT_INFINITY6; 183055163Sshin updated++; 183155163Sshin } 183255163Sshin } else { 183355163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 183455163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 183555163Sshin rrt->rrt_info.rip6_plen, 183655163Sshin rrt->rrt_index); 183755163Sshin } 183855163Sshin } else 183955163Sshin trace(1, "\tno p2p route found\n"); 184055163Sshin } 184155163Sshin return updated ? 0 : -1; 184255163Sshin} 184355163Sshin 184455163Sshin/* 184555163Sshin * Get each interface address and put those interface routes to the route 184655163Sshin * list. 184755163Sshin */ 184855163Sshinvoid 184955163Sshinifrt(ifcp, again) 185062607Sitojun struct ifc *ifcp; 185155163Sshin int again; 185255163Sshin{ 185362607Sitojun struct ifac *ifa; 185462607Sitojun struct riprt *rrt; 185562607Sitojun struct netinfo6 *np; 185655163Sshin 185755163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 185855163Sshin return; /* ignore loopback */ 185962607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 186062607Sitojun ifrt_p2p(ifcp, again); 186162607Sitojun return; 186262607Sitojun } 186362607Sitojun 186455163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 186562607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 186662607Sitojun#if 0 186762607Sitojun trace(1, "route: %s on %s: " 186862607Sitojun "skip linklocal interface address\n", 186962607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 187062607Sitojun#endif 187162607Sitojun continue; 187262607Sitojun } 187362607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 187462607Sitojun#if 0 187562607Sitojun trace(1, "route: %s: skip unspec interface address\n", 187662607Sitojun ifcp->ifc_name); 187762607Sitojun#endif 187862607Sitojun continue; 187962607Sitojun } 188055163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 188155163Sshin fatal("malloc: struct riprt"); 188262607Sitojun memset(rrt, 0, sizeof(*rrt)); 188355163Sshin rrt->rrt_same = NULL; 188455163Sshin rrt->rrt_index = ifcp->ifc_index; 188555163Sshin rrt->rrt_t = 0; /* don't age */ 188655163Sshin rrt->rrt_info.rip6_dest = ifa->ifa_addr; 188755163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 188855163Sshin rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 188955163Sshin rrt->rrt_info.rip6_plen = ifa->ifa_plen; 189055163Sshin applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 189155163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 189255163Sshin np = &rrt->rrt_info; 189355163Sshin if (rtsearch(np) == NULL) { 189455163Sshin /* Attach the route to the list */ 189562607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 189662607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 189762607Sitojun ifcp->ifc_name); 189855163Sshin rrt->rrt_next = riprt; 189955163Sshin riprt = rrt; 190055163Sshin } else { 190155163Sshin /* Already found */ 190255163Sshin if (!again) { 190362607Sitojun trace(1, "route: %s/%d: " 190462607Sitojun "already registered (%s)\n", 190562607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 190662607Sitojun ifcp->ifc_name); 190755163Sshin } 190855163Sshin free(rrt); 190955163Sshin } 191062607Sitojun } 191162607Sitojun} 191255163Sshin 191362607Sitojun/* 191462607Sitojun * there are couple of p2p interface routing models. "behavior" lets 191562607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 191662607Sitojun * since BSD kernels does not look at prefix length on p2p interfaces. 191762607Sitojun */ 191862607Sitojunvoid 191962607Sitojunifrt_p2p(ifcp, again) 192062607Sitojun struct ifc *ifcp; 192162607Sitojun int again; 192262607Sitojun{ 192362607Sitojun struct ifac *ifa; 192462607Sitojun struct riprt *rrt; 192562607Sitojun struct netinfo6 *np; 192662607Sitojun struct in6_addr addr, dest; 192762607Sitojun int advert, ignore, i; 192862607Sitojun#define P2PADVERT_NETWORK 1 192962607Sitojun#define P2PADVERT_ADDR 2 193062607Sitojun#define P2PADVERT_DEST 4 193162607Sitojun#define P2PADVERT_MAX 4 193262607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 193362607Sitojun const char *category; 193462607Sitojun const char *noadv; 193562607Sitojun 193662607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 193762607Sitojun addr = ifa->ifa_addr; 193862607Sitojun dest = ifa->ifa_raddr; 193962607Sitojun applyplen(&addr, ifa->ifa_plen); 194062607Sitojun applyplen(&dest, ifa->ifa_plen); 194162607Sitojun advert = ignore = 0; 194262607Sitojun switch (behavior) { 194362607Sitojun case CISCO: 194462607Sitojun /* 194562607Sitojun * honor addr/plen, just like normal shared medium 194662607Sitojun * interface. this may cause trouble if you reuse 194762607Sitojun * addr/plen on other interfaces. 194862607Sitojun * 194962607Sitojun * advertise addr/plen. 195062607Sitojun */ 195162607Sitojun advert |= P2PADVERT_NETWORK; 195262607Sitojun break; 195362607Sitojun case GATED: 195462607Sitojun /* 195562607Sitojun * prefixlen on p2p interface is meaningless. 195662607Sitojun * advertise addr/128 and dest/128. 195762607Sitojun * 195862607Sitojun * do not install network route to route6d routing 195962607Sitojun * table (if we do, it would prevent route installation 196062607Sitojun * for other p2p interface that shares addr/plen). 196162607Sitojun */ 196262607Sitojun advert |= P2PADVERT_ADDR; 196362607Sitojun advert |= P2PADVERT_DEST; 196462607Sitojun ignore |= P2PADVERT_NETWORK; 196562607Sitojun break; 196662607Sitojun case ROUTE6D: 196762607Sitojun /* 196862607Sitojun * just for testing... 196962607Sitojun */ 197062607Sitojun if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 197162607Sitojun advert |= P2PADVERT_NETWORK; 197262607Sitojun else { 197362607Sitojun advert |= P2PADVERT_ADDR; 197462607Sitojun advert |= P2PADVERT_DEST; 197562607Sitojun ignore |= P2PADVERT_NETWORK; 197662607Sitojun } 197762607Sitojun break; 197862607Sitojun } 197962607Sitojun 198062607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 198162607Sitojun if ((ignore & i) != 0) 198262607Sitojun continue; 198355163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 198455163Sshin fatal("malloc: struct riprt"); 198562607Sitojun memset(rrt, 0, sizeof(*rrt)); 198655163Sshin rrt->rrt_same = NULL; 198755163Sshin rrt->rrt_index = ifcp->ifc_index; 198862607Sitojun rrt->rrt_t = 0; /* don't age */ 198962607Sitojun switch (i) { 199062607Sitojun case P2PADVERT_NETWORK: 199162607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 199262607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 199362607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 199462607Sitojun ifa->ifa_plen); 199562607Sitojun category = "network"; 199662607Sitojun break; 199762607Sitojun case P2PADVERT_ADDR: 199862607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 199962607Sitojun rrt->rrt_info.rip6_plen = 128; 200062607Sitojun category = "addr"; 200162607Sitojun break; 200262607Sitojun case P2PADVERT_DEST: 200362607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 200462607Sitojun rrt->rrt_info.rip6_plen = 128; 200562607Sitojun category = "dest"; 200662607Sitojun break; 200762607Sitojun } 200862607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 200962607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 201062607Sitojun#if 0 201162607Sitojun trace(1, "route: %s: skip unspec/linklocal " 201262607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 201362607Sitojun#endif 201462607Sitojun free(rrt); 201562607Sitojun continue; 201662607Sitojun } 201762607Sitojun if ((advert & i) == 0) { 201862607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 201962607Sitojun noadv = ", NO-ADV"; 202062607Sitojun } else 202162607Sitojun noadv = ""; 202255163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 202362607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 202462607Sitojun memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 202555163Sshin np = &rrt->rrt_info; 202655163Sshin if (rtsearch(np) == NULL) { 202755163Sshin /* Attach the route to the list */ 202862607Sitojun trace(1, "route: %s/%d: register route " 202962607Sitojun "(%s on %s%s)\n", 203062607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 203162607Sitojun category, ifcp->ifc_name, noadv); 203255163Sshin rrt->rrt_next = riprt; 203355163Sshin riprt = rrt; 203455163Sshin } else { 203555163Sshin /* Already found */ 203655163Sshin if (!again) { 203762607Sitojun trace(1, "route: %s/%d: " 203862607Sitojun "already registered (%s on %s%s)\n", 203962607Sitojun inet6_n2p(&np->rip6_dest), 204062607Sitojun np->rip6_plen, category, 204162607Sitojun ifcp->ifc_name, noadv); 204255163Sshin } 204355163Sshin free(rrt); 204455163Sshin } 204555163Sshin } 204655163Sshin } 204762607Sitojun#undef P2PADVERT_NETWORK 204862607Sitojun#undef P2PADVERT_ADDR 204962607Sitojun#undef P2PADVERT_DEST 205062607Sitojun#undef P2PADVERT_MAX 205155163Sshin} 205255163Sshin 205355163Sshinint 205455163Sshingetifmtu(ifindex) 205555163Sshin int ifindex; 205655163Sshin{ 205755163Sshin int mib[6]; 205855163Sshin char *buf; 205955163Sshin size_t msize; 206055163Sshin struct if_msghdr *ifm; 206155163Sshin int mtu; 206255163Sshin 206355163Sshin mib[0] = CTL_NET; 206455163Sshin mib[1] = PF_ROUTE; 206555163Sshin mib[2] = 0; 206655163Sshin mib[3] = AF_INET6; 206755163Sshin mib[4] = NET_RT_IFLIST; 206855163Sshin mib[5] = ifindex; 206955163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) 207055163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 207155163Sshin if ((buf = malloc(msize)) == NULL) 207255163Sshin fatal("malloc"); 207355163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) 207455163Sshin fatal("sysctl NET_RT_IFLIST"); 207555163Sshin ifm = (struct if_msghdr *)buf; 207655163Sshin mtu = ifm->ifm_data.ifi_mtu; 207755163Sshin#ifdef __FREEBSD__ 207855163Sshin if (ifindex != ifm->ifm_index) 207955163Sshin fatal("ifindex does not match with ifm_index"); 208055163Sshin#endif /* __FREEBSD__ */ 208155163Sshin free(buf); 208255163Sshin return mtu; 208355163Sshin} 208455163Sshin 208555163Sshinconst char * 208655163Sshinrttypes(rtm) 208755163Sshin struct rt_msghdr *rtm; 208855163Sshin{ 208962607Sitojun#define RTTYPE(s, f) \ 209062607Sitojundo { \ 209162607Sitojun if (rtm->rtm_type == (f)) \ 209262607Sitojun return (s); \ 209362607Sitojun} while (0) 209455163Sshin RTTYPE("ADD", RTM_ADD); 209555163Sshin RTTYPE("DELETE", RTM_DELETE); 209655163Sshin RTTYPE("CHANGE", RTM_CHANGE); 209755163Sshin RTTYPE("GET", RTM_GET); 209855163Sshin RTTYPE("LOSING", RTM_LOSING); 209955163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 210055163Sshin RTTYPE("MISS", RTM_MISS); 210155163Sshin RTTYPE("LOCK", RTM_LOCK); 210255163Sshin RTTYPE("OLDADD", RTM_OLDADD); 210355163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 210455163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 210555163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 210655163Sshin RTTYPE("DELADDR", RTM_DELADDR); 210755163Sshin RTTYPE("IFINFO", RTM_IFINFO); 210855163Sshin#undef RTTYPE 210955163Sshin return NULL; 211055163Sshin} 211155163Sshin 211255163Sshinconst char * 211355163Sshinrtflags(rtm) 211455163Sshin struct rt_msghdr *rtm; 211555163Sshin{ 211655163Sshin static char buf[BUFSIZ]; 211755163Sshin 211855163Sshin strcpy(buf, ""); 211962607Sitojun#define RTFLAG(s, f) \ 212062607Sitojundo { \ 212162607Sitojun if (rtm->rtm_flags & (f)) \ 212262607Sitojun strcat(buf, (s)); \ 212362607Sitojun} while (0) 212455163Sshin RTFLAG("U", RTF_UP); 212555163Sshin RTFLAG("G", RTF_GATEWAY); 212655163Sshin RTFLAG("H", RTF_HOST); 212755163Sshin RTFLAG("R", RTF_REJECT); 212855163Sshin RTFLAG("D", RTF_DYNAMIC); 212955163Sshin RTFLAG("M", RTF_MODIFIED); 213055163Sshin RTFLAG("d", RTF_DONE); 213155163Sshin#ifdef RTF_MASK 213255163Sshin RTFLAG("m", RTF_MASK); 213355163Sshin#endif 213455163Sshin RTFLAG("C", RTF_CLONING); 213555163Sshin RTFLAG("X", RTF_XRESOLVE); 213655163Sshin RTFLAG("L", RTF_LLINFO); 213755163Sshin RTFLAG("S", RTF_STATIC); 213855163Sshin RTFLAG("B", RTF_BLACKHOLE); 213955163Sshin RTFLAG("2", RTF_PROTO2); 214055163Sshin RTFLAG("1", RTF_PROTO1); 214155163Sshin#undef RTFLAG 214255163Sshin return buf; 214355163Sshin} 214455163Sshin 214555163Sshinconst char * 214655163Sshinifflags(flags) 214755163Sshin int flags; 214855163Sshin{ 214955163Sshin static char buf[BUFSIZ]; 215055163Sshin 215155163Sshin strcpy(buf, ""); 215262607Sitojun#define IFFLAG(s, f) \ 215362607Sitojundo { \ 215462607Sitojun if (flags & f) { \ 215562607Sitojun if (buf[0]) \ 215662607Sitojun strcat(buf, ","); \ 215762607Sitojun strcat(buf, s); \ 215862607Sitojun } \ 215962607Sitojun} while (0) 216055163Sshin IFFLAG("UP", IFF_UP); 216155163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 216255163Sshin IFFLAG("DEBUG", IFF_DEBUG); 216355163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 216455163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 216555163Sshin#ifdef IFF_NOTRAILERS 216655163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 216755163Sshin#endif 216855163Sshin IFFLAG("RUNNING", IFF_RUNNING); 216955163Sshin IFFLAG("NOARP", IFF_NOARP); 217055163Sshin IFFLAG("PROMISC", IFF_PROMISC); 217155163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 217255163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 217355163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 217455163Sshin IFFLAG("LINK0", IFF_LINK0); 217555163Sshin IFFLAG("LINK1", IFF_LINK1); 217655163Sshin IFFLAG("LINK2", IFF_LINK2); 217755163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 217855163Sshin#undef IFFLAG 217955163Sshin return buf; 218055163Sshin} 218155163Sshin 218255163Sshinvoid 218355163Sshinkrtread(again) 218455163Sshin int again; 218555163Sshin{ 218655163Sshin int mib[6]; 218755163Sshin size_t msize; 218855163Sshin char *buf, *p, *lim; 218955163Sshin struct rt_msghdr *rtm; 219055163Sshin int retry; 219155163Sshin const char *errmsg; 219255163Sshin 219355163Sshin retry = 0; 219455163Sshin buf = NULL; 219555163Sshin mib[0] = CTL_NET; 219655163Sshin mib[1] = PF_ROUTE; 219755163Sshin mib[2] = 0; 219855163Sshin mib[3] = AF_INET6; /* Address family */ 219955163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 220055163Sshin mib[5] = 0; /* No flags */ 220155163Sshin do { 220255163Sshin retry++; 220355163Sshin errmsg = NULL; 220455163Sshin if (buf) 220555163Sshin free(buf); 220655163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 220755163Sshin errmsg = "sysctl estimate"; 220855163Sshin continue; 220955163Sshin } 221055163Sshin if ((buf = malloc(msize)) == NULL) { 221155163Sshin errmsg = "malloc"; 221255163Sshin continue; 221355163Sshin } 221455163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 221555163Sshin errmsg = "sysctl NET_RT_DUMP"; 221655163Sshin continue; 221755163Sshin } 221855163Sshin } while (retry < 5 && errmsg != NULL); 221955163Sshin if (errmsg) 222055163Sshin fatal("%s (with %d retries, msize=%d)", errmsg, retry, msize); 222155163Sshin else if (1 < retry) 222255163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 222355163Sshin 222455163Sshin lim = buf + msize; 222555163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 222655163Sshin rtm = (struct rt_msghdr *)p; 222755163Sshin rt_entry(rtm, again); 222855163Sshin } 222955163Sshin free(buf); 223055163Sshin} 223155163Sshin 223255163Sshinvoid 223355163Sshinrt_entry(rtm, again) 223455163Sshin struct rt_msghdr *rtm; 223555163Sshin int again; 223655163Sshin{ 223755163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 223855163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 223955163Sshin char *rtmp, *ifname = NULL; 224055163Sshin struct riprt *rrt; 224155163Sshin struct netinfo6 *np; 224255163Sshin int s; 224355163Sshin 224455163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 224555163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 224662607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 224755163Sshin return; /* not interested in the link route */ 224862607Sitojun } 224955163Sshin rtmp = (char *)(rtm + 1); 225055163Sshin /* Destination */ 225155163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 225255163Sshin return; /* ignore routes without destination address */ 225355163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 225455163Sshin rtmp += sin6_dst->sin6_len; 225555163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 225655163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 225755163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 225855163Sshin } 225955163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 226055163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 226155163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 226255163Sshin } 226355163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 226455163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 226555163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 226655163Sshin } 226755163Sshin if (rtm->rtm_addrs & RTA_IFP) { 226855163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 226955163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 227055163Sshin } 227155163Sshin 227255163Sshin /* Destination */ 227355163Sshin if (sin6_dst->sin6_family != AF_INET6) 227455163Sshin return; 227555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 227655163Sshin return; /* Link-local */ 227755163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 227855163Sshin return; /* Loopback */ 227955163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 228055163Sshin return; 228155163Sshin 228255163Sshin if ((rrt = MALLOC(struct riprt)) == NULL) 228355163Sshin fatal("malloc: struct riprt"); 228462607Sitojun memset(rrt, 0, sizeof(*rrt)); 228555163Sshin np = &rrt->rrt_info; 228655163Sshin rrt->rrt_same = NULL; 228755163Sshin rrt->rrt_t = time(NULL); 228855163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 228955163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 229055163Sshin#if 0 229155163Sshin np->rip6_tag = htons(routetag & 0xffff); 229255163Sshin#else 229355163Sshin np->rip6_tag = 0; 229455163Sshin#endif 229555163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 229655163Sshin if (np->rip6_metric < 1) 229755163Sshin np->rip6_metric = 1; 229855163Sshin rrt->rrt_flags = rtm->rtm_flags; 229955163Sshin np->rip6_dest = sin6_dst->sin6_addr; 230055163Sshin 230155163Sshin /* Mask or plen */ 230255163Sshin if (rtm->rtm_flags & RTF_HOST) 230355163Sshin np->rip6_plen = 128; /* Host route */ 230455163Sshin else if (sin6_mask) { 230555163Sshin np->rip6_plen = mask2len(&sin6_mask->sin6_addr, 230655163Sshin sin6_mask->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 230755163Sshin } else 230855163Sshin np->rip6_plen = 0; 230955163Sshin 231055163Sshin if (rtsearch(np)) { 231155163Sshin /* Already found */ 231255163Sshin if (!again) { 231355163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 231455163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 231555163Sshin rtflags(rtm)); 231655163Sshin } 231755163Sshin free(rrt); 231855163Sshin return; 231955163Sshin } 232055163Sshin /* Gateway */ 232155163Sshin if (!sin6_gw) 232255163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 232355163Sshin else { 232455163Sshin if (sin6_gw->sin6_family == AF_INET6) 232555163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 232655163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 232755163Sshin /* XXX in case ppp link? */ 232855163Sshin rrt->rrt_gw = in6addr_loopback; 232955163Sshin } else 233055163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 233155163Sshin } 233255163Sshin trace(1, "route: %s/%d flags %s", 233355163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 233455163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 233555163Sshin 233655163Sshin /* Interface */ 233755163Sshin s = rtm->rtm_index; 233855163Sshin if (s < nindex2ifc && index2ifc[s]) 233955163Sshin ifname = index2ifc[s]->ifc_name; 234058070Sshin else { 234158070Sshin trace(1, " not configured\n"); 234262607Sitojun free(rrt); 234358070Sshin return; 234458070Sshin } 234562607Sitojun trace(1, " if %s sock %d", ifname, s); 234655163Sshin rrt->rrt_index = s; 234755163Sshin 234862607Sitojun trace(1, "\n"); 234962607Sitojun 235055163Sshin /* Check gateway */ 235155163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 235255163Sshin !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 235355163Sshin#ifdef __FreeBSD__ 235455163Sshin && (rrt->rrt_flags & RTF_LOCAL) == 0 235555163Sshin#endif 235655163Sshin ) { 235755163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 235855163Sshin inet6_n2p(&rrt->rrt_gw)); 235955163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 236062607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 236162607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 236255163Sshin } 236355163Sshin 236455163Sshin /* Put it to the route list */ 236555163Sshin rrt->rrt_next = riprt; 236655163Sshin riprt = rrt; 236755163Sshin} 236855163Sshin 236955163Sshinint 237055163Sshinaddroute(rrt, gw, ifcp) 237155163Sshin struct riprt *rrt; 237255163Sshin const struct in6_addr *gw; 237355163Sshin struct ifc *ifcp; 237455163Sshin{ 237555163Sshin struct netinfo6 *np; 237655163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 237755163Sshin struct rt_msghdr *rtm; 237855163Sshin struct sockaddr_in6 *sin; 237955163Sshin int len; 238055163Sshin 238155163Sshin np = &rrt->rrt_info; 238255163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf1, sizeof(buf1)); 238355163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 238455163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 238555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 238655163Sshin np->rip6_metric - 1, buf2); 238755163Sshin if (rtlog) 238855163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 238955163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 239055163Sshin np->rip6_metric - 1, buf2); 239155163Sshin if (nflag) 239255163Sshin return 0; 239355163Sshin 239455163Sshin memset(buf, 0, sizeof(buf)); 239555163Sshin rtm = (struct rt_msghdr *)buf; 239655163Sshin rtm->rtm_type = RTM_ADD; 239755163Sshin rtm->rtm_version = RTM_VERSION; 239855163Sshin rtm->rtm_seq = ++seq; 239955163Sshin rtm->rtm_pid = pid; 240062607Sitojun rtm->rtm_flags = rrt->rrt_flags; 240155163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 240255163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 240355163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 240455163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 240555163Sshin /* Destination */ 240655163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 240755163Sshin sin->sin6_family = AF_INET6; 240855163Sshin sin->sin6_addr = np->rip6_dest; 240955163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 241055163Sshin /* Gateway */ 241155163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 241255163Sshin sin->sin6_family = AF_INET6; 241355163Sshin sin->sin6_addr = *gw; 241455163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 241555163Sshin /* Netmask */ 241655163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 241755163Sshin sin->sin6_family = AF_INET6; 241855163Sshin sin->sin6_addr = *(plen2mask(np->rip6_plen)); 241955163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 242055163Sshin 242155163Sshin len = (char *)sin - (char *)buf; 242255163Sshin rtm->rtm_msglen = len; 242355163Sshin if (write(rtsock, buf, len) > 0) 242455163Sshin return 0; 242555163Sshin 242655163Sshin if (errno == EEXIST) { 242755163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 242855163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 242955163Sshin if (rtlog) 243055163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 243155163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 243255163Sshin } else { 243355163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 243455163Sshin strerror(errno)); 243555163Sshin if (rtlog) 243655163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 243755163Sshin strerror(errno)); 243855163Sshin } 243955163Sshin return -1; 244055163Sshin} 244155163Sshin 244255163Sshinint 244355163Sshindelroute(np, gw) 244455163Sshin struct netinfo6 *np; 244555163Sshin struct in6_addr *gw; 244655163Sshin{ 244755163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 244855163Sshin struct rt_msghdr *rtm; 244955163Sshin struct sockaddr_in6 *sin; 245055163Sshin int len; 245155163Sshin 245255163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 245355163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 245455163Sshin np->rip6_plen, buf2); 245555163Sshin if (rtlog) 245655163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 245755163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 245855163Sshin if (nflag) 245955163Sshin return 0; 246055163Sshin 246155163Sshin memset(buf, 0, sizeof(buf)); 246255163Sshin rtm = (struct rt_msghdr *)buf; 246355163Sshin rtm->rtm_type = RTM_DELETE; 246455163Sshin rtm->rtm_version = RTM_VERSION; 246555163Sshin rtm->rtm_seq = ++seq; 246655163Sshin rtm->rtm_pid = pid; 246755163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 246855163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 246955163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 247055163Sshin /* Destination */ 247155163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 247255163Sshin sin->sin6_family = AF_INET6; 247355163Sshin sin->sin6_addr = np->rip6_dest; 247455163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 247555163Sshin /* Gateway */ 247655163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 247755163Sshin sin->sin6_family = AF_INET6; 247855163Sshin sin->sin6_addr = *gw; 247955163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 248055163Sshin /* Netmask */ 248155163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 248255163Sshin sin->sin6_family = AF_INET6; 248355163Sshin sin->sin6_addr = *(plen2mask(np->rip6_plen)); 248455163Sshin sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len)); 248555163Sshin 248655163Sshin len = (char *)sin - (char *)buf; 248755163Sshin rtm->rtm_msglen = len; 248855163Sshin if (write(rtsock, buf, len) >= 0) 248955163Sshin return 0; 249055163Sshin 249155163Sshin if (errno == ESRCH) { 249255163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 249355163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 249455163Sshin if (rtlog) 249555163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 249655163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 249755163Sshin } else { 249855163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 249955163Sshin strerror(errno)); 250055163Sshin if (rtlog) 250155163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 250255163Sshin strerror(errno)); 250355163Sshin } 250455163Sshin return -1; 250555163Sshin} 250655163Sshin 250755163Sshinstruct in6_addr * 250855163Sshingetroute(np, gw) 250955163Sshin struct netinfo6 *np; 251055163Sshin struct in6_addr *gw; 251155163Sshin{ 251255163Sshin u_char buf[BUFSIZ]; 251355163Sshin u_long myseq; 251455163Sshin int len; 251555163Sshin struct rt_msghdr *rtm; 251655163Sshin struct sockaddr_in6 *sin; 251755163Sshin 251855163Sshin rtm = (struct rt_msghdr *)buf; 251955163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 252055163Sshin memset(rtm, 0, len); 252155163Sshin rtm->rtm_type = RTM_GET; 252255163Sshin rtm->rtm_version = RTM_VERSION; 252355163Sshin myseq = ++seq; 252455163Sshin rtm->rtm_seq = myseq; 252555163Sshin rtm->rtm_addrs = RTA_DST; 252655163Sshin rtm->rtm_msglen = len; 252755163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 252855163Sshin sin->sin6_len = sizeof(struct sockaddr_in6); 252955163Sshin sin->sin6_family = AF_INET6; 253055163Sshin sin->sin6_addr = np->rip6_dest; 253155163Sshin if (write(rtsock, buf, len) < 0) { 253255163Sshin if (errno == ESRCH) /* No such route found */ 253355163Sshin return NULL; 253455163Sshin perror("write to rtsock"); 253555163Sshin exit(-1); 253655163Sshin } 253755163Sshin do { 253855163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 253955163Sshin perror("read from rtsock"); 254055163Sshin exit(-1); 254155163Sshin } 254255163Sshin rtm = (struct rt_msghdr *)buf; 254355163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 254455163Sshin sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 254555163Sshin if (rtm->rtm_addrs & RTA_DST) { 254655163Sshin sin = (struct sockaddr_in6 *) 254755163Sshin ((char *)sin + ROUNDUP(sin->sin6_len)); 254855163Sshin } 254955163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 255055163Sshin *gw = sin->sin6_addr; 255155163Sshin return gw; 255255163Sshin } 255355163Sshin return NULL; 255455163Sshin} 255555163Sshin 255655163Sshinconst char * 255755163Sshininet6_n2p(p) 255855163Sshin const struct in6_addr *p; 255955163Sshin{ 256055163Sshin static char buf[BUFSIZ]; 256155163Sshin 256255163Sshin return inet_ntop(AF_INET6, (void *)p, buf, sizeof(buf)); 256355163Sshin} 256455163Sshin 256555163Sshinvoid 256655163Sshinifrtdump(sig) 256755163Sshin int sig; 256855163Sshin{ 256955163Sshin 257055163Sshin ifdump(sig); 257155163Sshin rtdump(sig); 257255163Sshin} 257355163Sshin 257455163Sshinvoid 257555163Sshinifdump(sig) 257655163Sshin int sig; 257755163Sshin{ 257855163Sshin struct ifc *ifcp; 257955163Sshin FILE *dump; 258055163Sshin int i; 258155163Sshin 258255163Sshin if (sig == 0) 258355163Sshin dump = stderr; 258455163Sshin else 258555163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 258655163Sshin dump = stderr; 258755163Sshin 258855163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 258955163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 259055163Sshin for (i = 0; i < 2; i++) { 259155163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 259255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 259355163Sshin if (i == 0) { 259455163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 259555163Sshin continue; 259655163Sshin if (iff_find(ifcp, 'N') != NULL) 259755163Sshin continue; 259855163Sshin } else { 259955163Sshin if (ifcp->ifc_flags & IFF_UP) 260055163Sshin continue; 260155163Sshin } 260255163Sshin ifdump0(dump, ifcp); 260355163Sshin } 260455163Sshin } 260555163Sshin fprintf(dump, "\n"); 260655163Sshin if (dump != stderr) 260755163Sshin fclose(dump); 260855163Sshin} 260955163Sshin 261055163Sshinvoid 261155163Sshinifdump0(dump, ifcp) 261255163Sshin FILE *dump; 261355163Sshin const struct ifc *ifcp; 261455163Sshin{ 261555163Sshin struct ifac *ifa; 261655163Sshin struct iff *iffp; 261755163Sshin char buf[BUFSIZ]; 261855163Sshin const char *ft; 261955163Sshin int addr; 262055163Sshin 262155163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 262255163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 262355163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 262455163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 262555163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 262655163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 262755163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 262855163Sshin buf, sizeof(buf)); 262955163Sshin fprintf(dump, "\t%s/%d -- %s\n", 263055163Sshin inet6_n2p(&ifa->ifa_addr), 263155163Sshin ifa->ifa_plen, buf); 263255163Sshin } else { 263355163Sshin fprintf(dump, "\t%s/%d\n", 263455163Sshin inet6_n2p(&ifa->ifa_addr), 263555163Sshin ifa->ifa_plen); 263655163Sshin } 263755163Sshin } 263855163Sshin if (ifcp->ifc_filter) { 263955163Sshin fprintf(dump, "\tFilter:"); 264055163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 264155163Sshin addr = 0; 264255163Sshin switch (iffp->iff_type) { 264355163Sshin case 'A': 264455163Sshin ft = "Aggregate"; addr++; break; 264555163Sshin case 'N': 264655163Sshin ft = "No-advertise"; break; 264755163Sshin case 'O': 264855163Sshin ft = "Advertise-only"; addr++; break; 264955163Sshin case 'T': 265055163Sshin ft = "Default-only"; break; 265155163Sshin case 'L': 265255163Sshin ft = "Listen-only"; addr++; break; 265355163Sshin default: 265455163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 265555163Sshin ft = buf; 265655163Sshin addr++; 265755163Sshin break; 265855163Sshin } 265955163Sshin fprintf(dump, " %s", ft); 266055163Sshin if (addr) { 266155163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 266255163Sshin iffp->iff_plen); 266355163Sshin } 266455163Sshin } 266555163Sshin fprintf(dump, "\n"); 266655163Sshin } 266755163Sshin} 266855163Sshin 266955163Sshinvoid 267055163Sshinrtdump(sig) 267155163Sshin int sig; 267255163Sshin{ 267355163Sshin struct riprt *rrt; 267455163Sshin char buf[BUFSIZ]; 267555163Sshin FILE *dump; 267655163Sshin time_t t, age; 267755163Sshin 267855163Sshin if (sig == 0) 267955163Sshin dump = stderr; 268055163Sshin else 268155163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 268255163Sshin dump = stderr; 268355163Sshin 268455163Sshin t = time(NULL); 268555163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 268655163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 268755163Sshin if (rrt->rrt_t == 0) 268855163Sshin age = 0; 268955163Sshin else 269055163Sshin age = t - rrt->rrt_t; 269155163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 269255163Sshin buf, sizeof(buf)); 269355163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 269455163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 269555163Sshin index2ifc[rrt->rrt_index]->ifc_name, 269655163Sshin inet6_n2p(&rrt->rrt_gw), 269755163Sshin rrt->rrt_info.rip6_metric, (long)age); 269855163Sshin if (rrt->rrt_info.rip6_tag) { 269955163Sshin fprintf(dump, " tag(0x%04x)", 270055163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 270155163Sshin } 270262607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 270355163Sshin fprintf(dump, " NOT-LL"); 270462607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 270555163Sshin fprintf(dump, " NO-ADV"); 270655163Sshin fprintf(dump, "\n"); 270755163Sshin } 270855163Sshin fprintf(dump, "\n"); 270955163Sshin if (dump != stderr) 271055163Sshin fclose(dump); 271155163Sshin} 271255163Sshin 271355163Sshin/* 271455163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 271555163Sshin * specified interface structures. Each of the -A/O option has the following 271655163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 271755163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 271855163Sshin */ 271955163Sshinvoid 272055163Sshinfilterconfig() 272155163Sshin{ 272255163Sshin int i; 272355163Sshin char *p, *ap, *iflp, *ifname; 272455163Sshin struct iff ftmp, *iff_obj; 272555163Sshin struct ifc *ifcp; 272655163Sshin struct riprt *rrt; 272755163Sshin struct in6_addr gw; 272855163Sshin 272955163Sshin for (i = 0; i < nfilter; i++) { 273055163Sshin ap = filter[i]; 273155163Sshin iflp = NULL; 273255163Sshin ifcp = NULL; 273355163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 273455163Sshin iflp = ap; 273555163Sshin goto ifonly; 273655163Sshin } 273755163Sshin if ((p = index(ap, ',')) != NULL) { 273855163Sshin *p++ = '\0'; 273955163Sshin iflp = p; 274055163Sshin } 274155163Sshin if ((p = index(ap, '/')) == NULL) 274255163Sshin fatal("no prefixlen specified for '%s'", ap); 274355163Sshin *p++ = '\0'; 274455163Sshin if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) 274555163Sshin fatal("invalid prefix specified for '%s'", ap); 274655163Sshin ftmp.iff_plen = atoi(p); 274755163Sshin ftmp.iff_next = NULL; 274855163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 274955163Sshinifonly: 275055163Sshin ftmp.iff_type = filtertype[i]; 275155163Sshin if (iflp == NULL || *iflp == '\0') 275255163Sshin fatal("no interface specified for '%s'", ap); 275355163Sshin /* parse the interface listing portion */ 275455163Sshin while (iflp) { 275555163Sshin ifname = iflp; 275655163Sshin if ((iflp = index(iflp, ',')) != NULL) 275755163Sshin *iflp++ = '\0'; 275855163Sshin ifcp = ifc_find(ifname); 275955163Sshin if (ifcp == NULL) 276055163Sshin fatal("no interface %s exists", ifname); 276155163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 276255163Sshin if (iff_obj == NULL) 276355163Sshin fatal("malloc of iff_obj"); 276455163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 276555163Sshin sizeof(struct iff)); 276655163Sshin /* link it to the interface filter */ 276755163Sshin iff_obj->iff_next = ifcp->ifc_filter; 276855163Sshin ifcp->ifc_filter = iff_obj; 276955163Sshin } 277055163Sshin if (filtertype[i] != 'A') 277155163Sshin continue; 277255163Sshin /* put the aggregate to the kernel routing table */ 277355163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 277455163Sshin if (rrt == NULL) 277555163Sshin fatal("malloc: rrt"); 277655163Sshin memset(rrt, 0, sizeof(struct riprt)); 277755163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 277855163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 277955163Sshin rrt->rrt_info.rip6_metric = 1; 278055163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 278155163Sshin rrt->rrt_gw = in6addr_loopback; 278262607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 278362607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 278455163Sshin rrt->rrt_t = 0; 278555163Sshin rrt->rrt_index = loopifindex; 278655163Sshin /* Put the route to the list */ 278755163Sshin rrt->rrt_next = riprt; 278855163Sshin riprt = rrt; 278955163Sshin trace(1, "Aggregate: %s/%d for %s\n", 279055163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 279155163Sshin ifcp->ifc_name); 279255163Sshin /* Add this route to the kernel */ 279355163Sshin if (nflag) /* do not modify kernel routing table */ 279455163Sshin continue; 279555163Sshin if (getroute(&rrt->rrt_info, &gw)) { 279655163Sshin /* 279755163Sshin * When the address has already been registered in the 279862607Sitojun * kernel routing table, it should be removed 279955163Sshin */ 280055163Sshin delroute(&rrt->rrt_info, &gw); 280155163Sshin } 280255163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 280355163Sshin } 280455163Sshin} 280555163Sshin 280655163Sshin/***************** utility functions *****************/ 280755163Sshin 280855163Sshin/* 280955163Sshin * Returns a pointer to ifac whose address and prefix length matches 281055163Sshin * with the address and prefix length specified in the arguments. 281155163Sshin */ 281255163Sshinstruct ifac * 281355163Sshinifa_match(ifcp, ia, plen) 281455163Sshin const struct ifc *ifcp; 281555163Sshin const struct in6_addr *ia; 281655163Sshin int plen; 281755163Sshin{ 281855163Sshin struct ifac *ifa; 281955163Sshin 282055163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 282155163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 282255163Sshin ifa->ifa_plen == plen) 282355163Sshin break; 282455163Sshin } 282555163Sshin return ifa; 282655163Sshin} 282755163Sshin 282855163Sshin/* 282955163Sshin * Return a pointer to riprt structure whose address and prefix length 283055163Sshin * matches with the address and prefix length found in the argument. 283155163Sshin * Note: This is not a rtalloc(). Therefore exact match is necessary. 283255163Sshin */ 283355163Sshin 283455163Sshinstruct riprt * 283555163Sshinrtsearch(np) 283655163Sshin struct netinfo6 *np; 283755163Sshin{ 283855163Sshin struct riprt *rrt; 283955163Sshin 284055163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 284155163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 284255163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 284355163Sshin &np->rip6_dest)) 284455163Sshin return rrt; 284555163Sshin } 284655163Sshin return 0; 284755163Sshin} 284855163Sshin 284955163Sshinint 285055163Sshinmask2len(addr, lenlim) 285155163Sshin const struct in6_addr *addr; 285255163Sshin int lenlim; 285355163Sshin{ 285455163Sshin int i = 0, j; 285555163Sshin u_char *p = (u_char *)addr; 285662607Sitojun 285755163Sshin for (j = 0; j < lenlim; j++, p++) { 285855163Sshin if (*p != 0xff) 285955163Sshin break; 286055163Sshin i += 8; 286155163Sshin } 286255163Sshin if (j < lenlim) { 286355163Sshin switch (*p) { 286462607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 286562607Sitojun MASKLEN(0xfe, 7); break; 286662607Sitojun MASKLEN(0xfc, 6); break; 286762607Sitojun MASKLEN(0xf8, 5); break; 286862607Sitojun MASKLEN(0xf0, 4); break; 286962607Sitojun MASKLEN(0xe0, 3); break; 287062607Sitojun MASKLEN(0xc0, 2); break; 287162607Sitojun MASKLEN(0x80, 1); break; 287255163Sshin#undef MASKLEN 287355163Sshin } 287455163Sshin } 287555163Sshin return i; 287655163Sshin} 287755163Sshin 287855163Sshinvoid 287955163Sshinapplymask(addr, mask) 288055163Sshin struct in6_addr *addr, *mask; 288155163Sshin{ 288255163Sshin int i; 288355163Sshin u_long *p, *q; 288455163Sshin 288555163Sshin p = (u_long *)addr; q = (u_long *)mask; 288655163Sshin for (i = 0; i < 4; i++) 288755163Sshin *p++ &= *q++; 288855163Sshin} 288955163Sshin 289055163Sshinstatic const u_char plent[8] = { 289155163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 289255163Sshin}; 289355163Sshin 289455163Sshinvoid 289555163Sshinapplyplen(ia, plen) 289655163Sshin struct in6_addr *ia; 289755163Sshin int plen; 289855163Sshin{ 289955163Sshin u_char *p; 290055163Sshin int i; 290155163Sshin 290255163Sshin p = ia->s6_addr; 290355163Sshin for (i = 0; i < 16; i++) { 290455163Sshin if (plen <= 0) 290555163Sshin *p = 0; 290655163Sshin else if (plen < 8) 290755163Sshin *p &= plent[plen]; 290855163Sshin p++, plen -= 8; 290955163Sshin } 291055163Sshin} 291155163Sshin 291255163Sshinstatic const int pl2m[9] = { 291355163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 291455163Sshin}; 291555163Sshin 291655163Sshinstruct in6_addr * 291755163Sshinplen2mask(n) 291855163Sshin int n; 291955163Sshin{ 292055163Sshin static struct in6_addr ia; 292155163Sshin u_char *p; 292255163Sshin int i; 292355163Sshin 292455163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 292555163Sshin p = (u_char *)&ia; 292655163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 292755163Sshin if (n >= 8) { 292855163Sshin *p = 0xff; 292955163Sshin continue; 293055163Sshin } 293155163Sshin *p = pl2m[n]; 293255163Sshin break; 293355163Sshin } 293455163Sshin return &ia; 293555163Sshin} 293655163Sshin 293755163Sshinchar * 293855163Sshinallocopy(p) 293955163Sshin char *p; 294055163Sshin{ 294155163Sshin char *q = (char *)malloc(strlen(p) + 1); 294255163Sshin 294355163Sshin strcpy(q, p); 294455163Sshin return q; 294555163Sshin} 294655163Sshin 294755163Sshinchar * 294855163Sshinhms() 294955163Sshin{ 295055163Sshin static char buf[BUFSIZ]; 295155163Sshin time_t t; 295255163Sshin struct tm *tm; 295355163Sshin 295455163Sshin t = time(NULL); 295555163Sshin if ((tm = localtime(&t)) == 0) 295655163Sshin fatal("localtime"); 295755163Sshin snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); 295855163Sshin return buf; 295955163Sshin} 296055163Sshin 296155163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 296255163Sshin 296355163Sshinint 296455163Sshinripinterval(timer) 296555163Sshin int timer; 296655163Sshin{ 296755163Sshin double r = rand(); 296855163Sshin 296955163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 297055163Sshin nextalarm = time(NULL) + interval; 297155163Sshin return interval; 297255163Sshin} 297355163Sshin 297455163Sshintime_t 297555163Sshinripsuptrig() 297655163Sshin{ 297755163Sshin time_t t; 297855163Sshin 297955163Sshin double r = rand(); 298062607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 298155163Sshin (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX )); 298255163Sshin sup_trig_update = time(NULL) + t; 298355163Sshin return t; 298455163Sshin} 298555163Sshin 298655163Sshinvoid 298755163Sshin#ifdef __STDC__ 298855163Sshinfatal(const char *fmt, ...) 298955163Sshin#else 299055163Sshinfatal(fmt, va_alist) 299155163Sshin char *fmt; 299255163Sshin va_dcl 299355163Sshin#endif 299455163Sshin{ 299555163Sshin va_list ap; 299655163Sshin char buf[1024]; 299755163Sshin 299855163Sshin#ifdef __STDC__ 299955163Sshin va_start(ap, fmt); 300055163Sshin#else 300155163Sshin va_start(ap); 300255163Sshin#endif 300355163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 300455163Sshin perror(buf); 300555163Sshin syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 300655163Sshin rtdexit(0); 300755163Sshin va_end(ap); 300855163Sshin} 300955163Sshin 301055163Sshinvoid 301155163Sshin#ifdef __STDC__ 301255163Sshintracet(int level, const char *fmt, ...) 301355163Sshin#else 301455163Sshintracet(level, fmt, va_alist) 301555163Sshin int level; 301655163Sshin char *fmt; 301755163Sshin va_dcl 301855163Sshin#endif 301955163Sshin{ 302055163Sshin va_list ap; 302155163Sshin 302255163Sshin#ifdef __STDC__ 302355163Sshin va_start(ap, fmt); 302455163Sshin#else 302555163Sshin va_start(ap); 302655163Sshin#endif 302755163Sshin if (level <= dflag) { 302855163Sshin fprintf(stderr, "%s: ", hms()); 302955163Sshin vfprintf(stderr, fmt, ap); 303055163Sshin } 303155163Sshin if (dflag) { 303255163Sshin if (level > 0) 303355163Sshin vsyslog(LOG_DEBUG, fmt, ap); 303455163Sshin else 303555163Sshin vsyslog(LOG_WARNING, fmt, ap); 303655163Sshin } 303755163Sshin va_end(ap); 303855163Sshin} 303955163Sshin 304055163Sshinvoid 304155163Sshin#ifdef __STDC__ 304255163Sshintrace(int level, const char *fmt, ...) 304355163Sshin#else 304455163Sshintrace(level, fmt, va_alist) 304555163Sshin int level; 304655163Sshin char *fmt; 304755163Sshin va_dcl 304855163Sshin#endif 304955163Sshin{ 305055163Sshin va_list ap; 305155163Sshin 305255163Sshin#ifdef __STDC__ 305355163Sshin va_start(ap, fmt); 305455163Sshin#else 305555163Sshin va_start(ap); 305655163Sshin#endif 305755163Sshin if (level <= dflag) 305855163Sshin vfprintf(stderr, fmt, ap); 305955163Sshin if (dflag) { 306055163Sshin if (level > 0) 306155163Sshin vsyslog(LOG_DEBUG, fmt, ap); 306255163Sshin else 306355163Sshin vsyslog(LOG_WARNING, fmt, ap); 306455163Sshin } 306555163Sshin va_end(ap); 306655163Sshin} 306755163Sshin 306855163Sshinunsigned int 306955163Sshinif_maxindex() 307055163Sshin{ 307155163Sshin struct if_nameindex *p, *p0; 307255163Sshin unsigned int max = 0; 307355163Sshin 307455163Sshin p0 = if_nameindex(); 307555163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 307655163Sshin if (max < p->if_index) 307755163Sshin max = p->if_index; 307855163Sshin } 307955163Sshin if_freenameindex(p0); 308055163Sshin return max; 308155163Sshin} 308255163Sshin 308355163Sshinstruct ifc * 308455163Sshinifc_find(name) 308555163Sshin char *name; 308655163Sshin{ 308755163Sshin struct ifc *ifcp; 308855163Sshin 308955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 309055163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 309155163Sshin return ifcp; 309255163Sshin } 309355163Sshin return (struct ifc *)NULL; 309455163Sshin} 309555163Sshin 309655163Sshinstruct iff * 309755163Sshiniff_find(ifcp, type) 309855163Sshin struct ifc *ifcp; 309955163Sshin int type; 310055163Sshin{ 310155163Sshin struct iff *iffp; 310255163Sshin 310355163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 310455163Sshin if (iffp->iff_type == type) 310555163Sshin return iffp; 310655163Sshin } 310755163Sshin return NULL; 310855163Sshin} 310955163Sshin 311055163Sshinvoid 311155163Sshinsetindex2ifc(index, ifcp) 311255163Sshin int index; 311355163Sshin struct ifc *ifcp; 311455163Sshin{ 311555163Sshin int n; 311662607Sitojun struct ifc **p; 311755163Sshin 311855163Sshin if (!index2ifc) { 311955163Sshin nindex2ifc = 5; /*initial guess*/ 312055163Sshin index2ifc = (struct ifc **) 312155163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 312255163Sshin if (index2ifc == NULL) 312355163Sshin fatal("malloc"); 312455163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 312555163Sshin } 312655163Sshin n = nindex2ifc; 312755163Sshin while (nindex2ifc <= index) 312855163Sshin nindex2ifc *= 2; 312955163Sshin if (n != nindex2ifc) { 313062607Sitojun p = (struct ifc **)realloc(index2ifc, 313162607Sitojun sizeof(*index2ifc) * nindex2ifc); 313262607Sitojun if (p == NULL) 313355163Sshin fatal("realloc"); 313462607Sitojun index2ifc = p; 313555163Sshin } 313655163Sshin index2ifc[index] = ifcp; 313755163Sshin} 3138