route6d.c revision 119038
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 119038 2003-08-17 17:34:09Z ume $ */ 278064Sume/* $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $ */ 355163Sshin 455163Sshin/* 555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 655163Sshin * All rights reserved. 762607Sitojun * 855163Sshin * Redistribution and use in source and binary forms, with or without 955163Sshin * modification, are permitted provided that the following conditions 1055163Sshin * are met: 1155163Sshin * 1. Redistributions of source code must retain the above copyright 1255163Sshin * notice, this list of conditions and the following disclaimer. 1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455163Sshin * notice, this list of conditions and the following disclaimer in the 1555163Sshin * documentation and/or other materials provided with the distribution. 1655163Sshin * 3. Neither the name of the project nor the names of its contributors 1755163Sshin * may be used to endorse or promote products derived from this software 1855163Sshin * without specific prior written permission. 1962607Sitojun * 2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055163Sshin * SUCH DAMAGE. 3155163Sshin */ 3255163Sshin 3355163Sshin#ifndef lint 3478064Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $"; 3555163Sshin#endif 3655163Sshin 3755163Sshin#include <stdio.h> 3855163Sshin 3955163Sshin#include <time.h> 4055163Sshin#include <unistd.h> 4155163Sshin#include <stdlib.h> 4255163Sshin#include <string.h> 4355163Sshin#include <signal.h> 4455163Sshin#ifdef __STDC__ 4555163Sshin#include <stdarg.h> 4655163Sshin#else 4755163Sshin#include <varargs.h> 4855163Sshin#endif 4955163Sshin#include <syslog.h> 5055163Sshin#include <stddef.h> 5162607Sitojun#include <errno.h> 5255163Sshin#include <err.h> 5355163Sshin 5455163Sshin#include <sys/types.h> 5555163Sshin#include <sys/param.h> 5655163Sshin#include <sys/file.h> 5755163Sshin#include <sys/socket.h> 5855163Sshin#include <sys/ioctl.h> 5955163Sshin#include <sys/sysctl.h> 6055163Sshin#include <sys/uio.h> 6155163Sshin#include <net/if.h> 6262607Sitojun#if defined(__FreeBSD__) && __FreeBSD__ >= 3 6355163Sshin#include <net/if_var.h> 6462607Sitojun#endif /* __FreeBSD__ >= 3 */ 6562607Sitojun#define KERNEL 1 6662607Sitojun#define _KERNEL 1 6755163Sshin#include <net/route.h> 6862607Sitojun#undef KERNEL 6962607Sitojun#undef _KERNEL 7055163Sshin#include <netinet/in.h> 7155163Sshin#include <netinet/in_var.h> 7255163Sshin#include <netinet/ip6.h> 7355163Sshin#include <netinet/udp.h> 7455163Sshin#include <netdb.h> 7562607Sitojun#include <ifaddrs.h> 7655163Sshin 7755163Sshin#include <arpa/inet.h> 7855163Sshin 7955163Sshin#include "route6d.h" 8055163Sshin 8155163Sshin#define MAXFILTER 40 8255163Sshin 8355163Sshin#ifdef DEBUG 8455163Sshin#define INIT_INTERVAL6 6 8555163Sshin#else 86108533Sschweikh#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest. */ 8755163Sshin#endif 8855163Sshin 8955163Sshin/* alignment constraint for routing socket */ 9062607Sitojun#define ROUNDUP(a) \ 9155163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9262607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9355163Sshin 9455163Sshin/* 9555163Sshin * Following two macros are highly depending on KAME Release 9655163Sshin */ 9755163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 9855163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 9955163Sshin 10055163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10155163Sshin do { \ 10255163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10355163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10455163Sshin } while (0) 10555163Sshin 10655163Sshinstruct ifc { /* Configuration of an interface */ 10755163Sshin char *ifc_name; /* if name */ 10855163Sshin struct ifc *ifc_next; 10955163Sshin int ifc_index; /* if index */ 11055163Sshin int ifc_mtu; /* if mtu */ 11155163Sshin int ifc_metric; /* if metric */ 11278064Sume u_int ifc_flags; /* flags */ 11378064Sume short ifc_cflags; /* IFC_XXX */ 11455163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11555163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11655163Sshin struct iff *ifc_filter; /* filter structure */ 11755163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 11855163Sshin int ifc_joined; /* joined to ff02::9 */ 11955163Sshin}; 12055163Sshin 12162607Sitojunstruct ifac { /* Adddress associated to an interface */ 12255163Sshin struct ifc *ifa_conf; /* back pointer */ 12355163Sshin struct ifac *ifa_next; 12455163Sshin struct in6_addr ifa_addr; /* address */ 12555163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12655163Sshin int ifa_plen; /* prefix length */ 12755163Sshin}; 12855163Sshin 12955163Sshinstruct iff { 13055163Sshin int iff_type; 13155163Sshin struct in6_addr iff_addr; 13255163Sshin int iff_plen; 13355163Sshin struct iff *iff_next; 13455163Sshin}; 13555163Sshin 13655163Sshinstruct ifc *ifc; 13755163Sshinint nifc; /* number of valid ifc's */ 13855163Sshinstruct ifc **index2ifc; 13955163Sshinint nindex2ifc; 14055163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 14155163Sshinint loopifindex = 0; /* ditto */ 14255163Sshinfd_set sockvec; /* vector to select() for receiving */ 14355163Sshinint rtsock; /* the routing socket */ 14455163Sshinint ripsock; /* socket to send/receive RIP datagram */ 14555163Sshin 14655163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 14755163Sshin 14855163Sshin/* 14978064Sume * Maintain the routes in a linked list. When the number of the routes 15055163Sshin * grows, somebody would like to introduce a hash based or a radix tree 15178064Sume * based structure. I believe the number of routes handled by RIP is 15255163Sshin * limited and I don't have to manage a complex data structure, however. 15355163Sshin * 15455163Sshin * One of the major drawbacks of the linear linked list is the difficulty 15578064Sume * of representing the relationship between a couple of routes. This may 15655163Sshin * be a significant problem when we have to support route aggregation with 15755163Sshin * supressing the specifices covered by the aggregate. 15855163Sshin */ 15955163Sshin 16055163Sshinstruct riprt { 16155163Sshin struct riprt *rrt_next; /* next destination */ 16255163Sshin struct riprt *rrt_same; /* same destination - future use */ 16355163Sshin struct netinfo6 rrt_info; /* network info */ 16455163Sshin struct in6_addr rrt_gw; /* gateway */ 16562607Sitojun u_long rrt_flags; /* kernel routing table flags */ 16662607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 16755163Sshin time_t rrt_t; /* when the route validated */ 16855163Sshin int rrt_index; /* ifindex from which this route got */ 16955163Sshin}; 17055163Sshin 17155163Sshinstruct riprt *riprt = 0; 17255163Sshin 17355163Sshinint dflag = 0; /* debug flag */ 17455163Sshinint qflag = 0; /* quiet flag */ 17555163Sshinint nflag = 0; /* don't update kernel routing table */ 17655163Sshinint aflag = 0; /* age out even the statically defined routes */ 17755163Sshinint hflag = 0; /* don't split horizon */ 17855163Sshinint lflag = 0; /* exchange site local routes */ 17955163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 18055163Sshinint Sflag = 0; /* announce static routes to every interface */ 18162607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 18255163Sshin 18355163Sshinchar *filter[MAXFILTER]; 18455163Sshinint filtertype[MAXFILTER]; 18555163Sshinint nfilter = 0; 18655163Sshin 18755163Sshinpid_t pid; 18855163Sshin 18955163Sshinstruct sockaddr_storage ripsin; 19055163Sshin 19155163Sshinstruct rtentry rtentry; 19255163Sshin 19355163Sshinint interval = 1; 19455163Sshintime_t nextalarm = 0; 19555163Sshintime_t sup_trig_update = 0; 19655163Sshin 19755163SshinFILE *rtlog = NULL; 19855163Sshin 19955163Sshinint logopened = 0; 20055163Sshin 20155163Sshinstatic u_long seq = 0; 20255163Sshin 20378064Sumevolatile int signo; 20478064Sumevolatile sig_atomic_t seenalrm; 20578064Sumevolatile sig_atomic_t seenquit; 20678064Sumevolatile sig_atomic_t seenusr1; 20778064Sume 20862607Sitojun#define RRTF_AGGREGATE 0x08000000 20962607Sitojun#define RRTF_NOADVERTISE 0x10000000 21062607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 21162607Sitojun#define RRTF_SENDANYWAY 0x40000000 21262607Sitojun#define RRTF_CHANGED 0x80000000 21355163Sshin 21455163Sshinint main __P((int, char **)); 21578064Sumevoid sighandler __P((int)); 21678064Sumevoid ripalarm __P((void)); 21755163Sshinvoid riprecv __P((void)); 21855163Sshinvoid ripsend __P((struct ifc *, struct sockaddr_in6 *, int)); 21978064Sumeint out_filter __P((struct riprt *, struct ifc *)); 22055163Sshinvoid init __P((void)); 22155163Sshinvoid sockopt __P((struct ifc *)); 22255163Sshinvoid ifconfig __P((void)); 22362607Sitojunvoid ifconfig1 __P((const char *, const struct sockaddr *, struct ifc *, int)); 22455163Sshinvoid rtrecv __P((void)); 22555163Sshinint rt_del __P((const struct sockaddr_in6 *, const struct sockaddr_in6 *, 22655163Sshin const struct sockaddr_in6 *)); 22755163Sshinint rt_deladdr __P((struct ifc *, const struct sockaddr_in6 *, 22855163Sshin const struct sockaddr_in6 *)); 22955163Sshinvoid filterconfig __P((void)); 23055163Sshinint getifmtu __P((int)); 23178064Sumeconst char *rttypes __P((struct rt_msghdr *)); 23278064Sumeconst char *rtflags __P((struct rt_msghdr *)); 23378064Sumeconst char *ifflags __P((int)); 23478064Sumeint ifrt __P((struct ifc *, int)); 23562607Sitojunvoid ifrt_p2p __P((struct ifc *, int)); 23655163Sshinvoid applymask __P((struct in6_addr *, struct in6_addr *)); 23755163Sshinvoid applyplen __P((struct in6_addr *, int)); 23855163Sshinvoid ifrtdump __P((int)); 23955163Sshinvoid ifdump __P((int)); 24055163Sshinvoid ifdump0 __P((FILE *, const struct ifc *)); 24155163Sshinvoid rtdump __P((int)); 24255163Sshinvoid rt_entry __P((struct rt_msghdr *, int)); 24378064Sumevoid rtdexit __P((void)); 24478064Sumevoid riprequest __P((struct ifc *, struct netinfo6 *, int, 24578064Sume struct sockaddr_in6 *)); 24655163Sshinvoid ripflush __P((struct ifc *, struct sockaddr_in6 *)); 24755163Sshinvoid sendrequest __P((struct ifc *)); 24878064Sumeint sin6mask2len __P((const struct sockaddr_in6 *)); 24955163Sshinint mask2len __P((const struct in6_addr *, int)); 25055163Sshinint sendpacket __P((struct sockaddr_in6 *, int)); 25155163Sshinint addroute __P((struct riprt *, const struct in6_addr *, struct ifc *)); 25255163Sshinint delroute __P((struct netinfo6 *, struct in6_addr *)); 25355163Sshinstruct in6_addr *getroute __P((struct netinfo6 *, struct in6_addr *)); 25455163Sshinvoid krtread __P((int)); 25555163Sshinint tobeadv __P((struct riprt *, struct ifc *)); 25655163Sshinchar *allocopy __P((char *)); 25755163Sshinchar *hms __P((void)); 25855163Sshinconst char *inet6_n2p __P((const struct in6_addr *)); 25955163Sshinstruct ifac *ifa_match __P((const struct ifc *, const struct in6_addr *, int)); 26055163Sshinstruct in6_addr *plen2mask __P((int)); 26178064Sumestruct riprt *rtsearch __P((struct netinfo6 *, struct riprt **)); 26255163Sshinint ripinterval __P((int)); 26355163Sshintime_t ripsuptrig __P((void)); 26466807Skrisvoid fatal __P((const char *, ...)) 26566807Skris __attribute__((__format__(__printf__, 1, 2))); 26666807Skrisvoid trace __P((int, const char *, ...)) 26766807Skris __attribute__((__format__(__printf__, 2, 3))); 26866807Skrisvoid tracet __P((int, const char *, ...)) 26966807Skris __attribute__((__format__(__printf__, 2, 3))); 27055163Sshinunsigned int if_maxindex __P((void)); 27155163Sshinstruct ifc *ifc_find __P((char *)); 27255163Sshinstruct iff *iff_find __P((struct ifc *, int)); 27355163Sshinvoid setindex2ifc __P((int, struct ifc *)); 27455163Sshin 27555163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 27655163Sshin 27755163Sshinint 27855163Sshinmain(argc, argv) 27955163Sshin int argc; 28055163Sshin char **argv; 28155163Sshin{ 28255163Sshin int ch; 28355163Sshin int error = 0; 28455163Sshin struct ifc *ifcp; 28555163Sshin sigset_t mask, omask; 28655163Sshin FILE *pidfile; 28755163Sshin char *progname; 28862607Sitojun char *ep; 28955163Sshin 29055163Sshin progname = strrchr(*argv, '/'); 29155163Sshin if (progname) 29255163Sshin progname++; 29355163Sshin else 29455163Sshin progname = *argv; 29555163Sshin 29655163Sshin pid = getpid(); 29778064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 29855163Sshin switch (ch) { 29955163Sshin case 'A': 30055163Sshin case 'N': 30155163Sshin case 'O': 30255163Sshin case 'T': 30355163Sshin case 'L': 30462607Sitojun if (nfilter >= MAXFILTER) { 30555163Sshin fatal("Exceeds MAXFILTER"); 30662607Sitojun /*NOTREACHED*/ 30762607Sitojun } 30855163Sshin filtertype[nfilter] = ch; 30955163Sshin filter[nfilter++] = allocopy(optarg); 31055163Sshin break; 31155163Sshin case 't': 31262607Sitojun ep = NULL; 31362607Sitojun routetag = strtoul(optarg, &ep, 0); 31462607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 31555163Sshin fatal("invalid route tag"); 31655163Sshin /*NOTREACHED*/ 31755163Sshin } 31855163Sshin break; 31955163Sshin case 'R': 32062607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 32155163Sshin fatal("Can not write to routelog"); 32262607Sitojun /*NOTREACHED*/ 32362607Sitojun } 32455163Sshin break; 32562607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 32662607Sitojun FLAG('a', aflag, 1); break; 32762607Sitojun FLAG('d', dflag, 1); break; 32862607Sitojun FLAG('D', dflag, 2); break; 32962607Sitojun FLAG('h', hflag, 1); break; 33062607Sitojun FLAG('l', lflag, 1); break; 33162607Sitojun FLAG('n', nflag, 1); break; 33262607Sitojun FLAG('q', qflag, 1); break; 33362607Sitojun FLAG('s', sflag, 1); break; 33462607Sitojun FLAG('S', Sflag, 1); break; 33555163Sshin#undef FLAG 33655163Sshin default: 33755163Sshin fatal("Invalid option specified, terminating"); 33862607Sitojun /*NOTREACHED*/ 33955163Sshin } 34055163Sshin } 34155163Sshin argc -= optind; 34255163Sshin argv += optind; 34378064Sume if (argc > 0) { 34455163Sshin fatal("bogus extra arguments"); 34578064Sume /*NOTREACHED*/ 34678064Sume } 34755163Sshin 34855163Sshin if (geteuid()) { 34955163Sshin nflag = 1; 35055163Sshin fprintf(stderr, "No kernel update is allowed\n"); 35155163Sshin } 352119037Sume 353119037Sume if (dflag == 0) { 354119037Sume if (daemon(0, 0) < 0) { 355119037Sume fatal("daemon"); 356119037Sume /*NOTREACHED*/ 357119037Sume } 358119037Sume } 359119037Sume 36055163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 36155163Sshin logopened++; 36278064Sume 36378064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 36478064Sume fatal("malloc"); 36578064Sume memset(ripbuf, 0, RIP6_MAXMTU); 36678064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 36778064Sume ripbuf->rip6_vers = RIP6_VERSION; 36878064Sume ripbuf->rip6_res1[0] = 0; 36978064Sume ripbuf->rip6_res1[1] = 0; 37078064Sume 37155163Sshin init(); 37255163Sshin ifconfig(); 37355163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 37455163Sshin if (ifcp->ifc_index < 0) { 37555163Sshin fprintf(stderr, 37655163Sshin"No ifindex found at %s (no link-local address?)\n", 37755163Sshin ifcp->ifc_name); 37855163Sshin error++; 37955163Sshin } 38055163Sshin } 38155163Sshin if (error) 38255163Sshin exit(1); 38378064Sume if (loopifcp == NULL) { 38455163Sshin fatal("No loopback found"); 38578064Sume /*NOTREACHED*/ 38678064Sume } 387110666Sache#ifdef __FreeBSD__ 388110666Sache sranddev(); 389110666Sache#else 390110666Sache srand((unsigned)(time(NULL)^(pid<<16))); 391110666Sache#endif 39255163Sshin loopifindex = loopifcp->ifc_index; 39355163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 39455163Sshin ifrt(ifcp, 0); 39555163Sshin filterconfig(); 39655163Sshin krtread(0); 39755163Sshin if (dflag) 39855163Sshin ifrtdump(0); 39955163Sshin 40055163Sshin pid = getpid(); 40155163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 40255163Sshin fprintf(pidfile, "%d\n", pid); 40355163Sshin fclose(pidfile); 40455163Sshin } 40555163Sshin 40678064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 40755163Sshin fatal("malloc"); 40878064Sume /*NOTREACHED*/ 40978064Sume } 41062607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 41155163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 41255163Sshin ripbuf->rip6_vers = RIP6_VERSION; 41355163Sshin ripbuf->rip6_res1[0] = 0; 41455163Sshin ripbuf->rip6_res1[1] = 0; 41555163Sshin 41678064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 41778064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 41878064Sume signal(SIGTERM, sighandler) == SIG_ERR || 41978064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 42078064Sume signal(SIGHUP, sighandler) == SIG_ERR || 42178064Sume signal(SIGINT, sighandler) == SIG_ERR) { 42278064Sume fatal("signal"); 42378064Sume /*NOTREACHED*/ 42478064Sume } 42555163Sshin /* 42655163Sshin * To avoid rip packet congestion (not on a cable but in this 42755163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 42855163Sshin * packets. 42955163Sshin */ 43055163Sshin alarm(ripinterval(INIT_INTERVAL6)); 43155163Sshin 43255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 43355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 43455163Sshin sendrequest(ifcp); 43555163Sshin } 43655163Sshin 43755163Sshin syslog(LOG_INFO, "**** Started ****"); 43855163Sshin sigemptyset(&mask); 43955163Sshin sigaddset(&mask, SIGALRM); 44055163Sshin while (1) { 44155163Sshin fd_set recvec; 44255163Sshin 44378064Sume if (seenalrm) { 44478064Sume ripalarm(); 44578064Sume seenalrm = 0; 44678064Sume continue; 44778064Sume } 44878064Sume if (seenquit) { 44978064Sume rtdexit(); 45078064Sume seenquit = 0; 45178064Sume continue; 45278064Sume } 45378064Sume if (seenusr1) { 45478064Sume ifrtdump(SIGUSR1); 45578064Sume seenusr1 = 0; 45678064Sume continue; 45778064Sume } 45878064Sume 45955163Sshin FD_COPY(&sockvec, &recvec); 46078064Sume signo = 0; 46155163Sshin switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) { 46255163Sshin case -1: 46378064Sume if (errno != EINTR) { 46478064Sume fatal("select"); 46578064Sume /*NOTREACHED*/ 46678064Sume } 46778064Sume continue; 46855163Sshin case 0: 46955163Sshin continue; 47055163Sshin default: 47155163Sshin if (FD_ISSET(ripsock, &recvec)) { 47255163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47355163Sshin riprecv(); 47455163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 47555163Sshin } 47655163Sshin if (FD_ISSET(rtsock, &recvec)) { 47755163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47855163Sshin rtrecv(); 47955163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 48055163Sshin } 48155163Sshin } 48255163Sshin } 48355163Sshin} 48455163Sshin 48578064Sumevoid 48678064Sumesighandler(sig) 48778064Sume int sig; 48878064Sume{ 48978064Sume 49078064Sume signo = sig; 49178064Sume switch (signo) { 49278064Sume case SIGALRM: 49378064Sume seenalrm++; 49478064Sume break; 49578064Sume case SIGQUIT: 49678064Sume case SIGTERM: 49778064Sume seenquit++; 49878064Sume break; 49978064Sume case SIGUSR1: 50078064Sume case SIGHUP: 50178064Sume case SIGINT: 50278064Sume seenusr1++; 50378064Sume break; 50478064Sume } 50578064Sume} 50678064Sume 50755163Sshin/* 50855163Sshin * gracefully exits after resetting sockopts. 50955163Sshin */ 51055163Sshin/* ARGSUSED */ 51155163Sshinvoid 51278064Sumertdexit() 51355163Sshin{ 51455163Sshin struct riprt *rrt; 51555163Sshin 51655163Sshin alarm(0); 51755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 51862607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 51955163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 52055163Sshin } 52155163Sshin } 52255163Sshin close(ripsock); 52355163Sshin close(rtsock); 52455163Sshin syslog(LOG_INFO, "**** Terminated ****"); 52555163Sshin closelog(); 52655163Sshin exit(1); 52755163Sshin} 52855163Sshin 52955163Sshin/* 53055163Sshin * Called periodically: 53155163Sshin * 1. age out the learned route. remove it if necessary. 53255163Sshin * 2. submit RIP6_RESPONSE packets. 53378064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 53455163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 53555163Sshin * routes more precisely. 53655163Sshin */ 53755163Sshin/* ARGSUSED */ 53855163Sshinvoid 53978064Sumeripalarm() 54055163Sshin{ 54155163Sshin struct ifc *ifcp; 54255163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 54355163Sshin time_t t_lifetime, t_holddown; 54455163Sshin 54555163Sshin /* age the RIP routes */ 54655163Sshin rrt_prev = 0; 54755163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 54855163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 54955163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 55055163Sshin rrt_next = rrt->rrt_next; 55155163Sshin 55255163Sshin if (rrt->rrt_t == 0) { 55355163Sshin rrt_prev = rrt; 55455163Sshin continue; 55555163Sshin } 55655163Sshin if (rrt->rrt_t < t_holddown) { 55755163Sshin if (rrt_prev) { 55855163Sshin rrt_prev->rrt_next = rrt->rrt_next; 55955163Sshin } else { 56055163Sshin riprt = rrt->rrt_next; 56155163Sshin } 56255163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 56355163Sshin free(rrt); 56455163Sshin continue; 56555163Sshin } 56655163Sshin if (rrt->rrt_t < t_lifetime) 56755163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 56855163Sshin rrt_prev = rrt; 56955163Sshin } 57055163Sshin /* Supply updates */ 57155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 57255163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 57355163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 57455163Sshin } 57555163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 57655163Sshin} 57755163Sshin 57855163Sshinvoid 57955163Sshininit() 58055163Sshin{ 581119034Sume int error; 582119034Sume const int int0 = 0, int1 = 1, int255 = 255; 58355163Sshin struct addrinfo hints, *res; 58455163Sshin char port[10]; 58555163Sshin 58655163Sshin ifc = (struct ifc *)NULL; 58755163Sshin nifc = 0; 58855163Sshin nindex2ifc = 0; /*initial guess*/ 58955163Sshin index2ifc = NULL; 59055163Sshin snprintf(port, sizeof(port), "%d", RIP6_PORT); 59155163Sshin 59255163Sshin memset(&hints, 0, sizeof(hints)); 59355163Sshin hints.ai_family = PF_INET6; 59455163Sshin hints.ai_socktype = SOCK_DGRAM; 59555163Sshin hints.ai_flags = AI_PASSIVE; 59655163Sshin error = getaddrinfo(NULL, port, &hints, &res); 59778064Sume if (error) { 59866807Skris fatal("%s", gai_strerror(error)); 59978064Sume /*NOTREACHED*/ 60078064Sume } 60178064Sume if (res->ai_next) { 60255163Sshin fatal(":: resolved to multiple address"); 60378064Sume /*NOTREACHED*/ 60478064Sume } 60555163Sshin 60655163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 60778064Sume if (ripsock < 0) { 60855163Sshin fatal("rip socket"); 60978064Sume /*NOTREACHED*/ 61078064Sume } 611119034Sume#ifdef IPV6_V6ONLY 612119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 613119034Sume &int1, sizeof(int1)) < 0) { 614119034Sume fatal("rip IPV6_V6ONLY"); 615119034Sume /*NOTREACHED*/ 616119034Sume } 617119034Sume#endif 61878064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 61955163Sshin fatal("rip bind"); 62078064Sume /*NOTREACHED*/ 62178064Sume } 62255163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 62378064Sume &int255, sizeof(int255)) < 0) { 62455163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 62578064Sume /*NOTREACHED*/ 62678064Sume } 62755163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 62878064Sume &int0, sizeof(int0)) < 0) { 62955163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 63078064Sume /*NOTREACHED*/ 63178064Sume } 63262921Sume 63362607Sitojun#ifdef IPV6_RECVPKTINFO 634119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 635119034Sume &int1, sizeof(int1)) < 0) { 63662607Sitojun fatal("rip IPV6_RECVPKTINFO"); 63778064Sume /*NOTREACHED*/ 63878064Sume } 63962607Sitojun#else /* old adv. API */ 640119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 641119034Sume &int1, sizeof(int1)) < 0) { 64255163Sshin fatal("rip IPV6_PKTINFO"); 64378064Sume /*NOTREACHED*/ 64478064Sume } 64562607Sitojun#endif 64655163Sshin 64755163Sshin memset(&hints, 0, sizeof(hints)); 64855163Sshin hints.ai_family = PF_INET6; 64955163Sshin hints.ai_socktype = SOCK_DGRAM; 65055163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 65178064Sume if (error) { 65266807Skris fatal("%s", gai_strerror(error)); 65378064Sume /*NOTREACHED*/ 65478064Sume } 65578064Sume if (res->ai_next) { 65655163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 65778064Sume /*NOTREACHED*/ 65878064Sume } 65955163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 66055163Sshin 66155163Sshin#ifdef FD_ZERO 66255163Sshin FD_ZERO(&sockvec); 66355163Sshin#else 66455163Sshin memset(&sockvec, 0, sizeof(sockvec)); 66555163Sshin#endif 66655163Sshin FD_SET(ripsock, &sockvec); 66755163Sshin 66855163Sshin if (nflag == 0) { 66978064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 67055163Sshin fatal("route socket"); 67178064Sume /*NOTREACHED*/ 67278064Sume } 67355163Sshin FD_SET(rtsock, &sockvec); 67455163Sshin } else 67555163Sshin rtsock = -1; /*just for safety */ 67655163Sshin} 67755163Sshin 67862607Sitojun#define RIPSIZE(n) \ 67962607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 68055163Sshin 68155163Sshin/* 68255163Sshin * ripflush flushes the rip datagram stored in the rip buffer 68355163Sshin */ 68455163Sshinstatic int nrt; 68555163Sshinstatic struct netinfo6 *np; 68655163Sshin 68755163Sshinvoid 688119031Sumeripflush(ifcp, sin6) 68955163Sshin struct ifc *ifcp; 690119031Sume struct sockaddr_in6 *sin6; 69155163Sshin{ 69255163Sshin int i; 69355163Sshin int error; 69455163Sshin 69555163Sshin if (ifcp) 69655163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 69755163Sshin ifcp->ifc_name, nrt, 698119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 69955163Sshin else 70055163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 701119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 70255163Sshin if (dflag >= 2) { 70355163Sshin np = ripbuf->rip6_nets; 70455163Sshin for (i = 0; i < nrt; i++, np++) { 70555163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 70655163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 70762607Sitojun trace(2, " NextHop reset"); 70855163Sshin else { 70955163Sshin trace(2, " NextHop %s", 71055163Sshin inet6_n2p(&np->rip6_dest)); 71155163Sshin } 71255163Sshin } else { 71355163Sshin trace(2, " %s/%d[%d]", 71455163Sshin inet6_n2p(&np->rip6_dest), 71555163Sshin np->rip6_plen, np->rip6_metric); 71655163Sshin } 71755163Sshin if (np->rip6_tag) { 71855163Sshin trace(2, " tag=0x%04x", 71955163Sshin ntohs(np->rip6_tag) & 0xffff); 72055163Sshin } 72155163Sshin trace(2, "\n"); 72255163Sshin } 72355163Sshin } 724119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 72555163Sshin if (error == EAFNOSUPPORT) { 72655163Sshin /* Protocol not supported */ 72755163Sshin tracet(1, "Could not send info to %s (%s): " 72855163Sshin "set IFF_UP to 0\n", 72955163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 73055163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 73155163Sshin } 73255163Sshin nrt = 0; np = ripbuf->rip6_nets; 73355163Sshin} 73455163Sshin 73555163Sshin/* 73655163Sshin * Generate RIP6_RESPONSE packets and send them. 73755163Sshin */ 73855163Sshinvoid 739119031Sumeripsend(ifcp, sin6, flag) 74055163Sshin struct ifc *ifcp; 741119031Sume struct sockaddr_in6 *sin6; 74255163Sshin int flag; 74355163Sshin{ 74455163Sshin struct riprt *rrt; 74555163Sshin struct in6_addr *nh; /* next hop */ 74678064Sume int maxrte; 74755163Sshin 74855163Sshin if (ifcp == NULL) { 74955163Sshin /* 75055163Sshin * Request from non-link local address is not 75155163Sshin * a regular route6d update. 75255163Sshin */ 75362607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 75462607Sitojun sizeof(struct udphdr) - 75555163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 75655163Sshin sizeof(struct netinfo6); 75755163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 75855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 75962607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 76055163Sshin continue; 76155163Sshin /* Put the route to the buffer */ 76255163Sshin *np = rrt->rrt_info; 76355163Sshin np++; nrt++; 76455163Sshin if (nrt == maxrte) { 765119031Sume ripflush(NULL, sin6); 76655163Sshin nh = NULL; 76755163Sshin } 76855163Sshin } 76955163Sshin if (nrt) /* Send last packet */ 770119031Sume ripflush(NULL, sin6); 77155163Sshin return; 77255163Sshin } 77355163Sshin 77462607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 77555163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 77655163Sshin return; 77778064Sume 77878064Sume /* -N: no use */ 77955163Sshin if (iff_find(ifcp, 'N') != NULL) 78055163Sshin return; 78178064Sume 78278064Sume /* -T: generate default route only */ 78355163Sshin if (iff_find(ifcp, 'T') != NULL) { 78455163Sshin struct netinfo6 rrt_info; 78555163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 78655163Sshin rrt_info.rip6_dest = in6addr_any; 78755163Sshin rrt_info.rip6_plen = 0; 78855163Sshin rrt_info.rip6_metric = 1; 78978064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 79055163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 79155163Sshin np = ripbuf->rip6_nets; 79255163Sshin *np = rrt_info; 79355163Sshin nrt = 1; 794119031Sume ripflush(ifcp, sin6); 79555163Sshin return; 79655163Sshin } 79778064Sume 79862607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 79962607Sitojun sizeof(struct udphdr) - 80055163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 80155163Sshin sizeof(struct netinfo6); 80278064Sume 80355163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 80455163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 80562607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 80655163Sshin continue; 80778064Sume 80878064Sume /* Need to check filter here */ 80978064Sume if (out_filter(rrt, ifcp) == 0) 81055163Sshin continue; 81178064Sume 81255163Sshin /* Check split horizon and other conditions */ 81355163Sshin if (tobeadv(rrt, ifcp) == 0) 81455163Sshin continue; 81578064Sume 81655163Sshin /* Only considers the routes with flag if specified */ 81762607Sitojun if ((flag & RRTF_CHANGED) && 81862607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 81955163Sshin continue; 82078064Sume 82155163Sshin /* Check nexthop */ 82255163Sshin if (rrt->rrt_index == ifcp->ifc_index && 82355163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 82462607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 82555163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 82655163Sshin if (nrt == maxrte - 2) 827119031Sume ripflush(ifcp, sin6); 82855163Sshin np->rip6_dest = rrt->rrt_gw; 82955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 83055163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 83155163Sshin np->rip6_plen = 0; 83255163Sshin np->rip6_tag = 0; 83355163Sshin np->rip6_metric = NEXTHOP_METRIC; 83455163Sshin nh = &rrt->rrt_gw; 83555163Sshin np++; nrt++; 83655163Sshin } 83755163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 83855163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 83962607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 84055163Sshin /* Reset nexthop */ 84155163Sshin if (nrt == maxrte - 2) 842119031Sume ripflush(ifcp, sin6); 84355163Sshin memset(np, 0, sizeof(struct netinfo6)); 84455163Sshin np->rip6_metric = NEXTHOP_METRIC; 84555163Sshin nh = NULL; 84655163Sshin np++; nrt++; 84755163Sshin } 84878064Sume 84955163Sshin /* Put the route to the buffer */ 85055163Sshin *np = rrt->rrt_info; 85155163Sshin np++; nrt++; 85255163Sshin if (nrt == maxrte) { 853119031Sume ripflush(ifcp, sin6); 85455163Sshin nh = NULL; 85555163Sshin } 85655163Sshin } 85755163Sshin if (nrt) /* Send last packet */ 858119031Sume ripflush(ifcp, sin6); 85955163Sshin} 86055163Sshin 86155163Sshin/* 86278064Sume * outbound filter logic, per-route/interface. 86378064Sume */ 86478064Sumeint 86578064Sumeout_filter(rrt, ifcp) 86678064Sume struct riprt *rrt; 86778064Sume struct ifc *ifcp; 86878064Sume{ 86978064Sume struct iff *iffp; 87078064Sume struct in6_addr ia; 87178064Sume int ok; 87278064Sume 87378064Sume /* 87478064Sume * -A: filter out less specific routes, if we have aggregated 87578064Sume * route configured. 87678064Sume */ 87778064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 87878064Sume if (iffp->iff_type != 'A') 87978064Sume continue; 88078064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 88178064Sume continue; 88278064Sume ia = rrt->rrt_info.rip6_dest; 88378064Sume applyplen(&ia, iffp->iff_plen); 88478064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 88578064Sume return 0; 88678064Sume } 88778064Sume 88878064Sume /* 88978064Sume * if it is an aggregated route, advertise it only to the 89078064Sume * interfaces specified on -A. 89178064Sume */ 89278064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 89378064Sume ok = 0; 89478064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 89578064Sume if (iffp->iff_type != 'A') 89678064Sume continue; 89778064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 89878064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 89978064Sume &iffp->iff_addr)) { 90078064Sume ok = 1; 90178064Sume break; 90278064Sume } 90378064Sume } 90478064Sume if (!ok) 90578064Sume return 0; 90678064Sume } 90778064Sume 90878064Sume /* 90978064Sume * -O: advertise only if prefix matches the configured prefix. 91078064Sume */ 91178064Sume if (iff_find(ifcp, 'O')) { 91278064Sume ok = 0; 91378064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 91478064Sume if (iffp->iff_type != 'O') 91578064Sume continue; 91678064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 91778064Sume continue; 91878064Sume ia = rrt->rrt_info.rip6_dest; 91978064Sume applyplen(&ia, iffp->iff_plen); 92078064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 92178064Sume ok = 1; 92278064Sume break; 92378064Sume } 92478064Sume } 92578064Sume if (!ok) 92678064Sume return 0; 92778064Sume } 92878064Sume 92978064Sume /* the prefix should be advertised */ 93078064Sume return 1; 93178064Sume} 93278064Sume 93378064Sume/* 93455163Sshin * Determine if the route is to be advertised on the specified interface. 93555163Sshin * It checks options specified in the arguments and the split horizon rule. 93655163Sshin */ 93755163Sshinint 93855163Sshintobeadv(rrt, ifcp) 93955163Sshin struct riprt *rrt; 94055163Sshin struct ifc *ifcp; 94155163Sshin{ 94255163Sshin 94355163Sshin /* Special care for static routes */ 94455163Sshin if (rrt->rrt_flags & RTF_STATIC) { 94562607Sitojun /* XXX don't advertise reject/blackhole routes */ 94662607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 94762607Sitojun return 0; 94862607Sitojun 94955163Sshin if (Sflag) /* Yes, advertise it anyway */ 95055163Sshin return 1; 95155163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 95255163Sshin return 1; 95355163Sshin return 0; 95455163Sshin } 95555163Sshin /* Regular split horizon */ 95655163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 95755163Sshin return 0; 95855163Sshin return 1; 95955163Sshin} 96055163Sshin 96155163Sshin/* 96255163Sshin * Send a rip packet actually. 96355163Sshin */ 96455163Sshinint 965119031Sumesendpacket(sin6, len) 966119031Sume struct sockaddr_in6 *sin6; 96755163Sshin int len; 96855163Sshin{ 96955163Sshin /* 97055163Sshin * MSG_DONTROUTE should not be specified when it responds with a 97178064Sume * RIP6_REQUEST message. SO_DONTROUTE has been specified to 97255163Sshin * other sockets. 97355163Sshin */ 97455163Sshin struct msghdr m; 97555163Sshin struct cmsghdr *cm; 97655163Sshin struct iovec iov[2]; 97755163Sshin u_char cmsgbuf[256]; 97855163Sshin struct in6_pktinfo *pi; 97978064Sume int idx; 98055163Sshin struct sockaddr_in6 sincopy; 98155163Sshin 98255163Sshin /* do not overwrite the given sin */ 983119031Sume sincopy = *sin6; 984119031Sume sin6 = &sincopy; 98555163Sshin 986119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 987119035Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 988119031Sume idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 989119031Sume SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 99055163Sshin } else 99178064Sume idx = 0; 99255163Sshin 993119031Sume m.msg_name = (caddr_t)sin6; 994119031Sume m.msg_namelen = sizeof(*sin6); 99555163Sshin iov[0].iov_base = (caddr_t)ripbuf; 99655163Sshin iov[0].iov_len = len; 99755163Sshin m.msg_iov = iov; 99855163Sshin m.msg_iovlen = 1; 99978064Sume if (!idx) { 100055163Sshin m.msg_control = NULL; 100155163Sshin m.msg_controllen = 0; 100255163Sshin } else { 100355163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 100455163Sshin cm = (struct cmsghdr *)cmsgbuf; 100555163Sshin m.msg_control = (caddr_t)cm; 100655163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 100755163Sshin 100855163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 100955163Sshin cm->cmsg_level = IPPROTO_IPV6; 101055163Sshin cm->cmsg_type = IPV6_PKTINFO; 101155163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 101255163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 101378064Sume pi->ipi6_ifindex = idx; 101455163Sshin } 101555163Sshin 101655163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 101755163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 101855163Sshin return errno; 101955163Sshin } 102062921Sume 102155163Sshin return 0; 102255163Sshin} 102355163Sshin 102455163Sshin/* 102578064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 102655163Sshin * table if necessary. 102755163Sshin */ 102855163Sshinvoid 102955163Sshinriprecv() 103055163Sshin{ 103155163Sshin struct ifc *ifcp, *ic; 103255163Sshin struct sockaddr_in6 fsock; 103355163Sshin struct in6_addr nh; /* next hop */ 103455163Sshin struct rip6 *rp; 103555163Sshin struct netinfo6 *np, *nq; 103655163Sshin struct riprt *rrt; 103778064Sume int len, nn, need_trigger, idx; 103855163Sshin char buf[4 * RIP6_MAXMTU]; 103955163Sshin time_t t; 104055163Sshin struct msghdr m; 104155163Sshin struct cmsghdr *cm; 104255163Sshin struct iovec iov[2]; 104355163Sshin u_char cmsgbuf[256]; 104455163Sshin struct in6_pktinfo *pi; 104555163Sshin struct iff *iffp; 104655163Sshin struct in6_addr ia; 104755163Sshin int ok; 104878064Sume time_t t_half_lifetime; 104955163Sshin 105055163Sshin need_trigger = 0; 105162921Sume 105255163Sshin m.msg_name = (caddr_t)&fsock; 105355163Sshin m.msg_namelen = sizeof(fsock); 105455163Sshin iov[0].iov_base = (caddr_t)buf; 105555163Sshin iov[0].iov_len = sizeof(buf); 105655163Sshin m.msg_iov = iov; 105755163Sshin m.msg_iovlen = 1; 105855163Sshin cm = (struct cmsghdr *)cmsgbuf; 105955163Sshin m.msg_control = (caddr_t)cm; 106055163Sshin m.msg_controllen = sizeof(cmsgbuf); 106178064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 106255163Sshin fatal("recvmsg"); 106378064Sume /*NOTREACHED*/ 106478064Sume } 106578064Sume idx = 0; 106655163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 106755163Sshin cm; 106855163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 106978064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 107078064Sume cm->cmsg_type == IPV6_PKTINFO) { 107155163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 107278064Sume idx = pi->ipi6_ifindex; 107355163Sshin break; 107455163Sshin } 107555163Sshin } 107678064Sume if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 107778064Sume SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 107855163Sshin 107955163Sshin nh = fsock.sin6_addr; 108055163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 108155163Sshin sizeof(struct netinfo6); 108255163Sshin rp = (struct rip6 *)buf; 108355163Sshin np = rp->rip6_nets; 108455163Sshin 1085119035Sume if (rp->rip6_vers != RIP6_VERSION) { 108655163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 108755163Sshin return; 108855163Sshin } 108955163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 109078064Sume if (idx && idx < nindex2ifc) { 109178064Sume ifcp = index2ifc[idx]; 109255163Sshin riprequest(ifcp, np, nn, &fsock); 109355163Sshin } else { 109455163Sshin riprequest(NULL, np, nn, &fsock); 109555163Sshin } 109662607Sitojun return; 109762607Sitojun } 109855163Sshin 109955163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 110055163Sshin trace(1, "Packets from non-ll addr: %s\n", 110178064Sume inet6_n2p(&fsock.sin6_addr)); 110255163Sshin return; /* Ignore packets from non-link-local addr */ 110355163Sshin } 110478064Sume idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 110578064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 110655163Sshin if (!ifcp) { 110778064Sume trace(1, "Packets to unknown interface index %d\n", idx); 110855163Sshin return; /* Ignore it */ 110955163Sshin } 111055163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 111155163Sshin return; /* The packet is from me; ignore */ 111255163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 111355163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 111462607Sitojun return; 111555163Sshin } 111678064Sume 111778064Sume /* -N: no use */ 111855163Sshin if (iff_find(ifcp, 'N') != NULL) 111955163Sshin return; 112078064Sume 112155163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 112278064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 112355163Sshin 112455163Sshin t = time(NULL); 112578064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 112655163Sshin for (; nn; nn--, np++) { 112755163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 112855163Sshin /* modify neighbor address */ 112955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 113055163Sshin nh = np->rip6_dest; 113178064Sume SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 113255163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 113355163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 113455163Sshin nh = fsock.sin6_addr; 113555163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 113655163Sshin } else { 113755163Sshin nh = fsock.sin6_addr; 113855163Sshin trace(1, "\tInvalid Nexthop: %s\n", 113978064Sume inet6_n2p(&np->rip6_dest)); 114055163Sshin } 114155163Sshin continue; 114255163Sshin } 114355163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 114455163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 114555163Sshin inet6_n2p(&np->rip6_dest), 114655163Sshin np->rip6_plen, np->rip6_metric); 114755163Sshin continue; 114855163Sshin } 114955163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 115055163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 115155163Sshin inet6_n2p(&np->rip6_dest), 115255163Sshin np->rip6_plen, np->rip6_metric); 115355163Sshin continue; 115455163Sshin } 115555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 115655163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 115755163Sshin inet6_n2p(&np->rip6_dest), 115855163Sshin np->rip6_plen, np->rip6_metric); 115955163Sshin continue; 116055163Sshin } 116155163Sshin /* may need to pass sitelocal prefix in some case, however*/ 116255163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 116355163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 116455163Sshin inet6_n2p(&np->rip6_dest), 116555163Sshin np->rip6_plen, np->rip6_metric); 116655163Sshin continue; 116755163Sshin } 116855163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 116955163Sshin inet6_n2p(&np->rip6_dest), 117055163Sshin np->rip6_plen, np->rip6_metric); 117155163Sshin if (np->rip6_tag) 117255163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 117362607Sitojun if (dflag >= 2) { 117462607Sitojun ia = np->rip6_dest; 117562607Sitojun applyplen(&ia, np->rip6_plen); 117662607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 117762607Sitojun trace(2, " [junk outside prefix]"); 117862607Sitojun } 117955163Sshin 118078064Sume /* 118178064Sume * -L: listen only if the prefix matches the configuration 118278064Sume */ 118355163Sshin ok = 1; /* if there's no L filter, it is ok */ 118455163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 118555163Sshin if (iffp->iff_type != 'L') 118655163Sshin continue; 118755163Sshin ok = 0; 118855163Sshin if (np->rip6_plen < iffp->iff_plen) 118955163Sshin continue; 119055163Sshin /* special rule: ::/0 means default, not "in /0" */ 119155163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 119255163Sshin continue; 119362607Sitojun ia = np->rip6_dest; 119455163Sshin applyplen(&ia, iffp->iff_plen); 119555163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 119655163Sshin ok = 1; 119755163Sshin break; 119855163Sshin } 119955163Sshin } 120055163Sshin if (!ok) { 120155163Sshin trace(2, " (filtered)\n"); 120255163Sshin continue; 120355163Sshin } 120455163Sshin 120555163Sshin trace(2, "\n"); 120655163Sshin np->rip6_metric++; 120755163Sshin np->rip6_metric += ifcp->ifc_metric; 120855163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 120955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 121055163Sshin 121155163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 121278064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 121355163Sshin if (rrt->rrt_t == 0) 121455163Sshin continue; /* Intf route has priority */ 121555163Sshin nq = &rrt->rrt_info; 121655163Sshin if (nq->rip6_metric > np->rip6_metric) { 121755163Sshin if (rrt->rrt_index == ifcp->ifc_index && 121855163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 121955163Sshin /* Small metric from the same gateway */ 122055163Sshin nq->rip6_metric = np->rip6_metric; 122155163Sshin } else { 122255163Sshin /* Better route found */ 122355163Sshin rrt->rrt_index = ifcp->ifc_index; 122455163Sshin /* Update routing table */ 122555163Sshin delroute(nq, &rrt->rrt_gw); 122655163Sshin rrt->rrt_gw = nh; 122755163Sshin *nq = *np; 122855163Sshin addroute(rrt, &nh, ifcp); 122955163Sshin } 123062607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 123155163Sshin rrt->rrt_t = t; 123255163Sshin need_trigger = 1; 123355163Sshin } else if (nq->rip6_metric < np->rip6_metric && 123455163Sshin rrt->rrt_index == ifcp->ifc_index && 123555163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 123655163Sshin /* Got worse route from same gw */ 123755163Sshin nq->rip6_metric = np->rip6_metric; 123855163Sshin rrt->rrt_t = t; 123962607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 124055163Sshin need_trigger = 1; 124155163Sshin } else if (nq->rip6_metric == np->rip6_metric && 124255163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 124378064Sume if (rrt->rrt_index == ifcp->ifc_index && 124478064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 124578064Sume /* same metric, same route from same gw */ 124678064Sume rrt->rrt_t = t; 124778064Sume } else if (rrt->rrt_t < t_half_lifetime) { 124878064Sume /* Better route found */ 124978064Sume rrt->rrt_index = ifcp->ifc_index; 125078064Sume /* Update routing table */ 125178064Sume delroute(nq, &rrt->rrt_gw); 125278064Sume rrt->rrt_gw = nh; 125378064Sume *nq = *np; 125478064Sume addroute(rrt, &nh, ifcp); 125578064Sume rrt->rrt_rflags |= RRTF_CHANGED; 125678064Sume rrt->rrt_t = t; 125778064Sume } 125855163Sshin } 125962607Sitojun /* 126055163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 126178064Sume * do not update age value. Do nothing. 126255163Sshin */ 126355163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 126455163Sshin /* Got a new valid route */ 126578064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 126655163Sshin fatal("malloc: struct riprt"); 126778064Sume /*NOTREACHED*/ 126878064Sume } 126962607Sitojun memset(rrt, 0, sizeof(*rrt)); 127055163Sshin nq = &rrt->rrt_info; 127155163Sshin 127255163Sshin rrt->rrt_same = NULL; 127355163Sshin rrt->rrt_index = ifcp->ifc_index; 127455163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 127555163Sshin rrt->rrt_gw = nh; 127655163Sshin *nq = *np; 127755163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 127855163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 127955163Sshin rrt->rrt_flags |= RTF_HOST; 128055163Sshin 128155163Sshin /* Put the route to the list */ 128255163Sshin rrt->rrt_next = riprt; 128355163Sshin riprt = rrt; 128455163Sshin /* Update routing table */ 128555163Sshin addroute(rrt, &nh, ifcp); 128662607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 128755163Sshin need_trigger = 1; 128855163Sshin rrt->rrt_t = t; 128955163Sshin } 129055163Sshin } 129155163Sshin /* XXX need to care the interval between triggered updates */ 129255163Sshin if (need_trigger) { 129355163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 129455163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 129555163Sshin if (ifcp->ifc_index == ic->ifc_index) 129655163Sshin continue; 129755163Sshin if (ic->ifc_flags & IFF_UP) 129855163Sshin ripsend(ic, &ic->ifc_ripsin, 129962607Sitojun RRTF_CHANGED); 130055163Sshin } 130155163Sshin } 130255163Sshin /* Reset the flag */ 130355163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 130462607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 130555163Sshin } 130655163Sshin} 130755163Sshin 130855163Sshin/* 130955163Sshin * Send all routes request packet to the specified interface. 131055163Sshin */ 131155163Sshinvoid 131255163Sshinsendrequest(ifcp) 131355163Sshin struct ifc *ifcp; 131455163Sshin{ 131555163Sshin struct netinfo6 *np; 131655163Sshin int error; 131755163Sshin 131855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 131955163Sshin return; 132055163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 132155163Sshin np = ripbuf->rip6_nets; 132255163Sshin memset(np, 0, sizeof(struct netinfo6)); 132355163Sshin np->rip6_metric = HOPCNT_INFINITY6; 132455163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 132555163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 132655163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 132755163Sshin if (error == EAFNOSUPPORT) { 132855163Sshin /* Protocol not supported */ 132955163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 133055163Sshin "set IFF_UP to 0\n", 133155163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 133255163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 133355163Sshin } 133455163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 133555163Sshin} 133655163Sshin 133755163Sshin/* 133855163Sshin * Process a RIP6_REQUEST packet. 133955163Sshin */ 134055163Sshinvoid 1341119031Sumeriprequest(ifcp, np, nn, sin6) 134255163Sshin struct ifc *ifcp; 134355163Sshin struct netinfo6 *np; 134455163Sshin int nn; 1345119031Sume struct sockaddr_in6 *sin6; 134655163Sshin{ 134755163Sshin int i; 134855163Sshin struct riprt *rrt; 134955163Sshin 135055163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 135155163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 135255163Sshin /* Specific response, don't split-horizon */ 135355163Sshin trace(1, "\tRIP Request\n"); 135455163Sshin for (i = 0; i < nn; i++, np++) { 135578064Sume rrt = rtsearch(np, NULL); 135655163Sshin if (rrt) 135755163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 135855163Sshin else 135955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 136055163Sshin } 1361119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 136255163Sshin return; 136355163Sshin } 136455163Sshin /* Whole routing table dump */ 136555163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1366119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 136755163Sshin} 136855163Sshin 136955163Sshin/* 137055163Sshin * Get information of each interface. 137155163Sshin */ 137255163Sshinvoid 137355163Sshinifconfig() 137455163Sshin{ 137562607Sitojun struct ifaddrs *ifap, *ifa; 137662607Sitojun struct ifc *ifcp; 137762607Sitojun struct ipv6_mreq mreq; 137862607Sitojun int s; 137962607Sitojun 138078064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 138162607Sitojun fatal("socket"); 138278064Sume /*NOTREACHED*/ 138378064Sume } 138462607Sitojun 138578064Sume if (getifaddrs(&ifap) != 0) { 138662607Sitojun fatal("getifaddrs"); 138778064Sume /*NOTREACHED*/ 138878064Sume } 138962607Sitojun 139062607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 139162607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 139262607Sitojun continue; 139362607Sitojun ifcp = ifc_find(ifa->ifa_name); 139462607Sitojun /* we are interested in multicast-capable interfaces */ 139562607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 139662607Sitojun continue; 139762607Sitojun if (!ifcp) { 139862607Sitojun /* new interface */ 139978064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 140062607Sitojun fatal("malloc: struct ifc"); 140178064Sume /*NOTREACHED*/ 140278064Sume } 140362607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 140462607Sitojun ifcp->ifc_index = -1; 140562607Sitojun ifcp->ifc_next = ifc; 140662607Sitojun ifc = ifcp; 140762607Sitojun nifc++; 140862607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 140962607Sitojun ifcp->ifc_addr = 0; 141062607Sitojun ifcp->ifc_filter = 0; 141162607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 141262607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 141362607Sitojun ifflags(ifcp->ifc_flags)); 141462607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 141562607Sitojun loopifcp = ifcp; 141662607Sitojun } else { 141762607Sitojun /* update flag, this may be up again */ 141862607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 141962607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 142062607Sitojun ifflags(ifcp->ifc_flags)); 142162607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 142278064Sume ifcp->ifc_cflags |= IFC_CHANGED; 142362607Sitojun } 142462607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 142562607Sitojun } 142662607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 142762607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 142862607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 142962607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 143062607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 143178064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 143278064Sume &mreq, sizeof(mreq)) < 0) { 143362607Sitojun fatal("IPV6_JOIN_GROUP"); 143478064Sume /*NOTREACHED*/ 143578064Sume } 143662607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 143762607Sitojun ifcp->ifc_joined++; 143862607Sitojun } 143962607Sitojun } 144062607Sitojun close(s); 144162607Sitojun freeifaddrs(ifap); 144255163Sshin} 144355163Sshin 144455163Sshinvoid 144562607Sitojunifconfig1(name, sa, ifcp, s) 144662607Sitojun const char *name; 144762607Sitojun const struct sockaddr *sa; 144855163Sshin struct ifc *ifcp; 144955163Sshin int s; 145055163Sshin{ 145155163Sshin struct in6_ifreq ifr; 1452119031Sume const struct sockaddr_in6 *sin6; 145355163Sshin struct ifac *ifa; 145455163Sshin int plen; 145555163Sshin char buf[BUFSIZ]; 145655163Sshin 1457119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1458119031Sume ifr.ifr_addr = *sin6; 1459119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 146078064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 146155163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 146278064Sume /*NOTREACHED*/ 146378064Sume } 146478064Sume plen = sin6mask2len(&ifr.ifr_addr); 1465119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 146655163Sshin /* same interface found */ 146755163Sshin /* need check if something changed */ 146855163Sshin /* XXX not yet implemented */ 146955163Sshin return; 147055163Sshin } 147155163Sshin /* 147255163Sshin * New address is found 147355163Sshin */ 147478064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 147555163Sshin fatal("malloc: struct ifac"); 147678064Sume /*NOTREACHED*/ 147778064Sume } 147862607Sitojun memset(ifa, 0, sizeof(*ifa)); 147955163Sshin ifa->ifa_conf = ifcp; 148055163Sshin ifa->ifa_next = ifcp->ifc_addr; 148155163Sshin ifcp->ifc_addr = ifa; 1482119031Sume ifa->ifa_addr = sin6->sin6_addr; 148355163Sshin ifa->ifa_plen = plen; 148455163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1485119031Sume ifr.ifr_addr = *sin6; 148678064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 148755163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 148878064Sume /*NOTREACHED*/ 148978064Sume } 149055163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 149155163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 149255163Sshin trace(1, "found address %s/%d -- %s\n", 149355163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 149455163Sshin } else { 149555163Sshin trace(1, "found address %s/%d\n", 149655163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 149755163Sshin } 149855163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 149955163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 150055163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 150155163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 150255163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 150355163Sshin ifcp->ifc_index); 150455163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 150555163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 150655163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 150755163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 150878064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 150955163Sshin fatal("ioctl: SIOCGIFMETRIC"); 151078064Sume /*NOTREACHED*/ 151178064Sume } 151255163Sshin ifcp->ifc_metric = ifr.ifr_metric; 151355163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 151455163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 151578064Sume } else 151678064Sume ifcp->ifc_cflags |= IFC_CHANGED; 151755163Sshin} 151855163Sshin 151955163Sshin/* 152055163Sshin * Receive and process routing messages. 152155163Sshin * Update interface information as necesssary. 152255163Sshin */ 152355163Sshinvoid 152455163Sshinrtrecv() 152555163Sshin{ 152655163Sshin char buf[BUFSIZ]; 152755163Sshin char *p, *q; 152855163Sshin struct rt_msghdr *rtm; 152955163Sshin struct ifa_msghdr *ifam; 153055163Sshin struct if_msghdr *ifm; 153155163Sshin int len; 153278064Sume struct ifc *ifcp, *ic; 153355163Sshin int iface = 0, rtable = 0; 153455163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 153578064Sume struct sockaddr_in6 mask; 153655163Sshin int i, addrs; 153778064Sume struct riprt *rrt; 153855163Sshin 153955163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 154055163Sshin perror("read from rtsock"); 154178064Sume exit(1); 154255163Sshin } 154355163Sshin if (len < sizeof(*rtm)) { 154469279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 154569279Sume len, (u_long)sizeof(*rtm)); 154655163Sshin return; 154755163Sshin } 154855163Sshin 154955163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 155055163Sshin /* safety against bogus message */ 155155163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 155255163Sshin trace(1, "bogus rtmsg: length=%d\n", 155355163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 155455163Sshin break; 155555163Sshin } 155655163Sshin rtm = NULL; 155755163Sshin ifam = NULL; 155855163Sshin ifm = NULL; 155955163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 156055163Sshin case RTM_NEWADDR: 156155163Sshin case RTM_DELADDR: 156255163Sshin ifam = (struct ifa_msghdr *)p; 156355163Sshin addrs = ifam->ifam_addrs; 156455163Sshin q = (char *)(ifam + 1); 156555163Sshin break; 156655163Sshin case RTM_IFINFO: 156755163Sshin ifm = (struct if_msghdr *)p; 156855163Sshin addrs = ifm->ifm_addrs; 156955163Sshin q = (char *)(ifm + 1); 157055163Sshin break; 157155163Sshin default: 157255163Sshin rtm = (struct rt_msghdr *)p; 157355163Sshin addrs = rtm->rtm_addrs; 157455163Sshin q = (char *)(rtm + 1); 157555163Sshin if (rtm->rtm_version != RTM_VERSION) { 157655163Sshin trace(1, "unexpected rtmsg version %d " 157755163Sshin "(should be %d)\n", 157855163Sshin rtm->rtm_version, RTM_VERSION); 157955163Sshin continue; 158055163Sshin } 158155163Sshin if (rtm->rtm_pid == pid) { 158255163Sshin#if 0 158355163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 158455163Sshin#endif 158555163Sshin continue; 158655163Sshin } 158755163Sshin break; 158855163Sshin } 158955163Sshin memset(&rta, 0, sizeof(rta)); 159055163Sshin for (i = 0; i < RTAX_MAX; i++) { 159155163Sshin if (addrs & (1 << i)) { 159255163Sshin rta[i] = (struct sockaddr_in6 *)q; 159355163Sshin q += ROUNDUP(rta[i]->sin6_len); 159455163Sshin } 159555163Sshin } 159655163Sshin 159755163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 159855163Sshin rttypes((struct rt_msghdr *)p), addrs); 159955163Sshin if (dflag >= 2) { 160055163Sshin for (i = 0; 160155163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 160255163Sshin i++) { 160355163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 160455163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 160555163Sshin } 160655163Sshin fprintf(stderr, "\n"); 160755163Sshin } 160855163Sshin 160955163Sshin /* 161055163Sshin * Easy ones first. 161155163Sshin * 161255163Sshin * We may be able to optimize by using ifm->ifm_index or 161355163Sshin * ifam->ifam_index. For simplicity we don't do that here. 161455163Sshin */ 161555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 161655163Sshin case RTM_NEWADDR: 161755163Sshin case RTM_IFINFO: 161855163Sshin iface++; 161955163Sshin continue; 162055163Sshin case RTM_ADD: 162155163Sshin rtable++; 162255163Sshin continue; 162355163Sshin case RTM_LOSING: 162455163Sshin case RTM_MISS: 162555163Sshin case RTM_RESOLVE: 162655163Sshin case RTM_GET: 162755163Sshin case RTM_LOCK: 162855163Sshin /* nothing to be done here */ 162955163Sshin trace(1, "\tnothing to be done, ignored\n"); 163055163Sshin continue; 163155163Sshin } 163255163Sshin 163355163Sshin#if 0 163455163Sshin if (rta[RTAX_DST] == NULL) { 163555163Sshin trace(1, "\tno destination, ignored\n"); 163662607Sitojun continue; 163755163Sshin } 163855163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 163955163Sshin trace(1, "\taf mismatch, ignored\n"); 164055163Sshin continue; 164155163Sshin } 164255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 164355163Sshin trace(1, "\tlinklocal destination, ignored\n"); 164455163Sshin continue; 164555163Sshin } 164655163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 164755163Sshin trace(1, "\tloopback destination, ignored\n"); 164855163Sshin continue; /* Loopback */ 164955163Sshin } 165055163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 165155163Sshin trace(1, "\tmulticast destination, ignored\n"); 165255163Sshin continue; 165355163Sshin } 165455163Sshin#endif 165555163Sshin 165655163Sshin /* hard ones */ 165755163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 165855163Sshin case RTM_NEWADDR: 165955163Sshin case RTM_IFINFO: 166055163Sshin case RTM_ADD: 166155163Sshin case RTM_LOSING: 166255163Sshin case RTM_MISS: 166355163Sshin case RTM_RESOLVE: 166455163Sshin case RTM_GET: 166555163Sshin case RTM_LOCK: 166655163Sshin /* should already be handled */ 166755163Sshin fatal("rtrecv: never reach here"); 166878064Sume /*NOTREACHED*/ 166955163Sshin case RTM_DELETE: 167078064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 167178064Sume trace(1, "\tsome of dst/gw/netamsk are " 167278064Sume "unavailable, ignored\n"); 167355163Sshin break; 167455163Sshin } 167578064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 167678064Sume mask.sin6_len = sizeof(mask); 167778064Sume memset(&mask.sin6_addr, 0xff, 167878064Sume sizeof(mask.sin6_addr)); 167978064Sume rta[RTAX_NETMASK] = &mask; 168078064Sume } else if (!rta[RTAX_NETMASK]) { 168178064Sume trace(1, "\tsome of dst/gw/netamsk are " 168278064Sume "unavailable, ignored\n"); 168378064Sume break; 168478064Sume } 168578064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 168678064Sume rta[RTAX_NETMASK]) == 0) { 168755163Sshin rtable++; /*just to be sure*/ 168855163Sshin } 168955163Sshin break; 169055163Sshin case RTM_CHANGE: 169155163Sshin case RTM_REDIRECT: 169255163Sshin trace(1, "\tnot supported yet, ignored\n"); 169355163Sshin break; 169455163Sshin case RTM_DELADDR: 169555163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 169655163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 169755163Sshin break; 169855163Sshin } 169955163Sshin if (ifam->ifam_index < nindex2ifc) 170055163Sshin ifcp = index2ifc[ifam->ifam_index]; 170155163Sshin else 170255163Sshin ifcp = NULL; 170355163Sshin if (!ifcp) { 170455163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 170555163Sshin ifam->ifam_index); 170655163Sshin break; 170755163Sshin } 170878064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 170978064Sume iface++; 171055163Sshin break; 171155163Sshin case RTM_OLDADD: 171255163Sshin case RTM_OLDDEL: 171355163Sshin trace(1, "\tnot supported yet, ignored\n"); 171455163Sshin break; 171555163Sshin } 171655163Sshin 171755163Sshin } 171855163Sshin 171955163Sshin if (iface) { 172055163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 172155163Sshin ifconfig(); 172255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 172378064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 172478064Sume if (ifrt(ifcp, 1)) { 172578064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 172678064Sume if (ifcp->ifc_index == ic->ifc_index) 172778064Sume continue; 172878064Sume if (ic->ifc_flags & IFF_UP) 172978064Sume ripsend(ic, &ic->ifc_ripsin, 173078064Sume RRTF_CHANGED); 173178064Sume } 173278064Sume /* Reset the flag */ 173378064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 173478064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 173578064Sume } 173678064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 173778064Sume } 173855163Sshin } 173955163Sshin if (rtable) { 174055163Sshin trace(1, "rtsock: read routing table again\n"); 174155163Sshin krtread(1); 174255163Sshin } 174355163Sshin} 174455163Sshin 174555163Sshin/* 174655163Sshin * remove specified route from the internal routing table. 174755163Sshin */ 174855163Sshinint 174955163Sshinrt_del(sdst, sgw, smask) 175055163Sshin const struct sockaddr_in6 *sdst; 175155163Sshin const struct sockaddr_in6 *sgw; 175255163Sshin const struct sockaddr_in6 *smask; 175355163Sshin{ 175455163Sshin const struct in6_addr *dst = NULL; 175555163Sshin const struct in6_addr *gw = NULL; 175655163Sshin int prefix; 175755163Sshin struct netinfo6 ni6; 175855163Sshin struct riprt *rrt = NULL; 175955163Sshin time_t t_lifetime; 176055163Sshin 176155163Sshin if (sdst->sin6_family != AF_INET6) { 176255163Sshin trace(1, "\tother AF, ignored\n"); 176355163Sshin return -1; 176455163Sshin } 176555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 176655163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 176755163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 176855163Sshin trace(1, "\taddress %s not interesting, ignored\n", 176955163Sshin inet6_n2p(&sdst->sin6_addr)); 177055163Sshin return -1; 177155163Sshin } 177255163Sshin dst = &sdst->sin6_addr; 177378064Sume if (sgw->sin6_family == AF_INET6) { 177455163Sshin /* easy case */ 177555163Sshin gw = &sgw->sin6_addr; 177678064Sume prefix = sin6mask2len(smask); 177755163Sshin } else if (sgw->sin6_family == AF_LINK) { 177855163Sshin /* 177955163Sshin * Interface route... a hard case. We need to get the prefix 178055163Sshin * length from the kernel, but we now are parsing rtmsg. 178155163Sshin * We'll purge matching routes from my list, then get the 178255163Sshin * fresh list. 178355163Sshin */ 178455163Sshin struct riprt *longest; 1785108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 178655163Sshin inet6_n2p(dst)); 178755163Sshin longest = NULL; 178855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 178955163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 179055163Sshin &sdst->sin6_addr) 179155163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 179255163Sshin if (!longest 179355163Sshin || longest->rrt_info.rip6_plen < 179455163Sshin rrt->rrt_info.rip6_plen) { 179555163Sshin longest = rrt; 179655163Sshin } 179755163Sshin } 179855163Sshin } 179955163Sshin rrt = longest; 180055163Sshin if (!rrt) { 180155163Sshin trace(1, "\tno matching interface route found\n"); 180255163Sshin return -1; 180355163Sshin } 180455163Sshin gw = &in6addr_loopback; 180555163Sshin prefix = rrt->rrt_info.rip6_plen; 180655163Sshin } else { 180778064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 180855163Sshin return -1; 180955163Sshin } 181055163Sshin 181155163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 181255163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 181355163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 181455163Sshin /* age route for interface address */ 181555163Sshin memset(&ni6, 0, sizeof(ni6)); 181655163Sshin ni6.rip6_dest = *dst; 181755163Sshin ni6.rip6_plen = prefix; 181855163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 181955163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 182055163Sshin ni6.rip6_plen); 182178064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 182255163Sshin trace(1, "\tno route found\n"); 182355163Sshin return -1; 182455163Sshin } 182578064Sume#if 0 182655163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 182755163Sshin trace(1, "\tyou can delete static routes only\n"); 182878064Sume } else 182978064Sume#endif 183078064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 183155163Sshin trace(1, "\tgw mismatch: %s <-> ", 183255163Sshin inet6_n2p(&rrt->rrt_gw)); 183355163Sshin trace(1, "%s\n", inet6_n2p(gw)); 183455163Sshin } else { 183555163Sshin trace(1, "\troute found, age it\n"); 183655163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 183755163Sshin rrt->rrt_t = t_lifetime; 183855163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 183955163Sshin } 184055163Sshin } 184155163Sshin return 0; 184255163Sshin} 184355163Sshin 184455163Sshin/* 184555163Sshin * remove specified address from internal interface/routing table. 184655163Sshin */ 184755163Sshinint 184855163Sshinrt_deladdr(ifcp, sifa, smask) 184955163Sshin struct ifc *ifcp; 185055163Sshin const struct sockaddr_in6 *sifa; 185155163Sshin const struct sockaddr_in6 *smask; 185255163Sshin{ 185355163Sshin const struct in6_addr *addr = NULL; 185455163Sshin int prefix; 185555163Sshin struct ifac *ifa = NULL; 185655163Sshin struct netinfo6 ni6; 185755163Sshin struct riprt *rrt = NULL; 185855163Sshin time_t t_lifetime; 185955163Sshin int updated = 0; 186055163Sshin 186178064Sume if (sifa->sin6_family != AF_INET6) { 186255163Sshin trace(1, "\tother AF, ignored\n"); 186355163Sshin return -1; 186455163Sshin } 186555163Sshin addr = &sifa->sin6_addr; 186678064Sume prefix = sin6mask2len(smask); 186755163Sshin 186855163Sshin trace(1, "\tdeleting %s/%d from %s\n", 186955163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 187055163Sshin ifa = ifa_match(ifcp, addr, prefix); 187155163Sshin if (!ifa) { 187255163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 187355163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 187455163Sshin return -1; 187555163Sshin } 187655163Sshin if (ifa->ifa_conf != ifcp) { 187755163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 187855163Sshin "(%s != %s)\n", 187955163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 188055163Sshin return -1; 188155163Sshin } 188255163Sshin /* remove ifa from interface */ 188355163Sshin if (ifcp->ifc_addr == ifa) 188455163Sshin ifcp->ifc_addr = ifa->ifa_next; 188555163Sshin else { 188655163Sshin struct ifac *p; 188755163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 188855163Sshin if (p->ifa_next == ifa) { 188955163Sshin p->ifa_next = ifa->ifa_next; 189055163Sshin break; 189155163Sshin } 189255163Sshin } 189355163Sshin } 189455163Sshin ifa->ifa_next = NULL; 189555163Sshin ifa->ifa_conf = NULL; 189655163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 189755163Sshin /* age route for interface address */ 189855163Sshin memset(&ni6, 0, sizeof(ni6)); 189955163Sshin ni6.rip6_dest = ifa->ifa_addr; 190055163Sshin ni6.rip6_plen = ifa->ifa_plen; 190155163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 190255163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 190355163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 190478064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 190555163Sshin struct in6_addr none; 190655163Sshin memset(&none, 0, sizeof(none)); 190778064Sume if (rrt->rrt_index == ifcp->ifc_index && 190878064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 190978064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 191055163Sshin trace(1, "\troute found, age it\n"); 191155163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 191255163Sshin rrt->rrt_t = t_lifetime; 191355163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 191455163Sshin } 191555163Sshin updated++; 191655163Sshin } else { 191755163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 191855163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 191955163Sshin rrt->rrt_info.rip6_plen, 192055163Sshin rrt->rrt_index); 192155163Sshin } 192255163Sshin } else 192355163Sshin trace(1, "\tno interface route found\n"); 192455163Sshin /* age route for p2p destination */ 192555163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 192655163Sshin memset(&ni6, 0, sizeof(ni6)); 192755163Sshin ni6.rip6_dest = ifa->ifa_raddr; 192855163Sshin ni6.rip6_plen = 128; 192955163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 193055163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 193155163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 193255163Sshin ifcp->ifc_index); 193378064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 193478064Sume if (rrt->rrt_index == ifcp->ifc_index && 193578064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 193655163Sshin trace(1, "\troute found, age it\n"); 193755163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 193855163Sshin rrt->rrt_t = t_lifetime; 193955163Sshin rrt->rrt_info.rip6_metric = 194078064Sume HOPCNT_INFINITY6; 194155163Sshin updated++; 194255163Sshin } 194355163Sshin } else { 194455163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 194555163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 194655163Sshin rrt->rrt_info.rip6_plen, 194755163Sshin rrt->rrt_index); 194855163Sshin } 194955163Sshin } else 195055163Sshin trace(1, "\tno p2p route found\n"); 195155163Sshin } 195255163Sshin return updated ? 0 : -1; 195355163Sshin} 195455163Sshin 195555163Sshin/* 195655163Sshin * Get each interface address and put those interface routes to the route 195755163Sshin * list. 195855163Sshin */ 195978064Sumeint 196055163Sshinifrt(ifcp, again) 196162607Sitojun struct ifc *ifcp; 196255163Sshin int again; 196355163Sshin{ 196462607Sitojun struct ifac *ifa; 196578064Sume struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt; 196662607Sitojun struct netinfo6 *np; 196778064Sume time_t t_lifetime; 196878064Sume int need_trigger = 0; 196955163Sshin 197055163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 197178064Sume return 0; /* ignore loopback */ 197262607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 197362607Sitojun ifrt_p2p(ifcp, again); 197478064Sume return 0; 197562607Sitojun } 197662607Sitojun 197755163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 197862607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 197962607Sitojun#if 0 198062607Sitojun trace(1, "route: %s on %s: " 198162607Sitojun "skip linklocal interface address\n", 198262607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 198362607Sitojun#endif 198462607Sitojun continue; 198562607Sitojun } 198662607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 198762607Sitojun#if 0 198862607Sitojun trace(1, "route: %s: skip unspec interface address\n", 198962607Sitojun ifcp->ifc_name); 199062607Sitojun#endif 199162607Sitojun continue; 199262607Sitojun } 199378064Sume if (ifcp->ifc_flags & IFF_UP) { 199478064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 199578064Sume fatal("malloc: struct riprt"); 199678064Sume memset(rrt, 0, sizeof(*rrt)); 199778064Sume rrt->rrt_same = NULL; 199878064Sume rrt->rrt_index = ifcp->ifc_index; 199978064Sume rrt->rrt_t = 0; /* don't age */ 200078064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 200178064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 200278064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 200378064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 200478064Sume rrt->rrt_flags = RTF_CLONING; 200578064Sume rrt->rrt_rflags |= RRTF_CHANGED; 200678064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 200778064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 200878064Sume#if 0 200978064Sume /* XXX why gateway address == network adddress? */ 201078064Sume rrt->rrt_gw = ifa->ifa_addr; 201178064Sume#endif 201278064Sume np = &rrt->rrt_info; 201378064Sume search_rrt = rtsearch(np, &prev_rrt); 201478064Sume if (search_rrt != NULL) { 201578064Sume if (search_rrt->rrt_info.rip6_metric > 201678064Sume rrt->rrt_info.rip6_metric) { 201778064Sume if (prev_rrt) 201878064Sume prev_rrt->rrt_next = rrt->rrt_next; 201978064Sume else 202078064Sume riprt = rrt->rrt_next; 202178064Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 202278064Sume free(rrt); 202378064Sume } else { 202478064Sume /* Already have better route */ 202578064Sume if (!again) { 202678064Sume trace(1, "route: %s/%d: " 202778064Sume "already registered (%s)\n", 202878064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 202978064Sume ifcp->ifc_name); 203078064Sume } 203178064Sume free(rrt); 203278064Sume continue; 203378064Sume } 203478064Sume } 203555163Sshin /* Attach the route to the list */ 203662607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 203762607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 203862607Sitojun ifcp->ifc_name); 203955163Sshin rrt->rrt_next = riprt; 204055163Sshin riprt = rrt; 204178064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 204278064Sume sendrequest(ifcp); 204378064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 204478064Sume need_trigger = 1; 204555163Sshin } else { 204678064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 204778064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 204878064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 204978064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 205078064Sume loop_rrt->rrt_t = t_lifetime; 205178064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 205278064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 205378064Sume need_trigger = 1; 205478064Sume } 205578064Sume } 205655163Sshin } 205778064Sume } 205862607Sitojun } 205978064Sume return need_trigger; 206062607Sitojun} 206155163Sshin 206262607Sitojun/* 206362607Sitojun * there are couple of p2p interface routing models. "behavior" lets 206462607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2065119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 206662607Sitojun */ 206762607Sitojunvoid 206862607Sitojunifrt_p2p(ifcp, again) 206962607Sitojun struct ifc *ifcp; 207062607Sitojun int again; 207162607Sitojun{ 207262607Sitojun struct ifac *ifa; 207378064Sume struct riprt *rrt, *orrt, *prevrrt; 207462607Sitojun struct netinfo6 *np; 207562607Sitojun struct in6_addr addr, dest; 207662607Sitojun int advert, ignore, i; 207762607Sitojun#define P2PADVERT_NETWORK 1 207862607Sitojun#define P2PADVERT_ADDR 2 207962607Sitojun#define P2PADVERT_DEST 4 208062607Sitojun#define P2PADVERT_MAX 4 208162607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 208278064Sume const char *category = ""; 208362607Sitojun const char *noadv; 208462607Sitojun 208562607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 208662607Sitojun addr = ifa->ifa_addr; 208762607Sitojun dest = ifa->ifa_raddr; 208862607Sitojun applyplen(&addr, ifa->ifa_plen); 208962607Sitojun applyplen(&dest, ifa->ifa_plen); 209062607Sitojun advert = ignore = 0; 209162607Sitojun switch (behavior) { 209262607Sitojun case CISCO: 209362607Sitojun /* 209462607Sitojun * honor addr/plen, just like normal shared medium 209562607Sitojun * interface. this may cause trouble if you reuse 209662607Sitojun * addr/plen on other interfaces. 209762607Sitojun * 209862607Sitojun * advertise addr/plen. 209962607Sitojun */ 210062607Sitojun advert |= P2PADVERT_NETWORK; 210162607Sitojun break; 210262607Sitojun case GATED: 210362607Sitojun /* 210462607Sitojun * prefixlen on p2p interface is meaningless. 210562607Sitojun * advertise addr/128 and dest/128. 210662607Sitojun * 210762607Sitojun * do not install network route to route6d routing 210862607Sitojun * table (if we do, it would prevent route installation 210962607Sitojun * for other p2p interface that shares addr/plen). 211078064Sume * 211178064Sume * XXX what should we do if dest is ::? it will not 211278064Sume * get announced anyways (see following filter), 211378064Sume * but we need to think. 211462607Sitojun */ 211562607Sitojun advert |= P2PADVERT_ADDR; 211662607Sitojun advert |= P2PADVERT_DEST; 211762607Sitojun ignore |= P2PADVERT_NETWORK; 211862607Sitojun break; 211962607Sitojun case ROUTE6D: 212062607Sitojun /* 212178064Sume * just for testing. actually the code is redundant 212278064Sume * given the current p2p interface address assignment 212378064Sume * rule for kame kernel. 212478064Sume * 212578064Sume * intent: 212678064Sume * A/n -> announce A/n 212778064Sume * A B/n, A and B share prefix -> A/n (= B/n) 212878064Sume * A B/n, do not share prefix -> A/128 and B/128 212978064Sume * actually, A/64 and A B/128 are the only cases 213078064Sume * permitted by the kernel: 213178064Sume * A/64 -> A/64 213278064Sume * A B/128 -> A/128 and B/128 213362607Sitojun */ 213478064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 213578064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 213678064Sume advert |= P2PADVERT_NETWORK; 213778064Sume else { 213878064Sume advert |= P2PADVERT_ADDR; 213978064Sume advert |= P2PADVERT_DEST; 214078064Sume ignore |= P2PADVERT_NETWORK; 214178064Sume } 214278064Sume } else 214362607Sitojun advert |= P2PADVERT_NETWORK; 214462607Sitojun break; 214562607Sitojun } 214662607Sitojun 214762607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 214862607Sitojun if ((ignore & i) != 0) 214962607Sitojun continue; 215078064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 215155163Sshin fatal("malloc: struct riprt"); 215278064Sume /*NOTREACHED*/ 215378064Sume } 215462607Sitojun memset(rrt, 0, sizeof(*rrt)); 215555163Sshin rrt->rrt_same = NULL; 215655163Sshin rrt->rrt_index = ifcp->ifc_index; 215762607Sitojun rrt->rrt_t = 0; /* don't age */ 215862607Sitojun switch (i) { 215962607Sitojun case P2PADVERT_NETWORK: 216062607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 216162607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 216262607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 216362607Sitojun ifa->ifa_plen); 216462607Sitojun category = "network"; 216562607Sitojun break; 216662607Sitojun case P2PADVERT_ADDR: 216762607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 216862607Sitojun rrt->rrt_info.rip6_plen = 128; 216978064Sume rrt->rrt_gw = in6addr_loopback; 217062607Sitojun category = "addr"; 217162607Sitojun break; 217262607Sitojun case P2PADVERT_DEST: 217362607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 217462607Sitojun rrt->rrt_info.rip6_plen = 128; 217578064Sume rrt->rrt_gw = ifa->ifa_addr; 217662607Sitojun category = "dest"; 217762607Sitojun break; 217862607Sitojun } 217962607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 218062607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 218162607Sitojun#if 0 218262607Sitojun trace(1, "route: %s: skip unspec/linklocal " 218362607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 218462607Sitojun#endif 218562607Sitojun free(rrt); 218662607Sitojun continue; 218762607Sitojun } 218862607Sitojun if ((advert & i) == 0) { 218962607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 219062607Sitojun noadv = ", NO-ADV"; 219162607Sitojun } else 219262607Sitojun noadv = ""; 219355163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 219462607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 219555163Sshin np = &rrt->rrt_info; 219678064Sume orrt = rtsearch(np, &prevrrt); 219778064Sume if (!orrt) { 219855163Sshin /* Attach the route to the list */ 219962607Sitojun trace(1, "route: %s/%d: register route " 220062607Sitojun "(%s on %s%s)\n", 220162607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 220262607Sitojun category, ifcp->ifc_name, noadv); 220355163Sshin rrt->rrt_next = riprt; 220455163Sshin riprt = rrt; 220578064Sume } else if (rrt->rrt_index != orrt->rrt_index || 220678064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 220778064Sume /* swap route */ 220878064Sume rrt->rrt_next = orrt->rrt_next; 220978064Sume if (prevrrt) 221078064Sume prevrrt->rrt_next = rrt; 221178064Sume else 221278064Sume riprt = rrt; 221378064Sume free(orrt); 221478064Sume 221578064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 221678064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 221778064Sume category, ifcp->ifc_name, noadv); 221855163Sshin } else { 221955163Sshin /* Already found */ 222055163Sshin if (!again) { 222162607Sitojun trace(1, "route: %s/%d: " 222262607Sitojun "already registered (%s on %s%s)\n", 222362607Sitojun inet6_n2p(&np->rip6_dest), 222462607Sitojun np->rip6_plen, category, 222562607Sitojun ifcp->ifc_name, noadv); 222655163Sshin } 222755163Sshin free(rrt); 222855163Sshin } 222955163Sshin } 223055163Sshin } 223162607Sitojun#undef P2PADVERT_NETWORK 223262607Sitojun#undef P2PADVERT_ADDR 223362607Sitojun#undef P2PADVERT_DEST 223462607Sitojun#undef P2PADVERT_MAX 223555163Sshin} 223655163Sshin 223755163Sshinint 223855163Sshingetifmtu(ifindex) 223955163Sshin int ifindex; 224055163Sshin{ 224155163Sshin int mib[6]; 224255163Sshin char *buf; 224355163Sshin size_t msize; 224455163Sshin struct if_msghdr *ifm; 224555163Sshin int mtu; 224655163Sshin 224755163Sshin mib[0] = CTL_NET; 224855163Sshin mib[1] = PF_ROUTE; 224955163Sshin mib[2] = 0; 225055163Sshin mib[3] = AF_INET6; 225155163Sshin mib[4] = NET_RT_IFLIST; 225255163Sshin mib[5] = ifindex; 225378064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 225455163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 225578064Sume /*NOTREACHED*/ 225678064Sume } 225778064Sume if ((buf = malloc(msize)) == NULL) { 225855163Sshin fatal("malloc"); 225978064Sume /*NOTREACHED*/ 226078064Sume } 226178064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 226255163Sshin fatal("sysctl NET_RT_IFLIST"); 226378064Sume /*NOTREACHED*/ 226478064Sume } 226555163Sshin ifm = (struct if_msghdr *)buf; 226655163Sshin mtu = ifm->ifm_data.ifi_mtu; 226778064Sume#ifdef __FreeBSD__ 226878064Sume if (ifindex != ifm->ifm_index) { 226955163Sshin fatal("ifindex does not match with ifm_index"); 227078064Sume /*NOTREACHED*/ 227178064Sume } 227278064Sume#endif 227355163Sshin free(buf); 227455163Sshin return mtu; 227555163Sshin} 227655163Sshin 227755163Sshinconst char * 227855163Sshinrttypes(rtm) 227955163Sshin struct rt_msghdr *rtm; 228055163Sshin{ 228162607Sitojun#define RTTYPE(s, f) \ 228262607Sitojundo { \ 228362607Sitojun if (rtm->rtm_type == (f)) \ 228462607Sitojun return (s); \ 228562607Sitojun} while (0) 228655163Sshin RTTYPE("ADD", RTM_ADD); 228755163Sshin RTTYPE("DELETE", RTM_DELETE); 228855163Sshin RTTYPE("CHANGE", RTM_CHANGE); 228955163Sshin RTTYPE("GET", RTM_GET); 229055163Sshin RTTYPE("LOSING", RTM_LOSING); 229155163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 229255163Sshin RTTYPE("MISS", RTM_MISS); 229355163Sshin RTTYPE("LOCK", RTM_LOCK); 229455163Sshin RTTYPE("OLDADD", RTM_OLDADD); 229555163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 229655163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 229755163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 229855163Sshin RTTYPE("DELADDR", RTM_DELADDR); 229955163Sshin RTTYPE("IFINFO", RTM_IFINFO); 230078064Sume#ifdef RTM_OLDADD 230178064Sume RTTYPE("OLDADD", RTM_OLDADD); 230278064Sume#endif 230378064Sume#ifdef RTM_OLDDEL 230478064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 230578064Sume#endif 230678064Sume#ifdef RTM_OIFINFO 230778064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 230878064Sume#endif 230978064Sume#ifdef RTM_IFANNOUNCE 231078064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 231178064Sume#endif 231278064Sume#ifdef RTM_NEWMADDR 231378064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 231478064Sume#endif 231578064Sume#ifdef RTM_DELMADDR 231678064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 231778064Sume#endif 231855163Sshin#undef RTTYPE 231955163Sshin return NULL; 232055163Sshin} 232155163Sshin 232255163Sshinconst char * 232355163Sshinrtflags(rtm) 232455163Sshin struct rt_msghdr *rtm; 232555163Sshin{ 232655163Sshin static char buf[BUFSIZ]; 232755163Sshin 232878064Sume /* 232978064Sume * letter conflict should be okay. painful when *BSD diverges... 233078064Sume */ 233178064Sume strlcpy(buf, "", sizeof(buf)); 233262607Sitojun#define RTFLAG(s, f) \ 233362607Sitojundo { \ 233462607Sitojun if (rtm->rtm_flags & (f)) \ 233578064Sume strlcat(buf, (s), sizeof(buf)); \ 233662607Sitojun} while (0) 233755163Sshin RTFLAG("U", RTF_UP); 233855163Sshin RTFLAG("G", RTF_GATEWAY); 233955163Sshin RTFLAG("H", RTF_HOST); 234055163Sshin RTFLAG("R", RTF_REJECT); 234155163Sshin RTFLAG("D", RTF_DYNAMIC); 234255163Sshin RTFLAG("M", RTF_MODIFIED); 234355163Sshin RTFLAG("d", RTF_DONE); 234455163Sshin#ifdef RTF_MASK 234555163Sshin RTFLAG("m", RTF_MASK); 234655163Sshin#endif 234755163Sshin RTFLAG("C", RTF_CLONING); 234878064Sume#ifdef RTF_CLONED 234978064Sume RTFLAG("c", RTF_CLONED); 235078064Sume#endif 235178064Sume#ifdef RTF_PRCLONING 235278064Sume RTFLAG("c", RTF_PRCLONING); 235378064Sume#endif 235478064Sume#ifdef RTF_WASCLONED 235578064Sume RTFLAG("W", RTF_WASCLONED); 235678064Sume#endif 235755163Sshin RTFLAG("X", RTF_XRESOLVE); 235855163Sshin RTFLAG("L", RTF_LLINFO); 235955163Sshin RTFLAG("S", RTF_STATIC); 236055163Sshin RTFLAG("B", RTF_BLACKHOLE); 236178064Sume#ifdef RTF_PROTO3 236278064Sume RTFLAG("3", RTF_PROTO3); 236378064Sume#endif 236455163Sshin RTFLAG("2", RTF_PROTO2); 236555163Sshin RTFLAG("1", RTF_PROTO1); 236678064Sume#ifdef RTF_BROADCAST 236778064Sume RTFLAG("b", RTF_BROADCAST); 236878064Sume#endif 236978064Sume#ifdef RTF_DEFAULT 237078064Sume RTFLAG("d", RTF_DEFAULT); 237178064Sume#endif 237278064Sume#ifdef RTF_ISAROUTER 237378064Sume RTFLAG("r", RTF_ISAROUTER); 237478064Sume#endif 237578064Sume#ifdef RTF_TUNNEL 237678064Sume RTFLAG("T", RTF_TUNNEL); 237778064Sume#endif 237878064Sume#ifdef RTF_AUTH 237978064Sume RTFLAG("A", RTF_AUTH); 238078064Sume#endif 238178064Sume#ifdef RTF_CRYPT 238278064Sume RTFLAG("E", RTF_CRYPT); 238378064Sume#endif 238455163Sshin#undef RTFLAG 238555163Sshin return buf; 238655163Sshin} 238755163Sshin 238855163Sshinconst char * 238955163Sshinifflags(flags) 239055163Sshin int flags; 239155163Sshin{ 239255163Sshin static char buf[BUFSIZ]; 239355163Sshin 239478064Sume strlcpy(buf, "", sizeof(buf)); 239562607Sitojun#define IFFLAG(s, f) \ 239662607Sitojundo { \ 239762607Sitojun if (flags & f) { \ 239862607Sitojun if (buf[0]) \ 239978064Sume strlcat(buf, ",", sizeof(buf)); \ 240078064Sume strlcat(buf, s, sizeof(buf)); \ 240162607Sitojun } \ 240262607Sitojun} while (0) 240355163Sshin IFFLAG("UP", IFF_UP); 240455163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 240555163Sshin IFFLAG("DEBUG", IFF_DEBUG); 240655163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 240755163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 240855163Sshin#ifdef IFF_NOTRAILERS 240955163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 241055163Sshin#endif 241178064Sume#ifdef IFF_SMART 241278064Sume IFFLAG("SMART", IFF_SMART); 241378064Sume#endif 241455163Sshin IFFLAG("RUNNING", IFF_RUNNING); 241555163Sshin IFFLAG("NOARP", IFF_NOARP); 241655163Sshin IFFLAG("PROMISC", IFF_PROMISC); 241755163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 241855163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 241955163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 242055163Sshin IFFLAG("LINK0", IFF_LINK0); 242155163Sshin IFFLAG("LINK1", IFF_LINK1); 242255163Sshin IFFLAG("LINK2", IFF_LINK2); 242355163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 242455163Sshin#undef IFFLAG 242555163Sshin return buf; 242655163Sshin} 242755163Sshin 242855163Sshinvoid 242955163Sshinkrtread(again) 243055163Sshin int again; 243155163Sshin{ 243255163Sshin int mib[6]; 243355163Sshin size_t msize; 243455163Sshin char *buf, *p, *lim; 243555163Sshin struct rt_msghdr *rtm; 243655163Sshin int retry; 243755163Sshin const char *errmsg; 243855163Sshin 243955163Sshin retry = 0; 244055163Sshin buf = NULL; 244155163Sshin mib[0] = CTL_NET; 244255163Sshin mib[1] = PF_ROUTE; 244355163Sshin mib[2] = 0; 244455163Sshin mib[3] = AF_INET6; /* Address family */ 244555163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 244655163Sshin mib[5] = 0; /* No flags */ 244755163Sshin do { 244855163Sshin retry++; 244955163Sshin errmsg = NULL; 245055163Sshin if (buf) 245155163Sshin free(buf); 245255163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 245355163Sshin errmsg = "sysctl estimate"; 245455163Sshin continue; 245555163Sshin } 245655163Sshin if ((buf = malloc(msize)) == NULL) { 245755163Sshin errmsg = "malloc"; 245855163Sshin continue; 245955163Sshin } 246055163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 246155163Sshin errmsg = "sysctl NET_RT_DUMP"; 246255163Sshin continue; 246355163Sshin } 246455163Sshin } while (retry < 5 && errmsg != NULL); 246578064Sume if (errmsg) { 246669279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 246769279Sume (u_long)msize); 246878064Sume /*NOTREACHED*/ 246978064Sume } else if (1 < retry) 247055163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 247155163Sshin 247255163Sshin lim = buf + msize; 247355163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 247455163Sshin rtm = (struct rt_msghdr *)p; 247555163Sshin rt_entry(rtm, again); 247655163Sshin } 247755163Sshin free(buf); 247855163Sshin} 247955163Sshin 248055163Sshinvoid 248155163Sshinrt_entry(rtm, again) 248255163Sshin struct rt_msghdr *rtm; 248355163Sshin int again; 248455163Sshin{ 248555163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 248655163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 248755163Sshin char *rtmp, *ifname = NULL; 248878064Sume struct riprt *rrt, *orrt; 248955163Sshin struct netinfo6 *np; 249055163Sshin int s; 249155163Sshin 249255163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 249355163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 249462607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 249555163Sshin return; /* not interested in the link route */ 249662607Sitojun } 249769279Sume /* do not look at cloned routes */ 249869279Sume#ifdef RTF_WASCLONED 249969279Sume if (rtm->rtm_flags & RTF_WASCLONED) 250069279Sume return; 250169279Sume#endif 250269279Sume#ifdef RTF_CLONED 250369279Sume if (rtm->rtm_flags & RTF_CLONED) 250469279Sume return; 250569279Sume#endif 250669279Sume /* 250769279Sume * do not look at dynamic routes. 250869279Sume * netbsd/openbsd cloned routes have UGHD. 250969279Sume */ 251069279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 251169279Sume return; 251255163Sshin rtmp = (char *)(rtm + 1); 251355163Sshin /* Destination */ 251455163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 251555163Sshin return; /* ignore routes without destination address */ 251655163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 251764631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 251855163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 251955163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 252055163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 252155163Sshin } 252255163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 252355163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 252455163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 252555163Sshin } 252655163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 252755163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 252855163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 252955163Sshin } 253055163Sshin if (rtm->rtm_addrs & RTA_IFP) { 253155163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 253255163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 253355163Sshin } 253455163Sshin 253555163Sshin /* Destination */ 253655163Sshin if (sin6_dst->sin6_family != AF_INET6) 253755163Sshin return; 253855163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 253955163Sshin return; /* Link-local */ 254055163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 254155163Sshin return; /* Loopback */ 254255163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 254355163Sshin return; 254455163Sshin 254578064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 254655163Sshin fatal("malloc: struct riprt"); 254778064Sume /*NOTREACHED*/ 254878064Sume } 254962607Sitojun memset(rrt, 0, sizeof(*rrt)); 255055163Sshin np = &rrt->rrt_info; 255155163Sshin rrt->rrt_same = NULL; 255255163Sshin rrt->rrt_t = time(NULL); 255355163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 255455163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 255555163Sshin np->rip6_tag = 0; 255655163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 255755163Sshin if (np->rip6_metric < 1) 255855163Sshin np->rip6_metric = 1; 255955163Sshin rrt->rrt_flags = rtm->rtm_flags; 256055163Sshin np->rip6_dest = sin6_dst->sin6_addr; 256155163Sshin 256255163Sshin /* Mask or plen */ 256355163Sshin if (rtm->rtm_flags & RTF_HOST) 256455163Sshin np->rip6_plen = 128; /* Host route */ 256578064Sume else if (sin6_mask) 256678064Sume np->rip6_plen = sin6mask2len(sin6_mask); 256778064Sume else 256855163Sshin np->rip6_plen = 0; 256955163Sshin 257078064Sume orrt = rtsearch(np, NULL); 257178064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 257255163Sshin /* Already found */ 257355163Sshin if (!again) { 257455163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 257555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 257655163Sshin rtflags(rtm)); 257755163Sshin } 257855163Sshin free(rrt); 257955163Sshin return; 258055163Sshin } 258155163Sshin /* Gateway */ 258255163Sshin if (!sin6_gw) 258355163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 258455163Sshin else { 258555163Sshin if (sin6_gw->sin6_family == AF_INET6) 258655163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 258755163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 258855163Sshin /* XXX in case ppp link? */ 258955163Sshin rrt->rrt_gw = in6addr_loopback; 259055163Sshin } else 259155163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 259255163Sshin } 259355163Sshin trace(1, "route: %s/%d flags %s", 259455163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 259555163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 259655163Sshin 259755163Sshin /* Interface */ 259855163Sshin s = rtm->rtm_index; 259955163Sshin if (s < nindex2ifc && index2ifc[s]) 260055163Sshin ifname = index2ifc[s]->ifc_name; 260158070Sshin else { 260258070Sshin trace(1, " not configured\n"); 260362607Sitojun free(rrt); 260458070Sshin return; 260558070Sshin } 260662607Sitojun trace(1, " if %s sock %d", ifname, s); 260755163Sshin rrt->rrt_index = s; 260855163Sshin 260962607Sitojun trace(1, "\n"); 261062607Sitojun 261155163Sshin /* Check gateway */ 261255163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 261355163Sshin !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) 261455163Sshin#ifdef __FreeBSD__ 261555163Sshin && (rrt->rrt_flags & RTF_LOCAL) == 0 261655163Sshin#endif 261755163Sshin ) { 261855163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 261955163Sshin inet6_n2p(&rrt->rrt_gw)); 262055163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 262162607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 262262607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 262355163Sshin } 262455163Sshin 262555163Sshin /* Put it to the route list */ 262678064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 262778064Sume /* replace route list */ 262878064Sume rrt->rrt_next = orrt->rrt_next; 262978064Sume *orrt = *rrt; 263078064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 263178064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 263278064Sume rtflags(rtm)); 263378064Sume free(rrt); 263478064Sume } else { 263578064Sume rrt->rrt_next = riprt; 263678064Sume riprt = rrt; 263778064Sume } 263855163Sshin} 263955163Sshin 264055163Sshinint 264155163Sshinaddroute(rrt, gw, ifcp) 264255163Sshin struct riprt *rrt; 264355163Sshin const struct in6_addr *gw; 264455163Sshin struct ifc *ifcp; 264555163Sshin{ 264655163Sshin struct netinfo6 *np; 264755163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 264855163Sshin struct rt_msghdr *rtm; 2649119031Sume struct sockaddr_in6 *sin6; 265055163Sshin int len; 265155163Sshin 265255163Sshin np = &rrt->rrt_info; 265378064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 265455163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 265555163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 265655163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 265755163Sshin np->rip6_metric - 1, buf2); 265855163Sshin if (rtlog) 265955163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 266055163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 266155163Sshin np->rip6_metric - 1, buf2); 266255163Sshin if (nflag) 266355163Sshin return 0; 266455163Sshin 266555163Sshin memset(buf, 0, sizeof(buf)); 266655163Sshin rtm = (struct rt_msghdr *)buf; 266755163Sshin rtm->rtm_type = RTM_ADD; 266855163Sshin rtm->rtm_version = RTM_VERSION; 266955163Sshin rtm->rtm_seq = ++seq; 267055163Sshin rtm->rtm_pid = pid; 267162607Sitojun rtm->rtm_flags = rrt->rrt_flags; 267255163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 267355163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 267455163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2675119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 267655163Sshin /* Destination */ 2677119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2678119031Sume sin6->sin6_family = AF_INET6; 2679119031Sume sin6->sin6_addr = np->rip6_dest; 2680119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 268155163Sshin /* Gateway */ 2682119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2683119031Sume sin6->sin6_family = AF_INET6; 2684119031Sume sin6->sin6_addr = *gw; 2685119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 268655163Sshin /* Netmask */ 2687119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2688119031Sume sin6->sin6_family = AF_INET6; 2689119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2690119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 269155163Sshin 2692119031Sume len = (char *)sin6 - (char *)buf; 269355163Sshin rtm->rtm_msglen = len; 269455163Sshin if (write(rtsock, buf, len) > 0) 269555163Sshin return 0; 269655163Sshin 269755163Sshin if (errno == EEXIST) { 269855163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2699119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 270055163Sshin if (rtlog) 270155163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2702119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 270355163Sshin } else { 270455163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2705119035Sume strerror(errno)); 270655163Sshin if (rtlog) 270755163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2708119035Sume strerror(errno)); 270955163Sshin } 271055163Sshin return -1; 271155163Sshin} 271255163Sshin 271355163Sshinint 271455163Sshindelroute(np, gw) 271555163Sshin struct netinfo6 *np; 271655163Sshin struct in6_addr *gw; 271755163Sshin{ 271855163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 271955163Sshin struct rt_msghdr *rtm; 2720119031Sume struct sockaddr_in6 *sin6; 272155163Sshin int len; 272255163Sshin 272355163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 272455163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 272555163Sshin np->rip6_plen, buf2); 272655163Sshin if (rtlog) 272755163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 272855163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 272955163Sshin if (nflag) 273055163Sshin return 0; 273155163Sshin 273255163Sshin memset(buf, 0, sizeof(buf)); 273355163Sshin rtm = (struct rt_msghdr *)buf; 273455163Sshin rtm->rtm_type = RTM_DELETE; 273555163Sshin rtm->rtm_version = RTM_VERSION; 273655163Sshin rtm->rtm_seq = ++seq; 273755163Sshin rtm->rtm_pid = pid; 273855163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 273978064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 274078064Sume rtm->rtm_flags |= RTF_HOST; 274155163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2742119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 274355163Sshin /* Destination */ 2744119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2745119031Sume sin6->sin6_family = AF_INET6; 2746119031Sume sin6->sin6_addr = np->rip6_dest; 2747119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 274855163Sshin /* Gateway */ 2749119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2750119031Sume sin6->sin6_family = AF_INET6; 2751119031Sume sin6->sin6_addr = *gw; 2752119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275355163Sshin /* Netmask */ 2754119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2755119031Sume sin6->sin6_family = AF_INET6; 2756119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2757119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 275855163Sshin 2759119031Sume len = (char *)sin6 - (char *)buf; 276055163Sshin rtm->rtm_msglen = len; 276155163Sshin if (write(rtsock, buf, len) >= 0) 276255163Sshin return 0; 276355163Sshin 276455163Sshin if (errno == ESRCH) { 276555163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2766119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 276755163Sshin if (rtlog) 276855163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2769119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 277055163Sshin } else { 277155163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2772119035Sume strerror(errno)); 277355163Sshin if (rtlog) 277455163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2775119035Sume strerror(errno)); 277655163Sshin } 277755163Sshin return -1; 277855163Sshin} 277955163Sshin 278055163Sshinstruct in6_addr * 278155163Sshingetroute(np, gw) 278255163Sshin struct netinfo6 *np; 278355163Sshin struct in6_addr *gw; 278455163Sshin{ 278555163Sshin u_char buf[BUFSIZ]; 278655163Sshin u_long myseq; 278755163Sshin int len; 278855163Sshin struct rt_msghdr *rtm; 2789119031Sume struct sockaddr_in6 *sin6; 279055163Sshin 279155163Sshin rtm = (struct rt_msghdr *)buf; 279255163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 279355163Sshin memset(rtm, 0, len); 279455163Sshin rtm->rtm_type = RTM_GET; 279555163Sshin rtm->rtm_version = RTM_VERSION; 279655163Sshin myseq = ++seq; 279755163Sshin rtm->rtm_seq = myseq; 279855163Sshin rtm->rtm_addrs = RTA_DST; 279955163Sshin rtm->rtm_msglen = len; 2800119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2801119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2802119031Sume sin6->sin6_family = AF_INET6; 2803119031Sume sin6->sin6_addr = np->rip6_dest; 280455163Sshin if (write(rtsock, buf, len) < 0) { 280555163Sshin if (errno == ESRCH) /* No such route found */ 280655163Sshin return NULL; 280755163Sshin perror("write to rtsock"); 280878064Sume exit(1); 280955163Sshin } 281055163Sshin do { 281155163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 281255163Sshin perror("read from rtsock"); 281378064Sume exit(1); 281455163Sshin } 281555163Sshin rtm = (struct rt_msghdr *)buf; 281655163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2817119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 281855163Sshin if (rtm->rtm_addrs & RTA_DST) { 2819119031Sume sin6 = (struct sockaddr_in6 *) 2820119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 282155163Sshin } 282255163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2823119031Sume *gw = sin6->sin6_addr; 282455163Sshin return gw; 282555163Sshin } 282655163Sshin return NULL; 282755163Sshin} 282855163Sshin 282955163Sshinconst char * 283055163Sshininet6_n2p(p) 283155163Sshin const struct in6_addr *p; 283255163Sshin{ 283355163Sshin static char buf[BUFSIZ]; 283455163Sshin 283578064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 283655163Sshin} 283755163Sshin 283855163Sshinvoid 283955163Sshinifrtdump(sig) 284055163Sshin int sig; 284155163Sshin{ 284255163Sshin 284355163Sshin ifdump(sig); 284455163Sshin rtdump(sig); 284555163Sshin} 284655163Sshin 284755163Sshinvoid 284855163Sshinifdump(sig) 284955163Sshin int sig; 285055163Sshin{ 285155163Sshin struct ifc *ifcp; 285255163Sshin FILE *dump; 285355163Sshin int i; 285455163Sshin 285555163Sshin if (sig == 0) 285655163Sshin dump = stderr; 285755163Sshin else 285855163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 285955163Sshin dump = stderr; 286055163Sshin 286155163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 286255163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 286355163Sshin for (i = 0; i < 2; i++) { 286455163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 286555163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 286655163Sshin if (i == 0) { 286755163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 286855163Sshin continue; 286955163Sshin if (iff_find(ifcp, 'N') != NULL) 287055163Sshin continue; 287155163Sshin } else { 287255163Sshin if (ifcp->ifc_flags & IFF_UP) 287355163Sshin continue; 287455163Sshin } 287555163Sshin ifdump0(dump, ifcp); 287655163Sshin } 287755163Sshin } 287855163Sshin fprintf(dump, "\n"); 287955163Sshin if (dump != stderr) 288055163Sshin fclose(dump); 288155163Sshin} 288255163Sshin 288355163Sshinvoid 288455163Sshinifdump0(dump, ifcp) 288555163Sshin FILE *dump; 288655163Sshin const struct ifc *ifcp; 288755163Sshin{ 288855163Sshin struct ifac *ifa; 288955163Sshin struct iff *iffp; 289055163Sshin char buf[BUFSIZ]; 289155163Sshin const char *ft; 289255163Sshin int addr; 289355163Sshin 289455163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 289555163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 289655163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 289755163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 289855163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 289955163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 290055163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 290155163Sshin buf, sizeof(buf)); 290255163Sshin fprintf(dump, "\t%s/%d -- %s\n", 290355163Sshin inet6_n2p(&ifa->ifa_addr), 290455163Sshin ifa->ifa_plen, buf); 290555163Sshin } else { 290655163Sshin fprintf(dump, "\t%s/%d\n", 290755163Sshin inet6_n2p(&ifa->ifa_addr), 290855163Sshin ifa->ifa_plen); 290955163Sshin } 291055163Sshin } 291155163Sshin if (ifcp->ifc_filter) { 291255163Sshin fprintf(dump, "\tFilter:"); 291355163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 291455163Sshin addr = 0; 291555163Sshin switch (iffp->iff_type) { 291655163Sshin case 'A': 291755163Sshin ft = "Aggregate"; addr++; break; 291855163Sshin case 'N': 291978064Sume ft = "No-use"; break; 292055163Sshin case 'O': 292155163Sshin ft = "Advertise-only"; addr++; break; 292255163Sshin case 'T': 292355163Sshin ft = "Default-only"; break; 292455163Sshin case 'L': 292555163Sshin ft = "Listen-only"; addr++; break; 292655163Sshin default: 292755163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 292855163Sshin ft = buf; 292955163Sshin addr++; 293055163Sshin break; 293155163Sshin } 293255163Sshin fprintf(dump, " %s", ft); 293355163Sshin if (addr) { 293455163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 293555163Sshin iffp->iff_plen); 293655163Sshin } 293755163Sshin } 293855163Sshin fprintf(dump, "\n"); 293955163Sshin } 294055163Sshin} 294155163Sshin 294255163Sshinvoid 294355163Sshinrtdump(sig) 294455163Sshin int sig; 294555163Sshin{ 294655163Sshin struct riprt *rrt; 294755163Sshin char buf[BUFSIZ]; 294855163Sshin FILE *dump; 294955163Sshin time_t t, age; 295055163Sshin 295155163Sshin if (sig == 0) 295255163Sshin dump = stderr; 295355163Sshin else 295455163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 295555163Sshin dump = stderr; 295655163Sshin 295755163Sshin t = time(NULL); 295855163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 295955163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 296055163Sshin if (rrt->rrt_t == 0) 296155163Sshin age = 0; 296255163Sshin else 296355163Sshin age = t - rrt->rrt_t; 296455163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 296555163Sshin buf, sizeof(buf)); 296655163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 296755163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 296855163Sshin index2ifc[rrt->rrt_index]->ifc_name, 296955163Sshin inet6_n2p(&rrt->rrt_gw), 297055163Sshin rrt->rrt_info.rip6_metric, (long)age); 297155163Sshin if (rrt->rrt_info.rip6_tag) { 297255163Sshin fprintf(dump, " tag(0x%04x)", 297355163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 297455163Sshin } 297562607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 297655163Sshin fprintf(dump, " NOT-LL"); 297762607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 297855163Sshin fprintf(dump, " NO-ADV"); 297955163Sshin fprintf(dump, "\n"); 298055163Sshin } 298155163Sshin fprintf(dump, "\n"); 298255163Sshin if (dump != stderr) 298355163Sshin fclose(dump); 298455163Sshin} 298555163Sshin 298655163Sshin/* 298755163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 298878064Sume * specified interface structures. Each of the -A/O option has the following 298955163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 299055163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 299155163Sshin */ 299255163Sshinvoid 299355163Sshinfilterconfig() 299455163Sshin{ 299555163Sshin int i; 299655163Sshin char *p, *ap, *iflp, *ifname; 299778064Sume struct iff ftmp, *iff_obj; 299878064Sume struct ifc *ifcp; 299978064Sume struct riprt *rrt; 300064631Sitojun#if 0 300178064Sume struct in6_addr gw; 300264631Sitojun#endif 300355163Sshin 300455163Sshin for (i = 0; i < nfilter; i++) { 300555163Sshin ap = filter[i]; 300655163Sshin iflp = NULL; 300755163Sshin ifcp = NULL; 300855163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 300955163Sshin iflp = ap; 301055163Sshin goto ifonly; 301155163Sshin } 3012119038Sume if ((p = strchr(ap, ',')) != NULL) { 301355163Sshin *p++ = '\0'; 301455163Sshin iflp = p; 301555163Sshin } 3016119038Sume if ((p = strchr(ap, '/')) == NULL) { 301755163Sshin fatal("no prefixlen specified for '%s'", ap); 301878064Sume /*NOTREACHED*/ 301978064Sume } 302055163Sshin *p++ = '\0'; 302178064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 302255163Sshin fatal("invalid prefix specified for '%s'", ap); 302378064Sume /*NOTREACHED*/ 302478064Sume } 302555163Sshin ftmp.iff_plen = atoi(p); 302655163Sshin ftmp.iff_next = NULL; 302755163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 302855163Sshinifonly: 302955163Sshin ftmp.iff_type = filtertype[i]; 303078064Sume if (iflp == NULL || *iflp == '\0') { 303155163Sshin fatal("no interface specified for '%s'", ap); 303278064Sume /*NOTREACHED*/ 303378064Sume } 303455163Sshin /* parse the interface listing portion */ 303555163Sshin while (iflp) { 303655163Sshin ifname = iflp; 3037119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 303855163Sshin *iflp++ = '\0'; 303955163Sshin ifcp = ifc_find(ifname); 304078064Sume if (ifcp == NULL) { 304155163Sshin fatal("no interface %s exists", ifname); 304278064Sume /*NOTREACHED*/ 304378064Sume } 304455163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 304578064Sume if (iff_obj == NULL) { 304655163Sshin fatal("malloc of iff_obj"); 304778064Sume /*NOTREACHED*/ 304878064Sume } 304955163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 305078064Sume sizeof(struct iff)); 305155163Sshin /* link it to the interface filter */ 305255163Sshin iff_obj->iff_next = ifcp->ifc_filter; 305355163Sshin ifcp->ifc_filter = iff_obj; 305455163Sshin } 305578064Sume 305678064Sume /* 305778064Sume * -A: aggregate configuration. 305878064Sume */ 305955163Sshin if (filtertype[i] != 'A') 306055163Sshin continue; 306155163Sshin /* put the aggregate to the kernel routing table */ 306255163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 306378064Sume if (rrt == NULL) { 306455163Sshin fatal("malloc: rrt"); 306578064Sume /*NOTREACHED*/ 306678064Sume } 306755163Sshin memset(rrt, 0, sizeof(struct riprt)); 306855163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 306955163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 307055163Sshin rrt->rrt_info.rip6_metric = 1; 307155163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 307255163Sshin rrt->rrt_gw = in6addr_loopback; 307362607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 307462607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 307555163Sshin rrt->rrt_t = 0; 307655163Sshin rrt->rrt_index = loopifindex; 307764631Sitojun#if 0 307864631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 307964631Sitojun#if 0 308064631Sitojun /* 308164631Sitojun * When the address has already been registered in the 308264631Sitojun * kernel routing table, it should be removed 308364631Sitojun */ 308464631Sitojun delroute(&rrt->rrt_info, &gw); 308564631Sitojun#else 308678064Sume /* it is safer behavior */ 308764631Sitojun errno = EINVAL; 308864631Sitojun fatal("%s/%u already in routing table, " 308964631Sitojun "cannot aggregate", 309064631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 309164631Sitojun rrt->rrt_info.rip6_plen); 309278064Sume /*NOTREACHED*/ 309364631Sitojun#endif 309464631Sitojun } 309564631Sitojun#endif 309655163Sshin /* Put the route to the list */ 309755163Sshin rrt->rrt_next = riprt; 309855163Sshin riprt = rrt; 309955163Sshin trace(1, "Aggregate: %s/%d for %s\n", 310055163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 310155163Sshin ifcp->ifc_name); 310255163Sshin /* Add this route to the kernel */ 310355163Sshin if (nflag) /* do not modify kernel routing table */ 310455163Sshin continue; 310555163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 310655163Sshin } 310755163Sshin} 310855163Sshin 310955163Sshin/***************** utility functions *****************/ 311055163Sshin 311155163Sshin/* 311255163Sshin * Returns a pointer to ifac whose address and prefix length matches 311355163Sshin * with the address and prefix length specified in the arguments. 311455163Sshin */ 311555163Sshinstruct ifac * 311655163Sshinifa_match(ifcp, ia, plen) 311755163Sshin const struct ifc *ifcp; 311855163Sshin const struct in6_addr *ia; 311955163Sshin int plen; 312055163Sshin{ 312155163Sshin struct ifac *ifa; 312255163Sshin 312355163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 312455163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 312555163Sshin ifa->ifa_plen == plen) 312655163Sshin break; 312755163Sshin } 312855163Sshin return ifa; 312955163Sshin} 313055163Sshin 313155163Sshin/* 313255163Sshin * Return a pointer to riprt structure whose address and prefix length 313355163Sshin * matches with the address and prefix length found in the argument. 313478064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 313555163Sshin */ 313655163Sshinstruct riprt * 313778064Sumertsearch(np, prev_rrt) 313855163Sshin struct netinfo6 *np; 313978064Sume struct riprt **prev_rrt; 314055163Sshin{ 314155163Sshin struct riprt *rrt; 314255163Sshin 314378064Sume if (prev_rrt) 314478064Sume *prev_rrt = NULL; 314555163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 314655163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 314755163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 314855163Sshin &np->rip6_dest)) 314955163Sshin return rrt; 315078064Sume if (prev_rrt) 315178064Sume *prev_rrt = rrt; 315255163Sshin } 315378064Sume if (prev_rrt) 315478064Sume *prev_rrt = NULL; 315555163Sshin return 0; 315655163Sshin} 315755163Sshin 315855163Sshinint 315978064Sumesin6mask2len(sin6) 316078064Sume const struct sockaddr_in6 *sin6; 316178064Sume{ 316278064Sume 316378064Sume return mask2len(&sin6->sin6_addr, 316478064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 316578064Sume} 316678064Sume 316778064Sumeint 316855163Sshinmask2len(addr, lenlim) 316955163Sshin const struct in6_addr *addr; 317055163Sshin int lenlim; 317155163Sshin{ 317255163Sshin int i = 0, j; 317378064Sume const u_char *p = (const u_char *)addr; 317462607Sitojun 317555163Sshin for (j = 0; j < lenlim; j++, p++) { 317655163Sshin if (*p != 0xff) 317755163Sshin break; 317855163Sshin i += 8; 317955163Sshin } 318055163Sshin if (j < lenlim) { 318155163Sshin switch (*p) { 318262607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 318362607Sitojun MASKLEN(0xfe, 7); break; 318462607Sitojun MASKLEN(0xfc, 6); break; 318562607Sitojun MASKLEN(0xf8, 5); break; 318662607Sitojun MASKLEN(0xf0, 4); break; 318762607Sitojun MASKLEN(0xe0, 3); break; 318862607Sitojun MASKLEN(0xc0, 2); break; 318962607Sitojun MASKLEN(0x80, 1); break; 319055163Sshin#undef MASKLEN 319155163Sshin } 319255163Sshin } 319355163Sshin return i; 319455163Sshin} 319555163Sshin 319655163Sshinvoid 319755163Sshinapplymask(addr, mask) 319855163Sshin struct in6_addr *addr, *mask; 319955163Sshin{ 320055163Sshin int i; 320155163Sshin u_long *p, *q; 320255163Sshin 320355163Sshin p = (u_long *)addr; q = (u_long *)mask; 320455163Sshin for (i = 0; i < 4; i++) 320555163Sshin *p++ &= *q++; 320655163Sshin} 320755163Sshin 320855163Sshinstatic const u_char plent[8] = { 320955163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 321055163Sshin}; 321155163Sshin 321255163Sshinvoid 321355163Sshinapplyplen(ia, plen) 321455163Sshin struct in6_addr *ia; 321555163Sshin int plen; 321655163Sshin{ 321755163Sshin u_char *p; 321855163Sshin int i; 321955163Sshin 322055163Sshin p = ia->s6_addr; 322155163Sshin for (i = 0; i < 16; i++) { 322255163Sshin if (plen <= 0) 322355163Sshin *p = 0; 322455163Sshin else if (plen < 8) 322555163Sshin *p &= plent[plen]; 322655163Sshin p++, plen -= 8; 322755163Sshin } 322855163Sshin} 322955163Sshin 323055163Sshinstatic const int pl2m[9] = { 323155163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 323255163Sshin}; 323355163Sshin 323455163Sshinstruct in6_addr * 323555163Sshinplen2mask(n) 323655163Sshin int n; 323755163Sshin{ 323855163Sshin static struct in6_addr ia; 323955163Sshin u_char *p; 324055163Sshin int i; 324155163Sshin 324255163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 324355163Sshin p = (u_char *)&ia; 324455163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 324555163Sshin if (n >= 8) { 324655163Sshin *p = 0xff; 324755163Sshin continue; 324855163Sshin } 324955163Sshin *p = pl2m[n]; 325055163Sshin break; 325155163Sshin } 325255163Sshin return &ia; 325355163Sshin} 325455163Sshin 325555163Sshinchar * 325655163Sshinallocopy(p) 325755163Sshin char *p; 325855163Sshin{ 3259119033Sume int len = strlen(p) + 1; 3260119033Sume char *q = (char *)malloc(len); 326155163Sshin 3262119033Sume if (!q) { 3263119033Sume fatal("malloc"); 3264119033Sume /*NOTREACHED*/ 3265119033Sume } 3266119033Sume 3267119033Sume strlcpy(q, p, len); 326855163Sshin return q; 326955163Sshin} 327055163Sshin 327155163Sshinchar * 327255163Sshinhms() 327355163Sshin{ 327455163Sshin static char buf[BUFSIZ]; 327555163Sshin time_t t; 327655163Sshin struct tm *tm; 327755163Sshin 327855163Sshin t = time(NULL); 327978064Sume if ((tm = localtime(&t)) == 0) { 328055163Sshin fatal("localtime"); 328178064Sume /*NOTREACHED*/ 328278064Sume } 328378064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 328478064Sume tm->tm_sec); 328555163Sshin return buf; 328655163Sshin} 328755163Sshin 328855163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 328955163Sshin 329055163Sshinint 329155163Sshinripinterval(timer) 329255163Sshin int timer; 329355163Sshin{ 329455163Sshin double r = rand(); 329555163Sshin 329655163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 329755163Sshin nextalarm = time(NULL) + interval; 329855163Sshin return interval; 329955163Sshin} 330055163Sshin 330155163Sshintime_t 330255163Sshinripsuptrig() 330355163Sshin{ 330455163Sshin time_t t; 330555163Sshin 330655163Sshin double r = rand(); 330762607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 330878064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 330955163Sshin sup_trig_update = time(NULL) + t; 331055163Sshin return t; 331155163Sshin} 331255163Sshin 331355163Sshinvoid 331455163Sshin#ifdef __STDC__ 331555163Sshinfatal(const char *fmt, ...) 331655163Sshin#else 331755163Sshinfatal(fmt, va_alist) 331855163Sshin char *fmt; 331955163Sshin va_dcl 332055163Sshin#endif 332155163Sshin{ 332255163Sshin va_list ap; 332355163Sshin char buf[1024]; 332455163Sshin 332555163Sshin#ifdef __STDC__ 332655163Sshin va_start(ap, fmt); 332755163Sshin#else 332855163Sshin va_start(ap); 332955163Sshin#endif 333055163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 333155163Sshin perror(buf); 333255163Sshin syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 333378064Sume rtdexit(); 333455163Sshin va_end(ap); 333555163Sshin} 333655163Sshin 333755163Sshinvoid 333855163Sshin#ifdef __STDC__ 333955163Sshintracet(int level, const char *fmt, ...) 334055163Sshin#else 334155163Sshintracet(level, fmt, va_alist) 334255163Sshin int level; 334355163Sshin char *fmt; 334455163Sshin va_dcl 334555163Sshin#endif 334655163Sshin{ 334755163Sshin va_list ap; 334855163Sshin 334955163Sshin#ifdef __STDC__ 335055163Sshin va_start(ap, fmt); 335155163Sshin#else 335255163Sshin va_start(ap); 335355163Sshin#endif 335455163Sshin if (level <= dflag) { 335555163Sshin fprintf(stderr, "%s: ", hms()); 335655163Sshin vfprintf(stderr, fmt, ap); 335755163Sshin } 335855163Sshin if (dflag) { 335955163Sshin if (level > 0) 336055163Sshin vsyslog(LOG_DEBUG, fmt, ap); 336155163Sshin else 336255163Sshin vsyslog(LOG_WARNING, fmt, ap); 336355163Sshin } 336455163Sshin va_end(ap); 336555163Sshin} 336655163Sshin 336755163Sshinvoid 336855163Sshin#ifdef __STDC__ 336955163Sshintrace(int level, const char *fmt, ...) 337055163Sshin#else 337155163Sshintrace(level, fmt, va_alist) 337255163Sshin int level; 337355163Sshin char *fmt; 337455163Sshin va_dcl 337555163Sshin#endif 337655163Sshin{ 337755163Sshin va_list ap; 337855163Sshin 337955163Sshin#ifdef __STDC__ 338055163Sshin va_start(ap, fmt); 338155163Sshin#else 338255163Sshin va_start(ap); 338355163Sshin#endif 338455163Sshin if (level <= dflag) 338555163Sshin vfprintf(stderr, fmt, ap); 338655163Sshin if (dflag) { 338755163Sshin if (level > 0) 338855163Sshin vsyslog(LOG_DEBUG, fmt, ap); 338955163Sshin else 339055163Sshin vsyslog(LOG_WARNING, fmt, ap); 339155163Sshin } 339255163Sshin va_end(ap); 339355163Sshin} 339455163Sshin 339555163Sshinunsigned int 339655163Sshinif_maxindex() 339755163Sshin{ 339855163Sshin struct if_nameindex *p, *p0; 339955163Sshin unsigned int max = 0; 340055163Sshin 340155163Sshin p0 = if_nameindex(); 340255163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 340355163Sshin if (max < p->if_index) 340455163Sshin max = p->if_index; 340555163Sshin } 340655163Sshin if_freenameindex(p0); 340755163Sshin return max; 340855163Sshin} 340955163Sshin 341055163Sshinstruct ifc * 341155163Sshinifc_find(name) 341255163Sshin char *name; 341355163Sshin{ 341455163Sshin struct ifc *ifcp; 341555163Sshin 341655163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 341755163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 341855163Sshin return ifcp; 341955163Sshin } 342055163Sshin return (struct ifc *)NULL; 342155163Sshin} 342255163Sshin 342355163Sshinstruct iff * 342455163Sshiniff_find(ifcp, type) 342555163Sshin struct ifc *ifcp; 342655163Sshin int type; 342755163Sshin{ 342855163Sshin struct iff *iffp; 342955163Sshin 343055163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 343155163Sshin if (iffp->iff_type == type) 343255163Sshin return iffp; 343355163Sshin } 343455163Sshin return NULL; 343555163Sshin} 343655163Sshin 343755163Sshinvoid 343878064Sumesetindex2ifc(idx, ifcp) 343978064Sume int idx; 344055163Sshin struct ifc *ifcp; 344155163Sshin{ 344255163Sshin int n; 344362607Sitojun struct ifc **p; 344455163Sshin 344555163Sshin if (!index2ifc) { 344655163Sshin nindex2ifc = 5; /*initial guess*/ 344755163Sshin index2ifc = (struct ifc **) 344855163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 344978064Sume if (index2ifc == NULL) { 345055163Sshin fatal("malloc"); 345178064Sume /*NOTREACHED*/ 345278064Sume } 345355163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 345455163Sshin } 345555163Sshin n = nindex2ifc; 345678064Sume while (nindex2ifc <= idx) 345755163Sshin nindex2ifc *= 2; 345855163Sshin if (n != nindex2ifc) { 345962607Sitojun p = (struct ifc **)realloc(index2ifc, 346062607Sitojun sizeof(*index2ifc) * nindex2ifc); 346178064Sume if (p == NULL) { 346255163Sshin fatal("realloc"); 346378064Sume /*NOTREACHED*/ 346478064Sume } 346578064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 346662607Sitojun index2ifc = p; 346755163Sshin } 346878064Sume index2ifc[idx] = ifcp; 346955163Sshin} 3470