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