xref: /openbsd-src/sbin/slaacd/frontend.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*	$OpenBSD: frontend.c,v 1.64 2022/07/12 16:54:59 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2017 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 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/syslog.h>
26 #include <sys/uio.h>
27 
28 #include <net/if.h>
29 #include <net/if_dl.h>
30 #include <net/if_types.h>
31 #include <net/route.h>
32 
33 #include <arpa/inet.h>
34 
35 #include <netinet/in.h>
36 #include <netinet/if_ether.h>
37 #include <netinet6/nd6.h>
38 #include <netinet6/in6_var.h>
39 #include <netinet/ip6.h>
40 #include <netinet6/ip6_var.h>
41 #include <netinet/icmp6.h>
42 
43 #include <errno.h>
44 #include <event.h>
45 #include <ifaddrs.h>
46 #include <imsg.h>
47 #include <pwd.h>
48 #include <signal.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 
54 #include "log.h"
55 #include "slaacd.h"
56 #include "frontend.h"
57 #include "control.h"
58 
59 #define	ROUTE_SOCKET_BUF_SIZE	16384
60 #define	ALLROUTER		"ff02::2"
61 
62 struct icmp6_ev {
63 	struct event		 ev;
64 	uint8_t			 answer[1500];
65 	struct msghdr		 rcvmhdr;
66 	struct iovec		 rcviov[1];
67 	struct sockaddr_in6	 from;
68 	int			 refcnt;
69 };
70 
71 struct iface {
72 	LIST_ENTRY(iface)	 entries;
73 	struct icmp6_ev		*icmp6ev;
74 	struct ether_addr	 hw_address;
75 	uint32_t		 if_index;
76 	int			 rdomain;
77 	int			 send_solicitation;
78 	int			 ll_tentative;
79 };
80 
81 __dead void	 frontend_shutdown(void);
82 void		 frontend_sig_handler(int, short, void *);
83 void		 update_iface(uint32_t, char*);
84 void		 frontend_startup(void);
85 void		 route_receive(int, short, void *);
86 void		 handle_route_message(struct rt_msghdr *, struct sockaddr **);
87 void		 get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
88 void		 icmp6_receive(int, short, void *);
89 int		 get_flags(char *);
90 int		 get_xflags(char *);
91 int		 get_ifrdomain(char *);
92 struct iface	*get_iface_by_id(uint32_t);
93 void		 remove_iface(uint32_t);
94 struct icmp6_ev	*get_icmp6ev_by_rdomain(int);
95 void		 unref_icmp6ev(struct iface *);
96 void		 set_icmp6sock(int, int);
97 void		 send_solicitation(uint32_t);
98 #ifndef	SMALL
99 const char	*flags_to_str(int);
100 #endif	/* SMALL */
101 
102 LIST_HEAD(, iface)		 interfaces;
103 static struct imsgev		*iev_main;
104 static struct imsgev		*iev_engine;
105 struct event			 ev_route;
106 struct msghdr			 sndmhdr;
107 struct iovec			 sndiov[4];
108 struct nd_router_solicit	 rs;
109 struct nd_opt_hdr		 nd_opt_hdr;
110 struct ether_addr		 nd_opt_source_link_addr;
111 struct sockaddr_in6		 dst;
112 int				 ioctlsock;
113 
114 void
115 frontend_sig_handler(int sig, short event, void *bula)
116 {
117 	/*
118 	 * Normal signal handler rules don't apply because libevent
119 	 * decouples for us.
120 	 */
121 
122 	switch (sig) {
123 	case SIGINT:
124 	case SIGTERM:
125 		frontend_shutdown();
126 	default:
127 		fatalx("unexpected signal");
128 	}
129 }
130 
131 void
132 frontend(int debug, int verbose)
133 {
134 	struct event		 ev_sigint, ev_sigterm;
135 	struct passwd		*pw;
136 	struct in6_pktinfo	*pi;
137 	struct cmsghdr		*cm;
138 	size_t			 sndcmsglen;
139 	int			 hoplimit = 255;
140 	uint8_t			*sndcmsgbuf;
141 
142 	log_init(debug, LOG_DAEMON);
143 	log_setverbose(verbose);
144 
145 	if ((pw = getpwnam(SLAACD_USER)) == NULL)
146 		fatal("getpwnam");
147 
148 	if (chdir("/") == -1)
149 		fatal("chdir(\"/\")");
150 
151 	if (unveil("/", "") == -1)
152 		fatal("unveil /");
153 	if (unveil(NULL, NULL) == -1)
154 		fatal("unveil");
155 
156 	setproctitle("%s", "frontend");
157 	log_procinit("frontend");
158 
159 	if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
160 		fatal("socket");
161 
162 	if (setgroups(1, &pw->pw_gid) ||
163 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
164 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
165 		fatal("can't drop privileges");
166 
167 	if (pledge("stdio unix recvfd route", NULL) == -1)
168 		fatal("pledge");
169 
170 	event_init();
171 
172 	/* Setup signal handler. */
173 	signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL);
174 	signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL);
175 	signal_add(&ev_sigint, NULL);
176 	signal_add(&ev_sigterm, NULL);
177 	signal(SIGPIPE, SIG_IGN);
178 	signal(SIGHUP, SIG_IGN);
179 
180 	/* Setup pipe and event handler to the parent process. */
181 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
182 		fatal(NULL);
183 	imsg_init(&iev_main->ibuf, 3);
184 	iev_main->handler = frontend_dispatch_main;
185 	iev_main->events = EV_READ;
186 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
187 	    iev_main->handler, iev_main);
188 	event_add(&iev_main->ev, NULL);
189 
190 	sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
191 	    CMSG_SPACE(sizeof(int));
192 
193 	if ((sndcmsgbuf = malloc(sndcmsglen)) == NULL)
194 		fatal("malloc");
195 
196 	rs.nd_rs_type = ND_ROUTER_SOLICIT;
197 	rs.nd_rs_code = 0;
198 	rs.nd_rs_cksum = 0;
199 	rs.nd_rs_reserved = 0;
200 
201 	nd_opt_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
202 	nd_opt_hdr.nd_opt_len = 1;
203 
204 	memset(&dst, 0, sizeof(dst));
205 	dst.sin6_family = AF_INET6;
206 	if (inet_pton(AF_INET6, ALLROUTER, &dst.sin6_addr.s6_addr) != 1)
207 		fatal("inet_pton");
208 
209 	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
210 	sndmhdr.msg_iov = sndiov;
211 	sndmhdr.msg_iovlen = 3;
212 	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
213 	sndmhdr.msg_controllen = sndcmsglen;
214 
215 	sndmhdr.msg_name = (caddr_t)&dst;
216 	sndmhdr.msg_iov[0].iov_base = (caddr_t)&rs;
217 	sndmhdr.msg_iov[0].iov_len = sizeof(rs);
218 	sndmhdr.msg_iov[1].iov_base = (caddr_t)&nd_opt_hdr;
219 	sndmhdr.msg_iov[1].iov_len = sizeof(nd_opt_hdr);
220 	sndmhdr.msg_iov[2].iov_base = (caddr_t)&nd_opt_source_link_addr;
221 	sndmhdr.msg_iov[2].iov_len = sizeof(nd_opt_source_link_addr);
222 
223 	cm = CMSG_FIRSTHDR(&sndmhdr);
224 
225 	cm->cmsg_level = IPPROTO_IPV6;
226 	cm->cmsg_type = IPV6_PKTINFO;
227 	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
228 	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
229 	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
230 	pi->ipi6_ifindex = 0;
231 
232 	cm = CMSG_NXTHDR(&sndmhdr, cm);
233 	cm->cmsg_level = IPPROTO_IPV6;
234 	cm->cmsg_type = IPV6_HOPLIMIT;
235 	cm->cmsg_len = CMSG_LEN(sizeof(int));
236 	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
237 
238 	LIST_INIT(&interfaces);
239 
240 	event_dispatch();
241 
242 	frontend_shutdown();
243 }
244 
245 __dead void
246 frontend_shutdown(void)
247 {
248 	/* Close pipes. */
249 	msgbuf_write(&iev_engine->ibuf.w);
250 	msgbuf_clear(&iev_engine->ibuf.w);
251 	close(iev_engine->ibuf.fd);
252 	msgbuf_write(&iev_main->ibuf.w);
253 	msgbuf_clear(&iev_main->ibuf.w);
254 	close(iev_main->ibuf.fd);
255 
256 	free(iev_engine);
257 	free(iev_main);
258 
259 	log_info("frontend exiting");
260 	exit(0);
261 }
262 
263 int
264 frontend_imsg_compose_main(int type, pid_t pid, void *data,
265     uint16_t datalen)
266 {
267 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
268 	    datalen));
269 }
270 
271 int
272 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid,
273     void *data, uint16_t datalen)
274 {
275 	return (imsg_compose_event(iev_engine, type, peerid, pid, -1,
276 	    data, datalen));
277 }
278 
279 void
280 frontend_dispatch_main(int fd, short event, void *bula)
281 {
282 	struct imsg		 imsg;
283 	struct imsgev		*iev = bula;
284 	struct imsgbuf		*ibuf = &iev->ibuf;
285 	ssize_t			 n;
286 	int			 shut = 0, icmp6sock, rdomain;
287 
288 	if (event & EV_READ) {
289 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
290 			fatal("imsg_read error");
291 		if (n == 0)	/* Connection closed. */
292 			shut = 1;
293 	}
294 	if (event & EV_WRITE) {
295 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
296 			fatal("msgbuf_write");
297 		if (n == 0)	/* Connection closed. */
298 			shut = 1;
299 	}
300 
301 	for (;;) {
302 		if ((n = imsg_get(ibuf, &imsg)) == -1)
303 			fatal("%s: imsg_get error", __func__);
304 		if (n == 0)	/* No more messages. */
305 			break;
306 
307 		switch (imsg.hdr.type) {
308 		case IMSG_SOCKET_IPC:
309 			/*
310 			 * Setup pipe and event handler to the engine
311 			 * process.
312 			 */
313 			if (iev_engine)
314 				fatalx("%s: received unexpected imsg fd "
315 				    "to frontend", __func__);
316 
317 			if ((fd = imsg.fd) == -1)
318 				fatalx("%s: expected to receive imsg fd to "
319 				   "frontend but didn't receive any",
320 				   __func__);
321 
322 			iev_engine = malloc(sizeof(struct imsgev));
323 			if (iev_engine == NULL)
324 				fatal(NULL);
325 
326 			imsg_init(&iev_engine->ibuf, fd);
327 			iev_engine->handler = frontend_dispatch_engine;
328 			iev_engine->events = EV_READ;
329 
330 			event_set(&iev_engine->ev, iev_engine->ibuf.fd,
331 			iev_engine->events, iev_engine->handler, iev_engine);
332 			event_add(&iev_engine->ev, NULL);
333 			break;
334 		case IMSG_ICMP6SOCK:
335 			if ((icmp6sock = imsg.fd) == -1)
336 				fatalx("%s: expected to receive imsg "
337 				    "ICMPv6 fd but didn't receive any",
338 				    __func__);
339 			if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain))
340 				fatalx("%s: IMSG_ICMP6SOCK wrong length: "
341 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
342 			memcpy(&rdomain, imsg.data, sizeof(rdomain));
343 			set_icmp6sock(icmp6sock, rdomain);
344 			break;
345 		case IMSG_ROUTESOCK:
346 			if ((fd = imsg.fd) == -1)
347 				fatalx("%s: expected to receive imsg "
348 				    "routesocket fd but didn't receive any",
349 				    __func__);
350 			event_set(&ev_route, fd, EV_READ | EV_PERSIST,
351 			    route_receive, NULL);
352 			break;
353 		case IMSG_STARTUP:
354 			frontend_startup();
355 			break;
356 #ifndef	SMALL
357 		case IMSG_CONTROLFD:
358 			if ((fd = imsg.fd) == -1)
359 				fatalx("%s: expected to receive imsg "
360 				    "control fd but didn't receive any",
361 				    __func__);
362 			/* Listen on control socket. */
363 			control_listen(fd);
364 			break;
365 		case IMSG_CTL_END:
366 			control_imsg_relay(&imsg);
367 			break;
368 #endif	/* SMALL */
369 		default:
370 			log_debug("%s: error handling imsg %d", __func__,
371 			    imsg.hdr.type);
372 			break;
373 		}
374 		imsg_free(&imsg);
375 	}
376 	if (!shut)
377 		imsg_event_add(iev);
378 	else {
379 		/* This pipe is dead. Remove its event handler. */
380 		event_del(&iev->ev);
381 		event_loopexit(NULL);
382 	}
383 }
384 
385 void
386 frontend_dispatch_engine(int fd, short event, void *bula)
387 {
388 	struct imsgev		*iev = bula;
389 	struct imsgbuf		*ibuf = &iev->ibuf;
390 	struct imsg		 imsg;
391 	ssize_t			 n;
392 	int			 shut = 0;
393 	uint32_t		 if_index;
394 
395 	if (event & EV_READ) {
396 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
397 			fatal("imsg_read error");
398 		if (n == 0)	/* Connection closed. */
399 			shut = 1;
400 	}
401 	if (event & EV_WRITE) {
402 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
403 			fatal("msgbuf_write");
404 		if (n == 0)	/* Connection closed. */
405 			shut = 1;
406 	}
407 
408 	for (;;) {
409 		if ((n = imsg_get(ibuf, &imsg)) == -1)
410 			fatal("%s: imsg_get error", __func__);
411 		if (n == 0)	/* No more messages. */
412 			break;
413 
414 		switch (imsg.hdr.type) {
415 #ifndef	SMALL
416 		case IMSG_CTL_END:
417 		case IMSG_CTL_SHOW_INTERFACE_INFO:
418 		case IMSG_CTL_SHOW_INTERFACE_INFO_RA:
419 		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX:
420 		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS:
421 		case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS:
422 		case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL:
423 		case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
424 		case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
425 		case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS:
426 		case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL:
427 			control_imsg_relay(&imsg);
428 			break;
429 #endif	/* SMALL */
430 		case IMSG_CTL_SEND_SOLICITATION:
431 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
432 				fatalx("%s: IMSG_CTL_SEND_SOLICITATION wrong "
433 				    "length: %lu", __func__,
434 				    IMSG_DATA_SIZE(imsg));
435 			if_index = *((uint32_t *)imsg.data);
436 			send_solicitation(if_index);
437 			break;
438 		default:
439 			log_debug("%s: error handling imsg %d", __func__,
440 			    imsg.hdr.type);
441 			break;
442 		}
443 		imsg_free(&imsg);
444 	}
445 	if (!shut)
446 		imsg_event_add(iev);
447 	else {
448 		/* This pipe is dead. Remove its event handler. */
449 		event_del(&iev->ev);
450 		event_loopexit(NULL);
451 	}
452 }
453 
454 int
455 get_flags(char *if_name)
456 {
457 	struct ifreq		 ifr;
458 
459 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
460 	if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
461 		log_warn("SIOCGIFFLAGS");
462 		return -1;
463 	}
464 	return ifr.ifr_flags;
465 }
466 
467 int
468 get_xflags(char *if_name)
469 {
470 	struct ifreq		 ifr;
471 
472 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
473 	if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) {
474 		log_warn("SIOCGIFXFLAGS");
475 		return -1;
476 	}
477 	return ifr.ifr_flags;
478 }
479 
480 int
481 get_ifrdomain(char *if_name)
482 {
483 	struct ifreq		 ifr;
484 
485 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
486 	if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) {
487 		log_warn("SIOCGIFRDOMAIN");
488 		return -1;
489 	}
490 	return ifr.ifr_rdomainid;
491 }
492 
493 void
494 update_iface(uint32_t if_index, char* if_name)
495 {
496 	struct iface		*iface;
497 	struct ifaddrs		*ifap, *ifa;
498 	struct imsg_ifinfo	 imsg_ifinfo;
499 	struct sockaddr_dl	*sdl;
500 	struct sockaddr_in6	*sin6;
501 	struct in6_ifreq	 ifr6;
502 	int			 flags, xflags, ifrdomain;
503 
504 	if ((flags = get_flags(if_name)) == -1 || (xflags =
505 	    get_xflags(if_name)) == -1)
506 		return;
507 
508 	if (!(xflags & (IFXF_AUTOCONF6 | IFXF_AUTOCONF6TEMP)))
509 		return;
510 
511 	if((ifrdomain = get_ifrdomain(if_name)) == -1)
512 		return;
513 
514 	iface = get_iface_by_id(if_index);
515 
516 	if (iface != NULL) {
517 		if (iface->rdomain != ifrdomain) {
518 			unref_icmp6ev(iface);
519 			iface->rdomain = ifrdomain;
520 			iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain);
521 		}
522 	} else {
523 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
524 			fatal("calloc");
525 		iface->if_index = if_index;
526 		iface->rdomain = ifrdomain;
527 		iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain);
528 		iface->ll_tentative = 1;
529 
530 		LIST_INSERT_HEAD(&interfaces, iface, entries);
531 	}
532 
533 	memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo));
534 
535 	imsg_ifinfo.if_index = if_index;
536 	imsg_ifinfo.rdomain = ifrdomain;
537 	imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP |
538 	    IFF_RUNNING);
539 	imsg_ifinfo.autoconf = (xflags & IFXF_AUTOCONF6);
540 	imsg_ifinfo.temporary = (xflags & IFXF_AUTOCONF6TEMP);
541 	imsg_ifinfo.soii = !(xflags & IFXF_INET6_NOSOII);
542 
543 	if (getifaddrs(&ifap) != 0)
544 		fatal("getifaddrs");
545 
546 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
547 		if (strcmp(if_name, ifa->ifa_name) != 0)
548 			continue;
549 		if (ifa->ifa_addr == NULL)
550 			continue;
551 
552 		switch(ifa->ifa_addr->sa_family) {
553 		case AF_LINK:
554 			imsg_ifinfo.link_state =
555 			    ((struct if_data *)ifa->ifa_data)->ifi_link_state;
556 			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
557 			if (sdl->sdl_type != IFT_ETHER ||
558 			    sdl->sdl_alen != ETHER_ADDR_LEN)
559 				continue;
560 			memcpy(iface->hw_address.ether_addr_octet,
561 			    LLADDR(sdl), ETHER_ADDR_LEN);
562 			memcpy(imsg_ifinfo.hw_address.ether_addr_octet,
563 			    LLADDR(sdl), ETHER_ADDR_LEN);
564 		case AF_INET6:
565 			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
566 #ifdef __KAME__
567 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
568 			    sin6->sin6_scope_id == 0) {
569 				sin6->sin6_scope_id = ntohs(*(u_int16_t *)
570 				    &sin6->sin6_addr.s6_addr[2]);
571 				sin6->sin6_addr.s6_addr[2] =
572 				    sin6->sin6_addr.s6_addr[3] = 0;
573 			}
574 #endif
575 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
576 				memcpy(&imsg_ifinfo.ll_address, sin6,
577 				    sizeof(imsg_ifinfo.ll_address));
578 
579 				if (!iface->ll_tentative)
580 					break;
581 
582 				memset(&ifr6, 0, sizeof(ifr6));
583 				strlcpy(ifr6.ifr_name, if_name,
584 				    sizeof(ifr6.ifr_name));
585 				memcpy(&ifr6.ifr_addr, sin6,
586 				    sizeof(ifr6.ifr_addr));
587 
588 				if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6,
589 				    (caddr_t)&ifr6) == -1) {
590 					log_warn("SIOCGIFAFLAG_IN6");
591 					break;
592 				}
593 
594 				if (!(ifr6.ifr_ifru.ifru_flags6 &
595 				    IN6_IFF_TENTATIVE)) {
596 					iface->ll_tentative = 0;
597 					if (iface->send_solicitation)
598 						send_solicitation(
599 						    iface->if_index);
600 				}
601 			}
602 			break;
603 		default:
604 			break;
605 		}
606 	}
607 
608 	freeifaddrs(ifap);
609 
610 	frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo,
611 	    sizeof(imsg_ifinfo));
612 }
613 
614 #ifndef	SMALL
615 const char*
616 flags_to_str(int flags)
617 {
618 	static char	buf[sizeof(" anycast tentative duplicated detached "
619 			    "deprecated autoconf temporary")];
620 
621 	buf[0] = '\0';
622 	if (flags & IN6_IFF_ANYCAST)
623 		strlcat(buf, " anycast", sizeof(buf));
624 	if (flags & IN6_IFF_TENTATIVE)
625 		strlcat(buf, " tentative", sizeof(buf));
626 	if (flags & IN6_IFF_DUPLICATED)
627 		strlcat(buf, " duplicated", sizeof(buf));
628 	if (flags & IN6_IFF_DETACHED)
629 		strlcat(buf, " detached", sizeof(buf));
630 	if (flags & IN6_IFF_DEPRECATED)
631 		strlcat(buf, " deprecated", sizeof(buf));
632 	if (flags & IN6_IFF_AUTOCONF)
633 		strlcat(buf, " autoconf", sizeof(buf));
634 	if (flags & IN6_IFF_TEMPORARY)
635 		strlcat(buf, " temporary", sizeof(buf));
636 
637 	return (buf);
638 }
639 #endif	/* SMALL */
640 
641 void
642 frontend_startup(void)
643 {
644 	struct if_nameindex	*ifnidxp, *ifnidx;
645 
646 	if (!event_initialized(&ev_route))
647 		fatalx("%s: did not receive a route socket from the main "
648 		    "process", __func__);
649 
650 	event_add(&ev_route, NULL);
651 
652 	if ((ifnidxp = if_nameindex()) == NULL)
653 		fatalx("if_nameindex");
654 
655 	for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL;
656 	    ifnidx++)
657 		update_iface(ifnidx->if_index, ifnidx->if_name);
658 
659 	if_freenameindex(ifnidxp);
660 }
661 
662 void
663 route_receive(int fd, short events, void *arg)
664 {
665 	static uint8_t			 *buf;
666 
667 	struct rt_msghdr		*rtm;
668 	struct sockaddr			*sa, *rti_info[RTAX_MAX];
669 	ssize_t				 n;
670 
671 	if (buf == NULL) {
672 		buf = malloc(ROUTE_SOCKET_BUF_SIZE);
673 		if (buf == NULL)
674 			fatal("malloc");
675 	}
676 	rtm = (struct rt_msghdr *)buf;
677 	if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
678 		if (errno == EAGAIN || errno == EINTR)
679 			return;
680 		log_warn("dispatch_rtmsg: read error");
681 		return;
682 	}
683 
684 	if (n == 0)
685 		fatal("routing socket closed");
686 
687 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
688 		log_warnx("partial rtm of %zd in buffer", n);
689 		return;
690 	}
691 
692 	if (rtm->rtm_version != RTM_VERSION)
693 		return;
694 
695 	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
696 	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
697 
698 	handle_route_message(rtm, rti_info);
699 }
700 
701 void
702 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
703 {
704 	struct if_msghdr		*ifm;
705 	struct if_announcemsghdr	*ifan;
706 	struct imsg_del_addr		 del_addr;
707 	struct imsg_del_route		 del_route;
708 	struct imsg_dup_addr		 dup_addr;
709 	struct sockaddr_rtlabel		*rl;
710 	struct sockaddr_in6		*sin6;
711 	struct in6_ifreq		 ifr6;
712 	struct in6_addr			*in6;
713 	int				 xflags, if_index;
714 	char				 ifnamebuf[IFNAMSIZ];
715 	char				*if_name;
716 
717 	switch (rtm->rtm_type) {
718 	case RTM_IFINFO:
719 		ifm = (struct if_msghdr *)rtm;
720 		if_index = ifm->ifm_index;
721 		if_name = if_indextoname(if_index, ifnamebuf);
722 		if (if_name == NULL) {
723 			log_debug("RTM_IFINFO: lost if %d", if_index);
724 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
725 			    &if_index, sizeof(if_index));
726 			remove_iface(if_index);
727 			break;
728 		}
729 		xflags = get_xflags(if_name);
730 		if (xflags == -1 || !(xflags & (IFXF_AUTOCONF6 |
731 		    IFXF_AUTOCONF6TEMP))) {
732 			log_debug("RTM_IFINFO: %s(%d) no(longer) autoconf6",
733 			    if_name, if_index);
734 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
735 			    0, &if_index, sizeof(if_index));
736 			remove_iface(if_index);
737 		} else {
738 			update_iface(if_index, if_name);
739 		}
740 		break;
741 	case RTM_IFANNOUNCE:
742 		ifan = (struct if_announcemsghdr *)rtm;
743 		if_index = ifan->ifan_index;
744                 if (ifan->ifan_what == IFAN_DEPARTURE) {
745 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
746 			    &if_index, sizeof(if_index));
747 			remove_iface(if_index);
748 		}
749 		break;
750 	case RTM_NEWADDR:
751 		ifm = (struct if_msghdr *)rtm;
752 		if_index = ifm->ifm_index;
753 		if_name = if_indextoname(if_index, ifnamebuf);
754 		if (if_name == NULL) {
755 			log_debug("RTM_NEWADDR: lost if %d", if_index);
756 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
757 			    &if_index, sizeof(if_index));
758 			remove_iface(if_index);
759 			break;
760 		}
761 
762 		log_debug("RTM_NEWADDR: %s[%u]", if_name, if_index);
763 		update_iface(if_index, if_name);
764 		break;
765 	case RTM_DELADDR:
766 		ifm = (struct if_msghdr *)rtm;
767 		if_index = ifm->ifm_index;
768 		if_name = if_indextoname(if_index, ifnamebuf);
769 		if (if_name == NULL) {
770 			log_debug("RTM_DELADDR: lost if %d", if_index);
771 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
772 			    &if_index, sizeof(if_index));
773 			remove_iface(if_index);
774 			break;
775 		}
776 		if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family
777 		    == AF_INET6) {
778 			del_addr.if_index = if_index;
779 			memcpy(&del_addr.addr, rti_info[RTAX_IFA], sizeof(
780 			    del_addr.addr));
781 			frontend_imsg_compose_engine(IMSG_DEL_ADDRESS,
782 				    0, 0, &del_addr, sizeof(del_addr));
783 			log_debug("RTM_DELADDR: %s[%u]", if_name, if_index);
784 		}
785 		break;
786 	case RTM_CHGADDRATTR:
787 		ifm = (struct if_msghdr *)rtm;
788 		if_index = ifm->ifm_index;
789 		if_name = if_indextoname(if_index, ifnamebuf);
790 		if (if_name == NULL) {
791 			log_debug("RTM_CHGADDRATTR: lost if %d", if_index);
792 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
793 			    &if_index, sizeof(if_index));
794 			remove_iface(if_index);
795 			break;
796 		}
797 		if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family
798 		    == AF_INET6) {
799 			sin6 = (struct sockaddr_in6 *) rti_info[RTAX_IFA];
800 
801 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
802 				update_iface(if_index, if_name);
803 				break;
804 			}
805 
806 			memset(&ifr6, 0, sizeof(ifr6));
807 			strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
808 			memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
809 
810 			if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6)
811 			    == -1) {
812 				log_warn("SIOCGIFAFLAG_IN6");
813 				break;
814 			}
815 
816 #ifndef	SMALL
817 			log_debug("RTM_CHGADDRATTR: %s - %s",
818 			    sin6_to_str(sin6),
819 			    flags_to_str(ifr6.ifr_ifru.ifru_flags6));
820 #endif	/* SMALL */
821 
822 			if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) {
823 				dup_addr.if_index = if_index;
824 				dup_addr.addr = *sin6;
825 				frontend_imsg_compose_engine(IMSG_DUP_ADDRESS,
826 				    0, 0, &dup_addr, sizeof(dup_addr));
827 			}
828 
829 		}
830 		break;
831 	case RTM_DELETE:
832 		ifm = (struct if_msghdr *)rtm;
833 		if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_LABEL)) !=
834 		    (RTA_DST | RTA_GATEWAY | RTA_LABEL))
835 			break;
836 		if (rti_info[RTAX_DST]->sa_family != AF_INET6)
837 			break;
838 		if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)
839 		    rti_info[RTAX_DST])->sin6_addr))
840 			break;
841 		if (rti_info[RTAX_GATEWAY]->sa_family != AF_INET6)
842 			break;
843 		if (rti_info[RTAX_LABEL]->sa_len !=
844 		    sizeof(struct sockaddr_rtlabel))
845 			break;
846 
847 		rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
848 		if (strcmp(rl->sr_label, SLAACD_RTA_LABEL) != 0)
849 			break;
850 		if_index = ifm->ifm_index;
851 		if_name = if_indextoname(if_index, ifnamebuf);
852 		if (if_name == NULL) {
853 			log_debug("RTM_DELETE: lost if %d", if_index);
854 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
855 			    &if_index, sizeof(if_index));
856 			remove_iface(if_index);
857 			break;
858 		}
859 
860 		del_route.if_index = if_index;
861 		memcpy(&del_route.gw, rti_info[RTAX_GATEWAY],
862 		    sizeof(del_route.gw));
863 		in6 = &del_route.gw.sin6_addr;
864 #ifdef __KAME__
865 		/* XXX from route(8) p_sockaddr() */
866 		if ((IN6_IS_ADDR_LINKLOCAL(in6) ||
867 		    IN6_IS_ADDR_MC_LINKLOCAL(in6) ||
868 		    IN6_IS_ADDR_MC_INTFACELOCAL(in6)) &&
869 		    del_route.gw.sin6_scope_id == 0) {
870 			del_route.gw.sin6_scope_id =
871 			    (u_int32_t)ntohs(*(u_short *) &in6->s6_addr[2]);
872 			*(u_short *)&in6->s6_addr[2] = 0;
873 		}
874 #endif
875 		frontend_imsg_compose_engine(IMSG_DEL_ROUTE,
876 		    0, 0, &del_route, sizeof(del_route));
877 		log_debug("RTM_DELETE: %s[%u]", if_name,
878 		    ifm->ifm_index);
879 
880 		break;
881 #ifndef	SMALL
882 	case RTM_PROPOSAL:
883 		if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) {
884 			log_debug("RTP_PROPOSAL_SOLICIT");
885 			frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS,
886 			    0, 0, NULL, 0);
887 		}
888 		break;
889 #endif	/* SMALL */
890 	default:
891 		log_debug("unexpected RTM: %d", rtm->rtm_type);
892 		break;
893 	}
894 
895 }
896 
897 #define ROUNDUP(a) \
898 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
899 
900 void
901 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
902 {
903 	int	i;
904 
905 	for (i = 0; i < RTAX_MAX; i++) {
906 		if (addrs & (1 << i)) {
907 			rti_info[i] = sa;
908 			sa = (struct sockaddr *)((char *)(sa) +
909 			    ROUNDUP(sa->sa_len));
910 		} else
911 			rti_info[i] = NULL;
912 	}
913 }
914 
915 void
916 icmp6_receive(int fd, short events, void *arg)
917 {
918 	struct imsg_ra		 ra;
919 	struct icmp6_hdr	*icmp6_hdr;
920 	struct icmp6_ev		*icmp6ev;
921 	struct in6_pktinfo	*pi = NULL;
922 	struct cmsghdr		*cm;
923 	ssize_t			 len;
924 	int			 if_index = 0, *hlimp = NULL;
925 	char			 ntopbuf[INET6_ADDRSTRLEN];
926 #ifndef SMALL
927 	char			 ifnamebuf[IFNAMSIZ];
928 #endif	/* SMALL */
929 
930 	icmp6ev = arg;
931 	if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) {
932 		log_warn("recvmsg");
933 		return;
934 	}
935 
936 	if ((size_t)len < sizeof(struct icmp6_hdr))
937 		return;
938 
939 	icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer;
940 	if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT)
941 		return;
942 
943 	/* extract optional information via Advanced API */
944 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm;
945 	    cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) {
946 		if (cm->cmsg_level == IPPROTO_IPV6 &&
947 		    cm->cmsg_type == IPV6_PKTINFO &&
948 		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
949 			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
950 			if_index = pi->ipi6_ifindex;
951 		}
952 		if (cm->cmsg_level == IPPROTO_IPV6 &&
953 		    cm->cmsg_type == IPV6_HOPLIMIT &&
954 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
955 			hlimp = (int *)CMSG_DATA(cm);
956 	}
957 
958 	if (if_index == 0) {
959 		log_warnx("failed to get receiving interface");
960 		return;
961 	}
962 
963 	if (hlimp == NULL) {
964 		log_warnx("failed to get receiving hop limit");
965 		return;
966 	}
967 
968 	if (*hlimp != 255) {
969 		log_warnx("invalid RA with hop limit of %d from %s on %s",
970 		    *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr,
971 		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
972 		    ifnamebuf));
973 		return;
974 	}
975 
976 	if ((size_t)len > sizeof(ra.packet)) {
977 		log_warnx("invalid RA with size %ld from %s on %s",
978 		    len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr,
979 		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
980 		    ifnamebuf));
981 		return;
982 	}
983 	ra.if_index = if_index;
984 	memcpy(&ra.from,  &icmp6ev->from, sizeof(ra.from));
985 	ra.len = len;
986 	memcpy(ra.packet, icmp6ev->answer, len);
987 
988 	frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra));
989 }
990 
991 void
992 send_solicitation(uint32_t if_index)
993 {
994 	struct in6_pktinfo	*pi;
995 	struct cmsghdr		*cm;
996 	struct iface		*iface;
997 
998 	log_debug("%s(%u)", __func__, if_index);
999 
1000 	if ((iface = get_iface_by_id(if_index)) == NULL)
1001 		return;
1002 
1003 	if (!event_initialized(&iface->icmp6ev->ev)) {
1004 		iface->send_solicitation = 1;
1005 		return;
1006 	} else if (iface->ll_tentative) {
1007 		iface->send_solicitation = 1;
1008 		return;
1009 	}
1010 
1011 	iface->send_solicitation = 0;
1012 
1013 	dst.sin6_scope_id = if_index;
1014 
1015 	cm = CMSG_FIRSTHDR(&sndmhdr);
1016 	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
1017 	pi->ipi6_ifindex = if_index;
1018 
1019 	memcpy(&nd_opt_source_link_addr, &iface->hw_address,
1020 	    sizeof(nd_opt_source_link_addr));
1021 
1022 	if (sendmsg(EVENT_FD(&iface->icmp6ev->ev), &sndmhdr, 0) != sizeof(rs) +
1023 	    sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr))
1024 		log_warn("sendmsg");
1025 }
1026 
1027 struct iface*
1028 get_iface_by_id(uint32_t if_index)
1029 {
1030 	struct iface	*iface;
1031 
1032 	LIST_FOREACH (iface, &interfaces, entries) {
1033 		if (iface->if_index == if_index)
1034 			return (iface);
1035 	}
1036 
1037 	return (NULL);
1038 }
1039 
1040 void
1041 remove_iface(uint32_t if_index)
1042 {
1043 	struct iface	*iface;
1044 
1045 	iface = get_iface_by_id(if_index);
1046 
1047 	if (iface == NULL)
1048 		return;
1049 
1050 	LIST_REMOVE(iface, entries);
1051 
1052 	unref_icmp6ev(iface);
1053 	free(iface);
1054 }
1055 
1056 struct icmp6_ev*
1057 get_icmp6ev_by_rdomain(int rdomain)
1058 {
1059 	struct iface	*iface;
1060 	struct icmp6_ev	*icmp6ev = NULL;
1061 
1062 	LIST_FOREACH (iface, &interfaces, entries) {
1063 		if (iface->rdomain == rdomain) {
1064 			icmp6ev = iface->icmp6ev;
1065 			break;
1066 		}
1067 	}
1068 
1069 	if (icmp6ev == NULL) {
1070 		if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL)
1071 			fatal("calloc");
1072 		icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer;
1073 		icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer);
1074 		icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from;
1075 		icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from);
1076 		icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov;
1077 		icmp6ev->rcvmhdr.msg_iovlen = 1;
1078 		icmp6ev->rcvmhdr.msg_controllen =
1079 		    CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1080 		    CMSG_SPACE(sizeof(int));
1081 		if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev->
1082 		    rcvmhdr.msg_controllen)) == NULL)
1083 			fatal("malloc");
1084 		frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0,
1085 		    &rdomain, sizeof(rdomain));
1086 	}
1087 	icmp6ev->refcnt++;
1088 	return (icmp6ev);
1089 }
1090 
1091 void
1092 unref_icmp6ev(struct iface *iface)
1093 {
1094 	struct icmp6_ev *icmp6ev = iface->icmp6ev;
1095 
1096 	iface->icmp6ev = NULL;
1097 
1098 	if (icmp6ev != NULL) {
1099 		icmp6ev->refcnt--;
1100 		if (icmp6ev->refcnt == 0) {
1101 			event_del(&icmp6ev->ev);
1102 			close(EVENT_FD(&icmp6ev->ev));
1103 			free(icmp6ev);
1104 		}
1105 	}
1106 }
1107 
1108 void
1109 set_icmp6sock(int icmp6sock, int rdomain)
1110 {
1111 	struct iface	*iface;
1112 
1113 	LIST_FOREACH (iface, &interfaces, entries) {
1114 		if (!event_initialized(&iface->icmp6ev->ev) && iface->rdomain
1115 		    == rdomain) {
1116 			event_set(&iface->icmp6ev->ev, icmp6sock, EV_READ |
1117 			    EV_PERSIST, icmp6_receive, iface->icmp6ev);
1118 			event_add(&iface->icmp6ev->ev, NULL);
1119 			icmp6sock = -1;
1120 			break;
1121 		}
1122 	}
1123 
1124 	if (icmp6sock != -1) {
1125 		/*
1126 		 * The interface disappeared or changed rdomain while we were
1127 		 * waiting for the parent process to open the raw socket.
1128 		 */
1129 		close(icmp6sock);
1130 		return;
1131 	}
1132 
1133 	LIST_FOREACH (iface, &interfaces, entries) {
1134 		if (event_initialized(&iface->icmp6ev->ev) &&
1135 		    iface->send_solicitation)
1136 			send_solicitation(iface->if_index);
1137 	}
1138 }
1139