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