route6d.c revision 243231
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 243231 2012-11-18 15:11:47Z hrs $ */ 2122677Sume/* $KAME: route6d.c,v 1.104 2003/10/31 00:30:20 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 34122677Sumestatic char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $"; 3555163Sshin#endif 3655163Sshin 3755163Sshin#include <stdio.h> 3855163Sshin 3955163Sshin#include <time.h> 4055163Sshin#include <unistd.h> 4155163Sshin#include <stdlib.h> 4255163Sshin#include <string.h> 4355163Sshin#include <signal.h> 4455163Sshin#ifdef __STDC__ 4555163Sshin#include <stdarg.h> 4655163Sshin#else 4755163Sshin#include <varargs.h> 4855163Sshin#endif 4955163Sshin#include <syslog.h> 5055163Sshin#include <stddef.h> 5162607Sitojun#include <errno.h> 5255163Sshin#include <err.h> 53119076Sume#ifdef HAVE_POLL_H 54119076Sume#include <poll.h> 55119076Sume#endif 5655163Sshin 5755163Sshin#include <sys/types.h> 5855163Sshin#include <sys/param.h> 5955163Sshin#include <sys/file.h> 6055163Sshin#include <sys/socket.h> 6155163Sshin#include <sys/ioctl.h> 6255163Sshin#include <sys/sysctl.h> 6355163Sshin#include <sys/uio.h> 6455163Sshin#include <net/if.h> 6555163Sshin#include <net/if_var.h> 6662607Sitojun#define _KERNEL 1 6755163Sshin#include <net/route.h> 6862607Sitojun#undef _KERNEL 6955163Sshin#include <netinet/in.h> 7055163Sshin#include <netinet/in_var.h> 7155163Sshin#include <netinet/ip6.h> 7255163Sshin#include <netinet/udp.h> 7355163Sshin#include <netdb.h> 7462607Sitojun#include <ifaddrs.h> 7555163Sshin 7655163Sshin#include <arpa/inet.h> 7755163Sshin 7855163Sshin#include "route6d.h" 7955163Sshin 8055163Sshin#define MAXFILTER 40 8155163Sshin 8255163Sshin#ifdef DEBUG 8355163Sshin#define INIT_INTERVAL6 6 8455163Sshin#else 85119039Sume#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ 8655163Sshin#endif 8755163Sshin 8855163Sshin/* alignment constraint for routing socket */ 8962607Sitojun#define ROUNDUP(a) \ 9055163Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 9162607Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 9255163Sshin 9355163Sshinstruct ifc { /* Configuration of an interface */ 9455163Sshin char *ifc_name; /* if name */ 9555163Sshin struct ifc *ifc_next; 9655163Sshin int ifc_index; /* if index */ 9755163Sshin int ifc_mtu; /* if mtu */ 9855163Sshin int ifc_metric; /* if metric */ 9978064Sume u_int ifc_flags; /* flags */ 10078064Sume short ifc_cflags; /* IFC_XXX */ 10155163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 10255163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 10355163Sshin struct iff *ifc_filter; /* filter structure */ 10455163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 10555163Sshin int ifc_joined; /* joined to ff02::9 */ 10655163Sshin}; 10755163Sshin 10862607Sitojunstruct ifac { /* Adddress associated to an interface */ 10955163Sshin struct ifc *ifa_conf; /* back pointer */ 11055163Sshin struct ifac *ifa_next; 11155163Sshin struct in6_addr ifa_addr; /* address */ 11255163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 113243231Shrs int ifa_scope_id; /* scope id */ 11455163Sshin int ifa_plen; /* prefix length */ 11555163Sshin}; 11655163Sshin 11755163Sshinstruct iff { 11855163Sshin int iff_type; 11955163Sshin struct in6_addr iff_addr; 12055163Sshin int iff_plen; 12155163Sshin struct iff *iff_next; 12255163Sshin}; 12355163Sshin 12455163Sshinstruct ifc *ifc; 12555163Sshinint nifc; /* number of valid ifc's */ 12655163Sshinstruct ifc **index2ifc; 12755163Sshinint nindex2ifc; 12855163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 129119076Sume#ifdef HAVE_POLL_H 130119076Sumestruct pollfd set[2]; 131119076Sume#else 132119070Sumefd_set *sockvecp; /* vector to select() for receiving */ 133119070Sumefd_set *recvecp; 134119070Sumeint fdmasks; 135119070Sumeint maxfd; /* maximum fd for select() */ 136119076Sume#endif 13755163Sshinint rtsock; /* the routing socket */ 13855163Sshinint ripsock; /* socket to send/receive RIP datagram */ 13955163Sshin 14055163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 14155163Sshin 14255163Sshin/* 14378064Sume * Maintain the routes in a linked list. When the number of the routes 14455163Sshin * grows, somebody would like to introduce a hash based or a radix tree 14578064Sume * based structure. I believe the number of routes handled by RIP is 14655163Sshin * limited and I don't have to manage a complex data structure, however. 14755163Sshin * 14855163Sshin * One of the major drawbacks of the linear linked list is the difficulty 14978064Sume * of representing the relationship between a couple of routes. This may 15055163Sshin * be a significant problem when we have to support route aggregation with 151228990Suqs * suppressing the specifics covered by the aggregate. 15255163Sshin */ 15355163Sshin 15455163Sshinstruct riprt { 15555163Sshin struct riprt *rrt_next; /* next destination */ 15655163Sshin struct riprt *rrt_same; /* same destination - future use */ 15755163Sshin struct netinfo6 rrt_info; /* network info */ 15855163Sshin struct in6_addr rrt_gw; /* gateway */ 15962607Sitojun u_long rrt_flags; /* kernel routing table flags */ 16062607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 16155163Sshin time_t rrt_t; /* when the route validated */ 16255163Sshin int rrt_index; /* ifindex from which this route got */ 16355163Sshin}; 16455163Sshin 16555163Sshinstruct riprt *riprt = 0; 16655163Sshin 16755163Sshinint dflag = 0; /* debug flag */ 16855163Sshinint qflag = 0; /* quiet flag */ 16955163Sshinint nflag = 0; /* don't update kernel routing table */ 17055163Sshinint aflag = 0; /* age out even the statically defined routes */ 17155163Sshinint hflag = 0; /* don't split horizon */ 17255163Sshinint lflag = 0; /* exchange site local routes */ 17355163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 17455163Sshinint Sflag = 0; /* announce static routes to every interface */ 17562607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 17655163Sshin 17755163Sshinchar *filter[MAXFILTER]; 17855163Sshinint filtertype[MAXFILTER]; 17955163Sshinint nfilter = 0; 18055163Sshin 18155163Sshinpid_t pid; 18255163Sshin 18355163Sshinstruct sockaddr_storage ripsin; 18455163Sshin 18555163Sshinint interval = 1; 18655163Sshintime_t nextalarm = 0; 18755163Sshintime_t sup_trig_update = 0; 18855163Sshin 18955163SshinFILE *rtlog = NULL; 19055163Sshin 19155163Sshinint logopened = 0; 19255163Sshin 193119085Sumestatic int seq = 0; 19455163Sshin 19578064Sumevolatile sig_atomic_t seenalrm; 19678064Sumevolatile sig_atomic_t seenquit; 19778064Sumevolatile sig_atomic_t seenusr1; 19878064Sume 19962607Sitojun#define RRTF_AGGREGATE 0x08000000 20062607Sitojun#define RRTF_NOADVERTISE 0x10000000 20162607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 20262607Sitojun#define RRTF_SENDANYWAY 0x40000000 20362607Sitojun#define RRTF_CHANGED 0x80000000 20455163Sshin 205173412Skevloint main(int, char **); 206173412Skevlovoid sighandler(int); 207173412Skevlovoid ripalarm(void); 208173412Skevlovoid riprecv(void); 209173412Skevlovoid ripsend(struct ifc *, struct sockaddr_in6 *, int); 210173412Skevloint out_filter(struct riprt *, struct ifc *); 211173412Skevlovoid init(void); 212173412Skevlovoid sockopt(struct ifc *); 213173412Skevlovoid ifconfig(void); 214173412Skevlovoid ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); 215173412Skevlovoid rtrecv(void); 216173412Skevloint rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *, 217173412Skevlo const struct sockaddr_in6 *); 218173412Skevloint rt_deladdr(struct ifc *, const struct sockaddr_in6 *, 219173412Skevlo const struct sockaddr_in6 *); 220173412Skevlovoid filterconfig(void); 221173412Skevloint getifmtu(int); 222173412Skevloconst char *rttypes(struct rt_msghdr *); 223173412Skevloconst char *rtflags(struct rt_msghdr *); 224173412Skevloconst char *ifflags(int); 225173412Skevloint ifrt(struct ifc *, int); 226173412Skevlovoid ifrt_p2p(struct ifc *, int); 227173412Skevlovoid applymask(struct in6_addr *, struct in6_addr *); 228173412Skevlovoid applyplen(struct in6_addr *, int); 229173412Skevlovoid ifrtdump(int); 230173412Skevlovoid ifdump(int); 231173412Skevlovoid ifdump0(FILE *, const struct ifc *); 232173412Skevlovoid rtdump(int); 233173412Skevlovoid rt_entry(struct rt_msghdr *, int); 234173412Skevlovoid rtdexit(void); 235173412Skevlovoid riprequest(struct ifc *, struct netinfo6 *, int, 236173412Skevlo struct sockaddr_in6 *); 237173412Skevlovoid ripflush(struct ifc *, struct sockaddr_in6 *); 238173412Skevlovoid sendrequest(struct ifc *); 239173412Skevloint sin6mask2len(const struct sockaddr_in6 *); 240173412Skevloint mask2len(const struct in6_addr *, int); 241173412Skevloint sendpacket(struct sockaddr_in6 *, int); 242173412Skevloint addroute(struct riprt *, const struct in6_addr *, struct ifc *); 243173412Skevloint delroute(struct netinfo6 *, struct in6_addr *); 244173412Skevlostruct in6_addr *getroute(struct netinfo6 *, struct in6_addr *); 245173412Skevlovoid krtread(int); 246173412Skevloint tobeadv(struct riprt *, struct ifc *); 247173412Skevlochar *allocopy(char *); 248173412Skevlochar *hms(void); 249173412Skevloconst char *inet6_n2p(const struct in6_addr *); 250173412Skevlostruct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int); 251173412Skevlostruct in6_addr *plen2mask(int); 252173412Skevlostruct riprt *rtsearch(struct netinfo6 *, struct riprt **); 253173412Skevloint ripinterval(int); 254173412Skevlotime_t ripsuptrig(void); 255173412Skevlovoid fatal(const char *, ...) 25666807Skris __attribute__((__format__(__printf__, 1, 2))); 257173412Skevlovoid trace(int, const char *, ...) 25866807Skris __attribute__((__format__(__printf__, 2, 3))); 259173412Skevlovoid tracet(int, const char *, ...) 26066807Skris __attribute__((__format__(__printf__, 2, 3))); 261173412Skevlounsigned int if_maxindex(void); 262173412Skevlostruct ifc *ifc_find(char *); 263173412Skevlostruct iff *iff_find(struct ifc *, int); 264173412Skevlovoid setindex2ifc(int, struct ifc *); 26555163Sshin 26655163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 26755163Sshin 26855163Sshinint 26955163Sshinmain(argc, argv) 27055163Sshin int argc; 27155163Sshin char **argv; 27255163Sshin{ 27355163Sshin int ch; 27455163Sshin int error = 0; 27555163Sshin struct ifc *ifcp; 27655163Sshin sigset_t mask, omask; 27755163Sshin FILE *pidfile; 27855163Sshin char *progname; 27962607Sitojun char *ep; 28055163Sshin 28155163Sshin progname = strrchr(*argv, '/'); 28255163Sshin if (progname) 28355163Sshin progname++; 28455163Sshin else 28555163Sshin progname = *argv; 28655163Sshin 28755163Sshin pid = getpid(); 28878064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 28955163Sshin switch (ch) { 29055163Sshin case 'A': 29155163Sshin case 'N': 29255163Sshin case 'O': 29355163Sshin case 'T': 29455163Sshin case 'L': 29562607Sitojun if (nfilter >= MAXFILTER) { 29655163Sshin fatal("Exceeds MAXFILTER"); 29762607Sitojun /*NOTREACHED*/ 29862607Sitojun } 29955163Sshin filtertype[nfilter] = ch; 30055163Sshin filter[nfilter++] = allocopy(optarg); 30155163Sshin break; 30255163Sshin case 't': 30362607Sitojun ep = NULL; 30462607Sitojun routetag = strtoul(optarg, &ep, 0); 30562607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 30655163Sshin fatal("invalid route tag"); 30755163Sshin /*NOTREACHED*/ 30855163Sshin } 30955163Sshin break; 31055163Sshin case 'R': 31162607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 31255163Sshin fatal("Can not write to routelog"); 31362607Sitojun /*NOTREACHED*/ 31462607Sitojun } 31555163Sshin break; 31662607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 31762607Sitojun FLAG('a', aflag, 1); break; 31862607Sitojun FLAG('d', dflag, 1); break; 31962607Sitojun FLAG('D', dflag, 2); break; 32062607Sitojun FLAG('h', hflag, 1); break; 32162607Sitojun FLAG('l', lflag, 1); break; 32262607Sitojun FLAG('n', nflag, 1); break; 32362607Sitojun FLAG('q', qflag, 1); break; 32462607Sitojun FLAG('s', sflag, 1); break; 32562607Sitojun FLAG('S', Sflag, 1); break; 32655163Sshin#undef FLAG 32755163Sshin default: 32855163Sshin fatal("Invalid option specified, terminating"); 32962607Sitojun /*NOTREACHED*/ 33055163Sshin } 33155163Sshin } 33255163Sshin argc -= optind; 33355163Sshin argv += optind; 33478064Sume if (argc > 0) { 33555163Sshin fatal("bogus extra arguments"); 33678064Sume /*NOTREACHED*/ 33778064Sume } 33855163Sshin 33955163Sshin if (geteuid()) { 34055163Sshin nflag = 1; 34155163Sshin fprintf(stderr, "No kernel update is allowed\n"); 34255163Sshin } 343119037Sume 344119037Sume if (dflag == 0) { 345119037Sume if (daemon(0, 0) < 0) { 346119037Sume fatal("daemon"); 347119037Sume /*NOTREACHED*/ 348119037Sume } 349119037Sume } 350119037Sume 35155163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 35255163Sshin logopened++; 35378064Sume 35478064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 35578064Sume fatal("malloc"); 35678064Sume memset(ripbuf, 0, RIP6_MAXMTU); 35778064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 35878064Sume ripbuf->rip6_vers = RIP6_VERSION; 35978064Sume ripbuf->rip6_res1[0] = 0; 36078064Sume ripbuf->rip6_res1[1] = 0; 36178064Sume 36255163Sshin init(); 36355163Sshin ifconfig(); 36455163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 36555163Sshin if (ifcp->ifc_index < 0) { 36655163Sshin fprintf(stderr, 36755163Sshin"No ifindex found at %s (no link-local address?)\n", 36855163Sshin ifcp->ifc_name); 36955163Sshin error++; 37055163Sshin } 37155163Sshin } 37255163Sshin if (error) 37355163Sshin exit(1); 37478064Sume if (loopifcp == NULL) { 37555163Sshin fatal("No loopback found"); 37678064Sume /*NOTREACHED*/ 37778064Sume } 37855163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 37955163Sshin ifrt(ifcp, 0); 38055163Sshin filterconfig(); 38155163Sshin krtread(0); 38255163Sshin if (dflag) 38355163Sshin ifrtdump(0); 38455163Sshin 385122677Sume#if 1 38655163Sshin pid = getpid(); 38755163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 38855163Sshin fprintf(pidfile, "%d\n", pid); 38955163Sshin fclose(pidfile); 39055163Sshin } 391122677Sume#endif 39255163Sshin 39378064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 39455163Sshin fatal("malloc"); 39578064Sume /*NOTREACHED*/ 39678064Sume } 39762607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 39855163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 39955163Sshin ripbuf->rip6_vers = RIP6_VERSION; 40055163Sshin ripbuf->rip6_res1[0] = 0; 40155163Sshin ripbuf->rip6_res1[1] = 0; 40255163Sshin 40378064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 40478064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 40578064Sume signal(SIGTERM, sighandler) == SIG_ERR || 40678064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 40778064Sume signal(SIGHUP, sighandler) == SIG_ERR || 40878064Sume signal(SIGINT, sighandler) == SIG_ERR) { 40978064Sume fatal("signal"); 41078064Sume /*NOTREACHED*/ 41178064Sume } 41255163Sshin /* 41355163Sshin * To avoid rip packet congestion (not on a cable but in this 41455163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 41555163Sshin * packets. 41655163Sshin */ 41755163Sshin alarm(ripinterval(INIT_INTERVAL6)); 41855163Sshin 41955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 420119041Sume if (iff_find(ifcp, 'N')) 421119041Sume continue; 42255163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 42355163Sshin sendrequest(ifcp); 42455163Sshin } 42555163Sshin 42655163Sshin syslog(LOG_INFO, "**** Started ****"); 42755163Sshin sigemptyset(&mask); 42855163Sshin sigaddset(&mask, SIGALRM); 42955163Sshin while (1) { 43078064Sume if (seenalrm) { 43178064Sume ripalarm(); 43278064Sume seenalrm = 0; 43378064Sume continue; 43478064Sume } 43578064Sume if (seenquit) { 43678064Sume rtdexit(); 43778064Sume seenquit = 0; 43878064Sume continue; 43978064Sume } 44078064Sume if (seenusr1) { 44178064Sume ifrtdump(SIGUSR1); 44278064Sume seenusr1 = 0; 44378064Sume continue; 44478064Sume } 44578064Sume 446119076Sume#ifdef HAVE_POLL_H 447119076Sume switch (poll(set, 2, INFTIM)) 448119076Sume#else 449119070Sume memcpy(recvecp, sockvecp, fdmasks); 450119076Sume switch (select(maxfd + 1, recvecp, 0, 0, 0)) 451119076Sume#endif 452119076Sume { 45355163Sshin case -1: 45478064Sume if (errno != EINTR) { 45578064Sume fatal("select"); 45678064Sume /*NOTREACHED*/ 45778064Sume } 45878064Sume continue; 45955163Sshin case 0: 46055163Sshin continue; 46155163Sshin default: 462119076Sume#ifdef HAVE_POLL_H 463119076Sume if (set[0].revents & POLLIN) 464119076Sume#else 465119076Sume if (FD_ISSET(ripsock, recvecp)) 466119076Sume#endif 467119076Sume { 46855163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 46955163Sshin riprecv(); 47055163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 47155163Sshin } 472119076Sume#ifdef HAVE_POLL_H 473119076Sume if (set[1].revents & POLLIN) 474119076Sume#else 475119076Sume if (FD_ISSET(rtsock, recvecp)) 476119076Sume#endif 477119076Sume { 47855163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 47955163Sshin rtrecv(); 48055163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 48155163Sshin } 48255163Sshin } 48355163Sshin } 48455163Sshin} 48555163Sshin 48678064Sumevoid 487119079Sumesighandler(signo) 488119079Sume int signo; 48978064Sume{ 49078064Sume 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; 584119081Sume char port[NI_MAXSERV]; 58555163Sshin 58655163Sshin ifc = (struct ifc *)NULL; 58755163Sshin nifc = 0; 58855163Sshin nindex2ifc = 0; /*initial guess*/ 58955163Sshin index2ifc = NULL; 590119081Sume snprintf(port, sizeof(port), "%u", RIP6_PORT); 59155163Sshin 59255163Sshin memset(&hints, 0, sizeof(hints)); 59355163Sshin hints.ai_family = PF_INET6; 59455163Sshin hints.ai_socktype = SOCK_DGRAM; 595119080Sume hints.ai_protocol = IPPROTO_UDP; 59655163Sshin hints.ai_flags = AI_PASSIVE; 59755163Sshin error = getaddrinfo(NULL, port, &hints, &res); 59878064Sume if (error) { 59966807Skris fatal("%s", gai_strerror(error)); 60078064Sume /*NOTREACHED*/ 60178064Sume } 60278064Sume if (res->ai_next) { 60355163Sshin fatal(":: resolved to multiple address"); 60478064Sume /*NOTREACHED*/ 60578064Sume } 60655163Sshin 60755163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 60878064Sume if (ripsock < 0) { 60955163Sshin fatal("rip socket"); 61078064Sume /*NOTREACHED*/ 61178064Sume } 612119034Sume#ifdef IPV6_V6ONLY 613119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 614119034Sume &int1, sizeof(int1)) < 0) { 615119034Sume fatal("rip IPV6_V6ONLY"); 616119034Sume /*NOTREACHED*/ 617119034Sume } 618119034Sume#endif 61978064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 62055163Sshin fatal("rip bind"); 62178064Sume /*NOTREACHED*/ 62278064Sume } 62355163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 62478064Sume &int255, sizeof(int255)) < 0) { 62555163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 62678064Sume /*NOTREACHED*/ 62778064Sume } 62855163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 62978064Sume &int0, sizeof(int0)) < 0) { 63055163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 63178064Sume /*NOTREACHED*/ 63278064Sume } 63362921Sume 63462607Sitojun#ifdef IPV6_RECVPKTINFO 635119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 636119034Sume &int1, sizeof(int1)) < 0) { 63762607Sitojun fatal("rip IPV6_RECVPKTINFO"); 63878064Sume /*NOTREACHED*/ 63978064Sume } 64062607Sitojun#else /* old adv. API */ 641119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 642119034Sume &int1, sizeof(int1)) < 0) { 64355163Sshin fatal("rip IPV6_PKTINFO"); 64478064Sume /*NOTREACHED*/ 64578064Sume } 64662607Sitojun#endif 64755163Sshin 648164339Ssuz#ifdef IPV6_RECVPKTINFO 649164339Ssuz if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 650164339Ssuz &int1, sizeof(int1)) < 0) { 651164339Ssuz fatal("rip IPV6_RECVHOPLIMIT"); 652164339Ssuz /*NOTREACHED*/ 653164339Ssuz } 654164339Ssuz#else /* old adv. API */ 655164339Ssuz if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT, 656164339Ssuz &int1, sizeof(int1)) < 0) { 657164339Ssuz fatal("rip IPV6_HOPLIMIT"); 658164339Ssuz /*NOTREACHED*/ 659164339Ssuz } 660164339Ssuz#endif 661164339Ssuz 66255163Sshin memset(&hints, 0, sizeof(hints)); 66355163Sshin hints.ai_family = PF_INET6; 66455163Sshin hints.ai_socktype = SOCK_DGRAM; 665119080Sume hints.ai_protocol = IPPROTO_UDP; 66655163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 66778064Sume if (error) { 66866807Skris fatal("%s", gai_strerror(error)); 66978064Sume /*NOTREACHED*/ 67078064Sume } 67178064Sume if (res->ai_next) { 67255163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 67378064Sume /*NOTREACHED*/ 67478064Sume } 67555163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 67655163Sshin 677119076Sume#ifdef HAVE_POLL_H 678119076Sume set[0].fd = ripsock; 679119076Sume set[0].events = POLLIN; 680119076Sume#else 681119070Sume maxfd = ripsock; 682119076Sume#endif 68355163Sshin 68455163Sshin if (nflag == 0) { 68578064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 68655163Sshin fatal("route socket"); 68778064Sume /*NOTREACHED*/ 68878064Sume } 689119076Sume#ifdef HAVE_POLL_H 690119076Sume set[1].fd = rtsock; 691119076Sume set[1].events = POLLIN; 692119076Sume#else 693119070Sume if (rtsock > maxfd) 694119070Sume maxfd = rtsock; 695119076Sume#endif 696119076Sume } else { 697119076Sume#ifdef HAVE_POLL_H 698119076Sume set[1].fd = -1; 699119076Sume#else 70055163Sshin rtsock = -1; /*just for safety */ 701119076Sume#endif 702119076Sume } 703119070Sume 704119076Sume#ifndef HAVE_POLL_H 705119070Sume fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 706119070Sume if ((sockvecp = malloc(fdmasks)) == NULL) { 707119070Sume fatal("malloc"); 708119070Sume /*NOTREACHED*/ 709119070Sume } 710119070Sume if ((recvecp = malloc(fdmasks)) == NULL) { 711119070Sume fatal("malloc"); 712119070Sume /*NOTREACHED*/ 713119070Sume } 714119070Sume memset(sockvecp, 0, fdmasks); 715119070Sume FD_SET(ripsock, sockvecp); 716119070Sume if (rtsock >= 0) 717119070Sume FD_SET(rtsock, sockvecp); 718119076Sume#endif 71955163Sshin} 72055163Sshin 72162607Sitojun#define RIPSIZE(n) \ 72262607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 72355163Sshin 72455163Sshin/* 72555163Sshin * ripflush flushes the rip datagram stored in the rip buffer 72655163Sshin */ 72755163Sshinstatic int nrt; 72855163Sshinstatic struct netinfo6 *np; 72955163Sshin 73055163Sshinvoid 731119031Sumeripflush(ifcp, sin6) 73255163Sshin struct ifc *ifcp; 733119031Sume struct sockaddr_in6 *sin6; 73455163Sshin{ 73555163Sshin int i; 73655163Sshin int error; 73755163Sshin 73855163Sshin if (ifcp) 73955163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 74055163Sshin ifcp->ifc_name, nrt, 741119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 74255163Sshin else 74355163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 744119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 74555163Sshin if (dflag >= 2) { 74655163Sshin np = ripbuf->rip6_nets; 74755163Sshin for (i = 0; i < nrt; i++, np++) { 74855163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 74955163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 75062607Sitojun trace(2, " NextHop reset"); 75155163Sshin else { 75255163Sshin trace(2, " NextHop %s", 75355163Sshin inet6_n2p(&np->rip6_dest)); 75455163Sshin } 75555163Sshin } else { 75655163Sshin trace(2, " %s/%d[%d]", 75755163Sshin inet6_n2p(&np->rip6_dest), 75855163Sshin np->rip6_plen, np->rip6_metric); 75955163Sshin } 76055163Sshin if (np->rip6_tag) { 76155163Sshin trace(2, " tag=0x%04x", 76255163Sshin ntohs(np->rip6_tag) & 0xffff); 76355163Sshin } 76455163Sshin trace(2, "\n"); 76555163Sshin } 76655163Sshin } 767119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 76855163Sshin if (error == EAFNOSUPPORT) { 76955163Sshin /* Protocol not supported */ 77055163Sshin tracet(1, "Could not send info to %s (%s): " 77155163Sshin "set IFF_UP to 0\n", 77255163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 77355163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 77455163Sshin } 77555163Sshin nrt = 0; np = ripbuf->rip6_nets; 77655163Sshin} 77755163Sshin 77855163Sshin/* 77955163Sshin * Generate RIP6_RESPONSE packets and send them. 78055163Sshin */ 78155163Sshinvoid 782119031Sumeripsend(ifcp, sin6, flag) 78355163Sshin struct ifc *ifcp; 784119031Sume struct sockaddr_in6 *sin6; 78555163Sshin int flag; 78655163Sshin{ 78755163Sshin struct riprt *rrt; 78855163Sshin struct in6_addr *nh; /* next hop */ 78978064Sume int maxrte; 79055163Sshin 791119084Sume if (qflag) 792119084Sume return; 793119084Sume 79455163Sshin if (ifcp == NULL) { 79555163Sshin /* 79655163Sshin * Request from non-link local address is not 79755163Sshin * a regular route6d update. 79855163Sshin */ 79962607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 80062607Sitojun sizeof(struct udphdr) - 80155163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 80255163Sshin sizeof(struct netinfo6); 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; 80755163Sshin /* Put the route to the buffer */ 80855163Sshin *np = rrt->rrt_info; 80955163Sshin np++; nrt++; 81055163Sshin if (nrt == maxrte) { 811119031Sume ripflush(NULL, sin6); 81255163Sshin nh = NULL; 81355163Sshin } 81455163Sshin } 81555163Sshin if (nrt) /* Send last packet */ 816119031Sume ripflush(NULL, sin6); 81755163Sshin return; 81855163Sshin } 81955163Sshin 82062607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 82155163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 82255163Sshin return; 82378064Sume 82478064Sume /* -N: no use */ 82555163Sshin if (iff_find(ifcp, 'N') != NULL) 82655163Sshin return; 82778064Sume 82878064Sume /* -T: generate default route only */ 82955163Sshin if (iff_find(ifcp, 'T') != NULL) { 83055163Sshin struct netinfo6 rrt_info; 83155163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 83255163Sshin rrt_info.rip6_dest = in6addr_any; 83355163Sshin rrt_info.rip6_plen = 0; 83455163Sshin rrt_info.rip6_metric = 1; 83578064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 83655163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 83755163Sshin np = ripbuf->rip6_nets; 83855163Sshin *np = rrt_info; 83955163Sshin nrt = 1; 840119031Sume ripflush(ifcp, sin6); 84155163Sshin return; 84255163Sshin } 84378064Sume 84462607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 84562607Sitojun sizeof(struct udphdr) - 84655163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 84755163Sshin sizeof(struct netinfo6); 84878064Sume 84955163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 85055163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 85162607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 85255163Sshin continue; 85378064Sume 85478064Sume /* Need to check filter here */ 85578064Sume if (out_filter(rrt, ifcp) == 0) 85655163Sshin continue; 85778064Sume 85855163Sshin /* Check split horizon and other conditions */ 85955163Sshin if (tobeadv(rrt, ifcp) == 0) 86055163Sshin continue; 86178064Sume 86255163Sshin /* Only considers the routes with flag if specified */ 86362607Sitojun if ((flag & RRTF_CHANGED) && 86462607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 86555163Sshin continue; 86678064Sume 86755163Sshin /* Check nexthop */ 86855163Sshin if (rrt->rrt_index == ifcp->ifc_index && 86955163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 87062607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 87155163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 87255163Sshin if (nrt == maxrte - 2) 873119031Sume ripflush(ifcp, sin6); 87455163Sshin np->rip6_dest = rrt->rrt_gw; 87555163Sshin np->rip6_plen = 0; 87655163Sshin np->rip6_tag = 0; 87755163Sshin np->rip6_metric = NEXTHOP_METRIC; 87855163Sshin nh = &rrt->rrt_gw; 87955163Sshin np++; nrt++; 88055163Sshin } 88155163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 88255163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 88362607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 88455163Sshin /* Reset nexthop */ 88555163Sshin if (nrt == maxrte - 2) 886119031Sume ripflush(ifcp, sin6); 88755163Sshin memset(np, 0, sizeof(struct netinfo6)); 88855163Sshin np->rip6_metric = NEXTHOP_METRIC; 88955163Sshin nh = NULL; 89055163Sshin np++; nrt++; 89155163Sshin } 89278064Sume 89355163Sshin /* Put the route to the buffer */ 89455163Sshin *np = rrt->rrt_info; 89555163Sshin np++; nrt++; 89655163Sshin if (nrt == maxrte) { 897119031Sume ripflush(ifcp, sin6); 89855163Sshin nh = NULL; 89955163Sshin } 90055163Sshin } 90155163Sshin if (nrt) /* Send last packet */ 902119031Sume ripflush(ifcp, sin6); 90355163Sshin} 90455163Sshin 90555163Sshin/* 90678064Sume * outbound filter logic, per-route/interface. 90778064Sume */ 90878064Sumeint 90978064Sumeout_filter(rrt, ifcp) 91078064Sume struct riprt *rrt; 91178064Sume struct ifc *ifcp; 91278064Sume{ 91378064Sume struct iff *iffp; 91478064Sume struct in6_addr ia; 91578064Sume int ok; 91678064Sume 91778064Sume /* 91878064Sume * -A: filter out less specific routes, if we have aggregated 91978064Sume * route configured. 92078064Sume */ 92178064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 92278064Sume if (iffp->iff_type != 'A') 92378064Sume continue; 92478064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 92578064Sume continue; 92678064Sume ia = rrt->rrt_info.rip6_dest; 92778064Sume applyplen(&ia, iffp->iff_plen); 92878064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 92978064Sume return 0; 93078064Sume } 93178064Sume 93278064Sume /* 93378064Sume * if it is an aggregated route, advertise it only to the 93478064Sume * interfaces specified on -A. 93578064Sume */ 93678064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 93778064Sume ok = 0; 93878064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 93978064Sume if (iffp->iff_type != 'A') 94078064Sume continue; 94178064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 94278064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 94378064Sume &iffp->iff_addr)) { 94478064Sume ok = 1; 94578064Sume break; 94678064Sume } 94778064Sume } 94878064Sume if (!ok) 94978064Sume return 0; 95078064Sume } 95178064Sume 95278064Sume /* 95378064Sume * -O: advertise only if prefix matches the configured prefix. 95478064Sume */ 95578064Sume if (iff_find(ifcp, 'O')) { 95678064Sume ok = 0; 95778064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 95878064Sume if (iffp->iff_type != 'O') 95978064Sume continue; 96078064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 96178064Sume continue; 96278064Sume ia = rrt->rrt_info.rip6_dest; 96378064Sume applyplen(&ia, iffp->iff_plen); 96478064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 96578064Sume ok = 1; 96678064Sume break; 96778064Sume } 96878064Sume } 96978064Sume if (!ok) 97078064Sume return 0; 97178064Sume } 97278064Sume 97378064Sume /* the prefix should be advertised */ 97478064Sume return 1; 97578064Sume} 97678064Sume 97778064Sume/* 97855163Sshin * Determine if the route is to be advertised on the specified interface. 97955163Sshin * It checks options specified in the arguments and the split horizon rule. 98055163Sshin */ 98155163Sshinint 98255163Sshintobeadv(rrt, ifcp) 98355163Sshin struct riprt *rrt; 98455163Sshin struct ifc *ifcp; 98555163Sshin{ 98655163Sshin 98755163Sshin /* Special care for static routes */ 98855163Sshin if (rrt->rrt_flags & RTF_STATIC) { 98962607Sitojun /* XXX don't advertise reject/blackhole routes */ 99062607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 99162607Sitojun return 0; 99262607Sitojun 99355163Sshin if (Sflag) /* Yes, advertise it anyway */ 99455163Sshin return 1; 99555163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 99655163Sshin return 1; 99755163Sshin return 0; 99855163Sshin } 99955163Sshin /* Regular split horizon */ 100055163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 100155163Sshin return 0; 100255163Sshin return 1; 100355163Sshin} 100455163Sshin 100555163Sshin/* 100655163Sshin * Send a rip packet actually. 100755163Sshin */ 100855163Sshinint 1009119031Sumesendpacket(sin6, len) 1010119031Sume struct sockaddr_in6 *sin6; 101155163Sshin int len; 101255163Sshin{ 101355163Sshin struct msghdr m; 101455163Sshin struct cmsghdr *cm; 101555163Sshin struct iovec iov[2]; 101655163Sshin u_char cmsgbuf[256]; 101755163Sshin struct in6_pktinfo *pi; 101878064Sume int idx; 101955163Sshin struct sockaddr_in6 sincopy; 102055163Sshin 102155163Sshin /* do not overwrite the given sin */ 1022119031Sume sincopy = *sin6; 1023119031Sume sin6 = &sincopy; 102455163Sshin 1025119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 1026243231Shrs IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 1027243231Shrs idx = sin6->sin6_scope_id; 1028243231Shrs else 102978064Sume idx = 0; 103055163Sshin 1031119031Sume m.msg_name = (caddr_t)sin6; 1032119031Sume m.msg_namelen = sizeof(*sin6); 103355163Sshin iov[0].iov_base = (caddr_t)ripbuf; 103455163Sshin iov[0].iov_len = len; 103555163Sshin m.msg_iov = iov; 103655163Sshin m.msg_iovlen = 1; 103778064Sume if (!idx) { 103855163Sshin m.msg_control = NULL; 103955163Sshin m.msg_controllen = 0; 104055163Sshin } else { 104155163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 104255163Sshin cm = (struct cmsghdr *)cmsgbuf; 104355163Sshin m.msg_control = (caddr_t)cm; 104455163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 104555163Sshin 104655163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 104755163Sshin cm->cmsg_level = IPPROTO_IPV6; 104855163Sshin cm->cmsg_type = IPV6_PKTINFO; 104955163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 105055163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 105178064Sume pi->ipi6_ifindex = idx; 105255163Sshin } 105355163Sshin 105455163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 105555163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 105655163Sshin return errno; 105755163Sshin } 105862921Sume 105955163Sshin return 0; 106055163Sshin} 106155163Sshin 106255163Sshin/* 106378064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 106455163Sshin * table if necessary. 106555163Sshin */ 106655163Sshinvoid 106755163Sshinriprecv() 106855163Sshin{ 106955163Sshin struct ifc *ifcp, *ic; 107055163Sshin struct sockaddr_in6 fsock; 107155163Sshin struct in6_addr nh; /* next hop */ 107255163Sshin struct rip6 *rp; 107355163Sshin struct netinfo6 *np, *nq; 107455163Sshin struct riprt *rrt; 1075122677Sume ssize_t len, nn; 1076122677Sume unsigned int need_trigger, idx; 107755163Sshin char buf[4 * RIP6_MAXMTU]; 107855163Sshin time_t t; 107955163Sshin struct msghdr m; 108055163Sshin struct cmsghdr *cm; 108155163Sshin struct iovec iov[2]; 108255163Sshin u_char cmsgbuf[256]; 1083164339Ssuz struct in6_pktinfo *pi = NULL; 1084164339Ssuz int *hlimp = NULL; 108555163Sshin struct iff *iffp; 108655163Sshin struct in6_addr ia; 108755163Sshin int ok; 108878064Sume time_t t_half_lifetime; 108955163Sshin 109055163Sshin need_trigger = 0; 109162921Sume 109255163Sshin m.msg_name = (caddr_t)&fsock; 109355163Sshin m.msg_namelen = sizeof(fsock); 109455163Sshin iov[0].iov_base = (caddr_t)buf; 109555163Sshin iov[0].iov_len = sizeof(buf); 109655163Sshin m.msg_iov = iov; 109755163Sshin m.msg_iovlen = 1; 109855163Sshin cm = (struct cmsghdr *)cmsgbuf; 109955163Sshin m.msg_control = (caddr_t)cm; 110055163Sshin m.msg_controllen = sizeof(cmsgbuf); 110178064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 110255163Sshin fatal("recvmsg"); 110378064Sume /*NOTREACHED*/ 110478064Sume } 110578064Sume idx = 0; 110655163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 110755163Sshin cm; 110855163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 1109164339Ssuz if (cm->cmsg_level != IPPROTO_IPV6) 1110164339Ssuz continue; 1111164339Ssuz switch (cm->cmsg_type) { 1112164339Ssuz case IPV6_PKTINFO: 1113164339Ssuz if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) { 1114164339Ssuz trace(1, 1115164339Ssuz "invalid cmsg length for IPV6_PKTINFO\n"); 1116164339Ssuz return; 1117164339Ssuz } 111855163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 111978064Sume idx = pi->ipi6_ifindex; 112055163Sshin break; 1121164339Ssuz case IPV6_HOPLIMIT: 1122164339Ssuz if (cm->cmsg_len != CMSG_LEN(sizeof(int))) { 1123164339Ssuz trace(1, 1124164339Ssuz "invalid cmsg length for IPV6_HOPLIMIT\n"); 1125164339Ssuz return; 1126164339Ssuz } 1127164339Ssuz hlimp = (int *)CMSG_DATA(cm); 1128164339Ssuz break; 112955163Sshin } 113055163Sshin } 113155163Sshin 1132121779Ssuz if (len < sizeof(struct rip6)) { 1133121779Ssuz trace(1, "Packet too short\n"); 1134121779Ssuz return; 1135121779Ssuz } 1136121779Ssuz 1137164339Ssuz if (pi == NULL || hlimp == NULL) { 1138164339Ssuz /* 1139164339Ssuz * This can happen when the kernel failed to allocate memory 1140164339Ssuz * for the ancillary data. Although we might be able to handle 1141164339Ssuz * some cases without this info, those are minor and not so 1142164339Ssuz * important, so it's better to discard the packet for safer 1143164339Ssuz * operation. 1144164339Ssuz */ 1145164339Ssuz trace(1, "IPv6 packet information cannot be retrieved\n"); 1146164339Ssuz return; 1147164339Ssuz } 1148164339Ssuz 114955163Sshin nh = fsock.sin6_addr; 115055163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 115155163Sshin sizeof(struct netinfo6); 115255163Sshin rp = (struct rip6 *)buf; 115355163Sshin np = rp->rip6_nets; 115455163Sshin 1155119035Sume if (rp->rip6_vers != RIP6_VERSION) { 115655163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 115755163Sshin return; 115855163Sshin } 115955163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 116078064Sume if (idx && idx < nindex2ifc) { 116178064Sume ifcp = index2ifc[idx]; 116255163Sshin riprequest(ifcp, np, nn, &fsock); 116355163Sshin } else { 116455163Sshin riprequest(NULL, np, nn, &fsock); 116555163Sshin } 116662607Sitojun return; 116762607Sitojun } 116855163Sshin 116955163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 1170164339Ssuz trace(1, "Response from non-ll addr: %s\n", 117178064Sume inet6_n2p(&fsock.sin6_addr)); 117255163Sshin return; /* Ignore packets from non-link-local addr */ 117355163Sshin } 1174164339Ssuz if (ntohs(fsock.sin6_port) != RIP6_PORT) { 1175164339Ssuz trace(1, "Response from non-rip port from %s\n", 1176164339Ssuz inet6_n2p(&fsock.sin6_addr)); 1177164339Ssuz return; 1178164339Ssuz } 1179164339Ssuz if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) { 1180164339Ssuz trace(1, 1181164339Ssuz "Response packet with a smaller hop limit (%d) from %s\n", 1182164339Ssuz *hlimp, inet6_n2p(&fsock.sin6_addr)); 1183164339Ssuz return; 1184164339Ssuz } 1185164339Ssuz /* 1186164339Ssuz * Further validation: since this program does not send off-link 1187164339Ssuz * requests, an incoming response must always come from an on-link 1188164339Ssuz * node. Although this is normally ensured by the source address 1189164339Ssuz * check above, it may not 100% be safe because there are router 1190164339Ssuz * implementations that (invalidly) allow a packet with a link-local 1191164339Ssuz * source address to be forwarded to a different link. 1192164339Ssuz * So we also check whether the destination address is a link-local 1193164339Ssuz * address or the hop limit is 255. Note that RFC2080 does not require 1194164339Ssuz * the specific hop limit for a unicast response, so we cannot assume 1195164339Ssuz * the limitation. 1196164339Ssuz */ 1197164339Ssuz if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) { 1198164339Ssuz trace(1, 1199164339Ssuz "Response packet possibly from an off-link node: " 1200164339Ssuz "from %s to %s hlim=%d\n", 1201164339Ssuz inet6_n2p(&fsock.sin6_addr), 1202164339Ssuz inet6_n2p(&pi->ipi6_addr), *hlimp); 1203164339Ssuz return; 1204164339Ssuz } 1205164339Ssuz 1206243231Shrs idx = fsock.sin6_scope_id; 120778064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 120855163Sshin if (!ifcp) { 120978064Sume trace(1, "Packets to unknown interface index %d\n", idx); 121055163Sshin return; /* Ignore it */ 121155163Sshin } 121255163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 121355163Sshin return; /* The packet is from me; ignore */ 121455163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 121555163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 121662607Sitojun return; 121755163Sshin } 121878064Sume 121978064Sume /* -N: no use */ 122055163Sshin if (iff_find(ifcp, 'N') != NULL) 122155163Sshin return; 122278064Sume 1223228674Sdim tracet(1, "Recv(%s): from %s.%d info(%zd)\n", 122478064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 122555163Sshin 122655163Sshin t = time(NULL); 122778064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 122855163Sshin for (; nn; nn--, np++) { 122955163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 123055163Sshin /* modify neighbor address */ 123155163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 123255163Sshin nh = np->rip6_dest; 123355163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 123455163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 123555163Sshin nh = fsock.sin6_addr; 123655163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 123755163Sshin } else { 123855163Sshin nh = fsock.sin6_addr; 123955163Sshin trace(1, "\tInvalid Nexthop: %s\n", 124078064Sume inet6_n2p(&np->rip6_dest)); 124155163Sshin } 124255163Sshin continue; 124355163Sshin } 124455163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 124555163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 124655163Sshin inet6_n2p(&np->rip6_dest), 124755163Sshin np->rip6_plen, np->rip6_metric); 124855163Sshin continue; 124955163Sshin } 125055163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 125155163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 125255163Sshin inet6_n2p(&np->rip6_dest), 125355163Sshin np->rip6_plen, np->rip6_metric); 125455163Sshin continue; 125555163Sshin } 125655163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 125755163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 125855163Sshin inet6_n2p(&np->rip6_dest), 125955163Sshin np->rip6_plen, np->rip6_metric); 126055163Sshin continue; 126155163Sshin } 126255163Sshin /* may need to pass sitelocal prefix in some case, however*/ 126355163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 126455163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 126555163Sshin inet6_n2p(&np->rip6_dest), 126655163Sshin np->rip6_plen, np->rip6_metric); 126755163Sshin continue; 126855163Sshin } 126955163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 127055163Sshin inet6_n2p(&np->rip6_dest), 127155163Sshin np->rip6_plen, np->rip6_metric); 127255163Sshin if (np->rip6_tag) 127355163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 127462607Sitojun if (dflag >= 2) { 127562607Sitojun ia = np->rip6_dest; 127662607Sitojun applyplen(&ia, np->rip6_plen); 127762607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 127862607Sitojun trace(2, " [junk outside prefix]"); 127962607Sitojun } 128055163Sshin 128178064Sume /* 128278064Sume * -L: listen only if the prefix matches the configuration 128378064Sume */ 128455163Sshin ok = 1; /* if there's no L filter, it is ok */ 128555163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 128655163Sshin if (iffp->iff_type != 'L') 128755163Sshin continue; 128855163Sshin ok = 0; 128955163Sshin if (np->rip6_plen < iffp->iff_plen) 129055163Sshin continue; 129155163Sshin /* special rule: ::/0 means default, not "in /0" */ 129255163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 129355163Sshin continue; 129462607Sitojun ia = np->rip6_dest; 129555163Sshin applyplen(&ia, iffp->iff_plen); 129655163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 129755163Sshin ok = 1; 129855163Sshin break; 129955163Sshin } 130055163Sshin } 130155163Sshin if (!ok) { 130255163Sshin trace(2, " (filtered)\n"); 130355163Sshin continue; 130455163Sshin } 130555163Sshin 130655163Sshin trace(2, "\n"); 130755163Sshin np->rip6_metric++; 130855163Sshin np->rip6_metric += ifcp->ifc_metric; 130955163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 131055163Sshin np->rip6_metric = HOPCNT_INFINITY6; 131155163Sshin 131255163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 131378064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 131455163Sshin if (rrt->rrt_t == 0) 131555163Sshin continue; /* Intf route has priority */ 131655163Sshin nq = &rrt->rrt_info; 131755163Sshin if (nq->rip6_metric > np->rip6_metric) { 131855163Sshin if (rrt->rrt_index == ifcp->ifc_index && 131955163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 132055163Sshin /* Small metric from the same gateway */ 132155163Sshin nq->rip6_metric = np->rip6_metric; 132255163Sshin } else { 132355163Sshin /* Better route found */ 132455163Sshin rrt->rrt_index = ifcp->ifc_index; 132555163Sshin /* Update routing table */ 132655163Sshin delroute(nq, &rrt->rrt_gw); 132755163Sshin rrt->rrt_gw = nh; 132855163Sshin *nq = *np; 132955163Sshin addroute(rrt, &nh, ifcp); 133055163Sshin } 133162607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 133255163Sshin rrt->rrt_t = t; 133355163Sshin need_trigger = 1; 133455163Sshin } else if (nq->rip6_metric < np->rip6_metric && 133555163Sshin rrt->rrt_index == ifcp->ifc_index && 133655163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 133755163Sshin /* Got worse route from same gw */ 133855163Sshin nq->rip6_metric = np->rip6_metric; 133955163Sshin rrt->rrt_t = t; 134062607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 134155163Sshin need_trigger = 1; 134255163Sshin } else if (nq->rip6_metric == np->rip6_metric && 134355163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 134478064Sume if (rrt->rrt_index == ifcp->ifc_index && 134578064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 134678064Sume /* same metric, same route from same gw */ 134778064Sume rrt->rrt_t = t; 134878064Sume } else if (rrt->rrt_t < t_half_lifetime) { 134978064Sume /* Better route found */ 135078064Sume rrt->rrt_index = ifcp->ifc_index; 135178064Sume /* Update routing table */ 135278064Sume delroute(nq, &rrt->rrt_gw); 135378064Sume rrt->rrt_gw = nh; 135478064Sume *nq = *np; 135578064Sume addroute(rrt, &nh, ifcp); 135678064Sume rrt->rrt_rflags |= RRTF_CHANGED; 135778064Sume rrt->rrt_t = t; 135878064Sume } 135955163Sshin } 136062607Sitojun /* 136155163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 136278064Sume * do not update age value. Do nothing. 136355163Sshin */ 136455163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 136555163Sshin /* Got a new valid route */ 136678064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 136755163Sshin fatal("malloc: struct riprt"); 136878064Sume /*NOTREACHED*/ 136978064Sume } 137062607Sitojun memset(rrt, 0, sizeof(*rrt)); 137155163Sshin nq = &rrt->rrt_info; 137255163Sshin 137355163Sshin rrt->rrt_same = NULL; 137455163Sshin rrt->rrt_index = ifcp->ifc_index; 137555163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 137655163Sshin rrt->rrt_gw = nh; 137755163Sshin *nq = *np; 137855163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 137955163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 138055163Sshin rrt->rrt_flags |= RTF_HOST; 138155163Sshin 138255163Sshin /* Put the route to the list */ 138355163Sshin rrt->rrt_next = riprt; 138455163Sshin riprt = rrt; 138555163Sshin /* Update routing table */ 138655163Sshin addroute(rrt, &nh, ifcp); 138762607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 138855163Sshin need_trigger = 1; 138955163Sshin rrt->rrt_t = t; 139055163Sshin } 139155163Sshin } 139255163Sshin /* XXX need to care the interval between triggered updates */ 139355163Sshin if (need_trigger) { 139455163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 139555163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 139655163Sshin if (ifcp->ifc_index == ic->ifc_index) 139755163Sshin continue; 139855163Sshin if (ic->ifc_flags & IFF_UP) 139955163Sshin ripsend(ic, &ic->ifc_ripsin, 140062607Sitojun RRTF_CHANGED); 140155163Sshin } 140255163Sshin } 140355163Sshin /* Reset the flag */ 140455163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 140562607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 140655163Sshin } 140755163Sshin} 140855163Sshin 140955163Sshin/* 141055163Sshin * Send all routes request packet to the specified interface. 141155163Sshin */ 141255163Sshinvoid 141355163Sshinsendrequest(ifcp) 141455163Sshin struct ifc *ifcp; 141555163Sshin{ 141655163Sshin struct netinfo6 *np; 141755163Sshin int error; 141855163Sshin 141955163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 142055163Sshin return; 142155163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 142255163Sshin np = ripbuf->rip6_nets; 142355163Sshin memset(np, 0, sizeof(struct netinfo6)); 142455163Sshin np->rip6_metric = HOPCNT_INFINITY6; 142555163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 142655163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 142755163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 142855163Sshin if (error == EAFNOSUPPORT) { 142955163Sshin /* Protocol not supported */ 143055163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 143155163Sshin "set IFF_UP to 0\n", 143255163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 143355163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 143455163Sshin } 143555163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 143655163Sshin} 143755163Sshin 143855163Sshin/* 143955163Sshin * Process a RIP6_REQUEST packet. 144055163Sshin */ 144155163Sshinvoid 1442119031Sumeriprequest(ifcp, np, nn, sin6) 144355163Sshin struct ifc *ifcp; 144455163Sshin struct netinfo6 *np; 144555163Sshin int nn; 1446119031Sume struct sockaddr_in6 *sin6; 144755163Sshin{ 144855163Sshin int i; 144955163Sshin struct riprt *rrt; 145055163Sshin 145155163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 145255163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 145355163Sshin /* Specific response, don't split-horizon */ 145455163Sshin trace(1, "\tRIP Request\n"); 145555163Sshin for (i = 0; i < nn; i++, np++) { 145678064Sume rrt = rtsearch(np, NULL); 145755163Sshin if (rrt) 145855163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 145955163Sshin else 146055163Sshin np->rip6_metric = HOPCNT_INFINITY6; 146155163Sshin } 1462119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 146355163Sshin return; 146455163Sshin } 146555163Sshin /* Whole routing table dump */ 146655163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1467119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 146855163Sshin} 146955163Sshin 147055163Sshin/* 147155163Sshin * Get information of each interface. 147255163Sshin */ 147355163Sshinvoid 147455163Sshinifconfig() 147555163Sshin{ 147662607Sitojun struct ifaddrs *ifap, *ifa; 147762607Sitojun struct ifc *ifcp; 147862607Sitojun struct ipv6_mreq mreq; 147962607Sitojun int s; 148062607Sitojun 148178064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 148262607Sitojun fatal("socket"); 148378064Sume /*NOTREACHED*/ 148478064Sume } 148562607Sitojun 148678064Sume if (getifaddrs(&ifap) != 0) { 148762607Sitojun fatal("getifaddrs"); 148878064Sume /*NOTREACHED*/ 148978064Sume } 149062607Sitojun 149162607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 149262607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 149362607Sitojun continue; 149462607Sitojun ifcp = ifc_find(ifa->ifa_name); 149562607Sitojun /* we are interested in multicast-capable interfaces */ 149662607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 149762607Sitojun continue; 149862607Sitojun if (!ifcp) { 149962607Sitojun /* new interface */ 150078064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 150162607Sitojun fatal("malloc: struct ifc"); 150278064Sume /*NOTREACHED*/ 150378064Sume } 150462607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 150562607Sitojun ifcp->ifc_index = -1; 150662607Sitojun ifcp->ifc_next = ifc; 150762607Sitojun ifc = ifcp; 150862607Sitojun nifc++; 150962607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 151062607Sitojun ifcp->ifc_addr = 0; 151162607Sitojun ifcp->ifc_filter = 0; 151262607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 151362607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 151462607Sitojun ifflags(ifcp->ifc_flags)); 151562607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 151662607Sitojun loopifcp = ifcp; 151762607Sitojun } else { 151862607Sitojun /* update flag, this may be up again */ 151962607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 152062607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 152162607Sitojun ifflags(ifcp->ifc_flags)); 152262607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 152378064Sume ifcp->ifc_cflags |= IFC_CHANGED; 152462607Sitojun } 152562607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 152662607Sitojun } 152762607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 152862607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 152962607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 153062607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 153162607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 153278064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 153378064Sume &mreq, sizeof(mreq)) < 0) { 153462607Sitojun fatal("IPV6_JOIN_GROUP"); 153578064Sume /*NOTREACHED*/ 153678064Sume } 153762607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 153862607Sitojun ifcp->ifc_joined++; 153962607Sitojun } 154062607Sitojun } 154162607Sitojun close(s); 154262607Sitojun freeifaddrs(ifap); 154355163Sshin} 154455163Sshin 154555163Sshinvoid 154662607Sitojunifconfig1(name, sa, ifcp, s) 154762607Sitojun const char *name; 154862607Sitojun const struct sockaddr *sa; 154955163Sshin struct ifc *ifcp; 155055163Sshin int s; 155155163Sshin{ 155255163Sshin struct in6_ifreq ifr; 1553119031Sume const struct sockaddr_in6 *sin6; 155455163Sshin struct ifac *ifa; 155555163Sshin int plen; 155655163Sshin char buf[BUFSIZ]; 155755163Sshin 1558119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1559122677Sume if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) 1560122677Sume return; 1561119031Sume ifr.ifr_addr = *sin6; 1562119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 156378064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 156455163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 156578064Sume /*NOTREACHED*/ 156678064Sume } 156778064Sume plen = sin6mask2len(&ifr.ifr_addr); 1568119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 156955163Sshin /* same interface found */ 157055163Sshin /* need check if something changed */ 157155163Sshin /* XXX not yet implemented */ 157255163Sshin return; 157355163Sshin } 157455163Sshin /* 157555163Sshin * New address is found 157655163Sshin */ 157778064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 157855163Sshin fatal("malloc: struct ifac"); 157978064Sume /*NOTREACHED*/ 158078064Sume } 158162607Sitojun memset(ifa, 0, sizeof(*ifa)); 158255163Sshin ifa->ifa_conf = ifcp; 158355163Sshin ifa->ifa_next = ifcp->ifc_addr; 158455163Sshin ifcp->ifc_addr = ifa; 1585119031Sume ifa->ifa_addr = sin6->sin6_addr; 158655163Sshin ifa->ifa_plen = plen; 1587243231Shrs ifa->ifa_scope_id= sin6->sin6_scope_id; 158855163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1589119031Sume ifr.ifr_addr = *sin6; 159078064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 159155163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 159278064Sume /*NOTREACHED*/ 159378064Sume } 159455163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 159555163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 159655163Sshin trace(1, "found address %s/%d -- %s\n", 159755163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 159855163Sshin } else { 159955163Sshin trace(1, "found address %s/%d\n", 160055163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 160155163Sshin } 160255163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 160355163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 1604243231Shrs ifcp->ifc_index = ifa->ifa_scope_id; 160555163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 1606243231Shrs ifcp->ifc_ripsin.sin6_scope_id = ifcp->ifc_index; 160755163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 160855163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 160955163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 161055163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 161178064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 161255163Sshin fatal("ioctl: SIOCGIFMETRIC"); 161378064Sume /*NOTREACHED*/ 161478064Sume } 161555163Sshin ifcp->ifc_metric = ifr.ifr_metric; 161655163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 161755163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 161878064Sume } else 161978064Sume ifcp->ifc_cflags |= IFC_CHANGED; 162055163Sshin} 162155163Sshin 162255163Sshin/* 162355163Sshin * Receive and process routing messages. 162455163Sshin * Update interface information as necesssary. 162555163Sshin */ 162655163Sshinvoid 162755163Sshinrtrecv() 162855163Sshin{ 162955163Sshin char buf[BUFSIZ]; 163055163Sshin char *p, *q; 163155163Sshin struct rt_msghdr *rtm; 163255163Sshin struct ifa_msghdr *ifam; 163355163Sshin struct if_msghdr *ifm; 163455163Sshin int len; 163578064Sume struct ifc *ifcp, *ic; 163655163Sshin int iface = 0, rtable = 0; 163755163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 163878064Sume struct sockaddr_in6 mask; 163955163Sshin int i, addrs; 164078064Sume struct riprt *rrt; 164155163Sshin 164255163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 164355163Sshin perror("read from rtsock"); 164478064Sume exit(1); 164555163Sshin } 164655163Sshin if (len < sizeof(*rtm)) { 164769279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 164869279Sume len, (u_long)sizeof(*rtm)); 164955163Sshin return; 165055163Sshin } 1651119042Sume if (dflag >= 2) { 1652119042Sume fprintf(stderr, "rtmsg:\n"); 1653119042Sume for (i = 0; i < len; i++) { 1654119042Sume fprintf(stderr, "%02x ", buf[i] & 0xff); 1655119042Sume if (i % 16 == 15) fprintf(stderr, "\n"); 1656119042Sume } 1657119042Sume fprintf(stderr, "\n"); 1658119042Sume } 165955163Sshin 166055163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 166155163Sshin /* safety against bogus message */ 166255163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 166355163Sshin trace(1, "bogus rtmsg: length=%d\n", 166455163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 166555163Sshin break; 166655163Sshin } 166755163Sshin rtm = NULL; 166855163Sshin ifam = NULL; 166955163Sshin ifm = NULL; 167055163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 167155163Sshin case RTM_NEWADDR: 167255163Sshin case RTM_DELADDR: 167355163Sshin ifam = (struct ifa_msghdr *)p; 167455163Sshin addrs = ifam->ifam_addrs; 167555163Sshin q = (char *)(ifam + 1); 167655163Sshin break; 167755163Sshin case RTM_IFINFO: 167855163Sshin ifm = (struct if_msghdr *)p; 167955163Sshin addrs = ifm->ifm_addrs; 168055163Sshin q = (char *)(ifm + 1); 168155163Sshin break; 168255163Sshin default: 168355163Sshin rtm = (struct rt_msghdr *)p; 168455163Sshin addrs = rtm->rtm_addrs; 168555163Sshin q = (char *)(rtm + 1); 168655163Sshin if (rtm->rtm_version != RTM_VERSION) { 168755163Sshin trace(1, "unexpected rtmsg version %d " 168855163Sshin "(should be %d)\n", 168955163Sshin rtm->rtm_version, RTM_VERSION); 169055163Sshin continue; 169155163Sshin } 169255163Sshin if (rtm->rtm_pid == pid) { 169355163Sshin#if 0 169455163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 169555163Sshin#endif 169655163Sshin continue; 169755163Sshin } 169855163Sshin break; 169955163Sshin } 170055163Sshin memset(&rta, 0, sizeof(rta)); 170155163Sshin for (i = 0; i < RTAX_MAX; i++) { 170255163Sshin if (addrs & (1 << i)) { 170355163Sshin rta[i] = (struct sockaddr_in6 *)q; 170455163Sshin q += ROUNDUP(rta[i]->sin6_len); 170555163Sshin } 170655163Sshin } 170755163Sshin 170855163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 170955163Sshin rttypes((struct rt_msghdr *)p), addrs); 171055163Sshin if (dflag >= 2) { 171155163Sshin for (i = 0; 171255163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 171355163Sshin i++) { 171455163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 171555163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 171655163Sshin } 171755163Sshin fprintf(stderr, "\n"); 171855163Sshin } 171955163Sshin 172055163Sshin /* 172155163Sshin * Easy ones first. 172255163Sshin * 172355163Sshin * We may be able to optimize by using ifm->ifm_index or 172455163Sshin * ifam->ifam_index. For simplicity we don't do that here. 172555163Sshin */ 172655163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 172755163Sshin case RTM_NEWADDR: 172855163Sshin case RTM_IFINFO: 172955163Sshin iface++; 173055163Sshin continue; 173155163Sshin case RTM_ADD: 173255163Sshin rtable++; 173355163Sshin continue; 173455163Sshin case RTM_LOSING: 173555163Sshin case RTM_MISS: 173655163Sshin case RTM_GET: 173755163Sshin case RTM_LOCK: 173855163Sshin /* nothing to be done here */ 173955163Sshin trace(1, "\tnothing to be done, ignored\n"); 174055163Sshin continue; 174155163Sshin } 174255163Sshin 174355163Sshin#if 0 174455163Sshin if (rta[RTAX_DST] == NULL) { 174555163Sshin trace(1, "\tno destination, ignored\n"); 174662607Sitojun continue; 174755163Sshin } 174855163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 174955163Sshin trace(1, "\taf mismatch, ignored\n"); 175055163Sshin continue; 175155163Sshin } 175255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 175355163Sshin trace(1, "\tlinklocal destination, ignored\n"); 175455163Sshin continue; 175555163Sshin } 175655163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 175755163Sshin trace(1, "\tloopback destination, ignored\n"); 175855163Sshin continue; /* Loopback */ 175955163Sshin } 176055163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 176155163Sshin trace(1, "\tmulticast destination, ignored\n"); 176255163Sshin continue; 176355163Sshin } 176455163Sshin#endif 176555163Sshin 176655163Sshin /* hard ones */ 176755163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 176855163Sshin case RTM_NEWADDR: 176955163Sshin case RTM_IFINFO: 177055163Sshin case RTM_ADD: 177155163Sshin case RTM_LOSING: 177255163Sshin case RTM_MISS: 177355163Sshin case RTM_GET: 177455163Sshin case RTM_LOCK: 177555163Sshin /* should already be handled */ 177655163Sshin fatal("rtrecv: never reach here"); 177778064Sume /*NOTREACHED*/ 177855163Sshin case RTM_DELETE: 177978064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 178078064Sume trace(1, "\tsome of dst/gw/netamsk are " 178178064Sume "unavailable, ignored\n"); 178255163Sshin break; 178355163Sshin } 178478064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 178578064Sume mask.sin6_len = sizeof(mask); 178678064Sume memset(&mask.sin6_addr, 0xff, 178778064Sume sizeof(mask.sin6_addr)); 178878064Sume rta[RTAX_NETMASK] = &mask; 178978064Sume } else if (!rta[RTAX_NETMASK]) { 179078064Sume trace(1, "\tsome of dst/gw/netamsk are " 179178064Sume "unavailable, ignored\n"); 179278064Sume break; 179378064Sume } 179478064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 179578064Sume rta[RTAX_NETMASK]) == 0) { 179655163Sshin rtable++; /*just to be sure*/ 179755163Sshin } 179855163Sshin break; 179955163Sshin case RTM_CHANGE: 180055163Sshin case RTM_REDIRECT: 180155163Sshin trace(1, "\tnot supported yet, ignored\n"); 180255163Sshin break; 180355163Sshin case RTM_DELADDR: 180455163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 180555163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 180655163Sshin break; 180755163Sshin } 180855163Sshin if (ifam->ifam_index < nindex2ifc) 180955163Sshin ifcp = index2ifc[ifam->ifam_index]; 181055163Sshin else 181155163Sshin ifcp = NULL; 181255163Sshin if (!ifcp) { 181355163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 181455163Sshin ifam->ifam_index); 181555163Sshin break; 181655163Sshin } 181778064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 181878064Sume iface++; 181955163Sshin break; 182055163Sshin case RTM_OLDADD: 182155163Sshin case RTM_OLDDEL: 182255163Sshin trace(1, "\tnot supported yet, ignored\n"); 182355163Sshin break; 182455163Sshin } 182555163Sshin 182655163Sshin } 182755163Sshin 182855163Sshin if (iface) { 182955163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 183055163Sshin ifconfig(); 183155163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 183278064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 183378064Sume if (ifrt(ifcp, 1)) { 183478064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 183578064Sume if (ifcp->ifc_index == ic->ifc_index) 183678064Sume continue; 183778064Sume if (ic->ifc_flags & IFF_UP) 183878064Sume ripsend(ic, &ic->ifc_ripsin, 183978064Sume RRTF_CHANGED); 184078064Sume } 184178064Sume /* Reset the flag */ 184278064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 184378064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 184478064Sume } 184578064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 184678064Sume } 184755163Sshin } 184855163Sshin if (rtable) { 184955163Sshin trace(1, "rtsock: read routing table again\n"); 185055163Sshin krtread(1); 185155163Sshin } 185255163Sshin} 185355163Sshin 185455163Sshin/* 185555163Sshin * remove specified route from the internal routing table. 185655163Sshin */ 185755163Sshinint 185855163Sshinrt_del(sdst, sgw, smask) 185955163Sshin const struct sockaddr_in6 *sdst; 186055163Sshin const struct sockaddr_in6 *sgw; 186155163Sshin const struct sockaddr_in6 *smask; 186255163Sshin{ 186355163Sshin const struct in6_addr *dst = NULL; 186455163Sshin const struct in6_addr *gw = NULL; 186555163Sshin int prefix; 186655163Sshin struct netinfo6 ni6; 186755163Sshin struct riprt *rrt = NULL; 186855163Sshin time_t t_lifetime; 186955163Sshin 187055163Sshin if (sdst->sin6_family != AF_INET6) { 187155163Sshin trace(1, "\tother AF, ignored\n"); 187255163Sshin return -1; 187355163Sshin } 187455163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 187555163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 187655163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 187755163Sshin trace(1, "\taddress %s not interesting, ignored\n", 187855163Sshin inet6_n2p(&sdst->sin6_addr)); 187955163Sshin return -1; 188055163Sshin } 188155163Sshin dst = &sdst->sin6_addr; 188278064Sume if (sgw->sin6_family == AF_INET6) { 188355163Sshin /* easy case */ 188455163Sshin gw = &sgw->sin6_addr; 188578064Sume prefix = sin6mask2len(smask); 188655163Sshin } else if (sgw->sin6_family == AF_LINK) { 188755163Sshin /* 188855163Sshin * Interface route... a hard case. We need to get the prefix 188955163Sshin * length from the kernel, but we now are parsing rtmsg. 189055163Sshin * We'll purge matching routes from my list, then get the 189155163Sshin * fresh list. 189255163Sshin */ 189355163Sshin struct riprt *longest; 1894108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 189555163Sshin inet6_n2p(dst)); 189655163Sshin longest = NULL; 189755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 189855163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 189955163Sshin &sdst->sin6_addr) 190055163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 190155163Sshin if (!longest 190255163Sshin || longest->rrt_info.rip6_plen < 190355163Sshin rrt->rrt_info.rip6_plen) { 190455163Sshin longest = rrt; 190555163Sshin } 190655163Sshin } 190755163Sshin } 190855163Sshin rrt = longest; 190955163Sshin if (!rrt) { 191055163Sshin trace(1, "\tno matching interface route found\n"); 191155163Sshin return -1; 191255163Sshin } 191355163Sshin gw = &in6addr_loopback; 191455163Sshin prefix = rrt->rrt_info.rip6_plen; 191555163Sshin } else { 191678064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 191755163Sshin return -1; 191855163Sshin } 191955163Sshin 192055163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 192155163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 192255163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 192355163Sshin /* age route for interface address */ 192455163Sshin memset(&ni6, 0, sizeof(ni6)); 192555163Sshin ni6.rip6_dest = *dst; 192655163Sshin ni6.rip6_plen = prefix; 192755163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 192855163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 192955163Sshin ni6.rip6_plen); 193078064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 193155163Sshin trace(1, "\tno route found\n"); 193255163Sshin return -1; 193355163Sshin } 193478064Sume#if 0 193555163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 193655163Sshin trace(1, "\tyou can delete static routes only\n"); 193778064Sume } else 193878064Sume#endif 193978064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 194055163Sshin trace(1, "\tgw mismatch: %s <-> ", 194155163Sshin inet6_n2p(&rrt->rrt_gw)); 194255163Sshin trace(1, "%s\n", inet6_n2p(gw)); 194355163Sshin } else { 194455163Sshin trace(1, "\troute found, age it\n"); 194555163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 194655163Sshin rrt->rrt_t = t_lifetime; 194755163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 194855163Sshin } 194955163Sshin } 195055163Sshin return 0; 195155163Sshin} 195255163Sshin 195355163Sshin/* 195455163Sshin * remove specified address from internal interface/routing table. 195555163Sshin */ 195655163Sshinint 195755163Sshinrt_deladdr(ifcp, sifa, smask) 195855163Sshin struct ifc *ifcp; 195955163Sshin const struct sockaddr_in6 *sifa; 196055163Sshin const struct sockaddr_in6 *smask; 196155163Sshin{ 196255163Sshin const struct in6_addr *addr = NULL; 196355163Sshin int prefix; 196455163Sshin struct ifac *ifa = NULL; 196555163Sshin struct netinfo6 ni6; 196655163Sshin struct riprt *rrt = NULL; 196755163Sshin time_t t_lifetime; 196855163Sshin int updated = 0; 196955163Sshin 197078064Sume if (sifa->sin6_family != AF_INET6) { 197155163Sshin trace(1, "\tother AF, ignored\n"); 197255163Sshin return -1; 197355163Sshin } 197455163Sshin addr = &sifa->sin6_addr; 197578064Sume prefix = sin6mask2len(smask); 197655163Sshin 197755163Sshin trace(1, "\tdeleting %s/%d from %s\n", 197855163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 197955163Sshin ifa = ifa_match(ifcp, addr, prefix); 198055163Sshin if (!ifa) { 198155163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 198255163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 198355163Sshin return -1; 198455163Sshin } 198555163Sshin if (ifa->ifa_conf != ifcp) { 198655163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 198755163Sshin "(%s != %s)\n", 198855163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 198955163Sshin return -1; 199055163Sshin } 199155163Sshin /* remove ifa from interface */ 199255163Sshin if (ifcp->ifc_addr == ifa) 199355163Sshin ifcp->ifc_addr = ifa->ifa_next; 199455163Sshin else { 199555163Sshin struct ifac *p; 199655163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 199755163Sshin if (p->ifa_next == ifa) { 199855163Sshin p->ifa_next = ifa->ifa_next; 199955163Sshin break; 200055163Sshin } 200155163Sshin } 200255163Sshin } 200355163Sshin ifa->ifa_next = NULL; 200455163Sshin ifa->ifa_conf = NULL; 200555163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 200655163Sshin /* age route for interface address */ 200755163Sshin memset(&ni6, 0, sizeof(ni6)); 200855163Sshin ni6.rip6_dest = ifa->ifa_addr; 200955163Sshin ni6.rip6_plen = ifa->ifa_plen; 201055163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 201155163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 201255163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 201378064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 201455163Sshin struct in6_addr none; 201555163Sshin memset(&none, 0, sizeof(none)); 201678064Sume if (rrt->rrt_index == ifcp->ifc_index && 201778064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 201878064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 201955163Sshin trace(1, "\troute found, age it\n"); 202055163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 202155163Sshin rrt->rrt_t = t_lifetime; 202255163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 202355163Sshin } 202455163Sshin updated++; 202555163Sshin } else { 202655163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 202755163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 202855163Sshin rrt->rrt_info.rip6_plen, 202955163Sshin rrt->rrt_index); 203055163Sshin } 203155163Sshin } else 203255163Sshin trace(1, "\tno interface route found\n"); 203355163Sshin /* age route for p2p destination */ 203455163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 203555163Sshin memset(&ni6, 0, sizeof(ni6)); 203655163Sshin ni6.rip6_dest = ifa->ifa_raddr; 203755163Sshin ni6.rip6_plen = 128; 203855163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 203955163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 204055163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 204155163Sshin ifcp->ifc_index); 204278064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 204378064Sume if (rrt->rrt_index == ifcp->ifc_index && 204478064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 204555163Sshin trace(1, "\troute found, age it\n"); 204655163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 204755163Sshin rrt->rrt_t = t_lifetime; 204855163Sshin rrt->rrt_info.rip6_metric = 204978064Sume HOPCNT_INFINITY6; 205055163Sshin updated++; 205155163Sshin } 205255163Sshin } else { 205355163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 205455163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 205555163Sshin rrt->rrt_info.rip6_plen, 205655163Sshin rrt->rrt_index); 205755163Sshin } 205855163Sshin } else 205955163Sshin trace(1, "\tno p2p route found\n"); 206055163Sshin } 206155163Sshin return updated ? 0 : -1; 206255163Sshin} 206355163Sshin 206455163Sshin/* 206555163Sshin * Get each interface address and put those interface routes to the route 206655163Sshin * list. 206755163Sshin */ 206878064Sumeint 206955163Sshinifrt(ifcp, again) 207062607Sitojun struct ifc *ifcp; 207155163Sshin int again; 207255163Sshin{ 207362607Sitojun struct ifac *ifa; 2074119042Sume struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; 207562607Sitojun struct netinfo6 *np; 207678064Sume time_t t_lifetime; 207778064Sume int need_trigger = 0; 207855163Sshin 2079122677Sume#if 0 208055163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 208178064Sume return 0; /* ignore loopback */ 2082122677Sume#endif 2083122677Sume 208462607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 208562607Sitojun ifrt_p2p(ifcp, again); 208678064Sume return 0; 208762607Sitojun } 208862607Sitojun 208955163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 209062607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 209162607Sitojun#if 0 209262607Sitojun trace(1, "route: %s on %s: " 209362607Sitojun "skip linklocal interface address\n", 209462607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 209562607Sitojun#endif 209662607Sitojun continue; 209762607Sitojun } 209862607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 209962607Sitojun#if 0 210062607Sitojun trace(1, "route: %s: skip unspec interface address\n", 210162607Sitojun ifcp->ifc_name); 210262607Sitojun#endif 210362607Sitojun continue; 210462607Sitojun } 2105122677Sume if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) { 2106122677Sume#if 0 2107122677Sume trace(1, "route: %s: skip loopback address\n", 2108122677Sume ifcp->ifc_name); 2109122677Sume#endif 2110122677Sume continue; 2111122677Sume } 211278064Sume if (ifcp->ifc_flags & IFF_UP) { 211378064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 211478064Sume fatal("malloc: struct riprt"); 211578064Sume memset(rrt, 0, sizeof(*rrt)); 211678064Sume rrt->rrt_same = NULL; 211778064Sume rrt->rrt_index = ifcp->ifc_index; 211878064Sume rrt->rrt_t = 0; /* don't age */ 211978064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 212078064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 212178064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 212278064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 2123186119Sqingli rrt->rrt_flags = RTF_HOST; 212478064Sume rrt->rrt_rflags |= RRTF_CHANGED; 212578064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 212678064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 212778064Sume rrt->rrt_gw = ifa->ifa_addr; 212878064Sume np = &rrt->rrt_info; 212978064Sume search_rrt = rtsearch(np, &prev_rrt); 213078064Sume if (search_rrt != NULL) { 2131119042Sume if (search_rrt->rrt_info.rip6_metric <= 213278064Sume rrt->rrt_info.rip6_metric) { 213378064Sume /* Already have better route */ 213478064Sume if (!again) { 213578064Sume trace(1, "route: %s/%d: " 213678064Sume "already registered (%s)\n", 213778064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 213878064Sume ifcp->ifc_name); 213978064Sume } 2140119042Sume goto next; 214178064Sume } 2142119042Sume 2143119042Sume if (prev_rrt) 2144119042Sume prev_rrt->rrt_next = rrt->rrt_next; 2145119042Sume else 2146119042Sume riprt = rrt->rrt_next; 2147119042Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 214878064Sume } 214955163Sshin /* Attach the route to the list */ 215062607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 215162607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 215262607Sitojun ifcp->ifc_name); 215355163Sshin rrt->rrt_next = riprt; 215455163Sshin riprt = rrt; 215578064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 2156119042Sume rrt = NULL; 215778064Sume sendrequest(ifcp); 215878064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 215978064Sume need_trigger = 1; 216055163Sshin } else { 216178064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 216278064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 216378064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 216478064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 216578064Sume loop_rrt->rrt_t = t_lifetime; 216678064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 216778064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 216878064Sume need_trigger = 1; 216978064Sume } 217078064Sume } 217155163Sshin } 217278064Sume } 2173119042Sume next: 2174119042Sume if (rrt) 2175119042Sume free(rrt); 217662607Sitojun } 217778064Sume return need_trigger; 217862607Sitojun} 217955163Sshin 218062607Sitojun/* 218162607Sitojun * there are couple of p2p interface routing models. "behavior" lets 218262607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2183119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 218462607Sitojun */ 218562607Sitojunvoid 218662607Sitojunifrt_p2p(ifcp, again) 218762607Sitojun struct ifc *ifcp; 218862607Sitojun int again; 218962607Sitojun{ 219062607Sitojun struct ifac *ifa; 219178064Sume struct riprt *rrt, *orrt, *prevrrt; 219262607Sitojun struct netinfo6 *np; 219362607Sitojun struct in6_addr addr, dest; 219462607Sitojun int advert, ignore, i; 219562607Sitojun#define P2PADVERT_NETWORK 1 219662607Sitojun#define P2PADVERT_ADDR 2 219762607Sitojun#define P2PADVERT_DEST 4 219862607Sitojun#define P2PADVERT_MAX 4 219962607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 220078064Sume const char *category = ""; 220162607Sitojun const char *noadv; 220262607Sitojun 220362607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 220462607Sitojun addr = ifa->ifa_addr; 220562607Sitojun dest = ifa->ifa_raddr; 220662607Sitojun applyplen(&addr, ifa->ifa_plen); 220762607Sitojun applyplen(&dest, ifa->ifa_plen); 220862607Sitojun advert = ignore = 0; 220962607Sitojun switch (behavior) { 221062607Sitojun case CISCO: 221162607Sitojun /* 221262607Sitojun * honor addr/plen, just like normal shared medium 221362607Sitojun * interface. this may cause trouble if you reuse 221462607Sitojun * addr/plen on other interfaces. 221562607Sitojun * 221662607Sitojun * advertise addr/plen. 221762607Sitojun */ 221862607Sitojun advert |= P2PADVERT_NETWORK; 221962607Sitojun break; 222062607Sitojun case GATED: 222162607Sitojun /* 222262607Sitojun * prefixlen on p2p interface is meaningless. 222362607Sitojun * advertise addr/128 and dest/128. 222462607Sitojun * 222562607Sitojun * do not install network route to route6d routing 222662607Sitojun * table (if we do, it would prevent route installation 222762607Sitojun * for other p2p interface that shares addr/plen). 222878064Sume * 222978064Sume * XXX what should we do if dest is ::? it will not 223078064Sume * get announced anyways (see following filter), 223178064Sume * but we need to think. 223262607Sitojun */ 223362607Sitojun advert |= P2PADVERT_ADDR; 223462607Sitojun advert |= P2PADVERT_DEST; 223562607Sitojun ignore |= P2PADVERT_NETWORK; 223662607Sitojun break; 223762607Sitojun case ROUTE6D: 223862607Sitojun /* 223978064Sume * just for testing. actually the code is redundant 224078064Sume * given the current p2p interface address assignment 224178064Sume * rule for kame kernel. 224278064Sume * 224378064Sume * intent: 224478064Sume * A/n -> announce A/n 224578064Sume * A B/n, A and B share prefix -> A/n (= B/n) 224678064Sume * A B/n, do not share prefix -> A/128 and B/128 224778064Sume * actually, A/64 and A B/128 are the only cases 224878064Sume * permitted by the kernel: 224978064Sume * A/64 -> A/64 225078064Sume * A B/128 -> A/128 and B/128 225162607Sitojun */ 225278064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 225378064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 225478064Sume advert |= P2PADVERT_NETWORK; 225578064Sume else { 225678064Sume advert |= P2PADVERT_ADDR; 225778064Sume advert |= P2PADVERT_DEST; 225878064Sume ignore |= P2PADVERT_NETWORK; 225978064Sume } 226078064Sume } else 226162607Sitojun advert |= P2PADVERT_NETWORK; 226262607Sitojun break; 226362607Sitojun } 226462607Sitojun 226562607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 226662607Sitojun if ((ignore & i) != 0) 226762607Sitojun continue; 226878064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 226955163Sshin fatal("malloc: struct riprt"); 227078064Sume /*NOTREACHED*/ 227178064Sume } 227262607Sitojun memset(rrt, 0, sizeof(*rrt)); 227355163Sshin rrt->rrt_same = NULL; 227455163Sshin rrt->rrt_index = ifcp->ifc_index; 227562607Sitojun rrt->rrt_t = 0; /* don't age */ 227662607Sitojun switch (i) { 227762607Sitojun case P2PADVERT_NETWORK: 227862607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 227962607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 228062607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 228162607Sitojun ifa->ifa_plen); 228262607Sitojun category = "network"; 228362607Sitojun break; 228462607Sitojun case P2PADVERT_ADDR: 228562607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 228662607Sitojun rrt->rrt_info.rip6_plen = 128; 228778064Sume rrt->rrt_gw = in6addr_loopback; 228862607Sitojun category = "addr"; 228962607Sitojun break; 229062607Sitojun case P2PADVERT_DEST: 229162607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 229262607Sitojun rrt->rrt_info.rip6_plen = 128; 229378064Sume rrt->rrt_gw = ifa->ifa_addr; 229462607Sitojun category = "dest"; 229562607Sitojun break; 229662607Sitojun } 229762607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 229862607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 229962607Sitojun#if 0 230062607Sitojun trace(1, "route: %s: skip unspec/linklocal " 230162607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 230262607Sitojun#endif 230362607Sitojun free(rrt); 230462607Sitojun continue; 230562607Sitojun } 230662607Sitojun if ((advert & i) == 0) { 230762607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 230862607Sitojun noadv = ", NO-ADV"; 230962607Sitojun } else 231062607Sitojun noadv = ""; 231155163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 231262607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 231355163Sshin np = &rrt->rrt_info; 231478064Sume orrt = rtsearch(np, &prevrrt); 231578064Sume if (!orrt) { 231655163Sshin /* Attach the route to the list */ 231762607Sitojun trace(1, "route: %s/%d: register route " 231862607Sitojun "(%s on %s%s)\n", 231962607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 232062607Sitojun category, ifcp->ifc_name, noadv); 232155163Sshin rrt->rrt_next = riprt; 232255163Sshin riprt = rrt; 232378064Sume } else if (rrt->rrt_index != orrt->rrt_index || 232478064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 232578064Sume /* swap route */ 232678064Sume rrt->rrt_next = orrt->rrt_next; 232778064Sume if (prevrrt) 232878064Sume prevrrt->rrt_next = rrt; 232978064Sume else 233078064Sume riprt = rrt; 233178064Sume free(orrt); 233278064Sume 233378064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 233478064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 233578064Sume category, ifcp->ifc_name, noadv); 233655163Sshin } else { 233755163Sshin /* Already found */ 233855163Sshin if (!again) { 233962607Sitojun trace(1, "route: %s/%d: " 234062607Sitojun "already registered (%s on %s%s)\n", 234162607Sitojun inet6_n2p(&np->rip6_dest), 234262607Sitojun np->rip6_plen, category, 234362607Sitojun ifcp->ifc_name, noadv); 234455163Sshin } 234555163Sshin free(rrt); 234655163Sshin } 234755163Sshin } 234855163Sshin } 234962607Sitojun#undef P2PADVERT_NETWORK 235062607Sitojun#undef P2PADVERT_ADDR 235162607Sitojun#undef P2PADVERT_DEST 235262607Sitojun#undef P2PADVERT_MAX 235355163Sshin} 235455163Sshin 235555163Sshinint 235655163Sshingetifmtu(ifindex) 235755163Sshin int ifindex; 235855163Sshin{ 235955163Sshin int mib[6]; 236055163Sshin char *buf; 236155163Sshin size_t msize; 236255163Sshin struct if_msghdr *ifm; 236355163Sshin int mtu; 236455163Sshin 236555163Sshin mib[0] = CTL_NET; 236655163Sshin mib[1] = PF_ROUTE; 236755163Sshin mib[2] = 0; 236855163Sshin mib[3] = AF_INET6; 236955163Sshin mib[4] = NET_RT_IFLIST; 237055163Sshin mib[5] = ifindex; 237178064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 237255163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 237378064Sume /*NOTREACHED*/ 237478064Sume } 237578064Sume if ((buf = malloc(msize)) == NULL) { 237655163Sshin fatal("malloc"); 237778064Sume /*NOTREACHED*/ 237878064Sume } 237978064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 238055163Sshin fatal("sysctl NET_RT_IFLIST"); 238178064Sume /*NOTREACHED*/ 238278064Sume } 238355163Sshin ifm = (struct if_msghdr *)buf; 238455163Sshin mtu = ifm->ifm_data.ifi_mtu; 238578064Sume if (ifindex != ifm->ifm_index) { 238655163Sshin fatal("ifindex does not match with ifm_index"); 238778064Sume /*NOTREACHED*/ 238878064Sume } 238955163Sshin free(buf); 239055163Sshin return mtu; 239155163Sshin} 239255163Sshin 239355163Sshinconst char * 239455163Sshinrttypes(rtm) 239555163Sshin struct rt_msghdr *rtm; 239655163Sshin{ 239762607Sitojun#define RTTYPE(s, f) \ 239862607Sitojundo { \ 239962607Sitojun if (rtm->rtm_type == (f)) \ 240062607Sitojun return (s); \ 240162607Sitojun} while (0) 240255163Sshin RTTYPE("ADD", RTM_ADD); 240355163Sshin RTTYPE("DELETE", RTM_DELETE); 240455163Sshin RTTYPE("CHANGE", RTM_CHANGE); 240555163Sshin RTTYPE("GET", RTM_GET); 240655163Sshin RTTYPE("LOSING", RTM_LOSING); 240755163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 240855163Sshin RTTYPE("MISS", RTM_MISS); 240955163Sshin RTTYPE("LOCK", RTM_LOCK); 241055163Sshin RTTYPE("OLDADD", RTM_OLDADD); 241155163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 241255163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 241355163Sshin RTTYPE("DELADDR", RTM_DELADDR); 241455163Sshin RTTYPE("IFINFO", RTM_IFINFO); 241578064Sume#ifdef RTM_OLDADD 241678064Sume RTTYPE("OLDADD", RTM_OLDADD); 241778064Sume#endif 241878064Sume#ifdef RTM_OLDDEL 241978064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 242078064Sume#endif 242178064Sume#ifdef RTM_OIFINFO 242278064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 242378064Sume#endif 242478064Sume#ifdef RTM_IFANNOUNCE 242578064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 242678064Sume#endif 242778064Sume#ifdef RTM_NEWMADDR 242878064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 242978064Sume#endif 243078064Sume#ifdef RTM_DELMADDR 243178064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 243278064Sume#endif 243355163Sshin#undef RTTYPE 243455163Sshin return NULL; 243555163Sshin} 243655163Sshin 243755163Sshinconst char * 243855163Sshinrtflags(rtm) 243955163Sshin struct rt_msghdr *rtm; 244055163Sshin{ 244155163Sshin static char buf[BUFSIZ]; 244255163Sshin 244378064Sume /* 244478064Sume * letter conflict should be okay. painful when *BSD diverges... 244578064Sume */ 244678064Sume strlcpy(buf, "", sizeof(buf)); 244762607Sitojun#define RTFLAG(s, f) \ 244862607Sitojundo { \ 244962607Sitojun if (rtm->rtm_flags & (f)) \ 245078064Sume strlcat(buf, (s), sizeof(buf)); \ 245162607Sitojun} while (0) 245255163Sshin RTFLAG("U", RTF_UP); 245355163Sshin RTFLAG("G", RTF_GATEWAY); 245455163Sshin RTFLAG("H", RTF_HOST); 245555163Sshin RTFLAG("R", RTF_REJECT); 245655163Sshin RTFLAG("D", RTF_DYNAMIC); 245755163Sshin RTFLAG("M", RTF_MODIFIED); 245855163Sshin RTFLAG("d", RTF_DONE); 245955163Sshin#ifdef RTF_MASK 246055163Sshin RTFLAG("m", RTF_MASK); 246155163Sshin#endif 2462186119Sqingli#ifdef RTF_CLONING 246355163Sshin RTFLAG("C", RTF_CLONING); 2464186119Sqingli#endif 246578064Sume#ifdef RTF_CLONED 246678064Sume RTFLAG("c", RTF_CLONED); 246778064Sume#endif 246878064Sume#ifdef RTF_PRCLONING 246978064Sume RTFLAG("c", RTF_PRCLONING); 247078064Sume#endif 247178064Sume#ifdef RTF_WASCLONED 247278064Sume RTFLAG("W", RTF_WASCLONED); 247378064Sume#endif 247455163Sshin RTFLAG("X", RTF_XRESOLVE); 2475186119Sqingli#ifdef RTF_LLINFO 247655163Sshin RTFLAG("L", RTF_LLINFO); 2477186119Sqingli#endif 247855163Sshin RTFLAG("S", RTF_STATIC); 247955163Sshin RTFLAG("B", RTF_BLACKHOLE); 248078064Sume#ifdef RTF_PROTO3 248178064Sume RTFLAG("3", RTF_PROTO3); 248278064Sume#endif 248355163Sshin RTFLAG("2", RTF_PROTO2); 248455163Sshin RTFLAG("1", RTF_PROTO1); 248578064Sume#ifdef RTF_BROADCAST 248678064Sume RTFLAG("b", RTF_BROADCAST); 248778064Sume#endif 248878064Sume#ifdef RTF_DEFAULT 248978064Sume RTFLAG("d", RTF_DEFAULT); 249078064Sume#endif 249178064Sume#ifdef RTF_ISAROUTER 249278064Sume RTFLAG("r", RTF_ISAROUTER); 249378064Sume#endif 249478064Sume#ifdef RTF_TUNNEL 249578064Sume RTFLAG("T", RTF_TUNNEL); 249678064Sume#endif 249778064Sume#ifdef RTF_AUTH 249878064Sume RTFLAG("A", RTF_AUTH); 249978064Sume#endif 250078064Sume#ifdef RTF_CRYPT 250178064Sume RTFLAG("E", RTF_CRYPT); 250278064Sume#endif 250355163Sshin#undef RTFLAG 250455163Sshin return buf; 250555163Sshin} 250655163Sshin 250755163Sshinconst char * 250855163Sshinifflags(flags) 250955163Sshin int flags; 251055163Sshin{ 251155163Sshin static char buf[BUFSIZ]; 251255163Sshin 251378064Sume strlcpy(buf, "", sizeof(buf)); 251462607Sitojun#define IFFLAG(s, f) \ 251562607Sitojundo { \ 2516119040Sume if (flags & (f)) { \ 251762607Sitojun if (buf[0]) \ 251878064Sume strlcat(buf, ",", sizeof(buf)); \ 2519119040Sume strlcat(buf, (s), sizeof(buf)); \ 252062607Sitojun } \ 252162607Sitojun} while (0) 252255163Sshin IFFLAG("UP", IFF_UP); 252355163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 252455163Sshin IFFLAG("DEBUG", IFF_DEBUG); 252555163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 252655163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 252755163Sshin#ifdef IFF_NOTRAILERS 252855163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 252955163Sshin#endif 253078064Sume#ifdef IFF_SMART 253178064Sume IFFLAG("SMART", IFF_SMART); 253278064Sume#endif 253355163Sshin IFFLAG("RUNNING", IFF_RUNNING); 253455163Sshin IFFLAG("NOARP", IFF_NOARP); 253555163Sshin IFFLAG("PROMISC", IFF_PROMISC); 253655163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 253755163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 253855163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 253955163Sshin IFFLAG("LINK0", IFF_LINK0); 254055163Sshin IFFLAG("LINK1", IFF_LINK1); 254155163Sshin IFFLAG("LINK2", IFF_LINK2); 254255163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 254355163Sshin#undef IFFLAG 254455163Sshin return buf; 254555163Sshin} 254655163Sshin 254755163Sshinvoid 254855163Sshinkrtread(again) 254955163Sshin int again; 255055163Sshin{ 255155163Sshin int mib[6]; 255255163Sshin size_t msize; 255355163Sshin char *buf, *p, *lim; 255455163Sshin struct rt_msghdr *rtm; 255555163Sshin int retry; 255655163Sshin const char *errmsg; 255755163Sshin 255855163Sshin retry = 0; 255955163Sshin buf = NULL; 256055163Sshin mib[0] = CTL_NET; 256155163Sshin mib[1] = PF_ROUTE; 256255163Sshin mib[2] = 0; 256355163Sshin mib[3] = AF_INET6; /* Address family */ 256455163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 256555163Sshin mib[5] = 0; /* No flags */ 256655163Sshin do { 256755163Sshin retry++; 256855163Sshin errmsg = NULL; 256955163Sshin if (buf) 257055163Sshin free(buf); 257155163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 257255163Sshin errmsg = "sysctl estimate"; 257355163Sshin continue; 257455163Sshin } 257555163Sshin if ((buf = malloc(msize)) == NULL) { 257655163Sshin errmsg = "malloc"; 257755163Sshin continue; 257855163Sshin } 257955163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 258055163Sshin errmsg = "sysctl NET_RT_DUMP"; 258155163Sshin continue; 258255163Sshin } 258355163Sshin } while (retry < 5 && errmsg != NULL); 258478064Sume if (errmsg) { 258569279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 258669279Sume (u_long)msize); 258778064Sume /*NOTREACHED*/ 258878064Sume } else if (1 < retry) 258955163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 259055163Sshin 259155163Sshin lim = buf + msize; 259255163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 259355163Sshin rtm = (struct rt_msghdr *)p; 259455163Sshin rt_entry(rtm, again); 259555163Sshin } 259655163Sshin free(buf); 259755163Sshin} 259855163Sshin 259955163Sshinvoid 260055163Sshinrt_entry(rtm, again) 260155163Sshin struct rt_msghdr *rtm; 260255163Sshin int again; 260355163Sshin{ 260455163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 260555163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 260655163Sshin char *rtmp, *ifname = NULL; 260778064Sume struct riprt *rrt, *orrt; 260855163Sshin struct netinfo6 *np; 260955163Sshin int s; 261055163Sshin 261155163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 261255163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 2613186119Sqingli (RTF_XRESOLVE|RTF_BLACKHOLE)) { 261455163Sshin return; /* not interested in the link route */ 261562607Sitojun } 261669279Sume /* do not look at cloned routes */ 261769279Sume#ifdef RTF_WASCLONED 261869279Sume if (rtm->rtm_flags & RTF_WASCLONED) 261969279Sume return; 262069279Sume#endif 262169279Sume#ifdef RTF_CLONED 262269279Sume if (rtm->rtm_flags & RTF_CLONED) 262369279Sume return; 262469279Sume#endif 262569279Sume /* 262669279Sume * do not look at dynamic routes. 262769279Sume * netbsd/openbsd cloned routes have UGHD. 262869279Sume */ 262969279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 263069279Sume return; 263155163Sshin rtmp = (char *)(rtm + 1); 263255163Sshin /* Destination */ 263355163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 263455163Sshin return; /* ignore routes without destination address */ 263555163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 263664631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 263755163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 263855163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 263955163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 264055163Sshin } 264155163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 264255163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 264355163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 264455163Sshin } 264555163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 264655163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 264755163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 264855163Sshin } 264955163Sshin if (rtm->rtm_addrs & RTA_IFP) { 265055163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 265155163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 265255163Sshin } 265355163Sshin 265455163Sshin /* Destination */ 265555163Sshin if (sin6_dst->sin6_family != AF_INET6) 265655163Sshin return; 265755163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 265855163Sshin return; /* Link-local */ 265955163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 266055163Sshin return; /* Loopback */ 266155163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 266255163Sshin return; 266355163Sshin 266478064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 266555163Sshin fatal("malloc: struct riprt"); 266678064Sume /*NOTREACHED*/ 266778064Sume } 266862607Sitojun memset(rrt, 0, sizeof(*rrt)); 266955163Sshin np = &rrt->rrt_info; 267055163Sshin rrt->rrt_same = NULL; 267155163Sshin rrt->rrt_t = time(NULL); 267255163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 267355163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 2674122677Sume if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) 2675122677Sume rrt->rrt_t = 0; /* Don't age non-gateway host routes */ 267655163Sshin np->rip6_tag = 0; 267755163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 267855163Sshin if (np->rip6_metric < 1) 267955163Sshin np->rip6_metric = 1; 268055163Sshin rrt->rrt_flags = rtm->rtm_flags; 268155163Sshin np->rip6_dest = sin6_dst->sin6_addr; 268255163Sshin 268355163Sshin /* Mask or plen */ 268455163Sshin if (rtm->rtm_flags & RTF_HOST) 268555163Sshin np->rip6_plen = 128; /* Host route */ 268678064Sume else if (sin6_mask) 268778064Sume np->rip6_plen = sin6mask2len(sin6_mask); 268878064Sume else 268955163Sshin np->rip6_plen = 0; 269055163Sshin 269178064Sume orrt = rtsearch(np, NULL); 269278064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 269355163Sshin /* Already found */ 269455163Sshin if (!again) { 269555163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 269655163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 269755163Sshin rtflags(rtm)); 269855163Sshin } 269955163Sshin free(rrt); 270055163Sshin return; 270155163Sshin } 270255163Sshin /* Gateway */ 270355163Sshin if (!sin6_gw) 270455163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 270555163Sshin else { 270655163Sshin if (sin6_gw->sin6_family == AF_INET6) 270755163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 270855163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 270955163Sshin /* XXX in case ppp link? */ 271055163Sshin rrt->rrt_gw = in6addr_loopback; 271155163Sshin } else 271255163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 271355163Sshin } 271455163Sshin trace(1, "route: %s/%d flags %s", 271555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 271655163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 271755163Sshin 271855163Sshin /* Interface */ 271955163Sshin s = rtm->rtm_index; 272055163Sshin if (s < nindex2ifc && index2ifc[s]) 272155163Sshin ifname = index2ifc[s]->ifc_name; 272258070Sshin else { 272358070Sshin trace(1, " not configured\n"); 272462607Sitojun free(rrt); 272558070Sshin return; 272658070Sshin } 272762607Sitojun trace(1, " if %s sock %d", ifname, s); 272855163Sshin rrt->rrt_index = s; 272955163Sshin 273062607Sitojun trace(1, "\n"); 273162607Sitojun 273255163Sshin /* Check gateway */ 273355163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 2734122677Sume !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) && 2735122677Sume (rrt->rrt_flags & RTF_LOCAL) == 0) { 273655163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 273755163Sshin inet6_n2p(&rrt->rrt_gw)); 273855163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 273962607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 274062607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 274155163Sshin } 274255163Sshin 274355163Sshin /* Put it to the route list */ 274478064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 274578064Sume /* replace route list */ 274678064Sume rrt->rrt_next = orrt->rrt_next; 274778064Sume *orrt = *rrt; 274878064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 274978064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 275078064Sume rtflags(rtm)); 275178064Sume free(rrt); 275278064Sume } else { 275378064Sume rrt->rrt_next = riprt; 275478064Sume riprt = rrt; 275578064Sume } 275655163Sshin} 275755163Sshin 275855163Sshinint 275955163Sshinaddroute(rrt, gw, ifcp) 276055163Sshin struct riprt *rrt; 276155163Sshin const struct in6_addr *gw; 276255163Sshin struct ifc *ifcp; 276355163Sshin{ 276455163Sshin struct netinfo6 *np; 276555163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 276655163Sshin struct rt_msghdr *rtm; 2767119031Sume struct sockaddr_in6 *sin6; 276855163Sshin int len; 276955163Sshin 277055163Sshin np = &rrt->rrt_info; 277178064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 277255163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 277355163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 277455163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 277555163Sshin np->rip6_metric - 1, buf2); 277655163Sshin if (rtlog) 277755163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 277855163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 277955163Sshin np->rip6_metric - 1, buf2); 278055163Sshin if (nflag) 278155163Sshin return 0; 278255163Sshin 278355163Sshin memset(buf, 0, sizeof(buf)); 278455163Sshin rtm = (struct rt_msghdr *)buf; 278555163Sshin rtm->rtm_type = RTM_ADD; 278655163Sshin rtm->rtm_version = RTM_VERSION; 278755163Sshin rtm->rtm_seq = ++seq; 278855163Sshin rtm->rtm_pid = pid; 278962607Sitojun rtm->rtm_flags = rrt->rrt_flags; 279055163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 279155163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 279255163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2793119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 279455163Sshin /* Destination */ 2795119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2796119031Sume sin6->sin6_family = AF_INET6; 2797119031Sume sin6->sin6_addr = np->rip6_dest; 2798119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 279955163Sshin /* Gateway */ 2800119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2801119031Sume sin6->sin6_family = AF_INET6; 2802119031Sume sin6->sin6_addr = *gw; 2803119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 280455163Sshin /* Netmask */ 2805119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2806119031Sume sin6->sin6_family = AF_INET6; 2807119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2808119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 280955163Sshin 2810119031Sume len = (char *)sin6 - (char *)buf; 281155163Sshin rtm->rtm_msglen = len; 281255163Sshin if (write(rtsock, buf, len) > 0) 281355163Sshin return 0; 281455163Sshin 281555163Sshin if (errno == EEXIST) { 281655163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2817119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 281855163Sshin if (rtlog) 281955163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2820119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 282155163Sshin } else { 282255163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2823119035Sume strerror(errno)); 282455163Sshin if (rtlog) 282555163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2826119035Sume strerror(errno)); 282755163Sshin } 282855163Sshin return -1; 282955163Sshin} 283055163Sshin 283155163Sshinint 283255163Sshindelroute(np, gw) 283355163Sshin struct netinfo6 *np; 283455163Sshin struct in6_addr *gw; 283555163Sshin{ 283655163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 283755163Sshin struct rt_msghdr *rtm; 2838119031Sume struct sockaddr_in6 *sin6; 283955163Sshin int len; 284055163Sshin 284155163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 284255163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 284355163Sshin np->rip6_plen, buf2); 284455163Sshin if (rtlog) 284555163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 284655163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 284755163Sshin if (nflag) 284855163Sshin return 0; 284955163Sshin 285055163Sshin memset(buf, 0, sizeof(buf)); 285155163Sshin rtm = (struct rt_msghdr *)buf; 285255163Sshin rtm->rtm_type = RTM_DELETE; 285355163Sshin rtm->rtm_version = RTM_VERSION; 285455163Sshin rtm->rtm_seq = ++seq; 285555163Sshin rtm->rtm_pid = pid; 285655163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 285778064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 285878064Sume rtm->rtm_flags |= RTF_HOST; 285955163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2860119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 286155163Sshin /* Destination */ 2862119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2863119031Sume sin6->sin6_family = AF_INET6; 2864119031Sume sin6->sin6_addr = np->rip6_dest; 2865119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 286655163Sshin /* Gateway */ 2867119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2868119031Sume sin6->sin6_family = AF_INET6; 2869119031Sume sin6->sin6_addr = *gw; 2870119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 287155163Sshin /* Netmask */ 2872119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2873119031Sume sin6->sin6_family = AF_INET6; 2874119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2875119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 287655163Sshin 2877119031Sume len = (char *)sin6 - (char *)buf; 287855163Sshin rtm->rtm_msglen = len; 287955163Sshin if (write(rtsock, buf, len) >= 0) 288055163Sshin return 0; 288155163Sshin 288255163Sshin if (errno == ESRCH) { 288355163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2884119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 288555163Sshin if (rtlog) 288655163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2887119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 288855163Sshin } else { 288955163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2890119035Sume strerror(errno)); 289155163Sshin if (rtlog) 289255163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2893119035Sume strerror(errno)); 289455163Sshin } 289555163Sshin return -1; 289655163Sshin} 289755163Sshin 289855163Sshinstruct in6_addr * 289955163Sshingetroute(np, gw) 290055163Sshin struct netinfo6 *np; 290155163Sshin struct in6_addr *gw; 290255163Sshin{ 290355163Sshin u_char buf[BUFSIZ]; 2904119085Sume int myseq; 290555163Sshin int len; 290655163Sshin struct rt_msghdr *rtm; 2907119031Sume struct sockaddr_in6 *sin6; 290855163Sshin 290955163Sshin rtm = (struct rt_msghdr *)buf; 291055163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 291155163Sshin memset(rtm, 0, len); 291255163Sshin rtm->rtm_type = RTM_GET; 291355163Sshin rtm->rtm_version = RTM_VERSION; 291455163Sshin myseq = ++seq; 291555163Sshin rtm->rtm_seq = myseq; 291655163Sshin rtm->rtm_addrs = RTA_DST; 291755163Sshin rtm->rtm_msglen = len; 2918119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2919119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2920119031Sume sin6->sin6_family = AF_INET6; 2921119031Sume sin6->sin6_addr = np->rip6_dest; 292255163Sshin if (write(rtsock, buf, len) < 0) { 292355163Sshin if (errno == ESRCH) /* No such route found */ 292455163Sshin return NULL; 292555163Sshin perror("write to rtsock"); 292678064Sume exit(1); 292755163Sshin } 292855163Sshin do { 292955163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 293055163Sshin perror("read from rtsock"); 293178064Sume exit(1); 293255163Sshin } 293355163Sshin rtm = (struct rt_msghdr *)buf; 293455163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2935119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 293655163Sshin if (rtm->rtm_addrs & RTA_DST) { 2937119031Sume sin6 = (struct sockaddr_in6 *) 2938119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 293955163Sshin } 294055163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2941119031Sume *gw = sin6->sin6_addr; 294255163Sshin return gw; 294355163Sshin } 294455163Sshin return NULL; 294555163Sshin} 294655163Sshin 294755163Sshinconst char * 294855163Sshininet6_n2p(p) 294955163Sshin const struct in6_addr *p; 295055163Sshin{ 295155163Sshin static char buf[BUFSIZ]; 295255163Sshin 295378064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 295455163Sshin} 295555163Sshin 295655163Sshinvoid 295755163Sshinifrtdump(sig) 295855163Sshin int sig; 295955163Sshin{ 296055163Sshin 296155163Sshin ifdump(sig); 296255163Sshin rtdump(sig); 296355163Sshin} 296455163Sshin 296555163Sshinvoid 296655163Sshinifdump(sig) 296755163Sshin int sig; 296855163Sshin{ 296955163Sshin struct ifc *ifcp; 297055163Sshin FILE *dump; 297155163Sshin int i; 297255163Sshin 297355163Sshin if (sig == 0) 297455163Sshin dump = stderr; 297555163Sshin else 297655163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 297755163Sshin dump = stderr; 297855163Sshin 297955163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 298055163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 298155163Sshin for (i = 0; i < 2; i++) { 298255163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 298355163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 298455163Sshin if (i == 0) { 298555163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 298655163Sshin continue; 298755163Sshin if (iff_find(ifcp, 'N') != NULL) 298855163Sshin continue; 298955163Sshin } else { 299055163Sshin if (ifcp->ifc_flags & IFF_UP) 299155163Sshin continue; 299255163Sshin } 299355163Sshin ifdump0(dump, ifcp); 299455163Sshin } 299555163Sshin } 299655163Sshin fprintf(dump, "\n"); 299755163Sshin if (dump != stderr) 299855163Sshin fclose(dump); 299955163Sshin} 300055163Sshin 300155163Sshinvoid 300255163Sshinifdump0(dump, ifcp) 300355163Sshin FILE *dump; 300455163Sshin const struct ifc *ifcp; 300555163Sshin{ 300655163Sshin struct ifac *ifa; 300755163Sshin struct iff *iffp; 300855163Sshin char buf[BUFSIZ]; 300955163Sshin const char *ft; 301055163Sshin int addr; 301155163Sshin 301255163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 301355163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 301455163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 301555163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 301655163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 301755163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 301855163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 301955163Sshin buf, sizeof(buf)); 302055163Sshin fprintf(dump, "\t%s/%d -- %s\n", 302155163Sshin inet6_n2p(&ifa->ifa_addr), 302255163Sshin ifa->ifa_plen, buf); 302355163Sshin } else { 302455163Sshin fprintf(dump, "\t%s/%d\n", 302555163Sshin inet6_n2p(&ifa->ifa_addr), 302655163Sshin ifa->ifa_plen); 302755163Sshin } 302855163Sshin } 302955163Sshin if (ifcp->ifc_filter) { 303055163Sshin fprintf(dump, "\tFilter:"); 303155163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 303255163Sshin addr = 0; 303355163Sshin switch (iffp->iff_type) { 303455163Sshin case 'A': 303555163Sshin ft = "Aggregate"; addr++; break; 303655163Sshin case 'N': 303778064Sume ft = "No-use"; break; 303855163Sshin case 'O': 303955163Sshin ft = "Advertise-only"; addr++; break; 304055163Sshin case 'T': 304155163Sshin ft = "Default-only"; break; 304255163Sshin case 'L': 304355163Sshin ft = "Listen-only"; addr++; break; 304455163Sshin default: 304555163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 304655163Sshin ft = buf; 304755163Sshin addr++; 304855163Sshin break; 304955163Sshin } 305055163Sshin fprintf(dump, " %s", ft); 305155163Sshin if (addr) { 305255163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 305355163Sshin iffp->iff_plen); 305455163Sshin } 305555163Sshin } 305655163Sshin fprintf(dump, "\n"); 305755163Sshin } 305855163Sshin} 305955163Sshin 306055163Sshinvoid 306155163Sshinrtdump(sig) 306255163Sshin int sig; 306355163Sshin{ 306455163Sshin struct riprt *rrt; 306555163Sshin char buf[BUFSIZ]; 306655163Sshin FILE *dump; 306755163Sshin time_t t, age; 306855163Sshin 306955163Sshin if (sig == 0) 307055163Sshin dump = stderr; 307155163Sshin else 307255163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 307355163Sshin dump = stderr; 307455163Sshin 307555163Sshin t = time(NULL); 307655163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 307755163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 307855163Sshin if (rrt->rrt_t == 0) 307955163Sshin age = 0; 308055163Sshin else 308155163Sshin age = t - rrt->rrt_t; 308255163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 308355163Sshin buf, sizeof(buf)); 308455163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 308555163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 308655163Sshin index2ifc[rrt->rrt_index]->ifc_name, 308755163Sshin inet6_n2p(&rrt->rrt_gw), 308855163Sshin rrt->rrt_info.rip6_metric, (long)age); 308955163Sshin if (rrt->rrt_info.rip6_tag) { 309055163Sshin fprintf(dump, " tag(0x%04x)", 309155163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 309255163Sshin } 309362607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 309455163Sshin fprintf(dump, " NOT-LL"); 309562607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 309655163Sshin fprintf(dump, " NO-ADV"); 309755163Sshin fprintf(dump, "\n"); 309855163Sshin } 309955163Sshin fprintf(dump, "\n"); 310055163Sshin if (dump != stderr) 310155163Sshin fclose(dump); 310255163Sshin} 310355163Sshin 310455163Sshin/* 310555163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 310678064Sume * specified interface structures. Each of the -A/O option has the following 310755163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 310855163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 310955163Sshin */ 311055163Sshinvoid 311155163Sshinfilterconfig() 311255163Sshin{ 311355163Sshin int i; 3114119083Sume char *p, *ap, *iflp, *ifname, *ep; 311578064Sume struct iff ftmp, *iff_obj; 311678064Sume struct ifc *ifcp; 311778064Sume struct riprt *rrt; 311864631Sitojun#if 0 311978064Sume struct in6_addr gw; 312064631Sitojun#endif 3121119083Sume u_long plen; 312255163Sshin 312355163Sshin for (i = 0; i < nfilter; i++) { 312455163Sshin ap = filter[i]; 312555163Sshin iflp = NULL; 312655163Sshin ifcp = NULL; 312755163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 312855163Sshin iflp = ap; 312955163Sshin goto ifonly; 313055163Sshin } 3131119038Sume if ((p = strchr(ap, ',')) != NULL) { 313255163Sshin *p++ = '\0'; 313355163Sshin iflp = p; 313455163Sshin } 3135119038Sume if ((p = strchr(ap, '/')) == NULL) { 313655163Sshin fatal("no prefixlen specified for '%s'", ap); 313778064Sume /*NOTREACHED*/ 313878064Sume } 313955163Sshin *p++ = '\0'; 314078064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 314155163Sshin fatal("invalid prefix specified for '%s'", ap); 314278064Sume /*NOTREACHED*/ 314378064Sume } 3144119083Sume errno = 0; 3145119083Sume ep = NULL; 3146119083Sume plen = strtoul(p, &ep, 10); 3147119083Sume if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) { 3148119083Sume fatal("invalid prefix length specified for '%s'", ap); 3149119083Sume /*NOTREACHED*/ 3150119083Sume } 3151119083Sume ftmp.iff_plen = plen; 315255163Sshin ftmp.iff_next = NULL; 315355163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 315455163Sshinifonly: 315555163Sshin ftmp.iff_type = filtertype[i]; 315678064Sume if (iflp == NULL || *iflp == '\0') { 315755163Sshin fatal("no interface specified for '%s'", ap); 315878064Sume /*NOTREACHED*/ 315978064Sume } 316055163Sshin /* parse the interface listing portion */ 316155163Sshin while (iflp) { 316255163Sshin ifname = iflp; 3163119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 316455163Sshin *iflp++ = '\0'; 316555163Sshin ifcp = ifc_find(ifname); 316678064Sume if (ifcp == NULL) { 316755163Sshin fatal("no interface %s exists", ifname); 316878064Sume /*NOTREACHED*/ 316978064Sume } 317055163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 317178064Sume if (iff_obj == NULL) { 317255163Sshin fatal("malloc of iff_obj"); 317378064Sume /*NOTREACHED*/ 317478064Sume } 317555163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 317678064Sume sizeof(struct iff)); 317755163Sshin /* link it to the interface filter */ 317855163Sshin iff_obj->iff_next = ifcp->ifc_filter; 317955163Sshin ifcp->ifc_filter = iff_obj; 318055163Sshin } 318178064Sume 318278064Sume /* 318378064Sume * -A: aggregate configuration. 318478064Sume */ 318555163Sshin if (filtertype[i] != 'A') 318655163Sshin continue; 318755163Sshin /* put the aggregate to the kernel routing table */ 318855163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 318978064Sume if (rrt == NULL) { 319055163Sshin fatal("malloc: rrt"); 319178064Sume /*NOTREACHED*/ 319278064Sume } 319355163Sshin memset(rrt, 0, sizeof(struct riprt)); 319455163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 319555163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 319655163Sshin rrt->rrt_info.rip6_metric = 1; 319755163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 319855163Sshin rrt->rrt_gw = in6addr_loopback; 319962607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 320062607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 320155163Sshin rrt->rrt_t = 0; 3202119039Sume rrt->rrt_index = loopifcp->ifc_index; 320364631Sitojun#if 0 320464631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 320564631Sitojun#if 0 320664631Sitojun /* 320764631Sitojun * When the address has already been registered in the 320864631Sitojun * kernel routing table, it should be removed 320964631Sitojun */ 321064631Sitojun delroute(&rrt->rrt_info, &gw); 321164631Sitojun#else 321278064Sume /* it is safer behavior */ 321364631Sitojun errno = EINVAL; 321464631Sitojun fatal("%s/%u already in routing table, " 321564631Sitojun "cannot aggregate", 321664631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 321764631Sitojun rrt->rrt_info.rip6_plen); 321878064Sume /*NOTREACHED*/ 321964631Sitojun#endif 322064631Sitojun } 322164631Sitojun#endif 322255163Sshin /* Put the route to the list */ 322355163Sshin rrt->rrt_next = riprt; 322455163Sshin riprt = rrt; 322555163Sshin trace(1, "Aggregate: %s/%d for %s\n", 322655163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 322755163Sshin ifcp->ifc_name); 322855163Sshin /* Add this route to the kernel */ 322955163Sshin if (nflag) /* do not modify kernel routing table */ 323055163Sshin continue; 323155163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 323255163Sshin } 323355163Sshin} 323455163Sshin 323555163Sshin/***************** utility functions *****************/ 323655163Sshin 323755163Sshin/* 323855163Sshin * Returns a pointer to ifac whose address and prefix length matches 323955163Sshin * with the address and prefix length specified in the arguments. 324055163Sshin */ 324155163Sshinstruct ifac * 324255163Sshinifa_match(ifcp, ia, plen) 324355163Sshin const struct ifc *ifcp; 324455163Sshin const struct in6_addr *ia; 324555163Sshin int plen; 324655163Sshin{ 324755163Sshin struct ifac *ifa; 324855163Sshin 324955163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 325055163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 325155163Sshin ifa->ifa_plen == plen) 325255163Sshin break; 325355163Sshin } 325455163Sshin return ifa; 325555163Sshin} 325655163Sshin 325755163Sshin/* 325855163Sshin * Return a pointer to riprt structure whose address and prefix length 325955163Sshin * matches with the address and prefix length found in the argument. 326078064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 326155163Sshin */ 326255163Sshinstruct riprt * 326378064Sumertsearch(np, prev_rrt) 326455163Sshin struct netinfo6 *np; 326578064Sume struct riprt **prev_rrt; 326655163Sshin{ 326755163Sshin struct riprt *rrt; 326855163Sshin 326978064Sume if (prev_rrt) 327078064Sume *prev_rrt = NULL; 327155163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 327255163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 327355163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 327455163Sshin &np->rip6_dest)) 327555163Sshin return rrt; 327678064Sume if (prev_rrt) 327778064Sume *prev_rrt = rrt; 327855163Sshin } 327978064Sume if (prev_rrt) 328078064Sume *prev_rrt = NULL; 328155163Sshin return 0; 328255163Sshin} 328355163Sshin 328455163Sshinint 328578064Sumesin6mask2len(sin6) 328678064Sume const struct sockaddr_in6 *sin6; 328778064Sume{ 328878064Sume 328978064Sume return mask2len(&sin6->sin6_addr, 329078064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 329178064Sume} 329278064Sume 329378064Sumeint 329455163Sshinmask2len(addr, lenlim) 329555163Sshin const struct in6_addr *addr; 329655163Sshin int lenlim; 329755163Sshin{ 329855163Sshin int i = 0, j; 329978064Sume const u_char *p = (const u_char *)addr; 330062607Sitojun 330155163Sshin for (j = 0; j < lenlim; j++, p++) { 330255163Sshin if (*p != 0xff) 330355163Sshin break; 330455163Sshin i += 8; 330555163Sshin } 330655163Sshin if (j < lenlim) { 330755163Sshin switch (*p) { 330862607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 330962607Sitojun MASKLEN(0xfe, 7); break; 331062607Sitojun MASKLEN(0xfc, 6); break; 331162607Sitojun MASKLEN(0xf8, 5); break; 331262607Sitojun MASKLEN(0xf0, 4); break; 331362607Sitojun MASKLEN(0xe0, 3); break; 331462607Sitojun MASKLEN(0xc0, 2); break; 331562607Sitojun MASKLEN(0x80, 1); break; 331655163Sshin#undef MASKLEN 331755163Sshin } 331855163Sshin } 331955163Sshin return i; 332055163Sshin} 332155163Sshin 332255163Sshinvoid 332355163Sshinapplymask(addr, mask) 332455163Sshin struct in6_addr *addr, *mask; 332555163Sshin{ 332655163Sshin int i; 332755163Sshin u_long *p, *q; 332855163Sshin 332955163Sshin p = (u_long *)addr; q = (u_long *)mask; 333055163Sshin for (i = 0; i < 4; i++) 333155163Sshin *p++ &= *q++; 333255163Sshin} 333355163Sshin 333455163Sshinstatic const u_char plent[8] = { 333555163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 333655163Sshin}; 333755163Sshin 333855163Sshinvoid 333955163Sshinapplyplen(ia, plen) 334055163Sshin struct in6_addr *ia; 334155163Sshin int plen; 334255163Sshin{ 334355163Sshin u_char *p; 334455163Sshin int i; 334555163Sshin 334655163Sshin p = ia->s6_addr; 334755163Sshin for (i = 0; i < 16; i++) { 334855163Sshin if (plen <= 0) 334955163Sshin *p = 0; 335055163Sshin else if (plen < 8) 335155163Sshin *p &= plent[plen]; 335255163Sshin p++, plen -= 8; 335355163Sshin } 335455163Sshin} 335555163Sshin 335655163Sshinstatic const int pl2m[9] = { 335755163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 335855163Sshin}; 335955163Sshin 336055163Sshinstruct in6_addr * 336155163Sshinplen2mask(n) 336255163Sshin int n; 336355163Sshin{ 336455163Sshin static struct in6_addr ia; 336555163Sshin u_char *p; 336655163Sshin int i; 336755163Sshin 336855163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 336955163Sshin p = (u_char *)&ia; 337055163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 337155163Sshin if (n >= 8) { 337255163Sshin *p = 0xff; 337355163Sshin continue; 337455163Sshin } 337555163Sshin *p = pl2m[n]; 337655163Sshin break; 337755163Sshin } 337855163Sshin return &ia; 337955163Sshin} 338055163Sshin 338155163Sshinchar * 338255163Sshinallocopy(p) 338355163Sshin char *p; 338455163Sshin{ 3385119033Sume int len = strlen(p) + 1; 3386119033Sume char *q = (char *)malloc(len); 338755163Sshin 3388119033Sume if (!q) { 3389119033Sume fatal("malloc"); 3390119033Sume /*NOTREACHED*/ 3391119033Sume } 3392119033Sume 3393119033Sume strlcpy(q, p, len); 339455163Sshin return q; 339555163Sshin} 339655163Sshin 339755163Sshinchar * 339855163Sshinhms() 339955163Sshin{ 340055163Sshin static char buf[BUFSIZ]; 340155163Sshin time_t t; 340255163Sshin struct tm *tm; 340355163Sshin 340455163Sshin t = time(NULL); 340578064Sume if ((tm = localtime(&t)) == 0) { 340655163Sshin fatal("localtime"); 340778064Sume /*NOTREACHED*/ 340878064Sume } 340978064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 341078064Sume tm->tm_sec); 341155163Sshin return buf; 341255163Sshin} 341355163Sshin 341455163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 341555163Sshin 341655163Sshinint 341755163Sshinripinterval(timer) 341855163Sshin int timer; 341955163Sshin{ 342055163Sshin double r = rand(); 342155163Sshin 342255163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 342355163Sshin nextalarm = time(NULL) + interval; 342455163Sshin return interval; 342555163Sshin} 342655163Sshin 342755163Sshintime_t 342855163Sshinripsuptrig() 342955163Sshin{ 343055163Sshin time_t t; 343155163Sshin 343255163Sshin double r = rand(); 343362607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 343478064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 343555163Sshin sup_trig_update = time(NULL) + t; 343655163Sshin return t; 343755163Sshin} 343855163Sshin 343955163Sshinvoid 344055163Sshin#ifdef __STDC__ 344155163Sshinfatal(const char *fmt, ...) 344255163Sshin#else 344355163Sshinfatal(fmt, va_alist) 344455163Sshin char *fmt; 344555163Sshin va_dcl 344655163Sshin#endif 344755163Sshin{ 344855163Sshin va_list ap; 344955163Sshin char buf[1024]; 345055163Sshin 345155163Sshin#ifdef __STDC__ 345255163Sshin va_start(ap, fmt); 345355163Sshin#else 345455163Sshin va_start(ap); 345555163Sshin#endif 345655163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 3457119043Sume va_end(ap); 345855163Sshin perror(buf); 3459119043Sume if (errno) 3460119043Sume syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 3461119043Sume else 3462119043Sume syslog(LOG_ERR, "%s", buf); 346378064Sume rtdexit(); 346455163Sshin} 346555163Sshin 346655163Sshinvoid 346755163Sshin#ifdef __STDC__ 346855163Sshintracet(int level, const char *fmt, ...) 346955163Sshin#else 347055163Sshintracet(level, fmt, va_alist) 347155163Sshin int level; 347255163Sshin char *fmt; 347355163Sshin va_dcl 347455163Sshin#endif 347555163Sshin{ 347655163Sshin va_list ap; 347755163Sshin 3478119043Sume if (level <= dflag) { 347955163Sshin#ifdef __STDC__ 3480119043Sume va_start(ap, fmt); 348155163Sshin#else 3482119043Sume va_start(ap); 348355163Sshin#endif 348455163Sshin fprintf(stderr, "%s: ", hms()); 348555163Sshin vfprintf(stderr, fmt, ap); 3486119043Sume va_end(ap); 348755163Sshin } 348855163Sshin if (dflag) { 3489119043Sume#ifdef __STDC__ 3490119043Sume va_start(ap, fmt); 3491119043Sume#else 3492119043Sume va_start(ap); 3493119043Sume#endif 349455163Sshin if (level > 0) 349555163Sshin vsyslog(LOG_DEBUG, fmt, ap); 349655163Sshin else 349755163Sshin vsyslog(LOG_WARNING, fmt, ap); 3498119043Sume va_end(ap); 349955163Sshin } 350055163Sshin} 350155163Sshin 350255163Sshinvoid 350355163Sshin#ifdef __STDC__ 350455163Sshintrace(int level, const char *fmt, ...) 350555163Sshin#else 350655163Sshintrace(level, fmt, va_alist) 350755163Sshin int level; 350855163Sshin char *fmt; 350955163Sshin va_dcl 351055163Sshin#endif 351155163Sshin{ 351255163Sshin va_list ap; 351355163Sshin 3514119043Sume if (level <= dflag) { 351555163Sshin#ifdef __STDC__ 3516119043Sume va_start(ap, fmt); 351755163Sshin#else 3518119043Sume va_start(ap); 351955163Sshin#endif 352055163Sshin vfprintf(stderr, fmt, ap); 3521119043Sume va_end(ap); 3522119043Sume } 352355163Sshin if (dflag) { 3524119043Sume#ifdef __STDC__ 3525119043Sume va_start(ap, fmt); 3526119043Sume#else 3527119043Sume va_start(ap); 3528119043Sume#endif 352955163Sshin if (level > 0) 353055163Sshin vsyslog(LOG_DEBUG, fmt, ap); 353155163Sshin else 353255163Sshin vsyslog(LOG_WARNING, fmt, ap); 3533119043Sume va_end(ap); 353455163Sshin } 353555163Sshin} 353655163Sshin 353755163Sshinunsigned int 353855163Sshinif_maxindex() 353955163Sshin{ 354055163Sshin struct if_nameindex *p, *p0; 354155163Sshin unsigned int max = 0; 354255163Sshin 354355163Sshin p0 = if_nameindex(); 354455163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 354555163Sshin if (max < p->if_index) 354655163Sshin max = p->if_index; 354755163Sshin } 354855163Sshin if_freenameindex(p0); 354955163Sshin return max; 355055163Sshin} 355155163Sshin 355255163Sshinstruct ifc * 355355163Sshinifc_find(name) 355455163Sshin char *name; 355555163Sshin{ 355655163Sshin struct ifc *ifcp; 355755163Sshin 355855163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 355955163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 356055163Sshin return ifcp; 356155163Sshin } 356255163Sshin return (struct ifc *)NULL; 356355163Sshin} 356455163Sshin 356555163Sshinstruct iff * 356655163Sshiniff_find(ifcp, type) 356755163Sshin struct ifc *ifcp; 356855163Sshin int type; 356955163Sshin{ 357055163Sshin struct iff *iffp; 357155163Sshin 357255163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 357355163Sshin if (iffp->iff_type == type) 357455163Sshin return iffp; 357555163Sshin } 357655163Sshin return NULL; 357755163Sshin} 357855163Sshin 357955163Sshinvoid 358078064Sumesetindex2ifc(idx, ifcp) 358178064Sume int idx; 358255163Sshin struct ifc *ifcp; 358355163Sshin{ 3584122677Sume int n, nsize; 358562607Sitojun struct ifc **p; 358655163Sshin 358755163Sshin if (!index2ifc) { 358855163Sshin nindex2ifc = 5; /*initial guess*/ 358955163Sshin index2ifc = (struct ifc **) 359055163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 359178064Sume if (index2ifc == NULL) { 359255163Sshin fatal("malloc"); 359378064Sume /*NOTREACHED*/ 359478064Sume } 359555163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 359655163Sshin } 359755163Sshin n = nindex2ifc; 3598122677Sume for (nsize = nindex2ifc; nsize <= idx; nsize *= 2) 3599122677Sume ; 3600122677Sume if (n != nsize) { 360162607Sitojun p = (struct ifc **)realloc(index2ifc, 3602122677Sume sizeof(*index2ifc) * nsize); 360378064Sume if (p == NULL) { 360455163Sshin fatal("realloc"); 360578064Sume /*NOTREACHED*/ 360678064Sume } 360778064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 360862607Sitojun index2ifc = p; 3609122677Sume nindex2ifc = nsize; 361055163Sshin } 361178064Sume index2ifc[idx] = ifcp; 361255163Sshin} 3613