xref: /freebsd/usr.sbin/rtadvd/rtadvd.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
1 /*	$FreeBSD$	*/
2 /*	$KAME: rtadvd.c,v 1.82 2003/08/05 12:34:23 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/param.h>
34 #include <sys/socket.h>
35 #include <sys/uio.h>
36 #include <sys/time.h>
37 #include <sys/queue.h>
38 
39 #include <net/if.h>
40 #include <net/route.h>
41 #include <net/if_dl.h>
42 #include <netinet/in.h>
43 #include <netinet/ip6.h>
44 #include <netinet6/ip6_var.h>
45 #include <netinet/icmp6.h>
46 
47 #include <arpa/inet.h>
48 
49 #include <time.h>
50 #include <unistd.h>
51 #include <stdio.h>
52 #include <err.h>
53 #include <errno.h>
54 #include <libutil.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #include <syslog.h>
58 #ifdef HAVE_POLL_H
59 #include <poll.h>
60 #endif
61 
62 #include "rtadvd.h"
63 #include "rrenum.h"
64 #include "advcap.h"
65 #include "timer.h"
66 #include "if.h"
67 #include "config.h"
68 #include "dump.h"
69 
70 struct msghdr rcvmhdr;
71 static u_char *rcvcmsgbuf;
72 static size_t rcvcmsgbuflen;
73 static u_char *sndcmsgbuf = NULL;
74 static size_t sndcmsgbuflen;
75 volatile sig_atomic_t do_dump;
76 volatile sig_atomic_t do_die;
77 struct msghdr sndmhdr;
78 struct iovec rcviov[2];
79 struct iovec sndiov[2];
80 struct sockaddr_in6 rcvfrom;
81 struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
82 struct in6_addr in6a_site_allrouters;
83 static char *dumpfilename = "/var/run/rtadvd.dump";
84 static char *pidfilename = "/var/run/rtadvd.pid";
85 static struct pidfh *pfh;
86 static char *mcastif;
87 int sock;
88 int rtsock = -1;
89 int accept_rr = 0;
90 int dflag = 0, sflag = 0;
91 
92 u_char *conffile = NULL;
93 
94 struct rainfo *ralist = NULL;
95 struct nd_optlist {
96 	struct nd_optlist *next;
97 	struct nd_opt_hdr *opt;
98 };
99 union nd_opts {
100 	struct nd_opt_hdr *nd_opt_array[9];
101 	struct {
102 		struct nd_opt_hdr *zero;
103 		struct nd_opt_hdr *src_lladdr;
104 		struct nd_opt_hdr *tgt_lladdr;
105 		struct nd_opt_prefix_info *pi;
106 		struct nd_opt_rd_hdr *rh;
107 		struct nd_opt_mtu *mtu;
108 		struct nd_optlist *list;
109 	} nd_opt_each;
110 };
111 #define nd_opts_src_lladdr	nd_opt_each.src_lladdr
112 #define nd_opts_tgt_lladdr	nd_opt_each.tgt_lladdr
113 #define nd_opts_pi		nd_opt_each.pi
114 #define nd_opts_rh		nd_opt_each.rh
115 #define nd_opts_mtu		nd_opt_each.mtu
116 #define nd_opts_list		nd_opt_each.list
117 
118 #define NDOPT_FLAG_SRCLINKADDR 0x1
119 #define NDOPT_FLAG_TGTLINKADDR 0x2
120 #define NDOPT_FLAG_PREFIXINFO 0x4
121 #define NDOPT_FLAG_RDHDR 0x8
122 #define NDOPT_FLAG_MTU 0x10
123 
124 u_int32_t ndopt_flags[] = {
125 	0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
126 	NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU,
127 };
128 
129 int main(int, char *[]);
130 static void set_die(int);
131 static void die(void);
132 static void sock_open(void);
133 static void rtsock_open(void);
134 static void rtadvd_input(void);
135 static void rs_input(int, struct nd_router_solicit *,
136 			  struct in6_pktinfo *, struct sockaddr_in6 *);
137 static void ra_input(int, struct nd_router_advert *,
138 			  struct in6_pktinfo *, struct sockaddr_in6 *);
139 static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
140 			     struct sockaddr_in6 *);
141 static int nd6_options(struct nd_opt_hdr *, int,
142 			    union nd_opts *, u_int32_t);
143 static void free_ndopts(union nd_opts *);
144 static void ra_output(struct rainfo *);
145 static void rtmsg_input(void);
146 static void rtadvd_set_dump_file(int);
147 static void set_short_delay(struct rainfo *);
148 
149 int
150 main(argc, argv)
151 	int argc;
152 	char *argv[];
153 {
154 #ifdef HAVE_POLL_H
155 	struct pollfd set[2];
156 #else
157 	fd_set *fdsetp, *selectfdp;
158 	int fdmasks;
159 	int maxfd = 0;
160 #endif
161 	struct timeval *timeout;
162 	int i, ch;
163 	int fflag = 0, logopt;
164 	pid_t pid, otherpid;
165 
166 	/* get command line options and arguments */
167 	while ((ch = getopt(argc, argv, "c:dDF:fMp:Rs")) != -1) {
168 		switch (ch) {
169 		case 'c':
170 			conffile = optarg;
171 			break;
172 		case 'd':
173 			dflag = 1;
174 			break;
175 		case 'D':
176 			dflag = 2;
177 			break;
178 		case 'f':
179 			fflag = 1;
180 			break;
181 		case 'M':
182 			mcastif = optarg;
183 			break;
184 		case 'R':
185 			fprintf(stderr, "rtadvd: "
186 				"the -R option is currently ignored.\n");
187 			/* accept_rr = 1; */
188 			/* run anyway... */
189 			break;
190 		case 's':
191 			sflag = 1;
192 			break;
193 		case 'p':
194 			pidfilename = optarg;
195 			break;
196 		case 'F':
197 			dumpfilename = optarg;
198 			break;
199 		}
200 	}
201 	argc -= optind;
202 	argv += optind;
203 	if (argc == 0) {
204 		fprintf(stderr,
205 			"usage: rtadvd [-dDfMRs] [-c conffile] "
206 			"[-F dumpfile] [-p pidfile] interfaces...\n");
207 		exit(1);
208 	}
209 
210 	logopt = LOG_NDELAY | LOG_PID;
211 	if (fflag)
212 		logopt |= LOG_PERROR;
213 	openlog("rtadvd", logopt, LOG_DAEMON);
214 
215 	/* set log level */
216 	if (dflag == 0)
217 		(void)setlogmask(LOG_UPTO(LOG_ERR));
218 	if (dflag == 1)
219 		(void)setlogmask(LOG_UPTO(LOG_INFO));
220 
221 	/* timer initialization */
222 	rtadvd_timer_init();
223 
224 #ifndef HAVE_ARC4RANDOM
225 	/* random value initialization */
226 #ifdef __FreeBSD__
227 	srandomdev();
228 #else
229 	srandom((u_long)time(NULL));
230 #endif
231 #endif
232 
233 	/* get iflist block from kernel */
234 	init_iflist();
235 
236 	while (argc--)
237 		getconfig(*argv++);
238 
239 	if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
240 		fprintf(stderr, "fatal: inet_pton failed\n");
241 		exit(1);
242 	}
243 
244 	pfh = pidfile_open(pidfilename, 0600, &otherpid);
245 	if (pfh == NULL) {
246 		if (errno == EEXIST)
247 			errx(1, "%s already running, pid: %d",
248 			    getprogname(), otherpid);
249 		syslog(LOG_ERR,
250 		    "<%s> failed to open the pid log file, run anyway.",
251 		    __func__);
252 	}
253 
254 	if (!fflag)
255 		daemon(1, 0);
256 
257 	sock_open();
258 
259 	/* record the current PID */
260 	pid = getpid();
261 	pidfile_write(pfh);
262 
263 #ifdef HAVE_POLL_H
264 	set[0].fd = sock;
265 	set[0].events = POLLIN;
266 	if (sflag == 0) {
267 		rtsock_open();
268 		set[1].fd = rtsock;
269 		set[1].events = POLLIN;
270 	} else
271 		set[1].fd = -1;
272 #else
273 	maxfd = sock;
274 	if (sflag == 0) {
275 		rtsock_open();
276 		if (rtsock > sock)
277 			maxfd = rtsock;
278 	} else
279 		rtsock = -1;
280 
281 	fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
282 	if ((fdsetp = malloc(fdmasks)) == NULL) {
283 		err(1, "malloc");
284 		/*NOTREACHED*/
285 	}
286 	if ((selectfdp = malloc(fdmasks)) == NULL) {
287 		err(1, "malloc");
288 		/*NOTREACHED*/
289 	}
290 	memset(fdsetp, 0, fdmasks);
291 	FD_SET(sock, fdsetp);
292 	if (rtsock >= 0)
293 		FD_SET(rtsock, fdsetp);
294 #endif
295 
296 	signal(SIGTERM, set_die);
297 	signal(SIGUSR1, rtadvd_set_dump_file);
298 
299 	while (1) {
300 #ifndef HAVE_POLL_H
301 		memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */
302 #endif
303 
304 		if (do_dump) {	/* SIGUSR1 */
305 			do_dump = 0;
306 			rtadvd_dump_file(dumpfilename);
307 		}
308 
309 		if (do_die) {
310 			die();
311 			/*NOTREACHED*/
312 		}
313 
314 		/* timer expiration check and reset the timer */
315 		timeout = rtadvd_check_timer();
316 
317 		if (timeout != NULL) {
318 			syslog(LOG_DEBUG,
319 			    "<%s> set timer to %ld:%ld. waiting for "
320 			    "inputs or timeout", __func__,
321 			    (long int)timeout->tv_sec,
322 			    (long int)timeout->tv_usec);
323 		} else {
324 			syslog(LOG_DEBUG,
325 			    "<%s> there's no timer. waiting for inputs",
326 			    __func__);
327 		}
328 
329 #ifdef HAVE_POLL_H
330 		if ((i = poll(set, 2, timeout ? (timeout->tv_sec * 1000 +
331 		    timeout->tv_usec / 1000) : INFTIM)) < 0)
332 #else
333 		if ((i = select(maxfd + 1, selectfdp, NULL, NULL,
334 		    timeout)) < 0)
335 #endif
336 		{
337 			/* EINTR would occur upon SIGUSR1 for status dump */
338 			if (errno != EINTR)
339 				syslog(LOG_ERR, "<%s> select: %s",
340 				    __func__, strerror(errno));
341 			continue;
342 		}
343 		if (i == 0)	/* timeout */
344 			continue;
345 #ifdef HAVE_POLL_H
346 		if (rtsock != -1 && set[1].revents & POLLIN)
347 #else
348 		if (rtsock != -1 && FD_ISSET(rtsock, selectfdp))
349 #endif
350 			rtmsg_input();
351 #ifdef HAVE_POLL_H
352 		if (set[0].revents & POLLIN)
353 #else
354 		if (FD_ISSET(sock, selectfdp))
355 #endif
356 			rtadvd_input();
357 	}
358 	exit(0);		/* NOTREACHED */
359 }
360 
361 static void
362 rtadvd_set_dump_file(sig)
363 	int sig;
364 {
365 	do_dump = 1;
366 }
367 
368 static void
369 set_die(sig)
370 	int sig;
371 {
372 	do_die = 1;
373 }
374 
375 static void
376 die()
377 {
378 	struct rainfo *ra;
379 	int i;
380 	const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
381 
382 	if (dflag > 1) {
383 		syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n",
384 		    __func__);
385 	}
386 
387 	for (ra = ralist; ra; ra = ra->next) {
388 		ra->lifetime = 0;
389 		make_packet(ra);
390 	}
391 	for (i = 0; i < retrans; i++) {
392 		for (ra = ralist; ra; ra = ra->next)
393 			ra_output(ra);
394 		sleep(MIN_DELAY_BETWEEN_RAS);
395 	}
396 	pidfile_remove(pfh);
397 	exit(0);
398 	/*NOTREACHED*/
399 }
400 
401 static void
402 rtmsg_input()
403 {
404 	int n, type, ifindex = 0, plen;
405 	size_t len;
406 	char msg[2048], *next, *lim;
407 	u_char ifname[IF_NAMESIZE];
408 	struct prefix *prefix;
409 	struct rainfo *rai;
410 	struct in6_addr *addr;
411 	char addrbuf[INET6_ADDRSTRLEN];
412 	int prefixchange = 0;
413 
414 	n = read(rtsock, msg, sizeof(msg));
415 	if (dflag > 1) {
416 		syslog(LOG_DEBUG, "<%s> received a routing message "
417 		    "(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
418 	}
419 	if (n > rtmsg_len(msg)) {
420 		/*
421 		 * This usually won't happen for messages received on
422 		 * a routing socket.
423 		 */
424 		if (dflag > 1)
425 			syslog(LOG_DEBUG,
426 			    "<%s> received data length is larger than "
427 			    "1st routing message len. multiple messages? "
428 			    "read %d bytes, but 1st msg len = %d",
429 			    __func__, n, rtmsg_len(msg));
430 #if 0
431 		/* adjust length */
432 		n = rtmsg_len(msg);
433 #endif
434 	}
435 
436 	lim = msg + n;
437 	for (next = msg; next < lim; next += len) {
438 		int oldifflags;
439 
440 		next = get_next_msg(next, lim, 0, &len,
441 				    RTADV_TYPE2BITMASK(RTM_ADD) |
442 				    RTADV_TYPE2BITMASK(RTM_DELETE) |
443 				    RTADV_TYPE2BITMASK(RTM_NEWADDR) |
444 				    RTADV_TYPE2BITMASK(RTM_DELADDR) |
445 				    RTADV_TYPE2BITMASK(RTM_IFINFO));
446 		if (len == 0)
447 			break;
448 		type = rtmsg_type(next);
449 		switch (type) {
450 		case RTM_ADD:
451 		case RTM_DELETE:
452 			ifindex = get_rtm_ifindex(next);
453 			break;
454 		case RTM_NEWADDR:
455 		case RTM_DELADDR:
456 			ifindex = get_ifam_ifindex(next);
457 			break;
458 		case RTM_IFINFO:
459 			ifindex = get_ifm_ifindex(next);
460 			break;
461 		default:
462 			/* should not reach here */
463 			if (dflag > 1) {
464 				syslog(LOG_DEBUG,
465 				       "<%s:%d> unknown rtmsg %d on %s",
466 				       __func__, __LINE__, type,
467 				       if_indextoname(ifindex, ifname));
468 			}
469 			continue;
470 		}
471 
472 		if ((rai = if_indextorainfo(ifindex)) == NULL) {
473 			if (dflag > 1) {
474 				syslog(LOG_DEBUG,
475 				       "<%s> route changed on "
476 				       "non advertising interface(%s)",
477 				       __func__,
478 				       if_indextoname(ifindex, ifname));
479 			}
480 			continue;
481 		}
482 		oldifflags = iflist[ifindex]->ifm_flags;
483 
484 		switch (type) {
485 		case RTM_ADD:
486 			/* init ifflags because it may have changed */
487 			iflist[ifindex]->ifm_flags =
488 			    if_getflags(ifindex, iflist[ifindex]->ifm_flags);
489 
490 			if (sflag)
491 				break;	/* we aren't interested in prefixes  */
492 
493 			addr = get_addr(msg);
494 			plen = get_prefixlen(msg);
495 			/* sanity check for plen */
496 			/* as RFC2373, prefixlen is at least 4 */
497 			if (plen < 4 || plen > 127) {
498 				syslog(LOG_INFO, "<%s> new interface route's"
499 				    "plen %d is invalid for a prefix",
500 				    __func__, plen);
501 				break;
502 			}
503 			prefix = find_prefix(rai, addr, plen);
504 			if (prefix) {
505 				if (prefix->timer) {
506 					/*
507 					 * If the prefix has been invalidated,
508 					 * make it available again.
509 					 */
510 					update_prefix(prefix);
511 					prefixchange = 1;
512 				} else if (dflag > 1) {
513 					syslog(LOG_DEBUG,
514 					    "<%s> new prefix(%s/%d) "
515 					    "added on %s, "
516 					    "but it was already in list",
517 					    __func__,
518 					    inet_ntop(AF_INET6, addr,
519 					    (char *)addrbuf, INET6_ADDRSTRLEN),
520 					    plen, rai->ifname);
521 				}
522 				break;
523 			}
524 			make_prefix(rai, ifindex, addr, plen);
525 			prefixchange = 1;
526 			break;
527 		case RTM_DELETE:
528 			/* init ifflags because it may have changed */
529 			iflist[ifindex]->ifm_flags =
530 			    if_getflags(ifindex, iflist[ifindex]->ifm_flags);
531 
532 			if (sflag)
533 				break;
534 
535 			addr = get_addr(msg);
536 			plen = get_prefixlen(msg);
537 			/* sanity check for plen */
538 			/* as RFC2373, prefixlen is at least 4 */
539 			if (plen < 4 || plen > 127) {
540 				syslog(LOG_INFO,
541 				    "<%s> deleted interface route's "
542 				    "plen %d is invalid for a prefix",
543 				    __func__, plen);
544 				break;
545 			}
546 			prefix = find_prefix(rai, addr, plen);
547 			if (prefix == NULL) {
548 				if (dflag > 1) {
549 					syslog(LOG_DEBUG,
550 					    "<%s> prefix(%s/%d) was "
551 					    "deleted on %s, "
552 					    "but it was not in list",
553 					    __func__,
554 					    inet_ntop(AF_INET6, addr,
555 					    (char *)addrbuf, INET6_ADDRSTRLEN),
556 					    plen, rai->ifname);
557 				}
558 				break;
559 			}
560 			invalidate_prefix(prefix);
561 			prefixchange = 1;
562 			break;
563 		case RTM_NEWADDR:
564 		case RTM_DELADDR:
565 			/* init ifflags because it may have changed */
566 			iflist[ifindex]->ifm_flags =
567 			    if_getflags(ifindex, iflist[ifindex]->ifm_flags);
568 			break;
569 		case RTM_IFINFO:
570 			iflist[ifindex]->ifm_flags = get_ifm_flags(next);
571 			break;
572 		default:
573 			/* should not reach here */
574 			if (dflag > 1) {
575 				syslog(LOG_DEBUG,
576 				    "<%s:%d> unknown rtmsg %d on %s",
577 				    __func__, __LINE__, type,
578 				    if_indextoname(ifindex, ifname));
579 			}
580 			return;
581 		}
582 
583 		/* check if an interface flag is changed */
584 		if ((oldifflags & IFF_UP) && /* UP to DOWN */
585 		    !(iflist[ifindex]->ifm_flags & IFF_UP)) {
586 			syslog(LOG_INFO,
587 			    "<%s> interface %s becomes down. stop timer.",
588 			    __func__, rai->ifname);
589 			rtadvd_remove_timer(&rai->timer);
590 		} else if (!(oldifflags & IFF_UP) && /* DOWN to UP */
591 			 (iflist[ifindex]->ifm_flags & IFF_UP)) {
592 			syslog(LOG_INFO,
593 			    "<%s> interface %s becomes up. restart timer.",
594 			    __func__, rai->ifname);
595 
596 			rai->initcounter = 0; /* reset the counter */
597 			rai->waiting = 0; /* XXX */
598 			rai->timer = rtadvd_add_timer(ra_timeout,
599 			    ra_timer_update, rai, rai);
600 			ra_timer_update((void *)rai, &rai->timer->tm);
601 			rtadvd_set_timer(&rai->timer->tm, rai->timer);
602 		} else if (prefixchange &&
603 		    (iflist[ifindex]->ifm_flags & IFF_UP)) {
604 			/*
605 			 * An advertised prefix has been added or invalidated.
606 			 * Will notice the change in a short delay.
607 			 */
608 			rai->initcounter = 0;
609 			set_short_delay(rai);
610 		}
611 	}
612 
613 	return;
614 }
615 
616 void
617 rtadvd_input()
618 {
619 	int i;
620 	int *hlimp = NULL;
621 #ifdef OLDRAWSOCKET
622 	struct ip6_hdr *ip;
623 #endif
624 	struct icmp6_hdr *icp;
625 	int ifindex = 0;
626 	struct cmsghdr *cm;
627 	struct in6_pktinfo *pi = NULL;
628 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
629 	struct in6_addr dst = in6addr_any;
630 
631 	/*
632 	 * Get message. We reset msg_controllen since the field could
633 	 * be modified if we had received a message before setting
634 	 * receive options.
635 	 */
636 	rcvmhdr.msg_controllen = rcvcmsgbuflen;
637 	if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0)
638 		return;
639 
640 	/* extract optional information via Advanced API */
641 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
642 	     cm;
643 	     cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
644 		if (cm->cmsg_level == IPPROTO_IPV6 &&
645 		    cm->cmsg_type == IPV6_PKTINFO &&
646 		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
647 			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
648 			ifindex = pi->ipi6_ifindex;
649 			dst = pi->ipi6_addr;
650 		}
651 		if (cm->cmsg_level == IPPROTO_IPV6 &&
652 		    cm->cmsg_type == IPV6_HOPLIMIT &&
653 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
654 			hlimp = (int *)CMSG_DATA(cm);
655 	}
656 	if (ifindex == 0) {
657 		syslog(LOG_ERR,
658 		       "<%s> failed to get receiving interface",
659 		       __func__);
660 		return;
661 	}
662 	if (hlimp == NULL) {
663 		syslog(LOG_ERR,
664 		       "<%s> failed to get receiving hop limit",
665 		       __func__);
666 		return;
667 	}
668 
669 	/*
670 	 * If we happen to receive data on an interface which is now gone
671 	 * or down, just discard the data.
672 	 */
673 	if (iflist[pi->ipi6_ifindex] == NULL ||
674 	    (iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) {
675 		syslog(LOG_INFO,
676 		       "<%s> received data on a disabled interface (%s)",
677 		       __func__,
678 		       (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" :
679 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf));
680 		return;
681 	}
682 
683 #ifdef OLDRAWSOCKET
684 	if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
685 		syslog(LOG_ERR,
686 		       "<%s> packet size(%d) is too short",
687 		       __func__, i);
688 		return;
689 	}
690 
691 	ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
692 	icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
693 #else
694 	if (i < sizeof(struct icmp6_hdr)) {
695 		syslog(LOG_ERR,
696 		       "<%s> packet size(%d) is too short",
697 		       __func__, i);
698 		return;
699 	}
700 
701 	icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
702 #endif
703 
704 	switch (icp->icmp6_type) {
705 	case ND_ROUTER_SOLICIT:
706 		/*
707 		 * Message verification - RFC-2461 6.1.1
708 		 * XXX: these checks must be done in the kernel as well,
709 		 *      but we can't completely rely on them.
710 		 */
711 		if (*hlimp != 255) {
712 			syslog(LOG_NOTICE,
713 			    "<%s> RS with invalid hop limit(%d) "
714 			    "received from %s on %s",
715 			    __func__, *hlimp,
716 			    inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
717 			    INET6_ADDRSTRLEN),
718 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf));
719 			return;
720 		}
721 		if (icp->icmp6_code) {
722 			syslog(LOG_NOTICE,
723 			    "<%s> RS with invalid ICMP6 code(%d) "
724 			    "received from %s on %s",
725 			    __func__, icp->icmp6_code,
726 			    inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
727 			    INET6_ADDRSTRLEN),
728 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf));
729 			return;
730 		}
731 		if (i < sizeof(struct nd_router_solicit)) {
732 			syslog(LOG_NOTICE,
733 			    "<%s> RS from %s on %s does not have enough "
734 			    "length (len = %d)",
735 			    __func__,
736 			    inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
737 			    INET6_ADDRSTRLEN),
738 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
739 			return;
740 		}
741 		rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom);
742 		break;
743 	case ND_ROUTER_ADVERT:
744 		/*
745 		 * Message verification - RFC-2461 6.1.2
746 		 * XXX: there's a same dilemma as above...
747 		 */
748 		if (*hlimp != 255) {
749 			syslog(LOG_NOTICE,
750 			    "<%s> RA with invalid hop limit(%d) "
751 			    "received from %s on %s",
752 			    __func__, *hlimp,
753 			    inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
754 			    INET6_ADDRSTRLEN),
755 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf));
756 			return;
757 		}
758 		if (icp->icmp6_code) {
759 			syslog(LOG_NOTICE,
760 			    "<%s> RA with invalid ICMP6 code(%d) "
761 			    "received from %s on %s",
762 			    __func__, icp->icmp6_code,
763 			    inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
764 			    INET6_ADDRSTRLEN),
765 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf));
766 			return;
767 		}
768 		if (i < sizeof(struct nd_router_advert)) {
769 			syslog(LOG_NOTICE,
770 			    "<%s> RA from %s on %s does not have enough "
771 			    "length (len = %d)",
772 			    __func__,
773 			    inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
774 			    INET6_ADDRSTRLEN),
775 			    if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
776 			return;
777 		}
778 		ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom);
779 		break;
780 	case ICMP6_ROUTER_RENUMBERING:
781 		if (accept_rr == 0) {
782 			syslog(LOG_ERR, "<%s> received a router renumbering "
783 			    "message, but not allowed to be accepted",
784 			    __func__);
785 			break;
786 		}
787 		rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom,
788 			 &dst);
789 		break;
790 	default:
791 		/*
792 		 * Note that this case is POSSIBLE, especially just
793 		 * after invocation of the daemon. This is because we
794 		 * could receive message after opening the socket and
795 		 * before setting ICMP6 type filter(see sock_open()).
796 		 */
797 		syslog(LOG_ERR, "<%s> invalid icmp type(%d)",
798 		    __func__, icp->icmp6_type);
799 		return;
800 	}
801 
802 	return;
803 }
804 
805 static void
806 rs_input(int len, struct nd_router_solicit *rs,
807 	 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
808 {
809 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
810 	union nd_opts ndopts;
811 	struct rainfo *ra;
812 	struct soliciter *sol;
813 
814 	syslog(LOG_DEBUG,
815 	       "<%s> RS received from %s on %s",
816 	       __func__,
817 	       inet_ntop(AF_INET6, &from->sin6_addr,
818 			 ntopbuf, INET6_ADDRSTRLEN),
819 	       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
820 
821 	/* ND option check */
822 	memset(&ndopts, 0, sizeof(ndopts));
823 	if (nd6_options((struct nd_opt_hdr *)(rs + 1),
824 			len - sizeof(struct nd_router_solicit),
825 			&ndopts, NDOPT_FLAG_SRCLINKADDR)) {
826 		syslog(LOG_INFO,
827 		       "<%s> ND option check failed for an RS from %s on %s",
828 		       __func__,
829 		       inet_ntop(AF_INET6, &from->sin6_addr,
830 				 ntopbuf, INET6_ADDRSTRLEN),
831 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
832 		return;
833 	}
834 
835 	/*
836 	 * If the IP source address is the unspecified address, there
837 	 * must be no source link-layer address option in the message.
838 	 * (RFC-2461 6.1.1)
839 	 */
840 	if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
841 	    ndopts.nd_opts_src_lladdr) {
842 		syslog(LOG_INFO,
843 		       "<%s> RS from unspecified src on %s has a link-layer"
844 		       " address option",
845 		       __func__,
846 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
847 		goto done;
848 	}
849 
850 	ra = ralist;
851 	while (ra != NULL) {
852 		if (pi->ipi6_ifindex == ra->ifindex)
853 			break;
854 		ra = ra->next;
855 	}
856 	if (ra == NULL) {
857 		syslog(LOG_INFO,
858 		       "<%s> RS received on non advertising interface(%s)",
859 		       __func__,
860 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
861 		goto done;
862 	}
863 
864 	ra->rsinput++;		/* increment statistics */
865 
866 	/*
867 	 * Decide whether to send RA according to the rate-limit
868 	 * consideration.
869 	 */
870 
871 	/* record sockaddr waiting for RA, if possible */
872 	sol = (struct soliciter *)malloc(sizeof(*sol));
873 	if (sol) {
874 		sol->addr = *from;
875 		/* XXX RFC2553 need clarification on flowinfo */
876 		sol->addr.sin6_flowinfo = 0;
877 		sol->next = ra->soliciter;
878 		ra->soliciter = sol;
879 	}
880 
881 	/*
882 	 * If there is already a waiting RS packet, don't
883 	 * update the timer.
884 	 */
885 	if (ra->waiting++)
886 		goto done;
887 
888 	set_short_delay(ra);
889 
890   done:
891 	free_ndopts(&ndopts);
892 	return;
893 }
894 
895 static void
896 set_short_delay(rai)
897 	struct rainfo *rai;
898 {
899 	long delay;	/* must not be greater than 1000000 */
900 	struct timeval interval, now, min_delay, tm_tmp, *rest;
901 
902 	/*
903 	 * Compute a random delay. If the computed value
904 	 * corresponds to a time later than the time the next
905 	 * multicast RA is scheduled to be sent, ignore the random
906 	 * delay and send the advertisement at the
907 	 * already-scheduled time. RFC-2461 6.2.6
908 	 */
909 #ifdef HAVE_ARC4RANDOM
910 	delay = arc4random_uniform(MAX_RA_DELAY_TIME);
911 #else
912 	delay = random() % MAX_RA_DELAY_TIME;
913 #endif
914 	interval.tv_sec = 0;
915 	interval.tv_usec = delay;
916 	rest = rtadvd_timer_rest(rai->timer);
917 	if (TIMEVAL_LT(*rest, interval)) {
918 		syslog(LOG_DEBUG, "<%s> random delay is larger than "
919 		    "the rest of the current timer", __func__);
920 		interval = *rest;
921 	}
922 
923 	/*
924 	 * If we sent a multicast Router Advertisement within
925 	 * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
926 	 * the advertisement to be sent at a time corresponding to
927 	 * MIN_DELAY_BETWEEN_RAS plus the random value after the
928 	 * previous advertisement was sent.
929 	 */
930 	gettimeofday(&now, NULL);
931 	TIMEVAL_SUB(&now, &rai->lastsent, &tm_tmp);
932 	min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
933 	min_delay.tv_usec = 0;
934 	if (TIMEVAL_LT(tm_tmp, min_delay)) {
935 		TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
936 		TIMEVAL_ADD(&min_delay, &interval, &interval);
937 	}
938 	rtadvd_set_timer(&interval, rai->timer);
939 }
940 
941 static void
942 ra_input(int len, struct nd_router_advert *ra,
943 	 struct in6_pktinfo *pi, struct sockaddr_in6 *from)
944 {
945 	struct rainfo *rai;
946 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
947 	union nd_opts ndopts;
948 	char *on_off[] = {"OFF", "ON"};
949 	u_int32_t reachabletime, retranstimer, mtu;
950 	int inconsistent = 0;
951 
952 	syslog(LOG_DEBUG,
953 	       "<%s> RA received from %s on %s",
954 	       __func__,
955 	       inet_ntop(AF_INET6, &from->sin6_addr,
956 			 ntopbuf, INET6_ADDRSTRLEN),
957 	       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
958 
959 	/* ND option check */
960 	memset(&ndopts, 0, sizeof(ndopts));
961 	if (nd6_options((struct nd_opt_hdr *)(ra + 1),
962 			len - sizeof(struct nd_router_advert),
963 			&ndopts, NDOPT_FLAG_SRCLINKADDR |
964 			NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
965 		syslog(LOG_INFO,
966 		       "<%s> ND option check failed for an RA from %s on %s",
967 		       __func__,
968 		       inet_ntop(AF_INET6, &from->sin6_addr,
969 				 ntopbuf, INET6_ADDRSTRLEN),
970 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
971 		return;
972 	}
973 
974 	/*
975 	 * RA consistency check according to RFC-2461 6.2.7
976 	 */
977 	if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
978 		syslog(LOG_INFO,
979 		       "<%s> received RA from %s on non-advertising"
980 		       " interface(%s)",
981 		       __func__,
982 		       inet_ntop(AF_INET6, &from->sin6_addr,
983 				 ntopbuf, INET6_ADDRSTRLEN),
984 		       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
985 		goto done;
986 	}
987 	rai->rainput++;		/* increment statistics */
988 
989 	/* Cur Hop Limit value */
990 	if (ra->nd_ra_curhoplimit && rai->hoplimit &&
991 	    ra->nd_ra_curhoplimit != rai->hoplimit) {
992 		syslog(LOG_INFO,
993 		       "<%s> CurHopLimit inconsistent on %s:"
994 		       " %d from %s, %d from us",
995 		       __func__,
996 		       rai->ifname,
997 		       ra->nd_ra_curhoplimit,
998 		       inet_ntop(AF_INET6, &from->sin6_addr,
999 				 ntopbuf, INET6_ADDRSTRLEN),
1000 		       rai->hoplimit);
1001 		inconsistent++;
1002 	}
1003 	/* M flag */
1004 	if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
1005 	    rai->managedflg) {
1006 		syslog(LOG_INFO,
1007 		       "<%s> M flag inconsistent on %s:"
1008 		       " %s from %s, %s from us",
1009 		       __func__,
1010 		       rai->ifname,
1011 		       on_off[!rai->managedflg],
1012 		       inet_ntop(AF_INET6, &from->sin6_addr,
1013 				 ntopbuf, INET6_ADDRSTRLEN),
1014 		       on_off[rai->managedflg]);
1015 		inconsistent++;
1016 	}
1017 	/* O flag */
1018 	if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
1019 	    rai->otherflg) {
1020 		syslog(LOG_INFO,
1021 		       "<%s> O flag inconsistent on %s:"
1022 		       " %s from %s, %s from us",
1023 		       __func__,
1024 		       rai->ifname,
1025 		       on_off[!rai->otherflg],
1026 		       inet_ntop(AF_INET6, &from->sin6_addr,
1027 				 ntopbuf, INET6_ADDRSTRLEN),
1028 		       on_off[rai->otherflg]);
1029 		inconsistent++;
1030 	}
1031 	/* Reachable Time */
1032 	reachabletime = ntohl(ra->nd_ra_reachable);
1033 	if (reachabletime && rai->reachabletime &&
1034 	    reachabletime != rai->reachabletime) {
1035 		syslog(LOG_INFO,
1036 		       "<%s> ReachableTime inconsistent on %s:"
1037 		       " %d from %s, %d from us",
1038 		       __func__,
1039 		       rai->ifname,
1040 		       reachabletime,
1041 		       inet_ntop(AF_INET6, &from->sin6_addr,
1042 				 ntopbuf, INET6_ADDRSTRLEN),
1043 		       rai->reachabletime);
1044 		inconsistent++;
1045 	}
1046 	/* Retrans Timer */
1047 	retranstimer = ntohl(ra->nd_ra_retransmit);
1048 	if (retranstimer && rai->retranstimer &&
1049 	    retranstimer != rai->retranstimer) {
1050 		syslog(LOG_INFO,
1051 		       "<%s> RetranceTimer inconsistent on %s:"
1052 		       " %d from %s, %d from us",
1053 		       __func__,
1054 		       rai->ifname,
1055 		       retranstimer,
1056 		       inet_ntop(AF_INET6, &from->sin6_addr,
1057 				 ntopbuf, INET6_ADDRSTRLEN),
1058 		       rai->retranstimer);
1059 		inconsistent++;
1060 	}
1061 	/* Values in the MTU options */
1062 	if (ndopts.nd_opts_mtu) {
1063 		mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
1064 		if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
1065 			syslog(LOG_INFO,
1066 			       "<%s> MTU option value inconsistent on %s:"
1067 			       " %d from %s, %d from us",
1068 			       __func__,
1069 			       rai->ifname, mtu,
1070 			       inet_ntop(AF_INET6, &from->sin6_addr,
1071 					 ntopbuf, INET6_ADDRSTRLEN),
1072 			       rai->linkmtu);
1073 			inconsistent++;
1074 		}
1075 	}
1076 	/* Preferred and Valid Lifetimes for prefixes */
1077 	{
1078 		struct nd_optlist *optp = ndopts.nd_opts_list;
1079 
1080 		if (ndopts.nd_opts_pi) {
1081 			if (prefix_check(ndopts.nd_opts_pi, rai, from))
1082 				inconsistent++;
1083 		}
1084 		while (optp) {
1085 			if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
1086 					 rai, from))
1087 				inconsistent++;
1088 			optp = optp->next;
1089 		}
1090 	}
1091 
1092 	if (inconsistent)
1093 		rai->rainconsistent++;
1094 
1095   done:
1096 	free_ndopts(&ndopts);
1097 	return;
1098 }
1099 
1100 /* return a non-zero value if the received prefix is inconsitent with ours */
1101 static int
1102 prefix_check(struct nd_opt_prefix_info *pinfo,
1103 	     struct rainfo *rai, struct sockaddr_in6 *from)
1104 {
1105 	u_int32_t preferred_time, valid_time;
1106 	struct prefix *pp;
1107 	int inconsistent = 0;
1108 	u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
1109 	struct timeval now;
1110 
1111 #if 0				/* impossible */
1112 	if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
1113 		return(0);
1114 #endif
1115 
1116 	/*
1117 	 * log if the adveritsed prefix has link-local scope(sanity check?)
1118 	 */
1119 	if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
1120 		syslog(LOG_INFO,
1121 		       "<%s> link-local prefix %s/%d is advertised "
1122 		       "from %s on %s",
1123 		       __func__,
1124 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1125 				 prefixbuf, INET6_ADDRSTRLEN),
1126 		       pinfo->nd_opt_pi_prefix_len,
1127 		       inet_ntop(AF_INET6, &from->sin6_addr,
1128 				 ntopbuf, INET6_ADDRSTRLEN),
1129 		       rai->ifname);
1130 	}
1131 
1132 	if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
1133 			      pinfo->nd_opt_pi_prefix_len)) == NULL) {
1134 		syslog(LOG_INFO,
1135 		       "<%s> prefix %s/%d from %s on %s is not in our list",
1136 		       __func__,
1137 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1138 				 prefixbuf, INET6_ADDRSTRLEN),
1139 		       pinfo->nd_opt_pi_prefix_len,
1140 		       inet_ntop(AF_INET6, &from->sin6_addr,
1141 				 ntopbuf, INET6_ADDRSTRLEN),
1142 		       rai->ifname);
1143 		return(0);
1144 	}
1145 
1146 	preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
1147 	if (pp->pltimeexpire) {
1148 		/*
1149 		 * The lifetime is decremented in real time, so we should
1150 		 * compare the expiration time.
1151 		 * (RFC 2461 Section 6.2.7.)
1152 		 * XXX: can we really expect that all routers on the link
1153 		 * have synchronized clocks?
1154 		 */
1155 		gettimeofday(&now, NULL);
1156 		preferred_time += now.tv_sec;
1157 
1158 		if (!pp->timer && rai->clockskew &&
1159 		    abs(preferred_time - pp->pltimeexpire) > rai->clockskew) {
1160 			syslog(LOG_INFO,
1161 			       "<%s> preferred lifetime for %s/%d"
1162 			       " (decr. in real time) inconsistent on %s:"
1163 			       " %d from %s, %ld from us",
1164 			       __func__,
1165 			       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1166 					 prefixbuf, INET6_ADDRSTRLEN),
1167 			       pinfo->nd_opt_pi_prefix_len,
1168 			       rai->ifname, preferred_time,
1169 			       inet_ntop(AF_INET6, &from->sin6_addr,
1170 					 ntopbuf, INET6_ADDRSTRLEN),
1171 			       pp->pltimeexpire);
1172 			inconsistent++;
1173 		}
1174 	} else if (!pp->timer && preferred_time != pp->preflifetime) {
1175 		syslog(LOG_INFO,
1176 		       "<%s> preferred lifetime for %s/%d"
1177 		       " inconsistent on %s:"
1178 		       " %d from %s, %d from us",
1179 		       __func__,
1180 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1181 				 prefixbuf, INET6_ADDRSTRLEN),
1182 		       pinfo->nd_opt_pi_prefix_len,
1183 		       rai->ifname, preferred_time,
1184 		       inet_ntop(AF_INET6, &from->sin6_addr,
1185 				 ntopbuf, INET6_ADDRSTRLEN),
1186 		       pp->preflifetime);
1187 	}
1188 
1189 	valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
1190 	if (pp->vltimeexpire) {
1191 		gettimeofday(&now, NULL);
1192 		valid_time += now.tv_sec;
1193 
1194 		if (!pp->timer && rai->clockskew &&
1195 		    abs(valid_time - pp->vltimeexpire) > rai->clockskew) {
1196 			syslog(LOG_INFO,
1197 			       "<%s> valid lifetime for %s/%d"
1198 			       " (decr. in real time) inconsistent on %s:"
1199 			       " %d from %s, %ld from us",
1200 			       __func__,
1201 			       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1202 					 prefixbuf, INET6_ADDRSTRLEN),
1203 			       pinfo->nd_opt_pi_prefix_len,
1204 			       rai->ifname, preferred_time,
1205 			       inet_ntop(AF_INET6, &from->sin6_addr,
1206 					 ntopbuf, INET6_ADDRSTRLEN),
1207 			       pp->vltimeexpire);
1208 			inconsistent++;
1209 		}
1210 	} else if (!pp->timer && valid_time != pp->validlifetime) {
1211 		syslog(LOG_INFO,
1212 		       "<%s> valid lifetime for %s/%d"
1213 		       " inconsistent on %s:"
1214 		       " %d from %s, %d from us",
1215 		       __func__,
1216 		       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
1217 				 prefixbuf, INET6_ADDRSTRLEN),
1218 		       pinfo->nd_opt_pi_prefix_len,
1219 		       rai->ifname, valid_time,
1220 		       inet_ntop(AF_INET6, &from->sin6_addr,
1221 				 ntopbuf, INET6_ADDRSTRLEN),
1222 		       pp->validlifetime);
1223 		inconsistent++;
1224 	}
1225 
1226 	return(inconsistent);
1227 }
1228 
1229 struct prefix *
1230 find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
1231 {
1232 	struct prefix *pp;
1233 	int bytelen, bitlen;
1234 	u_char bitmask;
1235 
1236 	for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
1237 		if (plen != pp->prefixlen)
1238 			continue;
1239 		bytelen = plen / 8;
1240 		bitlen = plen % 8;
1241 		bitmask = 0xff << (8 - bitlen);
1242 		if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
1243 			continue;
1244 		if (bitlen == 0 ||
1245 		    ((prefix->s6_addr[bytelen] & bitmask) ==
1246 		     (pp->prefix.s6_addr[bytelen] & bitmask))) {
1247 			return(pp);
1248 		}
1249 	}
1250 
1251 	return(NULL);
1252 }
1253 
1254 /* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */
1255 int
1256 prefix_match(struct in6_addr *p0, int plen0,
1257 	     struct in6_addr *p1, int plen1)
1258 {
1259 	int bytelen, bitlen;
1260 	u_char bitmask;
1261 
1262 	if (plen0 < plen1)
1263 		return(0);
1264 	bytelen = plen1 / 8;
1265 	bitlen = plen1 % 8;
1266 	bitmask = 0xff << (8 - bitlen);
1267 	if (memcmp((void *)p0, (void *)p1, bytelen))
1268 		return(0);
1269 	if (bitlen == 0 ||
1270 	    ((p0->s6_addr[bytelen] & bitmask) ==
1271 	     (p1->s6_addr[bytelen] & bitmask))) {
1272 		return(1);
1273 	}
1274 
1275 	return(0);
1276 }
1277 
1278 static int
1279 nd6_options(struct nd_opt_hdr *hdr, int limit,
1280 	    union nd_opts *ndopts, u_int32_t optflags)
1281 {
1282 	int optlen = 0;
1283 
1284 	for (; limit > 0; limit -= optlen) {
1285 		if (limit < sizeof(struct nd_opt_hdr)) {
1286 			syslog(LOG_INFO, "<%s> short option header", __func__);
1287 			goto bad;
1288 		}
1289 
1290 		hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen);
1291 		if (hdr->nd_opt_len == 0) {
1292 			syslog(LOG_INFO,
1293 			    "<%s> bad ND option length(0) (type = %d)",
1294 			    __func__, hdr->nd_opt_type);
1295 			goto bad;
1296 		}
1297 		optlen = hdr->nd_opt_len << 3;
1298 		if (optlen > limit) {
1299 			syslog(LOG_INFO, "<%s> short option", __func__);
1300 			goto bad;
1301 		}
1302 
1303 		if (hdr->nd_opt_type > ND_OPT_MTU) {
1304 			syslog(LOG_INFO, "<%s> unknown ND option(type %d)",
1305 			    __func__, hdr->nd_opt_type);
1306 			continue;
1307 		}
1308 
1309 		if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
1310 			syslog(LOG_INFO, "<%s> unexpected ND option(type %d)",
1311 			    __func__, hdr->nd_opt_type);
1312 			continue;
1313 		}
1314 
1315 		/*
1316 		 * Option length check.  Do it here for all fixed-length
1317 		 * options.
1318 		 */
1319 		if ((hdr->nd_opt_type == ND_OPT_MTU &&
1320 		    (optlen != sizeof(struct nd_opt_mtu))) ||
1321 		    ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
1322 		    optlen != sizeof(struct nd_opt_prefix_info)))) {
1323 			syslog(LOG_INFO, "<%s> invalid option length",
1324 			    __func__);
1325 			continue;
1326 		}
1327 
1328 		switch (hdr->nd_opt_type) {
1329 		case ND_OPT_TARGET_LINKADDR:
1330 		case ND_OPT_REDIRECTED_HEADER:
1331 			break;	/* we don't care about these options */
1332 		case ND_OPT_SOURCE_LINKADDR:
1333 		case ND_OPT_MTU:
1334 			if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
1335 				syslog(LOG_INFO,
1336 				    "<%s> duplicated ND option (type = %d)",
1337 				    __func__, hdr->nd_opt_type);
1338 			}
1339 			ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
1340 			break;
1341 		case ND_OPT_PREFIX_INFORMATION:
1342 		{
1343 			struct nd_optlist *pfxlist;
1344 
1345 			if (ndopts->nd_opts_pi == 0) {
1346 				ndopts->nd_opts_pi =
1347 				    (struct nd_opt_prefix_info *)hdr;
1348 				continue;
1349 			}
1350 			if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
1351 				syslog(LOG_ERR, "<%s> can't allocate memory",
1352 				    __func__);
1353 				goto bad;
1354 			}
1355 			pfxlist->next = ndopts->nd_opts_list;
1356 			pfxlist->opt = hdr;
1357 			ndopts->nd_opts_list = pfxlist;
1358 
1359 			break;
1360 		}
1361 		default:	/* impossible */
1362 			break;
1363 		}
1364 	}
1365 
1366 	return(0);
1367 
1368   bad:
1369 	free_ndopts(ndopts);
1370 
1371 	return(-1);
1372 }
1373 
1374 static void
1375 free_ndopts(union nd_opts *ndopts)
1376 {
1377 	struct nd_optlist *opt = ndopts->nd_opts_list, *next;
1378 
1379 	while (opt) {
1380 		next = opt->next;
1381 		free(opt);
1382 		opt = next;
1383 	}
1384 }
1385 
1386 void
1387 sock_open()
1388 {
1389 	struct icmp6_filter filt;
1390 	struct ipv6_mreq mreq;
1391 	struct rainfo *ra = ralist;
1392 	int on;
1393 	/* XXX: should be max MTU attached to the node */
1394 	static u_char answer[1500];
1395 
1396 	rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1397 				CMSG_SPACE(sizeof(int));
1398 	rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen);
1399 	if (rcvcmsgbuf == NULL) {
1400 		syslog(LOG_ERR, "<%s> not enough core", __func__);
1401 		exit(1);
1402 	}
1403 
1404 	sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1405 				CMSG_SPACE(sizeof(int));
1406 	sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen);
1407 	if (sndcmsgbuf == NULL) {
1408 		syslog(LOG_ERR, "<%s> not enough core", __func__);
1409 		exit(1);
1410 	}
1411 
1412 	if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
1413 		syslog(LOG_ERR, "<%s> socket: %s", __func__,
1414 		       strerror(errno));
1415 		exit(1);
1416 	}
1417 
1418 	/* specify to tell receiving interface */
1419 	on = 1;
1420 #ifdef IPV6_RECVPKTINFO
1421 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
1422 		       sizeof(on)) < 0) {
1423 		syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s",
1424 		       __func__, strerror(errno));
1425 		exit(1);
1426 	}
1427 #else  /* old adv. API */
1428 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
1429 		       sizeof(on)) < 0) {
1430 		syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s",
1431 		       __func__, strerror(errno));
1432 		exit(1);
1433 	}
1434 #endif
1435 
1436 	on = 1;
1437 	/* specify to tell value of hoplimit field of received IP6 hdr */
1438 #ifdef IPV6_RECVHOPLIMIT
1439 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
1440 		       sizeof(on)) < 0) {
1441 		syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s",
1442 		       __func__, strerror(errno));
1443 		exit(1);
1444 	}
1445 #else  /* old adv. API */
1446 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
1447 		       sizeof(on)) < 0) {
1448 		syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s",
1449 		       __func__, strerror(errno));
1450 		exit(1);
1451 	}
1452 #endif
1453 
1454 	ICMP6_FILTER_SETBLOCKALL(&filt);
1455 	ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
1456 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
1457 	if (accept_rr)
1458 		ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
1459 	if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
1460 		       sizeof(filt)) < 0) {
1461 		syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s",
1462 		       __func__, strerror(errno));
1463 		exit(1);
1464 	}
1465 
1466 	/*
1467 	 * join all routers multicast address on each advertising interface.
1468 	 */
1469 	if (inet_pton(AF_INET6, ALLROUTERS_LINK,
1470 		      &mreq.ipv6mr_multiaddr.s6_addr)
1471 	    != 1) {
1472 		syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
1473 		       __func__);
1474 		exit(1);
1475 	}
1476 	while (ra) {
1477 		mreq.ipv6mr_interface = ra->ifindex;
1478 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
1479 			       sizeof(mreq)) < 0) {
1480 			syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s",
1481 			       __func__, ra->ifname, strerror(errno));
1482 			exit(1);
1483 		}
1484 		ra = ra->next;
1485 	}
1486 
1487 	/*
1488 	 * When attending router renumbering, join all-routers site-local
1489 	 * multicast group.
1490 	 */
1491 	if (accept_rr) {
1492 		if (inet_pton(AF_INET6, ALLROUTERS_SITE,
1493 			      &in6a_site_allrouters) != 1) {
1494 			syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
1495 			       __func__);
1496 			exit(1);
1497 		}
1498 		mreq.ipv6mr_multiaddr = in6a_site_allrouters;
1499 		if (mcastif) {
1500 			if ((mreq.ipv6mr_interface = if_nametoindex(mcastif))
1501 			    == 0) {
1502 				syslog(LOG_ERR,
1503 				       "<%s> invalid interface: %s",
1504 				       __func__, mcastif);
1505 				exit(1);
1506 			}
1507 		} else
1508 			mreq.ipv6mr_interface = ralist->ifindex;
1509 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1510 			       &mreq, sizeof(mreq)) < 0) {
1511 			syslog(LOG_ERR,
1512 			       "<%s> IPV6_JOIN_GROUP(site) on %s: %s",
1513 			       __func__,
1514 			       mcastif ? mcastif : ralist->ifname,
1515 			       strerror(errno));
1516 			exit(1);
1517 		}
1518 	}
1519 
1520 	/* initialize msghdr for receiving packets */
1521 	rcviov[0].iov_base = (caddr_t)answer;
1522 	rcviov[0].iov_len = sizeof(answer);
1523 	rcvmhdr.msg_name = (caddr_t)&rcvfrom;
1524 	rcvmhdr.msg_namelen = sizeof(rcvfrom);
1525 	rcvmhdr.msg_iov = rcviov;
1526 	rcvmhdr.msg_iovlen = 1;
1527 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
1528 	rcvmhdr.msg_controllen = rcvcmsgbuflen;
1529 
1530 	/* initialize msghdr for sending packets */
1531 	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
1532 	sndmhdr.msg_iov = sndiov;
1533 	sndmhdr.msg_iovlen = 1;
1534 	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
1535 	sndmhdr.msg_controllen = sndcmsgbuflen;
1536 
1537 	return;
1538 }
1539 
1540 /* open a routing socket to watch the routing table */
1541 static void
1542 rtsock_open()
1543 {
1544 	if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1545 		syslog(LOG_ERR,
1546 		       "<%s> socket: %s", __func__, strerror(errno));
1547 		exit(1);
1548 	}
1549 }
1550 
1551 struct rainfo *
1552 if_indextorainfo(int idx)
1553 {
1554 	struct rainfo *rai = ralist;
1555 
1556 	for (rai = ralist; rai; rai = rai->next) {
1557 		if (rai->ifindex == idx)
1558 			return(rai);
1559 	}
1560 
1561 	return(NULL);		/* search failed */
1562 }
1563 
1564 static void
1565 ra_output(rainfo)
1566 struct rainfo *rainfo;
1567 {
1568 	int i;
1569 	struct cmsghdr *cm;
1570 	struct in6_pktinfo *pi;
1571 	struct soliciter *sol, *nextsol;
1572 
1573 	if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) {
1574 		syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
1575 		       __func__, rainfo->ifname);
1576 		return;
1577 	}
1578 
1579 	make_packet(rainfo);	/* XXX: inefficient */
1580 
1581 	sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
1582 	sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
1583 	sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
1584 
1585 	cm = CMSG_FIRSTHDR(&sndmhdr);
1586 	/* specify the outgoing interface */
1587 	cm->cmsg_level = IPPROTO_IPV6;
1588 	cm->cmsg_type = IPV6_PKTINFO;
1589 	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1590 	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1591 	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));	/*XXX*/
1592 	pi->ipi6_ifindex = rainfo->ifindex;
1593 
1594 	/* specify the hop limit of the packet */
1595 	{
1596 		int hoplimit = 255;
1597 
1598 		cm = CMSG_NXTHDR(&sndmhdr, cm);
1599 		cm->cmsg_level = IPPROTO_IPV6;
1600 		cm->cmsg_type = IPV6_HOPLIMIT;
1601 		cm->cmsg_len = CMSG_LEN(sizeof(int));
1602 		memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
1603 	}
1604 
1605 	syslog(LOG_DEBUG,
1606 	       "<%s> send RA on %s, # of waitings = %d",
1607 	       __func__, rainfo->ifname, rainfo->waiting);
1608 
1609 	i = sendmsg(sock, &sndmhdr, 0);
1610 
1611 	if (i < 0 || i != rainfo->ra_datalen)  {
1612 		if (i < 0) {
1613 			syslog(LOG_ERR, "<%s> sendmsg on %s: %s",
1614 			       __func__, rainfo->ifname,
1615 			       strerror(errno));
1616 		}
1617 	}
1618 	/* update counter */
1619 	if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
1620 		rainfo->initcounter++;
1621 	rainfo->raoutput++;
1622 
1623 	/*
1624 	 * unicast advertisements
1625 	 * XXX commented out.  reason: though spec does not forbit it, unicast
1626 	 * advert does not really help
1627 	 */
1628 	for (sol = rainfo->soliciter; sol; sol = nextsol) {
1629 		nextsol = sol->next;
1630 
1631 		sol->next = NULL;
1632 		free(sol);
1633 	}
1634 	rainfo->soliciter = NULL;
1635 
1636 	/* update timestamp */
1637 	gettimeofday(&rainfo->lastsent, NULL);
1638 
1639 	/* reset waiting conter */
1640 	rainfo->waiting = 0;
1641 }
1642 
1643 /* process RA timer */
1644 struct rtadvd_timer *
1645 ra_timeout(void *data)
1646 {
1647 	struct rainfo *rai = (struct rainfo *)data;
1648 
1649 #ifdef notyet
1650 	/* if necessary, reconstruct the packet. */
1651 #endif
1652 
1653 	syslog(LOG_DEBUG,
1654 	       "<%s> RA timer on %s is expired",
1655 	       __func__, rai->ifname);
1656 
1657 	ra_output(rai);
1658 
1659 	return(rai->timer);
1660 }
1661 
1662 /* update RA timer */
1663 void
1664 ra_timer_update(void *data, struct timeval *tm)
1665 {
1666 	struct rainfo *rai = (struct rainfo *)data;
1667 	long interval;
1668 
1669 	/*
1670 	 * Whenever a multicast advertisement is sent from an interface,
1671 	 * the timer is reset to a uniformly-distributed random value
1672 	 * between the interface's configured MinRtrAdvInterval and
1673 	 * MaxRtrAdvInterval (RFC2461 6.2.4).
1674 	 */
1675 	interval = rai->mininterval;
1676 #ifdef HAVE_ARC4RANDOM
1677 	interval += arc4random_uniform(rai->maxinterval - rai->mininterval);
1678 #else
1679 	interval += random() % (rai->maxinterval - rai->mininterval);
1680 #endif
1681 
1682 	/*
1683 	 * For the first few advertisements (up to
1684 	 * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
1685 	 * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
1686 	 * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
1687 	 * (RFC-2461 6.2.4)
1688 	 */
1689 	if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
1690 	    interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
1691 		interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
1692 
1693 	tm->tv_sec = interval;
1694 	tm->tv_usec = 0;
1695 
1696 	syslog(LOG_DEBUG,
1697 	       "<%s> RA timer on %s is set to %ld:%ld",
1698 	       __func__, rai->ifname,
1699 	       (long int)tm->tv_sec, (long int)tm->tv_usec);
1700 
1701 	return;
1702 }
1703