1168404Spjd/* $KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $ */ 2168404Spjd 3168404Spjd/*- 4168404Spjd * SPDX-License-Identifier: BSD-3-Clause 5168404Spjd * 6168404Spjd * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7168404Spjd * All rights reserved. 8168404Spjd * 9168404Spjd * Redistribution and use in source and binary forms, with or without 10168404Spjd * modification, are permitted provided that the following conditions 11168404Spjd * are met: 12168404Spjd * 1. Redistributions of source code must retain the above copyright 13168404Spjd * notice, this list of conditions and the following disclaimer. 14168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 15168404Spjd * notice, this list of conditions and the following disclaimer in the 16168404Spjd * documentation and/or other materials provided with the distribution. 17168404Spjd * 3. Neither the name of the project nor the names of its contributors 18168404Spjd * may be used to endorse or promote products derived from this software 19168404Spjd * without specific prior written permission. 20168404Spjd * 21168404Spjd * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23219089Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24264670Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25268126Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26247265Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30251629Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31251629Sdelphij * SUCH DAMAGE. 32168404Spjd */ 33168404Spjd 34168404Spjd 35168404Spjd#include <sys/param.h> 36168404Spjd#include <sys/file.h> 37168404Spjd#include <sys/ioctl.h> 38168404Spjd#include <sys/queue.h> 39168404Spjd#include <sys/socket.h> 40168404Spjd#include <sys/sysctl.h> 41168404Spjd#include <sys/uio.h> 42168404Spjd#include <arpa/inet.h> 43168404Spjd#include <net/if.h> 44168404Spjd#include <net/route.h> 45168404Spjd#include <netinet/in.h> 46219089Spjd#include <netinet/in_var.h> 47168404Spjd#include <netinet/ip6.h> 48168404Spjd#include <netinet/udp.h> 49219089Spjd#include <err.h> 50168404Spjd#include <errno.h> 51168404Spjd#include <fnmatch.h> 52168404Spjd#include <ifaddrs.h> 53168404Spjd#include <netdb.h> 54168404Spjd#ifdef HAVE_POLL_H 55168404Spjd#include <poll.h> 56168404Spjd#endif 57168404Spjd#include <signal.h> 58168404Spjd#include <stdio.h> 59168404Spjd#include <stdarg.h> 60168404Spjd#include <stddef.h> 61168404Spjd#include <stdlib.h> 62185029Spjd#include <string.h> 63168404Spjd#include <syslog.h> 64185029Spjd#include <time.h> 65219089Spjd#include <unistd.h> 66219089Spjd 67248571Smm#include "route6d.h" 68248571Smm 69248571Smm#define MAXFILTER 40 70236884Smm#define RT_DUMP_MAXRETRY 15 71219089Spjd 72240868Spjd#ifdef DEBUG 73168404Spjd#define INIT_INTERVAL6 6 74219089Spjd#else 75219089Spjd#define INIT_INTERVAL6 10 /* Wait to submit an initial riprequest */ 76219089Spjd#endif 77219089Spjd 78219089Spjd/* alignment constraint for routing socket */ 79219089Spjd#define ROUNDUP(a) \ 80185029Spjd ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 81185029Spjd#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 82168404Spjd 83204073Spjdstruct ifc { /* Configuration of an interface */ 84204073Spjd TAILQ_ENTRY(ifc) ifc_next; 85204073Spjd 86204073Spjd char ifc_name[IFNAMSIZ]; /* if name */ 87267992Shselasky int ifc_index; /* if index */ 88204073Spjd int ifc_mtu; /* if mtu */ 89204073Spjd int ifc_metric; /* if metric */ 90251636Sdelphij u_int ifc_flags; /* flags */ 91251636Sdelphij short ifc_cflags; /* IFC_XXX */ 92251636Sdelphij struct in6_addr ifc_mylladdr; /* my link-local address */ 93251636Sdelphij struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ 94251636Sdelphij TAILQ_HEAD(, ifac) ifc_ifac_head; /* list of AF_INET6 addrs */ 95251636Sdelphij TAILQ_HEAD(, iff) ifc_iff_head; /* list of filters */ 96219089Spjd int ifc_joined; /* joined to ff02::9 */ 97258631Savg}; 98258631Savgstatic TAILQ_HEAD(, ifc) ifc_head = TAILQ_HEAD_INITIALIZER(ifc_head); 99258631Savg 100258631Savgstruct ifac { /* Address associated to an interface */ 101219089Spjd TAILQ_ENTRY(ifac) ifac_next; 102168712Spjd 103258631Savg struct ifc *ifac_ifc; /* back pointer */ 104258631Savg struct in6_addr ifac_addr; /* address */ 105258631Savg struct in6_addr ifac_raddr; /* remote address, valid in p2p */ 106209962Smm int ifac_scope_id; /* scope id */ 107258631Savg int ifac_plen; /* prefix length */ 108258631Savg}; 109209962Smm 110209962Smmstruct iff { /* Filters for an interface */ 111258631Savg TAILQ_ENTRY(iff) iff_next; 112211931Smm 113258631Savg int iff_type; 114209962Smm struct in6_addr iff_addr; 115209962Smm int iff_plen; 116209962Smm}; 117219089Spjd 118209962Smmstatic struct ifc **index2ifc; 119209962Smmstatic unsigned int nindex2ifc; 120211931Smmstatic struct ifc *loopifcp = NULL; /* pointing to loopback */ 121258631Savg#ifdef HAVE_POLL_H 122258631Savgstatic struct pollfd set[2]; 123258631Savg#else 124258631Savgstatic fd_set *sockvecp; /* vector to select() for receiving */ 125258631Savgstatic fd_set *recvecp; 126258631Savgstatic int fdmasks; 127258631Savgstatic int maxfd; /* maximum fd for select() */ 128258631Savg#endif 129258631Savgstatic int rtsock; /* the routing socket */ 130258631Savgstatic int ripsock; /* socket to send/receive RIP datagram */ 131258631Savg 132258631Savgstatic struct rip6 *ripbuf; /* packet buffer for sending */ 133258631Savg 134258631Savg/* 135258631Savg * Maintain the routes in a linked list. When the number of the routes 136211931Smm * grows, somebody would like to introduce a hash based or a radix tree 137211931Smm * based structure. I believe the number of routes handled by RIP is 138211931Smm * limited and I don't have to manage a complex data structure, however. 139258631Savg * 140264670Sdelphij * One of the major drawbacks of the linear linked list is the difficulty 141258631Savg * of representing the relationship between a couple of routes. This may 142258631Savg * be a significant problem when we have to support route aggregation with 143258631Savg * suppressing the specifics covered by the aggregate. 144258631Savg */ 145209962Smm 146209962Smmstruct riprt { 147248571Smm TAILQ_ENTRY(riprt) rrt_next; /* next destination */ 148248571Smm 149185029Spjd struct riprt *rrt_same; /* same destination - future use */ 150219089Spjd struct netinfo6 rrt_info; /* network info */ 151219089Spjd struct in6_addr rrt_gw; /* gateway */ 152219089Spjd u_long rrt_flags; /* kernel routing table flags */ 153219089Spjd u_long rrt_rflags; /* route6d routing table flags */ 154185029Spjd time_t rrt_t; /* when the route validated */ 155258632Savg int rrt_index; /* ifindex from which this route got */ 156219089Spjd}; 157219089Spjdstatic TAILQ_HEAD(, riprt) riprt_head = TAILQ_HEAD_INITIALIZER(riprt_head); 158219089Spjd 159219089Spjdstatic int dflag = 0; /* debug flag */ 160219089Spjdstatic int qflag = 0; /* quiet flag */ 161219089Spjdstatic int nflag = 0; /* don't update kernel routing table */ 162219089Spjdstatic int aflag = 0; /* age out even the statically defined routes */ 163219089Spjdstatic int hflag = 0; /* don't split horizon */ 164219089Spjdstatic int lflag = 0; /* exchange site local routes */ 165243503Smmstatic int Pflag = 0; /* don't age out routes with RTF_PROTO[123] */ 166219089Spjdstatic int Qflag = RTF_PROTO2; /* set RTF_PROTO[123] flag to routes by RIPng */ 167247265Smmstatic int sflag = 0; /* announce static routes w/ split horizon */ 168247265Smmstatic int Sflag = 0; /* announce static routes to every interface */ 169247265Smmstatic unsigned long routetag = 0; /* route tag attached on originating case */ 170247265Smm 171168404Spjdstatic char *filter[MAXFILTER]; 172219089Spjdstatic int filtertype[MAXFILTER]; 173219089Spjdstatic int nfilter = 0; 174219089Spjd 175219089Spjdstatic pid_t pid; 176219089Spjd 177219089Spjdstatic struct sockaddr_storage ripsin; 178168404Spjd 179185029Spjdstatic int interval = 1; 180185029Spjdstatic time_t nextalarm = 0; 181185029Spjd#if 0 182185029Spjdstatic time_t sup_trig_update = 0; 183185029Spjd#endif 184185029Spjd 185185029Spjdstatic FILE *rtlog = NULL; 186185029Spjd 187185029Spjdstatic int logopened = 0; 188185029Spjd 189185029Spjdstatic int seq = 0; 190185029Spjd 191185029Spjdstatic volatile sig_atomic_t seenalrm; 192185029Spjdstatic volatile sig_atomic_t seenquit; 193185029Spjdstatic volatile sig_atomic_t seenusr1; 194185029Spjd 195185029Spjd#define RRTF_AGGREGATE 0x08000000 196185029Spjd#define RRTF_NOADVERTISE 0x10000000 197185029Spjd#define RRTF_NH_NOT_LLADDR 0x20000000 198185029Spjd#define RRTF_SENDANYWAY 0x40000000 199185029Spjd#define RRTF_CHANGED 0x80000000 200185029Spjd 201185029Spjdstatic void sighandler(int); 202185029Spjdstatic void ripalarm(void); 203185029Spjdstatic void riprecv(void); 204185029Spjdstatic void ripsend(struct ifc *, struct sockaddr_in6 *, int); 205185029Spjdstatic int out_filter(struct riprt *, struct ifc *); 206185029Spjdstatic void init(void); 207185029Spjdstatic void ifconfig(void); 208185029Spjdstatic int ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); 209185029Spjdstatic void rtrecv(void); 210185029Spjdstatic int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *, 211236155Smm const struct sockaddr_in6 *); 212236884Smmstatic int rt_deladdr(struct ifc *, const struct sockaddr_in6 *, 213269118Sdelphij const struct sockaddr_in6 *); 214185029Spjdstatic void filterconfig(void); 215185029Spjdstatic int getifmtu(int); 216269118Sdelphijstatic const char *rttypes(struct rt_msghdr *); 217185029Spjdstatic const char *rtflags(struct rt_msghdr *); 218185029Spjdstatic const char *ifflags(int); 219185029Spjdstatic int ifrt(struct ifc *, int); 220236155Smmstatic void ifrt_p2p(struct ifc *, int); 221219089Spjdstatic void applyplen(struct in6_addr *, int); 222219089Spjdstatic void ifrtdump(int); 223209962Smmstatic void ifdump(int); 224209962Smmstatic void ifdump0(FILE *, const struct ifc *); 225219089Spjdstatic void ifremove(int); 226219089Spjdstatic void rtdump(int); 227219089Spjdstatic void rt_entry(struct rt_msghdr *, int); 228236155Smmstatic void rtdexit(void); 229269118Sdelphijstatic void riprequest(struct ifc *, struct netinfo6 *, int, 230269118Sdelphij struct sockaddr_in6 *); 231269118Sdelphijstatic void ripflush(struct ifc *, struct sockaddr_in6 *, int, struct netinfo6 *np); 232269118Sdelphijstatic void sendrequest(struct ifc *); 233219089Spjdstatic int sin6mask2len(const struct sockaddr_in6 *); 234219089Spjdstatic int mask2len(const struct in6_addr *, int); 235185029Spjdstatic int sendpacket(struct sockaddr_in6 *, int); 236219089Spjdstatic int addroute(struct riprt *, const struct in6_addr *, struct ifc *); 237209962Smmstatic int delroute(struct netinfo6 *, struct in6_addr *); 238185029Spjd#if 0 239219089Spjdstatic struct in6_addr *getroute(struct netinfo6 *, struct in6_addr *); 240219089Spjd#endif 241219089Spjdstatic void krtread(int); 242209962Smmstatic int tobeadv(struct riprt *, struct ifc *); 243236155Smmstatic char *allocopy(char *); 244209962Smmstatic char *hms(void); 245209962Smmstatic const char *inet6_n2p(const struct in6_addr *); 246209962Smmstatic struct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int); 247209962Smmstatic struct in6_addr *plen2mask(int); 248209962Smmstatic struct riprt *rtsearch(struct netinfo6 *); 249209962Smmstatic int ripinterval(int); 250209962Smm#if 0 251209962Smmstatic time_t ripsuptrig(void); 252209962Smm#endif 253236884Smmstatic void fatal(const char *, ...) 254236884Smm __attribute__((__format__(__printf__, 1, 2))); 255236884Smmstatic void trace(int, const char *, ...) 256236884Smm __attribute__((__format__(__printf__, 2, 3))); 257236884Smmstatic void tracet(int, const char *, ...) 258268079Sdelphij __attribute__((__format__(__printf__, 2, 3))); 259236884Smmstatic struct ifc *ifc_find(char *); 260268079Sdelphijstatic struct iff *iff_find(struct ifc *, int); 261236884Smmstatic void setindex2ifc(int, struct ifc *); 262236884Smm 263236884Smm#define MALLOC(type) ((type *)malloc(sizeof(type))) 264236884Smm 265268079Sdelphij#define IFIL_TYPE_ANY 0x0 266268079Sdelphij#define IFIL_TYPE_A 'A' 267268079Sdelphij#define IFIL_TYPE_N 'N' 268268079Sdelphij#define IFIL_TYPE_T 'T' 269268079Sdelphij#define IFIL_TYPE_O 'O' 270268079Sdelphij#define IFIL_TYPE_L 'L' 271268079Sdelphij 272268079Sdelphijint 273236884Smmmain(int argc, char *argv[]) 274236884Smm{ 275185029Spjd int ch; 276185029Spjd int error = 0; 277228103Smm unsigned long proto; 278228103Smm struct ifc *ifcp; 279228103Smm sigset_t mask, omask; 280228103Smm const char *pidfile = ROUTE6D_PID; 281228103Smm FILE *pidfh; 282185029Spjd char *progname; 283185029Spjd char *ep; 284185029Spjd 285185029Spjd progname = strrchr(*argv, '/'); 286185029Spjd if (progname) 287185029Spjd progname++; 288185029Spjd else 289185029Spjd progname = *argv; 290185029Spjd 291185029Spjd pid = getpid(); 292185029Spjd while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnp:P:Q:qsS")) != -1) { 293185029Spjd switch (ch) { 294185029Spjd case 'A': 295185029Spjd case 'N': 296185029Spjd case 'O': 297185029Spjd case 'T': 298185029Spjd case 'L': 299185029Spjd if (nfilter >= MAXFILTER) { 300185029Spjd fatal("Exceeds MAXFILTER"); 301185029Spjd /*NOTREACHED*/ 302185029Spjd } 303219089Spjd filtertype[nfilter] = ch; 304185029Spjd filter[nfilter++] = allocopy(optarg); 305185029Spjd break; 306185029Spjd case 't': 307185029Spjd ep = NULL; 308185029Spjd routetag = strtoul(optarg, &ep, 0); 309185029Spjd if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) { 310185029Spjd fatal("invalid route tag"); 311185029Spjd /*NOTREACHED*/ 312185029Spjd } 313185029Spjd break; 314185029Spjd case 'p': 315185029Spjd pidfile = optarg; 316185029Spjd break; 317185029Spjd case 'P': 318219089Spjd ep = NULL; 319185029Spjd proto = strtoul(optarg, &ep, 0); 320185029Spjd if (!ep || *ep != '\0' || 3 < proto) { 321185029Spjd fatal("invalid P flag"); 322185029Spjd /*NOTREACHED*/ 323185029Spjd } 324185029Spjd if (proto == 0) 325185029Spjd Pflag = 0; 326185029Spjd if (proto == 1) 327185029Spjd Pflag |= RTF_PROTO1; 328185029Spjd if (proto == 2) 329185029Spjd Pflag |= RTF_PROTO2; 330185029Spjd if (proto == 3) 331185029Spjd Pflag |= RTF_PROTO3; 332185029Spjd break; 333185029Spjd case 'Q': 334185029Spjd ep = NULL; 335185029Spjd proto = strtoul(optarg, &ep, 0); 336185029Spjd if (!ep || *ep != '\0' || 3 < proto) { 337185029Spjd fatal("invalid Q flag"); 338185029Spjd /*NOTREACHED*/ 339185029Spjd } 340185029Spjd if (proto == 0) 341185029Spjd Qflag = 0; 342185029Spjd if (proto == 1) 343185029Spjd Qflag |= RTF_PROTO1; 344185029Spjd if (proto == 2) 345185029Spjd Qflag |= RTF_PROTO2; 346185029Spjd if (proto == 3) 347185029Spjd Qflag |= RTF_PROTO3; 348185029Spjd break; 349248571Smm case 'R': 350185029Spjd if ((rtlog = fopen(optarg, "w")) == NULL) { 351185029Spjd fatal("Can not write to routelog"); 352248571Smm /*NOTREACHED*/ 353185029Spjd } 354185029Spjd break; 355185029Spjd#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0) 356185029Spjd FLAG('a', aflag, 1); break; 357185029Spjd FLAG('d', dflag, 1); break; 358185029Spjd FLAG('D', dflag, 2); break; 359185029Spjd FLAG('h', hflag, 1); break; 360185029Spjd FLAG('l', lflag, 1); break; 361248571Smm FLAG('n', nflag, 1); break; 362185029Spjd FLAG('q', qflag, 1); break; 363185029Spjd FLAG('s', sflag, 1); break; 364185029Spjd FLAG('S', Sflag, 1); break; 365185029Spjd#undef FLAG 366185029Spjd default: 367185029Spjd fatal("Invalid option specified, terminating"); 368185029Spjd /*NOTREACHED*/ 369185029Spjd } 370185029Spjd } 371185029Spjd argc -= optind; 372185029Spjd argv += optind; 373185029Spjd if (argc > 0) { 374185029Spjd fatal("bogus extra arguments"); 375185029Spjd /*NOTREACHED*/ 376185029Spjd } 377185029Spjd 378185029Spjd if (geteuid()) { 379185029Spjd nflag = 1; 380185029Spjd fprintf(stderr, "No kernel update is allowed\n"); 381185029Spjd } 382185029Spjd 383185029Spjd if (dflag == 0) { 384185029Spjd if (daemon(0, 0) < 0) { 385185029Spjd fatal("daemon"); 386185029Spjd /*NOTREACHED*/ 387185029Spjd } 388185029Spjd } 389185029Spjd 390185029Spjd openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 391185029Spjd logopened++; 392185029Spjd 393185029Spjd if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) 394185029Spjd fatal("malloc"); 395185029Spjd memset(ripbuf, 0, RIP6_MAXMTU); 396185029Spjd ripbuf->rip6_cmd = RIP6_RESPONSE; 397185029Spjd ripbuf->rip6_vers = RIP6_VERSION; 398185029Spjd ripbuf->rip6_res1[0] = 0; 399185029Spjd ripbuf->rip6_res1[1] = 0; 400185029Spjd 401185029Spjd init(); 402185029Spjd ifconfig(); 403185029Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 404185029Spjd if (ifcp->ifc_index < 0) { 405185029Spjd fprintf(stderr, "No ifindex found at %s " 406185029Spjd "(no link-local address?)\n", ifcp->ifc_name); 407185029Spjd error++; 408185029Spjd } 409185029Spjd } 410185029Spjd if (error) 411185029Spjd exit(1); 412185029Spjd if (loopifcp == NULL) { 413247187Smm fatal("No loopback found"); 414236884Smm /*NOTREACHED*/ 415185029Spjd } 416185029Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 417185029Spjd ifrt(ifcp, 0); 418185029Spjd } 419236884Smm filterconfig(); 420236884Smm krtread(0); 421236884Smm if (dflag) 422185029Spjd ifrtdump(0); 423236884Smm 424236884Smm pid = getpid(); 425236884Smm if ((pidfh = fopen(pidfile, "w")) != NULL) { 426249195Smm fprintf(pidfh, "%d\n", pid); 427236884Smm fclose(pidfh); 428236884Smm } 429185029Spjd 430236884Smm if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) { 431236884Smm fatal("malloc"); 432236884Smm /*NOTREACHED*/ 433236884Smm } 434249195Smm memset(ripbuf, 0, RIP6_MAXMTU); 435236884Smm ripbuf->rip6_cmd = RIP6_RESPONSE; 436236884Smm ripbuf->rip6_vers = RIP6_VERSION; 437185029Spjd ripbuf->rip6_res1[0] = 0; 438236884Smm ripbuf->rip6_res1[1] = 0; 439249195Smm 440236884Smm if (signal(SIGALRM, sighandler) == SIG_ERR || 441236884Smm signal(SIGQUIT, sighandler) == SIG_ERR || 442236884Smm signal(SIGTERM, sighandler) == SIG_ERR || 443236884Smm signal(SIGUSR1, sighandler) == SIG_ERR || 444249195Smm signal(SIGHUP, sighandler) == SIG_ERR || 445236884Smm signal(SIGINT, sighandler) == SIG_ERR) { 446236884Smm fatal("signal"); 447236884Smm /*NOTREACHED*/ 448236884Smm } 449236884Smm /* 450249195Smm * To avoid rip packet congestion (not on a cable but in this 451236884Smm * process), wait for a moment to send the first RIP6_RESPONSE 452236884Smm * packets. 453236884Smm */ 454236884Smm alarm(ripinterval(INIT_INTERVAL6)); 455236884Smm 456236884Smm TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 457185029Spjd if (iff_find(ifcp, IFIL_TYPE_N) != NULL) 458185029Spjd continue; 459185029Spjd if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 460236884Smm sendrequest(ifcp); 461236884Smm } 462236884Smm 463249195Smm syslog(LOG_INFO, "**** Started ****"); 464185029Spjd sigemptyset(&mask); 465185029Spjd sigaddset(&mask, SIGALRM); 466185029Spjd while (1) { 467185029Spjd if (seenalrm) { 468185029Spjd ripalarm(); 469219089Spjd seenalrm = 0; 470185029Spjd continue; 471185029Spjd } 472249195Smm if (seenquit) { 473185029Spjd rtdexit(); 474185029Spjd seenquit = 0; 475185029Spjd continue; 476209962Smm } 477209962Smm if (seenusr1) { 478209962Smm ifrtdump(SIGUSR1); 479209962Smm seenusr1 = 0; 480209962Smm continue; 481185029Spjd } 482249195Smm 483185029Spjd#ifdef HAVE_POLL_H 484185029Spjd switch (poll(set, 2, INFTIM)) 485185029Spjd#else 486185029Spjd memcpy(recvecp, sockvecp, fdmasks); 487185029Spjd switch (select(maxfd + 1, recvecp, 0, 0, 0)) 488185029Spjd#endif 489185029Spjd { 490249195Smm case -1: 491185029Spjd if (errno != EINTR) { 492185029Spjd fatal("select"); 493185029Spjd /*NOTREACHED*/ 494185029Spjd } 495185029Spjd continue; 496185029Spjd case 0: 497185029Spjd continue; 498185029Spjd default: 499236884Smm#ifdef HAVE_POLL_H 500185029Spjd if (set[0].revents & POLLIN) 501185029Spjd#else 502185029Spjd if (FD_ISSET(ripsock, recvecp)) 503185029Spjd#endif 504185029Spjd { 505185029Spjd sigprocmask(SIG_BLOCK, &mask, &omask); 506185029Spjd riprecv(); 507185029Spjd sigprocmask(SIG_SETMASK, &omask, NULL); 508219089Spjd } 509185029Spjd#ifdef HAVE_POLL_H 510185029Spjd if (set[1].revents & POLLIN) 511219089Spjd#else 512219089Spjd if (FD_ISSET(rtsock, recvecp)) 513219089Spjd#endif 514249195Smm { 515248571Smm sigprocmask(SIG_BLOCK, &mask, &omask); 516248571Smm rtrecv(); 517185029Spjd sigprocmask(SIG_SETMASK, &omask, NULL); 518248571Smm } 519185029Spjd } 520249195Smm } 521185029Spjd} 522185029Spjd 523185029Spjdstatic void 524219089Spjdsighandler(int signo) 525185029Spjd{ 526185029Spjd 527185029Spjd switch (signo) { 528185029Spjd case SIGALRM: 529185029Spjd seenalrm++; 530185029Spjd break; 531185029Spjd case SIGQUIT: 532249195Smm case SIGTERM: 533185029Spjd seenquit++; 534185029Spjd break; 535185029Spjd case SIGUSR1: 536185029Spjd case SIGHUP: 537185029Spjd case SIGINT: 538185029Spjd seenusr1++; 539185029Spjd break; 540185029Spjd } 541185029Spjd} 542185029Spjd 543185029Spjd/* 544185029Spjd * gracefully exits after resetting sockopts. 545185029Spjd */ 546249195Smm/* ARGSUSED */ 547185029Spjdstatic void 548185029Spjdrtdexit(void) 549185029Spjd{ 550185029Spjd struct riprt *rrt; 551185029Spjd 552185029Spjd alarm(0); 553185029Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 554185029Spjd if (rrt->rrt_rflags & RRTF_AGGREGATE) { 555185029Spjd delroute(&rrt->rrt_info, &rrt->rrt_gw); 556185029Spjd } 557185029Spjd } 558185029Spjd close(ripsock); 559185029Spjd close(rtsock); 560185029Spjd syslog(LOG_INFO, "**** Terminated ****"); 561249195Smm closelog(); 562185029Spjd exit(1); 563185029Spjd} 564185029Spjd 565185029Spjd/* 566185029Spjd * Called periodically: 567185029Spjd * 1. age out the learned route. remove it if necessary. 568185029Spjd * 2. submit RIP6_RESPONSE packets. 569185029Spjd * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have 570249195Smm * to invoke this function in every 1 or 5 or 10 seconds only to age the 571185029Spjd * routes more precisely. 572219089Spjd */ 573228103Smm/* ARGSUSED */ 574228103Smmstatic void 575228103Smmripalarm(void) 576228103Smm{ 577228103Smm struct ifc *ifcp; 578228103Smm struct riprt *rrt, *rrt_tmp; 579228103Smm time_t t_lifetime, t_holddown; 580228103Smm 581228103Smm /* age the RIP routes */ 582228103Smm t_lifetime = time(NULL) - RIP_LIFETIME; 583228103Smm t_holddown = t_lifetime - RIP_HOLDDOWN; 584249195Smm TAILQ_FOREACH_SAFE(rrt, &riprt_head, rrt_next, rrt_tmp) { 585228103Smm if (rrt->rrt_t == 0) 586228103Smm continue; 587228103Smm else if (rrt->rrt_t < t_holddown) { 588228103Smm TAILQ_REMOVE(&riprt_head, rrt, rrt_next); 589228103Smm delroute(&rrt->rrt_info, &rrt->rrt_gw); 590228103Smm free(rrt); 591228103Smm } else if (rrt->rrt_t < t_lifetime) 592228103Smm rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 593219089Spjd } 594219089Spjd /* Supply updates */ 595249195Smm TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 596219089Spjd if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) 597219089Spjd ripsend(ifcp, &ifcp->ifc_ripsin, 0); 598219089Spjd } 599219089Spjd alarm(ripinterval(SUPPLY_INTERVAL6)); 600249195Smm} 601219089Spjd 602185029Spjdstatic void 603185029Spjdinit(void) 604185029Spjd{ 605185029Spjd int error; 606185029Spjd const int int0 = 0, int1 = 1, int255 = 255; 607185029Spjd struct addrinfo hints, *res; 608185029Spjd char port[NI_MAXSERV]; 609185029Spjd 610185029Spjd TAILQ_INIT(&ifc_head); 611185029Spjd nindex2ifc = 0; /*initial guess*/ 612185029Spjd index2ifc = NULL; 613185029Spjd snprintf(port, sizeof(port), "%u", RIP6_PORT); 614185029Spjd 615185029Spjd memset(&hints, 0, sizeof(hints)); 616185029Spjd hints.ai_family = PF_INET6; 617185029Spjd hints.ai_socktype = SOCK_DGRAM; 618185029Spjd hints.ai_protocol = IPPROTO_UDP; 619185029Spjd hints.ai_flags = AI_PASSIVE; 620185029Spjd error = getaddrinfo(NULL, port, &hints, &res); 621209962Smm if (error) { 622209962Smm fatal("%s", gai_strerror(error)); 623209962Smm /*NOTREACHED*/ 624209962Smm } 625209962Smm if (res->ai_next) { 626209962Smm fatal(":: resolved to multiple address"); 627209962Smm /*NOTREACHED*/ 628209962Smm } 629209962Smm 630209962Smm ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 631209962Smm if (ripsock < 0) { 632209962Smm fatal("rip socket"); 633209962Smm /*NOTREACHED*/ 634209962Smm } 635209962Smm#ifdef IPV6_V6ONLY 636209962Smm if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_V6ONLY, 637209962Smm &int1, sizeof(int1)) < 0) { 638209962Smm fatal("rip IPV6_V6ONLY"); 639209962Smm /*NOTREACHED*/ 640209962Smm } 641209962Smm#endif 642209962Smm if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) { 643209962Smm fatal("rip bind"); 644209962Smm /*NOTREACHED*/ 645209962Smm } 646185029Spjd if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 647185029Spjd &int255, sizeof(int255)) < 0) { 648185029Spjd fatal("rip IPV6_MULTICAST_HOPS"); 649185029Spjd /*NOTREACHED*/ 650236884Smm } 651209962Smm if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 652185029Spjd &int0, sizeof(int0)) < 0) { 653185029Spjd fatal("rip IPV6_MULTICAST_LOOP"); 654185029Spjd /*NOTREACHED*/ 655185029Spjd } 656209962Smm 657236884Smm#ifdef IPV6_RECVPKTINFO 658209962Smm if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 659219089Spjd &int1, sizeof(int1)) < 0) { 660219089Spjd fatal("rip IPV6_RECVPKTINFO"); 661219089Spjd /*NOTREACHED*/ 662209962Smm } 663209962Smm#else /* old adv. API */ 664236884Smm if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, 665236884Smm &int1, sizeof(int1)) < 0) { 666236884Smm fatal("rip IPV6_PKTINFO"); 667236884Smm /*NOTREACHED*/ 668236884Smm } 669236884Smm#endif 670236884Smm 671236884Smm#ifdef IPV6_RECVPKTINFO 672236884Smm if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 673236884Smm &int1, sizeof(int1)) < 0) { 674236884Smm fatal("rip IPV6_RECVHOPLIMIT"); 675236884Smm /*NOTREACHED*/ 676236884Smm } 677236884Smm#else /* old adv. API */ 678236884Smm if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT, 679236884Smm &int1, sizeof(int1)) < 0) { 680236884Smm fatal("rip IPV6_HOPLIMIT"); 681236884Smm /*NOTREACHED*/ 682236884Smm } 683236884Smm#endif 684236884Smm freeaddrinfo(res); 685248571Smm 686268473Sdelphij memset(&hints, 0, sizeof(hints)); 687268473Sdelphij hints.ai_family = PF_INET6; 688236884Smm hints.ai_socktype = SOCK_DGRAM; 689236884Smm hints.ai_protocol = IPPROTO_UDP; 690236884Smm error = getaddrinfo(RIP6_DEST, port, &hints, &res); 691236884Smm if (error) { 692236884Smm fatal("%s", gai_strerror(error)); 693209962Smm /*NOTREACHED*/ 694209962Smm } 695209962Smm if (res->ai_next) { 696209962Smm fatal("%s resolved to multiple address", RIP6_DEST); 697236884Smm /*NOTREACHED*/ 698248571Smm } 699268473Sdelphij memcpy(&ripsin, res->ai_addr, res->ai_addrlen); 700236884Smm freeaddrinfo(res); 701236884Smm 702236884Smm#ifdef HAVE_POLL_H 703185029Spjd set[0].fd = ripsock; 704185029Spjd set[0].events = POLLIN; 705185029Spjd#else 706185029Spjd maxfd = ripsock; 707185029Spjd#endif 708185029Spjd 709185029Spjd if (nflag == 0) { 710185029Spjd if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { 711185029Spjd fatal("route socket"); 712185029Spjd /*NOTREACHED*/ 713185029Spjd } 714185029Spjd#ifdef HAVE_POLL_H 715185029Spjd set[1].fd = rtsock; 716185029Spjd set[1].events = POLLIN; 717185029Spjd#else 718185029Spjd if (rtsock > maxfd) 719239620Smm maxfd = rtsock; 720239620Smm#endif 721248571Smm } else { 722239620Smm#ifdef HAVE_POLL_H 723248571Smm set[1].fd = -1; 724248571Smm#else 725239620Smm rtsock = -1; /*just for safety */ 726239620Smm#endif 727239620Smm } 728239620Smm 729239620Smm#ifndef HAVE_POLL_H 730239620Smm fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 731239620Smm if ((sockvecp = malloc(fdmasks)) == NULL) { 732239620Smm fatal("malloc"); 733249195Smm /*NOTREACHED*/ 734239620Smm } 735239620Smm if ((recvecp = malloc(fdmasks)) == NULL) { 736239620Smm fatal("malloc"); 737239620Smm /*NOTREACHED*/ 738239620Smm } 739239620Smm memset(sockvecp, 0, fdmasks); 740239620Smm FD_SET(ripsock, sockvecp); 741248571Smm if (rtsock >= 0) 742239620Smm FD_SET(rtsock, sockvecp); 743248571Smm#endif 744248571Smm} 745239620Smm 746239620Smm#define RIPSIZE(n) \ 747239620Smm (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6)) 748239620Smm 749239620Smm/* 750239620Smm * ripflush flushes the rip datagram stored in the rip buffer 751239620Smm */ 752239620Smmstatic void 753239620Smmripflush(struct ifc *ifcp, struct sockaddr_in6 *sin6, int nrt, struct netinfo6 *np) 754239620Smm{ 755239620Smm int i; 756248571Smm int error; 757239620Smm 758239620Smm if (ifcp) 759239620Smm tracet(1, "Send(%s): info(%d) to %s.%d\n", 760185029Spjd ifcp->ifc_name, nrt, 761228103Smm inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 762228103Smm else 763228103Smm tracet(1, "Send: info(%d) to %s.%d\n", 764228103Smm nrt, inet6_n2p(&sin6->sin6_addr), ntohs(sin6->sin6_port)); 765228103Smm if (dflag >= 2) { 766228103Smm np = ripbuf->rip6_nets; 767228103Smm for (i = 0; i < nrt; i++, np++) { 768228103Smm if (np->rip6_metric == NEXTHOP_METRIC) { 769228103Smm if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) 770228103Smm trace(2, " NextHop reset"); 771228103Smm else { 772239620Smm trace(2, " NextHop %s", 773239620Smm inet6_n2p(&np->rip6_dest)); 774228103Smm } 775254074Sdelphij } else { 776239620Smm trace(2, " %s/%d[%d]", 777239620Smm inet6_n2p(&np->rip6_dest), 778228103Smm np->rip6_plen, np->rip6_metric); 779248571Smm } 780268473Sdelphij if (np->rip6_tag) { 781228103Smm trace(2, " tag=0x%04x", 782239620Smm ntohs(np->rip6_tag) & 0xffff); 783239620Smm } 784239620Smm trace(2, "\n"); 785239620Smm } 786228103Smm } 787239620Smm error = sendpacket(sin6, RIPSIZE(nrt)); 788254074Sdelphij if (error == EAFNOSUPPORT) { 789228103Smm /* Protocol not supported */ 790239620Smm if (ifcp != NULL) { 791228103Smm tracet(1, "Could not send info to %s (%s): " 792228103Smm "set IFF_UP to 0\n", 793228103Smm ifcp->ifc_name, 794185029Spjd inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 795168404Spjd /* As if down for AF_INET6 */ 796168404Spjd ifcp->ifc_flags &= ~IFF_UP; 797168404Spjd } else { 798168404Spjd tracet(1, "Could not send info to %s\n", 799168404Spjd inet6_n2p(&sin6->sin6_addr)); 800168404Spjd } 801168404Spjd } 802168404Spjd} 803168404Spjd 804168404Spjd/* 805168404Spjd * Generate RIP6_RESPONSE packets and send them. 806168404Spjd */ 807268123Sdelphijstatic void 808168404Spjdripsend(struct ifc *ifcp, struct sockaddr_in6 *sin6, int flag) 809168404Spjd{ 810168404Spjd struct riprt *rrt; 811168404Spjd struct in6_addr *nh; /* next hop */ 812168404Spjd struct netinfo6 *np; 813168404Spjd int maxrte; 814168404Spjd int nrt; 815168404Spjd 816168404Spjd if (qflag) 817168404Spjd return; 818168404Spjd 819168404Spjd if (ifcp == NULL) { 820168404Spjd /* 821168404Spjd * Request from non-link local address is not 822168404Spjd * a regular route6d update. 823168404Spjd */ 824168404Spjd maxrte = (IFMINMTU - sizeof(struct ip6_hdr) - 825168404Spjd sizeof(struct udphdr) - 826168404Spjd sizeof(struct rip6) + sizeof(struct netinfo6)) / 827168404Spjd sizeof(struct netinfo6); 828168404Spjd nh = NULL; 829168404Spjd nrt = 0; 830168404Spjd np = ripbuf->rip6_nets; 831168404Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 832168404Spjd if (rrt->rrt_rflags & RRTF_NOADVERTISE) 833168404Spjd continue; 834168404Spjd /* Put the route to the buffer */ 835168404Spjd *np = rrt->rrt_info; 836168404Spjd np++; nrt++; 837258631Savg if (nrt == maxrte) { 838258631Savg ripflush(NULL, sin6, nrt, np); 839168404Spjd nh = NULL; 840258631Savg nrt = 0; 841258631Savg np = ripbuf->rip6_nets; 842258631Savg } 843258631Savg } 844258631Savg if (nrt) /* Send last packet */ 845258631Savg ripflush(NULL, sin6, nrt, np); 846258630Savg return; 847219089Spjd } 848168404Spjd 849258631Savg if ((flag & RRTF_SENDANYWAY) == 0 && 850258631Savg (qflag || (ifcp->ifc_flags & IFF_LOOPBACK))) 851258631Savg return; 852258631Savg 853258631Savg /* -N: no use */ 854168404Spjd if (iff_find(ifcp, IFIL_TYPE_N) != NULL) 855258631Savg return; 856168404Spjd 857258631Savg /* -T: generate default route only */ 858258631Savg if (iff_find(ifcp, IFIL_TYPE_T) != NULL) { 859219089Spjd struct netinfo6 rrt_info; 860258632Savg memset(&rrt_info, 0, sizeof(struct netinfo6)); 861258632Savg rrt_info.rip6_dest = in6addr_any; 862258632Savg rrt_info.rip6_plen = 0; 863258632Savg rrt_info.rip6_metric = 1; 864258632Savg rrt_info.rip6_metric += ifcp->ifc_metric; 865219089Spjd rrt_info.rip6_tag = htons(routetag & 0xffff); 866258632Savg np = ripbuf->rip6_nets; 867258632Savg *np = rrt_info; 868258632Savg nrt = 1; 869258632Savg ripflush(ifcp, sin6, nrt, np); 870258632Savg return; 871219089Spjd } 872258632Savg 873258632Savg maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) - 874258632Savg sizeof(struct udphdr) - 875258632Savg sizeof(struct rip6) + sizeof(struct netinfo6)) / 876258632Savg sizeof(struct netinfo6); 877258632Savg 878258631Savg nrt = 0; np = ripbuf->rip6_nets; nh = NULL; 879258632Savg TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 880258632Savg if (rrt->rrt_rflags & RRTF_NOADVERTISE) 881258631Savg continue; 882258631Savg 883258631Savg /* Need to check filter here */ 884258631Savg if (out_filter(rrt, ifcp) == 0) 885258631Savg continue; 886258631Savg 887258631Savg /* Check split horizon and other conditions */ 888258631Savg if (tobeadv(rrt, ifcp) == 0) 889258631Savg continue; 890219089Spjd 891258631Savg /* Only considers the routes with flag if specified */ 892258631Savg if ((flag & RRTF_CHANGED) && 893258631Savg (rrt->rrt_rflags & RRTF_CHANGED) == 0) 894219089Spjd continue; 895258631Savg 896258631Savg /* Check nexthop */ 897258631Savg if (rrt->rrt_index == ifcp->ifc_index && 898258631Savg !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && 899258632Savg (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { 900258632Savg if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { 901258632Savg if (nrt == maxrte - 2) { 902258632Savg ripflush(ifcp, sin6, nrt, np); 903258632Savg nh = NULL; 904258632Savg nrt = 0; 905258632Savg np = ripbuf->rip6_nets; 906258632Savg } 907258632Savg 908258632Savg np->rip6_dest = rrt->rrt_gw; 909258631Savg np->rip6_plen = 0; 910258631Savg np->rip6_tag = 0; 911258631Savg np->rip6_metric = NEXTHOP_METRIC; 912258631Savg nh = &rrt->rrt_gw; 913258631Savg np++; nrt++; 914258631Savg } 915219089Spjd } else if (nh && (rrt->rrt_index != ifcp->ifc_index || 916219089Spjd !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || 917219089Spjd rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { 918219089Spjd /* Reset nexthop */ 919258631Savg if (nrt == maxrte - 2) { 920258631Savg ripflush(ifcp, sin6, nrt, np); 921258631Savg nh = NULL; 922258631Savg nrt = 0; 923258631Savg np = ripbuf->rip6_nets; 924258631Savg } 925258631Savg memset(np, 0, sizeof(struct netinfo6)); 926258631Savg np->rip6_metric = NEXTHOP_METRIC; 927258631Savg nh = NULL; 928258631Savg np++; nrt++; 929258631Savg } 930258631Savg 931258631Savg /* Put the route to the buffer */ 932258631Savg *np = rrt->rrt_info; 933258631Savg np++; nrt++; 934258631Savg if (nrt == maxrte) { 935258631Savg ripflush(ifcp, sin6, nrt, np); 936258631Savg nh = NULL; 937258631Savg nrt = 0; 938258631Savg np = ripbuf->rip6_nets; 939258631Savg } 940258631Savg } 941258631Savg if (nrt) /* Send last packet */ 942258631Savg ripflush(ifcp, sin6, nrt, np); 943258631Savg} 944258631Savg 945258631Savg/* 946258631Savg * outbound filter logic, per-route/interface. 947258631Savg */ 948258631Savgstatic int 949258631Savgout_filter(struct riprt *rrt, struct ifc *ifcp) 950258631Savg{ 951258631Savg struct iff *iffp; 952258631Savg struct in6_addr ia; 953258631Savg int ok; 954258631Savg 955258631Savg /* 956267038Sbdrewery * -A: filter out less specific routes, if we have aggregated 957267029Smav * route configured. 958267038Sbdrewery */ 959267038Sbdrewery TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { 960267038Sbdrewery if (iffp->iff_type != 'A') 961258631Savg continue; 962258631Savg if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) 963258631Savg continue; 964258631Savg ia = rrt->rrt_info.rip6_dest; 965258631Savg applyplen(&ia, iffp->iff_plen); 966258631Savg if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) 967219089Spjd return 0; 968219089Spjd } 969185029Spjd 970185029Spjd /* 971258631Savg * if it is an aggregated route, advertise it only to the 972219089Spjd * interfaces specified on -A. 973219089Spjd */ 974219089Spjd if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { 975209962Smm ok = 0; 976219089Spjd TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { 977219089Spjd if (iffp->iff_type != 'A') 978219089Spjd continue; 979219089Spjd if (rrt->rrt_info.rip6_plen == iffp->iff_plen && 980219089Spjd IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 981219089Spjd &iffp->iff_addr)) { 982209962Smm ok = 1; 983219089Spjd break; 984219089Spjd } 985209962Smm } 986219089Spjd if (!ok) 987219089Spjd return 0; 988209962Smm } 989219089Spjd 990219089Spjd /* 991219089Spjd * -O: advertise only if prefix matches the configured prefix. 992219089Spjd */ 993211931Smm if (iff_find(ifcp, IFIL_TYPE_O) != NULL) { 994219089Spjd ok = 0; 995219089Spjd TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { 996219089Spjd if (iffp->iff_type != 'O') 997219089Spjd continue; 998219089Spjd if (rrt->rrt_info.rip6_plen < iffp->iff_plen) 999219089Spjd continue; 1000219089Spjd ia = rrt->rrt_info.rip6_dest; 1001219089Spjd applyplen(&ia, iffp->iff_plen); 1002219089Spjd if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 1003219089Spjd ok = 1; 1004219089Spjd break; 1005219089Spjd } 1006219089Spjd } 1007219089Spjd if (!ok) 1008219089Spjd return 0; 1009219089Spjd } 1010219089Spjd 1011219089Spjd /* the prefix should be advertised */ 1012219089Spjd return 1; 1013219089Spjd} 1014219089Spjd 1015219089Spjd/* 1016219089Spjd * Determine if the route is to be advertised on the specified interface. 1017219089Spjd * It checks options specified in the arguments and the split horizon rule. 1018219089Spjd */ 1019219089Spjdstatic int 1020219089Spjdtobeadv(struct riprt *rrt, struct ifc *ifcp) 1021219089Spjd{ 1022219089Spjd 1023219089Spjd /* Special care for static routes */ 1024219089Spjd if (rrt->rrt_flags & RTF_STATIC) { 1025219089Spjd /* XXX don't advertise reject/blackhole routes */ 1026219089Spjd if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE)) 1027219089Spjd return 0; 1028219089Spjd 1029219089Spjd if (Sflag) /* Yes, advertise it anyway */ 1030219089Spjd return 1; 1031219089Spjd if (sflag && rrt->rrt_index != ifcp->ifc_index) 1032219089Spjd return 1; 1033219089Spjd return 0; 1034219089Spjd } 1035219089Spjd /* Regular split horizon */ 1036219089Spjd if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index) 1037219089Spjd return 0; 1038219089Spjd return 1; 1039219089Spjd} 1040219089Spjd 1041219089Spjd/* 1042219089Spjd * Send a rip packet actually. 1043219089Spjd */ 1044219089Spjdstatic int 1045219089Spjdsendpacket(struct sockaddr_in6 *sin6, int len) 1046219089Spjd{ 1047219089Spjd struct msghdr m; 1048219089Spjd struct cmsghdr *cm; 1049219089Spjd struct iovec iov[2]; 1050219089Spjd struct in6_pktinfo *pi; 1051219089Spjd u_char cmsgbuf[256]; 1052219089Spjd int idx; 1053219089Spjd struct sockaddr_in6 sincopy; 1054219089Spjd 1055219089Spjd /* do not overwrite the given sin */ 1056219089Spjd sincopy = *sin6; 1057219089Spjd sin6 = &sincopy; 1058219089Spjd 1059219089Spjd if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 1060219089Spjd IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 1061219089Spjd idx = sin6->sin6_scope_id; 1062219089Spjd else 1063219089Spjd idx = 0; 1064219089Spjd 1065219089Spjd m.msg_name = (caddr_t)sin6; 1066219089Spjd m.msg_namelen = sizeof(*sin6); 1067219089Spjd iov[0].iov_base = (caddr_t)ripbuf; 1068219089Spjd iov[0].iov_len = len; 1069219089Spjd m.msg_iov = iov; 1070219089Spjd m.msg_iovlen = 1; 1071219089Spjd m.msg_flags = 0; 1072219089Spjd if (!idx) { 1073219089Spjd m.msg_control = NULL; 1074219089Spjd m.msg_controllen = 0; 1075219089Spjd } else { 1076219089Spjd memset(cmsgbuf, 0, sizeof(cmsgbuf)); 1077219089Spjd cm = (struct cmsghdr *)(void *)cmsgbuf; 1078219089Spjd m.msg_control = (caddr_t)cm; 1079219089Spjd m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 1080219089Spjd 1081209962Smm cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1082219089Spjd cm->cmsg_level = IPPROTO_IPV6; 1083219089Spjd cm->cmsg_type = IPV6_PKTINFO; 1084219089Spjd pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm); 1085219089Spjd memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/ 1086219089Spjd pi->ipi6_ifindex = idx; 1087219089Spjd } 1088219089Spjd 1089219089Spjd if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) { 1090219089Spjd trace(1, "sendmsg: %s\n", strerror(errno)); 1091185029Spjd return errno; 1092168404Spjd } 1093219089Spjd 1094219089Spjd return 0; 1095168404Spjd} 1096219089Spjd 1097219089Spjd/* 1098219089Spjd * Receive and process RIP packets. Update the routes/kernel forwarding 1099219089Spjd * table if necessary. 1100219089Spjd */ 1101219089Spjdstatic void 1102240868Spjdriprecv(void) 1103240868Spjd{ 1104240868Spjd struct ifc *ifcp, *ic; 1105240868Spjd struct sockaddr_in6 fsock; 1106240868Spjd struct in6_addr nh; /* next hop */ 1107185029Spjd struct rip6 *rp; 1108185029Spjd struct netinfo6 *np, *nq; 1109185029Spjd struct riprt *rrt; 1110185029Spjd ssize_t len, nn; 1111168404Spjd unsigned int need_trigger, idx; 1112168404Spjd char buf[4 * RIP6_MAXMTU]; 1113168404Spjd time_t t; 1114168404Spjd struct msghdr m; 1115168404Spjd struct cmsghdr *cm; 1116168404Spjd struct iovec iov[2]; 1117168404Spjd u_char cmsgbuf[256]; 1118168404Spjd struct in6_pktinfo *pi = NULL; 1119168404Spjd int *hlimp = NULL; 1120168404Spjd struct iff *iffp; 1121168404Spjd struct in6_addr ia; 1122168404Spjd int ok; 1123168404Spjd time_t t_half_lifetime; 1124168404Spjd 1125168404Spjd need_trigger = 0; 1126168404Spjd 1127168404Spjd m.msg_name = (caddr_t)&fsock; 1128168404Spjd m.msg_namelen = sizeof(fsock); 1129168404Spjd iov[0].iov_base = (caddr_t)buf; 1130168404Spjd iov[0].iov_len = sizeof(buf); 1131168404Spjd m.msg_iov = iov; 1132209962Smm m.msg_iovlen = 1; 1133168404Spjd cm = (struct cmsghdr *)(void *)cmsgbuf; 1134168404Spjd m.msg_control = (caddr_t)cm; 1135240868Spjd m.msg_controllen = sizeof(cmsgbuf); 1136240868Spjd m.msg_flags = 0; 1137240868Spjd if ((len = recvmsg(ripsock, &m, 0)) < 0) { 1138240868Spjd fatal("recvmsg"); 1139240868Spjd /*NOTREACHED*/ 1140240868Spjd } 1141168404Spjd idx = 0; 1142168404Spjd for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); 1143185029Spjd cm; 1144185029Spjd cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { 1145168404Spjd if (cm->cmsg_level != IPPROTO_IPV6) 1146185029Spjd continue; 1147185029Spjd switch (cm->cmsg_type) { 1148258631Savg case IPV6_PKTINFO: 1149185029Spjd if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) { 1150168404Spjd trace(1, 1151168404Spjd "invalid cmsg length for IPV6_PKTINFO\n"); 1152168404Spjd return; 1153168404Spjd } 1154168404Spjd pi = (struct in6_pktinfo *)(void *)CMSG_DATA(cm); 1155185029Spjd idx = pi->ipi6_ifindex; 1156185029Spjd break; 1157185029Spjd case IPV6_HOPLIMIT: 1158168404Spjd if (cm->cmsg_len != CMSG_LEN(sizeof(int))) { 1159168404Spjd trace(1, 1160168404Spjd "invalid cmsg length for IPV6_HOPLIMIT\n"); 1161168404Spjd return; 1162168404Spjd } 1163168404Spjd hlimp = (int *)(void *)CMSG_DATA(cm); 1164168404Spjd break; 1165168404Spjd } 1166168404Spjd } 1167168404Spjd 1168219089Spjd if ((size_t)len < sizeof(struct rip6)) { 1169219089Spjd trace(1, "Packet too short\n"); 1170219089Spjd return; 1171219089Spjd } 1172219089Spjd 1173219089Spjd if (pi == NULL || hlimp == NULL) { 1174219089Spjd /* 1175219089Spjd * This can happen when the kernel failed to allocate memory 1176219089Spjd * for the ancillary data. Although we might be able to handle 1177219089Spjd * some cases without this info, those are minor and not so 1178219089Spjd * important, so it's better to discard the packet for safer 1179219089Spjd * operation. 1180219089Spjd */ 1181219089Spjd trace(1, "IPv6 packet information cannot be retrieved\n"); 1182219089Spjd return; 1183219089Spjd } 1184219089Spjd 1185219089Spjd nh = fsock.sin6_addr; 1186219089Spjd nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) / 1187219089Spjd sizeof(struct netinfo6); 1188219089Spjd rp = (struct rip6 *)(void *)buf; 1189219089Spjd np = rp->rip6_nets; 1190219089Spjd 1191219089Spjd if (rp->rip6_vers != RIP6_VERSION) { 1192219089Spjd trace(1, "Incorrect RIP version %d\n", rp->rip6_vers); 1193219089Spjd return; 1194219089Spjd } 1195168404Spjd if (rp->rip6_cmd == RIP6_REQUEST) { 1196168404Spjd if (idx && idx < nindex2ifc) { 1197168404Spjd ifcp = index2ifc[idx]; 1198168404Spjd riprequest(ifcp, np, nn, &fsock); 1199168404Spjd } else { 1200168404Spjd riprequest(NULL, np, nn, &fsock); 1201168404Spjd } 1202168404Spjd return; 1203168404Spjd } 1204168404Spjd 1205168404Spjd if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) { 1206168404Spjd trace(1, "Response from non-ll addr: %s\n", 1207168404Spjd inet6_n2p(&fsock.sin6_addr)); 1208219089Spjd return; /* Ignore packets from non-link-local addr */ 1209168404Spjd } 1210168404Spjd if (ntohs(fsock.sin6_port) != RIP6_PORT) { 1211168404Spjd trace(1, "Response from non-rip port from %s\n", 1212168404Spjd inet6_n2p(&fsock.sin6_addr)); 1213168404Spjd return; 1214168404Spjd } 1215168404Spjd if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) { 1216168404Spjd trace(1, 1217185029Spjd "Response packet with a smaller hop limit (%d) from %s\n", 1218185029Spjd *hlimp, inet6_n2p(&fsock.sin6_addr)); 1219185029Spjd return; 1220185029Spjd } 1221185029Spjd /* 1222185029Spjd * Further validation: since this program does not send off-link 1223185029Spjd * requests, an incoming response must always come from an on-link 1224168404Spjd * node. Although this is normally ensured by the source address 1225168404Spjd * check above, it may not 100% be safe because there are router 1226249195Smm * implementations that (invalidly) allow a packet with a link-local 1227168404Spjd * source address to be forwarded to a different link. 1228168404Spjd * So we also check whether the destination address is a link-local 1229219089Spjd * address or the hop limit is 255. Note that RFC2080 does not require 1230168404Spjd * the specific hop limit for a unicast response, so we cannot assume 1231168404Spjd * the limitation. 1232168404Spjd */ 1233168404Spjd if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) { 1234168404Spjd trace(1, 1235168404Spjd "Response packet possibly from an off-link node: " 1236168404Spjd "from %s to %s hlim=%d\n", 1237168404Spjd inet6_n2p(&fsock.sin6_addr), 1238168404Spjd inet6_n2p(&pi->ipi6_addr), *hlimp); 1239168404Spjd return; 1240168404Spjd } 1241168404Spjd 1242168404Spjd idx = fsock.sin6_scope_id; 1243168404Spjd ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL; 1244168404Spjd if (!ifcp) { 1245168404Spjd trace(1, "Packets to unknown interface index %d\n", idx); 1246168404Spjd return; /* Ignore it */ 1247168404Spjd } 1248168404Spjd if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr)) 1249168404Spjd return; /* The packet is from me; ignore */ 1250168404Spjd if (rp->rip6_cmd != RIP6_RESPONSE) { 1251168404Spjd trace(1, "Invalid command %d\n", rp->rip6_cmd); 1252185029Spjd return; 1253185029Spjd } 1254168404Spjd 1255240868Spjd /* -N: no use */ 1256240868Spjd if (iff_find(ifcp, IFIL_TYPE_N) != NULL) 1257240868Spjd return; 1258240868Spjd 1259240868Spjd tracet(1, "Recv(%s): from %s.%d info(%zd)\n", 1260168404Spjd ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn); 1261168404Spjd 1262168404Spjd t = time(NULL); 1263168404Spjd t_half_lifetime = t - (RIP_LIFETIME/2); 1264168404Spjd for (; nn; nn--, np++) { 1265168404Spjd if (np->rip6_metric == NEXTHOP_METRIC) { 1266168404Spjd /* modify neighbor address */ 1267168404Spjd if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 1268168404Spjd nh = np->rip6_dest; 1269168404Spjd trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 1270168404Spjd } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) { 1271168404Spjd nh = fsock.sin6_addr; 1272168404Spjd trace(1, "\tNexthop: %s\n", inet6_n2p(&nh)); 1273185029Spjd } else { 1274168404Spjd nh = fsock.sin6_addr; 1275209962Smm trace(1, "\tInvalid Nexthop: %s\n", 1276209962Smm inet6_n2p(&np->rip6_dest)); 1277209962Smm } 1278209962Smm continue; 1279168404Spjd } 1280219089Spjd if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) { 1281219089Spjd trace(1, "\tMulticast netinfo6: %s/%d [%d]\n", 1282258717Savg inet6_n2p(&np->rip6_dest), 1283258717Savg np->rip6_plen, np->rip6_metric); 1284168404Spjd continue; 1285258717Savg } 1286258717Savg if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) { 1287258717Savg trace(1, "\tLoopback netinfo6: %s/%d [%d]\n", 1288258717Savg inet6_n2p(&np->rip6_dest), 1289258717Savg np->rip6_plen, np->rip6_metric); 1290258717Savg continue; 1291258717Savg } 1292168404Spjd if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) { 1293168404Spjd trace(1, "\tLink Local netinfo6: %s/%d [%d]\n", 1294168404Spjd inet6_n2p(&np->rip6_dest), 1295168404Spjd np->rip6_plen, np->rip6_metric); 1296168404Spjd continue; 1297219089Spjd } 1298168404Spjd /* may need to pass sitelocal prefix in some case, however*/ 1299168404Spjd if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) { 1300219089Spjd trace(1, "\tSite Local netinfo6: %s/%d [%d]\n", 1301219089Spjd inet6_n2p(&np->rip6_dest), 1302209962Smm np->rip6_plen, np->rip6_metric); 1303168404Spjd continue; 1304209962Smm } 1305209962Smm trace(2, "\tnetinfo6: %s/%d [%d]", 1306209962Smm inet6_n2p(&np->rip6_dest), 1307209962Smm np->rip6_plen, np->rip6_metric); 1308185029Spjd if (np->rip6_tag) 1309185029Spjd trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff); 1310185029Spjd if (dflag >= 2) { 1311185029Spjd ia = np->rip6_dest; 1312185029Spjd applyplen(&ia, np->rip6_plen); 1313185029Spjd if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest)) 1314168404Spjd trace(2, " [junk outside prefix]"); 1315185029Spjd } 1316185029Spjd 1317185029Spjd /* 1318168404Spjd * -L: listen only if the prefix matches the configuration 1319185029Spjd */ 1320168404Spjd ok = 1; /* if there's no L filter, it is ok */ 1321230514Smm TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { 1322230514Smm if (iffp->iff_type != IFIL_TYPE_L) 1323185029Spjd continue; 1324230514Smm ok = 0; 1325185029Spjd if (np->rip6_plen < iffp->iff_plen) 1326185029Spjd continue; 1327185029Spjd /* special rule: ::/0 means default, not "in /0" */ 1328185029Spjd if (iffp->iff_plen == 0 && np->rip6_plen > 0) 1329185029Spjd continue; 1330185029Spjd ia = np->rip6_dest; 1331185029Spjd applyplen(&ia, iffp->iff_plen); 1332185029Spjd if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) { 1333185029Spjd ok = 1; 1334185029Spjd break; 1335185029Spjd } 1336168404Spjd } 1337209962Smm if (!ok) { 1338228103Smm trace(2, " (filtered)\n"); 1339228103Smm continue; 1340228103Smm } 1341228103Smm 1342228103Smm trace(2, "\n"); 1343209962Smm np->rip6_metric++; 1344168404Spjd np->rip6_metric += ifcp->ifc_metric; 1345168404Spjd if (np->rip6_metric > HOPCNT_INFINITY6) 1346168404Spjd np->rip6_metric = HOPCNT_INFINITY6; 1347168404Spjd 1348168404Spjd applyplen(&np->rip6_dest, np->rip6_plen); 1349185029Spjd if ((rrt = rtsearch(np)) != NULL) { 1350185029Spjd if (rrt->rrt_t == 0) 1351168404Spjd continue; /* Intf route has priority */ 1352168404Spjd nq = &rrt->rrt_info; 1353168404Spjd if (nq->rip6_metric > np->rip6_metric) { 1354168404Spjd if (rrt->rrt_index == ifcp->ifc_index && 1355168404Spjd IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1356168404Spjd /* Small metric from the same gateway */ 1357168404Spjd nq->rip6_metric = np->rip6_metric; 1358168404Spjd } else { 1359168404Spjd /* Better route found */ 1360185029Spjd rrt->rrt_index = ifcp->ifc_index; 1361185029Spjd /* Update routing table */ 1362168404Spjd delroute(nq, &rrt->rrt_gw); 1363168404Spjd rrt->rrt_gw = nh; 1364168404Spjd *nq = *np; 1365185029Spjd addroute(rrt, &nh, ifcp); 1366185029Spjd } 1367168404Spjd rrt->rrt_rflags |= RRTF_CHANGED; 1368168404Spjd rrt->rrt_t = t; 1369185029Spjd need_trigger = 1; 1370185029Spjd } else if (nq->rip6_metric < np->rip6_metric && 1371168404Spjd rrt->rrt_index == ifcp->ifc_index && 1372168404Spjd IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1373168404Spjd /* Got worse route from same gw */ 1374168404Spjd nq->rip6_metric = np->rip6_metric; 1375168404Spjd rrt->rrt_t = t; 1376185029Spjd rrt->rrt_rflags |= RRTF_CHANGED; 1377185029Spjd need_trigger = 1; 1378185029Spjd } else if (nq->rip6_metric == np->rip6_metric && 1379168404Spjd np->rip6_metric < HOPCNT_INFINITY6) { 1380185029Spjd if (rrt->rrt_index == ifcp->ifc_index && 1381168404Spjd IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) { 1382168404Spjd /* same metric, same route from same gw */ 1383185029Spjd rrt->rrt_t = t; 1384168404Spjd } else if (rrt->rrt_t < t_half_lifetime) { 1385168404Spjd /* Better route found */ 1386185029Spjd rrt->rrt_index = ifcp->ifc_index; 1387185029Spjd /* Update routing table */ 1388168404Spjd delroute(nq, &rrt->rrt_gw); 1389168404Spjd rrt->rrt_gw = nh; 1390168404Spjd *nq = *np; 1391168404Spjd addroute(rrt, &nh, ifcp); 1392168404Spjd rrt->rrt_rflags |= RRTF_CHANGED; 1393168404Spjd rrt->rrt_t = t; 1394168404Spjd } 1395168404Spjd } 1396168404Spjd /* 1397168404Spjd * if nq->rip6_metric == HOPCNT_INFINITY6 then 1398168404Spjd * do not update age value. Do nothing. 1399168404Spjd */ 1400168404Spjd } else if (np->rip6_metric < HOPCNT_INFINITY6) { 1401185029Spjd /* Got a new valid route */ 1402185029Spjd if ((rrt = MALLOC(struct riprt)) == NULL) { 1403185029Spjd fatal("malloc: struct riprt"); 1404168404Spjd /*NOTREACHED*/ 1405168404Spjd } 1406168404Spjd memset(rrt, 0, sizeof(*rrt)); 1407168404Spjd nq = &rrt->rrt_info; 1408185029Spjd 1409168404Spjd rrt->rrt_same = NULL; 1410185029Spjd rrt->rrt_index = ifcp->ifc_index; 1411185029Spjd rrt->rrt_flags = RTF_UP|RTF_GATEWAY; 1412168404Spjd rrt->rrt_gw = nh; 1413168404Spjd *nq = *np; 1414168404Spjd applyplen(&nq->rip6_dest, nq->rip6_plen); 1415168404Spjd if (nq->rip6_plen == sizeof(struct in6_addr) * 8) 1416168404Spjd rrt->rrt_flags |= RTF_HOST; 1417168404Spjd 1418168404Spjd /* Update routing table */ 1419168404Spjd addroute(rrt, &nh, ifcp); 1420168404Spjd rrt->rrt_rflags |= RRTF_CHANGED; 1421168404Spjd need_trigger = 1; 1422168404Spjd rrt->rrt_t = t; 1423168404Spjd 1424168404Spjd /* Put the route to the list */ 1425168404Spjd TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); 1426168404Spjd } 1427168404Spjd } 1428168404Spjd /* XXX need to care the interval between triggered updates */ 1429168404Spjd if (need_trigger) { 1430168404Spjd if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) { 1431168404Spjd TAILQ_FOREACH(ic, &ifc_head, ifc_next) { 1432185029Spjd if (ifcp->ifc_index == ic->ifc_index) 1433209962Smm continue; 1434185029Spjd if (ic->ifc_flags & IFF_UP) 1435168404Spjd ripsend(ic, &ic->ifc_ripsin, 1436168404Spjd RRTF_CHANGED); 1437168404Spjd } 1438185029Spjd } 1439185029Spjd /* Reset the flag */ 1440168404Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 1441168404Spjd rrt->rrt_rflags &= ~RRTF_CHANGED; 1442168404Spjd } 1443168404Spjd } 1444168404Spjd} 1445168404Spjd 1446185029Spjd/* 1447168404Spjd * Send all routes request packet to the specified interface. 1448168404Spjd */ 1449185029Spjdstatic void 1450185029Spjdsendrequest(struct ifc *ifcp) 1451185029Spjd{ 1452185029Spjd struct netinfo6 *np; 1453219089Spjd int error; 1454185029Spjd 1455185029Spjd if (ifcp->ifc_flags & IFF_LOOPBACK) 1456185029Spjd return; 1457168404Spjd ripbuf->rip6_cmd = RIP6_REQUEST; 1458185029Spjd np = ripbuf->rip6_nets; 1459168404Spjd memset(np, 0, sizeof(struct netinfo6)); 1460168404Spjd np->rip6_metric = HOPCNT_INFINITY6; 1461185029Spjd tracet(1, "Send rtdump Request to %s (%s)\n", 1462185029Spjd ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 1463185029Spjd error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1)); 1464185029Spjd if (error == EAFNOSUPPORT) { 1465185029Spjd /* Protocol not supported */ 1466185029Spjd tracet(1, "Could not send rtdump Request to %s (%s): " 1467185029Spjd "set IFF_UP to 0\n", 1468185029Spjd ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); 1469185029Spjd ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ 1470185029Spjd } 1471185029Spjd ripbuf->rip6_cmd = RIP6_RESPONSE; 1472185029Spjd} 1473185029Spjd 1474185029Spjd/* 1475219089Spjd * Process a RIP6_REQUEST packet. 1476185029Spjd */ 1477185029Spjdstatic void 1478185029Spjdriprequest(struct ifc *ifcp, 1479185029Spjd struct netinfo6 *np, 1480185029Spjd int nn, 1481185029Spjd struct sockaddr_in6 *sin6) 1482185029Spjd{ 1483185029Spjd int i; 1484185029Spjd struct riprt *rrt; 1485185029Spjd 1486185029Spjd if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) && 1487247187Smm np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) { 1488185029Spjd /* Specific response, don't split-horizon */ 1489185029Spjd trace(1, "\tRIP Request\n"); 1490185029Spjd for (i = 0; i < nn; i++, np++) { 1491185029Spjd rrt = rtsearch(np); 1492185029Spjd if (rrt) 1493185029Spjd np->rip6_metric = rrt->rrt_info.rip6_metric; 1494185029Spjd else 1495185029Spjd np->rip6_metric = HOPCNT_INFINITY6; 1496185029Spjd } 1497185029Spjd (void)sendpacket(sin6, RIPSIZE(nn)); 1498185029Spjd return; 1499185029Spjd } 1500185029Spjd /* Whole routing table dump */ 1501185029Spjd trace(1, "\tRIP Request -- whole routing table\n"); 1502185029Spjd ripsend(ifcp, sin6, RRTF_SENDANYWAY); 1503185029Spjd} 1504185029Spjd 1505185029Spjd/* 1506185029Spjd * Get information of each interface. 1507185029Spjd */ 1508185029Spjdstatic void 1509185029Spjdifconfig(void) 1510185029Spjd{ 1511185029Spjd struct ifaddrs *ifap, *ifa; 1512185029Spjd struct ifc *ifcp; 1513185029Spjd struct ipv6_mreq mreq; 1514185029Spjd int s; 1515185029Spjd 1516185029Spjd if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1517185029Spjd fatal("socket"); 1518185029Spjd /*NOTREACHED*/ 1519185029Spjd } 1520185029Spjd 1521185029Spjd if (getifaddrs(&ifap) != 0) { 1522185029Spjd fatal("getifaddrs"); 1523185029Spjd /*NOTREACHED*/ 1524185029Spjd } 1525185029Spjd 1526185029Spjd for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1527185029Spjd if (ifa->ifa_addr->sa_family != AF_INET6) 1528185029Spjd continue; 1529185029Spjd ifcp = ifc_find(ifa->ifa_name); 1530185029Spjd /* we are interested in multicast-capable interfaces */ 1531185029Spjd if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 1532185029Spjd continue; 1533185029Spjd if (!ifcp) { 1534185029Spjd /* new interface */ 1535185029Spjd if ((ifcp = MALLOC(struct ifc)) == NULL) { 1536185029Spjd fatal("malloc: struct ifc"); 1537185029Spjd /*NOTREACHED*/ 1538185029Spjd } 1539185029Spjd memset(ifcp, 0, sizeof(*ifcp)); 1540219089Spjd 1541219089Spjd ifcp->ifc_index = -1; 1542185029Spjd strlcpy(ifcp->ifc_name, ifa->ifa_name, 1543185029Spjd sizeof(ifcp->ifc_name)); 1544185029Spjd TAILQ_INIT(&ifcp->ifc_ifac_head); 1545185029Spjd TAILQ_INIT(&ifcp->ifc_iff_head); 1546185029Spjd ifcp->ifc_flags = ifa->ifa_flags; 1547185029Spjd TAILQ_INSERT_HEAD(&ifc_head, ifcp, ifc_next); 1548185029Spjd trace(1, "newif %s <%s>\n", ifcp->ifc_name, 1549185029Spjd ifflags(ifcp->ifc_flags)); 1550185029Spjd if (!strcmp(ifcp->ifc_name, LOOPBACK_IF)) 1551185029Spjd loopifcp = ifcp; 1552185029Spjd } else { 1553230514Smm /* update flag, this may be up again */ 1554230514Smm if (ifcp->ifc_flags != ifa->ifa_flags) { 1555209962Smm trace(1, "%s: <%s> -> ", ifcp->ifc_name, 1556209962Smm ifflags(ifcp->ifc_flags)); 1557185029Spjd trace(1, "<%s>\n", ifflags(ifa->ifa_flags)); 1558230514Smm ifcp->ifc_cflags |= IFC_CHANGED; 1559230514Smm } 1560185029Spjd ifcp->ifc_flags = ifa->ifa_flags; 1561185029Spjd } 1562185029Spjd if (ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s) < 0) { 1563185029Spjd /* maybe temporary failure */ 1564185029Spjd continue; 1565185029Spjd } 1566185029Spjd if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP 1567185029Spjd && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { 1568185029Spjd mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; 1569185029Spjd mreq.ipv6mr_interface = ifcp->ifc_index; 1570185029Spjd if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 1571185029Spjd &mreq, sizeof(mreq)) < 0) { 1572185029Spjd fatal("IPV6_JOIN_GROUP"); 1573185029Spjd /*NOTREACHED*/ 1574185029Spjd } 1575185029Spjd trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST); 1576185029Spjd ifcp->ifc_joined++; 1577185029Spjd } 1578185029Spjd } 1579185029Spjd close(s); 1580185029Spjd freeifaddrs(ifap); 1581185029Spjd} 1582219089Spjd 1583185029Spjdstatic int 1584185029Spjdifconfig1(const char *name, 1585185029Spjd const struct sockaddr *sa, 1586185029Spjd struct ifc *ifcp, 1587185029Spjd int s) 1588185029Spjd{ 1589185029Spjd struct in6_ifreq ifr; 1590185029Spjd const struct sockaddr_in6 *sin6; 1591185029Spjd struct ifac *ifac; 1592168404Spjd int plen; 1593168404Spjd char buf[BUFSIZ]; 1594168404Spjd 1595168404Spjd sin6 = (const struct sockaddr_in6 *)(const void *)sa; 1596168404Spjd if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) 1597168404Spjd return (-1); 1598168404Spjd ifr.ifr_addr = *sin6; 1599168404Spjd strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1600168404Spjd if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { 1601262676Sdelphij syslog(LOG_INFO, "ioctl: SIOCGIFNETMASK_IN6"); 1602262676Sdelphij return (-1); 1603262676Sdelphij } 1604168404Spjd plen = sin6mask2len(&ifr.ifr_addr); 1605168404Spjd if ((ifac = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { 1606168404Spjd /* same interface found */ 1607168404Spjd /* need check if something changed */ 1608209962Smm /* XXX not yet implemented */ 1609209962Smm return (-1); 1610168404Spjd } 1611168404Spjd /* 1612168404Spjd * New address is found 1613168404Spjd */ 1614168404Spjd if ((ifac = MALLOC(struct ifac)) == NULL) { 1615168404Spjd fatal("malloc: struct ifac"); 1616168404Spjd /*NOTREACHED*/ 1617168404Spjd } 1618185029Spjd memset(ifac, 0, sizeof(*ifac)); 1619185029Spjd 1620185029Spjd ifac->ifac_ifc = ifcp; 1621185029Spjd ifac->ifac_addr = sin6->sin6_addr; 1622185029Spjd ifac->ifac_plen = plen; 1623185029Spjd ifac->ifac_scope_id = sin6->sin6_scope_id; 1624219089Spjd if (ifcp->ifc_flags & IFF_POINTOPOINT) { 1625185029Spjd ifr.ifr_addr = *sin6; 1626185029Spjd if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) { 1627249188Smm fatal("ioctl: SIOCGIFDSTADDR_IN6"); 1628249188Smm /*NOTREACHED*/ 1629185029Spjd } 1630185029Spjd ifac->ifac_raddr = ifr.ifr_dstaddr.sin6_addr; 1631185029Spjd inet_ntop(AF_INET6, (void *)&ifac->ifac_raddr, buf, 1632185029Spjd sizeof(buf)); 1633185029Spjd trace(1, "found address %s/%d -- %s\n", 1634185029Spjd inet6_n2p(&ifac->ifac_addr), ifac->ifac_plen, buf); 1635219089Spjd } else { 1636213197Smm trace(1, "found address %s/%d\n", 1637219089Spjd inet6_n2p(&ifac->ifac_addr), ifac->ifac_plen); 1638219089Spjd } 1639213197Smm if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifac->ifac_addr)) { 1640219089Spjd ifcp->ifc_mylladdr = ifac->ifac_addr; 1641219089Spjd ifcp->ifc_index = ifac->ifac_scope_id; 1642213197Smm memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len); 1643219089Spjd ifcp->ifc_ripsin.sin6_scope_id = ifcp->ifc_index; 1644213197Smm setindex2ifc(ifcp->ifc_index, ifcp); 1645219089Spjd ifcp->ifc_mtu = getifmtu(ifcp->ifc_index); 1646219089Spjd if (ifcp->ifc_mtu > RIP6_MAXMTU) 1647219089Spjd ifcp->ifc_mtu = RIP6_MAXMTU; 1648219089Spjd if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) { 1649219089Spjd fatal("ioctl: SIOCGIFMETRIC"); 1650219089Spjd /*NOTREACHED*/ 1651219089Spjd } 1652219089Spjd ifcp->ifc_metric = ifr.ifr_metric; 1653219089Spjd trace(1, "\tindex: %d, mtu: %d, metric: %d\n", 1654219089Spjd ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); 1655219089Spjd } else 1656219089Spjd ifcp->ifc_cflags |= IFC_CHANGED; 1657219089Spjd 1658219089Spjd TAILQ_INSERT_HEAD(&ifcp->ifc_ifac_head, ifac, ifac_next); 1659219089Spjd 1660219089Spjd return 0; 1661219089Spjd} 1662219089Spjd 1663219089Spjdstatic void 1664219089Spjdifremove(int ifindex) 1665219089Spjd{ 1666219089Spjd struct ifc *ifcp; 1667219089Spjd struct riprt *rrt; 1668219089Spjd 1669219089Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 1670219089Spjd if (ifcp->ifc_index == ifindex) 1671219089Spjd break; 1672219089Spjd } 1673219089Spjd if (ifcp == NULL) 1674219089Spjd return; 1675219089Spjd 1676219089Spjd tracet(1, "ifremove: %s is departed.\n", ifcp->ifc_name); 1677219089Spjd TAILQ_REMOVE(&ifc_head, ifcp, ifc_next); 1678219089Spjd 1679219089Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 1680219089Spjd if (rrt->rrt_index == ifcp->ifc_index && 1681219089Spjd rrt->rrt_rflags & RRTF_AGGREGATE) 1682219089Spjd delroute(&rrt->rrt_info, &rrt->rrt_gw); 1683219089Spjd } 1684219089Spjd free(ifcp); 1685219089Spjd} 1686219089Spjd 1687219089Spjd/* 1688219089Spjd * Receive and process routing messages. 1689219089Spjd * Update interface information as necessary. 1690219089Spjd */ 1691219089Spjdstatic void 1692219089Spjdrtrecv(void) 1693213197Smm{ 1694219089Spjd char buf[BUFSIZ]; 1695213197Smm char *p, *q = NULL; 1696219089Spjd struct rt_msghdr *rtm; 1697219089Spjd struct ifa_msghdr *ifam; 1698219089Spjd struct if_msghdr *ifm; 1699219089Spjd struct if_announcemsghdr *ifan; 1700219089Spjd int len; 1701219089Spjd struct ifc *ifcp, *ic; 1702219089Spjd int iface = 0, rtable = 0; 1703219089Spjd struct sockaddr_in6 *rta[RTAX_MAX]; 1704219089Spjd struct sockaddr_in6 mask; 1705219089Spjd int i, addrs = 0; 1706219089Spjd struct riprt *rrt; 1707219089Spjd 1708219089Spjd if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 1709219089Spjd perror("read from rtsock"); 1710219089Spjd exit(1); 1711219089Spjd } 1712219089Spjd if (len == 0) 1713219089Spjd return; 1714219089Spjd#if 0 1715219089Spjd if (len < sizeof(*rtm)) { 1716219089Spjd trace(1, "short read from rtsock: %d (should be > %lu)\n", 1717219089Spjd len, (u_long)sizeof(*rtm)); 1718219089Spjd return; 1719219089Spjd } 1720219089Spjd#endif 1721219089Spjd if (dflag >= 2) { 1722219089Spjd fprintf(stderr, "rtmsg:\n"); 1723219089Spjd for (i = 0; i < len; i++) { 1724219089Spjd fprintf(stderr, "%02x ", buf[i] & 0xff); 1725219089Spjd if (i % 16 == 15) fprintf(stderr, "\n"); 1726219089Spjd } 1727219089Spjd fprintf(stderr, "\n"); 1728219089Spjd } 1729219089Spjd 1730219089Spjd for (p = buf; p - buf < len; p += 1731219089Spjd ((struct rt_msghdr *)(void *)p)->rtm_msglen) { 1732219089Spjd if (((struct rt_msghdr *)(void *)p)->rtm_version != RTM_VERSION) 1733219089Spjd continue; 1734219089Spjd 1735219089Spjd /* safety against bogus message */ 1736219089Spjd if (((struct rt_msghdr *)(void *)p)->rtm_msglen <= 0) { 1737219089Spjd trace(1, "bogus rtmsg: length=%d\n", 1738219089Spjd ((struct rt_msghdr *)(void *)p)->rtm_msglen); 1739219089Spjd break; 1740219089Spjd } 1741219089Spjd rtm = NULL; 1742219089Spjd ifam = NULL; 1743219089Spjd ifm = NULL; 1744219089Spjd switch (((struct rt_msghdr *)(void *)p)->rtm_type) { 1745219089Spjd case RTM_NEWADDR: 1746213197Smm case RTM_DELADDR: 1747219089Spjd ifam = (struct ifa_msghdr *)(void *)p; 1748219089Spjd addrs = ifam->ifam_addrs; 1749219089Spjd q = (char *)(ifam + 1); 1750219089Spjd break; 1751219089Spjd case RTM_IFINFO: 1752219089Spjd ifm = (struct if_msghdr *)(void *)p; 1753219089Spjd addrs = ifm->ifm_addrs; 1754213197Smm q = (char *)(ifm + 1); 1755213197Smm break; 1756213197Smm case RTM_IFANNOUNCE: 1757185029Spjd ifan = (struct if_announcemsghdr *)(void *)p; 1758185029Spjd switch (ifan->ifan_what) { 1759248571Smm case IFAN_ARRIVAL: 1760185029Spjd iface++; 1761185029Spjd break; 1762248571Smm case IFAN_DEPARTURE: 1763248571Smm ifremove(ifan->ifan_index); 1764185029Spjd iface++; 1765185029Spjd break; 1766185029Spjd } 1767185029Spjd break; 1768248571Smm default: 1769248571Smm rtm = (struct rt_msghdr *)(void *)p; 1770248571Smm if (rtm->rtm_version != RTM_VERSION) { 1771219089Spjd trace(1, "unexpected rtmsg version %d " 1772185029Spjd "(should be %d)\n", 1773185029Spjd rtm->rtm_version, RTM_VERSION); 1774248571Smm continue; 1775185029Spjd } 1776185029Spjd /* 1777219089Spjd * Only messages that use the struct rt_msghdr 1778219089Spjd * format are allowed beyond this point. 1779219089Spjd */ 1780219089Spjd if (rtm->rtm_type > RTM_RESOLVE) { 1781219089Spjd trace(1, "rtmsg type %d ignored\n", 1782219089Spjd rtm->rtm_type); 1783219089Spjd continue; 1784219089Spjd } 1785219089Spjd addrs = rtm->rtm_addrs; 1786219089Spjd q = (char *)(rtm + 1); 1787219089Spjd if (rtm->rtm_pid == pid) { 1788219089Spjd#if 0 1789219089Spjd trace(1, "rtmsg looped back to me, ignored\n"); 1790219089Spjd#endif 1791219089Spjd continue; 1792219089Spjd } 1793219089Spjd break; 1794219089Spjd } 1795219089Spjd memset(&rta, 0, sizeof(rta)); 1796219089Spjd for (i = 0; i < RTAX_MAX; i++) { 1797219089Spjd if (addrs & (1 << i)) { 1798219089Spjd rta[i] = (struct sockaddr_in6 *)(void *)q; 1799219089Spjd q += ROUNDUP(rta[i]->sin6_len); 1800219089Spjd } 1801219089Spjd } 1802219089Spjd 1803219089Spjd trace(1, "rtsock: %s (addrs=%x)\n", 1804219089Spjd rttypes((struct rt_msghdr *)(void *)p), addrs); 1805219089Spjd if (dflag >= 2) { 1806219089Spjd for (i = 0; 1807219089Spjd i < ((struct rt_msghdr *)(void *)p)->rtm_msglen; 1808219089Spjd i++) { 1809219089Spjd fprintf(stderr, "%02x ", p[i] & 0xff); 1810219089Spjd if (i % 16 == 15) fprintf(stderr, "\n"); 1811219089Spjd } 1812219089Spjd fprintf(stderr, "\n"); 1813219089Spjd } 1814219089Spjd 1815219089Spjd /* 1816219089Spjd * Easy ones first. 1817219089Spjd * 1818219089Spjd * We may be able to optimize by using ifm->ifm_index or 1819219089Spjd * ifam->ifam_index. For simplicity we don't do that here. 1820248571Smm */ 1821219089Spjd switch (((struct rt_msghdr *)(void *)p)->rtm_type) { 1822248571Smm case RTM_NEWADDR: 1823248571Smm case RTM_IFINFO: 1824248571Smm iface++; 1825219089Spjd continue; 1826219089Spjd case RTM_ADD: 1827219089Spjd rtable++; 1828219089Spjd continue; 1829219089Spjd case RTM_LOSING: 1830219089Spjd case RTM_MISS: 1831219089Spjd case RTM_GET: 1832219089Spjd case RTM_LOCK: 1833219089Spjd /* nothing to be done here */ 1834219089Spjd trace(1, "\tnothing to be done, ignored\n"); 1835219089Spjd continue; 1836219089Spjd } 1837219089Spjd 1838219089Spjd#if 0 1839219089Spjd if (rta[RTAX_DST] == NULL) { 1840219089Spjd trace(1, "\tno destination, ignored\n"); 1841219089Spjd continue; 1842219089Spjd } 1843219089Spjd if (rta[RTAX_DST]->sin6_family != AF_INET6) { 1844219089Spjd trace(1, "\taf mismatch, ignored\n"); 1845219089Spjd continue; 1846219089Spjd } 1847219089Spjd if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) { 1848219089Spjd trace(1, "\tlinklocal destination, ignored\n"); 1849219089Spjd continue; 1850219089Spjd } 1851219089Spjd if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) { 1852219089Spjd trace(1, "\tloopback destination, ignored\n"); 1853219089Spjd continue; /* Loopback */ 1854219089Spjd } 1855219089Spjd if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) { 1856219089Spjd trace(1, "\tmulticast destination, ignored\n"); 1857219089Spjd continue; 1858219089Spjd } 1859219089Spjd#endif 1860219089Spjd 1861219089Spjd /* hard ones */ 1862219089Spjd switch (((struct rt_msghdr *)(void *)p)->rtm_type) { 1863219089Spjd case RTM_NEWADDR: 1864219089Spjd case RTM_IFINFO: 1865219089Spjd case RTM_ADD: 1866219089Spjd case RTM_LOSING: 1867219089Spjd case RTM_MISS: 1868219089Spjd case RTM_GET: 1869219089Spjd case RTM_LOCK: 1870268720Sdelphij /* should already be handled */ 1871219089Spjd fatal("rtrecv: never reach here"); 1872219089Spjd /*NOTREACHED*/ 1873236884Smm case RTM_DELETE: 1874219089Spjd if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) { 1875219089Spjd trace(1, "\tsome of dst/gw/netamsk are " 1876219089Spjd "unavailable, ignored\n"); 1877219089Spjd break; 1878219089Spjd } 1879219089Spjd if ((rtm->rtm_flags & RTF_HOST) != 0) { 1880268720Sdelphij mask.sin6_len = sizeof(mask); 1881268720Sdelphij memset(&mask.sin6_addr, 0xff, 1882268720Sdelphij sizeof(mask.sin6_addr)); 1883268720Sdelphij rta[RTAX_NETMASK] = &mask; 1884268720Sdelphij } else if (!rta[RTAX_NETMASK]) { 1885219089Spjd trace(1, "\tsome of dst/gw/netamsk are " 1886219089Spjd "unavailable, ignored\n"); 1887268720Sdelphij break; 1888268720Sdelphij } 1889268720Sdelphij if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY], 1890268720Sdelphij rta[RTAX_NETMASK]) == 0) { 1891268720Sdelphij rtable++; /*just to be sure*/ 1892268720Sdelphij } 1893268720Sdelphij break; 1894268720Sdelphij case RTM_CHANGE: 1895268720Sdelphij case RTM_REDIRECT: 1896268720Sdelphij trace(1, "\tnot supported yet, ignored\n"); 1897268720Sdelphij break; 1898268720Sdelphij case RTM_DELADDR: 1899268720Sdelphij if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) { 1900268720Sdelphij trace(1, "\tno netmask or ifa given, ignored\n"); 1901268720Sdelphij break; 1902268720Sdelphij } 1903268720Sdelphij if (ifam->ifam_index < nindex2ifc) 1904268720Sdelphij ifcp = index2ifc[ifam->ifam_index]; 1905268720Sdelphij else 1906268720Sdelphij ifcp = NULL; 1907268720Sdelphij if (!ifcp) { 1908219089Spjd trace(1, "\tinvalid ifam_index %d, ignored\n", 1909219089Spjd ifam->ifam_index); 1910219089Spjd break; 1911268123Sdelphij } 1912219089Spjd if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK])) 1913268720Sdelphij iface++; 1914268720Sdelphij break; 1915268720Sdelphij } 1916268720Sdelphij 1917268720Sdelphij } 1918268720Sdelphij 1919268720Sdelphij if (iface) { 1920268720Sdelphij trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n"); 1921268720Sdelphij ifconfig(); 1922268720Sdelphij TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 1923268720Sdelphij if (ifcp->ifc_cflags & IFC_CHANGED) { 1924219089Spjd if (ifrt(ifcp, 1)) { 1925268720Sdelphij TAILQ_FOREACH(ic, &ifc_head, ifc_next) { 1926268720Sdelphij if (ifcp->ifc_index == ic->ifc_index) 1927268720Sdelphij continue; 1928268720Sdelphij if (ic->ifc_flags & IFF_UP) 1929268720Sdelphij ripsend(ic, &ic->ifc_ripsin, 1930268720Sdelphij RRTF_CHANGED); 1931268720Sdelphij } 1932268720Sdelphij /* Reset the flag */ 1933268720Sdelphij TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 1934268720Sdelphij rrt->rrt_rflags &= ~RRTF_CHANGED; 1935268720Sdelphij } 1936268720Sdelphij } 1937268720Sdelphij ifcp->ifc_cflags &= ~IFC_CHANGED; 1938268720Sdelphij } 1939219089Spjd } 1940219089Spjd } 1941219089Spjd if (rtable) { 1942219089Spjd trace(1, "rtsock: read routing table again\n"); 1943219089Spjd krtread(1); 1944219089Spjd } 1945219089Spjd} 1946219089Spjd 1947219089Spjd/* 1948219089Spjd * remove specified route from the internal routing table. 1949268720Sdelphij */ 1950219089Spjdstatic int 1951219089Spjdrt_del(const struct sockaddr_in6 *sdst, 1952219089Spjd const struct sockaddr_in6 *sgw, 1953219089Spjd const struct sockaddr_in6 *smask) 1954219089Spjd{ 1955219089Spjd const struct in6_addr *dst = NULL; 1956219089Spjd const struct in6_addr *gw = NULL; 1957219089Spjd int prefix; 1958219089Spjd struct netinfo6 ni6; 1959268720Sdelphij struct riprt *rrt = NULL; 1960268720Sdelphij time_t t_lifetime; 1961268720Sdelphij 1962268720Sdelphij if (sdst->sin6_family != AF_INET6) { 1963268720Sdelphij trace(1, "\tother AF, ignored\n"); 1964219089Spjd return -1; 1965219089Spjd } 1966219089Spjd if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr) 1967219089Spjd || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback) 1968219089Spjd || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) { 1969219089Spjd trace(1, "\taddress %s not interesting, ignored\n", 1970219089Spjd inet6_n2p(&sdst->sin6_addr)); 1971219089Spjd return -1; 1972219089Spjd } 1973219089Spjd dst = &sdst->sin6_addr; 1974219089Spjd if (sgw->sin6_family == AF_INET6) { 1975219089Spjd /* easy case */ 1976219089Spjd gw = &sgw->sin6_addr; 1977219089Spjd prefix = sin6mask2len(smask); 1978219089Spjd } else if (sgw->sin6_family == AF_LINK) { 1979219089Spjd /* 1980219089Spjd * Interface route... a hard case. We need to get the prefix 1981219089Spjd * length from the kernel, but we now are parsing rtmsg. 1982219089Spjd * We'll purge matching routes from my list, then get the 1983219089Spjd * fresh list. 1984219089Spjd */ 1985219089Spjd struct riprt *longest; 1986219089Spjd trace(1, "\t%s is an interface route, guessing prefixlen\n", 1987219089Spjd inet6_n2p(dst)); 1988219089Spjd longest = NULL; 1989219089Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 1990219089Spjd if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 1991249195Smm &sdst->sin6_addr) 1992219089Spjd && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) { 1993219089Spjd if (!longest 1994219089Spjd || longest->rrt_info.rip6_plen < 1995219089Spjd rrt->rrt_info.rip6_plen) { 1996219089Spjd longest = rrt; 1997219089Spjd } 1998185029Spjd } 1999219089Spjd } 2000168404Spjd rrt = longest; 2001219089Spjd if (!rrt) { 2002219089Spjd trace(1, "\tno matching interface route found\n"); 2003219089Spjd return -1; 2004219089Spjd } 2005219089Spjd gw = &in6addr_loopback; 2006219089Spjd prefix = rrt->rrt_info.rip6_plen; 2007219089Spjd } else { 2008219089Spjd trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family); 2009219089Spjd return -1; 2010219089Spjd } 2011168404Spjd 2012219089Spjd trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix); 2013168404Spjd trace(1, "gw %s\n", inet6_n2p(gw)); 2014219089Spjd t_lifetime = time(NULL) - RIP_LIFETIME; 2015219089Spjd /* age route for interface address */ 2016219089Spjd memset(&ni6, 0, sizeof(ni6)); 2017168404Spjd ni6.rip6_dest = *dst; 2018219089Spjd ni6.rip6_plen = prefix; 2019219089Spjd applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 2020219089Spjd trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest), 2021219089Spjd ni6.rip6_plen); 2022219089Spjd if (!rrt && (rrt = rtsearch(&ni6)) == NULL) { 2023219089Spjd trace(1, "\tno route found\n"); 2024219089Spjd return -1; 2025219089Spjd } 2026219089Spjd#if 0 2027219089Spjd if ((rrt->rrt_flags & RTF_STATIC) == 0) { 2028219089Spjd trace(1, "\tyou can delete static routes only\n"); 2029219089Spjd } else 2030219089Spjd#endif 2031219089Spjd if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) { 2032219089Spjd trace(1, "\tgw mismatch: %s <-> ", 2033219089Spjd inet6_n2p(&rrt->rrt_gw)); 2034219089Spjd trace(1, "%s\n", inet6_n2p(gw)); 2035219089Spjd } else { 2036219089Spjd trace(1, "\troute found, age it\n"); 2037219089Spjd if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 2038219089Spjd rrt->rrt_t = t_lifetime; 2039219089Spjd rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 2040219089Spjd } 2041219089Spjd } 2042219089Spjd return 0; 2043219089Spjd} 2044219089Spjd 2045219089Spjd/* 2046219089Spjd * remove specified address from internal interface/routing table. 2047219089Spjd */ 2048219089Spjdstatic int 2049219089Spjdrt_deladdr(struct ifc *ifcp, 2050219089Spjd const struct sockaddr_in6 *sifa, 2051219089Spjd const struct sockaddr_in6 *smask) 2052219089Spjd{ 2053219089Spjd const struct in6_addr *addr = NULL; 2054219089Spjd int prefix; 2055219089Spjd struct ifac *ifac = NULL; 2056219089Spjd struct netinfo6 ni6; 2057219089Spjd struct riprt *rrt = NULL; 2058219089Spjd time_t t_lifetime; 2059219089Spjd int updated = 0; 2060219089Spjd 2061219089Spjd if (sifa->sin6_family != AF_INET6) { 2062219089Spjd trace(1, "\tother AF, ignored\n"); 2063219089Spjd return -1; 2064219089Spjd } 2065219089Spjd addr = &sifa->sin6_addr; 2066219089Spjd prefix = sin6mask2len(smask); 2067219089Spjd 2068219089Spjd trace(1, "\tdeleting %s/%d from %s\n", 2069219089Spjd inet6_n2p(addr), prefix, ifcp->ifc_name); 2070219089Spjd ifac = ifa_match(ifcp, addr, prefix); 2071219089Spjd if (!ifac) { 2072219089Spjd trace(1, "\tno matching ifa found for %s/%d on %s\n", 2073219089Spjd inet6_n2p(addr), prefix, ifcp->ifc_name); 2074219089Spjd return -1; 2075219089Spjd } 2076219089Spjd if (ifac->ifac_ifc != ifcp) { 2077219089Spjd trace(1, "\taddress table corrupt: back pointer does not match " 2078219089Spjd "(%s != %s)\n", 2079219089Spjd ifcp->ifc_name, ifac->ifac_ifc->ifc_name); 2080219089Spjd return -1; 2081219089Spjd } 2082219089Spjd TAILQ_REMOVE(&ifcp->ifc_ifac_head, ifac, ifac_next); 2083219089Spjd t_lifetime = time(NULL) - RIP_LIFETIME; 2084219089Spjd /* age route for interface address */ 2085219089Spjd memset(&ni6, 0, sizeof(ni6)); 2086219089Spjd ni6.rip6_dest = ifac->ifac_addr; 2087219089Spjd ni6.rip6_plen = ifac->ifac_plen; 2088219089Spjd applyplen(&ni6.rip6_dest, ni6.rip6_plen); 2089219089Spjd trace(1, "\tfind interface route %s/%d on %d\n", 2090219089Spjd inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index); 2091219089Spjd if ((rrt = rtsearch(&ni6)) != NULL) { 2092209962Smm struct in6_addr none; 2093219089Spjd memset(&none, 0, sizeof(none)); 2094219089Spjd if (rrt->rrt_index == ifcp->ifc_index && 2095219089Spjd (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) || 2096209962Smm IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) { 2097219089Spjd trace(1, "\troute found, age it\n"); 2098219089Spjd if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 2099219089Spjd rrt->rrt_t = t_lifetime; 2100219089Spjd rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 2101219089Spjd } 2102219089Spjd updated++; 2103209962Smm } else { 2104219089Spjd trace(1, "\tnon-interface route found: %s/%d on %d\n", 2105219089Spjd inet6_n2p(&rrt->rrt_info.rip6_dest), 2106185029Spjd rrt->rrt_info.rip6_plen, 2107219089Spjd rrt->rrt_index); 2108219089Spjd } 2109219089Spjd } else 2110219089Spjd trace(1, "\tno interface route found\n"); 2111219089Spjd /* age route for p2p destination */ 2112219089Spjd if (ifcp->ifc_flags & IFF_POINTOPOINT) { 2113228103Smm memset(&ni6, 0, sizeof(ni6)); 2114219089Spjd ni6.rip6_dest = ifac->ifac_raddr; 2115219089Spjd ni6.rip6_plen = 128; 2116219089Spjd applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/ 2117168404Spjd trace(1, "\tfind p2p route %s/%d on %d\n", 2118219089Spjd inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, 2119249195Smm ifcp->ifc_index); 2120168404Spjd if ((rrt = rtsearch(&ni6)) != NULL) { 2121228103Smm if (rrt->rrt_index == ifcp->ifc_index && 2122228103Smm IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, 2123228103Smm &ifac->ifac_addr)) { 2124228103Smm trace(1, "\troute found, age it\n"); 2125168404Spjd if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) { 2126168404Spjd rrt->rrt_t = t_lifetime; 2127168404Spjd rrt->rrt_info.rip6_metric = 2128168404Spjd HOPCNT_INFINITY6; 2129219089Spjd updated++; 2130219089Spjd } 2131219089Spjd } else { 2132168404Spjd trace(1, "\tnon-p2p route found: %s/%d on %d\n", 2133168404Spjd inet6_n2p(&rrt->rrt_info.rip6_dest), 2134168404Spjd rrt->rrt_info.rip6_plen, 2135168404Spjd rrt->rrt_index); 2136168404Spjd } 2137168404Spjd } else 2138249195Smm trace(1, "\tno p2p route found\n"); 2139219089Spjd } 2140228103Smm free(ifac); 2141219089Spjd 2142219089Spjd return ((updated) ? 0 : -1); 2143219089Spjd} 2144219089Spjd 2145219089Spjd/* 2146219089Spjd * Get each interface address and put those interface routes to the route 2147219089Spjd * list. 2148236884Smm */ 2149236884Smmstatic int 2150236884Smmifrt(struct ifc *ifcp, int again) 2151219089Spjd{ 2152219089Spjd struct ifac *ifac; 2153219089Spjd struct riprt *rrt = NULL, *search_rrt, *loop_rrt; 2154168404Spjd struct netinfo6 *np; 2155168404Spjd time_t t_lifetime; 2156219089Spjd int need_trigger = 0; 2157219089Spjd 2158219089Spjd#if 0 2159219089Spjd if (ifcp->ifc_flags & IFF_LOOPBACK) 2160219089Spjd return 0; /* ignore loopback */ 2161219089Spjd#endif 2162219089Spjd 2163219089Spjd if (ifcp->ifc_flags & IFF_POINTOPOINT) { 2164219089Spjd ifrt_p2p(ifcp, again); 2165219089Spjd return 0; 2166219089Spjd } 2167219089Spjd 2168168404Spjd TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { 2169219089Spjd if (IN6_IS_ADDR_LINKLOCAL(&ifac->ifac_addr)) { 2170219089Spjd#if 0 2171219089Spjd trace(1, "route: %s on %s: " 2172219089Spjd "skip linklocal interface address\n", 2173219089Spjd inet6_n2p(&ifac->ifac_addr), ifcp->ifc_name); 2174219089Spjd#endif 2175219089Spjd continue; 2176219089Spjd } 2177219089Spjd if (IN6_IS_ADDR_UNSPECIFIED(&ifac->ifac_addr)) { 2178219089Spjd#if 0 2179219089Spjd trace(1, "route: %s: skip unspec interface address\n", 2180219089Spjd ifcp->ifc_name); 2181219089Spjd#endif 2182219089Spjd continue; 2183236884Smm } 2184219089Spjd if (IN6_IS_ADDR_LOOPBACK(&ifac->ifac_addr)) { 2185219089Spjd#if 0 2186219089Spjd trace(1, "route: %s: skip loopback address\n", 2187219089Spjd ifcp->ifc_name); 2188219089Spjd#endif 2189219089Spjd continue; 2190236884Smm } 2191219089Spjd if (ifcp->ifc_flags & IFF_UP) { 2192168404Spjd if ((rrt = MALLOC(struct riprt)) == NULL) 2193219089Spjd fatal("malloc: struct riprt"); 2194219089Spjd memset(rrt, 0, sizeof(*rrt)); 2195219089Spjd rrt->rrt_same = NULL; 2196219089Spjd rrt->rrt_index = ifcp->ifc_index; 2197219089Spjd rrt->rrt_t = 0; /* don't age */ 2198219089Spjd rrt->rrt_info.rip6_dest = ifac->ifac_addr; 2199219089Spjd rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 2200219089Spjd rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 2201219089Spjd rrt->rrt_info.rip6_plen = ifac->ifac_plen; 2202219089Spjd rrt->rrt_flags = RTF_HOST; 2203219089Spjd rrt->rrt_rflags |= RRTF_CHANGED; 2204249195Smm applyplen(&rrt->rrt_info.rip6_dest, ifac->ifac_plen); 2205219089Spjd memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2206219089Spjd rrt->rrt_gw = ifac->ifac_addr; 2207219089Spjd np = &rrt->rrt_info; 2208219089Spjd search_rrt = rtsearch(np); 2209219089Spjd if (search_rrt != NULL) { 2210209962Smm if (search_rrt->rrt_info.rip6_metric <= 2211209962Smm rrt->rrt_info.rip6_metric) { 2212209962Smm /* Already have better route */ 2213209962Smm if (!again) { 2214209962Smm trace(1, "route: %s/%d: " 2215209962Smm "already registered (%s)\n", 2216168404Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, 2217168404Spjd ifcp->ifc_name); 2218168404Spjd } 2219168404Spjd goto next; 2220185029Spjd } 2221219089Spjd 2222185029Spjd TAILQ_REMOVE(&riprt_head, search_rrt, rrt_next); 2223168404Spjd delroute(&search_rrt->rrt_info, 2224168404Spjd &search_rrt->rrt_gw); 2225219089Spjd free(search_rrt); 2226168404Spjd } 2227168404Spjd /* Attach the route to the list */ 2228168404Spjd trace(1, "route: %s/%d: register route (%s)\n", 2229219089Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, 2230219089Spjd ifcp->ifc_name); 2231219089Spjd TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); 2232219089Spjd addroute(rrt, &rrt->rrt_gw, ifcp); 2233168404Spjd rrt = NULL; 2234168404Spjd sendrequest(ifcp); 2235168404Spjd ripsend(ifcp, &ifcp->ifc_ripsin, 0); 2236185029Spjd need_trigger = 1; 2237168926Spjd } else { 2238185029Spjd TAILQ_FOREACH(loop_rrt, &riprt_head, rrt_next) { 2239168926Spjd if (loop_rrt->rrt_index == ifcp->ifc_index) { 2240219089Spjd t_lifetime = time(NULL) - RIP_LIFETIME; 2241168404Spjd if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) { 2242168404Spjd loop_rrt->rrt_t = t_lifetime; 2243209962Smm loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6; 2244209962Smm loop_rrt->rrt_rflags |= RRTF_CHANGED; 2245209962Smm need_trigger = 1; 2246219089Spjd } 2247209962Smm } 2248209962Smm } 2249209962Smm } 2250219089Spjd next: 2251219089Spjd if (rrt) 2252219089Spjd free(rrt); 2253219089Spjd } 2254168404Spjd return need_trigger; 2255219089Spjd} 2256219089Spjd 2257230514Smm/* 2258219089Spjd * there are couple of p2p interface routing models. "behavior" lets 2259168404Spjd * you pick one. it looks that gated behavior fits best with BSDs, 2260219089Spjd * since BSD kernels do not look at prefix length on p2p interfaces. 2261219089Spjd */ 2262219089Spjdstatic void 2263219089Spjdifrt_p2p(struct ifc *ifcp, int again) 2264249195Smm{ 2265168404Spjd struct ifac *ifac; 2266168404Spjd struct riprt *rrt, *orrt; 2267168404Spjd struct netinfo6 *np; 2268168404Spjd struct in6_addr addr, dest; 2269168404Spjd int advert, ignore, i; 2270236884Smm#define P2PADVERT_NETWORK 1 2271168404Spjd#define P2PADVERT_ADDR 2 2272168404Spjd#define P2PADVERT_DEST 4 2273168404Spjd#define P2PADVERT_MAX 4 2274168404Spjd const enum { CISCO, GATED, ROUTE6D } behavior = GATED; 2275236884Smm const char *category = ""; 2276236884Smm const char *noadv; 2277219089Spjd 2278236884Smm TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { 2279168404Spjd addr = ifac->ifac_addr; 2280168404Spjd dest = ifac->ifac_raddr; 2281236884Smm applyplen(&addr, ifac->ifac_plen); 2282168404Spjd applyplen(&dest, ifac->ifac_plen); 2283236884Smm advert = ignore = 0; 2284236884Smm switch (behavior) { 2285219089Spjd case CISCO: 2286236884Smm /* 2287168404Spjd * honor addr/plen, just like normal shared medium 2288236884Smm * interface. this may cause trouble if you reuse 2289236884Smm * addr/plen on other interfaces. 2290236884Smm * 2291236884Smm * advertise addr/plen. 2292236884Smm */ 2293236884Smm advert |= P2PADVERT_NETWORK; 2294236884Smm break; 2295236884Smm case GATED: 2296236884Smm /* 2297236884Smm * prefixlen on p2p interface is meaningless. 2298236884Smm * advertise addr/128 and dest/128. 2299236884Smm * 2300236884Smm * do not install network route to route6d routing 2301236884Smm * table (if we do, it would prevent route installation 2302236884Smm * for other p2p interface that shares addr/plen). 2303236884Smm * 2304236884Smm * XXX what should we do if dest is ::? it will not 2305236884Smm * get announced anyways (see following filter), 2306236884Smm * but we need to think. 2307236884Smm */ 2308236884Smm advert |= P2PADVERT_ADDR; 2309236884Smm advert |= P2PADVERT_DEST; 2310236884Smm ignore |= P2PADVERT_NETWORK; 2311236884Smm break; 2312168404Spjd case ROUTE6D: 2313236884Smm /* 2314236884Smm * just for testing. actually the code is redundant 2315236884Smm * given the current p2p interface address assignment 2316236884Smm * rule for kame kernel. 2317236884Smm * 2318236884Smm * intent: 2319236884Smm * A/n -> announce A/n 2320236884Smm * A B/n, A and B share prefix -> A/n (= B/n) 2321236884Smm * A B/n, do not share prefix -> A/128 and B/128 2322236884Smm * actually, A/64 and A B/128 are the only cases 2323236884Smm * permitted by the kernel: 2324236884Smm * A/64 -> A/64 2325236884Smm * A B/128 -> A/128 and B/128 2326236884Smm */ 2327236884Smm if (!IN6_IS_ADDR_UNSPECIFIED(&ifac->ifac_raddr)) { 2328236884Smm if (IN6_ARE_ADDR_EQUAL(&addr, &dest)) 2329236884Smm advert |= P2PADVERT_NETWORK; 2330236884Smm else { 2331236884Smm advert |= P2PADVERT_ADDR; 2332236884Smm advert |= P2PADVERT_DEST; 2333236884Smm ignore |= P2PADVERT_NETWORK; 2334236884Smm } 2335236884Smm } else 2336236884Smm advert |= P2PADVERT_NETWORK; 2337236884Smm break; 2338236884Smm } 2339236884Smm 2340236884Smm for (i = 1; i <= P2PADVERT_MAX; i *= 2) { 2341236884Smm if ((ignore & i) != 0) 2342236884Smm continue; 2343236884Smm if ((rrt = MALLOC(struct riprt)) == NULL) { 2344168404Spjd fatal("malloc: struct riprt"); 2345219089Spjd /*NOTREACHED*/ 2346219089Spjd } 2347219089Spjd memset(rrt, 0, sizeof(*rrt)); 2348219089Spjd rrt->rrt_same = NULL; 2349168404Spjd rrt->rrt_index = ifcp->ifc_index; 2350219089Spjd rrt->rrt_t = 0; /* don't age */ 2351219089Spjd switch (i) { 2352219089Spjd case P2PADVERT_NETWORK: 2353219089Spjd rrt->rrt_info.rip6_dest = ifac->ifac_addr; 2354219089Spjd rrt->rrt_info.rip6_plen = ifac->ifac_plen; 2355219089Spjd applyplen(&rrt->rrt_info.rip6_dest, 2356219089Spjd ifac->ifac_plen); 2357219089Spjd category = "network"; 2358219089Spjd break; 2359219089Spjd case P2PADVERT_ADDR: 2360219089Spjd rrt->rrt_info.rip6_dest = ifac->ifac_addr; 2361168404Spjd rrt->rrt_info.rip6_plen = 128; 2362168404Spjd rrt->rrt_gw = in6addr_loopback; 2363168404Spjd category = "addr"; 2364168404Spjd break; 2365168404Spjd case P2PADVERT_DEST: 2366168404Spjd rrt->rrt_info.rip6_dest = ifac->ifac_raddr; 2367168404Spjd rrt->rrt_info.rip6_plen = 128; 2368219089Spjd rrt->rrt_gw = ifac->ifac_addr; 2369219089Spjd category = "dest"; 2370219089Spjd break; 2371219089Spjd } 2372219089Spjd if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) || 2373219089Spjd IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) { 2374219089Spjd#if 0 2375236884Smm trace(1, "route: %s: skip unspec/linklocal " 2376219089Spjd "(%s on %s)\n", category, ifcp->ifc_name); 2377219089Spjd#endif 2378168404Spjd free(rrt); 2379168404Spjd continue; 2380219089Spjd } 2381219089Spjd if ((advert & i) == 0) { 2382168404Spjd rrt->rrt_rflags |= RRTF_NOADVERTISE; 2383236884Smm noadv = ", NO-ADV"; 2384236884Smm } else 2385238926Smm noadv = ""; 2386236884Smm rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 2387236884Smm rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric; 2388236884Smm np = &rrt->rrt_info; 2389236884Smm orrt = rtsearch(np); 2390236884Smm if (!orrt) { 2391236884Smm /* Attach the route to the list */ 2392236884Smm trace(1, "route: %s/%d: register route " 2393236884Smm "(%s on %s%s)\n", 2394236884Smm inet6_n2p(&np->rip6_dest), np->rip6_plen, 2395236884Smm category, ifcp->ifc_name, noadv); 2396236884Smm TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); 2397236884Smm } else if (rrt->rrt_index != orrt->rrt_index || 2398236884Smm rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) { 2399236884Smm /* replace route */ 2400236884Smm TAILQ_INSERT_BEFORE(orrt, rrt, rrt_next); 2401236884Smm TAILQ_REMOVE(&riprt_head, orrt, rrt_next); 2402238926Smm free(orrt); 2403238926Smm 2404236884Smm trace(1, "route: %s/%d: update (%s on %s%s)\n", 2405259813Sdelphij inet6_n2p(&np->rip6_dest), np->rip6_plen, 2406238926Smm category, ifcp->ifc_name, noadv); 2407236884Smm } else { 2408236884Smm /* Already found */ 2409236884Smm if (!again) { 2410259813Sdelphij trace(1, "route: %s/%d: " 2411238926Smm "already registered (%s on %s%s)\n", 2412236884Smm inet6_n2p(&np->rip6_dest), 2413238926Smm np->rip6_plen, category, 2414236884Smm ifcp->ifc_name, noadv); 2415236884Smm } 2416238926Smm free(rrt); 2417238926Smm } 2418238926Smm } 2419236884Smm } 2420238926Smm#undef P2PADVERT_NETWORK 2421238926Smm#undef P2PADVERT_ADDR 2422236884Smm#undef P2PADVERT_DEST 2423236884Smm#undef P2PADVERT_MAX 2424238926Smm} 2425238926Smm 2426236884Smmstatic int 2427236884Smmgetifmtu(int ifindex) 2428236884Smm{ 2429236884Smm int mib[6]; 2430236884Smm char *buf; 2431236884Smm size_t msize; 2432236884Smm struct if_msghdr *ifm; 2433236884Smm int mtu; 2434236884Smm 2435236884Smm mib[0] = CTL_NET; 2436236884Smm mib[1] = PF_ROUTE; 2437236884Smm mib[2] = 0; 2438236884Smm mib[3] = AF_INET6; 2439236884Smm mib[4] = NET_RT_IFLIST; 2440236884Smm mib[5] = ifindex; 2441236884Smm if (sysctl(mib, nitems(mib), NULL, &msize, NULL, 0) < 0) { 2442236884Smm fatal("sysctl estimate NET_RT_IFLIST"); 2443236884Smm /*NOTREACHED*/ 2444236884Smm } 2445236884Smm if ((buf = malloc(msize)) == NULL) { 2446236884Smm fatal("malloc"); 2447236884Smm /*NOTREACHED*/ 2448236884Smm } 2449236884Smm if (sysctl(mib, nitems(mib), buf, &msize, NULL, 0) < 0) { 2450236884Smm fatal("sysctl NET_RT_IFLIST"); 2451236884Smm /*NOTREACHED*/ 2452236884Smm } 2453236884Smm ifm = (struct if_msghdr *)(void *)buf; 2454236884Smm mtu = ifm->ifm_data.ifi_mtu; 2455236884Smm if (ifindex != ifm->ifm_index) { 2456260150Sdelphij fatal("ifindex does not match with ifm_index"); 2457260150Sdelphij /*NOTREACHED*/ 2458260150Sdelphij } 2459260150Sdelphij free(buf); 2460260150Sdelphij return mtu; 2461260150Sdelphij} 2462260150Sdelphij 2463260150Sdelphijstatic const char * 2464260150Sdelphijrttypes(struct rt_msghdr *rtm) 2465260150Sdelphij{ 2466260150Sdelphij#define RTTYPE(s, f) \ 2467260150Sdelphijdo { \ 2468260150Sdelphij if (rtm->rtm_type == (f)) \ 2469260150Sdelphij return (s); \ 2470260150Sdelphij} while (0) 2471260150Sdelphij RTTYPE("ADD", RTM_ADD); 2472260150Sdelphij RTTYPE("DELETE", RTM_DELETE); 2473260150Sdelphij RTTYPE("CHANGE", RTM_CHANGE); 2474260150Sdelphij RTTYPE("GET", RTM_GET); 2475260150Sdelphij RTTYPE("LOSING", RTM_LOSING); 2476236884Smm RTTYPE("REDIRECT", RTM_REDIRECT); 2477236884Smm RTTYPE("MISS", RTM_MISS); 2478260150Sdelphij RTTYPE("LOCK", RTM_LOCK); 2479260150Sdelphij RTTYPE("NEWADDR", RTM_NEWADDR); 2480268075Sdelphij RTTYPE("DELADDR", RTM_DELADDR); 2481260150Sdelphij RTTYPE("IFINFO", RTM_IFINFO); 2482260150Sdelphij#ifdef RTM_OIFINFO 2483260150Sdelphij RTTYPE("OIFINFO", RTM_OIFINFO); 2484236884Smm#endif 2485236884Smm#ifdef RTM_IFANNOUNCE 2486236884Smm RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE); 2487236884Smm#endif 2488236884Smm#ifdef RTM_NEWMADDR 2489236884Smm RTTYPE("NEWMADDR", RTM_NEWMADDR); 2490168404Spjd#endif 2491168498Spjd#ifdef RTM_DELMADDR 2492219089Spjd RTTYPE("DELMADDR", RTM_DELMADDR); 2493168404Spjd#endif 2494219089Spjd#undef RTTYPE 2495219089Spjd return NULL; 2496168404Spjd} 2497219089Spjd 2498185029Spjdstatic const char * 2499168498Spjdrtflags(struct rt_msghdr *rtm) 2500168498Spjd{ 2501168498Spjd static char buf[BUFSIZ]; 2502219089Spjd 2503168498Spjd /* 2504168498Spjd * letter conflict should be okay. painful when *BSD diverges... 2505219089Spjd */ 2506219089Spjd strlcpy(buf, "", sizeof(buf)); 2507219089Spjd#define RTFLAG(s, f) \ 2508219089Spjddo { \ 2509219089Spjd if (rtm->rtm_flags & (f)) \ 2510219089Spjd strlcat(buf, (s), sizeof(buf)); \ 2511219089Spjd} while (0) 2512168498Spjd RTFLAG("U", RTF_UP); 2513219089Spjd RTFLAG("G", RTF_GATEWAY); 2514204073Spjd RTFLAG("H", RTF_HOST); 2515219089Spjd RTFLAG("R", RTF_REJECT); 2516219089Spjd RTFLAG("D", RTF_DYNAMIC); 2517168498Spjd RTFLAG("M", RTF_MODIFIED); 2518168498Spjd RTFLAG("d", RTF_DONE); 2519185029Spjd#ifdef RTF_MASK 2520236146Smm RTFLAG("m", RTF_MASK); 2521185029Spjd#endif 2522168498Spjd#ifdef RTF_CLONED 2523249195Smm RTFLAG("c", RTF_CLONED); 2524168498Spjd#endif 2525168498Spjd RTFLAG("X", RTF_XRESOLVE); 2526219089Spjd#ifdef RTF_LLINFO 2527219089Spjd RTFLAG("L", RTF_LLINFO); 2528219089Spjd#endif 2529219089Spjd RTFLAG("S", RTF_STATIC); 2530168498Spjd RTFLAG("B", RTF_BLACKHOLE); 2531219089Spjd#ifdef RTF_PROTO3 2532168404Spjd RTFLAG("3", RTF_PROTO3); 2533168404Spjd#endif 2534209962Smm RTFLAG("2", RTF_PROTO2); 2535168404Spjd RTFLAG("1", RTF_PROTO1); 2536219089Spjd#ifdef RTF_BROADCAST 2537168404Spjd RTFLAG("b", RTF_BROADCAST); 2538168404Spjd#endif 2539219089Spjd#ifdef RTF_DEFAULT 2540219089Spjd RTFLAG("d", RTF_DEFAULT); 2541219089Spjd#endif 2542219089Spjd#ifdef RTF_ISAROUTER 2543219089Spjd RTFLAG("r", RTF_ISAROUTER); 2544168404Spjd#endif 2545168404Spjd#ifdef RTF_TUNNEL 2546168404Spjd RTFLAG("T", RTF_TUNNEL); 2547168404Spjd#endif 2548168404Spjd#ifdef RTF_AUTH 2549168404Spjd RTFLAG("A", RTF_AUTH); 2550219089Spjd#endif 2551219089Spjd#ifdef RTF_CRYPT 2552219089Spjd RTFLAG("E", RTF_CRYPT); 2553168404Spjd#endif 2554219089Spjd#undef RTFLAG 2555219089Spjd return buf; 2556219089Spjd} 2557219089Spjd 2558219089Spjdstatic const char * 2559168404Spjdifflags(int flags) 2560168404Spjd{ 2561168404Spjd static char buf[BUFSIZ]; 2562168404Spjd 2563219089Spjd strlcpy(buf, "", sizeof(buf)); 2564219089Spjd#define IFFLAG(s, f) \ 2565219089Spjddo { \ 2566168404Spjd if (flags & (f)) { \ 2567219089Spjd if (buf[0]) \ 2568219089Spjd strlcat(buf, ",", sizeof(buf)); \ 2569219089Spjd strlcat(buf, (s), sizeof(buf)); \ 2570219089Spjd } \ 2571168404Spjd} while (0) 2572168404Spjd IFFLAG("UP", IFF_UP); 2573168404Spjd IFFLAG("BROADCAST", IFF_BROADCAST); 2574168404Spjd IFFLAG("DEBUG", IFF_DEBUG); 2575168404Spjd IFFLAG("LOOPBACK", IFF_LOOPBACK); 2576219089Spjd IFFLAG("POINTOPOINT", IFF_POINTOPOINT); 2577219089Spjd#ifdef IFF_NOTRAILERS 2578219089Spjd IFFLAG("NOTRAILERS", IFF_NOTRAILERS); 2579168404Spjd#endif 2580168404Spjd IFFLAG("RUNNING", IFF_RUNNING); 2581219089Spjd IFFLAG("NOARP", IFF_NOARP); 2582219089Spjd IFFLAG("PROMISC", IFF_PROMISC); 2583219089Spjd IFFLAG("ALLMULTI", IFF_ALLMULTI); 2584219089Spjd IFFLAG("OACTIVE", IFF_OACTIVE); 2585219089Spjd IFFLAG("SIMPLEX", IFF_SIMPLEX); 2586219089Spjd IFFLAG("LINK0", IFF_LINK0); 2587168404Spjd IFFLAG("LINK1", IFF_LINK1); 2588168404Spjd IFFLAG("LINK2", IFF_LINK2); 2589219089Spjd IFFLAG("MULTICAST", IFF_MULTICAST); 2590219089Spjd#undef IFFLAG 2591219089Spjd return buf; 2592219089Spjd} 2593185029Spjd 2594185029Spjdstatic void 2595219089Spjdkrtread(int again) 2596219089Spjd{ 2597168404Spjd int mib[6]; 2598185029Spjd size_t msize; 2599168404Spjd char *buf, *p, *lim; 2600185029Spjd struct rt_msghdr *rtm; 2601219089Spjd int retry; 2602219089Spjd const char *errmsg; 2603168404Spjd 2604168404Spjd retry = 0; 2605185029Spjd buf = NULL; 2606185029Spjd mib[0] = CTL_NET; 2607185029Spjd mib[1] = PF_ROUTE; 2608219089Spjd mib[2] = 0; 2609185029Spjd mib[3] = AF_INET6; /* Address family */ 2610219089Spjd mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ 2611219089Spjd mib[5] = 0; /* No flags */ 2612219089Spjd do { 2613185029Spjd if (retry) 2614185029Spjd sleep(1); 2615219089Spjd retry++; 2616219089Spjd errmsg = NULL; 2617185029Spjd if (buf) { 2618185029Spjd free(buf); 2619185029Spjd buf = NULL; 2620185029Spjd } 2621219089Spjd if (sysctl(mib, nitems(mib), NULL, &msize, NULL, 0) < 0) { 2622219089Spjd errmsg = "sysctl estimate"; 2623185029Spjd continue; 2624185029Spjd } 2625219089Spjd if ((buf = malloc(msize)) == NULL) { 2626213197Smm errmsg = "malloc"; 2627219089Spjd continue; 2628219089Spjd } 2629219089Spjd if (sysctl(mib, nitems(mib), buf, &msize, NULL, 0) < 0) { 2630185029Spjd errmsg = "sysctl NET_RT_DUMP"; 2631219089Spjd continue; 2632219089Spjd } 2633185029Spjd } while (retry < RT_DUMP_MAXRETRY && errmsg != NULL); 2634219089Spjd if (errmsg) { 2635219089Spjd fatal("%s (with %d retries, msize=%lu)", errmsg, retry, 2636219089Spjd (u_long)msize); 2637219089Spjd /*NOTREACHED*/ 2638219089Spjd } else if (1 < retry) 2639219089Spjd syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry); 2640219089Spjd 2641185029Spjd lim = buf + msize; 2642219089Spjd for (p = buf; p < lim; p += rtm->rtm_msglen) { 2643168404Spjd rtm = (struct rt_msghdr *)(void *)p; 2644168404Spjd rt_entry(rtm, again); 2645168404Spjd } 2646185029Spjd free(buf); 2647185029Spjd} 2648185029Spjd 2649185029Spjdstatic void 2650185029Spjdrt_entry(struct rt_msghdr *rtm, int again) 2651185029Spjd{ 2652219089Spjd struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; 2653185029Spjd struct sockaddr_in6 *sin6_genmask, *sin6_ifp; 2654219089Spjd char *rtmp, *ifname = NULL; 2655219089Spjd struct riprt *rrt, *orrt; 2656219089Spjd struct netinfo6 *np; 2657219089Spjd int ifindex; 2658219089Spjd 2659219089Spjd sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; 2660219089Spjd if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & 2661219089Spjd (RTF_XRESOLVE|RTF_BLACKHOLE)) { 2662219089Spjd return; /* not interested in the link route */ 2663219089Spjd } 2664185029Spjd /* do not look at cloned routes */ 2665185029Spjd#ifdef RTF_WASCLONED 2666168404Spjd if (rtm->rtm_flags & RTF_WASCLONED) 2667168404Spjd return; 2668168404Spjd#endif 2669168404Spjd#ifdef RTF_CLONED 2670168404Spjd if (rtm->rtm_flags & RTF_CLONED) 2671168404Spjd return; 2672168404Spjd#endif 2673185029Spjd /* XXX: Ignore connected routes. */ 2674168404Spjd if (!(rtm->rtm_flags & (RTF_GATEWAY|RTF_HOST|RTF_STATIC))) 2675185029Spjd return; 2676168404Spjd /* 2677168404Spjd * do not look at dynamic routes. 2678219089Spjd * netbsd/openbsd cloned routes have UGHD. 2679168404Spjd */ 2680219089Spjd if (rtm->rtm_flags & RTF_DYNAMIC) 2681219089Spjd return; 2682219089Spjd rtmp = (char *)(rtm + 1); 2683219089Spjd /* Destination */ 2684219089Spjd if ((rtm->rtm_addrs & RTA_DST) == 0) 2685219089Spjd return; /* ignore routes without destination address */ 2686219089Spjd sin6_dst = (struct sockaddr_in6 *)(void *)rtmp; 2687219089Spjd rtmp += ROUNDUP(sin6_dst->sin6_len); 2688219089Spjd if (rtm->rtm_addrs & RTA_GATEWAY) { 2689219089Spjd sin6_gw = (struct sockaddr_in6 *)(void *)rtmp; 2690219089Spjd rtmp += ROUNDUP(sin6_gw->sin6_len); 2691219089Spjd } 2692219089Spjd if (rtm->rtm_addrs & RTA_NETMASK) { 2693219089Spjd sin6_mask = (struct sockaddr_in6 *)(void *)rtmp; 2694219089Spjd rtmp += ROUNDUP(sin6_mask->sin6_len); 2695219089Spjd } 2696219089Spjd if (rtm->rtm_addrs & RTA_GENMASK) { 2697219089Spjd sin6_genmask = (struct sockaddr_in6 *)(void *)rtmp; 2698219089Spjd rtmp += ROUNDUP(sin6_genmask->sin6_len); 2699219089Spjd } 2700219089Spjd if (rtm->rtm_addrs & RTA_IFP) { 2701219089Spjd sin6_ifp = (struct sockaddr_in6 *)(void *)rtmp; 2702219089Spjd rtmp += ROUNDUP(sin6_ifp->sin6_len); 2703219089Spjd } 2704219089Spjd 2705219089Spjd /* Destination */ 2706219089Spjd if (sin6_dst->sin6_family != AF_INET6) 2707236884Smm return; 2708219089Spjd if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr)) 2709219089Spjd return; /* Link-local */ 2710219089Spjd if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback)) 2711219089Spjd return; /* Loopback */ 2712249195Smm if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr)) 2713219089Spjd return; 2714219089Spjd 2715219089Spjd if ((rrt = MALLOC(struct riprt)) == NULL) { 2716219089Spjd fatal("malloc: struct riprt"); 2717219089Spjd /*NOTREACHED*/ 2718168404Spjd } 2719168404Spjd memset(rrt, 0, sizeof(*rrt)); 2720236884Smm np = &rrt->rrt_info; 2721236884Smm rrt->rrt_same = NULL; 2722236884Smm rrt->rrt_t = time(NULL); 2723236884Smm if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) 2724236884Smm rrt->rrt_t = 0; /* Don't age static routes */ 2725236884Smm if (rtm->rtm_flags & Pflag) 2726236884Smm rrt->rrt_t = 0; /* Don't age PROTO[123] routes */ 2727236884Smm if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) 2728236884Smm rrt->rrt_t = 0; /* Don't age non-gateway host routes */ 2729236884Smm np->rip6_tag = 0; 2730236884Smm np->rip6_metric = rtm->rtm_rmx.rmx_hopcount; 2731219089Spjd if (np->rip6_metric < 1) 2732219089Spjd np->rip6_metric = 1; 2733219089Spjd rrt->rrt_flags = rtm->rtm_flags; 2734219089Spjd np->rip6_dest = sin6_dst->sin6_addr; 2735219089Spjd 2736219089Spjd /* Mask or plen */ 2737219089Spjd if (rtm->rtm_flags & RTF_HOST) 2738219089Spjd np->rip6_plen = 128; /* Host route */ 2739219089Spjd else if (sin6_mask) 2740219089Spjd np->rip6_plen = sin6mask2len(sin6_mask); 2741219089Spjd else 2742219089Spjd np->rip6_plen = 0; 2743168404Spjd 2744168404Spjd orrt = rtsearch(np); 2745168404Spjd if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) { 2746209962Smm /* Already found */ 2747209962Smm if (!again) { 2748168404Spjd trace(1, "route: %s/%d flags %s: already registered\n", 2749168404Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, 2750168404Spjd rtflags(rtm)); 2751219089Spjd } 2752219089Spjd free(rrt); 2753219089Spjd return; 2754168404Spjd } 2755219089Spjd /* Gateway */ 2756219089Spjd if (!sin6_gw) 2757168404Spjd memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2758168404Spjd else { 2759185029Spjd if (sin6_gw->sin6_family == AF_INET6) 2760168404Spjd rrt->rrt_gw = sin6_gw->sin6_addr; 2761168404Spjd else if (sin6_gw->sin6_family == AF_LINK) { 2762168404Spjd /* XXX in case ppp link? */ 2763219089Spjd rrt->rrt_gw = in6addr_loopback; 2764219089Spjd } else 2765219089Spjd memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr)); 2766168404Spjd } 2767168404Spjd trace(1, "route: %s/%d flags %s", 2768168404Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm)); 2769168404Spjd trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); 2770219089Spjd 2771219089Spjd /* Interface */ 2772219089Spjd ifindex = rtm->rtm_index; 2773219089Spjd if ((unsigned int)ifindex < nindex2ifc && index2ifc[ifindex]) 2774219089Spjd ifname = index2ifc[ifindex]->ifc_name; 2775168404Spjd else { 2776219089Spjd trace(1, " not configured\n"); 2777168404Spjd free(rrt); 2778168404Spjd return; 2779168404Spjd } 2780168404Spjd trace(1, " if %s sock %d", ifname, ifindex); 2781209962Smm rrt->rrt_index = ifindex; 2782219089Spjd 2783209962Smm trace(1, "\n"); 2784168404Spjd 2785168404Spjd /* Check gateway */ 2786219089Spjd if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) && 2787219089Spjd !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw) && 2788219089Spjd (rrt->rrt_flags & RTF_LOCAL) == 0) { 2789168404Spjd trace(0, "***** Gateway %s is not a link-local address.\n", 2790168404Spjd inet6_n2p(&rrt->rrt_gw)); 2791209962Smm trace(0, "***** dest(%s) if(%s) -- Not optimized.\n", 2792168404Spjd inet6_n2p(&rrt->rrt_info.rip6_dest), ifname); 2793168404Spjd rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR; 2794168404Spjd } 2795168404Spjd 2796168404Spjd /* Put it to the route list */ 2797168404Spjd if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) { 2798168404Spjd /* replace route list */ 2799168404Spjd TAILQ_INSERT_BEFORE(orrt, rrt, rrt_next); 2800168404Spjd TAILQ_REMOVE(&riprt_head, orrt, rrt_next); 2801208683Spjd 2802208683Spjd trace(1, "route: %s/%d flags %s: replace new route\n", 2803208683Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, 2804208683Spjd rtflags(rtm)); 2805219089Spjd free(orrt); 2806219089Spjd } else 2807208683Spjd TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); 2808219089Spjd} 2809219089Spjd 2810248571Smmstatic int 2811248571Smmaddroute(struct riprt *rrt, 2812248571Smm const struct in6_addr *gw, 2813248571Smm struct ifc *ifcp) 2814248571Smm{ 2815248571Smm struct netinfo6 *np; 2816219089Spjd u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; 2817219089Spjd struct rt_msghdr *rtm; 2818219089Spjd struct sockaddr_in6 *sin6; 2819219089Spjd int len; 2820219089Spjd 2821219089Spjd np = &rrt->rrt_info; 2822219089Spjd inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1)); 2823219089Spjd inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2)); 2824219089Spjd tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n", 2825168404Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 2826168404Spjd np->rip6_metric - 1, buf2); 2827219089Spjd if (rtlog) 2828219089Spjd fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(), 2829168404Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1, 2830219089Spjd np->rip6_metric - 1, buf2); 2831219089Spjd if (nflag) 2832219089Spjd return 0; 2833219089Spjd 2834219089Spjd memset(buf, 0, sizeof(buf)); 2835219089Spjd rtm = (struct rt_msghdr *)(void *)buf; 2836219089Spjd rtm->rtm_type = RTM_ADD; 2837219089Spjd rtm->rtm_version = RTM_VERSION; 2838268720Sdelphij rtm->rtm_seq = ++seq; 2839219089Spjd rtm->rtm_pid = pid; 2840219089Spjd rtm->rtm_flags = rrt->rrt_flags; 2841219089Spjd rtm->rtm_flags |= Qflag; 2842219089Spjd rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2843219089Spjd rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; 2844168404Spjd rtm->rtm_inits = RTV_HOPCOUNT; 2845168404Spjd sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; 2846236884Smm /* Destination */ 2847236884Smm sin6->sin6_len = sizeof(struct sockaddr_in6); 2848236884Smm sin6->sin6_family = AF_INET6; 2849236884Smm sin6->sin6_addr = np->rip6_dest; 2850236884Smm sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2851236884Smm /* Gateway */ 2852236884Smm sin6->sin6_len = sizeof(struct sockaddr_in6); 2853219089Spjd sin6->sin6_family = AF_INET6; 2854219089Spjd sin6->sin6_addr = *gw; 2855219089Spjd if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 2856219089Spjd sin6->sin6_scope_id = ifcp->ifc_index; 2857236884Smm sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2858219089Spjd /* Netmask */ 2859219089Spjd sin6->sin6_len = sizeof(struct sockaddr_in6); 2860219089Spjd sin6->sin6_family = AF_INET6; 2861219089Spjd sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2862219089Spjd sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2863219089Spjd 2864219089Spjd len = (char *)sin6 - (char *)buf; 2865219089Spjd rtm->rtm_msglen = len; 2866219089Spjd if (write(rtsock, buf, len) > 0) 2867219089Spjd return 0; 2868268720Sdelphij 2869268720Sdelphij if (errno == EEXIST) { 2870219089Spjd trace(0, "ADD: Route already exists %s/%d gw %s\n", 2871219089Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 2872219089Spjd if (rtlog) 2873219089Spjd fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n", 2874219089Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1); 2875219089Spjd } else { 2876219089Spjd trace(0, "Can not write to rtsock (addroute): %s\n", 2877219089Spjd strerror(errno)); 2878219089Spjd if (rtlog) 2879219089Spjd fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2880219089Spjd strerror(errno)); 2881219089Spjd } 2882219089Spjd return -1; 2883219089Spjd} 2884219089Spjd 2885219089Spjdstatic int 2886219089Spjddelroute(struct netinfo6 *np, struct in6_addr *gw) 2887219089Spjd{ 2888236884Smm u_char buf[BUFSIZ], buf2[BUFSIZ]; 2889236884Smm struct rt_msghdr *rtm; 2890219089Spjd struct sockaddr_in6 *sin6; 2891236884Smm int len; 2892236884Smm 2893236884Smm inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2)); 2894236884Smm tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest), 2895236884Smm np->rip6_plen, buf2); 2896236884Smm if (rtlog) 2897236884Smm fprintf(rtlog, "%s: DEL: %s/%d gw %s\n", 2898236884Smm hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2899236884Smm if (nflag) 2900219089Spjd return 0; 2901219089Spjd 2902219089Spjd memset(buf, 0, sizeof(buf)); 2903219089Spjd rtm = (struct rt_msghdr *)(void *)buf; 2904219089Spjd rtm->rtm_type = RTM_DELETE; 2905219089Spjd rtm->rtm_version = RTM_VERSION; 2906219089Spjd rtm->rtm_seq = ++seq; 2907219089Spjd rtm->rtm_pid = pid; 2908219089Spjd rtm->rtm_flags = RTF_UP | RTF_GATEWAY; 2909219089Spjd rtm->rtm_flags |= Qflag; 2910219089Spjd if (np->rip6_plen == sizeof(struct in6_addr) * 8) 2911219089Spjd rtm->rtm_flags |= RTF_HOST; 2912219089Spjd rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 2913219089Spjd sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; 2914219089Spjd /* Destination */ 2915219089Spjd sin6->sin6_len = sizeof(struct sockaddr_in6); 2916219089Spjd sin6->sin6_family = AF_INET6; 2917219089Spjd sin6->sin6_addr = np->rip6_dest; 2918219089Spjd sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2919219089Spjd /* Gateway */ 2920219089Spjd sin6->sin6_len = sizeof(struct sockaddr_in6); 2921219089Spjd sin6->sin6_family = AF_INET6; 2922219089Spjd sin6->sin6_addr = *gw; 2923236884Smm sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2924236884Smm /* Netmask */ 2925236884Smm sin6->sin6_len = sizeof(struct sockaddr_in6); 2926236884Smm sin6->sin6_family = AF_INET6; 2927236884Smm sin6->sin6_addr = *(plen2mask(np->rip6_plen)); 2928236884Smm sin6 = (struct sockaddr_in6 *)(void *)((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2929236884Smm 2930236884Smm len = (char *)sin6 - (char *)buf; 2931236884Smm rtm->rtm_msglen = len; 2932236884Smm if (write(rtsock, buf, len) >= 0) 2933236884Smm return 0; 2934236884Smm 2935236884Smm if (errno == ESRCH) { 2936236884Smm trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n", 2937219089Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2938219089Spjd if (rtlog) 2939168404Spjd fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n", 2940168404Spjd inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2); 2941168404Spjd } else { 2942168404Spjd trace(0, "Can not write to rtsock (delroute): %s\n", 2943168404Spjd strerror(errno)); 2944168404Spjd if (rtlog) 2945185029Spjd fprintf(rtlog, "\tCan not write to rtsock: %s\n", 2946168404Spjd strerror(errno)); 2947168404Spjd } 2948168404Spjd return -1; 2949168404Spjd} 2950168404Spjd 2951168404Spjd#if 0 2952219089Spjdstatic struct in6_addr * 2953219089Spjdgetroute(struct netinfo6 *np, struct in6_addr *gw) 2954168404Spjd{ 2955168404Spjd u_char buf[BUFSIZ]; 2956219089Spjd int myseq; 2957168404Spjd int len; 2958168404Spjd struct rt_msghdr *rtm; 2959219089Spjd struct sockaddr_in6 *sin6; 2960168404Spjd 2961168404Spjd rtm = (struct rt_msghdr *)(void *)buf; 2962168404Spjd len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); 2963168404Spjd memset(rtm, 0, len); 2964168404Spjd rtm->rtm_type = RTM_GET; 2965168404Spjd rtm->rtm_version = RTM_VERSION; 2966168404Spjd myseq = ++seq; 2967168404Spjd rtm->rtm_seq = myseq; 2968168404Spjd rtm->rtm_addrs = RTA_DST; 2969168404Spjd rtm->rtm_msglen = len; 2970168404Spjd sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; 2971168404Spjd sin6->sin6_len = sizeof(struct sockaddr_in6); 2972168404Spjd sin6->sin6_family = AF_INET6; 2973168404Spjd sin6->sin6_addr = np->rip6_dest; 2974168404Spjd if (write(rtsock, buf, len) < 0) { 2975168404Spjd if (errno == ESRCH) /* No such route found */ 2976168404Spjd return NULL; 2977249195Smm perror("write to rtsock"); 2978168404Spjd exit(1); 2979219089Spjd } 2980168404Spjd do { 2981219089Spjd if ((len = read(rtsock, buf, sizeof(buf))) < 0) { 2982168404Spjd perror("read from rtsock"); 2983219089Spjd exit(1); 2984219089Spjd } 2985219089Spjd rtm = (struct rt_msghdr *)(void *)buf; 2986219089Spjd } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != myseq || 2987219089Spjd rtm->rtm_pid != pid); 2988219089Spjd sin6 = (struct sockaddr_in6 *)(void *)&buf[sizeof(struct rt_msghdr)]; 2989219089Spjd if (rtm->rtm_addrs & RTA_DST) { 2990209962Smm sin6 = (struct sockaddr_in6 *)(void *) 2991168404Spjd ((char *)sin6 + ROUNDUP(sin6->sin6_len)); 2992219089Spjd } 2993219089Spjd if (rtm->rtm_addrs & RTA_GATEWAY) { 2994168404Spjd *gw = sin6->sin6_addr; 2995219089Spjd return gw; 2996219089Spjd } 2997219089Spjd return NULL; 2998168404Spjd} 2999168404Spjd#endif 3000168404Spjd 3001168404Spjdstatic const char * 3002168404Spjdinet6_n2p(const struct in6_addr *p) 3003168404Spjd{ 3004168404Spjd static char buf[BUFSIZ]; 3005168404Spjd 3006168404Spjd return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf)); 3007168404Spjd} 3008185029Spjd 3009168404Spjdstatic void 3010168404Spjdifrtdump(int sig) 3011168404Spjd{ 3012249195Smm 3013168404Spjd ifdump(sig); 3014168404Spjd rtdump(sig); 3015168404Spjd} 3016168404Spjd 3017168404Spjdstatic void 3018168404Spjdifdump(int sig) 3019168404Spjd{ 3020168404Spjd struct ifc *ifcp; 3021219089Spjd FILE *dump; 3022219089Spjd int nifc = 0; 3023219089Spjd 3024219089Spjd if (sig == 0) 3025219089Spjd dump = stderr; 3026219089Spjd else 3027219089Spjd if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 3028168404Spjd dump = stderr; 3029168404Spjd 3030219089Spjd fprintf(dump, "%s: Interface Table Dump\n", hms()); 3031168404Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) 3032168404Spjd nifc++; 3033168404Spjd fprintf(dump, " Number of interfaces: %d\n", nifc); 3034168404Spjd 3035168404Spjd fprintf(dump, " advertising interfaces:\n"); 3036168404Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 3037168404Spjd if ((ifcp->ifc_flags & IFF_UP) == 0) 3038168404Spjd continue; 3039185029Spjd if (iff_find(ifcp, IFIL_TYPE_N) != NULL) 3040219089Spjd continue; 3041219089Spjd ifdump0(dump, ifcp); 3042219089Spjd } 3043219089Spjd fprintf(dump, "\n"); 3044219089Spjd fprintf(dump, " non-advertising interfaces:\n"); 3045219089Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 3046219089Spjd if ((ifcp->ifc_flags & IFF_UP) && 3047219089Spjd (iff_find(ifcp, IFIL_TYPE_N) == NULL)) 3048219089Spjd continue; 3049219089Spjd ifdump0(dump, ifcp); 3050219089Spjd } 3051219089Spjd fprintf(dump, "\n"); 3052219089Spjd if (dump != stderr) 3053219089Spjd fclose(dump); 3054219089Spjd} 3055219089Spjd 3056168404Spjdstatic void 3057219089Spjdifdump0(FILE *dump, const struct ifc *ifcp) 3058219089Spjd{ 3059219089Spjd struct ifac *ifac; 3060249047Savg struct iff *iffp; 3061219089Spjd char buf[BUFSIZ]; 3062219089Spjd const char *ft; 3063219089Spjd int addr; 3064168404Spjd 3065168404Spjd fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n", 3066168404Spjd ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags), 3067168404Spjd inet6_n2p(&ifcp->ifc_mylladdr), 3068168404Spjd ifcp->ifc_mtu, ifcp->ifc_metric); 3069168404Spjd TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { 3070168404Spjd if (ifcp->ifc_flags & IFF_POINTOPOINT) { 3071219089Spjd inet_ntop(AF_INET6, (void *)&ifac->ifac_raddr, 3072219089Spjd buf, sizeof(buf)); 3073219089Spjd fprintf(dump, "\t%s/%d -- %s\n", 3074219089Spjd inet6_n2p(&ifac->ifac_addr), 3075219089Spjd ifac->ifac_plen, buf); 3076219089Spjd } else { 3077219089Spjd fprintf(dump, "\t%s/%d\n", 3078168404Spjd inet6_n2p(&ifac->ifac_addr), 3079168404Spjd ifac->ifac_plen); 3080219089Spjd } 3081168404Spjd } 3082168404Spjd 3083168404Spjd fprintf(dump, "\tFilter:\n"); 3084168404Spjd TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { 3085168404Spjd addr = 0; 3086168404Spjd switch (iffp->iff_type) { 3087168404Spjd case IFIL_TYPE_A: 3088168404Spjd ft = "Aggregate"; addr++; break; 3089168404Spjd case IFIL_TYPE_N: 3090168404Spjd ft = "No-use"; break; 3091168404Spjd case IFIL_TYPE_O: 3092168404Spjd ft = "Advertise-only"; addr++; break; 3093168404Spjd case IFIL_TYPE_T: 3094168404Spjd ft = "Default-only"; break; 3095168404Spjd case IFIL_TYPE_L: 3096168404Spjd ft = "Listen-only"; addr++; break; 3097168404Spjd default: 3098168404Spjd snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); 3099168404Spjd ft = buf; 3100168404Spjd addr++; 3101168404Spjd break; 3102168404Spjd } 3103168404Spjd fprintf(dump, "\t\t%s", ft); 3104168404Spjd if (addr) 3105168404Spjd fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr), 3106168404Spjd iffp->iff_plen); 3107168404Spjd fprintf(dump, "\n"); 3108168404Spjd } 3109168404Spjd fprintf(dump, "\n"); 3110168404Spjd} 3111185029Spjd 3112185029Spjdstatic void 3113185029Spjdrtdump(int sig) 3114168404Spjd{ 3115168404Spjd struct riprt *rrt; 3116168404Spjd char buf[BUFSIZ]; 3117168404Spjd FILE *dump; 3118168404Spjd time_t t, age; 3119168404Spjd 3120168404Spjd if (sig == 0) 3121168404Spjd dump = stderr; 3122168404Spjd else 3123168404Spjd if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL) 3124168404Spjd dump = stderr; 3125209962Smm 3126209962Smm t = time(NULL); 3127185029Spjd fprintf(dump, "\n%s: Routing Table Dump\n", hms()); 3128168404Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 3129168404Spjd if (rrt->rrt_t == 0) 3130168404Spjd age = 0; 3131168404Spjd else 3132185029Spjd age = t - rrt->rrt_t; 3133168404Spjd inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest, 3134168404Spjd buf, sizeof(buf)); 3135168404Spjd fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)", 3136168404Spjd buf, rrt->rrt_info.rip6_plen, rrt->rrt_index, 3137168404Spjd index2ifc[rrt->rrt_index]->ifc_name, 3138168404Spjd inet6_n2p(&rrt->rrt_gw), 3139168404Spjd rrt->rrt_info.rip6_metric, (long)age); 3140168404Spjd if (rrt->rrt_info.rip6_tag) { 3141168404Spjd fprintf(dump, " tag(0x%04x)", 3142168404Spjd ntohs(rrt->rrt_info.rip6_tag) & 0xffff); 3143168404Spjd } 3144168404Spjd if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) 3145168404Spjd fprintf(dump, " NOT-LL"); 3146168404Spjd if (rrt->rrt_rflags & RRTF_NOADVERTISE) 3147168404Spjd fprintf(dump, " NO-ADV"); 3148185029Spjd fprintf(dump, "\n"); 3149185029Spjd } 3150168404Spjd fprintf(dump, "\n"); 3151219089Spjd if (dump != stderr) 3152168404Spjd fclose(dump); 3153168404Spjd} 3154168404Spjd 3155168404Spjd/* 3156168404Spjd * Parse the -A (and -O) options and put corresponding filter object to the 3157168404Spjd * specified interface structures. Each of the -A/O option has the following 3158168404Spjd * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate) 3159168404Spjd * -O 5f09:c400::/32,ef0,ef1 (only when match) 3160185029Spjd */ 3161185029Spjdstatic void 3162185029Spjdfilterconfig(void) 3163185029Spjd{ 3164185029Spjd int i; 3165185029Spjd char *p, *ap, *iflp, *ifname, *ep; 3166185029Spjd struct iff iff, *iffp; 3167185029Spjd struct ifc *ifcp; 3168185029Spjd struct riprt *rrt; 3169185029Spjd#if 0 3170185029Spjd struct in6_addr gw; 3171185029Spjd#endif 3172185029Spjd u_long plen; 3173185029Spjd 3174209962Smm for (i = 0; i < nfilter; i++) { 3175209962Smm ap = filter[i]; 3176185029Spjd iflp = NULL; 3177185029Spjd iffp = ⇔ 3178185029Spjd memset(iffp, 0, sizeof(*iffp)); 3179185029Spjd if (filtertype[i] == 'N' || filtertype[i] == 'T') { 3180185029Spjd iflp = ap; 3181185029Spjd goto ifonly; 3182185029Spjd } 3183185029Spjd if ((p = strchr(ap, ',')) != NULL) { 3184185029Spjd *p++ = '\0'; 3185185029Spjd iflp = p; 3186185029Spjd } 3187185029Spjd if ((p = strchr(ap, '/')) == NULL) { 3188185029Spjd fatal("no prefixlen specified for '%s'", ap); 3189185029Spjd /*NOTREACHED*/ 3190185029Spjd } 3191185029Spjd *p++ = '\0'; 3192185029Spjd if (inet_pton(AF_INET6, ap, &iffp->iff_addr) != 1) { 3193185029Spjd fatal("invalid prefix specified for '%s'", ap); 3194185029Spjd /*NOTREACHED*/ 3195185029Spjd } 3196185029Spjd errno = 0; 3197185029Spjd ep = NULL; 3198185029Spjd plen = strtoul(p, &ep, 10); 3199185029Spjd if (errno || !*p || *ep || plen > sizeof(iffp->iff_addr) * 8) { 3200185029Spjd fatal("invalid prefix length specified for '%s'", ap); 3201185029Spjd /*NOTREACHED*/ 3202185029Spjd } 3203185029Spjd iffp->iff_plen = plen; 3204185029Spjd applyplen(&iffp->iff_addr, iffp->iff_plen); 3205185029Spjdifonly: 3206185029Spjd iffp->iff_type = filtertype[i]; 3207185029Spjd if (iflp == NULL || *iflp == '\0') { 3208219089Spjd fatal("no interface specified for '%s'", ap); 3209219089Spjd /*NOTREACHED*/ 3210185029Spjd } 3211185029Spjd /* parse the interface listing portion */ 3212185029Spjd while (iflp) { 3213185029Spjd ifname = iflp; 3214185029Spjd if ((iflp = strchr(iflp, ',')) != NULL) 3215236884Smm *iflp++ = '\0'; 3216236884Smm 3217236884Smm TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 3218236884Smm if (fnmatch(ifname, ifcp->ifc_name, 0) != 0) 3219236884Smm continue; 3220236884Smm 3221236884Smm iffp = malloc(sizeof(*iffp)); 3222236884Smm if (iffp == NULL) { 3223236884Smm fatal("malloc of iff"); 3224236884Smm /*NOTREACHED*/ 3225253993Smav } 3226253993Smav memcpy(iffp, &iff, sizeof(*iffp)); 3227253993Smav#if 0 3228253993Smav syslog(LOG_INFO, "Add filter: type %d, ifname %s.", iffp->iff_type, ifname); 3229236884Smm#endif 3230236884Smm TAILQ_INSERT_HEAD(&ifcp->ifc_iff_head, iffp, iff_next); 3231236884Smm } 3232236884Smm } 3233236884Smm 3234236884Smm /* 3235236884Smm * -A: aggregate configuration. 3236236884Smm */ 3237236884Smm if (filtertype[i] != IFIL_TYPE_A) 3238236884Smm continue; 3239236884Smm /* put the aggregate to the kernel routing table */ 3240236884Smm rrt = (struct riprt *)malloc(sizeof(struct riprt)); 3241236884Smm if (rrt == NULL) { 3242236884Smm fatal("malloc: rrt"); 3243236884Smm /*NOTREACHED*/ 3244236884Smm } 3245236884Smm memset(rrt, 0, sizeof(struct riprt)); 3246236884Smm rrt->rrt_info.rip6_dest = iff.iff_addr; 3247236884Smm rrt->rrt_info.rip6_plen = iff.iff_plen; 3248236884Smm rrt->rrt_info.rip6_metric = 1; 3249236884Smm rrt->rrt_info.rip6_tag = htons(routetag & 0xffff); 3250236884Smm rrt->rrt_gw = in6addr_loopback; 3251236884Smm rrt->rrt_flags = RTF_UP | RTF_REJECT; 3252236884Smm rrt->rrt_rflags = RRTF_AGGREGATE; 3253236884Smm rrt->rrt_t = 0; 3254236884Smm rrt->rrt_index = loopifcp->ifc_index; 3255253993Smav#if 0 3256236884Smm if (getroute(&rrt->rrt_info, &gw)) { 3257236884Smm#if 0 3258236884Smm /* 3259236884Smm * When the address has already been registered in the 3260236884Smm * kernel routing table, it should be removed 3261168404Spjd */ 3262236884Smm delroute(&rrt->rrt_info, &gw); 3263236884Smm#else 3264168404Spjd /* it is safer behavior */ 3265168404Spjd errno = EINVAL; 3266168404Spjd fatal("%s/%u already in routing table, " 3267168404Spjd "cannot aggregate", 3268168404Spjd inet6_n2p(&rrt->rrt_info.rip6_dest), 3269219089Spjd rrt->rrt_info.rip6_plen); 3270168404Spjd /*NOTREACHED*/ 3271209962Smm#endif 3272209962Smm } 3273209962Smm#endif 3274209962Smm /* Put the route to the list */ 3275209962Smm TAILQ_INSERT_HEAD(&riprt_head, rrt, rrt_next); 3276209962Smm trace(1, "Aggregate: %s/%d for %s\n", 3277209962Smm inet6_n2p(&iff.iff_addr), iff.iff_plen, 3278168404Spjd loopifcp->ifc_name); 3279209962Smm /* Add this route to the kernel */ 3280219089Spjd if (nflag) /* do not modify kernel routing table */ 3281219089Spjd continue; 3282219089Spjd addroute(rrt, &in6addr_loopback, loopifcp); 3283219089Spjd } 3284219089Spjd} 3285219089Spjd 3286219089Spjd/***************** utility functions *****************/ 3287185029Spjd 3288209962Smm/* 3289209962Smm * Returns a pointer to ifac whose address and prefix length matches 3290185029Spjd * with the address and prefix length specified in the arguments. 3291209962Smm */ 3292209962Smmstatic struct ifac * 3293209962Smmifa_match(const struct ifc *ifcp, 3294209962Smm const struct in6_addr *ia, 3295209962Smm int plen) 3296209962Smm{ 3297209962Smm struct ifac *ifac; 3298236884Smm 3299209962Smm TAILQ_FOREACH(ifac, &ifcp->ifc_ifac_head, ifac_next) { 3300168404Spjd if (IN6_ARE_ADDR_EQUAL(&ifac->ifac_addr, ia) && 3301168404Spjd ifac->ifac_plen == plen) 3302168404Spjd break; 3303168404Spjd } 3304168404Spjd 3305168404Spjd return (ifac); 3306168404Spjd} 3307168404Spjd 3308168404Spjd/* 3309168404Spjd * Return a pointer to riprt structure whose address and prefix length 3310168404Spjd * matches with the address and prefix length found in the argument. 3311168404Spjd * Note: This is not a rtalloc(). Therefore exact match is necessary. 3312168404Spjd */ 3313168404Spjdstatic struct riprt * 3314168404Spjdrtsearch(struct netinfo6 *np) 3315168404Spjd{ 3316168404Spjd struct riprt *rrt; 3317168404Spjd 3318168404Spjd TAILQ_FOREACH(rrt, &riprt_head, rrt_next) { 3319168404Spjd if (rrt->rrt_info.rip6_plen == np->rip6_plen && 3320168404Spjd IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, 3321209962Smm &np->rip6_dest)) 3322209962Smm break; 3323168404Spjd } 3324209962Smm 3325168404Spjd return (rrt); 3326168404Spjd} 3327168404Spjd 3328168404Spjdstatic int 3329168404Spjdsin6mask2len(const struct sockaddr_in6 *sin6) 3330185029Spjd{ 3331185029Spjd 3332185029Spjd return mask2len(&sin6->sin6_addr, 3333185029Spjd sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr)); 3334168404Spjd} 3335168404Spjd 3336185029Spjdstatic int 3337185029Spjdmask2len(const struct in6_addr *addr, int lenlim) 3338185029Spjd{ 3339168404Spjd int i = 0, j; 3340185029Spjd const u_char *p = (const u_char *)addr; 3341185029Spjd 3342168404Spjd for (j = 0; j < lenlim; j++, p++) { 3343168404Spjd if (*p != 0xff) 3344168404Spjd break; 3345185029Spjd i += 8; 3346185029Spjd } 3347168404Spjd if (j < lenlim) { 3348185029Spjd switch (*p) { 3349168404Spjd#define MASKLEN(m, l) case m: do { i += l; break; } while (0) 3350185029Spjd MASKLEN(0xfe, 7); break; 3351168404Spjd MASKLEN(0xfc, 6); break; 3352168404Spjd MASKLEN(0xf8, 5); break; 3353185029Spjd MASKLEN(0xf0, 4); break; 3354249195Smm MASKLEN(0xe0, 3); break; 3355168404Spjd MASKLEN(0xc0, 2); break; 3356168404Spjd MASKLEN(0x80, 1); break; 3357185029Spjd#undef MASKLEN 3358185029Spjd } 3359168404Spjd } 3360185029Spjd return i; 3361249195Smm} 3362168404Spjd 3363168404Spjdstatic const u_char plent[8] = { 3364185029Spjd 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe 3365168404Spjd}; 3366168404Spjd 3367185029Spjdstatic void 3368185029Spjdapplyplen(struct in6_addr *ia, int plen) 3369168404Spjd{ 3370185029Spjd u_char *p; 3371185029Spjd int i; 3372168404Spjd 3373168404Spjd p = ia->s6_addr; 3374168404Spjd for (i = 0; i < 16; i++) { 3375168404Spjd if (plen <= 0) 3376168404Spjd *p = 0; 3377249195Smm else if (plen < 8) 3378168404Spjd *p &= plent[plen]; 3379168404Spjd p++, plen -= 8; 3380168404Spjd } 3381185029Spjd} 3382185029Spjd 3383185029Spjdstatic const int pl2m[9] = { 3384185029Spjd 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 3385185029Spjd}; 3386185029Spjd 3387185029Spjdstatic struct in6_addr * 3388249195Smmplen2mask(int n) 3389230514Smm{ 3390185029Spjd static struct in6_addr ia; 3391185029Spjd u_char *p; 3392185029Spjd int i; 3393168404Spjd 3394168404Spjd memset(&ia, 0, sizeof(struct in6_addr)); 3395168404Spjd p = (u_char *)&ia; 3396185029Spjd for (i = 0; i < 16; i++, p++, n -= 8) { 3397185029Spjd if (n >= 8) { 3398168404Spjd *p = 0xff; 3399168404Spjd continue; 3400168404Spjd } 3401168404Spjd *p = pl2m[n]; 3402168404Spjd break; 3403185029Spjd } 3404185029Spjd return &ia; 3405168404Spjd} 3406168404Spjd 3407168404Spjdstatic char * 3408168404Spjdallocopy(char *p) 3409168404Spjd{ 3410168404Spjd int len = strlen(p) + 1; 3411185029Spjd char *q = (char *)malloc(len); 3412185029Spjd 3413168404Spjd if (!q) { 3414168404Spjd fatal("malloc"); 3415168404Spjd /*NOTREACHED*/ 3416185029Spjd } 3417185029Spjd 3418185029Spjd strlcpy(q, p, len); 3419185029Spjd return q; 3420185029Spjd} 3421185029Spjd 3422185029Spjdstatic char * 3423185029Spjdhms(void) 3424185029Spjd{ 3425185029Spjd static char buf[BUFSIZ]; 3426185029Spjd time_t t; 3427185029Spjd struct tm *tm; 3428185029Spjd 3429185029Spjd t = time(NULL); 3430185029Spjd if ((tm = localtime(&t)) == 0) { 3431185029Spjd fatal("localtime"); 3432185029Spjd /*NOTREACHED*/ 3433185029Spjd } 3434185029Spjd snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 3435185029Spjd tm->tm_sec); 3436185029Spjd return buf; 3437185029Spjd} 3438185029Spjd 3439185029Spjd#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ 3440185029Spjd 3441185029Spjdstatic int 3442185029Spjdripinterval(int timer) 3443185029Spjd{ 3444185029Spjd double r = rand(); 3445185029Spjd 3446185029Spjd interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5)); 3447185029Spjd nextalarm = time(NULL) + interval; 3448185029Spjd return interval; 3449185029Spjd} 3450185029Spjd 3451185029Spjd#if 0 3452185029Spjdstatic time_t 3453185029Spjdripsuptrig(void) 3454185029Spjd{ 3455185029Spjd time_t t; 3456185029Spjd 3457185029Spjd double r = rand(); 3458185029Spjd t = (int)(RIP_TRIG_INT6_MIN + 3459185029Spjd (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX)); 3460185029Spjd sup_trig_update = time(NULL) + t; 3461185029Spjd return t; 3462185029Spjd} 3463185029Spjd#endif 3464185029Spjd 3465185029Spjdstatic void 3466185029Spjdfatal(const char *fmt, ...) 3467185029Spjd{ 3468185029Spjd va_list ap; 3469185029Spjd char buf[1024]; 3470185029Spjd 3471185029Spjd va_start(ap, fmt); 3472185029Spjd vsnprintf(buf, sizeof(buf), fmt, ap); 3473185029Spjd va_end(ap); 3474185029Spjd perror(buf); 3475185029Spjd if (errno) 3476185029Spjd syslog(LOG_ERR, "%s: %s", buf, strerror(errno)); 3477185029Spjd else 3478185029Spjd syslog(LOG_ERR, "%s", buf); 3479185029Spjd rtdexit(); 3480168404Spjd} 3481185029Spjd 3482185029Spjdstatic void 3483185029Spjdtracet(int level, const char *fmt, ...) 3484185029Spjd{ 3485185029Spjd va_list ap; 3486185029Spjd 3487185029Spjd if (level <= dflag) { 3488185029Spjd va_start(ap, fmt); 3489185029Spjd fprintf(stderr, "%s: ", hms()); 3490185029Spjd vfprintf(stderr, fmt, ap); 3491185029Spjd va_end(ap); 3492185029Spjd } 3493185029Spjd if (dflag) { 3494185029Spjd va_start(ap, fmt); 3495185029Spjd if (level > 0) 3496209962Smm vsyslog(LOG_DEBUG, fmt, ap); 3497209962Smm else 3498185029Spjd vsyslog(LOG_WARNING, fmt, ap); 3499185029Spjd va_end(ap); 3500185029Spjd } 3501185029Spjd} 3502185029Spjd 3503168404Spjdstatic void 3504168404Spjdtrace(int level, const char *fmt, ...) 3505168404Spjd{ 3506185029Spjd va_list ap; 3507248571Smm 3508168404Spjd if (level <= dflag) { 3509168404Spjd va_start(ap, fmt); 3510185029Spjd vfprintf(stderr, fmt, ap); 3511168404Spjd va_end(ap); 3512168404Spjd } 3513168404Spjd if (dflag) { 3514219089Spjd va_start(ap, fmt); 3515168404Spjd if (level > 0) 3516185029Spjd vsyslog(LOG_DEBUG, fmt, ap); 3517185029Spjd else 3518219089Spjd vsyslog(LOG_WARNING, fmt, ap); 3519236884Smm va_end(ap); 3520168404Spjd } 3521168404Spjd} 3522168404Spjd 3523168404Spjdstatic struct ifc * 3524168404Spjdifc_find(char *name) 3525168404Spjd{ 3526168404Spjd struct ifc *ifcp; 3527249195Smm 3528168404Spjd TAILQ_FOREACH(ifcp, &ifc_head, ifc_next) { 3529168404Spjd if (strcmp(name, ifcp->ifc_name) == 0) 3530168404Spjd break; 3531168404Spjd } 3532168404Spjd return (ifcp); 3533185029Spjd} 3534185029Spjd 3535219089Spjdstatic struct iff * 3536209962Smmiff_find(struct ifc *ifcp, int type) 3537168404Spjd{ 3538185029Spjd struct iff *iffp; 3539185029Spjd 3540185029Spjd TAILQ_FOREACH(iffp, &ifcp->ifc_iff_head, iff_next) { 3541185029Spjd if (type == IFIL_TYPE_ANY || 3542185029Spjd type == iffp->iff_type) 3543185029Spjd break; 3544185029Spjd } 3545236884Smm 3546236884Smm return (iffp); 3547236884Smm} 3548236884Smm 3549236884Smmstatic void 3550236884Smmsetindex2ifc(int idx, struct ifc *ifcp) 3551236884Smm{ 3552236884Smm int n, nsize; 3553236884Smm struct ifc **p; 3554185029Spjd 3555236884Smm if (!index2ifc) { 3556236884Smm nindex2ifc = 5; /*initial guess*/ 3557219089Spjd index2ifc = (struct ifc **) 3558219089Spjd malloc(sizeof(*index2ifc) * nindex2ifc); 3559219089Spjd if (index2ifc == NULL) { 3560185029Spjd fatal("malloc"); 3561168404Spjd /*NOTREACHED*/ 3562168404Spjd } 3563168404Spjd memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc); 3564209962Smm } 3565209962Smm n = nindex2ifc; 3566209962Smm for (nsize = nindex2ifc; nsize <= idx; nsize *= 2) 3567209962Smm ; 3568209962Smm if (n != nsize) { 3569209962Smm p = (struct ifc **)realloc(index2ifc, 3570168404Spjd sizeof(*index2ifc) * nsize); 3571168404Spjd if (p == NULL) { 3572185029Spjd fatal("realloc"); 3573168404Spjd /*NOTREACHED*/ 3574168404Spjd } 3575168404Spjd memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n)); 3576168404Spjd index2ifc = p; 3577168404Spjd nindex2ifc = nsize; 3578168404Spjd } 3579185029Spjd index2ifc[idx] = ifcp; 3580249195Smm} 3581168404Spjd