route6d.c revision 173412
162607Sitojun/* $FreeBSD: head/usr.sbin/route6d/route6d.c 173412 2007-11-07 10:53:41Z kevlo $ */ 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 9355163Sshin/* 9455163Sshin * Following two macros are highly depending on KAME Release 9555163Sshin */ 9655163Sshin#define IN6_LINKLOCAL_IFINDEX(addr) \ 9755163Sshin ((addr).s6_addr[2] << 8 | (addr).s6_addr[3]) 9855163Sshin 9955163Sshin#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \ 10055163Sshin do { \ 10155163Sshin (addr).s6_addr[2] = ((index) >> 8) & 0xff; \ 10255163Sshin (addr).s6_addr[3] = (index) & 0xff; \ 10355163Sshin } while (0) 10455163Sshin 10555163Sshinstruct ifc { /* Configuration of an interface */ 10655163Sshin char *ifc_name; /* if name */ 10755163Sshin struct ifc *ifc_next; 10855163Sshin int ifc_index; /* if index */ 10955163Sshin int ifc_mtu; /* if mtu */ 11055163Sshin int ifc_metric; /* if metric */ 11178064Sume u_int ifc_flags; /* flags */ 11278064Sume short ifc_cflags; /* IFC_XXX */ 11355163Sshin struct in6_addr ifc_mylladdr; /* my link-local address */ 11455163Sshin struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 11555163Sshin struct iff *ifc_filter; /* filter structure */ 11655163Sshin struct ifac *ifc_addr; /* list of AF_INET6 addresses */ 11755163Sshin int ifc_joined; /* joined to ff02::9 */ 11855163Sshin}; 11955163Sshin 12062607Sitojunstruct ifac { /* Adddress associated to an interface */ 12155163Sshin struct ifc *ifa_conf; /* back pointer */ 12255163Sshin struct ifac *ifa_next; 12355163Sshin struct in6_addr ifa_addr; /* address */ 12455163Sshin struct in6_addr ifa_raddr; /* remote address, valid in p2p */ 12555163Sshin int ifa_plen; /* prefix length */ 12655163Sshin}; 12755163Sshin 12855163Sshinstruct iff { 12955163Sshin int iff_type; 13055163Sshin struct in6_addr iff_addr; 13155163Sshin int iff_plen; 13255163Sshin struct iff *iff_next; 13355163Sshin}; 13455163Sshin 13555163Sshinstruct ifc *ifc; 13655163Sshinint nifc; /* number of valid ifc's */ 13755163Sshinstruct ifc **index2ifc; 13855163Sshinint nindex2ifc; 13955163Sshinstruct ifc *loopifcp = NULL; /* pointing to loopback */ 140119076Sume#ifdef HAVE_POLL_H 141119076Sumestruct pollfd set[2]; 142119076Sume#else 143119070Sumefd_set *sockvecp; /* vector to select() for receiving */ 144119070Sumefd_set *recvecp; 145119070Sumeint fdmasks; 146119070Sumeint maxfd; /* maximum fd for select() */ 147119076Sume#endif 14855163Sshinint rtsock; /* the routing socket */ 14955163Sshinint ripsock; /* socket to send/receive RIP datagram */ 15055163Sshin 15155163Sshinstruct rip6 *ripbuf; /* packet buffer for sending */ 15255163Sshin 15355163Sshin/* 15478064Sume * Maintain the routes in a linked list. When the number of the routes 15555163Sshin * grows, somebody would like to introduce a hash based or a radix tree 15678064Sume * based structure. I believe the number of routes handled by RIP is 15755163Sshin * limited and I don't have to manage a complex data structure, however. 15855163Sshin * 15955163Sshin * One of the major drawbacks of the linear linked list is the difficulty 16078064Sume * of representing the relationship between a couple of routes. This may 16155163Sshin * be a significant problem when we have to support route aggregation with 16255163Sshin * supressing the specifices covered by the aggregate. 16355163Sshin */ 16455163Sshin 16555163Sshinstruct riprt { 16655163Sshin struct riprt *rrt_next; /* next destination */ 16755163Sshin struct riprt *rrt_same; /* same destination - future use */ 16855163Sshin struct netinfo6 rrt_info; /* network info */ 16955163Sshin struct in6_addr rrt_gw; /* gateway */ 17062607Sitojun u_long rrt_flags; /* kernel routing table flags */ 17162607Sitojun u_long rrt_rflags; /* route6d routing table flags */ 17255163Sshin time_t rrt_t; /* when the route validated */ 17355163Sshin int rrt_index; /* ifindex from which this route got */ 17455163Sshin}; 17555163Sshin 17655163Sshinstruct riprt *riprt = 0; 17755163Sshin 17855163Sshinint dflag = 0; /* debug flag */ 17955163Sshinint qflag = 0; /* quiet flag */ 18055163Sshinint nflag = 0; /* don't update kernel routing table */ 18155163Sshinint aflag = 0; /* age out even the statically defined routes */ 18255163Sshinint hflag = 0; /* don't split horizon */ 18355163Sshinint lflag = 0; /* exchange site local routes */ 18455163Sshinint sflag = 0; /* announce static routes w/ split horizon */ 18555163Sshinint Sflag = 0; /* announce static routes to every interface */ 18662607Sitojununsigned long routetag = 0; /* route tag attached on originating case */ 18755163Sshin 18855163Sshinchar *filter[MAXFILTER]; 18955163Sshinint filtertype[MAXFILTER]; 19055163Sshinint nfilter = 0; 19155163Sshin 19255163Sshinpid_t pid; 19355163Sshin 19455163Sshinstruct sockaddr_storage ripsin; 19555163Sshin 19655163Sshinint interval = 1; 19755163Sshintime_t nextalarm = 0; 19855163Sshintime_t sup_trig_update = 0; 19955163Sshin 20055163SshinFILE *rtlog = NULL; 20155163Sshin 20255163Sshinint logopened = 0; 20355163Sshin 204119085Sumestatic int seq = 0; 20555163Sshin 20678064Sumevolatile sig_atomic_t seenalrm; 20778064Sumevolatile sig_atomic_t seenquit; 20878064Sumevolatile sig_atomic_t seenusr1; 20978064Sume 21062607Sitojun#define RRTF_AGGREGATE 0x08000000 21162607Sitojun#define RRTF_NOADVERTISE 0x10000000 21262607Sitojun#define RRTF_NH_NOT_LLADDR 0x20000000 21362607Sitojun#define RRTF_SENDANYWAY 0x40000000 21462607Sitojun#define RRTF_CHANGED 0x80000000 21555163Sshin 216173412Skevloint main(int, char **); 217173412Skevlovoid sighandler(int); 218173412Skevlovoid ripalarm(void); 219173412Skevlovoid riprecv(void); 220173412Skevlovoid ripsend(struct ifc *, struct sockaddr_in6 *, int); 221173412Skevloint out_filter(struct riprt *, struct ifc *); 222173412Skevlovoid init(void); 223173412Skevlovoid sockopt(struct ifc *); 224173412Skevlovoid ifconfig(void); 225173412Skevlovoid ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); 226173412Skevlovoid rtrecv(void); 227173412Skevloint rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *, 228173412Skevlo const struct sockaddr_in6 *); 229173412Skevloint rt_deladdr(struct ifc *, const struct sockaddr_in6 *, 230173412Skevlo const struct sockaddr_in6 *); 231173412Skevlovoid filterconfig(void); 232173412Skevloint getifmtu(int); 233173412Skevloconst char *rttypes(struct rt_msghdr *); 234173412Skevloconst char *rtflags(struct rt_msghdr *); 235173412Skevloconst char *ifflags(int); 236173412Skevloint ifrt(struct ifc *, int); 237173412Skevlovoid ifrt_p2p(struct ifc *, int); 238173412Skevlovoid applymask(struct in6_addr *, struct in6_addr *); 239173412Skevlovoid applyplen(struct in6_addr *, int); 240173412Skevlovoid ifrtdump(int); 241173412Skevlovoid ifdump(int); 242173412Skevlovoid ifdump0(FILE *, const struct ifc *); 243173412Skevlovoid rtdump(int); 244173412Skevlovoid rt_entry(struct rt_msghdr *, int); 245173412Skevlovoid rtdexit(void); 246173412Skevlovoid riprequest(struct ifc *, struct netinfo6 *, int, 247173412Skevlo struct sockaddr_in6 *); 248173412Skevlovoid ripflush(struct ifc *, struct sockaddr_in6 *); 249173412Skevlovoid sendrequest(struct ifc *); 250173412Skevloint sin6mask2len(const struct sockaddr_in6 *); 251173412Skevloint mask2len(const struct in6_addr *, int); 252173412Skevloint sendpacket(struct sockaddr_in6 *, int); 253173412Skevloint addroute(struct riprt *, const struct in6_addr *, struct ifc *); 254173412Skevloint delroute(struct netinfo6 *, struct in6_addr *); 255173412Skevlostruct in6_addr *getroute(struct netinfo6 *, struct in6_addr *); 256173412Skevlovoid krtread(int); 257173412Skevloint tobeadv(struct riprt *, struct ifc *); 258173412Skevlochar *allocopy(char *); 259173412Skevlochar *hms(void); 260173412Skevloconst char *inet6_n2p(const struct in6_addr *); 261173412Skevlostruct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int); 262173412Skevlostruct in6_addr *plen2mask(int); 263173412Skevlostruct riprt *rtsearch(struct netinfo6 *, struct riprt **); 264173412Skevloint ripinterval(int); 265173412Skevlotime_t ripsuptrig(void); 266173412Skevlovoid fatal(const char *, ...) 26766807Skris __attribute__((__format__(__printf__, 1, 2))); 268173412Skevlovoid trace(int, const char *, ...) 26966807Skris __attribute__((__format__(__printf__, 2, 3))); 270173412Skevlovoid tracet(int, const char *, ...) 27166807Skris __attribute__((__format__(__printf__, 2, 3))); 272173412Skevlounsigned int if_maxindex(void); 273173412Skevlostruct ifc *ifc_find(char *); 274173412Skevlostruct iff *iff_find(struct ifc *, int); 275173412Skevlovoid setindex2ifc(int, struct ifc *); 27655163Sshin 27755163Sshin#define MALLOC(type) ((type *)malloc(sizeof(type))) 27855163Sshin 27955163Sshinint 28055163Sshinmain(argc, argv) 28155163Sshin int argc; 28255163Sshin char **argv; 28355163Sshin{ 28455163Sshin int ch; 28555163Sshin int error = 0; 28655163Sshin struct ifc *ifcp; 28755163Sshin sigset_t mask, omask; 28855163Sshin FILE *pidfile; 28955163Sshin char *progname; 29062607Sitojun char *ep; 29155163Sshin 29255163Sshin progname = strrchr(*argv, '/'); 29355163Sshin if (progname) 29455163Sshin progname++; 29555163Sshin else 29655163Sshin progname = *argv; 29755163Sshin 29855163Sshin pid = getpid(); 29978064Sume while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { 30055163Sshin switch (ch) { 30155163Sshin case 'A': 30255163Sshin case 'N': 30355163Sshin case 'O': 30455163Sshin case 'T': 30555163Sshin case 'L': 30662607Sitojun if (nfilter >= MAXFILTER) { 30755163Sshin fatal("Exceeds MAXFILTER"); 30862607Sitojun /*NOTREACHED*/ 30962607Sitojun } 31055163Sshin filtertype[nfilter] = ch; 31155163Sshin filter[nfilter++] = allocopy(optarg); 31255163Sshin break; 31355163Sshin case 't': 31462607Sitojun ep = NULL; 31562607Sitojun routetag = strtoul(optarg, &ep, 0); 31662607Sitojun if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 31755163Sshin fatal("invalid route tag"); 31855163Sshin /*NOTREACHED*/ 31955163Sshin } 32055163Sshin break; 32155163Sshin case 'R': 32262607Sitojun if ((rtlog = fopen(optarg, "w")) == NULL) { 32355163Sshin fatal("Can not write to routelog"); 32462607Sitojun /*NOTREACHED*/ 32562607Sitojun } 32655163Sshin break; 32762607Sitojun#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 32862607Sitojun FLAG('a', aflag, 1); break; 32962607Sitojun FLAG('d', dflag, 1); break; 33062607Sitojun FLAG('D', dflag, 2); break; 33162607Sitojun FLAG('h', hflag, 1); break; 33262607Sitojun FLAG('l', lflag, 1); break; 33362607Sitojun FLAG('n', nflag, 1); break; 33462607Sitojun FLAG('q', qflag, 1); break; 33562607Sitojun FLAG('s', sflag, 1); break; 33662607Sitojun FLAG('S', Sflag, 1); break; 33755163Sshin#undef FLAG 33855163Sshin default: 33955163Sshin fatal("Invalid option specified, terminating"); 34062607Sitojun /*NOTREACHED*/ 34155163Sshin } 34255163Sshin } 34355163Sshin argc -= optind; 34455163Sshin argv += optind; 34578064Sume if (argc > 0) { 34655163Sshin fatal("bogus extra arguments"); 34778064Sume /*NOTREACHED*/ 34878064Sume } 34955163Sshin 35055163Sshin if (geteuid()) { 35155163Sshin nflag = 1; 35255163Sshin fprintf(stderr, "No kernel update is allowed\n"); 35355163Sshin } 354119037Sume 355119037Sume if (dflag == 0) { 356119037Sume if (daemon(0, 0) < 0) { 357119037Sume fatal("daemon"); 358119037Sume /*NOTREACHED*/ 359119037Sume } 360119037Sume } 361119037Sume 36255163Sshin openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 36355163Sshin logopened++; 36478064Sume 36578064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 36678064Sume fatal("malloc"); 36778064Sume memset(ripbuf, 0, RIP6_MAXMTU); 36878064Sume ripbuf->rip6_cmd = RIP6_RESPONSE; 36978064Sume ripbuf->rip6_vers = RIP6_VERSION; 37078064Sume ripbuf->rip6_res1[0] = 0; 37178064Sume ripbuf->rip6_res1[1] = 0; 37278064Sume 37355163Sshin init(); 37455163Sshin ifconfig(); 37555163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 37655163Sshin if (ifcp->ifc_index < 0) { 37755163Sshin fprintf(stderr, 37855163Sshin"No ifindex found at %s (no link-local address?)\n", 37955163Sshin ifcp->ifc_name); 38055163Sshin error++; 38155163Sshin } 38255163Sshin } 38355163Sshin if (error) 38455163Sshin exit(1); 38578064Sume if (loopifcp == NULL) { 38655163Sshin fatal("No loopback found"); 38778064Sume /*NOTREACHED*/ 38878064Sume } 38955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 39055163Sshin ifrt(ifcp, 0); 39155163Sshin filterconfig(); 39255163Sshin krtread(0); 39355163Sshin if (dflag) 39455163Sshin ifrtdump(0); 39555163Sshin 396122677Sume#if 1 39755163Sshin pid = getpid(); 39855163Sshin if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { 39955163Sshin fprintf(pidfile, "%d\n", pid); 40055163Sshin fclose(pidfile); 40155163Sshin } 402122677Sume#endif 40355163Sshin 40478064Sume if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 40555163Sshin fatal("malloc"); 40678064Sume /*NOTREACHED*/ 40778064Sume } 40862607Sitojun memset(ripbuf, 0, RIP6_MAXMTU); 40955163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 41055163Sshin ripbuf->rip6_vers = RIP6_VERSION; 41155163Sshin ripbuf->rip6_res1[0] = 0; 41255163Sshin ripbuf->rip6_res1[1] = 0; 41355163Sshin 41478064Sume if (signal(SIGALRM, sighandler) == SIG_ERR || 41578064Sume signal(SIGQUIT, sighandler) == SIG_ERR || 41678064Sume signal(SIGTERM, sighandler) == SIG_ERR || 41778064Sume signal(SIGUSR1, sighandler) == SIG_ERR || 41878064Sume signal(SIGHUP, sighandler) == SIG_ERR || 41978064Sume signal(SIGINT, sighandler) == SIG_ERR) { 42078064Sume fatal("signal"); 42178064Sume /*NOTREACHED*/ 42278064Sume } 42355163Sshin /* 42455163Sshin * To avoid rip packet congestion (not on a cable but in this 42555163Sshin * process), wait for a moment to send the first RIP6_RESPONSE 42655163Sshin * packets. 42755163Sshin */ 42855163Sshin alarm(ripinterval(INIT_INTERVAL6)); 42955163Sshin 43055163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 431119041Sume if (iff_find(ifcp, 'N')) 432119041Sume continue; 43355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 43455163Sshin sendrequest(ifcp); 43555163Sshin } 43655163Sshin 43755163Sshin syslog(LOG_INFO, "**** Started ****"); 43855163Sshin sigemptyset(&mask); 43955163Sshin sigaddset(&mask, SIGALRM); 44055163Sshin while (1) { 44178064Sume if (seenalrm) { 44278064Sume ripalarm(); 44378064Sume seenalrm = 0; 44478064Sume continue; 44578064Sume } 44678064Sume if (seenquit) { 44778064Sume rtdexit(); 44878064Sume seenquit = 0; 44978064Sume continue; 45078064Sume } 45178064Sume if (seenusr1) { 45278064Sume ifrtdump(SIGUSR1); 45378064Sume seenusr1 = 0; 45478064Sume continue; 45578064Sume } 45678064Sume 457119076Sume#ifdef HAVE_POLL_H 458119076Sume switch (poll(set, 2, INFTIM)) 459119076Sume#else 460119070Sume memcpy(recvecp, sockvecp, fdmasks); 461119076Sume switch (select(maxfd + 1, recvecp, 0, 0, 0)) 462119076Sume#endif 463119076Sume { 46455163Sshin case -1: 46578064Sume if (errno != EINTR) { 46678064Sume fatal("select"); 46778064Sume /*NOTREACHED*/ 46878064Sume } 46978064Sume continue; 47055163Sshin case 0: 47155163Sshin continue; 47255163Sshin default: 473119076Sume#ifdef HAVE_POLL_H 474119076Sume if (set[0].revents & POLLIN) 475119076Sume#else 476119076Sume if (FD_ISSET(ripsock, recvecp)) 477119076Sume#endif 478119076Sume { 47955163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 48055163Sshin riprecv(); 48155163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 48255163Sshin } 483119076Sume#ifdef HAVE_POLL_H 484119076Sume if (set[1].revents & POLLIN) 485119076Sume#else 486119076Sume if (FD_ISSET(rtsock, recvecp)) 487119076Sume#endif 488119076Sume { 48955163Sshin sigprocmask(SIG_BLOCK, &mask, &omask); 49055163Sshin rtrecv(); 49155163Sshin sigprocmask(SIG_SETMASK, &omask, NULL); 49255163Sshin } 49355163Sshin } 49455163Sshin } 49555163Sshin} 49655163Sshin 49778064Sumevoid 498119079Sumesighandler(signo) 499119079Sume int signo; 50078064Sume{ 50178064Sume 50278064Sume switch (signo) { 50378064Sume case SIGALRM: 50478064Sume seenalrm++; 50578064Sume break; 50678064Sume case SIGQUIT: 50778064Sume case SIGTERM: 50878064Sume seenquit++; 50978064Sume break; 51078064Sume case SIGUSR1: 51178064Sume case SIGHUP: 51278064Sume case SIGINT: 51378064Sume seenusr1++; 51478064Sume break; 51578064Sume } 51678064Sume} 51778064Sume 51855163Sshin/* 51955163Sshin * gracefully exits after resetting sockopts. 52055163Sshin */ 52155163Sshin/* ARGSUSED */ 52255163Sshinvoid 52378064Sumertdexit() 52455163Sshin{ 52555163Sshin struct riprt *rrt; 52655163Sshin 52755163Sshin alarm(0); 52855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 52962607Sitojun if (rrt->rrt_rflags & RRTF_AGGREGATE) { 53055163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 53155163Sshin } 53255163Sshin } 53355163Sshin close(ripsock); 53455163Sshin close(rtsock); 53555163Sshin syslog(LOG_INFO, "**** Terminated ****"); 53655163Sshin closelog(); 53755163Sshin exit(1); 53855163Sshin} 53955163Sshin 54055163Sshin/* 54155163Sshin * Called periodically: 54255163Sshin * 1. age out the learned route. remove it if necessary. 54355163Sshin * 2. submit RIP6_RESPONSE packets. 54478064Sume * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 54555163Sshin * to invoke this function in every 1 or 5 or 10 seconds only to age the 54655163Sshin * routes more precisely. 54755163Sshin */ 54855163Sshin/* ARGSUSED */ 54955163Sshinvoid 55078064Sumeripalarm() 55155163Sshin{ 55255163Sshin struct ifc *ifcp; 55355163Sshin struct riprt *rrt, *rrt_prev, *rrt_next; 55455163Sshin time_t t_lifetime, t_holddown; 55555163Sshin 55655163Sshin /* age the RIP routes */ 55755163Sshin rrt_prev = 0; 55855163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 55955163Sshin t_holddown = t_lifetime - RIP_HOLDDOWN; 56055163Sshin for (rrt = riprt; rrt; rrt = rrt_next) { 56155163Sshin rrt_next = rrt->rrt_next; 56255163Sshin 56355163Sshin if (rrt->rrt_t == 0) { 56455163Sshin rrt_prev = rrt; 56555163Sshin continue; 56655163Sshin } 56755163Sshin if (rrt->rrt_t < t_holddown) { 56855163Sshin if (rrt_prev) { 56955163Sshin rrt_prev->rrt_next = rrt->rrt_next; 57055163Sshin } else { 57155163Sshin riprt = rrt->rrt_next; 57255163Sshin } 57355163Sshin delroute(&rrt->rrt_info, &rrt->rrt_gw); 57455163Sshin free(rrt); 57555163Sshin continue; 57655163Sshin } 57755163Sshin if (rrt->rrt_t < t_lifetime) 57855163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 57955163Sshin rrt_prev = rrt; 58055163Sshin } 58155163Sshin /* Supply updates */ 58255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 58355163Sshin if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 58455163Sshin ripsend(ifcp, &ifcp->ifc_ripsin, 0); 58555163Sshin } 58655163Sshin alarm(ripinterval(SUPPLY_INTERVAL6)); 58755163Sshin} 58855163Sshin 58955163Sshinvoid 59055163Sshininit() 59155163Sshin{ 592119034Sume int error; 593119034Sume const int int0 = 0, int1 = 1, int255 = 255; 59455163Sshin struct addrinfo hints, *res; 595119081Sume char port[NI_MAXSERV]; 59655163Sshin 59755163Sshin ifc = (struct ifc *)NULL; 59855163Sshin nifc = 0; 59955163Sshin nindex2ifc = 0; /*initial guess*/ 60055163Sshin index2ifc = NULL; 601119081Sume snprintf(port, sizeof(port), "%u", RIP6_PORT); 60255163Sshin 60355163Sshin memset(&hints, 0, sizeof(hints)); 60455163Sshin hints.ai_family = PF_INET6; 60555163Sshin hints.ai_socktype = SOCK_DGRAM; 606119080Sume hints.ai_protocol = IPPROTO_UDP; 60755163Sshin hints.ai_flags = AI_PASSIVE; 60855163Sshin error = getaddrinfo(NULL, port, &hints, &res); 60978064Sume if (error) { 61066807Skris fatal("%s", gai_strerror(error)); 61178064Sume /*NOTREACHED*/ 61278064Sume } 61378064Sume if (res->ai_next) { 61455163Sshin fatal(":: resolved to multiple address"); 61578064Sume /*NOTREACHED*/ 61678064Sume } 61755163Sshin 61855163Sshin ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 61978064Sume if (ripsock < 0) { 62055163Sshin fatal("rip socket"); 62178064Sume /*NOTREACHED*/ 62278064Sume } 623119034Sume#ifdef IPV6_V6ONLY 624119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 625119034Sume &int1, sizeof(int1)) < 0) { 626119034Sume fatal("rip IPV6_V6ONLY"); 627119034Sume /*NOTREACHED*/ 628119034Sume } 629119034Sume#endif 63078064Sume if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 63155163Sshin fatal("rip bind"); 63278064Sume /*NOTREACHED*/ 63378064Sume } 63455163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 63578064Sume &int255, sizeof(int255)) < 0) { 63655163Sshin fatal("rip IPV6_MULTICAST_HOPS"); 63778064Sume /*NOTREACHED*/ 63878064Sume } 63955163Sshin if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 64078064Sume &int0, sizeof(int0)) < 0) { 64155163Sshin fatal("rip IPV6_MULTICAST_LOOP"); 64278064Sume /*NOTREACHED*/ 64378064Sume } 64462921Sume 64562607Sitojun#ifdef IPV6_RECVPKTINFO 646119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 647119034Sume &int1, sizeof(int1)) < 0) { 64862607Sitojun fatal("rip IPV6_RECVPKTINFO"); 64978064Sume /*NOTREACHED*/ 65078064Sume } 65162607Sitojun#else /* old adv. API */ 652119034Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 653119034Sume &int1, sizeof(int1)) < 0) { 65455163Sshin fatal("rip IPV6_PKTINFO"); 65578064Sume /*NOTREACHED*/ 65678064Sume } 65762607Sitojun#endif 65855163Sshin 659164339Ssuz#ifdef IPV6_RECVPKTINFO 660164339Ssuz if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 661164339Ssuz &int1, sizeof(int1)) < 0) { 662164339Ssuz fatal("rip IPV6_RECVHOPLIMIT"); 663164339Ssuz /*NOTREACHED*/ 664164339Ssuz } 665164339Ssuz#else /* old adv. API */ 666164339Ssuz if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT, 667164339Ssuz &int1, sizeof(int1)) < 0) { 668164339Ssuz fatal("rip IPV6_HOPLIMIT"); 669164339Ssuz /*NOTREACHED*/ 670164339Ssuz } 671164339Ssuz#endif 672164339Ssuz 67355163Sshin memset(&hints, 0, sizeof(hints)); 67455163Sshin hints.ai_family = PF_INET6; 67555163Sshin hints.ai_socktype = SOCK_DGRAM; 676119080Sume hints.ai_protocol = IPPROTO_UDP; 67755163Sshin error = getaddrinfo(RIP6_DEST, port, &hints, &res); 67878064Sume if (error) { 67966807Skris fatal("%s", gai_strerror(error)); 68078064Sume /*NOTREACHED*/ 68178064Sume } 68278064Sume if (res->ai_next) { 68355163Sshin fatal("%s resolved to multiple address", RIP6_DEST); 68478064Sume /*NOTREACHED*/ 68578064Sume } 68655163Sshin memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 68755163Sshin 688119076Sume#ifdef HAVE_POLL_H 689119076Sume set[0].fd = ripsock; 690119076Sume set[0].events = POLLIN; 691119076Sume#else 692119070Sume maxfd = ripsock; 693119076Sume#endif 69455163Sshin 69555163Sshin if (nflag == 0) { 69678064Sume if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 69755163Sshin fatal("route socket"); 69878064Sume /*NOTREACHED*/ 69978064Sume } 700119076Sume#ifdef HAVE_POLL_H 701119076Sume set[1].fd = rtsock; 702119076Sume set[1].events = POLLIN; 703119076Sume#else 704119070Sume if (rtsock > maxfd) 705119070Sume maxfd = rtsock; 706119076Sume#endif 707119076Sume } else { 708119076Sume#ifdef HAVE_POLL_H 709119076Sume set[1].fd = -1; 710119076Sume#else 71155163Sshin rtsock = -1; /*just for safety */ 712119076Sume#endif 713119076Sume } 714119070Sume 715119076Sume#ifndef HAVE_POLL_H 716119070Sume fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 717119070Sume if ((sockvecp = malloc(fdmasks)) == NULL) { 718119070Sume fatal("malloc"); 719119070Sume /*NOTREACHED*/ 720119070Sume } 721119070Sume if ((recvecp = malloc(fdmasks)) == NULL) { 722119070Sume fatal("malloc"); 723119070Sume /*NOTREACHED*/ 724119070Sume } 725119070Sume memset(sockvecp, 0, fdmasks); 726119070Sume FD_SET(ripsock, sockvecp); 727119070Sume if (rtsock >= 0) 728119070Sume FD_SET(rtsock, sockvecp); 729119076Sume#endif 73055163Sshin} 73155163Sshin 73262607Sitojun#define RIPSIZE(n) \ 73362607Sitojun (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 73455163Sshin 73555163Sshin/* 73655163Sshin * ripflush flushes the rip datagram stored in the rip buffer 73755163Sshin */ 73855163Sshinstatic int nrt; 73955163Sshinstatic struct netinfo6 *np; 74055163Sshin 74155163Sshinvoid 742119031Sumeripflush(ifcp, sin6) 74355163Sshin struct ifc *ifcp; 744119031Sume struct sockaddr_in6 *sin6; 74555163Sshin{ 74655163Sshin int i; 74755163Sshin int error; 74855163Sshin 74955163Sshin if (ifcp) 75055163Sshin tracet(1, "Send(%s): info(%d) to %s.%d\n", 75155163Sshin ifcp->ifc_name, nrt, 752119031Sume inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 75355163Sshin else 75455163Sshin tracet(1, "Send: info(%d) to %s.%d\n", 755119031Sume nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 75655163Sshin if (dflag >= 2) { 75755163Sshin np = ripbuf->rip6_nets; 75855163Sshin for (i = 0; i < nrt; i++, np++) { 75955163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 76055163Sshin if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 76162607Sitojun trace(2, " NextHop reset"); 76255163Sshin else { 76355163Sshin trace(2, " NextHop %s", 76455163Sshin inet6_n2p(&np->rip6_dest)); 76555163Sshin } 76655163Sshin } else { 76755163Sshin trace(2, " %s/%d[%d]", 76855163Sshin inet6_n2p(&np->rip6_dest), 76955163Sshin np->rip6_plen, np->rip6_metric); 77055163Sshin } 77155163Sshin if (np->rip6_tag) { 77255163Sshin trace(2, " tag=0x%04x", 77355163Sshin ntohs(np->rip6_tag) & 0xffff); 77455163Sshin } 77555163Sshin trace(2, "\n"); 77655163Sshin } 77755163Sshin } 778119031Sume error = sendpacket(sin6, RIPSIZE(nrt)); 77955163Sshin if (error == EAFNOSUPPORT) { 78055163Sshin /* Protocol not supported */ 78155163Sshin tracet(1, "Could not send info to %s (%s): " 78255163Sshin "set IFF_UP to 0\n", 78355163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 78455163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 78555163Sshin } 78655163Sshin nrt = 0; np = ripbuf->rip6_nets; 78755163Sshin} 78855163Sshin 78955163Sshin/* 79055163Sshin * Generate RIP6_RESPONSE packets and send them. 79155163Sshin */ 79255163Sshinvoid 793119031Sumeripsend(ifcp, sin6, flag) 79455163Sshin struct ifc *ifcp; 795119031Sume struct sockaddr_in6 *sin6; 79655163Sshin int flag; 79755163Sshin{ 79855163Sshin struct riprt *rrt; 79955163Sshin struct in6_addr *nh; /* next hop */ 80078064Sume int maxrte; 80155163Sshin 802119084Sume if (qflag) 803119084Sume return; 804119084Sume 80555163Sshin if (ifcp == NULL) { 80655163Sshin /* 80755163Sshin * Request from non-link local address is not 80855163Sshin * a regular route6d update. 80955163Sshin */ 81062607Sitojun maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 81162607Sitojun sizeof(struct udphdr) - 81255163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 81355163Sshin sizeof(struct netinfo6); 81455163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 81555163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 81662607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 81755163Sshin continue; 81855163Sshin /* Put the route to the buffer */ 81955163Sshin *np = rrt->rrt_info; 82055163Sshin np++; nrt++; 82155163Sshin if (nrt == maxrte) { 822119031Sume ripflush(NULL, sin6); 82355163Sshin nh = NULL; 82455163Sshin } 82555163Sshin } 82655163Sshin if (nrt) /* Send last packet */ 827119031Sume ripflush(NULL, sin6); 82855163Sshin return; 82955163Sshin } 83055163Sshin 83162607Sitojun if ((flag & RRTF_SENDANYWAY) == 0 && 83255163Sshin (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 83355163Sshin return; 83478064Sume 83578064Sume /* -N: no use */ 83655163Sshin if (iff_find(ifcp, 'N') != NULL) 83755163Sshin return; 83878064Sume 83978064Sume /* -T: generate default route only */ 84055163Sshin if (iff_find(ifcp, 'T') != NULL) { 84155163Sshin struct netinfo6 rrt_info; 84255163Sshin memset(&rrt_info, 0, sizeof(struct netinfo6)); 84355163Sshin rrt_info.rip6_dest = in6addr_any; 84455163Sshin rrt_info.rip6_plen = 0; 84555163Sshin rrt_info.rip6_metric = 1; 84678064Sume rrt_info.rip6_metric += ifcp->ifc_metric; 84755163Sshin rrt_info.rip6_tag = htons(routetag & 0xffff); 84855163Sshin np = ripbuf->rip6_nets; 84955163Sshin *np = rrt_info; 85055163Sshin nrt = 1; 851119031Sume ripflush(ifcp, sin6); 85255163Sshin return; 85355163Sshin } 85478064Sume 85562607Sitojun maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 85662607Sitojun sizeof(struct udphdr) - 85755163Sshin sizeof(struct rip6) + sizeof(struct netinfo6)) / 85855163Sshin sizeof(struct netinfo6); 85978064Sume 86055163Sshin nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 86155163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 86262607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 86355163Sshin continue; 86478064Sume 86578064Sume /* Need to check filter here */ 86678064Sume if (out_filter(rrt, ifcp) == 0) 86755163Sshin continue; 86878064Sume 86955163Sshin /* Check split horizon and other conditions */ 87055163Sshin if (tobeadv(rrt, ifcp) == 0) 87155163Sshin continue; 87278064Sume 87355163Sshin /* Only considers the routes with flag if specified */ 87462607Sitojun if ((flag & RRTF_CHANGED) && 87562607Sitojun (rrt->rrt_rflags & RRTF_CHANGED) == 0) 87655163Sshin continue; 87778064Sume 87855163Sshin /* Check nexthop */ 87955163Sshin if (rrt->rrt_index == ifcp->ifc_index && 88055163Sshin !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 88162607Sitojun (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 88255163Sshin if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 88355163Sshin if (nrt == maxrte - 2) 884119031Sume ripflush(ifcp, sin6); 88555163Sshin np->rip6_dest = rrt->rrt_gw; 88655163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) 88755163Sshin SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); 88855163Sshin np->rip6_plen = 0; 88955163Sshin np->rip6_tag = 0; 89055163Sshin np->rip6_metric = NEXTHOP_METRIC; 89155163Sshin nh = &rrt->rrt_gw; 89255163Sshin np++; nrt++; 89355163Sshin } 89455163Sshin } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 89555163Sshin !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 89662607Sitojun rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 89755163Sshin /* Reset nexthop */ 89855163Sshin if (nrt == maxrte - 2) 899119031Sume ripflush(ifcp, sin6); 90055163Sshin memset(np, 0, sizeof(struct netinfo6)); 90155163Sshin np->rip6_metric = NEXTHOP_METRIC; 90255163Sshin nh = NULL; 90355163Sshin np++; nrt++; 90455163Sshin } 90578064Sume 90655163Sshin /* Put the route to the buffer */ 90755163Sshin *np = rrt->rrt_info; 90855163Sshin np++; nrt++; 90955163Sshin if (nrt == maxrte) { 910119031Sume ripflush(ifcp, sin6); 91155163Sshin nh = NULL; 91255163Sshin } 91355163Sshin } 91455163Sshin if (nrt) /* Send last packet */ 915119031Sume ripflush(ifcp, sin6); 91655163Sshin} 91755163Sshin 91855163Sshin/* 91978064Sume * outbound filter logic, per-route/interface. 92078064Sume */ 92178064Sumeint 92278064Sumeout_filter(rrt, ifcp) 92378064Sume struct riprt *rrt; 92478064Sume struct ifc *ifcp; 92578064Sume{ 92678064Sume struct iff *iffp; 92778064Sume struct in6_addr ia; 92878064Sume int ok; 92978064Sume 93078064Sume /* 93178064Sume * -A: filter out less specific routes, if we have aggregated 93278064Sume * route configured. 93378064Sume */ 93478064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 93578064Sume if (iffp->iff_type != 'A') 93678064Sume continue; 93778064Sume if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 93878064Sume continue; 93978064Sume ia = rrt->rrt_info.rip6_dest; 94078064Sume applyplen(&ia, iffp->iff_plen); 94178064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 94278064Sume return 0; 94378064Sume } 94478064Sume 94578064Sume /* 94678064Sume * if it is an aggregated route, advertise it only to the 94778064Sume * interfaces specified on -A. 94878064Sume */ 94978064Sume if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 95078064Sume ok = 0; 95178064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 95278064Sume if (iffp->iff_type != 'A') 95378064Sume continue; 95478064Sume if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 95578064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 95678064Sume &iffp->iff_addr)) { 95778064Sume ok = 1; 95878064Sume break; 95978064Sume } 96078064Sume } 96178064Sume if (!ok) 96278064Sume return 0; 96378064Sume } 96478064Sume 96578064Sume /* 96678064Sume * -O: advertise only if prefix matches the configured prefix. 96778064Sume */ 96878064Sume if (iff_find(ifcp, 'O')) { 96978064Sume ok = 0; 97078064Sume for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 97178064Sume if (iffp->iff_type != 'O') 97278064Sume continue; 97378064Sume if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 97478064Sume continue; 97578064Sume ia = rrt->rrt_info.rip6_dest; 97678064Sume applyplen(&ia, iffp->iff_plen); 97778064Sume if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 97878064Sume ok = 1; 97978064Sume break; 98078064Sume } 98178064Sume } 98278064Sume if (!ok) 98378064Sume return 0; 98478064Sume } 98578064Sume 98678064Sume /* the prefix should be advertised */ 98778064Sume return 1; 98878064Sume} 98978064Sume 99078064Sume/* 99155163Sshin * Determine if the route is to be advertised on the specified interface. 99255163Sshin * It checks options specified in the arguments and the split horizon rule. 99355163Sshin */ 99455163Sshinint 99555163Sshintobeadv(rrt, ifcp) 99655163Sshin struct riprt *rrt; 99755163Sshin struct ifc *ifcp; 99855163Sshin{ 99955163Sshin 100055163Sshin /* Special care for static routes */ 100155163Sshin if (rrt->rrt_flags & RTF_STATIC) { 100262607Sitojun /* XXX don't advertise reject/blackhole routes */ 100362607Sitojun if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 100462607Sitojun return 0; 100562607Sitojun 100655163Sshin if (Sflag) /* Yes, advertise it anyway */ 100755163Sshin return 1; 100855163Sshin if (sflag && rrt->rrt_index != ifcp->ifc_index) 100955163Sshin return 1; 101055163Sshin return 0; 101155163Sshin } 101255163Sshin /* Regular split horizon */ 101355163Sshin if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 101455163Sshin return 0; 101555163Sshin return 1; 101655163Sshin} 101755163Sshin 101855163Sshin/* 101955163Sshin * Send a rip packet actually. 102055163Sshin */ 102155163Sshinint 1022119031Sumesendpacket(sin6, len) 1023119031Sume struct sockaddr_in6 *sin6; 102455163Sshin int len; 102555163Sshin{ 102655163Sshin struct msghdr m; 102755163Sshin struct cmsghdr *cm; 102855163Sshin struct iovec iov[2]; 102955163Sshin u_char cmsgbuf[256]; 103055163Sshin struct in6_pktinfo *pi; 103178064Sume int idx; 103255163Sshin struct sockaddr_in6 sincopy; 103355163Sshin 103455163Sshin /* do not overwrite the given sin */ 1035119031Sume sincopy = *sin6; 1036119031Sume sin6 = &sincopy; 103755163Sshin 1038119035Sume if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 1039119035Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 1040122677Sume /* XXX: do not mix the interface index and link index */ 1041119031Sume idx = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); 1042119031Sume SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); 1043122677Sume sin6->sin6_scope_id = idx; 104455163Sshin } else 104578064Sume idx = 0; 104655163Sshin 1047119031Sume m.msg_name = (caddr_t)sin6; 1048119031Sume m.msg_namelen = sizeof(*sin6); 104955163Sshin iov[0].iov_base = (caddr_t)ripbuf; 105055163Sshin iov[0].iov_len = len; 105155163Sshin m.msg_iov = iov; 105255163Sshin m.msg_iovlen = 1; 105378064Sume if (!idx) { 105455163Sshin m.msg_control = NULL; 105555163Sshin m.msg_controllen = 0; 105655163Sshin } else { 105755163Sshin memset(cmsgbuf, 0, sizeof(cmsgbuf)); 105855163Sshin cm = (struct cmsghdr *)cmsgbuf; 105955163Sshin m.msg_control = (caddr_t)cm; 106055163Sshin m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 106155163Sshin 106255163Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 106355163Sshin cm->cmsg_level = IPPROTO_IPV6; 106455163Sshin cm->cmsg_type = IPV6_PKTINFO; 106555163Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 106655163Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 106778064Sume pi->ipi6_ifindex = idx; 106855163Sshin } 106955163Sshin 107055163Sshin if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 107155163Sshin trace(1, "sendmsg: %s\n", strerror(errno)); 107255163Sshin return errno; 107355163Sshin } 107462921Sume 107555163Sshin return 0; 107655163Sshin} 107755163Sshin 107855163Sshin/* 107978064Sume * Receive and process RIP packets. Update the routes/kernel forwarding 108055163Sshin * table if necessary. 108155163Sshin */ 108255163Sshinvoid 108355163Sshinriprecv() 108455163Sshin{ 108555163Sshin struct ifc *ifcp, *ic; 108655163Sshin struct sockaddr_in6 fsock; 108755163Sshin struct in6_addr nh; /* next hop */ 108855163Sshin struct rip6 *rp; 108955163Sshin struct netinfo6 *np, *nq; 109055163Sshin struct riprt *rrt; 1091122677Sume ssize_t len, nn; 1092122677Sume unsigned int need_trigger, idx; 109355163Sshin char buf[4 * RIP6_MAXMTU]; 109455163Sshin time_t t; 109555163Sshin struct msghdr m; 109655163Sshin struct cmsghdr *cm; 109755163Sshin struct iovec iov[2]; 109855163Sshin u_char cmsgbuf[256]; 1099164339Ssuz struct in6_pktinfo *pi = NULL; 1100164339Ssuz int *hlimp = NULL; 110155163Sshin struct iff *iffp; 110255163Sshin struct in6_addr ia; 110355163Sshin int ok; 110478064Sume time_t t_half_lifetime; 110555163Sshin 110655163Sshin need_trigger = 0; 110762921Sume 110855163Sshin m.msg_name = (caddr_t)&fsock; 110955163Sshin m.msg_namelen = sizeof(fsock); 111055163Sshin iov[0].iov_base = (caddr_t)buf; 111155163Sshin iov[0].iov_len = sizeof(buf); 111255163Sshin m.msg_iov = iov; 111355163Sshin m.msg_iovlen = 1; 111455163Sshin cm = (struct cmsghdr *)cmsgbuf; 111555163Sshin m.msg_control = (caddr_t)cm; 111655163Sshin m.msg_controllen = sizeof(cmsgbuf); 111778064Sume if ((len = recvmsg(ripsock, &m, 0)) < 0) { 111855163Sshin fatal("recvmsg"); 111978064Sume /*NOTREACHED*/ 112078064Sume } 112178064Sume idx = 0; 112255163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 112355163Sshin cm; 112455163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 1125164339Ssuz if (cm->cmsg_level != IPPROTO_IPV6) 1126164339Ssuz continue; 1127164339Ssuz switch (cm->cmsg_type) { 1128164339Ssuz case IPV6_PKTINFO: 1129164339Ssuz if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) { 1130164339Ssuz trace(1, 1131164339Ssuz "invalid cmsg length for IPV6_PKTINFO\n"); 1132164339Ssuz return; 1133164339Ssuz } 113455163Sshin pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 113578064Sume idx = pi->ipi6_ifindex; 113655163Sshin break; 1137164339Ssuz case IPV6_HOPLIMIT: 1138164339Ssuz if (cm->cmsg_len != CMSG_LEN(sizeof(int))) { 1139164339Ssuz trace(1, 1140164339Ssuz "invalid cmsg length for IPV6_HOPLIMIT\n"); 1141164339Ssuz return; 1142164339Ssuz } 1143164339Ssuz hlimp = (int *)CMSG_DATA(cm); 1144164339Ssuz break; 114555163Sshin } 114655163Sshin } 114778064Sume if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) 114878064Sume SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); 114955163Sshin 1150121779Ssuz if (len < sizeof(struct rip6)) { 1151121779Ssuz trace(1, "Packet too short\n"); 1152121779Ssuz return; 1153121779Ssuz } 1154121779Ssuz 1155164339Ssuz if (pi == NULL || hlimp == NULL) { 1156164339Ssuz /* 1157164339Ssuz * This can happen when the kernel failed to allocate memory 1158164339Ssuz * for the ancillary data. Although we might be able to handle 1159164339Ssuz * some cases without this info, those are minor and not so 1160164339Ssuz * important, so it's better to discard the packet for safer 1161164339Ssuz * operation. 1162164339Ssuz */ 1163164339Ssuz trace(1, "IPv6 packet information cannot be retrieved\n"); 1164164339Ssuz return; 1165164339Ssuz } 1166164339Ssuz 116755163Sshin nh = fsock.sin6_addr; 116855163Sshin nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 116955163Sshin sizeof(struct netinfo6); 117055163Sshin rp = (struct rip6 *)buf; 117155163Sshin np = rp->rip6_nets; 117255163Sshin 1173119035Sume if (rp->rip6_vers != RIP6_VERSION) { 117455163Sshin trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 117555163Sshin return; 117655163Sshin } 117755163Sshin if (rp->rip6_cmd == RIP6_REQUEST) { 117878064Sume if (idx && idx < nindex2ifc) { 117978064Sume ifcp = index2ifc[idx]; 118055163Sshin riprequest(ifcp, np, nn, &fsock); 118155163Sshin } else { 118255163Sshin riprequest(NULL, np, nn, &fsock); 118355163Sshin } 118462607Sitojun return; 118562607Sitojun } 118655163Sshin 118755163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 1188164339Ssuz trace(1, "Response from non-ll addr: %s\n", 118978064Sume inet6_n2p(&fsock.sin6_addr)); 119055163Sshin return; /* Ignore packets from non-link-local addr */ 119155163Sshin } 1192164339Ssuz if (ntohs(fsock.sin6_port) != RIP6_PORT) { 1193164339Ssuz trace(1, "Response from non-rip port from %s\n", 1194164339Ssuz inet6_n2p(&fsock.sin6_addr)); 1195164339Ssuz return; 1196164339Ssuz } 1197164339Ssuz if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) { 1198164339Ssuz trace(1, 1199164339Ssuz "Response packet with a smaller hop limit (%d) from %s\n", 1200164339Ssuz *hlimp, inet6_n2p(&fsock.sin6_addr)); 1201164339Ssuz return; 1202164339Ssuz } 1203164339Ssuz /* 1204164339Ssuz * Further validation: since this program does not send off-link 1205164339Ssuz * requests, an incoming response must always come from an on-link 1206164339Ssuz * node. Although this is normally ensured by the source address 1207164339Ssuz * check above, it may not 100% be safe because there are router 1208164339Ssuz * implementations that (invalidly) allow a packet with a link-local 1209164339Ssuz * source address to be forwarded to a different link. 1210164339Ssuz * So we also check whether the destination address is a link-local 1211164339Ssuz * address or the hop limit is 255. Note that RFC2080 does not require 1212164339Ssuz * the specific hop limit for a unicast response, so we cannot assume 1213164339Ssuz * the limitation. 1214164339Ssuz */ 1215164339Ssuz if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) { 1216164339Ssuz trace(1, 1217164339Ssuz "Response packet possibly from an off-link node: " 1218164339Ssuz "from %s to %s hlim=%d\n", 1219164339Ssuz inet6_n2p(&fsock.sin6_addr), 1220164339Ssuz inet6_n2p(&pi->ipi6_addr), *hlimp); 1221164339Ssuz return; 1222164339Ssuz } 1223164339Ssuz 122478064Sume idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr); 122578064Sume ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 122655163Sshin if (!ifcp) { 122778064Sume trace(1, "Packets to unknown interface index %d\n", idx); 122855163Sshin return; /* Ignore it */ 122955163Sshin } 123055163Sshin if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 123155163Sshin return; /* The packet is from me; ignore */ 123255163Sshin if (rp->rip6_cmd != RIP6_RESPONSE) { 123355163Sshin trace(1, "Invalid command %d\n", rp->rip6_cmd); 123462607Sitojun return; 123555163Sshin } 123678064Sume 123778064Sume /* -N: no use */ 123855163Sshin if (iff_find(ifcp, 'N') != NULL) 123955163Sshin return; 124078064Sume 124155163Sshin tracet(1, "Recv(%s): from %s.%d info(%d)\n", 124278064Sume ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 124355163Sshin 124455163Sshin t = time(NULL); 124578064Sume t_half_lifetime = t - (RIP_LIFETIME/2); 124655163Sshin for (; nn; nn--, np++) { 124755163Sshin if (np->rip6_metric == NEXTHOP_METRIC) { 124855163Sshin /* modify neighbor address */ 124955163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 125055163Sshin nh = np->rip6_dest; 125178064Sume SET_IN6_LINKLOCAL_IFINDEX(nh, idx); 125255163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 125355163Sshin } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 125455163Sshin nh = fsock.sin6_addr; 125555163Sshin trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 125655163Sshin } else { 125755163Sshin nh = fsock.sin6_addr; 125855163Sshin trace(1, "\tInvalid Nexthop: %s\n", 125978064Sume inet6_n2p(&np->rip6_dest)); 126055163Sshin } 126155163Sshin continue; 126255163Sshin } 126355163Sshin if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 126455163Sshin trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 126555163Sshin inet6_n2p(&np->rip6_dest), 126655163Sshin np->rip6_plen, np->rip6_metric); 126755163Sshin continue; 126855163Sshin } 126955163Sshin if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 127055163Sshin trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 127155163Sshin inet6_n2p(&np->rip6_dest), 127255163Sshin np->rip6_plen, np->rip6_metric); 127355163Sshin continue; 127455163Sshin } 127555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 127655163Sshin trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 127755163Sshin inet6_n2p(&np->rip6_dest), 127855163Sshin np->rip6_plen, np->rip6_metric); 127955163Sshin continue; 128055163Sshin } 128155163Sshin /* may need to pass sitelocal prefix in some case, however*/ 128255163Sshin if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 128355163Sshin trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 128455163Sshin inet6_n2p(&np->rip6_dest), 128555163Sshin np->rip6_plen, np->rip6_metric); 128655163Sshin continue; 128755163Sshin } 128855163Sshin trace(2, "\tnetinfo6: %s/%d [%d]", 128955163Sshin inet6_n2p(&np->rip6_dest), 129055163Sshin np->rip6_plen, np->rip6_metric); 129155163Sshin if (np->rip6_tag) 129255163Sshin trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 129362607Sitojun if (dflag >= 2) { 129462607Sitojun ia = np->rip6_dest; 129562607Sitojun applyplen(&ia, np->rip6_plen); 129662607Sitojun if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 129762607Sitojun trace(2, " [junk outside prefix]"); 129862607Sitojun } 129955163Sshin 130078064Sume /* 130178064Sume * -L: listen only if the prefix matches the configuration 130278064Sume */ 130355163Sshin ok = 1; /* if there's no L filter, it is ok */ 130455163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 130555163Sshin if (iffp->iff_type != 'L') 130655163Sshin continue; 130755163Sshin ok = 0; 130855163Sshin if (np->rip6_plen < iffp->iff_plen) 130955163Sshin continue; 131055163Sshin /* special rule: ::/0 means default, not "in /0" */ 131155163Sshin if (iffp->iff_plen == 0 && np->rip6_plen > 0) 131255163Sshin continue; 131362607Sitojun ia = np->rip6_dest; 131455163Sshin applyplen(&ia, iffp->iff_plen); 131555163Sshin if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 131655163Sshin ok = 1; 131755163Sshin break; 131855163Sshin } 131955163Sshin } 132055163Sshin if (!ok) { 132155163Sshin trace(2, " (filtered)\n"); 132255163Sshin continue; 132355163Sshin } 132455163Sshin 132555163Sshin trace(2, "\n"); 132655163Sshin np->rip6_metric++; 132755163Sshin np->rip6_metric += ifcp->ifc_metric; 132855163Sshin if (np->rip6_metric > HOPCNT_INFINITY6) 132955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 133055163Sshin 133155163Sshin applyplen(&np->rip6_dest, np->rip6_plen); 133278064Sume if ((rrt = rtsearch(np, NULL)) != NULL) { 133355163Sshin if (rrt->rrt_t == 0) 133455163Sshin continue; /* Intf route has priority */ 133555163Sshin nq = &rrt->rrt_info; 133655163Sshin if (nq->rip6_metric > np->rip6_metric) { 133755163Sshin if (rrt->rrt_index == ifcp->ifc_index && 133855163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 133955163Sshin /* Small metric from the same gateway */ 134055163Sshin nq->rip6_metric = np->rip6_metric; 134155163Sshin } else { 134255163Sshin /* Better route found */ 134355163Sshin rrt->rrt_index = ifcp->ifc_index; 134455163Sshin /* Update routing table */ 134555163Sshin delroute(nq, &rrt->rrt_gw); 134655163Sshin rrt->rrt_gw = nh; 134755163Sshin *nq = *np; 134855163Sshin addroute(rrt, &nh, ifcp); 134955163Sshin } 135062607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 135155163Sshin rrt->rrt_t = t; 135255163Sshin need_trigger = 1; 135355163Sshin } else if (nq->rip6_metric < np->rip6_metric && 135455163Sshin rrt->rrt_index == ifcp->ifc_index && 135555163Sshin IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 135655163Sshin /* Got worse route from same gw */ 135755163Sshin nq->rip6_metric = np->rip6_metric; 135855163Sshin rrt->rrt_t = t; 135962607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 136055163Sshin need_trigger = 1; 136155163Sshin } else if (nq->rip6_metric == np->rip6_metric && 136255163Sshin np->rip6_metric < HOPCNT_INFINITY6) { 136378064Sume if (rrt->rrt_index == ifcp->ifc_index && 136478064Sume IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 136578064Sume /* same metric, same route from same gw */ 136678064Sume rrt->rrt_t = t; 136778064Sume } else if (rrt->rrt_t < t_half_lifetime) { 136878064Sume /* Better route found */ 136978064Sume rrt->rrt_index = ifcp->ifc_index; 137078064Sume /* Update routing table */ 137178064Sume delroute(nq, &rrt->rrt_gw); 137278064Sume rrt->rrt_gw = nh; 137378064Sume *nq = *np; 137478064Sume addroute(rrt, &nh, ifcp); 137578064Sume rrt->rrt_rflags |= RRTF_CHANGED; 137678064Sume rrt->rrt_t = t; 137778064Sume } 137855163Sshin } 137962607Sitojun /* 138055163Sshin * if nq->rip6_metric == HOPCNT_INFINITY6 then 138178064Sume * do not update age value. Do nothing. 138255163Sshin */ 138355163Sshin } else if (np->rip6_metric < HOPCNT_INFINITY6) { 138455163Sshin /* Got a new valid route */ 138578064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 138655163Sshin fatal("malloc: struct riprt"); 138778064Sume /*NOTREACHED*/ 138878064Sume } 138962607Sitojun memset(rrt, 0, sizeof(*rrt)); 139055163Sshin nq = &rrt->rrt_info; 139155163Sshin 139255163Sshin rrt->rrt_same = NULL; 139355163Sshin rrt->rrt_index = ifcp->ifc_index; 139455163Sshin rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 139555163Sshin rrt->rrt_gw = nh; 139655163Sshin *nq = *np; 139755163Sshin applyplen(&nq->rip6_dest, nq->rip6_plen); 139855163Sshin if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 139955163Sshin rrt->rrt_flags |= RTF_HOST; 140055163Sshin 140155163Sshin /* Put the route to the list */ 140255163Sshin rrt->rrt_next = riprt; 140355163Sshin riprt = rrt; 140455163Sshin /* Update routing table */ 140555163Sshin addroute(rrt, &nh, ifcp); 140662607Sitojun rrt->rrt_rflags |= RRTF_CHANGED; 140755163Sshin need_trigger = 1; 140855163Sshin rrt->rrt_t = t; 140955163Sshin } 141055163Sshin } 141155163Sshin /* XXX need to care the interval between triggered updates */ 141255163Sshin if (need_trigger) { 141355163Sshin if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 141455163Sshin for (ic = ifc; ic; ic = ic->ifc_next) { 141555163Sshin if (ifcp->ifc_index == ic->ifc_index) 141655163Sshin continue; 141755163Sshin if (ic->ifc_flags & IFF_UP) 141855163Sshin ripsend(ic, &ic->ifc_ripsin, 141962607Sitojun RRTF_CHANGED); 142055163Sshin } 142155163Sshin } 142255163Sshin /* Reset the flag */ 142355163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) 142462607Sitojun rrt->rrt_rflags &= ~RRTF_CHANGED; 142555163Sshin } 142655163Sshin} 142755163Sshin 142855163Sshin/* 142955163Sshin * Send all routes request packet to the specified interface. 143055163Sshin */ 143155163Sshinvoid 143255163Sshinsendrequest(ifcp) 143355163Sshin struct ifc *ifcp; 143455163Sshin{ 143555163Sshin struct netinfo6 *np; 143655163Sshin int error; 143755163Sshin 143855163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 143955163Sshin return; 144055163Sshin ripbuf->rip6_cmd = RIP6_REQUEST; 144155163Sshin np = ripbuf->rip6_nets; 144255163Sshin memset(np, 0, sizeof(struct netinfo6)); 144355163Sshin np->rip6_metric = HOPCNT_INFINITY6; 144455163Sshin tracet(1, "Send rtdump Request to %s (%s)\n", 144555163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 144655163Sshin error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 144755163Sshin if (error == EAFNOSUPPORT) { 144855163Sshin /* Protocol not supported */ 144955163Sshin tracet(1, "Could not send rtdump Request to %s (%s): " 145055163Sshin "set IFF_UP to 0\n", 145155163Sshin ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 145255163Sshin ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 145355163Sshin } 145455163Sshin ripbuf->rip6_cmd = RIP6_RESPONSE; 145555163Sshin} 145655163Sshin 145755163Sshin/* 145855163Sshin * Process a RIP6_REQUEST packet. 145955163Sshin */ 146055163Sshinvoid 1461119031Sumeriprequest(ifcp, np, nn, sin6) 146255163Sshin struct ifc *ifcp; 146355163Sshin struct netinfo6 *np; 146455163Sshin int nn; 1465119031Sume struct sockaddr_in6 *sin6; 146655163Sshin{ 146755163Sshin int i; 146855163Sshin struct riprt *rrt; 146955163Sshin 147055163Sshin if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 147155163Sshin np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 147255163Sshin /* Specific response, don't split-horizon */ 147355163Sshin trace(1, "\tRIP Request\n"); 147455163Sshin for (i = 0; i < nn; i++, np++) { 147578064Sume rrt = rtsearch(np, NULL); 147655163Sshin if (rrt) 147755163Sshin np->rip6_metric = rrt->rrt_info.rip6_metric; 147855163Sshin else 147955163Sshin np->rip6_metric = HOPCNT_INFINITY6; 148055163Sshin } 1481119031Sume (void)sendpacket(sin6, RIPSIZE(nn)); 148255163Sshin return; 148355163Sshin } 148455163Sshin /* Whole routing table dump */ 148555163Sshin trace(1, "\tRIP Request -- whole routing table\n"); 1486119031Sume ripsend(ifcp, sin6, RRTF_SENDANYWAY); 148755163Sshin} 148855163Sshin 148955163Sshin/* 149055163Sshin * Get information of each interface. 149155163Sshin */ 149255163Sshinvoid 149355163Sshinifconfig() 149455163Sshin{ 149562607Sitojun struct ifaddrs *ifap, *ifa; 149662607Sitojun struct ifc *ifcp; 149762607Sitojun struct ipv6_mreq mreq; 149862607Sitojun int s; 149962607Sitojun 150078064Sume if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 150162607Sitojun fatal("socket"); 150278064Sume /*NOTREACHED*/ 150378064Sume } 150462607Sitojun 150578064Sume if (getifaddrs(&ifap) != 0) { 150662607Sitojun fatal("getifaddrs"); 150778064Sume /*NOTREACHED*/ 150878064Sume } 150962607Sitojun 151062607Sitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 151162607Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 151262607Sitojun continue; 151362607Sitojun ifcp = ifc_find(ifa->ifa_name); 151462607Sitojun /* we are interested in multicast-capable interfaces */ 151562607Sitojun if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 151662607Sitojun continue; 151762607Sitojun if (!ifcp) { 151862607Sitojun /* new interface */ 151978064Sume if ((ifcp = MALLOC(struct ifc)) == NULL) { 152062607Sitojun fatal("malloc: struct ifc"); 152178064Sume /*NOTREACHED*/ 152278064Sume } 152362607Sitojun memset(ifcp, 0, sizeof(*ifcp)); 152462607Sitojun ifcp->ifc_index = -1; 152562607Sitojun ifcp->ifc_next = ifc; 152662607Sitojun ifc = ifcp; 152762607Sitojun nifc++; 152862607Sitojun ifcp->ifc_name = allocopy(ifa->ifa_name); 152962607Sitojun ifcp->ifc_addr = 0; 153062607Sitojun ifcp->ifc_filter = 0; 153162607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 153262607Sitojun trace(1, "newif %s <%s>\n", ifcp->ifc_name, 153362607Sitojun ifflags(ifcp->ifc_flags)); 153462607Sitojun if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 153562607Sitojun loopifcp = ifcp; 153662607Sitojun } else { 153762607Sitojun /* update flag, this may be up again */ 153862607Sitojun if (ifcp->ifc_flags != ifa->ifa_flags) { 153962607Sitojun trace(1, "%s: <%s> -> ", ifcp->ifc_name, 154062607Sitojun ifflags(ifcp->ifc_flags)); 154162607Sitojun trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 154278064Sume ifcp->ifc_cflags |= IFC_CHANGED; 154362607Sitojun } 154462607Sitojun ifcp->ifc_flags = ifa->ifa_flags; 154562607Sitojun } 154662607Sitojun ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); 154762607Sitojun if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 154862607Sitojun && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 154962607Sitojun mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 155062607Sitojun mreq.ipv6mr_interface = ifcp->ifc_index; 155178064Sume if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 155278064Sume &mreq, sizeof(mreq)) < 0) { 155362607Sitojun fatal("IPV6_JOIN_GROUP"); 155478064Sume /*NOTREACHED*/ 155578064Sume } 155662607Sitojun trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 155762607Sitojun ifcp->ifc_joined++; 155862607Sitojun } 155962607Sitojun } 156062607Sitojun close(s); 156162607Sitojun freeifaddrs(ifap); 156255163Sshin} 156355163Sshin 156455163Sshinvoid 156562607Sitojunifconfig1(name, sa, ifcp, s) 156662607Sitojun const char *name; 156762607Sitojun const struct sockaddr *sa; 156855163Sshin struct ifc *ifcp; 156955163Sshin int s; 157055163Sshin{ 157155163Sshin struct in6_ifreq ifr; 1572119031Sume const struct sockaddr_in6 *sin6; 157355163Sshin struct ifac *ifa; 157455163Sshin int plen; 157555163Sshin char buf[BUFSIZ]; 157655163Sshin 1577119031Sume sin6 = (const struct sockaddr_in6 *)sa; 1578122677Sume if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) 1579122677Sume return; 1580119031Sume ifr.ifr_addr = *sin6; 1581119032Sume strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 158278064Sume if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 158355163Sshin fatal("ioctl: SIOCGIFNETMASK_IN6"); 158478064Sume /*NOTREACHED*/ 158578064Sume } 158678064Sume plen = sin6mask2len(&ifr.ifr_addr); 1587119031Sume if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 158855163Sshin /* same interface found */ 158955163Sshin /* need check if something changed */ 159055163Sshin /* XXX not yet implemented */ 159155163Sshin return; 159255163Sshin } 159355163Sshin /* 159455163Sshin * New address is found 159555163Sshin */ 159678064Sume if ((ifa = MALLOC(struct ifac)) == NULL) { 159755163Sshin fatal("malloc: struct ifac"); 159878064Sume /*NOTREACHED*/ 159978064Sume } 160062607Sitojun memset(ifa, 0, sizeof(*ifa)); 160155163Sshin ifa->ifa_conf = ifcp; 160255163Sshin ifa->ifa_next = ifcp->ifc_addr; 160355163Sshin ifcp->ifc_addr = ifa; 1604119031Sume ifa->ifa_addr = sin6->sin6_addr; 160555163Sshin ifa->ifa_plen = plen; 160655163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1607119031Sume ifr.ifr_addr = *sin6; 160878064Sume if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 160955163Sshin fatal("ioctl: SIOCGIFDSTADDR_IN6"); 161078064Sume /*NOTREACHED*/ 161178064Sume } 161255163Sshin ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr; 161355163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf)); 161455163Sshin trace(1, "found address %s/%d -- %s\n", 161555163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf); 161655163Sshin } else { 161755163Sshin trace(1, "found address %s/%d\n", 161855163Sshin inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen); 161955163Sshin } 162055163Sshin if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 162155163Sshin ifcp->ifc_mylladdr = ifa->ifa_addr; 162255163Sshin ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr); 162355163Sshin memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 162455163Sshin SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr, 162555163Sshin ifcp->ifc_index); 162655163Sshin setindex2ifc(ifcp->ifc_index, ifcp); 162755163Sshin ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 162855163Sshin if (ifcp->ifc_mtu > RIP6_MAXMTU) 162955163Sshin ifcp->ifc_mtu = RIP6_MAXMTU; 163078064Sume if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 163155163Sshin fatal("ioctl: SIOCGIFMETRIC"); 163278064Sume /*NOTREACHED*/ 163378064Sume } 163455163Sshin ifcp->ifc_metric = ifr.ifr_metric; 163555163Sshin trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 163655163Sshin ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 163778064Sume } else 163878064Sume ifcp->ifc_cflags |= IFC_CHANGED; 163955163Sshin} 164055163Sshin 164155163Sshin/* 164255163Sshin * Receive and process routing messages. 164355163Sshin * Update interface information as necesssary. 164455163Sshin */ 164555163Sshinvoid 164655163Sshinrtrecv() 164755163Sshin{ 164855163Sshin char buf[BUFSIZ]; 164955163Sshin char *p, *q; 165055163Sshin struct rt_msghdr *rtm; 165155163Sshin struct ifa_msghdr *ifam; 165255163Sshin struct if_msghdr *ifm; 165355163Sshin int len; 165478064Sume struct ifc *ifcp, *ic; 165555163Sshin int iface = 0, rtable = 0; 165655163Sshin struct sockaddr_in6 *rta[RTAX_MAX]; 165778064Sume struct sockaddr_in6 mask; 165855163Sshin int i, addrs; 165978064Sume struct riprt *rrt; 166055163Sshin 166155163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 166255163Sshin perror("read from rtsock"); 166378064Sume exit(1); 166455163Sshin } 166555163Sshin if (len < sizeof(*rtm)) { 166669279Sume trace(1, "short read from rtsock: %d (should be > %lu)\n", 166769279Sume len, (u_long)sizeof(*rtm)); 166855163Sshin return; 166955163Sshin } 1670119042Sume if (dflag >= 2) { 1671119042Sume fprintf(stderr, "rtmsg:\n"); 1672119042Sume for (i = 0; i < len; i++) { 1673119042Sume fprintf(stderr, "%02x ", buf[i] & 0xff); 1674119042Sume if (i % 16 == 15) fprintf(stderr, "\n"); 1675119042Sume } 1676119042Sume fprintf(stderr, "\n"); 1677119042Sume } 167855163Sshin 167955163Sshin for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { 168055163Sshin /* safety against bogus message */ 168155163Sshin if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { 168255163Sshin trace(1, "bogus rtmsg: length=%d\n", 168355163Sshin ((struct rt_msghdr *)p)->rtm_msglen); 168455163Sshin break; 168555163Sshin } 168655163Sshin rtm = NULL; 168755163Sshin ifam = NULL; 168855163Sshin ifm = NULL; 168955163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 169055163Sshin case RTM_NEWADDR: 169155163Sshin case RTM_DELADDR: 169255163Sshin ifam = (struct ifa_msghdr *)p; 169355163Sshin addrs = ifam->ifam_addrs; 169455163Sshin q = (char *)(ifam + 1); 169555163Sshin break; 169655163Sshin case RTM_IFINFO: 169755163Sshin ifm = (struct if_msghdr *)p; 169855163Sshin addrs = ifm->ifm_addrs; 169955163Sshin q = (char *)(ifm + 1); 170055163Sshin break; 170155163Sshin default: 170255163Sshin rtm = (struct rt_msghdr *)p; 170355163Sshin addrs = rtm->rtm_addrs; 170455163Sshin q = (char *)(rtm + 1); 170555163Sshin if (rtm->rtm_version != RTM_VERSION) { 170655163Sshin trace(1, "unexpected rtmsg version %d " 170755163Sshin "(should be %d)\n", 170855163Sshin rtm->rtm_version, RTM_VERSION); 170955163Sshin continue; 171055163Sshin } 171155163Sshin if (rtm->rtm_pid == pid) { 171255163Sshin#if 0 171355163Sshin trace(1, "rtmsg looped back to me, ignored\n"); 171455163Sshin#endif 171555163Sshin continue; 171655163Sshin } 171755163Sshin break; 171855163Sshin } 171955163Sshin memset(&rta, 0, sizeof(rta)); 172055163Sshin for (i = 0; i < RTAX_MAX; i++) { 172155163Sshin if (addrs & (1 << i)) { 172255163Sshin rta[i] = (struct sockaddr_in6 *)q; 172355163Sshin q += ROUNDUP(rta[i]->sin6_len); 172455163Sshin } 172555163Sshin } 172655163Sshin 172755163Sshin trace(1, "rtsock: %s (addrs=%x)\n", 172855163Sshin rttypes((struct rt_msghdr *)p), addrs); 172955163Sshin if (dflag >= 2) { 173055163Sshin for (i = 0; 173155163Sshin i < ((struct rt_msghdr *)p)->rtm_msglen; 173255163Sshin i++) { 173355163Sshin fprintf(stderr, "%02x ", p[i] & 0xff); 173455163Sshin if (i % 16 == 15) fprintf(stderr, "\n"); 173555163Sshin } 173655163Sshin fprintf(stderr, "\n"); 173755163Sshin } 173855163Sshin 173955163Sshin /* 174055163Sshin * Easy ones first. 174155163Sshin * 174255163Sshin * We may be able to optimize by using ifm->ifm_index or 174355163Sshin * ifam->ifam_index. For simplicity we don't do that here. 174455163Sshin */ 174555163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 174655163Sshin case RTM_NEWADDR: 174755163Sshin case RTM_IFINFO: 174855163Sshin iface++; 174955163Sshin continue; 175055163Sshin case RTM_ADD: 175155163Sshin rtable++; 175255163Sshin continue; 175355163Sshin case RTM_LOSING: 175455163Sshin case RTM_MISS: 175555163Sshin case RTM_RESOLVE: 175655163Sshin case RTM_GET: 175755163Sshin case RTM_LOCK: 175855163Sshin /* nothing to be done here */ 175955163Sshin trace(1, "\tnothing to be done, ignored\n"); 176055163Sshin continue; 176155163Sshin } 176255163Sshin 176355163Sshin#if 0 176455163Sshin if (rta[RTAX_DST] == NULL) { 176555163Sshin trace(1, "\tno destination, ignored\n"); 176662607Sitojun continue; 176755163Sshin } 176855163Sshin if (rta[RTAX_DST]->sin6_family != AF_INET6) { 176955163Sshin trace(1, "\taf mismatch, ignored\n"); 177055163Sshin continue; 177155163Sshin } 177255163Sshin if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 177355163Sshin trace(1, "\tlinklocal destination, ignored\n"); 177455163Sshin continue; 177555163Sshin } 177655163Sshin if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 177755163Sshin trace(1, "\tloopback destination, ignored\n"); 177855163Sshin continue; /* Loopback */ 177955163Sshin } 178055163Sshin if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 178155163Sshin trace(1, "\tmulticast destination, ignored\n"); 178255163Sshin continue; 178355163Sshin } 178455163Sshin#endif 178555163Sshin 178655163Sshin /* hard ones */ 178755163Sshin switch (((struct rt_msghdr *)p)->rtm_type) { 178855163Sshin case RTM_NEWADDR: 178955163Sshin case RTM_IFINFO: 179055163Sshin case RTM_ADD: 179155163Sshin case RTM_LOSING: 179255163Sshin case RTM_MISS: 179355163Sshin case RTM_RESOLVE: 179455163Sshin case RTM_GET: 179555163Sshin case RTM_LOCK: 179655163Sshin /* should already be handled */ 179755163Sshin fatal("rtrecv: never reach here"); 179878064Sume /*NOTREACHED*/ 179955163Sshin case RTM_DELETE: 180078064Sume if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 180178064Sume trace(1, "\tsome of dst/gw/netamsk are " 180278064Sume "unavailable, ignored\n"); 180355163Sshin break; 180455163Sshin } 180578064Sume if ((rtm->rtm_flags & RTF_HOST) != 0) { 180678064Sume mask.sin6_len = sizeof(mask); 180778064Sume memset(&mask.sin6_addr, 0xff, 180878064Sume sizeof(mask.sin6_addr)); 180978064Sume rta[RTAX_NETMASK] = &mask; 181078064Sume } else if (!rta[RTAX_NETMASK]) { 181178064Sume trace(1, "\tsome of dst/gw/netamsk are " 181278064Sume "unavailable, ignored\n"); 181378064Sume break; 181478064Sume } 181578064Sume if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 181678064Sume rta[RTAX_NETMASK]) == 0) { 181755163Sshin rtable++; /*just to be sure*/ 181855163Sshin } 181955163Sshin break; 182055163Sshin case RTM_CHANGE: 182155163Sshin case RTM_REDIRECT: 182255163Sshin trace(1, "\tnot supported yet, ignored\n"); 182355163Sshin break; 182455163Sshin case RTM_DELADDR: 182555163Sshin if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 182655163Sshin trace(1, "\tno netmask or ifa given, ignored\n"); 182755163Sshin break; 182855163Sshin } 182955163Sshin if (ifam->ifam_index < nindex2ifc) 183055163Sshin ifcp = index2ifc[ifam->ifam_index]; 183155163Sshin else 183255163Sshin ifcp = NULL; 183355163Sshin if (!ifcp) { 183455163Sshin trace(1, "\tinvalid ifam_index %d, ignored\n", 183555163Sshin ifam->ifam_index); 183655163Sshin break; 183755163Sshin } 183878064Sume if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 183978064Sume iface++; 184055163Sshin break; 184155163Sshin case RTM_OLDADD: 184255163Sshin case RTM_OLDDEL: 184355163Sshin trace(1, "\tnot supported yet, ignored\n"); 184455163Sshin break; 184555163Sshin } 184655163Sshin 184755163Sshin } 184855163Sshin 184955163Sshin if (iface) { 185055163Sshin trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 185155163Sshin ifconfig(); 185255163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) 185378064Sume if (ifcp->ifc_cflags & IFC_CHANGED) { 185478064Sume if (ifrt(ifcp, 1)) { 185578064Sume for (ic = ifc; ic; ic = ic->ifc_next) { 185678064Sume if (ifcp->ifc_index == ic->ifc_index) 185778064Sume continue; 185878064Sume if (ic->ifc_flags & IFF_UP) 185978064Sume ripsend(ic, &ic->ifc_ripsin, 186078064Sume RRTF_CHANGED); 186178064Sume } 186278064Sume /* Reset the flag */ 186378064Sume for (rrt = riprt; rrt; rrt = rrt->rrt_next) 186478064Sume rrt->rrt_rflags &= ~RRTF_CHANGED; 186578064Sume } 186678064Sume ifcp->ifc_cflags &= ~IFC_CHANGED; 186778064Sume } 186855163Sshin } 186955163Sshin if (rtable) { 187055163Sshin trace(1, "rtsock: read routing table again\n"); 187155163Sshin krtread(1); 187255163Sshin } 187355163Sshin} 187455163Sshin 187555163Sshin/* 187655163Sshin * remove specified route from the internal routing table. 187755163Sshin */ 187855163Sshinint 187955163Sshinrt_del(sdst, sgw, smask) 188055163Sshin const struct sockaddr_in6 *sdst; 188155163Sshin const struct sockaddr_in6 *sgw; 188255163Sshin const struct sockaddr_in6 *smask; 188355163Sshin{ 188455163Sshin const struct in6_addr *dst = NULL; 188555163Sshin const struct in6_addr *gw = NULL; 188655163Sshin int prefix; 188755163Sshin struct netinfo6 ni6; 188855163Sshin struct riprt *rrt = NULL; 188955163Sshin time_t t_lifetime; 189055163Sshin 189155163Sshin if (sdst->sin6_family != AF_INET6) { 189255163Sshin trace(1, "\tother AF, ignored\n"); 189355163Sshin return -1; 189455163Sshin } 189555163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 189655163Sshin || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 189755163Sshin || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 189855163Sshin trace(1, "\taddress %s not interesting, ignored\n", 189955163Sshin inet6_n2p(&sdst->sin6_addr)); 190055163Sshin return -1; 190155163Sshin } 190255163Sshin dst = &sdst->sin6_addr; 190378064Sume if (sgw->sin6_family == AF_INET6) { 190455163Sshin /* easy case */ 190555163Sshin gw = &sgw->sin6_addr; 190678064Sume prefix = sin6mask2len(smask); 190755163Sshin } else if (sgw->sin6_family == AF_LINK) { 190855163Sshin /* 190955163Sshin * Interface route... a hard case. We need to get the prefix 191055163Sshin * length from the kernel, but we now are parsing rtmsg. 191155163Sshin * We'll purge matching routes from my list, then get the 191255163Sshin * fresh list. 191355163Sshin */ 191455163Sshin struct riprt *longest; 1915108533Sschweikh trace(1, "\t%s is an interface route, guessing prefixlen\n", 191655163Sshin inet6_n2p(dst)); 191755163Sshin longest = NULL; 191855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 191955163Sshin if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 192055163Sshin &sdst->sin6_addr) 192155163Sshin && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 192255163Sshin if (!longest 192355163Sshin || longest->rrt_info.rip6_plen < 192455163Sshin rrt->rrt_info.rip6_plen) { 192555163Sshin longest = rrt; 192655163Sshin } 192755163Sshin } 192855163Sshin } 192955163Sshin rrt = longest; 193055163Sshin if (!rrt) { 193155163Sshin trace(1, "\tno matching interface route found\n"); 193255163Sshin return -1; 193355163Sshin } 193455163Sshin gw = &in6addr_loopback; 193555163Sshin prefix = rrt->rrt_info.rip6_plen; 193655163Sshin } else { 193778064Sume trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 193855163Sshin return -1; 193955163Sshin } 194055163Sshin 194155163Sshin trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 194255163Sshin trace(1, "gw %s\n", inet6_n2p(gw)); 194355163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 194455163Sshin /* age route for interface address */ 194555163Sshin memset(&ni6, 0, sizeof(ni6)); 194655163Sshin ni6.rip6_dest = *dst; 194755163Sshin ni6.rip6_plen = prefix; 194855163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 194955163Sshin trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 195055163Sshin ni6.rip6_plen); 195178064Sume if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) { 195255163Sshin trace(1, "\tno route found\n"); 195355163Sshin return -1; 195455163Sshin } 195578064Sume#if 0 195655163Sshin if ((rrt->rrt_flags & RTF_STATIC) == 0) { 195755163Sshin trace(1, "\tyou can delete static routes only\n"); 195878064Sume } else 195978064Sume#endif 196078064Sume if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 196155163Sshin trace(1, "\tgw mismatch: %s <-> ", 196255163Sshin inet6_n2p(&rrt->rrt_gw)); 196355163Sshin trace(1, "%s\n", inet6_n2p(gw)); 196455163Sshin } else { 196555163Sshin trace(1, "\troute found, age it\n"); 196655163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 196755163Sshin rrt->rrt_t = t_lifetime; 196855163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 196955163Sshin } 197055163Sshin } 197155163Sshin return 0; 197255163Sshin} 197355163Sshin 197455163Sshin/* 197555163Sshin * remove specified address from internal interface/routing table. 197655163Sshin */ 197755163Sshinint 197855163Sshinrt_deladdr(ifcp, sifa, smask) 197955163Sshin struct ifc *ifcp; 198055163Sshin const struct sockaddr_in6 *sifa; 198155163Sshin const struct sockaddr_in6 *smask; 198255163Sshin{ 198355163Sshin const struct in6_addr *addr = NULL; 198455163Sshin int prefix; 198555163Sshin struct ifac *ifa = NULL; 198655163Sshin struct netinfo6 ni6; 198755163Sshin struct riprt *rrt = NULL; 198855163Sshin time_t t_lifetime; 198955163Sshin int updated = 0; 199055163Sshin 199178064Sume if (sifa->sin6_family != AF_INET6) { 199255163Sshin trace(1, "\tother AF, ignored\n"); 199355163Sshin return -1; 199455163Sshin } 199555163Sshin addr = &sifa->sin6_addr; 199678064Sume prefix = sin6mask2len(smask); 199755163Sshin 199855163Sshin trace(1, "\tdeleting %s/%d from %s\n", 199955163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 200055163Sshin ifa = ifa_match(ifcp, addr, prefix); 200155163Sshin if (!ifa) { 200255163Sshin trace(1, "\tno matching ifa found for %s/%d on %s\n", 200355163Sshin inet6_n2p(addr), prefix, ifcp->ifc_name); 200455163Sshin return -1; 200555163Sshin } 200655163Sshin if (ifa->ifa_conf != ifcp) { 200755163Sshin trace(1, "\taddress table corrupt: back pointer does not match " 200855163Sshin "(%s != %s)\n", 200955163Sshin ifcp->ifc_name, ifa->ifa_conf->ifc_name); 201055163Sshin return -1; 201155163Sshin } 201255163Sshin /* remove ifa from interface */ 201355163Sshin if (ifcp->ifc_addr == ifa) 201455163Sshin ifcp->ifc_addr = ifa->ifa_next; 201555163Sshin else { 201655163Sshin struct ifac *p; 201755163Sshin for (p = ifcp->ifc_addr; p; p = p->ifa_next) { 201855163Sshin if (p->ifa_next == ifa) { 201955163Sshin p->ifa_next = ifa->ifa_next; 202055163Sshin break; 202155163Sshin } 202255163Sshin } 202355163Sshin } 202455163Sshin ifa->ifa_next = NULL; 202555163Sshin ifa->ifa_conf = NULL; 202655163Sshin t_lifetime = time(NULL) - RIP_LIFETIME; 202755163Sshin /* age route for interface address */ 202855163Sshin memset(&ni6, 0, sizeof(ni6)); 202955163Sshin ni6.rip6_dest = ifa->ifa_addr; 203055163Sshin ni6.rip6_plen = ifa->ifa_plen; 203155163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); 203255163Sshin trace(1, "\tfind interface route %s/%d on %d\n", 203355163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 203478064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 203555163Sshin struct in6_addr none; 203655163Sshin memset(&none, 0, sizeof(none)); 203778064Sume if (rrt->rrt_index == ifcp->ifc_index && 203878064Sume (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 203978064Sume IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 204055163Sshin trace(1, "\troute found, age it\n"); 204155163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 204255163Sshin rrt->rrt_t = t_lifetime; 204355163Sshin rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 204455163Sshin } 204555163Sshin updated++; 204655163Sshin } else { 204755163Sshin trace(1, "\tnon-interface route found: %s/%d on %d\n", 204855163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 204955163Sshin rrt->rrt_info.rip6_plen, 205055163Sshin rrt->rrt_index); 205155163Sshin } 205255163Sshin } else 205355163Sshin trace(1, "\tno interface route found\n"); 205455163Sshin /* age route for p2p destination */ 205555163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 205655163Sshin memset(&ni6, 0, sizeof(ni6)); 205755163Sshin ni6.rip6_dest = ifa->ifa_raddr; 205855163Sshin ni6.rip6_plen = 128; 205955163Sshin applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 206055163Sshin trace(1, "\tfind p2p route %s/%d on %d\n", 206155163Sshin inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 206255163Sshin ifcp->ifc_index); 206378064Sume if ((rrt = rtsearch(&ni6, NULL)) != NULL) { 206478064Sume if (rrt->rrt_index == ifcp->ifc_index && 206578064Sume IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) { 206655163Sshin trace(1, "\troute found, age it\n"); 206755163Sshin if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 206855163Sshin rrt->rrt_t = t_lifetime; 206955163Sshin rrt->rrt_info.rip6_metric = 207078064Sume HOPCNT_INFINITY6; 207155163Sshin updated++; 207255163Sshin } 207355163Sshin } else { 207455163Sshin trace(1, "\tnon-p2p route found: %s/%d on %d\n", 207555163Sshin inet6_n2p(&rrt->rrt_info.rip6_dest), 207655163Sshin rrt->rrt_info.rip6_plen, 207755163Sshin rrt->rrt_index); 207855163Sshin } 207955163Sshin } else 208055163Sshin trace(1, "\tno p2p route found\n"); 208155163Sshin } 208255163Sshin return updated ? 0 : -1; 208355163Sshin} 208455163Sshin 208555163Sshin/* 208655163Sshin * Get each interface address and put those interface routes to the route 208755163Sshin * list. 208855163Sshin */ 208978064Sumeint 209055163Sshinifrt(ifcp, again) 209162607Sitojun struct ifc *ifcp; 209255163Sshin int again; 209355163Sshin{ 209462607Sitojun struct ifac *ifa; 2095119042Sume struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; 209662607Sitojun struct netinfo6 *np; 209778064Sume time_t t_lifetime; 209878064Sume int need_trigger = 0; 209955163Sshin 2100122677Sume#if 0 210155163Sshin if (ifcp->ifc_flags & IFF_LOOPBACK) 210278064Sume return 0; /* ignore loopback */ 2103122677Sume#endif 2104122677Sume 210562607Sitojun if (ifcp->ifc_flags & IFF_POINTOPOINT) { 210662607Sitojun ifrt_p2p(ifcp, again); 210778064Sume return 0; 210862607Sitojun } 210962607Sitojun 211055163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 211162607Sitojun if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) { 211262607Sitojun#if 0 211362607Sitojun trace(1, "route: %s on %s: " 211462607Sitojun "skip linklocal interface address\n", 211562607Sitojun inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name); 211662607Sitojun#endif 211762607Sitojun continue; 211862607Sitojun } 211962607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) { 212062607Sitojun#if 0 212162607Sitojun trace(1, "route: %s: skip unspec interface address\n", 212262607Sitojun ifcp->ifc_name); 212362607Sitojun#endif 212462607Sitojun continue; 212562607Sitojun } 2126122677Sume if (IN6_IS_ADDR_LOOPBACK(&ifa->ifa_addr)) { 2127122677Sume#if 0 2128122677Sume trace(1, "route: %s: skip loopback address\n", 2129122677Sume ifcp->ifc_name); 2130122677Sume#endif 2131122677Sume continue; 2132122677Sume } 213378064Sume if (ifcp->ifc_flags & IFF_UP) { 213478064Sume if ((rrt = MALLOC(struct riprt)) == NULL) 213578064Sume fatal("malloc: struct riprt"); 213678064Sume memset(rrt, 0, sizeof(*rrt)); 213778064Sume rrt->rrt_same = NULL; 213878064Sume rrt->rrt_index = ifcp->ifc_index; 213978064Sume rrt->rrt_t = 0; /* don't age */ 214078064Sume rrt->rrt_info.rip6_dest = ifa->ifa_addr; 214178064Sume rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 214278064Sume rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 214378064Sume rrt->rrt_info.rip6_plen = ifa->ifa_plen; 2144122677Sume if (ifa->ifa_plen == 128) 2145122677Sume rrt->rrt_flags = RTF_HOST; 2146122677Sume else 2147122677Sume rrt->rrt_flags = RTF_CLONING; 214878064Sume rrt->rrt_rflags |= RRTF_CHANGED; 214978064Sume applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); 215078064Sume memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 215178064Sume rrt->rrt_gw = ifa->ifa_addr; 215278064Sume np = &rrt->rrt_info; 215378064Sume search_rrt = rtsearch(np, &prev_rrt); 215478064Sume if (search_rrt != NULL) { 2155119042Sume if (search_rrt->rrt_info.rip6_metric <= 215678064Sume rrt->rrt_info.rip6_metric) { 215778064Sume /* Already have better route */ 215878064Sume if (!again) { 215978064Sume trace(1, "route: %s/%d: " 216078064Sume "already registered (%s)\n", 216178064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 216278064Sume ifcp->ifc_name); 216378064Sume } 2164119042Sume goto next; 216578064Sume } 2166119042Sume 2167119042Sume if (prev_rrt) 2168119042Sume prev_rrt->rrt_next = rrt->rrt_next; 2169119042Sume else 2170119042Sume riprt = rrt->rrt_next; 2171119042Sume delroute(&rrt->rrt_info, &rrt->rrt_gw); 217278064Sume } 217355163Sshin /* Attach the route to the list */ 217462607Sitojun trace(1, "route: %s/%d: register route (%s)\n", 217562607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 217662607Sitojun ifcp->ifc_name); 217755163Sshin rrt->rrt_next = riprt; 217855163Sshin riprt = rrt; 217978064Sume addroute(rrt, &rrt->rrt_gw, ifcp); 2180119042Sume rrt = NULL; 218178064Sume sendrequest(ifcp); 218278064Sume ripsend(ifcp, &ifcp->ifc_ripsin, 0); 218378064Sume need_trigger = 1; 218455163Sshin } else { 218578064Sume for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) { 218678064Sume if (loop_rrt->rrt_index == ifcp->ifc_index) { 218778064Sume t_lifetime = time(NULL) - RIP_LIFETIME; 218878064Sume if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 218978064Sume loop_rrt->rrt_t = t_lifetime; 219078064Sume loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 219178064Sume loop_rrt->rrt_rflags |= RRTF_CHANGED; 219278064Sume need_trigger = 1; 219378064Sume } 219478064Sume } 219555163Sshin } 219678064Sume } 2197119042Sume next: 2198119042Sume if (rrt) 2199119042Sume free(rrt); 220062607Sitojun } 220178064Sume return need_trigger; 220262607Sitojun} 220355163Sshin 220462607Sitojun/* 220562607Sitojun * there are couple of p2p interface routing models. "behavior" lets 220662607Sitojun * you pick one. it looks that gated behavior fits best with BSDs, 2207119035Sume * since BSD kernels do not look at prefix length on p2p interfaces. 220862607Sitojun */ 220962607Sitojunvoid 221062607Sitojunifrt_p2p(ifcp, again) 221162607Sitojun struct ifc *ifcp; 221262607Sitojun int again; 221362607Sitojun{ 221462607Sitojun struct ifac *ifa; 221578064Sume struct riprt *rrt, *orrt, *prevrrt; 221662607Sitojun struct netinfo6 *np; 221762607Sitojun struct in6_addr addr, dest; 221862607Sitojun int advert, ignore, i; 221962607Sitojun#define P2PADVERT_NETWORK 1 222062607Sitojun#define P2PADVERT_ADDR 2 222162607Sitojun#define P2PADVERT_DEST 4 222262607Sitojun#define P2PADVERT_MAX 4 222362607Sitojun const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 222478064Sume const char *category = ""; 222562607Sitojun const char *noadv; 222662607Sitojun 222762607Sitojun for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 222862607Sitojun addr = ifa->ifa_addr; 222962607Sitojun dest = ifa->ifa_raddr; 223062607Sitojun applyplen(&addr, ifa->ifa_plen); 223162607Sitojun applyplen(&dest, ifa->ifa_plen); 223262607Sitojun advert = ignore = 0; 223362607Sitojun switch (behavior) { 223462607Sitojun case CISCO: 223562607Sitojun /* 223662607Sitojun * honor addr/plen, just like normal shared medium 223762607Sitojun * interface. this may cause trouble if you reuse 223862607Sitojun * addr/plen on other interfaces. 223962607Sitojun * 224062607Sitojun * advertise addr/plen. 224162607Sitojun */ 224262607Sitojun advert |= P2PADVERT_NETWORK; 224362607Sitojun break; 224462607Sitojun case GATED: 224562607Sitojun /* 224662607Sitojun * prefixlen on p2p interface is meaningless. 224762607Sitojun * advertise addr/128 and dest/128. 224862607Sitojun * 224962607Sitojun * do not install network route to route6d routing 225062607Sitojun * table (if we do, it would prevent route installation 225162607Sitojun * for other p2p interface that shares addr/plen). 225278064Sume * 225378064Sume * XXX what should we do if dest is ::? it will not 225478064Sume * get announced anyways (see following filter), 225578064Sume * but we need to think. 225662607Sitojun */ 225762607Sitojun advert |= P2PADVERT_ADDR; 225862607Sitojun advert |= P2PADVERT_DEST; 225962607Sitojun ignore |= P2PADVERT_NETWORK; 226062607Sitojun break; 226162607Sitojun case ROUTE6D: 226262607Sitojun /* 226378064Sume * just for testing. actually the code is redundant 226478064Sume * given the current p2p interface address assignment 226578064Sume * rule for kame kernel. 226678064Sume * 226778064Sume * intent: 226878064Sume * A/n -> announce A/n 226978064Sume * A B/n, A and B share prefix -> A/n (= B/n) 227078064Sume * A B/n, do not share prefix -> A/128 and B/128 227178064Sume * actually, A/64 and A B/128 are the only cases 227278064Sume * permitted by the kernel: 227378064Sume * A/64 -> A/64 227478064Sume * A B/128 -> A/128 and B/128 227562607Sitojun */ 227678064Sume if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) { 227778064Sume if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 227878064Sume advert |= P2PADVERT_NETWORK; 227978064Sume else { 228078064Sume advert |= P2PADVERT_ADDR; 228178064Sume advert |= P2PADVERT_DEST; 228278064Sume ignore |= P2PADVERT_NETWORK; 228378064Sume } 228478064Sume } else 228562607Sitojun advert |= P2PADVERT_NETWORK; 228662607Sitojun break; 228762607Sitojun } 228862607Sitojun 228962607Sitojun for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 229062607Sitojun if ((ignore & i) != 0) 229162607Sitojun continue; 229278064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 229355163Sshin fatal("malloc: struct riprt"); 229478064Sume /*NOTREACHED*/ 229578064Sume } 229662607Sitojun memset(rrt, 0, sizeof(*rrt)); 229755163Sshin rrt->rrt_same = NULL; 229855163Sshin rrt->rrt_index = ifcp->ifc_index; 229962607Sitojun rrt->rrt_t = 0; /* don't age */ 230062607Sitojun switch (i) { 230162607Sitojun case P2PADVERT_NETWORK: 230262607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 230362607Sitojun rrt->rrt_info.rip6_plen = ifa->ifa_plen; 230462607Sitojun applyplen(&rrt->rrt_info.rip6_dest, 230562607Sitojun ifa->ifa_plen); 230662607Sitojun category = "network"; 230762607Sitojun break; 230862607Sitojun case P2PADVERT_ADDR: 230962607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_addr; 231062607Sitojun rrt->rrt_info.rip6_plen = 128; 231178064Sume rrt->rrt_gw = in6addr_loopback; 231262607Sitojun category = "addr"; 231362607Sitojun break; 231462607Sitojun case P2PADVERT_DEST: 231562607Sitojun rrt->rrt_info.rip6_dest = ifa->ifa_raddr; 231662607Sitojun rrt->rrt_info.rip6_plen = 128; 231778064Sume rrt->rrt_gw = ifa->ifa_addr; 231862607Sitojun category = "dest"; 231962607Sitojun break; 232062607Sitojun } 232162607Sitojun if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 232262607Sitojun IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 232362607Sitojun#if 0 232462607Sitojun trace(1, "route: %s: skip unspec/linklocal " 232562607Sitojun "(%s on %s)\n", category, ifcp->ifc_name); 232662607Sitojun#endif 232762607Sitojun free(rrt); 232862607Sitojun continue; 232962607Sitojun } 233062607Sitojun if ((advert & i) == 0) { 233162607Sitojun rrt->rrt_rflags |= RRTF_NOADVERTISE; 233262607Sitojun noadv = ", NO-ADV"; 233362607Sitojun } else 233462607Sitojun noadv = ""; 233555163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 233662607Sitojun rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 233755163Sshin np = &rrt->rrt_info; 233878064Sume orrt = rtsearch(np, &prevrrt); 233978064Sume if (!orrt) { 234055163Sshin /* Attach the route to the list */ 234162607Sitojun trace(1, "route: %s/%d: register route " 234262607Sitojun "(%s on %s%s)\n", 234362607Sitojun inet6_n2p(&np->rip6_dest), np->rip6_plen, 234462607Sitojun category, ifcp->ifc_name, noadv); 234555163Sshin rrt->rrt_next = riprt; 234655163Sshin riprt = rrt; 234778064Sume } else if (rrt->rrt_index != orrt->rrt_index || 234878064Sume rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 234978064Sume /* swap route */ 235078064Sume rrt->rrt_next = orrt->rrt_next; 235178064Sume if (prevrrt) 235278064Sume prevrrt->rrt_next = rrt; 235378064Sume else 235478064Sume riprt = rrt; 235578064Sume free(orrt); 235678064Sume 235778064Sume trace(1, "route: %s/%d: update (%s on %s%s)\n", 235878064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 235978064Sume category, ifcp->ifc_name, noadv); 236055163Sshin } else { 236155163Sshin /* Already found */ 236255163Sshin if (!again) { 236362607Sitojun trace(1, "route: %s/%d: " 236462607Sitojun "already registered (%s on %s%s)\n", 236562607Sitojun inet6_n2p(&np->rip6_dest), 236662607Sitojun np->rip6_plen, category, 236762607Sitojun ifcp->ifc_name, noadv); 236855163Sshin } 236955163Sshin free(rrt); 237055163Sshin } 237155163Sshin } 237255163Sshin } 237362607Sitojun#undef P2PADVERT_NETWORK 237462607Sitojun#undef P2PADVERT_ADDR 237562607Sitojun#undef P2PADVERT_DEST 237662607Sitojun#undef P2PADVERT_MAX 237755163Sshin} 237855163Sshin 237955163Sshinint 238055163Sshingetifmtu(ifindex) 238155163Sshin int ifindex; 238255163Sshin{ 238355163Sshin int mib[6]; 238455163Sshin char *buf; 238555163Sshin size_t msize; 238655163Sshin struct if_msghdr *ifm; 238755163Sshin int mtu; 238855163Sshin 238955163Sshin mib[0] = CTL_NET; 239055163Sshin mib[1] = PF_ROUTE; 239155163Sshin mib[2] = 0; 239255163Sshin mib[3] = AF_INET6; 239355163Sshin mib[4] = NET_RT_IFLIST; 239455163Sshin mib[5] = ifindex; 239578064Sume if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 239655163Sshin fatal("sysctl estimate NET_RT_IFLIST"); 239778064Sume /*NOTREACHED*/ 239878064Sume } 239978064Sume if ((buf = malloc(msize)) == NULL) { 240055163Sshin fatal("malloc"); 240178064Sume /*NOTREACHED*/ 240278064Sume } 240378064Sume if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 240455163Sshin fatal("sysctl NET_RT_IFLIST"); 240578064Sume /*NOTREACHED*/ 240678064Sume } 240755163Sshin ifm = (struct if_msghdr *)buf; 240855163Sshin mtu = ifm->ifm_data.ifi_mtu; 240978064Sume if (ifindex != ifm->ifm_index) { 241055163Sshin fatal("ifindex does not match with ifm_index"); 241178064Sume /*NOTREACHED*/ 241278064Sume } 241355163Sshin free(buf); 241455163Sshin return mtu; 241555163Sshin} 241655163Sshin 241755163Sshinconst char * 241855163Sshinrttypes(rtm) 241955163Sshin struct rt_msghdr *rtm; 242055163Sshin{ 242162607Sitojun#define RTTYPE(s, f) \ 242262607Sitojundo { \ 242362607Sitojun if (rtm->rtm_type == (f)) \ 242462607Sitojun return (s); \ 242562607Sitojun} while (0) 242655163Sshin RTTYPE("ADD", RTM_ADD); 242755163Sshin RTTYPE("DELETE", RTM_DELETE); 242855163Sshin RTTYPE("CHANGE", RTM_CHANGE); 242955163Sshin RTTYPE("GET", RTM_GET); 243055163Sshin RTTYPE("LOSING", RTM_LOSING); 243155163Sshin RTTYPE("REDIRECT", RTM_REDIRECT); 243255163Sshin RTTYPE("MISS", RTM_MISS); 243355163Sshin RTTYPE("LOCK", RTM_LOCK); 243455163Sshin RTTYPE("OLDADD", RTM_OLDADD); 243555163Sshin RTTYPE("OLDDEL", RTM_OLDDEL); 243655163Sshin RTTYPE("RESOLVE", RTM_RESOLVE); 243755163Sshin RTTYPE("NEWADDR", RTM_NEWADDR); 243855163Sshin RTTYPE("DELADDR", RTM_DELADDR); 243955163Sshin RTTYPE("IFINFO", RTM_IFINFO); 244078064Sume#ifdef RTM_OLDADD 244178064Sume RTTYPE("OLDADD", RTM_OLDADD); 244278064Sume#endif 244378064Sume#ifdef RTM_OLDDEL 244478064Sume RTTYPE("OLDDEL", RTM_OLDDEL); 244578064Sume#endif 244678064Sume#ifdef RTM_OIFINFO 244778064Sume RTTYPE("OIFINFO", RTM_OIFINFO); 244878064Sume#endif 244978064Sume#ifdef RTM_IFANNOUNCE 245078064Sume RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 245178064Sume#endif 245278064Sume#ifdef RTM_NEWMADDR 245378064Sume RTTYPE("NEWMADDR", RTM_NEWMADDR); 245478064Sume#endif 245578064Sume#ifdef RTM_DELMADDR 245678064Sume RTTYPE("DELMADDR", RTM_DELMADDR); 245778064Sume#endif 245855163Sshin#undef RTTYPE 245955163Sshin return NULL; 246055163Sshin} 246155163Sshin 246255163Sshinconst char * 246355163Sshinrtflags(rtm) 246455163Sshin struct rt_msghdr *rtm; 246555163Sshin{ 246655163Sshin static char buf[BUFSIZ]; 246755163Sshin 246878064Sume /* 246978064Sume * letter conflict should be okay. painful when *BSD diverges... 247078064Sume */ 247178064Sume strlcpy(buf, "", sizeof(buf)); 247262607Sitojun#define RTFLAG(s, f) \ 247362607Sitojundo { \ 247462607Sitojun if (rtm->rtm_flags & (f)) \ 247578064Sume strlcat(buf, (s), sizeof(buf)); \ 247662607Sitojun} while (0) 247755163Sshin RTFLAG("U", RTF_UP); 247855163Sshin RTFLAG("G", RTF_GATEWAY); 247955163Sshin RTFLAG("H", RTF_HOST); 248055163Sshin RTFLAG("R", RTF_REJECT); 248155163Sshin RTFLAG("D", RTF_DYNAMIC); 248255163Sshin RTFLAG("M", RTF_MODIFIED); 248355163Sshin RTFLAG("d", RTF_DONE); 248455163Sshin#ifdef RTF_MASK 248555163Sshin RTFLAG("m", RTF_MASK); 248655163Sshin#endif 248755163Sshin RTFLAG("C", RTF_CLONING); 248878064Sume#ifdef RTF_CLONED 248978064Sume RTFLAG("c", RTF_CLONED); 249078064Sume#endif 249178064Sume#ifdef RTF_PRCLONING 249278064Sume RTFLAG("c", RTF_PRCLONING); 249378064Sume#endif 249478064Sume#ifdef RTF_WASCLONED 249578064Sume RTFLAG("W", RTF_WASCLONED); 249678064Sume#endif 249755163Sshin RTFLAG("X", RTF_XRESOLVE); 249855163Sshin RTFLAG("L", RTF_LLINFO); 249955163Sshin RTFLAG("S", RTF_STATIC); 250055163Sshin RTFLAG("B", RTF_BLACKHOLE); 250178064Sume#ifdef RTF_PROTO3 250278064Sume RTFLAG("3", RTF_PROTO3); 250378064Sume#endif 250455163Sshin RTFLAG("2", RTF_PROTO2); 250555163Sshin RTFLAG("1", RTF_PROTO1); 250678064Sume#ifdef RTF_BROADCAST 250778064Sume RTFLAG("b", RTF_BROADCAST); 250878064Sume#endif 250978064Sume#ifdef RTF_DEFAULT 251078064Sume RTFLAG("d", RTF_DEFAULT); 251178064Sume#endif 251278064Sume#ifdef RTF_ISAROUTER 251378064Sume RTFLAG("r", RTF_ISAROUTER); 251478064Sume#endif 251578064Sume#ifdef RTF_TUNNEL 251678064Sume RTFLAG("T", RTF_TUNNEL); 251778064Sume#endif 251878064Sume#ifdef RTF_AUTH 251978064Sume RTFLAG("A", RTF_AUTH); 252078064Sume#endif 252178064Sume#ifdef RTF_CRYPT 252278064Sume RTFLAG("E", RTF_CRYPT); 252378064Sume#endif 252455163Sshin#undef RTFLAG 252555163Sshin return buf; 252655163Sshin} 252755163Sshin 252855163Sshinconst char * 252955163Sshinifflags(flags) 253055163Sshin int flags; 253155163Sshin{ 253255163Sshin static char buf[BUFSIZ]; 253355163Sshin 253478064Sume strlcpy(buf, "", sizeof(buf)); 253562607Sitojun#define IFFLAG(s, f) \ 253662607Sitojundo { \ 2537119040Sume if (flags & (f)) { \ 253862607Sitojun if (buf[0]) \ 253978064Sume strlcat(buf, ",", sizeof(buf)); \ 2540119040Sume strlcat(buf, (s), sizeof(buf)); \ 254162607Sitojun } \ 254262607Sitojun} while (0) 254355163Sshin IFFLAG("UP", IFF_UP); 254455163Sshin IFFLAG("BROADCAST", IFF_BROADCAST); 254555163Sshin IFFLAG("DEBUG", IFF_DEBUG); 254655163Sshin IFFLAG("LOOPBACK", IFF_LOOPBACK); 254755163Sshin IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 254855163Sshin#ifdef IFF_NOTRAILERS 254955163Sshin IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 255055163Sshin#endif 255178064Sume#ifdef IFF_SMART 255278064Sume IFFLAG("SMART", IFF_SMART); 255378064Sume#endif 255455163Sshin IFFLAG("RUNNING", IFF_RUNNING); 255555163Sshin IFFLAG("NOARP", IFF_NOARP); 255655163Sshin IFFLAG("PROMISC", IFF_PROMISC); 255755163Sshin IFFLAG("ALLMULTI", IFF_ALLMULTI); 255855163Sshin IFFLAG("OACTIVE", IFF_OACTIVE); 255955163Sshin IFFLAG("SIMPLEX", IFF_SIMPLEX); 256055163Sshin IFFLAG("LINK0", IFF_LINK0); 256155163Sshin IFFLAG("LINK1", IFF_LINK1); 256255163Sshin IFFLAG("LINK2", IFF_LINK2); 256355163Sshin IFFLAG("MULTICAST", IFF_MULTICAST); 256455163Sshin#undef IFFLAG 256555163Sshin return buf; 256655163Sshin} 256755163Sshin 256855163Sshinvoid 256955163Sshinkrtread(again) 257055163Sshin int again; 257155163Sshin{ 257255163Sshin int mib[6]; 257355163Sshin size_t msize; 257455163Sshin char *buf, *p, *lim; 257555163Sshin struct rt_msghdr *rtm; 257655163Sshin int retry; 257755163Sshin const char *errmsg; 257855163Sshin 257955163Sshin retry = 0; 258055163Sshin buf = NULL; 258155163Sshin mib[0] = CTL_NET; 258255163Sshin mib[1] = PF_ROUTE; 258355163Sshin mib[2] = 0; 258455163Sshin mib[3] = AF_INET6; /* Address family */ 258555163Sshin mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 258655163Sshin mib[5] = 0; /* No flags */ 258755163Sshin do { 258855163Sshin retry++; 258955163Sshin errmsg = NULL; 259055163Sshin if (buf) 259155163Sshin free(buf); 259255163Sshin if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) { 259355163Sshin errmsg = "sysctl estimate"; 259455163Sshin continue; 259555163Sshin } 259655163Sshin if ((buf = malloc(msize)) == NULL) { 259755163Sshin errmsg = "malloc"; 259855163Sshin continue; 259955163Sshin } 260055163Sshin if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) { 260155163Sshin errmsg = "sysctl NET_RT_DUMP"; 260255163Sshin continue; 260355163Sshin } 260455163Sshin } while (retry < 5 && errmsg != NULL); 260578064Sume if (errmsg) { 260669279Sume fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 260769279Sume (u_long)msize); 260878064Sume /*NOTREACHED*/ 260978064Sume } else if (1 < retry) 261055163Sshin syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 261155163Sshin 261255163Sshin lim = buf + msize; 261355163Sshin for (p = buf; p < lim; p += rtm->rtm_msglen) { 261455163Sshin rtm = (struct rt_msghdr *)p; 261555163Sshin rt_entry(rtm, again); 261655163Sshin } 261755163Sshin free(buf); 261855163Sshin} 261955163Sshin 262055163Sshinvoid 262155163Sshinrt_entry(rtm, again) 262255163Sshin struct rt_msghdr *rtm; 262355163Sshin int again; 262455163Sshin{ 262555163Sshin struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 262655163Sshin struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 262755163Sshin char *rtmp, *ifname = NULL; 262878064Sume struct riprt *rrt, *orrt; 262955163Sshin struct netinfo6 *np; 263055163Sshin int s; 263155163Sshin 263255163Sshin sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 263355163Sshin if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 263462607Sitojun (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) { 263555163Sshin return; /* not interested in the link route */ 263662607Sitojun } 263769279Sume /* do not look at cloned routes */ 263869279Sume#ifdef RTF_WASCLONED 263969279Sume if (rtm->rtm_flags & RTF_WASCLONED) 264069279Sume return; 264169279Sume#endif 264269279Sume#ifdef RTF_CLONED 264369279Sume if (rtm->rtm_flags & RTF_CLONED) 264469279Sume return; 264569279Sume#endif 264669279Sume /* 264769279Sume * do not look at dynamic routes. 264869279Sume * netbsd/openbsd cloned routes have UGHD. 264969279Sume */ 265069279Sume if (rtm->rtm_flags & RTF_DYNAMIC) 265169279Sume return; 265255163Sshin rtmp = (char *)(rtm + 1); 265355163Sshin /* Destination */ 265455163Sshin if ((rtm->rtm_addrs & RTA_DST) == 0) 265555163Sshin return; /* ignore routes without destination address */ 265655163Sshin sin6_dst = (struct sockaddr_in6 *)rtmp; 265764631Sitojun rtmp += ROUNDUP(sin6_dst->sin6_len); 265855163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 265955163Sshin sin6_gw = (struct sockaddr_in6 *)rtmp; 266055163Sshin rtmp += ROUNDUP(sin6_gw->sin6_len); 266155163Sshin } 266255163Sshin if (rtm->rtm_addrs & RTA_NETMASK) { 266355163Sshin sin6_mask = (struct sockaddr_in6 *)rtmp; 266455163Sshin rtmp += ROUNDUP(sin6_mask->sin6_len); 266555163Sshin } 266655163Sshin if (rtm->rtm_addrs & RTA_GENMASK) { 266755163Sshin sin6_genmask = (struct sockaddr_in6 *)rtmp; 266855163Sshin rtmp += ROUNDUP(sin6_genmask->sin6_len); 266955163Sshin } 267055163Sshin if (rtm->rtm_addrs & RTA_IFP) { 267155163Sshin sin6_ifp = (struct sockaddr_in6 *)rtmp; 267255163Sshin rtmp += ROUNDUP(sin6_ifp->sin6_len); 267355163Sshin } 267455163Sshin 267555163Sshin /* Destination */ 267655163Sshin if (sin6_dst->sin6_family != AF_INET6) 267755163Sshin return; 267855163Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 267955163Sshin return; /* Link-local */ 268055163Sshin if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 268155163Sshin return; /* Loopback */ 268255163Sshin if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 268355163Sshin return; 268455163Sshin 268578064Sume if ((rrt = MALLOC(struct riprt)) == NULL) { 268655163Sshin fatal("malloc: struct riprt"); 268778064Sume /*NOTREACHED*/ 268878064Sume } 268962607Sitojun memset(rrt, 0, sizeof(*rrt)); 269055163Sshin np = &rrt->rrt_info; 269155163Sshin rrt->rrt_same = NULL; 269255163Sshin rrt->rrt_t = time(NULL); 269355163Sshin if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 269455163Sshin rrt->rrt_t = 0; /* Don't age static routes */ 2695122677Sume if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) 2696122677Sume rrt->rrt_t = 0; /* Don't age non-gateway host routes */ 269755163Sshin np->rip6_tag = 0; 269855163Sshin np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 269955163Sshin if (np->rip6_metric < 1) 270055163Sshin np->rip6_metric = 1; 270155163Sshin rrt->rrt_flags = rtm->rtm_flags; 270255163Sshin np->rip6_dest = sin6_dst->sin6_addr; 270355163Sshin 270455163Sshin /* Mask or plen */ 270555163Sshin if (rtm->rtm_flags & RTF_HOST) 270655163Sshin np->rip6_plen = 128; /* Host route */ 270778064Sume else if (sin6_mask) 270878064Sume np->rip6_plen = sin6mask2len(sin6_mask); 270978064Sume else 271055163Sshin np->rip6_plen = 0; 271155163Sshin 271278064Sume orrt = rtsearch(np, NULL); 271378064Sume if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 271455163Sshin /* Already found */ 271555163Sshin if (!again) { 271655163Sshin trace(1, "route: %s/%d flags %s: already registered\n", 271755163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, 271855163Sshin rtflags(rtm)); 271955163Sshin } 272055163Sshin free(rrt); 272155163Sshin return; 272255163Sshin } 272355163Sshin /* Gateway */ 272455163Sshin if (!sin6_gw) 272555163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 272655163Sshin else { 272755163Sshin if (sin6_gw->sin6_family == AF_INET6) 272855163Sshin rrt->rrt_gw = sin6_gw->sin6_addr; 272955163Sshin else if (sin6_gw->sin6_family == AF_LINK) { 273055163Sshin /* XXX in case ppp link? */ 273155163Sshin rrt->rrt_gw = in6addr_loopback; 273255163Sshin } else 273355163Sshin memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 273455163Sshin } 273555163Sshin trace(1, "route: %s/%d flags %s", 273655163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 273755163Sshin trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 273855163Sshin 273955163Sshin /* Interface */ 274055163Sshin s = rtm->rtm_index; 274155163Sshin if (s < nindex2ifc && index2ifc[s]) 274255163Sshin ifname = index2ifc[s]->ifc_name; 274358070Sshin else { 274458070Sshin trace(1, " not configured\n"); 274562607Sitojun free(rrt); 274658070Sshin return; 274758070Sshin } 274862607Sitojun trace(1, " if %s sock %d", ifname, s); 274955163Sshin rrt->rrt_index = s; 275055163Sshin 275162607Sitojun trace(1, "\n"); 275262607Sitojun 275355163Sshin /* Check gateway */ 275455163Sshin if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 2755122677Sume !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) && 2756122677Sume (rrt->rrt_flags & RTF_LOCAL) == 0) { 275755163Sshin trace(0, "***** Gateway %s is not a link-local address.\n", 275855163Sshin inet6_n2p(&rrt->rrt_gw)); 275955163Sshin trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 276062607Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 276162607Sitojun rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 276255163Sshin } 276355163Sshin 276455163Sshin /* Put it to the route list */ 276578064Sume if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 276678064Sume /* replace route list */ 276778064Sume rrt->rrt_next = orrt->rrt_next; 276878064Sume *orrt = *rrt; 276978064Sume trace(1, "route: %s/%d flags %s: replace new route\n", 277078064Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, 277178064Sume rtflags(rtm)); 277278064Sume free(rrt); 277378064Sume } else { 277478064Sume rrt->rrt_next = riprt; 277578064Sume riprt = rrt; 277678064Sume } 277755163Sshin} 277855163Sshin 277955163Sshinint 278055163Sshinaddroute(rrt, gw, ifcp) 278155163Sshin struct riprt *rrt; 278255163Sshin const struct in6_addr *gw; 278355163Sshin struct ifc *ifcp; 278455163Sshin{ 278555163Sshin struct netinfo6 *np; 278655163Sshin u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 278755163Sshin struct rt_msghdr *rtm; 2788119031Sume struct sockaddr_in6 *sin6; 278955163Sshin int len; 279055163Sshin 279155163Sshin np = &rrt->rrt_info; 279278064Sume inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 279355163Sshin inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 279455163Sshin tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 279555163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 279655163Sshin np->rip6_metric - 1, buf2); 279755163Sshin if (rtlog) 279855163Sshin fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 279955163Sshin inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 280055163Sshin np->rip6_metric - 1, buf2); 280155163Sshin if (nflag) 280255163Sshin return 0; 280355163Sshin 280455163Sshin memset(buf, 0, sizeof(buf)); 280555163Sshin rtm = (struct rt_msghdr *)buf; 280655163Sshin rtm->rtm_type = RTM_ADD; 280755163Sshin rtm->rtm_version = RTM_VERSION; 280855163Sshin rtm->rtm_seq = ++seq; 280955163Sshin rtm->rtm_pid = pid; 281062607Sitojun rtm->rtm_flags = rrt->rrt_flags; 281155163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 281255163Sshin rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 281355163Sshin rtm->rtm_inits = RTV_HOPCOUNT; 2814119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 281555163Sshin /* Destination */ 2816119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2817119031Sume sin6->sin6_family = AF_INET6; 2818119031Sume sin6->sin6_addr = np->rip6_dest; 2819119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 282055163Sshin /* Gateway */ 2821119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2822119031Sume sin6->sin6_family = AF_INET6; 2823119031Sume sin6->sin6_addr = *gw; 2824119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 282555163Sshin /* Netmask */ 2826119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2827119031Sume sin6->sin6_family = AF_INET6; 2828119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2829119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 283055163Sshin 2831119031Sume len = (char *)sin6 - (char *)buf; 283255163Sshin rtm->rtm_msglen = len; 283355163Sshin if (write(rtsock, buf, len) > 0) 283455163Sshin return 0; 283555163Sshin 283655163Sshin if (errno == EEXIST) { 283755163Sshin trace(0, "ADD: Route already exists %s/%d gw %s\n", 2838119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 283955163Sshin if (rtlog) 284055163Sshin fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2841119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 284255163Sshin } else { 284355163Sshin trace(0, "Can not write to rtsock (addroute): %s\n", 2844119035Sume strerror(errno)); 284555163Sshin if (rtlog) 284655163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2847119035Sume strerror(errno)); 284855163Sshin } 284955163Sshin return -1; 285055163Sshin} 285155163Sshin 285255163Sshinint 285355163Sshindelroute(np, gw) 285455163Sshin struct netinfo6 *np; 285555163Sshin struct in6_addr *gw; 285655163Sshin{ 285755163Sshin u_char buf[BUFSIZ], buf2[BUFSIZ]; 285855163Sshin struct rt_msghdr *rtm; 2859119031Sume struct sockaddr_in6 *sin6; 286055163Sshin int len; 286155163Sshin 286255163Sshin inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 286355163Sshin tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 286455163Sshin np->rip6_plen, buf2); 286555163Sshin if (rtlog) 286655163Sshin fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 286755163Sshin hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 286855163Sshin if (nflag) 286955163Sshin return 0; 287055163Sshin 287155163Sshin memset(buf, 0, sizeof(buf)); 287255163Sshin rtm = (struct rt_msghdr *)buf; 287355163Sshin rtm->rtm_type = RTM_DELETE; 287455163Sshin rtm->rtm_version = RTM_VERSION; 287555163Sshin rtm->rtm_seq = ++seq; 287655163Sshin rtm->rtm_pid = pid; 287755163Sshin rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 287878064Sume if (np->rip6_plen == sizeof(struct in6_addr) * 8) 287978064Sume rtm->rtm_flags |= RTF_HOST; 288055163Sshin rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2881119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 288255163Sshin /* Destination */ 2883119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2884119031Sume sin6->sin6_family = AF_INET6; 2885119031Sume sin6->sin6_addr = np->rip6_dest; 2886119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 288755163Sshin /* Gateway */ 2888119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2889119031Sume sin6->sin6_family = AF_INET6; 2890119031Sume sin6->sin6_addr = *gw; 2891119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 289255163Sshin /* Netmask */ 2893119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2894119031Sume sin6->sin6_family = AF_INET6; 2895119031Sume sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2896119031Sume sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 289755163Sshin 2898119031Sume len = (char *)sin6 - (char *)buf; 289955163Sshin rtm->rtm_msglen = len; 290055163Sshin if (write(rtsock, buf, len) >= 0) 290155163Sshin return 0; 290255163Sshin 290355163Sshin if (errno == ESRCH) { 290455163Sshin trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2905119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 290655163Sshin if (rtlog) 290755163Sshin fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2908119035Sume inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 290955163Sshin } else { 291055163Sshin trace(0, "Can not write to rtsock (delroute): %s\n", 2911119035Sume strerror(errno)); 291255163Sshin if (rtlog) 291355163Sshin fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2914119035Sume strerror(errno)); 291555163Sshin } 291655163Sshin return -1; 291755163Sshin} 291855163Sshin 291955163Sshinstruct in6_addr * 292055163Sshingetroute(np, gw) 292155163Sshin struct netinfo6 *np; 292255163Sshin struct in6_addr *gw; 292355163Sshin{ 292455163Sshin u_char buf[BUFSIZ]; 2925119085Sume int myseq; 292655163Sshin int len; 292755163Sshin struct rt_msghdr *rtm; 2928119031Sume struct sockaddr_in6 *sin6; 292955163Sshin 293055163Sshin rtm = (struct rt_msghdr *)buf; 293155163Sshin len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 293255163Sshin memset(rtm, 0, len); 293355163Sshin rtm->rtm_type = RTM_GET; 293455163Sshin rtm->rtm_version = RTM_VERSION; 293555163Sshin myseq = ++seq; 293655163Sshin rtm->rtm_seq = myseq; 293755163Sshin rtm->rtm_addrs = RTA_DST; 293855163Sshin rtm->rtm_msglen = len; 2939119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 2940119031Sume sin6->sin6_len = sizeof(struct sockaddr_in6); 2941119031Sume sin6->sin6_family = AF_INET6; 2942119031Sume sin6->sin6_addr = np->rip6_dest; 294355163Sshin if (write(rtsock, buf, len) < 0) { 294455163Sshin if (errno == ESRCH) /* No such route found */ 294555163Sshin return NULL; 294655163Sshin perror("write to rtsock"); 294778064Sume exit(1); 294855163Sshin } 294955163Sshin do { 295055163Sshin if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 295155163Sshin perror("read from rtsock"); 295278064Sume exit(1); 295355163Sshin } 295455163Sshin rtm = (struct rt_msghdr *)buf; 295555163Sshin } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid); 2956119031Sume sin6 = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)]; 295755163Sshin if (rtm->rtm_addrs & RTA_DST) { 2958119031Sume sin6 = (struct sockaddr_in6 *) 2959119031Sume ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 296055163Sshin } 296155163Sshin if (rtm->rtm_addrs & RTA_GATEWAY) { 2962119031Sume *gw = sin6->sin6_addr; 296355163Sshin return gw; 296455163Sshin } 296555163Sshin return NULL; 296655163Sshin} 296755163Sshin 296855163Sshinconst char * 296955163Sshininet6_n2p(p) 297055163Sshin const struct in6_addr *p; 297155163Sshin{ 297255163Sshin static char buf[BUFSIZ]; 297355163Sshin 297478064Sume return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 297555163Sshin} 297655163Sshin 297755163Sshinvoid 297855163Sshinifrtdump(sig) 297955163Sshin int sig; 298055163Sshin{ 298155163Sshin 298255163Sshin ifdump(sig); 298355163Sshin rtdump(sig); 298455163Sshin} 298555163Sshin 298655163Sshinvoid 298755163Sshinifdump(sig) 298855163Sshin int sig; 298955163Sshin{ 299055163Sshin struct ifc *ifcp; 299155163Sshin FILE *dump; 299255163Sshin int i; 299355163Sshin 299455163Sshin if (sig == 0) 299555163Sshin dump = stderr; 299655163Sshin else 299755163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 299855163Sshin dump = stderr; 299955163Sshin 300055163Sshin fprintf(dump, "%s: Interface Table Dump\n", hms()); 300155163Sshin fprintf(dump, " Number of interfaces: %d\n", nifc); 300255163Sshin for (i = 0; i < 2; i++) { 300355163Sshin fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : ""); 300455163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 300555163Sshin if (i == 0) { 300655163Sshin if ((ifcp->ifc_flags & IFF_UP) == 0) 300755163Sshin continue; 300855163Sshin if (iff_find(ifcp, 'N') != NULL) 300955163Sshin continue; 301055163Sshin } else { 301155163Sshin if (ifcp->ifc_flags & IFF_UP) 301255163Sshin continue; 301355163Sshin } 301455163Sshin ifdump0(dump, ifcp); 301555163Sshin } 301655163Sshin } 301755163Sshin fprintf(dump, "\n"); 301855163Sshin if (dump != stderr) 301955163Sshin fclose(dump); 302055163Sshin} 302155163Sshin 302255163Sshinvoid 302355163Sshinifdump0(dump, ifcp) 302455163Sshin FILE *dump; 302555163Sshin const struct ifc *ifcp; 302655163Sshin{ 302755163Sshin struct ifac *ifa; 302855163Sshin struct iff *iffp; 302955163Sshin char buf[BUFSIZ]; 303055163Sshin const char *ft; 303155163Sshin int addr; 303255163Sshin 303355163Sshin fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 303455163Sshin ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 303555163Sshin inet6_n2p(&ifcp->ifc_mylladdr), 303655163Sshin ifcp->ifc_mtu, ifcp->ifc_metric); 303755163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 303855163Sshin if (ifcp->ifc_flags & IFF_POINTOPOINT) { 303955163Sshin inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, 304055163Sshin buf, sizeof(buf)); 304155163Sshin fprintf(dump, "\t%s/%d -- %s\n", 304255163Sshin inet6_n2p(&ifa->ifa_addr), 304355163Sshin ifa->ifa_plen, buf); 304455163Sshin } else { 304555163Sshin fprintf(dump, "\t%s/%d\n", 304655163Sshin inet6_n2p(&ifa->ifa_addr), 304755163Sshin ifa->ifa_plen); 304855163Sshin } 304955163Sshin } 305055163Sshin if (ifcp->ifc_filter) { 305155163Sshin fprintf(dump, "\tFilter:"); 305255163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 305355163Sshin addr = 0; 305455163Sshin switch (iffp->iff_type) { 305555163Sshin case 'A': 305655163Sshin ft = "Aggregate"; addr++; break; 305755163Sshin case 'N': 305878064Sume ft = "No-use"; break; 305955163Sshin case 'O': 306055163Sshin ft = "Advertise-only"; addr++; break; 306155163Sshin case 'T': 306255163Sshin ft = "Default-only"; break; 306355163Sshin case 'L': 306455163Sshin ft = "Listen-only"; addr++; break; 306555163Sshin default: 306655163Sshin snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 306755163Sshin ft = buf; 306855163Sshin addr++; 306955163Sshin break; 307055163Sshin } 307155163Sshin fprintf(dump, " %s", ft); 307255163Sshin if (addr) { 307355163Sshin fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 307455163Sshin iffp->iff_plen); 307555163Sshin } 307655163Sshin } 307755163Sshin fprintf(dump, "\n"); 307855163Sshin } 307955163Sshin} 308055163Sshin 308155163Sshinvoid 308255163Sshinrtdump(sig) 308355163Sshin int sig; 308455163Sshin{ 308555163Sshin struct riprt *rrt; 308655163Sshin char buf[BUFSIZ]; 308755163Sshin FILE *dump; 308855163Sshin time_t t, age; 308955163Sshin 309055163Sshin if (sig == 0) 309155163Sshin dump = stderr; 309255163Sshin else 309355163Sshin if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 309455163Sshin dump = stderr; 309555163Sshin 309655163Sshin t = time(NULL); 309755163Sshin fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 309855163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 309955163Sshin if (rrt->rrt_t == 0) 310055163Sshin age = 0; 310155163Sshin else 310255163Sshin age = t - rrt->rrt_t; 310355163Sshin inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 310455163Sshin buf, sizeof(buf)); 310555163Sshin fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 310655163Sshin buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 310755163Sshin index2ifc[rrt->rrt_index]->ifc_name, 310855163Sshin inet6_n2p(&rrt->rrt_gw), 310955163Sshin rrt->rrt_info.rip6_metric, (long)age); 311055163Sshin if (rrt->rrt_info.rip6_tag) { 311155163Sshin fprintf(dump, " tag(0x%04x)", 311255163Sshin ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 311355163Sshin } 311462607Sitojun if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 311555163Sshin fprintf(dump, " NOT-LL"); 311662607Sitojun if (rrt->rrt_rflags & RRTF_NOADVERTISE) 311755163Sshin fprintf(dump, " NO-ADV"); 311855163Sshin fprintf(dump, "\n"); 311955163Sshin } 312055163Sshin fprintf(dump, "\n"); 312155163Sshin if (dump != stderr) 312255163Sshin fclose(dump); 312355163Sshin} 312455163Sshin 312555163Sshin/* 312655163Sshin * Parse the -A (and -O) options and put corresponding filter object to the 312778064Sume * specified interface structures. Each of the -A/O option has the following 312855163Sshin * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 312955163Sshin * -O 5f09:c400::/32,ef0,ef1 (only when match) 313055163Sshin */ 313155163Sshinvoid 313255163Sshinfilterconfig() 313355163Sshin{ 313455163Sshin int i; 3135119083Sume char *p, *ap, *iflp, *ifname, *ep; 313678064Sume struct iff ftmp, *iff_obj; 313778064Sume struct ifc *ifcp; 313878064Sume struct riprt *rrt; 313964631Sitojun#if 0 314078064Sume struct in6_addr gw; 314164631Sitojun#endif 3142119083Sume u_long plen; 314355163Sshin 314455163Sshin for (i = 0; i < nfilter; i++) { 314555163Sshin ap = filter[i]; 314655163Sshin iflp = NULL; 314755163Sshin ifcp = NULL; 314855163Sshin if (filtertype[i] == 'N' || filtertype[i] == 'T') { 314955163Sshin iflp = ap; 315055163Sshin goto ifonly; 315155163Sshin } 3152119038Sume if ((p = strchr(ap, ',')) != NULL) { 315355163Sshin *p++ = '\0'; 315455163Sshin iflp = p; 315555163Sshin } 3156119038Sume if ((p = strchr(ap, '/')) == NULL) { 315755163Sshin fatal("no prefixlen specified for '%s'", ap); 315878064Sume /*NOTREACHED*/ 315978064Sume } 316055163Sshin *p++ = '\0'; 316178064Sume if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) { 316255163Sshin fatal("invalid prefix specified for '%s'", ap); 316378064Sume /*NOTREACHED*/ 316478064Sume } 3165119083Sume errno = 0; 3166119083Sume ep = NULL; 3167119083Sume plen = strtoul(p, &ep, 10); 3168119083Sume if (errno || !*p || *ep || plen > sizeof(ftmp.iff_addr) * 8) { 3169119083Sume fatal("invalid prefix length specified for '%s'", ap); 3170119083Sume /*NOTREACHED*/ 3171119083Sume } 3172119083Sume ftmp.iff_plen = plen; 317355163Sshin ftmp.iff_next = NULL; 317455163Sshin applyplen(&ftmp.iff_addr, ftmp.iff_plen); 317555163Sshinifonly: 317655163Sshin ftmp.iff_type = filtertype[i]; 317778064Sume if (iflp == NULL || *iflp == '\0') { 317855163Sshin fatal("no interface specified for '%s'", ap); 317978064Sume /*NOTREACHED*/ 318078064Sume } 318155163Sshin /* parse the interface listing portion */ 318255163Sshin while (iflp) { 318355163Sshin ifname = iflp; 3184119038Sume if ((iflp = strchr(iflp, ',')) != NULL) 318555163Sshin *iflp++ = '\0'; 318655163Sshin ifcp = ifc_find(ifname); 318778064Sume if (ifcp == NULL) { 318855163Sshin fatal("no interface %s exists", ifname); 318978064Sume /*NOTREACHED*/ 319078064Sume } 319155163Sshin iff_obj = (struct iff *)malloc(sizeof(struct iff)); 319278064Sume if (iff_obj == NULL) { 319355163Sshin fatal("malloc of iff_obj"); 319478064Sume /*NOTREACHED*/ 319578064Sume } 319655163Sshin memcpy((void *)iff_obj, (void *)&ftmp, 319778064Sume sizeof(struct iff)); 319855163Sshin /* link it to the interface filter */ 319955163Sshin iff_obj->iff_next = ifcp->ifc_filter; 320055163Sshin ifcp->ifc_filter = iff_obj; 320155163Sshin } 320278064Sume 320378064Sume /* 320478064Sume * -A: aggregate configuration. 320578064Sume */ 320655163Sshin if (filtertype[i] != 'A') 320755163Sshin continue; 320855163Sshin /* put the aggregate to the kernel routing table */ 320955163Sshin rrt = (struct riprt *)malloc(sizeof(struct riprt)); 321078064Sume if (rrt == NULL) { 321155163Sshin fatal("malloc: rrt"); 321278064Sume /*NOTREACHED*/ 321378064Sume } 321455163Sshin memset(rrt, 0, sizeof(struct riprt)); 321555163Sshin rrt->rrt_info.rip6_dest = ftmp.iff_addr; 321655163Sshin rrt->rrt_info.rip6_plen = ftmp.iff_plen; 321755163Sshin rrt->rrt_info.rip6_metric = 1; 321855163Sshin rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 321955163Sshin rrt->rrt_gw = in6addr_loopback; 322062607Sitojun rrt->rrt_flags = RTF_UP | RTF_REJECT; 322162607Sitojun rrt->rrt_rflags = RRTF_AGGREGATE; 322255163Sshin rrt->rrt_t = 0; 3223119039Sume rrt->rrt_index = loopifcp->ifc_index; 322464631Sitojun#if 0 322564631Sitojun if (getroute(&rrt->rrt_info, &gw)) { 322664631Sitojun#if 0 322764631Sitojun /* 322864631Sitojun * When the address has already been registered in the 322964631Sitojun * kernel routing table, it should be removed 323064631Sitojun */ 323164631Sitojun delroute(&rrt->rrt_info, &gw); 323264631Sitojun#else 323378064Sume /* it is safer behavior */ 323464631Sitojun errno = EINVAL; 323564631Sitojun fatal("%s/%u already in routing table, " 323664631Sitojun "cannot aggregate", 323764631Sitojun inet6_n2p(&rrt->rrt_info.rip6_dest), 323864631Sitojun rrt->rrt_info.rip6_plen); 323978064Sume /*NOTREACHED*/ 324064631Sitojun#endif 324164631Sitojun } 324264631Sitojun#endif 324355163Sshin /* Put the route to the list */ 324455163Sshin rrt->rrt_next = riprt; 324555163Sshin riprt = rrt; 324655163Sshin trace(1, "Aggregate: %s/%d for %s\n", 324755163Sshin inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, 324855163Sshin ifcp->ifc_name); 324955163Sshin /* Add this route to the kernel */ 325055163Sshin if (nflag) /* do not modify kernel routing table */ 325155163Sshin continue; 325255163Sshin addroute(rrt, &in6addr_loopback, loopifcp); 325355163Sshin } 325455163Sshin} 325555163Sshin 325655163Sshin/***************** utility functions *****************/ 325755163Sshin 325855163Sshin/* 325955163Sshin * Returns a pointer to ifac whose address and prefix length matches 326055163Sshin * with the address and prefix length specified in the arguments. 326155163Sshin */ 326255163Sshinstruct ifac * 326355163Sshinifa_match(ifcp, ia, plen) 326455163Sshin const struct ifc *ifcp; 326555163Sshin const struct in6_addr *ia; 326655163Sshin int plen; 326755163Sshin{ 326855163Sshin struct ifac *ifa; 326955163Sshin 327055163Sshin for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) { 327155163Sshin if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) && 327255163Sshin ifa->ifa_plen == plen) 327355163Sshin break; 327455163Sshin } 327555163Sshin return ifa; 327655163Sshin} 327755163Sshin 327855163Sshin/* 327955163Sshin * Return a pointer to riprt structure whose address and prefix length 328055163Sshin * matches with the address and prefix length found in the argument. 328178064Sume * Note: This is not a rtalloc(). Therefore exact match is necessary. 328255163Sshin */ 328355163Sshinstruct riprt * 328478064Sumertsearch(np, prev_rrt) 328555163Sshin struct netinfo6 *np; 328678064Sume struct riprt **prev_rrt; 328755163Sshin{ 328855163Sshin struct riprt *rrt; 328955163Sshin 329078064Sume if (prev_rrt) 329178064Sume *prev_rrt = NULL; 329255163Sshin for (rrt = riprt; rrt; rrt = rrt->rrt_next) { 329355163Sshin if (rrt->rrt_info.rip6_plen == np->rip6_plen && 329455163Sshin IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 329555163Sshin &np->rip6_dest)) 329655163Sshin return rrt; 329778064Sume if (prev_rrt) 329878064Sume *prev_rrt = rrt; 329955163Sshin } 330078064Sume if (prev_rrt) 330178064Sume *prev_rrt = NULL; 330255163Sshin return 0; 330355163Sshin} 330455163Sshin 330555163Sshinint 330678064Sumesin6mask2len(sin6) 330778064Sume const struct sockaddr_in6 *sin6; 330878064Sume{ 330978064Sume 331078064Sume return mask2len(&sin6->sin6_addr, 331178064Sume sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 331278064Sume} 331378064Sume 331478064Sumeint 331555163Sshinmask2len(addr, lenlim) 331655163Sshin const struct in6_addr *addr; 331755163Sshin int lenlim; 331855163Sshin{ 331955163Sshin int i = 0, j; 332078064Sume const u_char *p = (const u_char *)addr; 332162607Sitojun 332255163Sshin for (j = 0; j < lenlim; j++, p++) { 332355163Sshin if (*p != 0xff) 332455163Sshin break; 332555163Sshin i += 8; 332655163Sshin } 332755163Sshin if (j < lenlim) { 332855163Sshin switch (*p) { 332962607Sitojun#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 333062607Sitojun MASKLEN(0xfe, 7); break; 333162607Sitojun MASKLEN(0xfc, 6); break; 333262607Sitojun MASKLEN(0xf8, 5); break; 333362607Sitojun MASKLEN(0xf0, 4); break; 333462607Sitojun MASKLEN(0xe0, 3); break; 333562607Sitojun MASKLEN(0xc0, 2); break; 333662607Sitojun MASKLEN(0x80, 1); break; 333755163Sshin#undef MASKLEN 333855163Sshin } 333955163Sshin } 334055163Sshin return i; 334155163Sshin} 334255163Sshin 334355163Sshinvoid 334455163Sshinapplymask(addr, mask) 334555163Sshin struct in6_addr *addr, *mask; 334655163Sshin{ 334755163Sshin int i; 334855163Sshin u_long *p, *q; 334955163Sshin 335055163Sshin p = (u_long *)addr; q = (u_long *)mask; 335155163Sshin for (i = 0; i < 4; i++) 335255163Sshin *p++ &= *q++; 335355163Sshin} 335455163Sshin 335555163Sshinstatic const u_char plent[8] = { 335655163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 335755163Sshin}; 335855163Sshin 335955163Sshinvoid 336055163Sshinapplyplen(ia, plen) 336155163Sshin struct in6_addr *ia; 336255163Sshin int plen; 336355163Sshin{ 336455163Sshin u_char *p; 336555163Sshin int i; 336655163Sshin 336755163Sshin p = ia->s6_addr; 336855163Sshin for (i = 0; i < 16; i++) { 336955163Sshin if (plen <= 0) 337055163Sshin *p = 0; 337155163Sshin else if (plen < 8) 337255163Sshin *p &= plent[plen]; 337355163Sshin p++, plen -= 8; 337455163Sshin } 337555163Sshin} 337655163Sshin 337755163Sshinstatic const int pl2m[9] = { 337855163Sshin 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 337955163Sshin}; 338055163Sshin 338155163Sshinstruct in6_addr * 338255163Sshinplen2mask(n) 338355163Sshin int n; 338455163Sshin{ 338555163Sshin static struct in6_addr ia; 338655163Sshin u_char *p; 338755163Sshin int i; 338855163Sshin 338955163Sshin memset(&ia, 0, sizeof(struct in6_addr)); 339055163Sshin p = (u_char *)&ia; 339155163Sshin for (i = 0; i < 16; i++, p++, n -= 8) { 339255163Sshin if (n >= 8) { 339355163Sshin *p = 0xff; 339455163Sshin continue; 339555163Sshin } 339655163Sshin *p = pl2m[n]; 339755163Sshin break; 339855163Sshin } 339955163Sshin return &ia; 340055163Sshin} 340155163Sshin 340255163Sshinchar * 340355163Sshinallocopy(p) 340455163Sshin char *p; 340555163Sshin{ 3406119033Sume int len = strlen(p) + 1; 3407119033Sume char *q = (char *)malloc(len); 340855163Sshin 3409119033Sume if (!q) { 3410119033Sume fatal("malloc"); 3411119033Sume /*NOTREACHED*/ 3412119033Sume } 3413119033Sume 3414119033Sume strlcpy(q, p, len); 341555163Sshin return q; 341655163Sshin} 341755163Sshin 341855163Sshinchar * 341955163Sshinhms() 342055163Sshin{ 342155163Sshin static char buf[BUFSIZ]; 342255163Sshin time_t t; 342355163Sshin struct tm *tm; 342455163Sshin 342555163Sshin t = time(NULL); 342678064Sume if ((tm = localtime(&t)) == 0) { 342755163Sshin fatal("localtime"); 342878064Sume /*NOTREACHED*/ 342978064Sume } 343078064Sume snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 343178064Sume tm->tm_sec); 343255163Sshin return buf; 343355163Sshin} 343455163Sshin 343555163Sshin#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 343655163Sshin 343755163Sshinint 343855163Sshinripinterval(timer) 343955163Sshin int timer; 344055163Sshin{ 344155163Sshin double r = rand(); 344255163Sshin 344355163Sshin interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 344455163Sshin nextalarm = time(NULL) + interval; 344555163Sshin return interval; 344655163Sshin} 344755163Sshin 344855163Sshintime_t 344955163Sshinripsuptrig() 345055163Sshin{ 345155163Sshin time_t t; 345255163Sshin 345355163Sshin double r = rand(); 345462607Sitojun t = (int)(RIP_TRIG_INT6_MIN + 345578064Sume (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 345655163Sshin sup_trig_update = time(NULL) + t; 345755163Sshin return t; 345855163Sshin} 345955163Sshin 346055163Sshinvoid 346155163Sshin#ifdef __STDC__ 346255163Sshinfatal(const char *fmt, ...) 346355163Sshin#else 346455163Sshinfatal(fmt, va_alist) 346555163Sshin char *fmt; 346655163Sshin va_dcl 346755163Sshin#endif 346855163Sshin{ 346955163Sshin va_list ap; 347055163Sshin char buf[1024]; 347155163Sshin 347255163Sshin#ifdef __STDC__ 347355163Sshin va_start(ap, fmt); 347455163Sshin#else 347555163Sshin va_start(ap); 347655163Sshin#endif 347755163Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 3478119043Sume va_end(ap); 347955163Sshin perror(buf); 3480119043Sume if (errno) 3481119043Sume syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 3482119043Sume else 3483119043Sume syslog(LOG_ERR, "%s", buf); 348478064Sume rtdexit(); 348555163Sshin} 348655163Sshin 348755163Sshinvoid 348855163Sshin#ifdef __STDC__ 348955163Sshintracet(int level, const char *fmt, ...) 349055163Sshin#else 349155163Sshintracet(level, fmt, va_alist) 349255163Sshin int level; 349355163Sshin char *fmt; 349455163Sshin va_dcl 349555163Sshin#endif 349655163Sshin{ 349755163Sshin va_list ap; 349855163Sshin 3499119043Sume if (level <= dflag) { 350055163Sshin#ifdef __STDC__ 3501119043Sume va_start(ap, fmt); 350255163Sshin#else 3503119043Sume va_start(ap); 350455163Sshin#endif 350555163Sshin fprintf(stderr, "%s: ", hms()); 350655163Sshin vfprintf(stderr, fmt, ap); 3507119043Sume va_end(ap); 350855163Sshin } 350955163Sshin if (dflag) { 3510119043Sume#ifdef __STDC__ 3511119043Sume va_start(ap, fmt); 3512119043Sume#else 3513119043Sume va_start(ap); 3514119043Sume#endif 351555163Sshin if (level > 0) 351655163Sshin vsyslog(LOG_DEBUG, fmt, ap); 351755163Sshin else 351855163Sshin vsyslog(LOG_WARNING, fmt, ap); 3519119043Sume va_end(ap); 352055163Sshin } 352155163Sshin} 352255163Sshin 352355163Sshinvoid 352455163Sshin#ifdef __STDC__ 352555163Sshintrace(int level, const char *fmt, ...) 352655163Sshin#else 352755163Sshintrace(level, fmt, va_alist) 352855163Sshin int level; 352955163Sshin char *fmt; 353055163Sshin va_dcl 353155163Sshin#endif 353255163Sshin{ 353355163Sshin va_list ap; 353455163Sshin 3535119043Sume if (level <= dflag) { 353655163Sshin#ifdef __STDC__ 3537119043Sume va_start(ap, fmt); 353855163Sshin#else 3539119043Sume va_start(ap); 354055163Sshin#endif 354155163Sshin vfprintf(stderr, fmt, ap); 3542119043Sume va_end(ap); 3543119043Sume } 354455163Sshin if (dflag) { 3545119043Sume#ifdef __STDC__ 3546119043Sume va_start(ap, fmt); 3547119043Sume#else 3548119043Sume va_start(ap); 3549119043Sume#endif 355055163Sshin if (level > 0) 355155163Sshin vsyslog(LOG_DEBUG, fmt, ap); 355255163Sshin else 355355163Sshin vsyslog(LOG_WARNING, fmt, ap); 3554119043Sume va_end(ap); 355555163Sshin } 355655163Sshin} 355755163Sshin 355855163Sshinunsigned int 355955163Sshinif_maxindex() 356055163Sshin{ 356155163Sshin struct if_nameindex *p, *p0; 356255163Sshin unsigned int max = 0; 356355163Sshin 356455163Sshin p0 = if_nameindex(); 356555163Sshin for (p = p0; p && p->if_index && p->if_name; p++) { 356655163Sshin if (max < p->if_index) 356755163Sshin max = p->if_index; 356855163Sshin } 356955163Sshin if_freenameindex(p0); 357055163Sshin return max; 357155163Sshin} 357255163Sshin 357355163Sshinstruct ifc * 357455163Sshinifc_find(name) 357555163Sshin char *name; 357655163Sshin{ 357755163Sshin struct ifc *ifcp; 357855163Sshin 357955163Sshin for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { 358055163Sshin if (strcmp(name, ifcp->ifc_name) == 0) 358155163Sshin return ifcp; 358255163Sshin } 358355163Sshin return (struct ifc *)NULL; 358455163Sshin} 358555163Sshin 358655163Sshinstruct iff * 358755163Sshiniff_find(ifcp, type) 358855163Sshin struct ifc *ifcp; 358955163Sshin int type; 359055163Sshin{ 359155163Sshin struct iff *iffp; 359255163Sshin 359355163Sshin for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { 359455163Sshin if (iffp->iff_type == type) 359555163Sshin return iffp; 359655163Sshin } 359755163Sshin return NULL; 359855163Sshin} 359955163Sshin 360055163Sshinvoid 360178064Sumesetindex2ifc(idx, ifcp) 360278064Sume int idx; 360355163Sshin struct ifc *ifcp; 360455163Sshin{ 3605122677Sume int n, nsize; 360662607Sitojun struct ifc **p; 360755163Sshin 360855163Sshin if (!index2ifc) { 360955163Sshin nindex2ifc = 5; /*initial guess*/ 361055163Sshin index2ifc = (struct ifc **) 361155163Sshin malloc(sizeof(*index2ifc) * nindex2ifc); 361278064Sume if (index2ifc == NULL) { 361355163Sshin fatal("malloc"); 361478064Sume /*NOTREACHED*/ 361578064Sume } 361655163Sshin memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 361755163Sshin } 361855163Sshin n = nindex2ifc; 3619122677Sume for (nsize = nindex2ifc; nsize <= idx; nsize *= 2) 3620122677Sume ; 3621122677Sume if (n != nsize) { 362262607Sitojun p = (struct ifc **)realloc(index2ifc, 3623122677Sume sizeof(*index2ifc) * nsize); 362478064Sume if (p == NULL) { 362555163Sshin fatal("realloc"); 362678064Sume /*NOTREACHED*/ 362778064Sume } 362878064Sume memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 362962607Sitojun index2ifc = p; 3630122677Sume nindex2ifc = nsize; 363155163Sshin } 363278064Sume index2ifc[idx] = ifcp; 363355163Sshin} 3634