Remove some __STDC__ checks.
[dragonfly.git] / usr.sbin / route6d / route6d.c
CommitLineData
984263bc
MD
1/* $FreeBSD: src/usr.sbin/route6d/route6d.c,v 1.2.2.5 2001/07/03 11:02:09 ume Exp $ */
2/* $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
1de703da
MD
31 *
32 * $KAME: route6d.c,v 1.64 2001/05/08 04:36:37 itojun Exp $
984263bc
MD
33 */
34
cc970022
MD
35#define _KERNEL_STRUCTURES
36
984263bc
MD
37#include <stdio.h>
38
39#include <time.h>
40#include <unistd.h>
41#include <stdlib.h>
42#include <string.h>
43#include <signal.h>
984263bc 44#include <stdarg.h>
984263bc
MD
45#include <syslog.h>
46#include <stddef.h>
47#include <errno.h>
48#include <err.h>
49
50#include <sys/types.h>
51#include <sys/param.h>
52#include <sys/file.h>
53#include <sys/socket.h>
54#include <sys/ioctl.h>
55#include <sys/sysctl.h>
56#include <sys/uio.h>
57#include <net/if.h>
db43ed0f 58#if defined(__DragonFly__)
984263bc 59#include <net/if_var.h>
db43ed0f 60#endif /* __DragonFly__ */
984263bc 61#include <net/route.h>
984263bc
MD
62#include <netinet/in.h>
63#include <netinet/in_var.h>
64#include <netinet/ip6.h>
65#include <netinet/udp.h>
66#include <netdb.h>
67#include <ifaddrs.h>
68
69#include <arpa/inet.h>
70
71#include "route6d.h"
72
73#define MAXFILTER 40
74
75#ifdef DEBUG
76#define INIT_INTERVAL6 6
77#else
78#define INIT_INTERVAL6 10 /* Wait to submit a initial riprequest */
79#endif
80
81/* alignment constraint for routing socket */
82#define ROUNDUP(a) \
83 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
84#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
85
86/*
87 * Following two macros are highly depending on KAME Release
88 */
89#define IN6_LINKLOCAL_IFINDEX(addr) \
90 ((addr).s6_addr[2] << 8 | (addr).s6_addr[3])
91
92#define SET_IN6_LINKLOCAL_IFINDEX(addr, index) \
93 do { \
94 (addr).s6_addr[2] = ((index) >> 8) & 0xff; \
95 (addr).s6_addr[3] = (index) & 0xff; \
96 } while (0)
97
98struct ifc { /* Configuration of an interface */
99 char *ifc_name; /* if name */
100 struct ifc *ifc_next;
101 int ifc_index; /* if index */
102 int ifc_mtu; /* if mtu */
103 int ifc_metric; /* if metric */
104 u_int ifc_flags; /* flags */
105 short ifc_cflags; /* IFC_XXX */
106 struct in6_addr ifc_mylladdr; /* my link-local address */
107 struct sockaddr_in6 ifc_ripsin; /* rip multicast address */
108 struct iff *ifc_filter; /* filter structure */
109 struct ifac *ifc_addr; /* list of AF_INET6 addresses */
110 int ifc_joined; /* joined to ff02::9 */
111};
112
113struct ifac { /* Adddress associated to an interface */
114 struct ifc *ifa_conf; /* back pointer */
115 struct ifac *ifa_next;
116 struct in6_addr ifa_addr; /* address */
117 struct in6_addr ifa_raddr; /* remote address, valid in p2p */
118 int ifa_plen; /* prefix length */
119};
120
121struct iff {
122 int iff_type;
123 struct in6_addr iff_addr;
124 int iff_plen;
125 struct iff *iff_next;
126};
127
128struct ifc *ifc;
129int nifc; /* number of valid ifc's */
130struct ifc **index2ifc;
131int nindex2ifc;
132struct ifc *loopifcp = NULL; /* pointing to loopback */
133int loopifindex = 0; /* ditto */
134fd_set sockvec; /* vector to select() for receiving */
135int rtsock; /* the routing socket */
136int ripsock; /* socket to send/receive RIP datagram */
137
138struct rip6 *ripbuf; /* packet buffer for sending */
139
140/*
141 * Maintain the routes in a linked list. When the number of the routes
142 * grows, somebody would like to introduce a hash based or a radix tree
143 * based structure. I believe the number of routes handled by RIP is
144 * limited and I don't have to manage a complex data structure, however.
145 *
146 * One of the major drawbacks of the linear linked list is the difficulty
147 * of representing the relationship between a couple of routes. This may
148 * be a significant problem when we have to support route aggregation with
149 * supressing the specifices covered by the aggregate.
150 */
151
152struct riprt {
153 struct riprt *rrt_next; /* next destination */
154 struct riprt *rrt_same; /* same destination - future use */
155 struct netinfo6 rrt_info; /* network info */
156 struct in6_addr rrt_gw; /* gateway */
157 u_long rrt_flags; /* kernel routing table flags */
158 u_long rrt_rflags; /* route6d routing table flags */
159 time_t rrt_t; /* when the route validated */
160 int rrt_index; /* ifindex from which this route got */
161};
162
163struct riprt *riprt = 0;
164
165int dflag = 0; /* debug flag */
166int qflag = 0; /* quiet flag */
167int nflag = 0; /* don't update kernel routing table */
168int aflag = 0; /* age out even the statically defined routes */
169int hflag = 0; /* don't split horizon */
170int lflag = 0; /* exchange site local routes */
171int sflag = 0; /* announce static routes w/ split horizon */
172int Sflag = 0; /* announce static routes to every interface */
173unsigned long routetag = 0; /* route tag attached on originating case */
174
175char *filter[MAXFILTER];
176int filtertype[MAXFILTER];
177int nfilter = 0;
178
179pid_t pid;
180
181struct sockaddr_storage ripsin;
182
183struct rtentry rtentry;
184
185int interval = 1;
186time_t nextalarm = 0;
187time_t sup_trig_update = 0;
188
189FILE *rtlog = NULL;
190
191int logopened = 0;
192
193static u_long seq = 0;
194
195volatile int signo;
196volatile sig_atomic_t seenalrm;
197volatile sig_atomic_t seenquit;
198volatile sig_atomic_t seenusr1;
199
200#define RRTF_AGGREGATE 0x08000000
201#define RRTF_NOADVERTISE 0x10000000
202#define RRTF_NH_NOT_LLADDR 0x20000000
203#define RRTF_SENDANYWAY 0x40000000
204#define RRTF_CHANGED 0x80000000
205
2d8a3be7
EN
206int main(int, char **);
207void sighandler(int);
208void ripalarm(void);
209void riprecv(void);
210void ripsend(struct ifc *, struct sockaddr_in6 *, int);
211int out_filter(struct riprt *, struct ifc *);
212void init(void);
213void sockopt(struct ifc *);
214void ifconfig(void);
215void ifconfig1(const char *, const struct sockaddr *, struct ifc *, int);
216void rtrecv(void);
217int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *,
218 const struct sockaddr_in6 *);
219int rt_deladdr(struct ifc *, const struct sockaddr_in6 *,
220 const struct sockaddr_in6 *);
221void filterconfig(void);
222int getifmtu(int);
223const char *rttypes(struct rt_msghdr *);
224const char *rtflags(struct rt_msghdr *);
225const char *ifflags(int);
226int ifrt(struct ifc *, int);
227void ifrt_p2p(struct ifc *, int);
228void applymask(struct in6_addr *, struct in6_addr *);
229void applyplen(struct in6_addr *, int);
230void ifrtdump(int);
231void ifdump(int);
232void ifdump0(FILE *, const struct ifc *);
233void rtdump(int);
234void rt_entry(struct rt_msghdr *, int);
235void rtdexit(void);
236void riprequest(struct ifc *, struct netinfo6 *, int,
237 struct sockaddr_in6 *);
238void ripflush(struct ifc *, struct sockaddr_in6 *);
239void sendrequest(struct ifc *);
240int sin6mask2len(const struct sockaddr_in6 *);
241int mask2len(const struct in6_addr *, int);
242int sendpacket(struct sockaddr_in6 *, int);
243int addroute(struct riprt *, const struct in6_addr *, struct ifc *);
244int delroute(struct netinfo6 *, struct in6_addr *);
245struct in6_addr *getroute(struct netinfo6 *, struct in6_addr *);
246void krtread(int);
247int tobeadv(struct riprt *, struct ifc *);
248char *allocopy(char *);
249char *hms(void);
250const char *inet6_n2p(const struct in6_addr *);
251struct ifac *ifa_match(const struct ifc *, const struct in6_addr *, int);
252struct in6_addr *plen2mask(int);
253struct riprt *rtsearch(struct netinfo6 *, struct riprt **);
254int ripinterval(int);
255time_t ripsuptrig(void);
256void fatal(const char *, ...)
984263bc 257 __attribute__((__format__(__printf__, 1, 2)));
2d8a3be7 258void trace(int, const char *, ...)
984263bc 259 __attribute__((__format__(__printf__, 2, 3)));
2d8a3be7 260void tracet(int, const char *, ...)
984263bc 261 __attribute__((__format__(__printf__, 2, 3)));
2d8a3be7
EN
262unsigned int if_maxindex(void);
263struct ifc *ifc_find(char *);
264struct iff *iff_find(struct ifc *, int);
265void setindex2ifc(int, struct ifc *);
984263bc
MD
266
267#define MALLOC(type) ((type *)malloc(sizeof(type)))
268
269int
36471bd1 270main(int argc, char **argv)
984263bc
MD
271{
272 int ch;
273 int error = 0;
274 struct ifc *ifcp;
275 sigset_t mask, omask;
276 FILE *pidfile;
277 char *progname;
278 char *ep;
279
280 progname = strrchr(*argv, '/');
281 if (progname)
282 progname++;
283 else
284 progname = *argv;
285
286 pid = getpid();
287 while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) {
288 switch (ch) {
289 case 'A':
290 case 'N':
291 case 'O':
292 case 'T':
293 case 'L':
294 if (nfilter >= MAXFILTER) {
295 fatal("Exceeds MAXFILTER");
296 /*NOTREACHED*/
297 }
298 filtertype[nfilter] = ch;
299 filter[nfilter++] = allocopy(optarg);
300 break;
301 case 't':
302 ep = NULL;
303 routetag = strtoul(optarg, &ep, 0);
304 if (!ep || *ep != '\0' || (routetag & ~0xffff) != 0) {
305 fatal("invalid route tag");
306 /*NOTREACHED*/
307 }
308 break;
309 case 'R':
310 if ((rtlog = fopen(optarg, "w")) == NULL) {
311 fatal("Can not write to routelog");
312 /*NOTREACHED*/
313 }
314 break;
315#define FLAG(c, flag, n) case c: do { flag = n; break; } while(0)
316 FLAG('a', aflag, 1); break;
317 FLAG('d', dflag, 1); break;
318 FLAG('D', dflag, 2); break;
319 FLAG('h', hflag, 1); break;
320 FLAG('l', lflag, 1); break;
321 FLAG('n', nflag, 1); break;
322 FLAG('q', qflag, 1); break;
323 FLAG('s', sflag, 1); break;
324 FLAG('S', Sflag, 1); break;
325#undef FLAG
326 default:
327 fatal("Invalid option specified, terminating");
328 /*NOTREACHED*/
329 }
330 }
331 argc -= optind;
332 argv += optind;
333 if (argc > 0) {
334 fatal("bogus extra arguments");
335 /*NOTREACHED*/
336 }
337
338 if (geteuid()) {
339 nflag = 1;
340 fprintf(stderr, "No kernel update is allowed\n");
341 }
342 openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
343 logopened++;
344
345 if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL)
346 fatal("malloc");
347 memset(ripbuf, 0, RIP6_MAXMTU);
348 ripbuf->rip6_cmd = RIP6_RESPONSE;
349 ripbuf->rip6_vers = RIP6_VERSION;
350 ripbuf->rip6_res1[0] = 0;
351 ripbuf->rip6_res1[1] = 0;
352
353 init();
354 ifconfig();
355 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
356 if (ifcp->ifc_index < 0) {
357 fprintf(stderr,
358"No ifindex found at %s (no link-local address?)\n",
359 ifcp->ifc_name);
360 error++;
361 }
362 }
363 if (error)
364 exit(1);
365 if (loopifcp == NULL) {
366 fatal("No loopback found");
367 /*NOTREACHED*/
368 }
369 loopifindex = loopifcp->ifc_index;
370 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
371 ifrt(ifcp, 0);
372 filterconfig();
373 krtread(0);
374 if (dflag)
375 ifrtdump(0);
376
377 if (dflag == 0) {
378#if 1
379 if (daemon(0, 0) < 0) {
380 fatal("daemon");
381 /*NOTREACHED*/
382 }
383#else
384 if (fork())
385 exit(0);
386 if (setsid() < 0) {
387 fatal("setid");
388 /*NOTREACHED*/
389 }
390#endif
391 }
392 pid = getpid();
393 if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) {
394 fprintf(pidfile, "%d\n", pid);
395 fclose(pidfile);
396 }
397
398 if ((ripbuf = (struct rip6 *)malloc(RIP6_MAXMTU)) == NULL) {
399 fatal("malloc");
400 /*NOTREACHED*/
401 }
402 memset(ripbuf, 0, RIP6_MAXMTU);
403 ripbuf->rip6_cmd = RIP6_RESPONSE;
404 ripbuf->rip6_vers = RIP6_VERSION;
405 ripbuf->rip6_res1[0] = 0;
406 ripbuf->rip6_res1[1] = 0;
407
408 if (signal(SIGALRM, sighandler) == SIG_ERR ||
409 signal(SIGQUIT, sighandler) == SIG_ERR ||
410 signal(SIGTERM, sighandler) == SIG_ERR ||
411 signal(SIGUSR1, sighandler) == SIG_ERR ||
412 signal(SIGHUP, sighandler) == SIG_ERR ||
413 signal(SIGINT, sighandler) == SIG_ERR) {
414 fatal("signal");
415 /*NOTREACHED*/
416 }
417 /*
418 * To avoid rip packet congestion (not on a cable but in this
419 * process), wait for a moment to send the first RIP6_RESPONSE
420 * packets.
421 */
422 alarm(ripinterval(INIT_INTERVAL6));
423
424 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
425 if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
426 sendrequest(ifcp);
427 }
428
429 syslog(LOG_INFO, "**** Started ****");
430 sigemptyset(&mask);
431 sigaddset(&mask, SIGALRM);
432 while (1) {
433 fd_set recvec;
434
435 if (seenalrm) {
436 ripalarm();
437 seenalrm = 0;
438 continue;
439 }
440 if (seenquit) {
441 rtdexit();
442 seenquit = 0;
443 continue;
444 }
445 if (seenusr1) {
446 ifrtdump(SIGUSR1);
447 seenusr1 = 0;
448 continue;
449 }
450
451 FD_COPY(&sockvec, &recvec);
452 signo = 0;
453 switch (select(FD_SETSIZE, &recvec, 0, 0, 0)) {
454 case -1:
455 if (errno != EINTR) {
456 fatal("select");
457 /*NOTREACHED*/
458 }
459 continue;
460 case 0:
461 continue;
462 default:
463 if (FD_ISSET(ripsock, &recvec)) {
464 sigprocmask(SIG_BLOCK, &mask, &omask);
465 riprecv();
466 sigprocmask(SIG_SETMASK, &omask, NULL);
467 }
468 if (FD_ISSET(rtsock, &recvec)) {
469 sigprocmask(SIG_BLOCK, &mask, &omask);
470 rtrecv();
471 sigprocmask(SIG_SETMASK, &omask, NULL);
472 }
473 }
474 }
475}
476
477void
36471bd1 478sighandler(int sig)
984263bc
MD
479{
480
481 signo = sig;
482 switch (signo) {
483 case SIGALRM:
484 seenalrm++;
485 break;
486 case SIGQUIT:
487 case SIGTERM:
488 seenquit++;
489 break;
490 case SIGUSR1:
491 case SIGHUP:
492 case SIGINT:
493 seenusr1++;
494 break;
495 }
496}
497
498/*
499 * gracefully exits after resetting sockopts.
500 */
501/* ARGSUSED */
502void
36471bd1 503rtdexit(void)
984263bc
MD
504{
505 struct riprt *rrt;
506
507 alarm(0);
508 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
509 if (rrt->rrt_rflags & RRTF_AGGREGATE) {
510 delroute(&rrt->rrt_info, &rrt->rrt_gw);
511 }
512 }
513 close(ripsock);
514 close(rtsock);
515 syslog(LOG_INFO, "**** Terminated ****");
516 closelog();
517 exit(1);
518}
519
520/*
521 * Called periodically:
522 * 1. age out the learned route. remove it if necessary.
523 * 2. submit RIP6_RESPONSE packets.
524 * Invoked in every SUPPLY_INTERVAL6 (30) seconds. I believe we don't have
525 * to invoke this function in every 1 or 5 or 10 seconds only to age the
526 * routes more precisely.
527 */
528/* ARGSUSED */
529void
36471bd1 530ripalarm(void)
984263bc
MD
531{
532 struct ifc *ifcp;
533 struct riprt *rrt, *rrt_prev, *rrt_next;
534 time_t t_lifetime, t_holddown;
535
536 /* age the RIP routes */
537 rrt_prev = 0;
538 t_lifetime = time(NULL) - RIP_LIFETIME;
539 t_holddown = t_lifetime - RIP_HOLDDOWN;
540 for (rrt = riprt; rrt; rrt = rrt_next) {
541 rrt_next = rrt->rrt_next;
542
543 if (rrt->rrt_t == 0) {
544 rrt_prev = rrt;
545 continue;
546 }
547 if (rrt->rrt_t < t_holddown) {
548 if (rrt_prev) {
549 rrt_prev->rrt_next = rrt->rrt_next;
550 } else {
551 riprt = rrt->rrt_next;
552 }
553 delroute(&rrt->rrt_info, &rrt->rrt_gw);
554 free(rrt);
555 continue;
556 }
557 if (rrt->rrt_t < t_lifetime)
558 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
559 rrt_prev = rrt;
560 }
561 /* Supply updates */
562 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
563 if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP))
564 ripsend(ifcp, &ifcp->ifc_ripsin, 0);
565 }
566 alarm(ripinterval(SUPPLY_INTERVAL6));
567}
568
569void
36471bd1 570init(void)
984263bc
MD
571{
572 int i, int0, int255, error;
573 struct addrinfo hints, *res;
574 char port[10];
575
2038fb68 576 ifc = NULL;
984263bc
MD
577 nifc = 0;
578 nindex2ifc = 0; /*initial guess*/
579 index2ifc = NULL;
580 snprintf(port, sizeof(port), "%d", RIP6_PORT);
581
582 memset(&hints, 0, sizeof(hints));
583 hints.ai_family = PF_INET6;
584 hints.ai_socktype = SOCK_DGRAM;
585 hints.ai_flags = AI_PASSIVE;
586 error = getaddrinfo(NULL, port, &hints, &res);
587 if (error) {
588 fatal("%s", gai_strerror(error));
589 /*NOTREACHED*/
590 }
591 if (res->ai_next) {
592 fatal(":: resolved to multiple address");
593 /*NOTREACHED*/
594 }
595
596 int0 = 0; int255 = 255;
597 ripsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
598 if (ripsock < 0) {
599 fatal("rip socket");
600 /*NOTREACHED*/
601 }
602 if (bind(ripsock, res->ai_addr, res->ai_addrlen) < 0) {
603 fatal("rip bind");
604 /*NOTREACHED*/
605 }
606 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
607 &int255, sizeof(int255)) < 0) {
608 fatal("rip IPV6_MULTICAST_HOPS");
609 /*NOTREACHED*/
610 }
611 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
612 &int0, sizeof(int0)) < 0) {
613 fatal("rip IPV6_MULTICAST_LOOP");
614 /*NOTREACHED*/
615 }
616
617 i = 1;
618#ifdef IPV6_RECVPKTINFO
619 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &i,
620 sizeof(i)) < 0) {
621 fatal("rip IPV6_RECVPKTINFO");
622 /*NOTREACHED*/
623 }
624#else /* old adv. API */
625 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_PKTINFO, &i,
626 sizeof(i)) < 0) {
627 fatal("rip IPV6_PKTINFO");
628 /*NOTREACHED*/
629 }
630#endif
631
632 memset(&hints, 0, sizeof(hints));
633 hints.ai_family = PF_INET6;
634 hints.ai_socktype = SOCK_DGRAM;
635 error = getaddrinfo(RIP6_DEST, port, &hints, &res);
636 if (error) {
637 fatal("%s", gai_strerror(error));
638 /*NOTREACHED*/
639 }
640 if (res->ai_next) {
641 fatal("%s resolved to multiple address", RIP6_DEST);
642 /*NOTREACHED*/
643 }
644 memcpy(&ripsin, res->ai_addr, res->ai_addrlen);
645
646#ifdef FD_ZERO
647 FD_ZERO(&sockvec);
648#else
649 memset(&sockvec, 0, sizeof(sockvec));
650#endif
651 FD_SET(ripsock, &sockvec);
652
653 if (nflag == 0) {
654 if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
655 fatal("route socket");
656 /*NOTREACHED*/
657 }
658 FD_SET(rtsock, &sockvec);
659 } else
660 rtsock = -1; /*just for safety */
661}
662
663#define RIPSIZE(n) \
664 (sizeof(struct rip6) + ((n)-1) * sizeof(struct netinfo6))
665
666/*
667 * ripflush flushes the rip datagram stored in the rip buffer
668 */
669static int nrt;
670static struct netinfo6 *np;
671
672void
36471bd1 673ripflush(struct ifc *ifcp, struct sockaddr_in6 *sin)
984263bc
MD
674{
675 int i;
676 int error;
677
678 if (ifcp)
679 tracet(1, "Send(%s): info(%d) to %s.%d\n",
680 ifcp->ifc_name, nrt,
681 inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
682 else
683 tracet(1, "Send: info(%d) to %s.%d\n",
684 nrt, inet6_n2p(&sin->sin6_addr), ntohs(sin->sin6_port));
685 if (dflag >= 2) {
686 np = ripbuf->rip6_nets;
687 for (i = 0; i < nrt; i++, np++) {
688 if (np->rip6_metric == NEXTHOP_METRIC) {
689 if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest))
690 trace(2, " NextHop reset");
691 else {
692 trace(2, " NextHop %s",
693 inet6_n2p(&np->rip6_dest));
694 }
695 } else {
696 trace(2, " %s/%d[%d]",
697 inet6_n2p(&np->rip6_dest),
698 np->rip6_plen, np->rip6_metric);
699 }
700 if (np->rip6_tag) {
701 trace(2, " tag=0x%04x",
702 ntohs(np->rip6_tag) & 0xffff);
703 }
704 trace(2, "\n");
705 }
706 }
707 error = sendpacket(sin, RIPSIZE(nrt));
708 if (error == EAFNOSUPPORT) {
709 /* Protocol not supported */
710 tracet(1, "Could not send info to %s (%s): "
711 "set IFF_UP to 0\n",
712 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
713 ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */
714 }
715 nrt = 0; np = ripbuf->rip6_nets;
716}
717
718/*
719 * Generate RIP6_RESPONSE packets and send them.
720 */
721void
36471bd1 722ripsend(struct ifc *ifcp, struct sockaddr_in6 *sin, int flag)
984263bc
MD
723{
724 struct riprt *rrt;
725 struct in6_addr *nh; /* next hop */
726 int maxrte;
727
728 if (ifcp == NULL) {
729 /*
730 * Request from non-link local address is not
731 * a regular route6d update.
732 */
733 maxrte = (IFMINMTU - sizeof(struct ip6_hdr) -
734 sizeof(struct udphdr) -
735 sizeof(struct rip6) + sizeof(struct netinfo6)) /
736 sizeof(struct netinfo6);
737 nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
738 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
739 if (rrt->rrt_rflags & RRTF_NOADVERTISE)
740 continue;
741 /* Put the route to the buffer */
742 *np = rrt->rrt_info;
743 np++; nrt++;
744 if (nrt == maxrte) {
745 ripflush(NULL, sin);
746 nh = NULL;
747 }
748 }
749 if (nrt) /* Send last packet */
750 ripflush(NULL, sin);
751 return;
752 }
753
754 if ((flag & RRTF_SENDANYWAY) == 0 &&
755 (qflag || (ifcp->ifc_flags & IFF_LOOPBACK)))
756 return;
757
758 /* -N: no use */
759 if (iff_find(ifcp, 'N') != NULL)
760 return;
761
762 /* -T: generate default route only */
763 if (iff_find(ifcp, 'T') != NULL) {
764 struct netinfo6 rrt_info;
765 memset(&rrt_info, 0, sizeof(struct netinfo6));
766 rrt_info.rip6_dest = in6addr_any;
767 rrt_info.rip6_plen = 0;
768 rrt_info.rip6_metric = 1;
769 rrt_info.rip6_metric += ifcp->ifc_metric;
770 rrt_info.rip6_tag = htons(routetag & 0xffff);
771 np = ripbuf->rip6_nets;
772 *np = rrt_info;
773 nrt = 1;
774 ripflush(ifcp, sin);
775 return;
776 }
777
778 maxrte = (ifcp->ifc_mtu - sizeof(struct ip6_hdr) -
779 sizeof(struct udphdr) -
780 sizeof(struct rip6) + sizeof(struct netinfo6)) /
781 sizeof(struct netinfo6);
782
783 nrt = 0; np = ripbuf->rip6_nets; nh = NULL;
784 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
785 if (rrt->rrt_rflags & RRTF_NOADVERTISE)
786 continue;
787
788 /* Need to check filter here */
789 if (out_filter(rrt, ifcp) == 0)
790 continue;
791
792 /* Check split horizon and other conditions */
793 if (tobeadv(rrt, ifcp) == 0)
794 continue;
795
796 /* Only considers the routes with flag if specified */
797 if ((flag & RRTF_CHANGED) &&
798 (rrt->rrt_rflags & RRTF_CHANGED) == 0)
799 continue;
800
801 /* Check nexthop */
802 if (rrt->rrt_index == ifcp->ifc_index &&
803 !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) &&
804 (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) {
805 if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) {
806 if (nrt == maxrte - 2)
807 ripflush(ifcp, sin);
808 np->rip6_dest = rrt->rrt_gw;
809 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest))
810 SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0);
811 np->rip6_plen = 0;
812 np->rip6_tag = 0;
813 np->rip6_metric = NEXTHOP_METRIC;
814 nh = &rrt->rrt_gw;
815 np++; nrt++;
816 }
817 } else if (nh && (rrt->rrt_index != ifcp->ifc_index ||
818 !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) ||
819 rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) {
820 /* Reset nexthop */
821 if (nrt == maxrte - 2)
822 ripflush(ifcp, sin);
823 memset(np, 0, sizeof(struct netinfo6));
824 np->rip6_metric = NEXTHOP_METRIC;
825 nh = NULL;
826 np++; nrt++;
827 }
828
829 /* Put the route to the buffer */
830 *np = rrt->rrt_info;
831 np++; nrt++;
832 if (nrt == maxrte) {
833 ripflush(ifcp, sin);
834 nh = NULL;
835 }
836 }
837 if (nrt) /* Send last packet */
838 ripflush(ifcp, sin);
839}
840
841/*
842 * outbound filter logic, per-route/interface.
843 */
844int
36471bd1 845out_filter(struct riprt *rrt, struct ifc *ifcp)
984263bc
MD
846{
847 struct iff *iffp;
848 struct in6_addr ia;
849 int ok;
850
851 /*
852 * -A: filter out less specific routes, if we have aggregated
853 * route configured.
854 */
855 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
856 if (iffp->iff_type != 'A')
857 continue;
858 if (rrt->rrt_info.rip6_plen <= iffp->iff_plen)
859 continue;
860 ia = rrt->rrt_info.rip6_dest;
861 applyplen(&ia, iffp->iff_plen);
862 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr))
863 return 0;
864 }
865
866 /*
867 * if it is an aggregated route, advertise it only to the
868 * interfaces specified on -A.
869 */
870 if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) {
871 ok = 0;
872 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
873 if (iffp->iff_type != 'A')
874 continue;
875 if (rrt->rrt_info.rip6_plen == iffp->iff_plen &&
876 IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
877 &iffp->iff_addr)) {
878 ok = 1;
879 break;
880 }
881 }
882 if (!ok)
883 return 0;
884 }
885
886 /*
887 * -O: advertise only if prefix matches the configured prefix.
888 */
889 if (iff_find(ifcp, 'O')) {
890 ok = 0;
891 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
892 if (iffp->iff_type != 'O')
893 continue;
894 if (rrt->rrt_info.rip6_plen < iffp->iff_plen)
895 continue;
896 ia = rrt->rrt_info.rip6_dest;
897 applyplen(&ia, iffp->iff_plen);
898 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
899 ok = 1;
900 break;
901 }
902 }
903 if (!ok)
904 return 0;
905 }
906
907 /* the prefix should be advertised */
908 return 1;
909}
910
911/*
912 * Determine if the route is to be advertised on the specified interface.
913 * It checks options specified in the arguments and the split horizon rule.
914 */
915int
36471bd1 916tobeadv(struct riprt *rrt, struct ifc *ifcp)
984263bc
MD
917{
918
919 /* Special care for static routes */
920 if (rrt->rrt_flags & RTF_STATIC) {
921 /* XXX don't advertise reject/blackhole routes */
922 if (rrt->rrt_flags & (RTF_REJECT | RTF_BLACKHOLE))
923 return 0;
924
925 if (Sflag) /* Yes, advertise it anyway */
926 return 1;
927 if (sflag && rrt->rrt_index != ifcp->ifc_index)
928 return 1;
929 return 0;
930 }
931 /* Regular split horizon */
932 if (hflag == 0 && rrt->rrt_index == ifcp->ifc_index)
933 return 0;
934 return 1;
935}
936
937/*
938 * Send a rip packet actually.
939 */
940int
36471bd1 941sendpacket(struct sockaddr_in6 *sin, int len)
984263bc
MD
942{
943 /*
944 * MSG_DONTROUTE should not be specified when it responds with a
945 * RIP6_REQUEST message. SO_DONTROUTE has been specified to
946 * other sockets.
947 */
948 struct msghdr m;
949 struct cmsghdr *cm;
950 struct iovec iov[2];
951 u_char cmsgbuf[256];
952 struct in6_pktinfo *pi;
953 int idx;
954 struct sockaddr_in6 sincopy;
955
956 /* do not overwrite the given sin */
957 sincopy = *sin;
958 sin = &sincopy;
959
960 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)
961 || IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) {
962 idx = IN6_LINKLOCAL_IFINDEX(sin->sin6_addr);
963 SET_IN6_LINKLOCAL_IFINDEX(sin->sin6_addr, 0);
964 } else
965 idx = 0;
966
967 m.msg_name = (caddr_t)sin;
968 m.msg_namelen = sizeof(*sin);
969 iov[0].iov_base = (caddr_t)ripbuf;
970 iov[0].iov_len = len;
971 m.msg_iov = iov;
972 m.msg_iovlen = 1;
973 if (!idx) {
974 m.msg_control = NULL;
975 m.msg_controllen = 0;
976 } else {
977 memset(cmsgbuf, 0, sizeof(cmsgbuf));
978 cm = (struct cmsghdr *)cmsgbuf;
979 m.msg_control = (caddr_t)cm;
980 m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
981
982 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
983 cm->cmsg_level = IPPROTO_IPV6;
984 cm->cmsg_type = IPV6_PKTINFO;
985 pi = (struct in6_pktinfo *)CMSG_DATA(cm);
986 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*::*/
987 pi->ipi6_ifindex = idx;
988 }
989
990 if (sendmsg(ripsock, &m, 0 /*MSG_DONTROUTE*/) < 0) {
991 trace(1, "sendmsg: %s\n", strerror(errno));
992 return errno;
993 }
994
995 return 0;
996}
997
998/*
999 * Receive and process RIP packets. Update the routes/kernel forwarding
1000 * table if necessary.
1001 */
1002void
36471bd1 1003riprecv(void)
984263bc
MD
1004{
1005 struct ifc *ifcp, *ic;
1006 struct sockaddr_in6 fsock;
1007 struct in6_addr nh; /* next hop */
1008 struct rip6 *rp;
1009 struct netinfo6 *np, *nq;
1010 struct riprt *rrt;
1011 int len, nn, need_trigger, idx;
1012 char buf[4 * RIP6_MAXMTU];
1013 time_t t;
1014 struct msghdr m;
1015 struct cmsghdr *cm;
1016 struct iovec iov[2];
1017 u_char cmsgbuf[256];
1018 struct in6_pktinfo *pi;
1019 struct iff *iffp;
1020 struct in6_addr ia;
1021 int ok;
1022 time_t t_half_lifetime;
1023
1024 need_trigger = 0;
1025
1026 m.msg_name = (caddr_t)&fsock;
1027 m.msg_namelen = sizeof(fsock);
1028 iov[0].iov_base = (caddr_t)buf;
1029 iov[0].iov_len = sizeof(buf);
1030 m.msg_iov = iov;
1031 m.msg_iovlen = 1;
1032 cm = (struct cmsghdr *)cmsgbuf;
1033 m.msg_control = (caddr_t)cm;
1034 m.msg_controllen = sizeof(cmsgbuf);
1035 if ((len = recvmsg(ripsock, &m, 0)) < 0) {
1036 fatal("recvmsg");
1037 /*NOTREACHED*/
1038 }
1039 idx = 0;
1040 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
1041 cm;
1042 cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
1043 if (cm->cmsg_level == IPPROTO_IPV6 &&
1044 cm->cmsg_type == IPV6_PKTINFO) {
1045 pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
1046 idx = pi->ipi6_ifindex;
1047 break;
1048 }
1049 }
1050 if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
1051 SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx);
1052
1053 nh = fsock.sin6_addr;
1054 nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
1055 sizeof(struct netinfo6);
1056 rp = (struct rip6 *)buf;
1057 np = rp->rip6_nets;
1058
1059 if (rp->rip6_vers != RIP6_VERSION) {
1060 trace(1, "Incorrect RIP version %d\n", rp->rip6_vers);
1061 return;
1062 }
1063 if (rp->rip6_cmd == RIP6_REQUEST) {
1064 if (idx && idx < nindex2ifc) {
1065 ifcp = index2ifc[idx];
1066 riprequest(ifcp, np, nn, &fsock);
1067 } else {
1068 riprequest(NULL, np, nn, &fsock);
1069 }
1070 return;
1071 }
1072
1073 if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
1074 trace(1, "Packets from non-ll addr: %s\n",
1075 inet6_n2p(&fsock.sin6_addr));
1076 return; /* Ignore packets from non-link-local addr */
1077 }
1078 idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
1079 ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
1080 if (!ifcp) {
1081 trace(1, "Packets to unknown interface index %d\n", idx);
1082 return; /* Ignore it */
1083 }
1084 if (IN6_ARE_ADDR_EQUAL(&ifcp->ifc_mylladdr, &fsock.sin6_addr))
1085 return; /* The packet is from me; ignore */
1086 if (rp->rip6_cmd != RIP6_RESPONSE) {
1087 trace(1, "Invalid command %d\n", rp->rip6_cmd);
1088 return;
1089 }
1090
1091 /* -N: no use */
1092 if (iff_find(ifcp, 'N') != NULL)
1093 return;
1094
1095 tracet(1, "Recv(%s): from %s.%d info(%d)\n",
1096 ifcp->ifc_name, inet6_n2p(&nh), ntohs(fsock.sin6_port), nn);
1097
1098 t = time(NULL);
1099 t_half_lifetime = t - (RIP_LIFETIME/2);
1100 for (; nn; nn--, np++) {
1101 if (np->rip6_metric == NEXTHOP_METRIC) {
1102 /* modify neighbor address */
1103 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1104 nh = np->rip6_dest;
1105 SET_IN6_LINKLOCAL_IFINDEX(nh, idx);
1106 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1107 } else if (IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest)) {
1108 nh = fsock.sin6_addr;
1109 trace(1, "\tNexthop: %s\n", inet6_n2p(&nh));
1110 } else {
1111 nh = fsock.sin6_addr;
1112 trace(1, "\tInvalid Nexthop: %s\n",
1113 inet6_n2p(&np->rip6_dest));
1114 }
1115 continue;
1116 }
1117 if (IN6_IS_ADDR_MULTICAST(&np->rip6_dest)) {
1118 trace(1, "\tMulticast netinfo6: %s/%d [%d]\n",
1119 inet6_n2p(&np->rip6_dest),
1120 np->rip6_plen, np->rip6_metric);
1121 continue;
1122 }
1123 if (IN6_IS_ADDR_LOOPBACK(&np->rip6_dest)) {
1124 trace(1, "\tLoopback netinfo6: %s/%d [%d]\n",
1125 inet6_n2p(&np->rip6_dest),
1126 np->rip6_plen, np->rip6_metric);
1127 continue;
1128 }
1129 if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) {
1130 trace(1, "\tLink Local netinfo6: %s/%d [%d]\n",
1131 inet6_n2p(&np->rip6_dest),
1132 np->rip6_plen, np->rip6_metric);
1133 continue;
1134 }
1135 /* may need to pass sitelocal prefix in some case, however*/
1136 if (IN6_IS_ADDR_SITELOCAL(&np->rip6_dest) && !lflag) {
1137 trace(1, "\tSite Local netinfo6: %s/%d [%d]\n",
1138 inet6_n2p(&np->rip6_dest),
1139 np->rip6_plen, np->rip6_metric);
1140 continue;
1141 }
1142 trace(2, "\tnetinfo6: %s/%d [%d]",
1143 inet6_n2p(&np->rip6_dest),
1144 np->rip6_plen, np->rip6_metric);
1145 if (np->rip6_tag)
1146 trace(2, " tag=0x%04x", ntohs(np->rip6_tag) & 0xffff);
1147 if (dflag >= 2) {
1148 ia = np->rip6_dest;
1149 applyplen(&ia, np->rip6_plen);
1150 if (!IN6_ARE_ADDR_EQUAL(&ia, &np->rip6_dest))
1151 trace(2, " [junk outside prefix]");
1152 }
1153
1154 /*
1155 * -L: listen only if the prefix matches the configuration
1156 */
1157 ok = 1; /* if there's no L filter, it is ok */
1158 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
1159 if (iffp->iff_type != 'L')
1160 continue;
1161 ok = 0;
1162 if (np->rip6_plen < iffp->iff_plen)
1163 continue;
1164 /* special rule: ::/0 means default, not "in /0" */
1165 if (iffp->iff_plen == 0 && np->rip6_plen > 0)
1166 continue;
1167 ia = np->rip6_dest;
1168 applyplen(&ia, iffp->iff_plen);
1169 if (IN6_ARE_ADDR_EQUAL(&ia, &iffp->iff_addr)) {
1170 ok = 1;
1171 break;
1172 }
1173 }
1174 if (!ok) {
1175 trace(2, " (filtered)\n");
1176 continue;
1177 }
1178
1179 trace(2, "\n");
1180 np->rip6_metric++;
1181 np->rip6_metric += ifcp->ifc_metric;
1182 if (np->rip6_metric > HOPCNT_INFINITY6)
1183 np->rip6_metric = HOPCNT_INFINITY6;
1184
1185 applyplen(&np->rip6_dest, np->rip6_plen);
1186 if ((rrt = rtsearch(np, NULL)) != NULL) {
1187 if (rrt->rrt_t == 0)
1188 continue; /* Intf route has priority */
1189 nq = &rrt->rrt_info;
1190 if (nq->rip6_metric > np->rip6_metric) {
1191 if (rrt->rrt_index == ifcp->ifc_index &&
1192 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1193 /* Small metric from the same gateway */
1194 nq->rip6_metric = np->rip6_metric;
1195 } else {
1196 /* Better route found */
1197 rrt->rrt_index = ifcp->ifc_index;
1198 /* Update routing table */
1199 delroute(nq, &rrt->rrt_gw);
1200 rrt->rrt_gw = nh;
1201 *nq = *np;
1202 addroute(rrt, &nh, ifcp);
1203 }
1204 rrt->rrt_rflags |= RRTF_CHANGED;
1205 rrt->rrt_t = t;
1206 need_trigger = 1;
1207 } else if (nq->rip6_metric < np->rip6_metric &&
1208 rrt->rrt_index == ifcp->ifc_index &&
1209 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1210 /* Got worse route from same gw */
1211 nq->rip6_metric = np->rip6_metric;
1212 rrt->rrt_t = t;
1213 rrt->rrt_rflags |= RRTF_CHANGED;
1214 need_trigger = 1;
1215 } else if (nq->rip6_metric == np->rip6_metric &&
1216 np->rip6_metric < HOPCNT_INFINITY6) {
1217 if (rrt->rrt_index == ifcp->ifc_index &&
1218 IN6_ARE_ADDR_EQUAL(&nh, &rrt->rrt_gw)) {
1219 /* same metric, same route from same gw */
1220 rrt->rrt_t = t;
1221 } else if (rrt->rrt_t < t_half_lifetime) {
1222 /* Better route found */
1223 rrt->rrt_index = ifcp->ifc_index;
1224 /* Update routing table */
1225 delroute(nq, &rrt->rrt_gw);
1226 rrt->rrt_gw = nh;
1227 *nq = *np;
1228 addroute(rrt, &nh, ifcp);
1229 rrt->rrt_rflags |= RRTF_CHANGED;
1230 rrt->rrt_t = t;
1231 }
1232 }
1233 /*
1234 * if nq->rip6_metric == HOPCNT_INFINITY6 then
1235 * do not update age value. Do nothing.
1236 */
1237 } else if (np->rip6_metric < HOPCNT_INFINITY6) {
1238 /* Got a new valid route */
1239 if ((rrt = MALLOC(struct riprt)) == NULL) {
1240 fatal("malloc: struct riprt");
1241 /*NOTREACHED*/
1242 }
1243 memset(rrt, 0, sizeof(*rrt));
1244 nq = &rrt->rrt_info;
1245
1246 rrt->rrt_same = NULL;
1247 rrt->rrt_index = ifcp->ifc_index;
1248 rrt->rrt_flags = RTF_UP|RTF_GATEWAY;
1249 rrt->rrt_gw = nh;
1250 *nq = *np;
1251 applyplen(&nq->rip6_dest, nq->rip6_plen);
1252 if (nq->rip6_plen == sizeof(struct in6_addr) * 8)
1253 rrt->rrt_flags |= RTF_HOST;
1254
1255 /* Put the route to the list */
1256 rrt->rrt_next = riprt;
1257 riprt = rrt;
1258 /* Update routing table */
1259 addroute(rrt, &nh, ifcp);
1260 rrt->rrt_rflags |= RRTF_CHANGED;
1261 need_trigger = 1;
1262 rrt->rrt_t = t;
1263 }
1264 }
1265 /* XXX need to care the interval between triggered updates */
1266 if (need_trigger) {
1267 if (nextalarm > time(NULL) + RIP_TRIG_INT6_MAX) {
1268 for (ic = ifc; ic; ic = ic->ifc_next) {
1269 if (ifcp->ifc_index == ic->ifc_index)
1270 continue;
1271 if (ic->ifc_flags & IFF_UP)
1272 ripsend(ic, &ic->ifc_ripsin,
1273 RRTF_CHANGED);
1274 }
1275 }
1276 /* Reset the flag */
1277 for (rrt = riprt; rrt; rrt = rrt->rrt_next)
1278 rrt->rrt_rflags &= ~RRTF_CHANGED;
1279 }
1280}
1281
1282/*
1283 * Send all routes request packet to the specified interface.
1284 */
1285void
36471bd1 1286sendrequest(struct ifc *ifcp)
984263bc
MD
1287{
1288 struct netinfo6 *np;
1289 int error;
1290
1291 if (ifcp->ifc_flags & IFF_LOOPBACK)
1292 return;
1293 ripbuf->rip6_cmd = RIP6_REQUEST;
1294 np = ripbuf->rip6_nets;
1295 memset(np, 0, sizeof(struct netinfo6));
1296 np->rip6_metric = HOPCNT_INFINITY6;
1297 tracet(1, "Send rtdump Request to %s (%s)\n",
1298 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1299 error = sendpacket(&ifcp->ifc_ripsin, RIPSIZE(1));
1300 if (error == EAFNOSUPPORT) {
1301 /* Protocol not supported */
1302 tracet(1, "Could not send rtdump Request to %s (%s): "
1303 "set IFF_UP to 0\n",
1304 ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr));
1305 ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */
1306 }
1307 ripbuf->rip6_cmd = RIP6_RESPONSE;
1308}
1309
1310/*
1311 * Process a RIP6_REQUEST packet.
1312 */
1313void
36471bd1
SW
1314riprequest(struct ifc *ifcp, struct netinfo6 *np, int nn,
1315 struct sockaddr_in6 *sin)
984263bc
MD
1316{
1317 int i;
1318 struct riprt *rrt;
1319
1320 if (!(nn == 1 && IN6_IS_ADDR_UNSPECIFIED(&np->rip6_dest) &&
1321 np->rip6_plen == 0 && np->rip6_metric == HOPCNT_INFINITY6)) {
1322 /* Specific response, don't split-horizon */
1323 trace(1, "\tRIP Request\n");
1324 for (i = 0; i < nn; i++, np++) {
1325 rrt = rtsearch(np, NULL);
1326 if (rrt)
1327 np->rip6_metric = rrt->rrt_info.rip6_metric;
1328 else
1329 np->rip6_metric = HOPCNT_INFINITY6;
1330 }
71126e33 1331 sendpacket(sin, RIPSIZE(nn));
984263bc
MD
1332 return;
1333 }
1334 /* Whole routing table dump */
1335 trace(1, "\tRIP Request -- whole routing table\n");
1336 ripsend(ifcp, sin, RRTF_SENDANYWAY);
1337}
1338
1339/*
1340 * Get information of each interface.
1341 */
1342void
36471bd1 1343ifconfig(void)
984263bc
MD
1344{
1345 struct ifaddrs *ifap, *ifa;
1346 struct ifc *ifcp;
1347 struct ipv6_mreq mreq;
1348 int s;
1349
1350 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1351 fatal("socket");
1352 /*NOTREACHED*/
1353 }
1354
1355 if (getifaddrs(&ifap) != 0) {
1356 fatal("getifaddrs");
1357 /*NOTREACHED*/
1358 }
1359
1360 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1361 if (ifa->ifa_addr->sa_family != AF_INET6)
1362 continue;
1363 ifcp = ifc_find(ifa->ifa_name);
1364 /* we are interested in multicast-capable interfaces */
1365 if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
1366 continue;
1367 if (!ifcp) {
1368 /* new interface */
1369 if ((ifcp = MALLOC(struct ifc)) == NULL) {
1370 fatal("malloc: struct ifc");
1371 /*NOTREACHED*/
1372 }
1373 memset(ifcp, 0, sizeof(*ifcp));
1374 ifcp->ifc_index = -1;
1375 ifcp->ifc_next = ifc;
1376 ifc = ifcp;
1377 nifc++;
1378 ifcp->ifc_name = allocopy(ifa->ifa_name);
1379 ifcp->ifc_addr = 0;
1380 ifcp->ifc_filter = 0;
1381 ifcp->ifc_flags = ifa->ifa_flags;
1382 trace(1, "newif %s <%s>\n", ifcp->ifc_name,
1383 ifflags(ifcp->ifc_flags));
1384 if (!strcmp(ifcp->ifc_name, LOOPBACK_IF))
1385 loopifcp = ifcp;
1386 } else {
1387 /* update flag, this may be up again */
1388 if (ifcp->ifc_flags != ifa->ifa_flags) {
1389 trace(1, "%s: <%s> -> ", ifcp->ifc_name,
1390 ifflags(ifcp->ifc_flags));
1391 trace(1, "<%s>\n", ifflags(ifa->ifa_flags));
1392 ifcp->ifc_cflags |= IFC_CHANGED;
1393 }
1394 ifcp->ifc_flags = ifa->ifa_flags;
1395 }
1396 ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s);
1397 if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP
1398 && 0 < ifcp->ifc_index && !ifcp->ifc_joined) {
1399 mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr;
1400 mreq.ipv6mr_interface = ifcp->ifc_index;
1401 if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1402 &mreq, sizeof(mreq)) < 0) {
1403 fatal("IPV6_JOIN_GROUP");
1404 /*NOTREACHED*/
1405 }
1406 trace(1, "join %s %s\n", ifcp->ifc_name, RIP6_DEST);
1407 ifcp->ifc_joined++;
1408 }
1409 }
1410 close(s);
1411 freeifaddrs(ifap);
1412}
1413
1414void
36471bd1 1415ifconfig1(const char *name, const struct sockaddr *sa, struct ifc *ifcp, int s)
984263bc
MD
1416{
1417 struct in6_ifreq ifr;
1418 const struct sockaddr_in6 *sin;
1419 struct ifac *ifa;
1420 int plen;
1421 char buf[BUFSIZ];
1422
1423 sin = (const struct sockaddr_in6 *)sa;
1424 ifr.ifr_addr = *sin;
1425 strcpy(ifr.ifr_name, name);
1426 if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) {
1427 fatal("ioctl: SIOCGIFNETMASK_IN6");
1428 /*NOTREACHED*/
1429 }
1430 plen = sin6mask2len(&ifr.ifr_addr);
1431 if ((ifa = ifa_match(ifcp, &sin->sin6_addr, plen)) != NULL) {
1432 /* same interface found */
1433 /* need check if something changed */
1434 /* XXX not yet implemented */
1435 return;
1436 }
1437 /*
1438 * New address is found
1439 */
1440 if ((ifa = MALLOC(struct ifac)) == NULL) {
1441 fatal("malloc: struct ifac");
1442 /*NOTREACHED*/
1443 }
1444 memset(ifa, 0, sizeof(*ifa));
1445 ifa->ifa_conf = ifcp;
1446 ifa->ifa_next = ifcp->ifc_addr;
1447 ifcp->ifc_addr = ifa;
1448 ifa->ifa_addr = sin->sin6_addr;
1449 ifa->ifa_plen = plen;
1450 if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1451 ifr.ifr_addr = *sin;
1452 if (ioctl(s, SIOCGIFDSTADDR_IN6, (char *)&ifr) < 0) {
1453 fatal("ioctl: SIOCGIFDSTADDR_IN6");
1454 /*NOTREACHED*/
1455 }
1456 ifa->ifa_raddr = ifr.ifr_dstaddr.sin6_addr;
1457 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr, buf, sizeof(buf));
1458 trace(1, "found address %s/%d -- %s\n",
1459 inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen, buf);
1460 } else {
1461 trace(1, "found address %s/%d\n",
1462 inet6_n2p(&ifa->ifa_addr), ifa->ifa_plen);
1463 }
1464 if (ifcp->ifc_index < 0 && IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
1465 ifcp->ifc_mylladdr = ifa->ifa_addr;
1466 ifcp->ifc_index = IN6_LINKLOCAL_IFINDEX(ifa->ifa_addr);
1467 memcpy(&ifcp->ifc_ripsin, &ripsin, ripsin.ss_len);
1468 SET_IN6_LINKLOCAL_IFINDEX(ifcp->ifc_ripsin.sin6_addr,
1469 ifcp->ifc_index);
1470 setindex2ifc(ifcp->ifc_index, ifcp);
1471 ifcp->ifc_mtu = getifmtu(ifcp->ifc_index);
1472 if (ifcp->ifc_mtu > RIP6_MAXMTU)
1473 ifcp->ifc_mtu = RIP6_MAXMTU;
1474 if (ioctl(s, SIOCGIFMETRIC, (char *)&ifr) < 0) {
1475 fatal("ioctl: SIOCGIFMETRIC");
1476 /*NOTREACHED*/
1477 }
1478 ifcp->ifc_metric = ifr.ifr_metric;
1479 trace(1, "\tindex: %d, mtu: %d, metric: %d\n",
1480 ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric);
1481 } else
1482 ifcp->ifc_cflags |= IFC_CHANGED;
1483}
1484
1485/*
1486 * Receive and process routing messages.
1487 * Update interface information as necesssary.
1488 */
1489void
36471bd1 1490rtrecv(void)
984263bc
MD
1491{
1492 char buf[BUFSIZ];
1493 char *p, *q;
1494 struct rt_msghdr *rtm;
1495 struct ifa_msghdr *ifam;
1496 struct if_msghdr *ifm;
1497 int len;
1498 struct ifc *ifcp, *ic;
1499 int iface = 0, rtable = 0;
1500 struct sockaddr_in6 *rta[RTAX_MAX];
1501 struct sockaddr_in6 mask;
1502 int i, addrs;
1503 struct riprt *rrt;
1504
1505 if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
1506 perror("read from rtsock");
1507 exit(1);
1508 }
1509 if (len < sizeof(*rtm)) {
1510 trace(1, "short read from rtsock: %d (should be > %lu)\n",
1511 len, (u_long)sizeof(*rtm));
1512 return;
1513 }
1514
1515 for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) {
1516 /* safety against bogus message */
1517 if (((struct rt_msghdr *)p)->rtm_msglen <= 0) {
1518 trace(1, "bogus rtmsg: length=%d\n",
1519 ((struct rt_msghdr *)p)->rtm_msglen);
1520 break;
1521 }
1522 rtm = NULL;
1523 ifam = NULL;
1524 ifm = NULL;
1525 switch (((struct rt_msghdr *)p)->rtm_type) {
1526 case RTM_NEWADDR:
1527 case RTM_DELADDR:
1528 ifam = (struct ifa_msghdr *)p;
1529 addrs = ifam->ifam_addrs;
1530 q = (char *)(ifam + 1);
1531 break;
1532 case RTM_IFINFO:
1533 ifm = (struct if_msghdr *)p;
1534 addrs = ifm->ifm_addrs;
1535 q = (char *)(ifm + 1);
1536 break;
1537 default:
1538 rtm = (struct rt_msghdr *)p;
1539 addrs = rtm->rtm_addrs;
1540 q = (char *)(rtm + 1);
1541 if (rtm->rtm_version != RTM_VERSION) {
1542 trace(1, "unexpected rtmsg version %d "
1543 "(should be %d)\n",
1544 rtm->rtm_version, RTM_VERSION);
1545 continue;
1546 }
1547 if (rtm->rtm_pid == pid) {
1548#if 0
1549 trace(1, "rtmsg looped back to me, ignored\n");
1550#endif
1551 continue;
1552 }
1553 break;
1554 }
1555 memset(&rta, 0, sizeof(rta));
1556 for (i = 0; i < RTAX_MAX; i++) {
1557 if (addrs & (1 << i)) {
1558 rta[i] = (struct sockaddr_in6 *)q;
1559 q += ROUNDUP(rta[i]->sin6_len);
1560 }
1561 }
1562
1563 trace(1, "rtsock: %s (addrs=%x)\n",
1564 rttypes((struct rt_msghdr *)p), addrs);
1565 if (dflag >= 2) {
1566 for (i = 0;
1567 i < ((struct rt_msghdr *)p)->rtm_msglen;
1568 i++) {
1569 fprintf(stderr, "%02x ", p[i] & 0xff);
1570 if (i % 16 == 15) fprintf(stderr, "\n");
1571 }
1572 fprintf(stderr, "\n");
1573 }
1574
1575 /*
1576 * Easy ones first.
1577 *
1578 * We may be able to optimize by using ifm->ifm_index or
1579 * ifam->ifam_index. For simplicity we don't do that here.
1580 */
1581 switch (((struct rt_msghdr *)p)->rtm_type) {
1582 case RTM_NEWADDR:
1583 case RTM_IFINFO:
1584 iface++;
1585 continue;
1586 case RTM_ADD:
1587 rtable++;
1588 continue;
1589 case RTM_LOSING:
1590 case RTM_MISS:
1591 case RTM_RESOLVE:
1592 case RTM_GET:
1593 case RTM_LOCK:
1594 /* nothing to be done here */
1595 trace(1, "\tnothing to be done, ignored\n");
1596 continue;
1597 }
1598
1599#if 0
1600 if (rta[RTAX_DST] == NULL) {
1601 trace(1, "\tno destination, ignored\n");
1602 continue;
1603 }
1604 if (rta[RTAX_DST]->sin6_family != AF_INET6) {
1605 trace(1, "\taf mismatch, ignored\n");
1606 continue;
1607 }
1608 if (IN6_IS_ADDR_LINKLOCAL(&rta[RTAX_DST]->sin6_addr)) {
1609 trace(1, "\tlinklocal destination, ignored\n");
1610 continue;
1611 }
1612 if (IN6_ARE_ADDR_EQUAL(&rta[RTAX_DST]->sin6_addr, &in6addr_loopback)) {
1613 trace(1, "\tloopback destination, ignored\n");
1614 continue; /* Loopback */
1615 }
1616 if (IN6_IS_ADDR_MULTICAST(&rta[RTAX_DST]->sin6_addr)) {
1617 trace(1, "\tmulticast destination, ignored\n");
1618 continue;
1619 }
1620#endif
1621
1622 /* hard ones */
1623 switch (((struct rt_msghdr *)p)->rtm_type) {
1624 case RTM_NEWADDR:
1625 case RTM_IFINFO:
1626 case RTM_ADD:
1627 case RTM_LOSING:
1628 case RTM_MISS:
1629 case RTM_RESOLVE:
1630 case RTM_GET:
1631 case RTM_LOCK:
1632 /* should already be handled */
1633 fatal("rtrecv: never reach here");
1634 /*NOTREACHED*/
1635 case RTM_DELETE:
1636 if (!rta[RTAX_DST] || !rta[RTAX_GATEWAY]) {
1637 trace(1, "\tsome of dst/gw/netamsk are "
1638 "unavailable, ignored\n");
1639 break;
1640 }
1641 if ((rtm->rtm_flags & RTF_HOST) != 0) {
1642 mask.sin6_len = sizeof(mask);
1643 memset(&mask.sin6_addr, 0xff,
1644 sizeof(mask.sin6_addr));
1645 rta[RTAX_NETMASK] = &mask;
1646 } else if (!rta[RTAX_NETMASK]) {
1647 trace(1, "\tsome of dst/gw/netamsk are "
1648 "unavailable, ignored\n");
1649 break;
1650 }
1651 if (rt_del(rta[RTAX_DST], rta[RTAX_GATEWAY],
1652 rta[RTAX_NETMASK]) == 0) {
1653 rtable++; /*just to be sure*/
1654 }
1655 break;
1656 case RTM_CHANGE:
1657 case RTM_REDIRECT:
1658 trace(1, "\tnot supported yet, ignored\n");
1659 break;
1660 case RTM_DELADDR:
1661 if (!rta[RTAX_NETMASK] || !rta[RTAX_IFA]) {
1662 trace(1, "\tno netmask or ifa given, ignored\n");
1663 break;
1664 }
1665 if (ifam->ifam_index < nindex2ifc)
1666 ifcp = index2ifc[ifam->ifam_index];
1667 else
1668 ifcp = NULL;
1669 if (!ifcp) {
1670 trace(1, "\tinvalid ifam_index %d, ignored\n",
1671 ifam->ifam_index);
1672 break;
1673 }
1674 if (!rt_deladdr(ifcp, rta[RTAX_IFA], rta[RTAX_NETMASK]))
1675 iface++;
1676 break;
1677 case RTM_OLDADD:
1678 case RTM_OLDDEL:
1679 trace(1, "\tnot supported yet, ignored\n");
1680 break;
1681 }
1682
1683 }
1684
1685 if (iface) {
1686 trace(1, "rtsock: reconfigure interfaces, refresh interface routes\n");
1687 ifconfig();
1688 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next)
1689 if (ifcp->ifc_cflags & IFC_CHANGED) {
1690 if (ifrt(ifcp, 1)) {
1691 for (ic = ifc; ic; ic = ic->ifc_next) {
1692 if (ifcp->ifc_index == ic->ifc_index)
1693 continue;
1694 if (ic->ifc_flags & IFF_UP)
1695 ripsend(ic, &ic->ifc_ripsin,
1696 RRTF_CHANGED);
1697 }
1698 /* Reset the flag */
1699 for (rrt = riprt; rrt; rrt = rrt->rrt_next)
1700 rrt->rrt_rflags &= ~RRTF_CHANGED;
1701 }
1702 ifcp->ifc_cflags &= ~IFC_CHANGED;
1703 }
1704 }
1705 if (rtable) {
1706 trace(1, "rtsock: read routing table again\n");
1707 krtread(1);
1708 }
1709}
1710
1711/*
1712 * remove specified route from the internal routing table.
1713 */
1714int
36471bd1
SW
1715rt_del(const struct sockaddr_in6 *sdst, const struct sockaddr_in6 *sgw,
1716 const struct sockaddr_in6 *smask)
984263bc
MD
1717{
1718 const struct in6_addr *dst = NULL;
1719 const struct in6_addr *gw = NULL;
1720 int prefix;
1721 struct netinfo6 ni6;
1722 struct riprt *rrt = NULL;
1723 time_t t_lifetime;
1724
1725 if (sdst->sin6_family != AF_INET6) {
1726 trace(1, "\tother AF, ignored\n");
1727 return -1;
1728 }
1729 if (IN6_IS_ADDR_LINKLOCAL(&sdst->sin6_addr)
1730 || IN6_ARE_ADDR_EQUAL(&sdst->sin6_addr, &in6addr_loopback)
1731 || IN6_IS_ADDR_MULTICAST(&sdst->sin6_addr)) {
1732 trace(1, "\taddress %s not interesting, ignored\n",
1733 inet6_n2p(&sdst->sin6_addr));
1734 return -1;
1735 }
1736 dst = &sdst->sin6_addr;
1737 if (sgw->sin6_family == AF_INET6) {
1738 /* easy case */
1739 gw = &sgw->sin6_addr;
1740 prefix = sin6mask2len(smask);
1741 } else if (sgw->sin6_family == AF_LINK) {
1742 /*
1743 * Interface route... a hard case. We need to get the prefix
1744 * length from the kernel, but we now are parsing rtmsg.
1745 * We'll purge matching routes from my list, then get the
1746 * fresh list.
1747 */
1748 struct riprt *longest;
1749 trace(1, "\t%s is a interface route, guessing prefixlen\n",
1750 inet6_n2p(dst));
1751 longest = NULL;
1752 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
1753 if (IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
1754 &sdst->sin6_addr)
1755 && IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)) {
1756 if (!longest
1757 || longest->rrt_info.rip6_plen <
1758 rrt->rrt_info.rip6_plen) {
1759 longest = rrt;
1760 }
1761 }
1762 }
1763 rrt = longest;
1764 if (!rrt) {
1765 trace(1, "\tno matching interface route found\n");
1766 return -1;
1767 }
1768 gw = &in6addr_loopback;
1769 prefix = rrt->rrt_info.rip6_plen;
1770 } else {
1771 trace(1, "\tunsupported af: (gw=%d)\n", sgw->sin6_family);
1772 return -1;
1773 }
1774
1775 trace(1, "\tdeleting %s/%d ", inet6_n2p(dst), prefix);
1776 trace(1, "gw %s\n", inet6_n2p(gw));
1777 t_lifetime = time(NULL) - RIP_LIFETIME;
1778 /* age route for interface address */
1779 memset(&ni6, 0, sizeof(ni6));
1780 ni6.rip6_dest = *dst;
1781 ni6.rip6_plen = prefix;
1782 applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/
1783 trace(1, "\tfind route %s/%d\n", inet6_n2p(&ni6.rip6_dest),
1784 ni6.rip6_plen);
1785 if (!rrt && (rrt = rtsearch(&ni6, NULL)) == NULL) {
1786 trace(1, "\tno route found\n");
1787 return -1;
1788 }
1789#if 0
1790 if ((rrt->rrt_flags & RTF_STATIC) == 0) {
1791 trace(1, "\tyou can delete static routes only\n");
1792 } else
1793#endif
1794 if (!IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, gw)) {
1795 trace(1, "\tgw mismatch: %s <-> ",
1796 inet6_n2p(&rrt->rrt_gw));
1797 trace(1, "%s\n", inet6_n2p(gw));
1798 } else {
1799 trace(1, "\troute found, age it\n");
1800 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1801 rrt->rrt_t = t_lifetime;
1802 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
1803 }
1804 }
1805 return 0;
1806}
1807
1808/*
1809 * remove specified address from internal interface/routing table.
1810 */
1811int
36471bd1
SW
1812rt_deladdr(struct ifc *ifcp, const struct sockaddr_in6 *sifa,
1813 const struct sockaddr_in6 *smask)
984263bc
MD
1814{
1815 const struct in6_addr *addr = NULL;
1816 int prefix;
1817 struct ifac *ifa = NULL;
1818 struct netinfo6 ni6;
1819 struct riprt *rrt = NULL;
1820 time_t t_lifetime;
1821 int updated = 0;
1822
1823 if (sifa->sin6_family != AF_INET6) {
1824 trace(1, "\tother AF, ignored\n");
1825 return -1;
1826 }
1827 addr = &sifa->sin6_addr;
1828 prefix = sin6mask2len(smask);
1829
1830 trace(1, "\tdeleting %s/%d from %s\n",
1831 inet6_n2p(addr), prefix, ifcp->ifc_name);
1832 ifa = ifa_match(ifcp, addr, prefix);
1833 if (!ifa) {
1834 trace(1, "\tno matching ifa found for %s/%d on %s\n",
1835 inet6_n2p(addr), prefix, ifcp->ifc_name);
1836 return -1;
1837 }
1838 if (ifa->ifa_conf != ifcp) {
1839 trace(1, "\taddress table corrupt: back pointer does not match "
1840 "(%s != %s)\n",
1841 ifcp->ifc_name, ifa->ifa_conf->ifc_name);
1842 return -1;
1843 }
1844 /* remove ifa from interface */
1845 if (ifcp->ifc_addr == ifa)
1846 ifcp->ifc_addr = ifa->ifa_next;
1847 else {
1848 struct ifac *p;
1849 for (p = ifcp->ifc_addr; p; p = p->ifa_next) {
1850 if (p->ifa_next == ifa) {
1851 p->ifa_next = ifa->ifa_next;
1852 break;
1853 }
1854 }
1855 }
1856 ifa->ifa_next = NULL;
1857 ifa->ifa_conf = NULL;
1858 t_lifetime = time(NULL) - RIP_LIFETIME;
1859 /* age route for interface address */
1860 memset(&ni6, 0, sizeof(ni6));
1861 ni6.rip6_dest = ifa->ifa_addr;
1862 ni6.rip6_plen = ifa->ifa_plen;
1863 applyplen(&ni6.rip6_dest, ni6.rip6_plen);
1864 trace(1, "\tfind interface route %s/%d on %d\n",
1865 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen, ifcp->ifc_index);
1866 if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
1867 struct in6_addr none;
1868 memset(&none, 0, sizeof(none));
1869 if (rrt->rrt_index == ifcp->ifc_index &&
1870 (IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &none) ||
1871 IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw))) {
1872 trace(1, "\troute found, age it\n");
1873 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1874 rrt->rrt_t = t_lifetime;
1875 rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
1876 }
1877 updated++;
1878 } else {
1879 trace(1, "\tnon-interface route found: %s/%d on %d\n",
1880 inet6_n2p(&rrt->rrt_info.rip6_dest),
1881 rrt->rrt_info.rip6_plen,
1882 rrt->rrt_index);
1883 }
1884 } else
1885 trace(1, "\tno interface route found\n");
1886 /* age route for p2p destination */
1887 if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1888 memset(&ni6, 0, sizeof(ni6));
1889 ni6.rip6_dest = ifa->ifa_raddr;
1890 ni6.rip6_plen = 128;
1891 applyplen(&ni6.rip6_dest, ni6.rip6_plen); /*to be sure*/
1892 trace(1, "\tfind p2p route %s/%d on %d\n",
1893 inet6_n2p(&ni6.rip6_dest), ni6.rip6_plen,
1894 ifcp->ifc_index);
1895 if ((rrt = rtsearch(&ni6, NULL)) != NULL) {
1896 if (rrt->rrt_index == ifcp->ifc_index &&
1897 IN6_ARE_ADDR_EQUAL(&rrt->rrt_gw, &ifa->ifa_addr)) {
1898 trace(1, "\troute found, age it\n");
1899 if (rrt->rrt_t == 0 || rrt->rrt_t > t_lifetime) {
1900 rrt->rrt_t = t_lifetime;
1901 rrt->rrt_info.rip6_metric =
1902 HOPCNT_INFINITY6;
1903 updated++;
1904 }
1905 } else {
1906 trace(1, "\tnon-p2p route found: %s/%d on %d\n",
1907 inet6_n2p(&rrt->rrt_info.rip6_dest),
1908 rrt->rrt_info.rip6_plen,
1909 rrt->rrt_index);
1910 }
1911 } else
1912 trace(1, "\tno p2p route found\n");
1913 }
1914 return updated ? 0 : -1;
1915}
1916
1917/*
1918 * Get each interface address and put those interface routes to the route
1919 * list.
1920 */
1921int
36471bd1 1922ifrt(struct ifc *ifcp, int again)
984263bc
MD
1923{
1924 struct ifac *ifa;
1925 struct riprt *rrt, *search_rrt, *prev_rrt, *loop_rrt;
1926 struct netinfo6 *np;
1927 time_t t_lifetime;
1928 int need_trigger = 0;
1929
1930 if (ifcp->ifc_flags & IFF_LOOPBACK)
1931 return 0; /* ignore loopback */
1932 if (ifcp->ifc_flags & IFF_POINTOPOINT) {
1933 ifrt_p2p(ifcp, again);
1934 return 0;
1935 }
1936
1937 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
1938 if (IN6_IS_ADDR_LINKLOCAL(&ifa->ifa_addr)) {
1939#if 0
1940 trace(1, "route: %s on %s: "
1941 "skip linklocal interface address\n",
1942 inet6_n2p(&ifa->ifa_addr), ifcp->ifc_name);
1943#endif
1944 continue;
1945 }
1946 if (IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_addr)) {
1947#if 0
1948 trace(1, "route: %s: skip unspec interface address\n",
1949 ifcp->ifc_name);
1950#endif
1951 continue;
1952 }
1953 if (ifcp->ifc_flags & IFF_UP) {
1954 if ((rrt = MALLOC(struct riprt)) == NULL)
1955 fatal("malloc: struct riprt");
1956 memset(rrt, 0, sizeof(*rrt));
1957 rrt->rrt_same = NULL;
1958 rrt->rrt_index = ifcp->ifc_index;
1959 rrt->rrt_t = 0; /* don't age */
1960 rrt->rrt_info.rip6_dest = ifa->ifa_addr;
1961 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
1962 rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
1963 rrt->rrt_info.rip6_plen = ifa->ifa_plen;
1964 rrt->rrt_flags = RTF_CLONING;
1965 rrt->rrt_rflags |= RRTF_CHANGED;
1966 applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen);
1967 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
1968#if 0
1969 /* XXX why gateway address == network adddress? */
1970 rrt->rrt_gw = ifa->ifa_addr;
1971#endif
1972 np = &rrt->rrt_info;
1973 search_rrt = rtsearch(np, &prev_rrt);
1974 if (search_rrt != NULL) {
1975 if (search_rrt->rrt_info.rip6_metric >
1976 rrt->rrt_info.rip6_metric) {
1977 if (prev_rrt)
1978 prev_rrt->rrt_next = rrt->rrt_next;
1979 else
1980 riprt = rrt->rrt_next;
1981 delroute(&rrt->rrt_info, &rrt->rrt_gw);
1982 free(rrt);
1983 } else {
1984 /* Already have better route */
1985 if (!again) {
1986 trace(1, "route: %s/%d: "
1987 "already registered (%s)\n",
1988 inet6_n2p(&np->rip6_dest), np->rip6_plen,
1989 ifcp->ifc_name);
1990 }
1991 free(rrt);
1992 continue;
1993 }
1994 }
1995 /* Attach the route to the list */
1996 trace(1, "route: %s/%d: register route (%s)\n",
1997 inet6_n2p(&np->rip6_dest), np->rip6_plen,
1998 ifcp->ifc_name);
1999 rrt->rrt_next = riprt;
2000 riprt = rrt;
2001 addroute(rrt, &rrt->rrt_gw, ifcp);
2002 sendrequest(ifcp);
2003 ripsend(ifcp, &ifcp->ifc_ripsin, 0);
2004 need_trigger = 1;
2005 } else {
2006 for (loop_rrt = riprt; loop_rrt; loop_rrt = loop_rrt->rrt_next) {
2007 if (loop_rrt->rrt_index == ifcp->ifc_index) {
2008 t_lifetime = time(NULL) - RIP_LIFETIME;
2009 if (loop_rrt->rrt_t == 0 || loop_rrt->rrt_t > t_lifetime) {
2010 loop_rrt->rrt_t = t_lifetime;
2011 loop_rrt->rrt_info.rip6_metric = HOPCNT_INFINITY6;
2012 loop_rrt->rrt_rflags |= RRTF_CHANGED;
2013 need_trigger = 1;
2014 }
2015 }
2016 }
2017 }
2018 }
2019 return need_trigger;
2020}
2021
2022/*
2023 * there are couple of p2p interface routing models. "behavior" lets
2024 * you pick one. it looks that gated behavior fits best with BSDs,
2025 * since BSD kernels does not look at prefix length on p2p interfaces.
2026 */
2027void
36471bd1 2028ifrt_p2p(struct ifc *ifcp, int again)
984263bc
MD
2029{
2030 struct ifac *ifa;
2031 struct riprt *rrt, *orrt, *prevrrt;
2032 struct netinfo6 *np;
2033 struct in6_addr addr, dest;
2034 int advert, ignore, i;
2035#define P2PADVERT_NETWORK 1
2036#define P2PADVERT_ADDR 2
2037#define P2PADVERT_DEST 4
2038#define P2PADVERT_MAX 4
2039 const enum { CISCO, GATED, ROUTE6D } behavior = GATED;
2040 const char *category = "";
2041 const char *noadv;
2042
2043 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
2044 addr = ifa->ifa_addr;
2045 dest = ifa->ifa_raddr;
2046 applyplen(&addr, ifa->ifa_plen);
2047 applyplen(&dest, ifa->ifa_plen);
2048 advert = ignore = 0;
2049 switch (behavior) {
2050 case CISCO:
2051 /*
2052 * honor addr/plen, just like normal shared medium
2053 * interface. this may cause trouble if you reuse
2054 * addr/plen on other interfaces.
2055 *
2056 * advertise addr/plen.
2057 */
2058 advert |= P2PADVERT_NETWORK;
2059 break;
2060 case GATED:
2061 /*
2062 * prefixlen on p2p interface is meaningless.
2063 * advertise addr/128 and dest/128.
2064 *
2065 * do not install network route to route6d routing
2066 * table (if we do, it would prevent route installation
2067 * for other p2p interface that shares addr/plen).
2068 *
2069 * XXX what should we do if dest is ::? it will not
2070 * get announced anyways (see following filter),
2071 * but we need to think.
2072 */
2073 advert |= P2PADVERT_ADDR;
2074 advert |= P2PADVERT_DEST;
2075 ignore |= P2PADVERT_NETWORK;
2076 break;
2077 case ROUTE6D:
2078 /*
2079 * just for testing. actually the code is redundant
2080 * given the current p2p interface address assignment
2081 * rule for kame kernel.
2082 *
2083 * intent:
2084 * A/n -> announce A/n
2085 * A B/n, A and B share prefix -> A/n (= B/n)
2086 * A B/n, do not share prefix -> A/128 and B/128
2087 * actually, A/64 and A B/128 are the only cases
2088 * permitted by the kernel:
2089 * A/64 -> A/64
2090 * A B/128 -> A/128 and B/128
2091 */
2092 if (!IN6_IS_ADDR_UNSPECIFIED(&ifa->ifa_raddr)) {
2093 if (IN6_ARE_ADDR_EQUAL(&addr, &dest))
2094 advert |= P2PADVERT_NETWORK;
2095 else {
2096 advert |= P2PADVERT_ADDR;
2097 advert |= P2PADVERT_DEST;
2098 ignore |= P2PADVERT_NETWORK;
2099 }
2100 } else
2101 advert |= P2PADVERT_NETWORK;
2102 break;
2103 }
2104
2105 for (i = 1; i <= P2PADVERT_MAX; i *= 2) {
2106 if ((ignore & i) != 0)
2107 continue;
2108 if ((rrt = MALLOC(struct riprt)) == NULL) {
2109 fatal("malloc: struct riprt");
2110 /*NOTREACHED*/
2111 }
2112 memset(rrt, 0, sizeof(*rrt));
2113 rrt->rrt_same = NULL;
2114 rrt->rrt_index = ifcp->ifc_index;
2115 rrt->rrt_t = 0; /* don't age */
2116 switch (i) {
2117 case P2PADVERT_NETWORK:
2118 rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2119 rrt->rrt_info.rip6_plen = ifa->ifa_plen;
2120 applyplen(&rrt->rrt_info.rip6_dest,
2121 ifa->ifa_plen);
2122 category = "network";
2123 break;
2124 case P2PADVERT_ADDR:
2125 rrt->rrt_info.rip6_dest = ifa->ifa_addr;
2126 rrt->rrt_info.rip6_plen = 128;
2127 rrt->rrt_gw = in6addr_loopback;
2128 category = "addr";
2129 break;
2130 case P2PADVERT_DEST:
2131 rrt->rrt_info.rip6_dest = ifa->ifa_raddr;
2132 rrt->rrt_info.rip6_plen = 128;
2133 rrt->rrt_gw = ifa->ifa_addr;
2134 category = "dest";
2135 break;
2136 }
2137 if (IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_info.rip6_dest) ||
2138 IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_info.rip6_dest)) {
2139#if 0
2140 trace(1, "route: %s: skip unspec/linklocal "
2141 "(%s on %s)\n", category, ifcp->ifc_name);
2142#endif
2143 free(rrt);
2144 continue;
2145 }
2146 if ((advert & i) == 0) {
2147 rrt->rrt_rflags |= RRTF_NOADVERTISE;
2148 noadv = ", NO-ADV";
2149 } else
2150 noadv = "";
2151 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
2152 rrt->rrt_info.rip6_metric = 1 + ifcp->ifc_metric;
2153 np = &rrt->rrt_info;
2154 orrt = rtsearch(np, &prevrrt);
2155 if (!orrt) {
2156 /* Attach the route to the list */
2157 trace(1, "route: %s/%d: register route "
2158 "(%s on %s%s)\n",
2159 inet6_n2p(&np->rip6_dest), np->rip6_plen,
2160 category, ifcp->ifc_name, noadv);
2161 rrt->rrt_next = riprt;
2162 riprt = rrt;
2163 } else if (rrt->rrt_index != orrt->rrt_index ||
2164 rrt->rrt_info.rip6_metric != orrt->rrt_info.rip6_metric) {
2165 /* swap route */
2166 rrt->rrt_next = orrt->rrt_next;
2167 if (prevrrt)
2168 prevrrt->rrt_next = rrt;
2169 else
2170 riprt = rrt;
2171 free(orrt);
2172
2173 trace(1, "route: %s/%d: update (%s on %s%s)\n",
2174 inet6_n2p(&np->rip6_dest), np->rip6_plen,
2175 category, ifcp->ifc_name, noadv);
2176 } else {
2177 /* Already found */
2178 if (!again) {
2179 trace(1, "route: %s/%d: "
2180 "already registered (%s on %s%s)\n",
2181 inet6_n2p(&np->rip6_dest),
2182 np->rip6_plen, category,
2183 ifcp->ifc_name, noadv);
2184 }
2185 free(rrt);
2186 }
2187 }
2188 }
2189#undef P2PADVERT_NETWORK
2190#undef P2PADVERT_ADDR
2191#undef P2PADVERT_DEST
2192#undef P2PADVERT_MAX
2193}
2194
2195int
36471bd1 2196getifmtu(int ifindex)
984263bc
MD
2197{
2198 int mib[6];
2199 char *buf;
2200 size_t msize;
2201 struct if_msghdr *ifm;
2202 int mtu;
2203
2204 mib[0] = CTL_NET;
2205 mib[1] = PF_ROUTE;
2206 mib[2] = 0;
2207 mib[3] = AF_INET6;
2208 mib[4] = NET_RT_IFLIST;
2209 mib[5] = ifindex;
2210 if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
2211 fatal("sysctl estimate NET_RT_IFLIST");
2212 /*NOTREACHED*/
2213 }
2214 if ((buf = malloc(msize)) == NULL) {
2215 fatal("malloc");
2216 /*NOTREACHED*/
2217 }
2218 if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
2219 fatal("sysctl NET_RT_IFLIST");
2220 /*NOTREACHED*/
2221 }
2222 ifm = (struct if_msghdr *)buf;
2223 mtu = ifm->ifm_data.ifi_mtu;
db43ed0f 2224#ifdef __DragonFly__
984263bc
MD
2225 if (ifindex != ifm->ifm_index) {
2226 fatal("ifindex does not match with ifm_index");
2227 /*NOTREACHED*/
2228 }
2229#endif
2230 free(buf);
2231 return mtu;
2232}
2233
2234const char *
36471bd1 2235rttypes(struct rt_msghdr *rtm)
984263bc
MD
2236{
2237#define RTTYPE(s, f) \
2238do { \
2239 if (rtm->rtm_type == (f)) \
2240 return (s); \
2241} while (0)
2242 RTTYPE("ADD", RTM_ADD);
2243 RTTYPE("DELETE", RTM_DELETE);
2244 RTTYPE("CHANGE", RTM_CHANGE);
2245 RTTYPE("GET", RTM_GET);
2246 RTTYPE("LOSING", RTM_LOSING);
2247 RTTYPE("REDIRECT", RTM_REDIRECT);
2248 RTTYPE("MISS", RTM_MISS);
2249 RTTYPE("LOCK", RTM_LOCK);
2250 RTTYPE("OLDADD", RTM_OLDADD);
2251 RTTYPE("OLDDEL", RTM_OLDDEL);
2252 RTTYPE("RESOLVE", RTM_RESOLVE);
2253 RTTYPE("NEWADDR", RTM_NEWADDR);
2254 RTTYPE("DELADDR", RTM_DELADDR);
2255 RTTYPE("IFINFO", RTM_IFINFO);
2256#ifdef RTM_OLDADD
2257 RTTYPE("OLDADD", RTM_OLDADD);
2258#endif
2259#ifdef RTM_OLDDEL
2260 RTTYPE("OLDDEL", RTM_OLDDEL);
2261#endif
2262#ifdef RTM_OIFINFO
2263 RTTYPE("OIFINFO", RTM_OIFINFO);
2264#endif
2265#ifdef RTM_IFANNOUNCE
2266 RTTYPE("IFANNOUNCE", RTM_IFANNOUNCE);
2267#endif
2268#ifdef RTM_NEWMADDR
2269 RTTYPE("NEWMADDR", RTM_NEWMADDR);
2270#endif
2271#ifdef RTM_DELMADDR
2272 RTTYPE("DELMADDR", RTM_DELMADDR);
2273#endif
2274#undef RTTYPE
2275 return NULL;
2276}
2277
2278const char *
36471bd1 2279rtflags(struct rt_msghdr *rtm)
984263bc
MD
2280{
2281 static char buf[BUFSIZ];
2282
2283 /*
2284 * letter conflict should be okay. painful when *BSD diverges...
2285 */
2286 strlcpy(buf, "", sizeof(buf));
2287#define RTFLAG(s, f) \
2288do { \
2289 if (rtm->rtm_flags & (f)) \
2290 strlcat(buf, (s), sizeof(buf)); \
2291} while (0)
2292 RTFLAG("U", RTF_UP);
2293 RTFLAG("G", RTF_GATEWAY);
2294 RTFLAG("H", RTF_HOST);
2295 RTFLAG("R", RTF_REJECT);
2296 RTFLAG("D", RTF_DYNAMIC);
2297 RTFLAG("M", RTF_MODIFIED);
2298 RTFLAG("d", RTF_DONE);
2299#ifdef RTF_MASK
2300 RTFLAG("m", RTF_MASK);
2301#endif
2302 RTFLAG("C", RTF_CLONING);
2303#ifdef RTF_CLONED
2304 RTFLAG("c", RTF_CLONED);
2305#endif
2306#ifdef RTF_PRCLONING
2307 RTFLAG("c", RTF_PRCLONING);
2308#endif
2309#ifdef RTF_WASCLONED
2310 RTFLAG("W", RTF_WASCLONED);
2311#endif
2312 RTFLAG("X", RTF_XRESOLVE);
2313 RTFLAG("L", RTF_LLINFO);
2314 RTFLAG("S", RTF_STATIC);
2315 RTFLAG("B", RTF_BLACKHOLE);
2316#ifdef RTF_PROTO3
2317 RTFLAG("3", RTF_PROTO3);
2318#endif
2319 RTFLAG("2", RTF_PROTO2);
2320 RTFLAG("1", RTF_PROTO1);
2321#ifdef RTF_BROADCAST
2322 RTFLAG("b", RTF_BROADCAST);
2323#endif
2324#ifdef RTF_DEFAULT
2325 RTFLAG("d", RTF_DEFAULT);
2326#endif
2327#ifdef RTF_ISAROUTER
2328 RTFLAG("r", RTF_ISAROUTER);
2329#endif
2330#ifdef RTF_TUNNEL
2331 RTFLAG("T", RTF_TUNNEL);
2332#endif
2333#ifdef RTF_AUTH
2334 RTFLAG("A", RTF_AUTH);
2335#endif
2336#ifdef RTF_CRYPT
2337 RTFLAG("E", RTF_CRYPT);
2338#endif
2339#undef RTFLAG
2340 return buf;
2341}
2342
2343const char *
36471bd1 2344ifflags(int flags)
984263bc
MD
2345{
2346 static char buf[BUFSIZ];
2347
2348 strlcpy(buf, "", sizeof(buf));
2349#define IFFLAG(s, f) \
2350do { \
2351 if (flags & f) { \
2352 if (buf[0]) \
2353 strlcat(buf, ",", sizeof(buf)); \
2354 strlcat(buf, s, sizeof(buf)); \
2355 } \
2356} while (0)
2357 IFFLAG("UP", IFF_UP);
2358 IFFLAG("BROADCAST", IFF_BROADCAST);
2359 IFFLAG("DEBUG", IFF_DEBUG);
2360 IFFLAG("LOOPBACK", IFF_LOOPBACK);
2361 IFFLAG("POINTOPOINT", IFF_POINTOPOINT);
2362#ifdef IFF_NOTRAILERS
2363 IFFLAG("NOTRAILERS", IFF_NOTRAILERS);
2364#endif
2365#ifdef IFF_SMART
2366 IFFLAG("SMART", IFF_SMART);
2367#endif
2368 IFFLAG("RUNNING", IFF_RUNNING);
2369 IFFLAG("NOARP", IFF_NOARP);
2370 IFFLAG("PROMISC", IFF_PROMISC);
2371 IFFLAG("ALLMULTI", IFF_ALLMULTI);
2372 IFFLAG("OACTIVE", IFF_OACTIVE);
2373 IFFLAG("SIMPLEX", IFF_SIMPLEX);
2374 IFFLAG("LINK0", IFF_LINK0);
2375 IFFLAG("LINK1", IFF_LINK1);
2376 IFFLAG("LINK2", IFF_LINK2);
2377 IFFLAG("MULTICAST", IFF_MULTICAST);
2378#undef IFFLAG
2379 return buf;
2380}
2381
2382void
36471bd1 2383krtread(int again)
984263bc
MD
2384{
2385 int mib[6];
2386 size_t msize;
2387 char *buf, *p, *lim;
2388 struct rt_msghdr *rtm;
2389 int retry;
2390 const char *errmsg;
2391
2392 retry = 0;
2393 buf = NULL;
2394 mib[0] = CTL_NET;
2395 mib[1] = PF_ROUTE;
2396 mib[2] = 0;
2397 mib[3] = AF_INET6; /* Address family */
2398 mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */
2399 mib[5] = 0; /* No flags */
2400 do {
2401 retry++;
2402 errmsg = NULL;
2403 if (buf)
2404 free(buf);
2405 if (sysctl(mib, 6, NULL, &msize, NULL, 0) < 0) {
2406 errmsg = "sysctl estimate";
2407 continue;
2408 }
2409 if ((buf = malloc(msize)) == NULL) {
2410 errmsg = "malloc";
2411 continue;
2412 }
2413 if (sysctl(mib, 6, buf, &msize, NULL, 0) < 0) {
2414 errmsg = "sysctl NET_RT_DUMP";
2415 continue;
2416 }
2417 } while (retry < 5 && errmsg != NULL);
2418 if (errmsg) {
2419 fatal("%s (with %d retries, msize=%lu)", errmsg, retry,
2420 (u_long)msize);
2421 /*NOTREACHED*/
2422 } else if (1 < retry)
2423 syslog(LOG_INFO, "NET_RT_DUMP %d retires", retry);
2424
2425 lim = buf + msize;
2426 for (p = buf; p < lim; p += rtm->rtm_msglen) {
2427 rtm = (struct rt_msghdr *)p;
2428 rt_entry(rtm, again);
2429 }
2430 free(buf);
2431}
2432
2433void
36471bd1 2434rt_entry(struct rt_msghdr *rtm, int again)
984263bc
MD
2435{
2436 struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask;
2437 struct sockaddr_in6 *sin6_genmask, *sin6_ifp;
2438 char *rtmp, *ifname = NULL;
2439 struct riprt *rrt, *orrt;
2440 struct netinfo6 *np;
2441 int s;
2442
2443 sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0;
2444 if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags &
2445 (RTF_CLONING|RTF_XRESOLVE|RTF_LLINFO|RTF_BLACKHOLE)) {
2446 return; /* not interested in the link route */
2447 }
2448 /* do not look at cloned routes */
2449#ifdef RTF_WASCLONED
2450 if (rtm->rtm_flags & RTF_WASCLONED)
2451 return;
2452#endif
2453#ifdef RTF_CLONED
2454 if (rtm->rtm_flags & RTF_CLONED)
2455 return;
2456#endif
2457 /*
2458 * do not look at dynamic routes.
2459 * netbsd/openbsd cloned routes have UGHD.
2460 */
2461 if (rtm->rtm_flags & RTF_DYNAMIC)
2462 return;
2463 rtmp = (char *)(rtm + 1);
2464 /* Destination */
2465 if ((rtm->rtm_addrs & RTA_DST) == 0)
2466 return; /* ignore routes without destination address */
2467 sin6_dst = (struct sockaddr_in6 *)rtmp;
2468 rtmp += ROUNDUP(sin6_dst->sin6_len);
2469 if (rtm->rtm_addrs & RTA_GATEWAY) {
2470 sin6_gw = (struct sockaddr_in6 *)rtmp;
2471 rtmp += ROUNDUP(sin6_gw->sin6_len);
2472 }
2473 if (rtm->rtm_addrs & RTA_NETMASK) {
2474 sin6_mask = (struct sockaddr_in6 *)rtmp;
2475 rtmp += ROUNDUP(sin6_mask->sin6_len);
2476 }
2477 if (rtm->rtm_addrs & RTA_GENMASK) {
2478 sin6_genmask = (struct sockaddr_in6 *)rtmp;
2479 rtmp += ROUNDUP(sin6_genmask->sin6_len);
2480 }
2481 if (rtm->rtm_addrs & RTA_IFP) {
2482 sin6_ifp = (struct sockaddr_in6 *)rtmp;
2483 rtmp += ROUNDUP(sin6_ifp->sin6_len);
2484 }
2485
2486 /* Destination */
2487 if (sin6_dst->sin6_family != AF_INET6)
2488 return;
2489 if (IN6_IS_ADDR_LINKLOCAL(&sin6_dst->sin6_addr))
2490 return; /* Link-local */
2491 if (IN6_ARE_ADDR_EQUAL(&sin6_dst->sin6_addr, &in6addr_loopback))
2492 return; /* Loopback */
2493 if (IN6_IS_ADDR_MULTICAST(&sin6_dst->sin6_addr))
2494 return;
2495
2496 if ((rrt = MALLOC(struct riprt)) == NULL) {
2497 fatal("malloc: struct riprt");
2498 /*NOTREACHED*/
2499 }
2500 memset(rrt, 0, sizeof(*rrt));
2501 np = &rrt->rrt_info;
2502 rrt->rrt_same = NULL;
2503 rrt->rrt_t = time(NULL);
2504 if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC))
2505 rrt->rrt_t = 0; /* Don't age static routes */
2506#if 0
2507 np->rip6_tag = htons(routetag & 0xffff);
2508#else
2509 np->rip6_tag = 0;
2510#endif
2511 np->rip6_metric = rtm->rtm_rmx.rmx_hopcount;
2512 if (np->rip6_metric < 1)
2513 np->rip6_metric = 1;
2514 rrt->rrt_flags = rtm->rtm_flags;
2515 np->rip6_dest = sin6_dst->sin6_addr;
2516
2517 /* Mask or plen */
2518 if (rtm->rtm_flags & RTF_HOST)
2519 np->rip6_plen = 128; /* Host route */
2520 else if (sin6_mask)
2521 np->rip6_plen = sin6mask2len(sin6_mask);
2522 else
2523 np->rip6_plen = 0;
2524
2525 orrt = rtsearch(np, NULL);
2526 if (orrt && orrt->rrt_info.rip6_metric != HOPCNT_INFINITY6) {
2527 /* Already found */
2528 if (!again) {
2529 trace(1, "route: %s/%d flags %s: already registered\n",
2530 inet6_n2p(&np->rip6_dest), np->rip6_plen,
2531 rtflags(rtm));
2532 }
2533 free(rrt);
2534 return;
2535 }
2536 /* Gateway */
2537 if (!sin6_gw)
2538 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2539 else {
2540 if (sin6_gw->sin6_family == AF_INET6)
2541 rrt->rrt_gw = sin6_gw->sin6_addr;
2542 else if (sin6_gw->sin6_family == AF_LINK) {
2543 /* XXX in case ppp link? */
2544 rrt->rrt_gw = in6addr_loopback;
2545 } else
2546 memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));
2547 }
2548 trace(1, "route: %s/%d flags %s",
2549 inet6_n2p(&np->rip6_dest), np->rip6_plen, rtflags(rtm));
2550 trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw));
2551
2552 /* Interface */
2553 s = rtm->rtm_index;
2554 if (s < nindex2ifc && index2ifc[s])
2555 ifname = index2ifc[s]->ifc_name;
2556 else {
2557 trace(1, " not configured\n");
2558 free(rrt);
2559 return;
2560 }
2561 trace(1, " if %s sock %d", ifname, s);
2562 rrt->rrt_index = s;
2563
2564 trace(1, "\n");
2565
2566 /* Check gateway */
2567 if (!IN6_IS_ADDR_LINKLOCAL(&rrt->rrt_gw) &&
2568 !IN6_IS_ADDR_LOOPBACK(&rrt->rrt_gw)
db43ed0f 2569#ifdef __DragonFly__
984263bc
MD
2570 && (rrt->rrt_flags & RTF_LOCAL) == 0
2571#endif
2572 ) {
2573 trace(0, "***** Gateway %s is not a link-local address.\n",
2574 inet6_n2p(&rrt->rrt_gw));
2575 trace(0, "***** dest(%s) if(%s) -- Not optimized.\n",
2576 inet6_n2p(&rrt->rrt_info.rip6_dest), ifname);
2577 rrt->rrt_rflags |= RRTF_NH_NOT_LLADDR;
2578 }
2579
2580 /* Put it to the route list */
2581 if (orrt && orrt->rrt_info.rip6_metric == HOPCNT_INFINITY6) {
2582 /* replace route list */
2583 rrt->rrt_next = orrt->rrt_next;
2584 *orrt = *rrt;
2585 trace(1, "route: %s/%d flags %s: replace new route\n",
2586 inet6_n2p(&np->rip6_dest), np->rip6_plen,
2587 rtflags(rtm));
2588 free(rrt);
2589 } else {
2590 rrt->rrt_next = riprt;
2591 riprt = rrt;
2592 }
2593}
2594
2595int
36471bd1 2596addroute(struct riprt *rrt, const struct in6_addr *gw, struct ifc *ifcp)
984263bc
MD
2597{
2598 struct netinfo6 *np;
2599 u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ];
2600 struct rt_msghdr *rtm;
2601 struct sockaddr_in6 *sin;
2602 int len;
2603
2604 np = &rrt->rrt_info;
2605 inet_ntop(AF_INET6, (const void *)gw, (char *)buf1, sizeof(buf1));
2606 inet_ntop(AF_INET6, (void *)&ifcp->ifc_mylladdr, (char *)buf2, sizeof(buf2));
2607 tracet(1, "ADD: %s/%d gw %s [%d] ifa %s\n",
2608 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2609 np->rip6_metric - 1, buf2);
2610 if (rtlog)
2611 fprintf(rtlog, "%s: ADD: %s/%d gw %s [%d] ifa %s\n", hms(),
2612 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1,
2613 np->rip6_metric - 1, buf2);
2614 if (nflag)
2615 return 0;
2616
2617 memset(buf, 0, sizeof(buf));
2618 rtm = (struct rt_msghdr *)buf;
2619 rtm->rtm_type = RTM_ADD;
2620 rtm->rtm_version = RTM_VERSION;
2621 rtm->rtm_seq = ++seq;
2622 rtm->rtm_pid = pid;
2623 rtm->rtm_flags = rrt->rrt_flags;
2624 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2625 rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1;
2626 rtm->rtm_inits = RTV_HOPCOUNT;
2627 sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2628 /* Destination */
2629 sin->sin6_len = sizeof(struct sockaddr_in6);
2630 sin->sin6_family = AF_INET6;
2631 sin->sin6_addr = np->rip6_dest;
2632 sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2633 /* Gateway */
2634 sin->sin6_len = sizeof(struct sockaddr_in6);
2635 sin->sin6_family = AF_INET6;
2636 sin->sin6_addr = *gw;
2637 sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2638 /* Netmask */
2639 sin->sin6_len = sizeof(struct sockaddr_in6);
2640 sin->sin6_family = AF_INET6;
2641 sin->sin6_addr = *(plen2mask(np->rip6_plen));
2642 sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2643
2644 len = (char *)sin - (char *)buf;
2645 rtm->rtm_msglen = len;
2646 if (write(rtsock, buf, len) > 0)
2647 return 0;
2648
2649 if (errno == EEXIST) {
2650 trace(0, "ADD: Route already exists %s/%d gw %s\n",
2651 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2652 if (rtlog)
2653 fprintf(rtlog, "ADD: Route already exists %s/%d gw %s\n",
2654 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf1);
2655 } else {
2656 trace(0, "Can not write to rtsock (addroute): %s\n",
2657 strerror(errno));
2658 if (rtlog)
2659 fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2660 strerror(errno));
2661 }
2662 return -1;
2663}
2664
2665int
36471bd1 2666delroute(struct netinfo6 *np, struct in6_addr *gw)
984263bc
MD
2667{
2668 u_char buf[BUFSIZ], buf2[BUFSIZ];
2669 struct rt_msghdr *rtm;
2670 struct sockaddr_in6 *sin;
2671 int len;
2672
2673 inet_ntop(AF_INET6, (void *)gw, (char *)buf2, sizeof(buf2));
2674 tracet(1, "DEL: %s/%d gw %s\n", inet6_n2p(&np->rip6_dest),
2675 np->rip6_plen, buf2);
2676 if (rtlog)
2677 fprintf(rtlog, "%s: DEL: %s/%d gw %s\n",
2678 hms(), inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2679 if (nflag)
2680 return 0;
2681
2682 memset(buf, 0, sizeof(buf));
2683 rtm = (struct rt_msghdr *)buf;
2684 rtm->rtm_type = RTM_DELETE;
2685 rtm->rtm_version = RTM_VERSION;
2686 rtm->rtm_seq = ++seq;
2687 rtm->rtm_pid = pid;
2688 rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
2689 if (np->rip6_plen == sizeof(struct in6_addr) * 8)
2690 rtm->rtm_flags |= RTF_HOST;
2691 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
2692 sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2693 /* Destination */
2694 sin->sin6_len = sizeof(struct sockaddr_in6);
2695 sin->sin6_family = AF_INET6;
2696 sin->sin6_addr = np->rip6_dest;
2697 sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2698 /* Gateway */
2699 sin->sin6_len = sizeof(struct sockaddr_in6);
2700 sin->sin6_family = AF_INET6;
2701 sin->sin6_addr = *gw;
2702 sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2703 /* Netmask */
2704 sin->sin6_len = sizeof(struct sockaddr_in6);
2705 sin->sin6_family = AF_INET6;
2706 sin->sin6_addr = *(plen2mask(np->rip6_plen));
2707 sin = (struct sockaddr_in6 *)((char *)sin + ROUNDUP(sin->sin6_len));
2708
2709 len = (char *)sin - (char *)buf;
2710 rtm->rtm_msglen = len;
2711 if (write(rtsock, buf, len) >= 0)
2712 return 0;
2713
2714 if (errno == ESRCH) {
2715 trace(0, "RTDEL: Route does not exist: %s/%d gw %s\n",
2716 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2717 if (rtlog)
2718 fprintf(rtlog, "RTDEL: Route does not exist: %s/%d gw %s\n",
2719 inet6_n2p(&np->rip6_dest), np->rip6_plen, buf2);
2720 } else {
2721 trace(0, "Can not write to rtsock (delroute): %s\n",
2722 strerror(errno));
2723 if (rtlog)
2724 fprintf(rtlog, "\tCan not write to rtsock: %s\n",
2725 strerror(errno));
2726 }
2727 return -1;
2728}
2729
2730struct in6_addr *
36471bd1 2731getroute(struct netinfo6 *np, struct in6_addr *gw)
984263bc
MD
2732{
2733 u_char buf[BUFSIZ];
2734 u_long myseq;
2735 int len;
2736 struct rt_msghdr *rtm;
2737 struct sockaddr_in6 *sin;
2738
2739 rtm = (struct rt_msghdr *)buf;
2740 len = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
2741 memset(rtm, 0, len);
2742 rtm->rtm_type = RTM_GET;
2743 rtm->rtm_version = RTM_VERSION;
2744 myseq = ++seq;
2745 rtm->rtm_seq = myseq;
2746 rtm->rtm_addrs = RTA_DST;
2747 rtm->rtm_msglen = len;
2748 sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2749 sin->sin6_len = sizeof(struct sockaddr_in6);
2750 sin->sin6_family = AF_INET6;
2751 sin->sin6_addr = np->rip6_dest;
2752 if (write(rtsock, buf, len) < 0) {
2753 if (errno == ESRCH) /* No such route found */
2754 return NULL;
2755 perror("write to rtsock");
2756 exit(1);
2757 }
2758 do {
2759 if ((len = read(rtsock, buf, sizeof(buf))) < 0) {
2760 perror("read from rtsock");
2761 exit(1);
2762 }
2763 rtm = (struct rt_msghdr *)buf;
2764 } while (rtm->rtm_seq != myseq || rtm->rtm_pid != pid);
2765 sin = (struct sockaddr_in6 *)&buf[sizeof(struct rt_msghdr)];
2766 if (rtm->rtm_addrs & RTA_DST) {
2767 sin = (struct sockaddr_in6 *)
2768 ((char *)sin + ROUNDUP(sin->sin6_len));
2769 }
2770 if (rtm->rtm_addrs & RTA_GATEWAY) {
2771 *gw = sin->sin6_addr;
2772 return gw;
2773 }
2774 return NULL;
2775}
2776
2777const char *
36471bd1 2778inet6_n2p(const struct in6_addr *p)
984263bc
MD
2779{
2780 static char buf[BUFSIZ];
2781
2782 return inet_ntop(AF_INET6, (const void *)p, buf, sizeof(buf));
2783}
2784
2785void
36471bd1 2786ifrtdump(int sig)
984263bc 2787{
984263bc
MD
2788 ifdump(sig);
2789 rtdump(sig);
2790}
2791
2792void
36471bd1 2793ifdump(int sig)
984263bc
MD
2794{
2795 struct ifc *ifcp;
2796 FILE *dump;
2797 int i;
2798
2799 if (sig == 0)
2800 dump = stderr;
2801 else
2802 if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
2803 dump = stderr;
2804
2805 fprintf(dump, "%s: Interface Table Dump\n", hms());
2806 fprintf(dump, " Number of interfaces: %d\n", nifc);
2807 for (i = 0; i < 2; i++) {
2808 fprintf(dump, " %sadvertising interfaces:\n", i ? "non-" : "");
2809 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
2810 if (i == 0) {
2811 if ((ifcp->ifc_flags & IFF_UP) == 0)
2812 continue;
2813 if (iff_find(ifcp, 'N') != NULL)
2814 continue;
2815 } else {
2816 if (ifcp->ifc_flags & IFF_UP)
2817 continue;
2818 }
2819 ifdump0(dump, ifcp);
2820 }
2821 }
2822 fprintf(dump, "\n");
2823 if (dump != stderr)
2824 fclose(dump);
2825}
2826
2827void
36471bd1 2828ifdump0(FILE *dump, const struct ifc *ifcp)
984263bc
MD
2829{
2830 struct ifac *ifa;
2831 struct iff *iffp;
2832 char buf[BUFSIZ];
2833 const char *ft;
2834 int addr;
2835
2836 fprintf(dump, " %s: index(%d) flags(%s) addr(%s) mtu(%d) metric(%d)\n",
2837 ifcp->ifc_name, ifcp->ifc_index, ifflags(ifcp->ifc_flags),
2838 inet6_n2p(&ifcp->ifc_mylladdr),
2839 ifcp->ifc_mtu, ifcp->ifc_metric);
2840 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
2841 if (ifcp->ifc_flags & IFF_POINTOPOINT) {
2842 inet_ntop(AF_INET6, (void *)&ifa->ifa_raddr,
2843 buf, sizeof(buf));
2844 fprintf(dump, "\t%s/%d -- %s\n",
2845 inet6_n2p(&ifa->ifa_addr),
2846 ifa->ifa_plen, buf);
2847 } else {
2848 fprintf(dump, "\t%s/%d\n",
2849 inet6_n2p(&ifa->ifa_addr),
2850 ifa->ifa_plen);
2851 }
2852 }
2853 if (ifcp->ifc_filter) {
2854 fprintf(dump, "\tFilter:");
2855 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
2856 addr = 0;
2857 switch (iffp->iff_type) {
2858 case 'A':
2859 ft = "Aggregate"; addr++; break;
2860 case 'N':
2861 ft = "No-use"; break;
2862 case 'O':
2863 ft = "Advertise-only"; addr++; break;
2864 case 'T':
2865 ft = "Default-only"; break;
2866 case 'L':
2867 ft = "Listen-only"; addr++; break;
2868 default:
2869 snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type);
2870 ft = buf;
2871 addr++;
2872 break;
2873 }
2874 fprintf(dump, " %s", ft);
2875 if (addr) {
2876 fprintf(dump, "(%s/%d)", inet6_n2p(&iffp->iff_addr),
2877 iffp->iff_plen);
2878 }
2879 }
2880 fprintf(dump, "\n");
2881 }
2882}
2883
2884void
36471bd1 2885rtdump(int sig)
984263bc
MD
2886{
2887 struct riprt *rrt;
2888 char buf[BUFSIZ];
2889 FILE *dump;
2890 time_t t, age;
2891
2892 if (sig == 0)
2893 dump = stderr;
2894 else
2895 if ((dump = fopen(ROUTE6D_DUMP, "a")) == NULL)
2896 dump = stderr;
2897
2898 t = time(NULL);
2899 fprintf(dump, "\n%s: Routing Table Dump\n", hms());
2900 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
2901 if (rrt->rrt_t == 0)
2902 age = 0;
2903 else
2904 age = t - rrt->rrt_t;
2905 inet_ntop(AF_INET6, (void *)&rrt->rrt_info.rip6_dest,
2906 buf, sizeof(buf));
2907 fprintf(dump, " %s/%d if(%d:%s) gw(%s) [%d] age(%ld)",
2908 buf, rrt->rrt_info.rip6_plen, rrt->rrt_index,
2909 index2ifc[rrt->rrt_index]->ifc_name,
2910 inet6_n2p(&rrt->rrt_gw),
2911 rrt->rrt_info.rip6_metric, (long)age);
2912 if (rrt->rrt_info.rip6_tag) {
2913 fprintf(dump, " tag(0x%04x)",
2914 ntohs(rrt->rrt_info.rip6_tag) & 0xffff);
2915 }
2916 if (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)
2917 fprintf(dump, " NOT-LL");
2918 if (rrt->rrt_rflags & RRTF_NOADVERTISE)
2919 fprintf(dump, " NO-ADV");
2920 fprintf(dump, "\n");
2921 }
2922 fprintf(dump, "\n");
2923 if (dump != stderr)
2924 fclose(dump);
2925}
2926
2927/*
2928 * Parse the -A (and -O) options and put corresponding filter object to the
2929 * specified interface structures. Each of the -A/O option has the following
2930 * syntax: -A 5f09:c400::/32,ef0,ef1 (aggregate)
2931 * -O 5f09:c400::/32,ef0,ef1 (only when match)
2932 */
2933void
36471bd1 2934filterconfig(void)
984263bc
MD
2935{
2936 int i;
2937 char *p, *ap, *iflp, *ifname;
2938 struct iff ftmp, *iff_obj;
2939 struct ifc *ifcp;
2940 struct riprt *rrt;
2941#if 0
2942 struct in6_addr gw;
2943#endif
2944
2945 for (i = 0; i < nfilter; i++) {
2946 ap = filter[i];
2947 iflp = NULL;
2948 ifcp = NULL;
2949 if (filtertype[i] == 'N' || filtertype[i] == 'T') {
2950 iflp = ap;
2951 goto ifonly;
2952 }
17b61719 2953 if ((p = strchr(ap, ',')) != NULL) {
984263bc
MD
2954 *p++ = '\0';
2955 iflp = p;
2956 }
17b61719 2957 if ((p = strchr(ap, '/')) == NULL) {
984263bc
MD
2958 fatal("no prefixlen specified for '%s'", ap);
2959 /*NOTREACHED*/
2960 }
2961 *p++ = '\0';
2962 if (inet_pton(AF_INET6, ap, &ftmp.iff_addr) != 1) {
2963 fatal("invalid prefix specified for '%s'", ap);
2964 /*NOTREACHED*/
2965 }
2966 ftmp.iff_plen = atoi(p);
2967 ftmp.iff_next = NULL;
2968 applyplen(&ftmp.iff_addr, ftmp.iff_plen);
2969ifonly:
2970 ftmp.iff_type = filtertype[i];
2971 if (iflp == NULL || *iflp == '\0') {
2972 fatal("no interface specified for '%s'", ap);
2973 /*NOTREACHED*/
2974 }
2975 /* parse the interface listing portion */
2976 while (iflp) {
2977 ifname = iflp;
17b61719 2978 if ((iflp = strchr(iflp, ',')) != NULL)
984263bc
MD
2979 *iflp++ = '\0';
2980 ifcp = ifc_find(ifname);
2981 if (ifcp == NULL) {
2982 fatal("no interface %s exists", ifname);
2983 /*NOTREACHED*/
2984 }
2985 iff_obj = (struct iff *)malloc(sizeof(struct iff));
2986 if (iff_obj == NULL) {
2987 fatal("malloc of iff_obj");
2988 /*NOTREACHED*/
2989 }
2990 memcpy((void *)iff_obj, (void *)&ftmp,
2991 sizeof(struct iff));
2992 /* link it to the interface filter */
2993 iff_obj->iff_next = ifcp->ifc_filter;
2994 ifcp->ifc_filter = iff_obj;
2995 }
2996
2997 /*
2998 * -A: aggregate configuration.
2999 */
3000 if (filtertype[i] != 'A')
3001 continue;
3002 /* put the aggregate to the kernel routing table */
3003 rrt = (struct riprt *)malloc(sizeof(struct riprt));
3004 if (rrt == NULL) {
3005 fatal("malloc: rrt");
3006 /*NOTREACHED*/
3007 }
3008 memset(rrt, 0, sizeof(struct riprt));
3009 rrt->rrt_info.rip6_dest = ftmp.iff_addr;
3010 rrt->rrt_info.rip6_plen = ftmp.iff_plen;
3011 rrt->rrt_info.rip6_metric = 1;
3012 rrt->rrt_info.rip6_tag = htons(routetag & 0xffff);
3013 rrt->rrt_gw = in6addr_loopback;
3014 rrt->rrt_flags = RTF_UP | RTF_REJECT;
3015 rrt->rrt_rflags = RRTF_AGGREGATE;
3016 rrt->rrt_t = 0;
3017 rrt->rrt_index = loopifindex;
3018#if 0
3019 if (getroute(&rrt->rrt_info, &gw)) {
3020#if 0
3021 /*
3022 * When the address has already been registered in the
3023 * kernel routing table, it should be removed
3024 */
3025 delroute(&rrt->rrt_info, &gw);
3026#else
3027 /* it is safer behavior */
3028 errno = EINVAL;
3029 fatal("%s/%u already in routing table, "
3030 "cannot aggregate",
3031 inet6_n2p(&rrt->rrt_info.rip6_dest),
3032 rrt->rrt_info.rip6_plen);
3033 /*NOTREACHED*/
3034#endif
3035 }
3036#endif
3037 /* Put the route to the list */
3038 rrt->rrt_next = riprt;
3039 riprt = rrt;
3040 trace(1, "Aggregate: %s/%d for %s\n",
3041 inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen,
3042 ifcp->ifc_name);
3043 /* Add this route to the kernel */
3044 if (nflag) /* do not modify kernel routing table */
3045 continue;
3046 addroute(rrt, &in6addr_loopback, loopifcp);
3047 }
3048}
3049
3050/***************** utility functions *****************/
3051
3052/*
3053 * Returns a pointer to ifac whose address and prefix length matches
3054 * with the address and prefix length specified in the arguments.
3055 */
3056struct ifac *
36471bd1 3057ifa_match(const struct ifc *ifcp, const struct in6_addr *ia, int plen)
984263bc
MD
3058{
3059 struct ifac *ifa;
3060
3061 for (ifa = ifcp->ifc_addr; ifa; ifa = ifa->ifa_next) {
3062 if (IN6_ARE_ADDR_EQUAL(&ifa->ifa_addr, ia) &&
3063 ifa->ifa_plen == plen)
3064 break;
3065 }
3066 return ifa;
3067}
3068
3069/*
3070 * Return a pointer to riprt structure whose address and prefix length
3071 * matches with the address and prefix length found in the argument.
3072 * Note: This is not a rtalloc(). Therefore exact match is necessary.
3073 */
3074struct riprt *
36471bd1 3075rtsearch(struct netinfo6 *np, struct riprt **prev_rrt)
984263bc
MD
3076{
3077 struct riprt *rrt;
3078
3079 if (prev_rrt)
3080 *prev_rrt = NULL;
3081 for (rrt = riprt; rrt; rrt = rrt->rrt_next) {
3082 if (rrt->rrt_info.rip6_plen == np->rip6_plen &&
3083 IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest,
3084 &np->rip6_dest))
3085 return rrt;
3086 if (prev_rrt)
3087 *prev_rrt = rrt;
3088 }
3089 if (prev_rrt)
3090 *prev_rrt = NULL;
3091 return 0;
3092}
3093
3094int
36471bd1 3095sin6mask2len(const struct sockaddr_in6 *sin6)
984263bc 3096{
984263bc
MD
3097 return mask2len(&sin6->sin6_addr,
3098 sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr));
3099}
3100
3101int
36471bd1 3102mask2len(const struct in6_addr *addr, int lenlim)
984263bc
MD
3103{
3104 int i = 0, j;
3105 const u_char *p = (const u_char *)addr;
3106
3107 for (j = 0; j < lenlim; j++, p++) {
3108 if (*p != 0xff)
3109 break;
3110 i += 8;
3111 }
3112 if (j < lenlim) {
3113 switch (*p) {
3114#define MASKLEN(m, l) case m: do { i += l; break; } while (0)
3115 MASKLEN(0xfe, 7); break;
3116 MASKLEN(0xfc, 6); break;
3117 MASKLEN(0xf8, 5); break;
3118 MASKLEN(0xf0, 4); break;
3119 MASKLEN(0xe0, 3); break;
3120 MASKLEN(0xc0, 2); break;
3121 MASKLEN(0x80, 1); break;
3122#undef MASKLEN
3123 }
3124 }
3125 return i;
3126}
3127
3128void
36471bd1 3129applymask(struct in6_addr *addr, struct in6_addr *mask)
984263bc
MD
3130{
3131 int i;
3132 u_long *p, *q;
3133
3134 p = (u_long *)addr; q = (u_long *)mask;
3135 for (i = 0; i < 4; i++)
3136 *p++ &= *q++;
3137}
3138
3139static const u_char plent[8] = {
3140 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
3141};
3142
3143void
36471bd1 3144applyplen(struct in6_addr *ia, int plen)
984263bc
MD
3145{
3146 u_char *p;
3147 int i;
3148
3149 p = ia->s6_addr;
3150 for (i = 0; i < 16; i++) {
3151 if (plen <= 0)
3152 *p = 0;
3153 else if (plen < 8)
3154 *p &= plent[plen];
3155 p++, plen -= 8;
3156 }
3157}
3158
3159static const int pl2m[9] = {
3160 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
3161};
3162
3163struct in6_addr *
36471bd1 3164plen2mask(int n)
984263bc
MD
3165{
3166 static struct in6_addr ia;
3167 u_char *p;
3168 int i;
3169
3170 memset(&ia, 0, sizeof(struct in6_addr));
3171 p = (u_char *)&ia;
3172 for (i = 0; i < 16; i++, p++, n -= 8) {
3173 if (n >= 8) {
3174 *p = 0xff;
3175 continue;
3176 }
3177 *p = pl2m[n];
3178 break;
3179 }
3180 return &ia;
3181}
3182
3183char *
36471bd1 3184allocopy(char *p)
984263bc
MD
3185{
3186 char *q = (char *)malloc(strlen(p) + 1);
3187
3188 strcpy(q, p);
3189 return q;
3190}
3191
3192char *
36471bd1 3193hms(void)
984263bc
MD
3194{
3195 static char buf[BUFSIZ];
3196 time_t t;
3197 struct tm *tm;
3198
3199 t = time(NULL);
3200 if ((tm = localtime(&t)) == 0) {
3201 fatal("localtime");
3202 /*NOTREACHED*/
3203 }
3204 snprintf(buf, sizeof(buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
3205 tm->tm_sec);
3206 return buf;
3207}
3208
3209#define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */
3210
3211int
36471bd1 3212ripinterval(int timer)
984263bc
MD
3213{
3214 double r = rand();
3215
3216 interval = (int)(timer + timer * RIPRANDDEV * (r / RAND_MAX - 0.5));
3217 nextalarm = time(NULL) + interval;
3218 return interval;
3219}
3220
3221time_t
36471bd1 3222ripsuptrig(void)
984263bc
MD
3223{
3224 time_t t;
3225
3226 double r = rand();
3227 t = (int)(RIP_TRIG_INT6_MIN +
3228 (RIP_TRIG_INT6_MAX - RIP_TRIG_INT6_MIN) * (r / RAND_MAX));
3229 sup_trig_update = time(NULL) + t;
3230 return t;
3231}
3232
3233void
984263bc 3234fatal(const char *fmt, ...)
984263bc
MD
3235{
3236 va_list ap;
3237 char buf[1024];
3238
984263bc 3239 va_start(ap, fmt);
984263bc
MD
3240 vsnprintf(buf, sizeof(buf), fmt, ap);
3241 perror(buf);
3242 syslog(LOG_ERR, "%s: %s", buf, strerror(errno));
3243 rtdexit();
3244 va_end(ap);
3245}
3246
3247void
984263bc 3248tracet(int level, const char *fmt, ...)
984263bc
MD
3249{
3250 va_list ap;
3251
984263bc 3252 va_start(ap, fmt);
984263bc
MD
3253 if (level <= dflag) {
3254 fprintf(stderr, "%s: ", hms());
3255 vfprintf(stderr, fmt, ap);
3256 }
3257 if (dflag) {
3258 if (level > 0)
3259 vsyslog(LOG_DEBUG, fmt, ap);
3260 else
3261 vsyslog(LOG_WARNING, fmt, ap);
3262 }
3263 va_end(ap);
3264}
3265
3266void
984263bc 3267trace(int level, const char *fmt, ...)
984263bc
MD
3268{
3269 va_list ap;
3270
984263bc 3271 va_start(ap, fmt);
984263bc
MD
3272 if (level <= dflag)
3273 vfprintf(stderr, fmt, ap);
3274 if (dflag) {
3275 if (level > 0)
3276 vsyslog(LOG_DEBUG, fmt, ap);
3277 else
3278 vsyslog(LOG_WARNING, fmt, ap);
3279 }
3280 va_end(ap);
3281}
3282
3283unsigned int
36471bd1 3284if_maxindex(void)
984263bc
MD
3285{
3286 struct if_nameindex *p, *p0;
3287 unsigned int max = 0;
3288
3289 p0 = if_nameindex();
3290 for (p = p0; p && p->if_index && p->if_name; p++) {
3291 if (max < p->if_index)
3292 max = p->if_index;
3293 }
3294 if_freenameindex(p0);
3295 return max;
3296}
3297
3298struct ifc *
36471bd1 3299ifc_find(char *name)
984263bc
MD
3300{
3301 struct ifc *ifcp;
3302
3303 for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) {
3304 if (strcmp(name, ifcp->ifc_name) == 0)
3305 return ifcp;
3306 }
2038fb68 3307 return NULL;
984263bc
MD
3308}
3309
3310struct iff *
36471bd1 3311iff_find(struct ifc *ifcp, int type)
984263bc
MD
3312{
3313 struct iff *iffp;
3314
3315 for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) {
3316 if (iffp->iff_type == type)
3317 return iffp;
3318 }
3319 return NULL;
3320}
3321
3322void
36471bd1 3323setindex2ifc(int idx, struct ifc *ifcp)
984263bc
MD
3324{
3325 int n;
3326 struct ifc **p;
3327
3328 if (!index2ifc) {
3329 nindex2ifc = 5; /*initial guess*/
3330 index2ifc = (struct ifc **)
3331 malloc(sizeof(*index2ifc) * nindex2ifc);
3332 if (index2ifc == NULL) {
3333 fatal("malloc");
3334 /*NOTREACHED*/
3335 }
3336 memset(index2ifc, 0, sizeof(*index2ifc) * nindex2ifc);
3337 }
3338 n = nindex2ifc;
3339 while (nindex2ifc <= idx)
3340 nindex2ifc *= 2;
3341 if (n != nindex2ifc) {
3342 p = (struct ifc **)realloc(index2ifc,
3343 sizeof(*index2ifc) * nindex2ifc);
3344 if (p == NULL) {
3345 fatal("realloc");
3346 /*NOTREACHED*/
3347 }
3348 memset(p + n, 0, sizeof(*index2ifc) * (nindex2ifc - n));
3349 index2ifc = p;
3350 }
3351 index2ifc[idx] = ifcp;
3352}