xref: /openbsd-src/usr.sbin/rad/frontend.c (revision f6b75673f6c960a9743bfd16c1e52dd100265c68)
1 /*	$OpenBSD: frontend.c,v 1.19 2018/11/28 06:41:31 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
5  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24  * All rights reserved.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions and the following disclaimer.
31  * 2. Redistributions in binary form must reproduce the above copyright
32  *    notice, this list of conditions and the following disclaimer in the
33  *    documentation and/or other materials provided with the distribution.
34  * 3. Neither the name of the project nor the names of its contributors
35  *    may be used to endorse or promote products derived from this software
36  *    without specific prior written permission.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  */
50 
51 #include <sys/types.h>
52 #include <sys/ioctl.h>
53 #include <sys/queue.h>
54 #include <sys/socket.h>
55 #include <sys/syslog.h>
56 #include <sys/uio.h>
57 
58 #include <net/if.h>
59 #include <net/if_dl.h>
60 #include <net/if_types.h>
61 #include <net/route.h>
62 
63 #include <arpa/inet.h>
64 
65 #include <netinet/in.h>
66 #include <netinet/if_ether.h>
67 #include <netinet6/nd6.h>
68 #include <netinet6/in6_var.h>
69 #include <netinet/ip6.h>
70 #include <netinet6/ip6_var.h>
71 #include <netinet/icmp6.h>
72 
73 #include <ctype.h>
74 #include <errno.h>
75 #include <event.h>
76 #include <ifaddrs.h>
77 #include <imsg.h>
78 #include <pwd.h>
79 #include <signal.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 
85 #include "log.h"
86 #include "rad.h"
87 #include "frontend.h"
88 #include "control.h"
89 
90 #define	RA_MAX_SIZE		1500
91 #define	ROUTE_SOCKET_BUF_SIZE	16384
92 
93 struct icmp6_ev {
94 	struct event		 ev;
95 	uint8_t			 answer[1500];
96 	struct msghdr		 rcvmhdr;
97 	struct iovec		 rcviov[1];
98 	struct sockaddr_in6	 from;
99 } icmp6ev;
100 
101 struct ra_iface {
102 	TAILQ_ENTRY(ra_iface)		entry;
103 	struct ra_prefix_conf_head	prefixes;
104 	char				name[IF_NAMESIZE];
105 	char				conf_name[IF_NAMESIZE];
106 	uint32_t			if_index;
107 	int				removed;
108 	int				prefix_count;
109 	size_t				datalen;
110 	uint8_t				data[RA_MAX_SIZE];
111 };
112 
113 TAILQ_HEAD(, ra_iface)	ra_interfaces;
114 
115 __dead void		 frontend_shutdown(void);
116 void			 frontend_sig_handler(int, short, void *);
117 void			 frontend_startup(void);
118 void			 icmp6_receive(int, short, void *);
119 void			 join_all_routers_mcast_group(struct ra_iface *);
120 void			 leave_all_routers_mcast_group(struct ra_iface *);
121 void			 merge_ra_interface(char *, char *);
122 void			 merge_ra_interfaces(void);
123 struct ra_iface		*find_ra_iface_by_id(uint32_t);
124 struct ra_iface		*find_ra_iface_by_name(char *);
125 struct ra_iface_conf	*find_ra_iface_conf(struct ra_iface_conf_head *,
126 			    char *);
127 struct ra_prefix_conf	*find_ra_prefix_conf(struct ra_prefix_conf_head*,
128 			    struct in6_addr *, int);
129 void			 add_new_prefix_to_ra_iface(struct ra_iface *r,
130 			    struct in6_addr *, int, struct ra_prefix_conf *);
131 void			 free_ra_iface(struct ra_iface *);
132 int			 in6_mask2prefixlen(struct in6_addr *);
133 void			 get_interface_prefixes(struct ra_iface *,
134 			     struct ra_prefix_conf *);
135 void			 build_packet(struct ra_iface *);
136 void			 build_leaving_packet(struct ra_iface *);
137 void			 ra_output(struct ra_iface *, struct sockaddr_in6 *);
138 void			 get_rtaddrs(int, struct sockaddr *,
139 			     struct sockaddr **);
140 void			 route_receive(int, short, void *);
141 void			 handle_route_message(struct rt_msghdr *,
142 			     struct sockaddr **);
143 
144 struct rad_conf	*frontend_conf;
145 struct imsgev		*iev_main;
146 struct imsgev		*iev_engine;
147 struct event		 ev_route;
148 int			 icmp6sock = -1, ioctlsock = -1;
149 struct ipv6_mreq	 all_routers;
150 struct sockaddr_in6	 all_nodes;
151 struct msghdr		 sndmhdr;
152 struct iovec		 sndiov[2];
153 
154 void
155 frontend_sig_handler(int sig, short event, void *bula)
156 {
157 	/*
158 	 * Normal signal handler rules don't apply because libevent
159 	 * decouples for us.
160 	 */
161 
162 	switch (sig) {
163 	case SIGINT:
164 	case SIGTERM:
165 		frontend_shutdown();
166 	default:
167 		fatalx("unexpected signal");
168 	}
169 }
170 
171 void
172 frontend(int debug, int verbose)
173 {
174 	struct event		 ev_sigint, ev_sigterm;
175 	struct passwd		*pw;
176 	size_t			 rcvcmsglen, sndcmsgbuflen;
177 	uint8_t			*rcvcmsgbuf;
178 	uint8_t			*sndcmsgbuf = NULL;
179 
180 	frontend_conf = config_new_empty();
181 	control_state.fd = -1;
182 
183 	log_init(debug, LOG_DAEMON);
184 	log_setverbose(verbose);
185 
186 	if ((pw = getpwnam(RAD_USER)) == NULL)
187 		fatal("getpwnam");
188 
189 	if (chroot(pw->pw_dir) == -1)
190 		fatal("chroot");
191 	if (chdir("/") == -1)
192 		fatal("chdir(\"/\")");
193 
194 	rad_process = PROC_FRONTEND;
195 	setproctitle("%s", log_procnames[rad_process]);
196 	log_procinit(log_procnames[rad_process]);
197 
198 	if (setgroups(1, &pw->pw_gid) ||
199 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
200 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
201 		fatal("can't drop privileges");
202 
203 	/* XXX pass in from main */
204 	if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0)
205 		fatal("socket");
206 
207 	if (pledge("stdio inet unix recvfd route mcast", NULL) == -1)
208 		fatal("pledge");
209 
210 	event_init();
211 
212 	/* Setup signal handler. */
213 	signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL);
214 	signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL);
215 	signal_add(&ev_sigint, NULL);
216 	signal_add(&ev_sigterm, NULL);
217 	signal(SIGPIPE, SIG_IGN);
218 	signal(SIGHUP, SIG_IGN);
219 
220 	/* Setup pipe and event handler to the parent process. */
221 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
222 		fatal(NULL);
223 	imsg_init(&iev_main->ibuf, 3);
224 	iev_main->handler = frontend_dispatch_main;
225 	iev_main->events = EV_READ;
226 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
227 	    iev_main->handler, iev_main);
228 	event_add(&iev_main->ev, NULL);
229 
230 	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
231 	    CMSG_SPACE(sizeof(int));
232 	if((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL)
233 		fatal("malloc");
234 
235 	icmp6ev.rcviov[0].iov_base = (caddr_t)icmp6ev.answer;
236 	icmp6ev.rcviov[0].iov_len = sizeof(icmp6ev.answer);
237 	icmp6ev.rcvmhdr.msg_name = (caddr_t)&icmp6ev.from;
238 	icmp6ev.rcvmhdr.msg_namelen = sizeof(icmp6ev.from);
239 	icmp6ev.rcvmhdr.msg_iov = icmp6ev.rcviov;
240 	icmp6ev.rcvmhdr.msg_iovlen = 1;
241 	icmp6ev.rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
242 	icmp6ev.rcvmhdr.msg_controllen = rcvcmsglen;
243 
244 	if (inet_pton(AF_INET6, "ff02::2",
245 	    &all_routers.ipv6mr_multiaddr.s6_addr) == -1)
246 		fatal("inet_pton");
247 
248 	all_nodes.sin6_len = sizeof(all_nodes);
249 	all_nodes.sin6_family = AF_INET6;
250 	if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1)
251 		fatal("inet_pton");
252 
253 	sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
254 	    CMSG_SPACE(sizeof(int));
255 	if ((sndcmsgbuf = malloc(sndcmsgbuflen)) == NULL)
256 		fatal("%s", __func__);
257 
258 	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
259 	sndmhdr.msg_iov = sndiov;
260 	sndmhdr.msg_iovlen = 1;
261 	sndmhdr.msg_control = sndcmsgbuf;
262 	sndmhdr.msg_controllen = sndcmsgbuflen;
263 
264 	TAILQ_INIT(&ra_interfaces);
265 
266 	event_dispatch();
267 
268 	frontend_shutdown();
269 }
270 
271 __dead void
272 frontend_shutdown(void)
273 {
274 	/* Close pipes. */
275 	msgbuf_write(&iev_engine->ibuf.w);
276 	msgbuf_clear(&iev_engine->ibuf.w);
277 	close(iev_engine->ibuf.fd);
278 	msgbuf_write(&iev_main->ibuf.w);
279 	msgbuf_clear(&iev_main->ibuf.w);
280 	close(iev_main->ibuf.fd);
281 
282 	config_clear(frontend_conf);
283 
284 	free(iev_engine);
285 	free(iev_main);
286 
287 	log_info("frontend exiting");
288 	exit(0);
289 }
290 
291 int
292 frontend_imsg_compose_main(int type, pid_t pid, void *data, uint16_t datalen)
293 {
294 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
295 	    datalen));
296 }
297 
298 int
299 frontend_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen)
300 {
301 	return (imsg_compose_event(iev_engine, type, 0, pid, -1, data,
302 	    datalen));
303 }
304 
305 void
306 frontend_dispatch_main(int fd, short event, void *bula)
307 {
308 	static struct rad_conf		*nconf;
309 	static struct ra_iface_conf	*ra_iface_conf;
310 	static struct ra_options_conf	*ra_options;
311 	struct imsg			 imsg;
312 	struct imsgev			*iev = bula;
313 	struct imsgbuf			*ibuf = &iev->ibuf;
314 	struct ra_prefix_conf		*ra_prefix_conf;
315 	struct ra_rdnss_conf		*ra_rdnss_conf;
316 	struct ra_dnssl_conf		*ra_dnssl_conf;
317 	int				 n, shut = 0;
318 
319 	if (event & EV_READ) {
320 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
321 			fatal("imsg_read error");
322 		if (n == 0)	/* Connection closed. */
323 			shut = 1;
324 	}
325 	if (event & EV_WRITE) {
326 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
327 			fatal("msgbuf_write");
328 		if (n == 0)	/* Connection closed. */
329 			shut = 1;
330 	}
331 
332 	for (;;) {
333 		if ((n = imsg_get(ibuf, &imsg)) == -1)
334 			fatal("%s: imsg_get error", __func__);
335 		if (n == 0)	/* No more messages. */
336 			break;
337 
338 		switch (imsg.hdr.type) {
339 		case IMSG_SOCKET_IPC:
340 			/*
341 			 * Setup pipe and event handler to the engine
342 			 * process.
343 			 */
344 			if (iev_engine) {
345 				log_warnx("%s: received unexpected imsg fd "
346 				    "to frontend", __func__);
347 				break;
348 			}
349 			if ((fd = imsg.fd) == -1) {
350 				log_warnx("%s: expected to receive imsg fd to "
351 				   "frontend but didn't receive any",
352 				   __func__);
353 				break;
354 			}
355 
356 			iev_engine = malloc(sizeof(struct imsgev));
357 			if (iev_engine == NULL)
358 				fatal(NULL);
359 
360 			imsg_init(&iev_engine->ibuf, fd);
361 			iev_engine->handler = frontend_dispatch_engine;
362 			iev_engine->events = EV_READ;
363 
364 			event_set(&iev_engine->ev, iev_engine->ibuf.fd,
365 			iev_engine->events, iev_engine->handler, iev_engine);
366 			event_add(&iev_engine->ev, NULL);
367 			break;
368 		case IMSG_RECONF_CONF:
369 			if ((nconf = malloc(sizeof(struct rad_conf))) ==
370 			    NULL)
371 				fatal(NULL);
372 			memcpy(nconf, imsg.data, sizeof(struct rad_conf));
373 			SIMPLEQ_INIT(&nconf->ra_iface_list);
374 			SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list);
375 			SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list);
376 			ra_options = &nconf->ra_options;
377 			break;
378 		case IMSG_RECONF_RA_IFACE:
379 			if ((ra_iface_conf = malloc(sizeof(struct
380 			    ra_iface_conf))) == NULL)
381 				fatal(NULL);
382 			memcpy(ra_iface_conf, imsg.data, sizeof(struct
383 			    ra_iface_conf));
384 			ra_iface_conf->autoprefix = NULL;
385 			SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
386 			SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list);
387 			SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list);
388 			SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
389 			    ra_iface_conf, entry);
390 			ra_options = &ra_iface_conf->ra_options;
391 			break;
392 		case IMSG_RECONF_RA_AUTOPREFIX:
393 			if ((ra_iface_conf->autoprefix = malloc(sizeof(struct
394 			    ra_prefix_conf))) == NULL)
395 				fatal(NULL);
396 			memcpy(ra_iface_conf->autoprefix, imsg.data,
397 			    sizeof(struct ra_prefix_conf));
398 			break;
399 		case IMSG_RECONF_RA_PREFIX:
400 			if ((ra_prefix_conf = malloc(sizeof(struct
401 			    ra_prefix_conf))) == NULL)
402 				fatal(NULL);
403 			memcpy(ra_prefix_conf, imsg.data,
404 			    sizeof(struct ra_prefix_conf));
405 			SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,
406 			    ra_prefix_conf, entry);
407 			break;
408 		case IMSG_RECONF_RA_RDNSS:
409 			if ((ra_rdnss_conf = malloc(sizeof(struct
410 			    ra_rdnss_conf))) == NULL)
411 				fatal(NULL);
412 			memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
413 			    ra_rdnss_conf));
414 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list,
415 			    ra_rdnss_conf, entry);
416 			break;
417 		case IMSG_RECONF_RA_DNSSL:
418 			if ((ra_dnssl_conf = malloc(sizeof(struct
419 			    ra_dnssl_conf))) == NULL)
420 				fatal(NULL);
421 			memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
422 			    ra_dnssl_conf));
423 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
424 			    ra_dnssl_conf, entry);
425 			break;
426 		case IMSG_RECONF_END:
427 			merge_config(frontend_conf, nconf);
428 			merge_ra_interfaces();
429 			nconf = NULL;
430 			break;
431 		case IMSG_ICMP6SOCK:
432 			if ((icmp6sock = imsg.fd) == -1)
433 				fatalx("%s: expected to receive imsg "
434 				    "ICMPv6 fd but didn't receive any",
435 				    __func__);
436 			event_set(&icmp6ev.ev, icmp6sock, EV_READ | EV_PERSIST,
437 			    icmp6_receive, NULL);
438 		case IMSG_ROUTESOCK:
439 			if ((fd = imsg.fd) == -1)
440 				fatalx("%s: expected to receive imsg "
441 				    "routesocket fd but didn't receive any",
442 				    __func__);
443 			event_set(&ev_route, fd, EV_READ | EV_PERSIST,
444 			    route_receive, NULL);
445 			break;
446 		case IMSG_STARTUP:
447 			if (pledge("stdio inet unix route mcast", NULL) == -1)
448 				fatal("pledge");
449 			frontend_startup();
450 			break;
451 		case IMSG_CONTROLFD:
452 			if ((fd = imsg.fd) == -1)
453 				fatalx("%s: expected to receive imsg "
454 				    "control fd but didn't receive any",
455 				    __func__);
456 			control_state.fd = fd;
457 			/* Listen on control socket. */
458 			TAILQ_INIT(&ctl_conns);
459 			control_listen();
460 			break;
461 		case IMSG_SHUTDOWN:
462 			frontend_imsg_compose_engine(IMSG_SHUTDOWN, 0, NULL, 0);
463 			break;
464 		default:
465 			log_debug("%s: error handling imsg %d", __func__,
466 			    imsg.hdr.type);
467 			break;
468 		}
469 		imsg_free(&imsg);
470 	}
471 	if (!shut)
472 		imsg_event_add(iev);
473 	else {
474 		/* This pipe is dead. Remove its event handler. */
475 		event_del(&iev->ev);
476 		event_loopexit(NULL);
477 	}
478 }
479 
480 void
481 frontend_dispatch_engine(int fd, short event, void *bula)
482 {
483 	struct imsgev		*iev = bula;
484 	struct imsgbuf		*ibuf = &iev->ibuf;
485 	struct imsg		 imsg;
486 	struct imsg_send_ra	 send_ra;
487 	struct ra_iface		*ra_iface;
488 	uint32_t		 if_index;
489 	int			 n, shut = 0;
490 
491 	if (event & EV_READ) {
492 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
493 			fatal("imsg_read error");
494 		if (n == 0)	/* Connection closed. */
495 			shut = 1;
496 	}
497 	if (event & EV_WRITE) {
498 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
499 			fatal("msgbuf_write");
500 		if (n == 0)	/* Connection closed. */
501 			shut = 1;
502 	}
503 
504 	for (;;) {
505 		if ((n = imsg_get(ibuf, &imsg)) == -1)
506 			fatal("%s: imsg_get error", __func__);
507 		if (n == 0)	/* No more messages. */
508 			break;
509 
510 		switch (imsg.hdr.type) {
511 		case IMSG_SEND_RA:
512 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(send_ra))
513 				fatal("%s: IMSG_SEND_RA wrong length: %d",
514 				    __func__, imsg.hdr.len);
515 			memcpy(&send_ra, imsg.data, sizeof(send_ra));
516 			ra_iface = find_ra_iface_by_id(send_ra.if_index);
517 			if (ra_iface)
518 				ra_output(ra_iface, &send_ra.to);
519 			break;
520 		case IMSG_REMOVE_IF:
521 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index))
522 				fatal("%s: IMSG_REMOVE_IF wrong length: %d",
523 				    __func__, imsg.hdr.len);
524 			memcpy(&if_index, imsg.data, sizeof(if_index));
525 			ra_iface = find_ra_iface_by_id(if_index);
526 			if (ra_iface) {
527 				TAILQ_REMOVE(&ra_interfaces, ra_iface, entry);
528 				free_ra_iface(ra_iface);
529 			}
530 			break;
531 		case IMSG_SHUTDOWN:
532 			frontend_imsg_compose_main(IMSG_SHUTDOWN, 0, NULL, 0);
533 			break;
534 		default:
535 			log_debug("%s: error handling imsg %d", __func__,
536 			    imsg.hdr.type);
537 			break;
538 		}
539 		imsg_free(&imsg);
540 	}
541 	if (!shut)
542 		imsg_event_add(iev);
543 	else {
544 		/* This pipe is dead. Remove its event handler. */
545 		event_del(&iev->ev);
546 		event_loopexit(NULL);
547 	}
548 }
549 
550 void
551 frontend_startup(void)
552 {
553 	if (!event_initialized(&ev_route))
554 		fatalx("%s: did not receive a route socket from the main "
555 		    "process", __func__);
556 
557 	event_add(&ev_route, NULL);
558 
559 	if (!event_initialized(&icmp6ev.ev))
560 		fatalx("%s: did not receive a icmp6 socket fd from the main "
561 		    "process", __func__);
562 
563 	event_add(&icmp6ev.ev, NULL);
564 
565 	frontend_imsg_compose_main(IMSG_STARTUP_DONE, 0, NULL, 0);
566 }
567 
568 
569 void
570 icmp6_receive(int fd, short events, void *arg)
571 {
572 	struct imsg_ra_rs	 ra_rs;
573 	struct in6_pktinfo	*pi = NULL;
574 	struct cmsghdr		*cm;
575 	ssize_t			 len;
576 	int			 if_index = 0, *hlimp = NULL;
577 	char			 ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
578 
579 	if ((len = recvmsg(fd, &icmp6ev.rcvmhdr, 0)) < 0) {
580 		log_warn("recvmsg");
581 		return;
582 	}
583 
584 	/* extract optional information via Advanced API */
585 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev.rcvmhdr); cm;
586 	    cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev.rcvmhdr, cm)) {
587 		if (cm->cmsg_level == IPPROTO_IPV6 &&
588 		    cm->cmsg_type == IPV6_PKTINFO &&
589 		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
590 			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
591 			if_index = pi->ipi6_ifindex;
592 		}
593 		if (cm->cmsg_level == IPPROTO_IPV6 &&
594 		    cm->cmsg_type == IPV6_HOPLIMIT &&
595 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
596 			hlimp = (int *)CMSG_DATA(cm);
597 	}
598 
599 	if (if_index == 0) {
600 		log_warnx("failed to get receiving interface");
601 		return;
602 	}
603 
604 	if (hlimp == NULL) {
605 		log_warnx("failed to get receiving hop limit");
606 		return;
607 	}
608 
609 	if (*hlimp != 255) {
610 		log_warnx("invalid RA or RS with hop limit of %d from %s on %s",
611 		    *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
612 		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
613 		    ifnamebuf));
614 		return;
615 	}
616 
617 	log_debug("RA or RS with hop limit of %d from %s on %s",
618 	    *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
619 	    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
620 	    ifnamebuf));
621 
622 	if ((size_t)len > sizeof(ra_rs.packet)) {
623 		log_warnx("invalid RA or RS with size %ld from %s on %s",
624 		    len, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
625 		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
626 		    ifnamebuf));
627 		return;
628 	}
629 
630 	ra_rs.if_index = if_index;
631 	memcpy(&ra_rs.from,  &icmp6ev.from, sizeof(ra_rs.from));
632 	ra_rs.len = len;
633 	memcpy(ra_rs.packet, icmp6ev.answer, len);
634 
635 	frontend_imsg_compose_engine(IMSG_RA_RS, 0, &ra_rs, sizeof(ra_rs));
636 }
637 
638 void
639 join_all_routers_mcast_group(struct ra_iface *ra_iface)
640 {
641 	log_debug("joining multicast group on %s", ra_iface->name);
642 	all_routers.ipv6mr_interface = ra_iface->if_index;
643 	if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
644 	    &all_routers, sizeof(all_routers)) == -1)
645 		fatal("IPV6_JOIN_GROUP(%s)", ra_iface->name);
646 }
647 
648 void
649 leave_all_routers_mcast_group(struct ra_iface *ra_iface)
650 {
651 	log_debug("leaving multicast group on %s", ra_iface->name);
652 	all_routers.ipv6mr_interface = ra_iface->if_index;
653 	setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
654 	    &all_routers, sizeof(all_routers));
655 }
656 
657 struct ra_iface*
658 find_ra_iface_by_id(uint32_t if_index)
659 {
660 	struct ra_iface	*ra_iface;
661 
662 	TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) {
663 		if (ra_iface->if_index == if_index)
664 			return ra_iface;
665 	}
666 	return (NULL);
667 }
668 
669 struct ra_iface*
670 find_ra_iface_by_name(char *if_name)
671 {
672 	struct ra_iface	*ra_iface;
673 
674 	TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) {
675 		if (strcmp(ra_iface->name, if_name) == 0)
676 			return ra_iface;
677 	}
678 	return (NULL);
679 }
680 
681 struct ra_iface_conf*
682 find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name)
683 {
684 	struct ra_iface_conf	*ra_iface_conf;
685 
686 	SIMPLEQ_FOREACH(ra_iface_conf, head, entry) {
687 		if (strcmp(ra_iface_conf->name, if_name) == 0)
688 			return ra_iface_conf;
689 	}
690 	return (NULL);
691 }
692 
693 void
694 merge_ra_interface(char *name, char *conf_name)
695 {
696 	struct ra_iface		*ra_iface;
697 	uint32_t		 if_index;
698 
699 	if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
700 		log_debug("keeping interface %s", name);
701 		ra_iface->removed = 0;
702 		return;
703 	}
704 
705 	log_debug("new interface %s", name);
706 	if ((if_index = if_nametoindex(name)) == 0)
707 		return;
708 	log_debug("adding interface %s", name);
709 	if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
710 		fatal("%s", __func__);
711 
712 	strlcpy(ra_iface->name, name, sizeof(ra_iface->name));
713 	strlcpy(ra_iface->conf_name, conf_name,
714 	    sizeof(ra_iface->conf_name));
715 
716 	ra_iface->if_index = if_index;
717 	SIMPLEQ_INIT(&ra_iface->prefixes);
718 	TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry);
719 	join_all_routers_mcast_group(ra_iface);
720 }
721 
722 void
723 merge_ra_interfaces(void)
724 {
725 	struct ra_iface_conf	*ra_iface_conf;
726 	struct ra_prefix_conf	*ra_prefix_conf;
727 	struct ra_iface		*ra_iface;
728 	struct ifgroupreq	 ifgr;
729 	struct ifg_req		*ifg;
730 	char			*conf_name;
731 	unsigned int		 len;
732 
733 	TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)
734 		ra_iface->removed = 1;
735 
736 	SIMPLEQ_FOREACH(ra_iface_conf, &frontend_conf->ra_iface_list, entry) {
737 		conf_name = ra_iface_conf->name;
738 
739 		/* check if network interface or group */
740 		if (isdigit((unsigned char)conf_name[strlen(conf_name) - 1])) {
741 			merge_ra_interface(conf_name, conf_name);
742 		} else {
743 			log_debug("interface group %s", conf_name);
744 
745 			memset(&ifgr, 0, sizeof(ifgr));
746 			strlcpy(ifgr.ifgr_name, conf_name,
747 			    sizeof(ifgr.ifgr_name));
748 			if (ioctl(ioctlsock, SIOCGIFGMEMB,
749 			    (caddr_t)&ifgr) == -1)
750 				continue;
751 
752 			len = ifgr.ifgr_len;
753 			if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
754 				fatal("%s: calloc", __func__);
755 			if (ioctl(ioctlsock, SIOCGIFGMEMB,
756 			    (caddr_t)&ifgr) == -1) {
757 				log_debug("group %s without members",
758 				    conf_name);
759 				free(ifgr.ifgr_groups);
760 				continue;
761 			}
762 
763 			for (ifg = ifgr.ifgr_groups;
764 			    (ifg != NULL) && (len >= sizeof(struct ifg_req));
765 			    ifg++) {
766 				len -= sizeof(struct ifg_req);
767 				merge_ra_interface(ifg->ifgrq_member,
768 				    conf_name);
769 			}
770 			free(ifgr.ifgr_groups);
771 		}
772 	}
773 
774 	TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) {
775 		while ((ra_prefix_conf = SIMPLEQ_FIRST(&ra_iface->prefixes))
776 		    != NULL) {
777 			SIMPLEQ_REMOVE_HEAD(&ra_iface->prefixes,
778 			    entry);
779 			free(ra_prefix_conf);
780 		}
781 		ra_iface->prefix_count = 0;
782 
783 		if (ra_iface->removed) {
784 			log_debug("iface removed: %s", ra_iface->name);
785 			build_leaving_packet(ra_iface);
786 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
787 			    &ra_iface->if_index, sizeof(ra_iface->if_index));
788 			continue;
789 		}
790 
791 		ra_iface_conf = find_ra_iface_conf(
792 		    &frontend_conf->ra_iface_list, ra_iface->conf_name);
793 
794 		log_debug("add static prefixes for %s", ra_iface->name);
795 
796 		SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface_conf->ra_prefix_list,
797 		    entry) {
798 			add_new_prefix_to_ra_iface(ra_iface,
799 			    &ra_prefix_conf->prefix,
800 			    ra_prefix_conf->prefixlen, ra_prefix_conf);
801 		}
802 
803 		if (ra_iface_conf->autoprefix)
804 			get_interface_prefixes(ra_iface,
805 			    ra_iface_conf->autoprefix);
806 
807 		build_packet(ra_iface);
808 	}
809 }
810 
811 void
812 free_ra_iface(struct ra_iface *ra_iface)
813 {
814 	struct ra_prefix_conf	*prefix;
815 
816 	leave_all_routers_mcast_group(ra_iface);
817 
818 	while ((prefix = SIMPLEQ_FIRST(&ra_iface->prefixes)) != NULL) {
819 		SIMPLEQ_REMOVE_HEAD(&ra_iface->prefixes, entry);
820 		free(prefix);
821 	}
822 
823 	free(ra_iface);
824 }
825 
826 /* from kame via ifconfig, where it's called prefix() */
827 int
828 in6_mask2prefixlen(struct in6_addr *in6)
829 {
830 	u_char *nam = (u_char *)in6;
831 	int byte, bit, plen = 0, size = sizeof(struct in6_addr);
832 
833 	for (byte = 0; byte < size; byte++, plen += 8)
834 		if (nam[byte] != 0xff)
835 			break;
836 	if (byte == size)
837 		return (plen);
838 	for (bit = 7; bit != 0; bit--, plen++)
839 		if (!(nam[byte] & (1 << bit)))
840 			break;
841 	for (; bit != 0; bit--)
842 		if (nam[byte] & (1 << bit))
843 			return (0);
844 	byte++;
845 	for (; byte < size; byte++)
846 		if (nam[byte])
847 			return (0);
848 	return (plen);
849 }
850 
851 void
852 get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf
853     *autoprefix)
854 {
855 	struct in6_ifreq	 ifr6;
856 	struct ifaddrs		*ifap, *ifa;
857 	struct sockaddr_in6	*sin6;
858 	int			 prefixlen;
859 
860 	log_debug("%s: %s", __func__, ra_iface->name);
861 
862 	if (getifaddrs(&ifap) != 0)
863 		fatal("getifaddrs");
864 
865 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
866 		if (strcmp(ra_iface->name, ifa->ifa_name) != 0)
867 			continue;
868 		if (ifa->ifa_addr->sa_family != AF_INET6)
869 			continue;
870 
871 		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
872 
873 		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
874 			continue;
875 
876 		memset(&ifr6, 0, sizeof(ifr6));
877 		(void) strlcpy(ifr6.ifr_name, ra_iface->name,
878 		    sizeof(ifr6.ifr_name));
879 		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
880 
881 		if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0)
882 			continue; /* addr got deleted while we were looking */
883 
884 		prefixlen = in6_mask2prefixlen(&((struct sockaddr_in6 *)
885 		    &ifr6.ifr_addr)->sin6_addr);
886 
887 		if (prefixlen == 128)
888 			continue;
889 
890 		mask_prefix(&sin6->sin6_addr, prefixlen);
891 
892 		add_new_prefix_to_ra_iface(ra_iface, &sin6->sin6_addr,
893 		    prefixlen, autoprefix);
894 	}
895 	freeifaddrs(ifap);
896 }
897 
898 struct ra_prefix_conf*
899 find_ra_prefix_conf(struct ra_prefix_conf_head* head, struct in6_addr *prefix,
900     int prefixlen)
901 {
902 	struct ra_prefix_conf	*ra_prefix_conf;
903 
904 	SIMPLEQ_FOREACH(ra_prefix_conf, head, entry) {
905 		if (ra_prefix_conf->prefixlen == prefixlen &&
906 		    memcmp(&ra_prefix_conf->prefix, prefix, sizeof(*prefix)) ==
907 		    0)
908 			return (ra_prefix_conf);
909 	}
910 	return (NULL);
911 }
912 
913 void
914 add_new_prefix_to_ra_iface(struct ra_iface *ra_iface, struct in6_addr *addr,
915     int prefixlen, struct ra_prefix_conf *ra_prefix_conf)
916 {
917 	struct ra_prefix_conf	*new_ra_prefix_conf;
918 
919 	if (find_ra_prefix_conf(&ra_iface->prefixes, addr, prefixlen)) {
920 		log_debug("ignoring duplicate %s/%d prefix",
921 		    in6_to_str(addr), prefixlen);
922 		return;
923 	}
924 
925 	log_debug("adding %s/%d prefix", in6_to_str(addr), prefixlen);
926 
927 	if ((new_ra_prefix_conf = calloc(1, sizeof(*ra_prefix_conf))) == NULL)
928 		fatal("%s", __func__);
929 	new_ra_prefix_conf->prefix = *addr;
930 	new_ra_prefix_conf->prefixlen = prefixlen;
931 	new_ra_prefix_conf->vltime = ra_prefix_conf->vltime;
932 	new_ra_prefix_conf->pltime = ra_prefix_conf->pltime;
933 	new_ra_prefix_conf->aflag = ra_prefix_conf->aflag;
934 	new_ra_prefix_conf->lflag = ra_prefix_conf->lflag;
935 	SIMPLEQ_INSERT_TAIL(&ra_iface->prefixes, new_ra_prefix_conf, entry);
936 	ra_iface->prefix_count++;
937 }
938 
939 void
940 build_packet(struct ra_iface *ra_iface)
941 {
942 	struct nd_router_advert		*ra;
943 	struct nd_opt_mtu		*ndopt_mtu;
944 	struct nd_opt_prefix_info	*ndopt_pi;
945 	struct ra_iface_conf		*ra_iface_conf;
946 	struct ra_options_conf		*ra_options_conf;
947 	struct ra_prefix_conf		*ra_prefix_conf;
948 	struct nd_opt_rdnss		*ndopt_rdnss;
949 	struct nd_opt_dnssl		*ndopt_dnssl;
950 	struct ra_rdnss_conf		*ra_rdnss;
951 	struct ra_dnssl_conf		*ra_dnssl;
952 	size_t				 len, label_len;
953 	uint8_t				*p, buf[RA_MAX_SIZE];
954 	char				*label_start, *label_end;
955 
956 	ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
957 	    ra_iface->conf_name);
958 	ra_options_conf = &ra_iface_conf->ra_options;
959 
960 	len = sizeof(*ra);
961 	if (ra_options_conf->mtu > 0)
962 		len += sizeof(*ndopt_mtu);
963 	len += sizeof(*ndopt_pi) * ra_iface->prefix_count;
964 	if (ra_iface_conf->ra_options.rdnss_count > 0)
965 		len += sizeof(*ndopt_rdnss) +
966 		    ra_iface_conf->ra_options.rdnss_count *
967 		    sizeof(struct in6_addr);
968 
969 	if (ra_iface_conf->ra_options.dnssl_len > 0)
970 		/* round up to 8 byte boundary */
971 		len += sizeof(*ndopt_dnssl) +
972 		    ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7);
973 
974 	if (len > sizeof(ra_iface->data))
975 		fatal("%s: packet too big", __func__); /* XXX send multiple */
976 
977 	p = buf;
978 
979 	ra = (struct nd_router_advert *)p;
980 
981 	memset(ra, 0, sizeof(*ra));
982 
983 	ra->nd_ra_type = ND_ROUTER_ADVERT;
984 	ra->nd_ra_curhoplimit = ra_options_conf->cur_hl;
985 	if (ra_options_conf->m_flag)
986 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
987 	if (ra_options_conf->o_flag)
988 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
989 	if (ra_iface->removed)
990 		/* tell clients that we are no longer a default router */
991 		ra->nd_ra_router_lifetime = 0;
992 	else if (ra_options_conf->dfr) {
993 		ra->nd_ra_router_lifetime =
994 		    htons(ra_options_conf->router_lifetime);
995 	}
996 	ra->nd_ra_reachable = htonl(ra_options_conf->reachable_time);
997 	ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer);
998 	p += sizeof(*ra);
999 
1000 	if (ra_options_conf->mtu > 0) {
1001 		ndopt_mtu = (struct nd_opt_mtu *)p;
1002 		ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
1003 		ndopt_mtu->nd_opt_mtu_len = 1;
1004 		ndopt_mtu->nd_opt_mtu_reserved = 0;
1005 		ndopt_mtu->nd_opt_mtu_mtu = htonl(ra_options_conf->mtu);
1006 		p += sizeof(*ndopt_mtu);
1007 	}
1008 
1009 	SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface->prefixes, entry) {
1010 		ndopt_pi = (struct nd_opt_prefix_info *)p;
1011 		memset(ndopt_pi, 0, sizeof(*ndopt_pi));
1012 		ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
1013 		ndopt_pi->nd_opt_pi_len = 4;
1014 		ndopt_pi->nd_opt_pi_prefix_len = ra_prefix_conf->prefixlen;
1015 		if (ra_prefix_conf->lflag)
1016 			ndopt_pi->nd_opt_pi_flags_reserved |=
1017 			    ND_OPT_PI_FLAG_ONLINK;
1018 		if (ra_prefix_conf->aflag)
1019 			ndopt_pi->nd_opt_pi_flags_reserved |=
1020 			    ND_OPT_PI_FLAG_AUTO;
1021 		ndopt_pi->nd_opt_pi_valid_time = htonl(ra_prefix_conf->vltime);
1022 		ndopt_pi->nd_opt_pi_preferred_time =
1023 		    htonl(ra_prefix_conf->pltime);
1024 		ndopt_pi->nd_opt_pi_prefix = ra_prefix_conf->prefix;
1025 
1026 		p += sizeof(*ndopt_pi);
1027 	}
1028 
1029 	if (ra_iface_conf->ra_options.rdnss_count > 0) {
1030 		ndopt_rdnss = (struct nd_opt_rdnss *)p;
1031 		ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
1032 		ndopt_rdnss->nd_opt_rdnss_len = 1 +
1033 		    ra_iface_conf->ra_options.rdnss_count * 2;
1034 		ndopt_rdnss->nd_opt_rdnss_reserved = 0;
1035 		ndopt_rdnss->nd_opt_rdnss_lifetime =
1036 		    htonl(ra_iface_conf->ra_options.rdns_lifetime);
1037 		p += sizeof(struct nd_opt_rdnss);
1038 		SIMPLEQ_FOREACH(ra_rdnss,
1039 		    &ra_iface_conf->ra_options.ra_rdnss_list, entry) {
1040 			memcpy(p, &ra_rdnss->rdnss, sizeof(ra_rdnss->rdnss));
1041 			p += sizeof(ra_rdnss->rdnss);
1042 		}
1043 	}
1044 
1045 	if (ra_iface_conf->ra_options.dnssl_len > 0) {
1046 		ndopt_dnssl = (struct nd_opt_dnssl *)p;
1047 		ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
1048 		/* round up to 8 byte boundary */
1049 		ndopt_dnssl->nd_opt_dnssl_len = 1 +
1050 		    ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7) / 8;
1051 		ndopt_dnssl->nd_opt_dnssl_reserved = 0;
1052 		ndopt_dnssl->nd_opt_dnssl_lifetime =
1053 		    htonl(ra_iface_conf->ra_options.rdns_lifetime);
1054 		p += sizeof(struct nd_opt_dnssl);
1055 
1056 		SIMPLEQ_FOREACH(ra_dnssl,
1057 		    &ra_iface_conf->ra_options.ra_dnssl_list, entry) {
1058 			label_start = ra_dnssl->search;
1059 			while ((label_end = strchr(label_start, '.')) != NULL) {
1060 				label_len = label_end - label_start;
1061 				*p++ = label_len;
1062 				memcpy(p, label_start, label_len);
1063 				p += label_len;
1064 				label_start = label_end + 1;
1065 			}
1066 			*p++ = '\0'; /* last dot */
1067 		}
1068 		/* zero pad */
1069 		while (((uintptr_t)p) % 8 != 0)
1070 			*p++ = '\0';
1071 	}
1072 
1073 	if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len)
1074 	    != 0) {
1075 		memcpy(ra_iface->data, buf, len);
1076 		ra_iface->datalen = len;
1077 		/* packet changed; tell engine to send new advertisments */
1078 		frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0,
1079 		    &ra_iface->if_index, sizeof(ra_iface->if_index));
1080 	}
1081 }
1082 
1083 void
1084 build_leaving_packet(struct ra_iface *ra_iface)
1085 {
1086 	struct nd_router_advert		 ra;
1087 	size_t				 len;
1088 
1089 	len = sizeof(ra);
1090 
1091 	memset(&ra, 0, sizeof(ra));
1092 
1093 	ra.nd_ra_type = ND_ROUTER_ADVERT;
1094 
1095 	memcpy(ra_iface->data, &ra, sizeof(ra));
1096 	ra_iface->datalen = sizeof(ra);
1097 }
1098 
1099 void
1100 ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
1101 {
1102 
1103 	struct cmsghdr		*cm;
1104 	struct in6_pktinfo	*pi;
1105 	ssize_t			 len;
1106 	int			 hoplimit = 255;
1107 
1108 	sndmhdr.msg_name = to;
1109 	sndmhdr.msg_iov[0].iov_base = ra_iface->data;
1110 	sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;
1111 
1112 	cm = CMSG_FIRSTHDR(&sndmhdr);
1113 	/* specify the outgoing interface */
1114 	cm->cmsg_level = IPPROTO_IPV6;
1115 	cm->cmsg_type = IPV6_PKTINFO;
1116 	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1117 	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1118 	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
1119 	pi->ipi6_ifindex = ra_iface->if_index;
1120 
1121 	/* specify the hop limit of the packet */
1122 	cm = CMSG_NXTHDR(&sndmhdr, cm);
1123 	cm->cmsg_level = IPPROTO_IPV6;
1124 	cm->cmsg_type = IPV6_HOPLIMIT;
1125 	cm->cmsg_len = CMSG_LEN(sizeof(int));
1126 	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
1127 
1128 	log_debug("send RA on %s", ra_iface->name);
1129 
1130 	len = sendmsg(icmp6sock, &sndmhdr, 0);
1131 	if (len < 0)
1132 		log_warn("sendmsg on %s", ra_iface->name);
1133 
1134 }
1135 
1136 #define ROUNDUP(a) \
1137 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1138 
1139 void
1140 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1141 {
1142 	int	i;
1143 
1144 	for (i = 0; i < RTAX_MAX; i++) {
1145 		if (addrs & (1 << i)) {
1146 			rti_info[i] = sa;
1147 			sa = (struct sockaddr *)((char *)(sa) +
1148 			    ROUNDUP(sa->sa_len));
1149 		} else
1150 			rti_info[i] = NULL;
1151 	}
1152 }
1153 
1154 void
1155 route_receive(int fd, short events, void *arg)
1156 {
1157 	static uint8_t			 *buf;
1158 
1159 	struct rt_msghdr		*rtm;
1160 	struct sockaddr			*sa, *rti_info[RTAX_MAX];
1161 	ssize_t				 n;
1162 
1163 	if (buf == NULL) {
1164 		buf = malloc(ROUTE_SOCKET_BUF_SIZE);
1165 		if (buf == NULL)
1166 			fatal("malloc");
1167 	}
1168 	rtm = (struct rt_msghdr *)buf;
1169 	if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
1170 		if (errno == EAGAIN || errno == EINTR)
1171 			return;
1172 		log_warn("dispatch_rtmsg: read error");
1173 		return;
1174 	}
1175 
1176 	if (n == 0)
1177 		fatal("routing socket closed");
1178 
1179 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
1180 		log_warnx("partial rtm of %zd in buffer", n);
1181 		return;
1182 	}
1183 
1184 	if (rtm->rtm_version != RTM_VERSION)
1185 		return;
1186 
1187 	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
1188 	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1189 
1190 	handle_route_message(rtm, rti_info);
1191 }
1192 
1193 void
1194 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
1195 {
1196 	switch (rtm->rtm_type) {
1197 	case RTM_IFINFO:
1198 	case RTM_NEWADDR:
1199 	case RTM_DELADDR:
1200 		/*
1201 		 * do the same thing as after a config reload when interfaces
1202 		 * change or IPv6 addresses show up / disappear
1203 		 */
1204 		merge_ra_interfaces();
1205 		break;
1206 	default:
1207 		log_debug("unexpected RTM: %d", rtm->rtm_type);
1208 		break;
1209 	}
1210 }
1211