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