xref: /openbsd/sbin/dhcp6leased/frontend.c (revision 7520e8fa)
1 /*	$OpenBSD: frontend.c,v 1.14 2024/07/11 13:38:03 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2017, 2021, 2024 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 #include <sys/utsname.h>
28 
29 #include <net/if.h>
30 #include <net/if_dl.h>
31 #include <net/if_types.h>
32 #include <net/route.h>
33 
34 #include <netinet/in.h>
35 #include <netinet/ip.h>
36 
37 #include <arpa/inet.h>
38 
39 #include <errno.h>
40 #include <event.h>
41 #include <ifaddrs.h>
42 #include <imsg.h>
43 #include <pwd.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 
50 #include "log.h"
51 #include "dhcp6leased.h"
52 #include "frontend.h"
53 #include "control.h"
54 
55 #define	ALL_DHCP_RELAY_AGENTS_AND_SERVERS	"ff02::1:2"
56 #define	ROUTE_SOCKET_BUF_SIZE			16384
57 
58 struct iface {
59 	LIST_ENTRY(iface)	 entries;
60 	struct event		 udpev;
61 	struct imsg_ifinfo	 ifinfo;
62 	int			 send_solicit;
63 	int			 elapsed_time;
64 	uint8_t			 xid[XID_SIZE];
65 	int			 serverid_len;
66 	uint8_t			 serverid[SERVERID_SIZE];
67 	struct prefix		 pds[MAX_IA];
68 };
69 
70 __dead void	 frontend_shutdown(void);
71 void		 frontend_sig_handler(int, short, void *);
72 void		 frontend_startup(void);
73 void		 update_iface(uint32_t);
74 void		 route_receive(int, short, void *);
75 void		 handle_route_message(struct rt_msghdr *, struct sockaddr **);
76 void		 get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
77 void		 udp_receive(int, short, void *);
78 int		 get_flags(char *);
79 struct iface	*get_iface_by_id(uint32_t);
80 struct iface	*get_iface_by_name(const char *);
81 void		 remove_iface(uint32_t);
82 void		 set_udpsock(int, uint32_t);
83 void		 iface_data_from_imsg(struct iface*, struct imsg_req_dhcp *);
84 ssize_t		 build_packet(uint8_t, struct iface *, char *);
85 void		 send_packet(uint8_t, struct iface *);
86 int		 iface_conf_cmp(struct iface_conf *, struct iface_conf *);
87 
88 LIST_HEAD(, iface)		 interfaces;
89 struct dhcp6leased_conf		*frontend_conf;
90 static struct imsgev		*iev_main;
91 static struct imsgev		*iev_engine;
92 struct event			 ev_route;
93 struct sockaddr_in6		 dst;
94 int				 ioctlsock;
95 
96 uint8_t				 dhcp_packet[1500];
97 static struct dhcp_duid		 duid;
98 char				*vendor_class_data;
99 int				 vendor_class_len;
100 
101 void
frontend_sig_handler(int sig,short event,void * bula)102 frontend_sig_handler(int sig, short event, void *bula)
103 {
104 	/*
105 	 * Normal signal handler rules don't apply because libevent
106 	 * decouples for us.
107 	 */
108 
109 	switch (sig) {
110 	case SIGINT:
111 	case SIGTERM:
112 		frontend_shutdown();
113 	default:
114 		fatalx("unexpected signal");
115 	}
116 }
117 
118 void
frontend(int debug,int verbose)119 frontend(int debug, int verbose)
120 {
121 	struct event		 ev_sigint, ev_sigterm;
122 	struct passwd		*pw;
123 	struct utsname		 utsname;
124 
125 	frontend_conf = config_new_empty();
126 
127 	log_init(debug, LOG_DAEMON);
128 	log_setverbose(verbose);
129 
130 	if ((pw = getpwnam(DHCP6LEASED_USER)) == NULL)
131 		fatal("getpwnam");
132 
133 	if (chdir("/") == -1)
134 		fatal("chdir(\"/\")");
135 
136 	if (unveil("/", "") == -1)
137 		fatal("unveil /");
138 	if (unveil(NULL, NULL) == -1)
139 		fatal("unveil");
140 
141 	setproctitle("%s", "frontend");
142 	log_procinit("frontend");
143 
144 	if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
145 		fatal("socket");
146 
147 	if (setgroups(1, &pw->pw_gid) ||
148 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
149 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
150 		fatal("can't drop privileges");
151 
152 	if (pledge("stdio unix recvfd route", NULL) == -1)
153 		fatal("pledge");
154 
155 	if (uname(&utsname) == -1)
156 		fatal("uname");
157 	vendor_class_len = asprintf(&vendor_class_data, "%s %s %s",
158 	    utsname.sysname, utsname.release, utsname.machine);
159 	if (vendor_class_len == -1)
160 		fatal("Cannot generate vendor-class-data");
161 
162 	memset(&dst, 0, sizeof(dst));
163 	dst.sin6_family = AF_INET6;
164 	if (inet_pton(AF_INET6, ALL_DHCP_RELAY_AGENTS_AND_SERVERS,
165 	    &dst.sin6_addr.s6_addr) != 1)
166 		fatal("inet_pton");
167 
168 	dst.sin6_port = ntohs(SERVER_PORT);
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 	LIST_INIT(&interfaces);
191 	event_dispatch();
192 
193 	frontend_shutdown();
194 }
195 
196 __dead void
frontend_shutdown(void)197 frontend_shutdown(void)
198 {
199 	/* Close pipes. */
200 	msgbuf_write(&iev_engine->ibuf.w);
201 	msgbuf_clear(&iev_engine->ibuf.w);
202 	close(iev_engine->ibuf.fd);
203 	msgbuf_write(&iev_main->ibuf.w);
204 	msgbuf_clear(&iev_main->ibuf.w);
205 	close(iev_main->ibuf.fd);
206 
207 	config_clear(frontend_conf);
208 
209 	free(iev_engine);
210 	free(iev_main);
211 
212 	log_info("frontend exiting");
213 	exit(0);
214 }
215 
216 int
frontend_imsg_compose_main(int type,pid_t pid,void * data,uint16_t datalen)217 frontend_imsg_compose_main(int type, pid_t pid, void *data,
218     uint16_t datalen)
219 {
220 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
221 	    datalen));
222 }
223 
224 int
frontend_imsg_compose_engine(int type,uint32_t peerid,pid_t pid,void * data,uint16_t datalen)225 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid,
226     void *data, uint16_t datalen)
227 {
228 	return (imsg_compose_event(iev_engine, type, peerid, pid, -1,
229 	    data, datalen));
230 }
231 
232 void
frontend_dispatch_main(int fd,short event,void * bula)233 frontend_dispatch_main(int fd, short event, void *bula)
234 {
235 	static struct dhcp6leased_conf	*nconf;
236 	static struct iface_conf	*iface_conf;
237 	static struct iface_ia_conf	*iface_ia_conf;
238 	struct iface_pd_conf		*iface_pd_conf;
239 	struct imsg			 imsg;
240 	struct imsgev			*iev = bula;
241 	struct imsgbuf			*ibuf = &iev->ibuf;
242 	ssize_t				 n;
243 	int				 shut = 0, udpsock, if_index;
244 
245 	if (event & EV_READ) {
246 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
247 			fatal("imsg_read error");
248 		if (n == 0)	/* Connection closed. */
249 			shut = 1;
250 	}
251 	if (event & EV_WRITE) {
252 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
253 			fatal("msgbuf_write");
254 		if (n == 0)	/* Connection closed. */
255 			shut = 1;
256 	}
257 
258 	for (;;) {
259 		if ((n = imsg_get(ibuf, &imsg)) == -1)
260 			fatal("%s: imsg_get error", __func__);
261 		if (n == 0)	/* No more messages. */
262 			break;
263 
264 		switch (imsg.hdr.type) {
265 		case IMSG_SOCKET_IPC:
266 			/*
267 			 * Setup pipe and event handler to the engine
268 			 * process.
269 			 */
270 			if (iev_engine)
271 				fatalx("%s: received unexpected imsg fd "
272 				    "to frontend", __func__);
273 
274 			if ((fd = imsg_get_fd(&imsg)) == -1)
275 				fatalx("%s: expected to receive imsg fd to "
276 				   "frontend but didn't receive any",
277 				   __func__);
278 
279 			iev_engine = malloc(sizeof(struct imsgev));
280 			if (iev_engine == NULL)
281 				fatal(NULL);
282 
283 			imsg_init(&iev_engine->ibuf, fd);
284 			iev_engine->handler = frontend_dispatch_engine;
285 			iev_engine->events = EV_READ;
286 
287 			event_set(&iev_engine->ev, iev_engine->ibuf.fd,
288 			iev_engine->events, iev_engine->handler, iev_engine);
289 			event_add(&iev_engine->ev, NULL);
290 			break;
291 		case IMSG_UDPSOCK:
292 			if ((udpsock = imsg_get_fd(&imsg)) == -1)
293 				fatalx("%s: expected to receive imsg "
294 				    "udp fd but didn't receive any",
295 				    __func__);
296 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
297 				fatalx("%s: IMSG_UDPSOCK wrong length: "
298 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
299 			memcpy(&if_index, imsg.data, sizeof(if_index));
300 			set_udpsock(udpsock, if_index);
301 			break;
302 		case IMSG_ROUTESOCK:
303 			if ((fd = imsg_get_fd(&imsg)) == -1)
304 				fatalx("%s: expected to receive imsg "
305 				    "routesocket fd but didn't receive any",
306 				    __func__);
307 			event_set(&ev_route, fd, EV_READ | EV_PERSIST,
308 			    route_receive, NULL);
309 			break;
310 		case IMSG_UUID:
311 			if (IMSG_DATA_SIZE(imsg) != sizeof(duid.uuid))
312 				fatalx("%s: IMSG_UUID wrong length: "
313 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
314 			duid.type = htons(DUID_UUID_TYPE);
315 			memcpy(duid.uuid, imsg.data, sizeof(duid.uuid));
316 			break;
317 		case IMSG_STARTUP:
318 			frontend_startup();
319 			break;
320 		case IMSG_RECONF_CONF:
321 			if (nconf != NULL)
322 				fatalx("%s: IMSG_RECONF_CONF already in "
323 				    "progress", __func__);
324 			if (IMSG_DATA_SIZE(imsg) !=
325 			    sizeof(struct dhcp6leased_conf))
326 				fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
327 				    __func__, IMSG_DATA_SIZE(imsg));
328 			if ((nconf = malloc(sizeof(struct dhcp6leased_conf))) ==
329 			    NULL)
330 				fatal(NULL);
331 			memcpy(nconf, imsg.data,
332 			    sizeof(struct dhcp6leased_conf));
333 			SIMPLEQ_INIT(&nconf->iface_list);
334 			break;
335 		case IMSG_RECONF_IFACE:
336 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
337 			    iface_conf))
338 				fatalx("%s: IMSG_RECONF_IFACE wrong length: "
339 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
340 			if ((iface_conf = malloc(sizeof(struct iface_conf)))
341 			    == NULL)
342 				fatal(NULL);
343 			memcpy(iface_conf, imsg.data, sizeof(struct
344 			    iface_conf));
345 			SIMPLEQ_INIT(&iface_conf->iface_ia_list);
346 			SIMPLEQ_INSERT_TAIL(&nconf->iface_list,
347 			    iface_conf, entry);
348 			iface_conf->ia_count = 0;
349 			break;
350 		case IMSG_RECONF_IFACE_IA:
351 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
352 			    iface_ia_conf))
353 				fatalx("%s: IMSG_RECONF_IFACE_IA wrong "
354 				    "length: %lu", __func__,
355 				    IMSG_DATA_SIZE(imsg));
356 			if ((iface_ia_conf =
357 			    malloc(sizeof(struct iface_ia_conf))) == NULL)
358 				fatal(NULL);
359 			memcpy(iface_ia_conf, imsg.data, sizeof(struct
360 			    iface_ia_conf));
361 			SIMPLEQ_INIT(&iface_ia_conf->iface_pd_list);
362 			SIMPLEQ_INSERT_TAIL(&iface_conf->iface_ia_list,
363 			    iface_ia_conf, entry);
364 			iface_ia_conf->id = iface_conf->ia_count++;
365 			if (iface_conf->ia_count > MAX_IA)
366 				fatalx("Too many prefix delegation requests.");
367 			break;
368 		case IMSG_RECONF_IFACE_PD:
369 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
370 			    iface_pd_conf))
371 				fatalx("%s: IMSG_RECONF_IFACE_PD wrong length: "
372 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
373 			if ((iface_pd_conf =
374 			    malloc(sizeof(struct iface_pd_conf))) == NULL)
375 				fatal(NULL);
376 			memcpy(iface_pd_conf, imsg.data, sizeof(struct
377 			    iface_pd_conf));
378 			SIMPLEQ_INSERT_TAIL(&iface_ia_conf->iface_pd_list,
379 			    iface_pd_conf, entry);
380 			break;
381 		case IMSG_RECONF_IFACE_IA_END:
382 			iface_ia_conf = NULL;
383 			break;
384 		case IMSG_RECONF_IFACE_END:
385 			iface_conf = NULL;
386 			break;
387 		case IMSG_RECONF_END: {
388 			int	 i;
389 			int	*ifaces;
390 			char	 ifnamebuf[IF_NAMESIZE], *if_name;
391 
392 			if (nconf == NULL)
393 				fatalx("%s: IMSG_RECONF_END without "
394 				    "IMSG_RECONF_CONF", __func__);
395 
396 			ifaces = changed_ifaces(frontend_conf, nconf);
397 			merge_config(frontend_conf, nconf);
398 			nconf = NULL;
399 			for (i = 0; ifaces[i] != 0; i++) {
400 				if_index = ifaces[i];
401 				if_name = if_indextoname(if_index, ifnamebuf);
402 				log_debug("changed iface: %s[%d]", if_name !=
403 				    NULL ? if_name : "<unknown>", if_index);
404 				update_iface(if_index);
405 				frontend_imsg_compose_engine(
406 				    IMSG_REQUEST_REBOOT, 0, 0, &if_index,
407 				    sizeof(if_index));
408 			}
409 			free(ifaces);
410 			break;
411 		}
412 		case IMSG_CONTROLFD:
413 			if ((fd = imsg_get_fd(&imsg)) == -1)
414 				fatalx("%s: expected to receive imsg "
415 				    "control fd but didn't receive any",
416 				    __func__);
417 			/* Listen on control socket. */
418 			control_listen(fd);
419 			break;
420 		case IMSG_CTL_END:
421 			control_imsg_relay(&imsg);
422 			break;
423 		default:
424 			log_debug("%s: error handling imsg %d", __func__,
425 			    imsg.hdr.type);
426 			break;
427 		}
428 		imsg_free(&imsg);
429 	}
430 	if (!shut)
431 		imsg_event_add(iev);
432 	else {
433 		/* This pipe is dead. Remove its event handler. */
434 		event_del(&iev->ev);
435 		event_loopexit(NULL);
436 	}
437 }
438 
439 void
frontend_dispatch_engine(int fd,short event,void * bula)440 frontend_dispatch_engine(int fd, short event, void *bula)
441 {
442 	struct imsgev		*iev = bula;
443 	struct imsgbuf		*ibuf = &iev->ibuf;
444 	struct imsg		 imsg;
445 	struct iface		*iface;
446 	ssize_t			 n;
447 	int			 shut = 0;
448 
449 	if (event & EV_READ) {
450 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
451 			fatal("imsg_read error");
452 		if (n == 0)	/* Connection closed. */
453 			shut = 1;
454 	}
455 	if (event & EV_WRITE) {
456 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
457 			fatal("msgbuf_write");
458 		if (n == 0)	/* Connection closed. */
459 			shut = 1;
460 	}
461 
462 	for (;;) {
463 		if ((n = imsg_get(ibuf, &imsg)) == -1)
464 			fatal("%s: imsg_get error", __func__);
465 		if (n == 0)	/* No more messages. */
466 			break;
467 
468 		switch (imsg.hdr.type) {
469 		case IMSG_CTL_END:
470 		case IMSG_CTL_SHOW_INTERFACE_INFO:
471 			control_imsg_relay(&imsg);
472 			break;
473 		case IMSG_SEND_SOLICIT:
474 		case IMSG_SEND_REQUEST:
475 		case IMSG_SEND_RENEW:
476 		case IMSG_SEND_REBIND: {
477 			struct imsg_req_dhcp	 imsg_req_dhcp;
478 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp))
479 				fatalx("%s: IMSG_SEND_DISCOVER wrong "
480 				    "length: %lu", __func__,
481 				    IMSG_DATA_SIZE(imsg));
482 			memcpy(&imsg_req_dhcp, imsg.data,
483 			    sizeof(imsg_req_dhcp));
484 
485 			iface = get_iface_by_id(imsg_req_dhcp.if_index);
486 
487 			if (iface == NULL)
488 				break;
489 
490 			iface_data_from_imsg(iface, &imsg_req_dhcp);
491 			switch (imsg.hdr.type) {
492 			case IMSG_SEND_SOLICIT:
493 				send_packet(DHCPSOLICIT, iface);
494 				break;
495 			case IMSG_SEND_REQUEST:
496 				send_packet(DHCPREQUEST, iface);
497 				break;
498 			case IMSG_SEND_RENEW:
499 				send_packet(DHCPRENEW, iface);
500 				break;
501 			case IMSG_SEND_REBIND:
502 				send_packet(DHCPREBIND, iface);
503 				break;
504 			}
505 			break;
506 		}
507 		default:
508 			log_debug("%s: error handling imsg %d", __func__,
509 			    imsg.hdr.type);
510 			break;
511 		}
512 		imsg_free(&imsg);
513 	}
514 	if (!shut)
515 		imsg_event_add(iev);
516 	else {
517 		/* This pipe is dead. Remove its event handler. */
518 		event_del(&iev->ev);
519 		event_loopexit(NULL);
520 	}
521 }
522 
523 int
get_flags(char * if_name)524 get_flags(char *if_name)
525 {
526 	struct ifreq		 ifr;
527 
528 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
529 	if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
530 		log_warn("SIOCGIFFLAGS");
531 		return -1;
532 	}
533 	return ifr.ifr_flags;
534 }
535 
536 void
update_iface(uint32_t if_index)537 update_iface(uint32_t if_index)
538 {
539 	struct ifaddrs		*ifap, *ifa;
540 	struct iface		*iface;
541 	struct imsg_ifinfo	 ifinfo;
542 	int			 flags;
543 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
544 
545 	if (getifaddrs(&ifap) != 0)
546 		fatal("getifaddrs");
547 
548 	if ((if_name = if_indextoname(if_index, ifnamebuf)) == NULL)
549 		return;
550 
551 	if ((flags = get_flags(if_name)) == -1)
552 		return;
553 
554 	if (find_iface_conf(&frontend_conf->iface_list, if_name) == NULL)
555 		return;
556 
557 	memset(&ifinfo, 0, sizeof(ifinfo));
558 	ifinfo.if_index = if_index;
559 	ifinfo.link_state = -1;
560 	ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) ==
561 	    (IFF_UP | IFF_RUNNING);
562 
563 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
564 		if (strcmp(if_name, ifa->ifa_name) != 0)
565 			continue;
566 		if (ifa->ifa_addr == NULL)
567 			continue;
568 
569 		switch (ifa->ifa_addr->sa_family) {
570 		case AF_LINK: {
571 			struct if_data		*if_data;
572 
573 			if_data = (struct if_data *)ifa->ifa_data;
574 			ifinfo.link_state = if_data->ifi_link_state;
575 			ifinfo.rdomain = if_data->ifi_rdomain;
576 			goto out;
577 		}
578 		default:
579 			break;
580 		}
581 	}
582  out:
583 	freeifaddrs(ifap);
584 	iface = get_iface_by_id(if_index);
585 	if (iface == NULL) {
586 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
587 			fatal("calloc");
588 		memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo));
589 		LIST_INSERT_HEAD(&interfaces, iface, entries);
590 		frontend_imsg_compose_main(IMSG_OPEN_UDPSOCK, 0,
591 		    &if_index, sizeof(if_index));
592 	} else
593 		/* XXX check rdomain changed ?*/
594 		memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo));
595 
596 	frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo,
597 	    sizeof(iface->ifinfo));
598 }
599 
600 void
frontend_startup(void)601 frontend_startup(void)
602 {
603 	if (!event_initialized(&ev_route))
604 		fatalx("%s: did not receive a route socket from the main "
605 		    "process", __func__);
606 
607 	event_add(&ev_route, NULL);
608 }
609 
610 void
route_receive(int fd,short events,void * arg)611 route_receive(int fd, short events, void *arg)
612 {
613 	static uint8_t			 *buf;
614 
615 	struct rt_msghdr		*rtm;
616 	struct sockaddr			*sa, *rti_info[RTAX_MAX];
617 	ssize_t				 n;
618 
619 	if (buf == NULL) {
620 		buf = malloc(ROUTE_SOCKET_BUF_SIZE);
621 		if (buf == NULL)
622 			fatal("malloc");
623 	}
624 	rtm = (struct rt_msghdr *)buf;
625 	if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
626 		if (errno == EAGAIN || errno == EINTR)
627 			return;
628 		log_warn("dispatch_rtmsg: read error");
629 		return;
630 	}
631 
632 	if (n == 0)
633 		fatal("routing socket closed");
634 
635 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
636 		log_warnx("partial rtm of %zd in buffer", n);
637 		return;
638 	}
639 
640 	if (rtm->rtm_version != RTM_VERSION)
641 		return;
642 
643 	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
644 	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
645 
646 	handle_route_message(rtm, rti_info);
647 }
648 
649 void
handle_route_message(struct rt_msghdr * rtm,struct sockaddr ** rti_info)650 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
651 {
652 	struct if_announcemsghdr	*ifan;
653 	uint32_t			 if_index;
654 
655 	switch (rtm->rtm_type) {
656 	case RTM_IFINFO:
657 		if_index = ((struct if_msghdr *)rtm)->ifm_index;
658 		update_iface(if_index);
659 		break;
660 	case RTM_IFANNOUNCE:
661 		ifan = (struct if_announcemsghdr *)rtm;
662 		if_index = ifan->ifan_index;
663 		if (ifan->ifan_what == IFAN_DEPARTURE) {
664 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
665 			    &if_index, sizeof(if_index));
666 			remove_iface(if_index);
667 		}
668 		break;
669 	default:
670 		log_debug("unexpected RTM: %d", rtm->rtm_type);
671 		break;
672 	}
673 }
674 
675 #define ROUNDUP(a) \
676 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
677 
678 void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)679 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
680 {
681 	int	i;
682 
683 	for (i = 0; i < RTAX_MAX; i++) {
684 		if (addrs & (1 << i)) {
685 			rti_info[i] = sa;
686 			sa = (struct sockaddr *)((char *)(sa) +
687 			    ROUNDUP(sa->sa_len));
688 		} else
689 			rti_info[i] = NULL;
690 	}
691 }
692 
693 void
udp_receive(int fd,short events,void * arg)694 udp_receive(int fd, short events, void *arg)
695 {
696 	struct imsg_dhcp	 imsg_dhcp;
697 	struct iface		*iface;
698 	ssize_t			 len;
699 
700 	iface = (struct iface *)arg;
701 	memset(&imsg_dhcp, 0, sizeof(imsg_dhcp));
702 
703 	if ((len = read(fd, imsg_dhcp.packet, 1500)) == -1) {
704 		log_warn("%s: read", __func__);
705 		return;
706 	}
707 
708 	if (len == 0)
709 		fatal("%s len == 0", __func__);
710 
711 	imsg_dhcp.if_index = iface->ifinfo.if_index;
712 	imsg_dhcp.len = len;
713 	frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp,
714 	    sizeof(imsg_dhcp));
715 }
716 
717 void
iface_data_from_imsg(struct iface * iface,struct imsg_req_dhcp * imsg)718 iface_data_from_imsg(struct iface* iface, struct imsg_req_dhcp *imsg)
719 {
720 	memcpy(iface->xid, imsg->xid, sizeof(iface->xid));
721 	iface->elapsed_time = imsg->elapsed_time;
722 	iface->serverid_len = imsg->serverid_len;
723 	memcpy(iface->serverid, imsg->serverid, SERVERID_SIZE);
724 	memcpy(iface->pds, imsg->pds, sizeof(iface->pds));
725 }
726 
727 ssize_t
build_packet(uint8_t message_type,struct iface * iface,char * if_name)728 build_packet(uint8_t message_type, struct iface *iface, char *if_name)
729 {
730 	struct iface_conf		*iface_conf;
731 	struct iface_ia_conf		*ia_conf;
732 	struct dhcp_hdr			 hdr;
733 	struct dhcp_option_hdr		 opt_hdr;
734 	struct dhcp_iapd		 iapd;
735 	struct dhcp_iaprefix		 iaprefix;
736 	struct dhcp_vendor_class	 vendor_class;
737 	size_t				 i;
738 	ssize_t				 len;
739 	uint16_t			 request_option_code, elapsed_time;
740 	const uint16_t			 options[] = {DHO_SOL_MAX_RT,
741 					     DHO_INF_MAX_RT};
742 	uint8_t				*p;
743 
744 	switch (message_type) {
745 	case DHCPSOLICIT:
746 	case DHCPREQUEST:
747 	case DHCPRENEW:
748 	case DHCPREBIND:
749 		break;
750 	default:
751 		fatalx("%s: %s not implemented", __func__,
752 		    dhcp_message_type2str(message_type));
753 	}
754 
755 	iface_conf = find_iface_conf(&frontend_conf->iface_list, if_name);
756 
757 	memset(dhcp_packet, 0, sizeof(dhcp_packet));
758 
759 	p = dhcp_packet;
760 	hdr.msg_type = message_type;
761 	memcpy(hdr.xid, iface->xid, sizeof(hdr.xid));
762 	memcpy(p, &hdr, sizeof(struct dhcp_hdr));
763 	p += sizeof(struct dhcp_hdr);
764 
765 	opt_hdr.code = htons(DHO_CLIENTID);
766 	opt_hdr.len = htons(sizeof(struct dhcp_duid));
767 	memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
768 	p += sizeof(struct dhcp_option_hdr);
769 	memcpy(p, &duid, sizeof(struct dhcp_duid));
770 	p += sizeof(struct dhcp_duid);
771 
772 	switch (message_type) {
773 	case DHCPSOLICIT:
774 	case DHCPREBIND:
775 		break;
776 	case DHCPREQUEST:
777 	case DHCPRENEW:
778 		opt_hdr.code = htons(DHO_SERVERID);
779 		opt_hdr.len = htons(iface->serverid_len);
780 		memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
781 		p += sizeof(struct dhcp_option_hdr);
782 		memcpy(p, iface->serverid, iface->serverid_len);
783 		p += iface->serverid_len;
784 		break;
785 	default:
786 		fatalx("%s: %s not implemented", __func__,
787 		    dhcp_message_type2str(message_type));
788 	}
789 	SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) {
790 		struct prefix *pd;
791 
792 		opt_hdr.code = htons(DHO_IA_PD);
793 		opt_hdr.len = htons(sizeof(struct dhcp_iapd) +
794 		    sizeof(struct dhcp_option_hdr) +
795 		    sizeof(struct dhcp_iaprefix));
796 		memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
797 		p += sizeof(struct dhcp_option_hdr);
798 		iapd.iaid = htonl(ia_conf->id);
799 		iapd.t1 = 0;
800 		iapd.t2 = 0;
801 		memcpy(p, &iapd, sizeof(struct dhcp_iapd));
802 		p += sizeof(struct dhcp_iapd);
803 
804 		opt_hdr.code = htons(DHO_IA_PREFIX);
805 		opt_hdr.len = htons(sizeof(struct dhcp_iaprefix));
806 		memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
807 		p += sizeof(struct dhcp_option_hdr);
808 
809 		memset(&iaprefix, 0, sizeof(struct dhcp_iaprefix));
810 
811 		switch (message_type) {
812 		case DHCPSOLICIT:
813 			iaprefix.prefix_len = ia_conf->prefix_len;
814 			break;
815 		case DHCPREQUEST:
816 		case DHCPRENEW:
817 		case DHCPREBIND:
818 			pd = &iface->pds[ia_conf->id];
819 			if (pd->prefix_len > 0) {
820 				iaprefix.prefix_len = pd->prefix_len;
821 				memcpy(&iaprefix.prefix, &pd->prefix,
822 				    sizeof(struct in6_addr));
823 			} else
824 				iaprefix.prefix_len = ia_conf->prefix_len;
825 			break;
826 		default:
827 			fatalx("%s: %s not implemented", __func__,
828 			    dhcp_message_type2str(message_type));
829 		}
830 		memcpy(p, &iaprefix, sizeof(struct dhcp_iaprefix));
831 		p += sizeof(struct dhcp_iaprefix);
832 	}
833 
834 	opt_hdr.code = htons(DHO_ORO);
835 	opt_hdr.len = htons(sizeof(request_option_code) * nitems(options));
836 	memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
837 	p += sizeof(struct dhcp_option_hdr);
838 	for (i = 0; i < nitems(options); i++) {
839 		request_option_code = htons(options[i]);
840 		memcpy(p, &request_option_code, sizeof(uint16_t));
841 		p += sizeof(uint16_t);
842 	}
843 
844 	opt_hdr.code = htons(DHO_ELAPSED_TIME);
845 	opt_hdr.len = htons(2);
846 	memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
847 	p += sizeof(struct dhcp_option_hdr);
848 	elapsed_time = htons(iface->elapsed_time);
849 	memcpy(p, &elapsed_time, sizeof(uint16_t));
850 	p += sizeof(uint16_t);
851 
852 	if (message_type == DHCPSOLICIT && frontend_conf->rapid_commit) {
853 		opt_hdr.code = htons(DHO_RAPID_COMMIT);
854 		opt_hdr.len = htons(0);
855 		memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
856 		p += sizeof(struct dhcp_option_hdr);
857 	}
858 
859 	opt_hdr.code = htons(DHO_VENDOR_CLASS);
860 	opt_hdr.len = htons(sizeof(struct dhcp_vendor_class) +
861 	    vendor_class_len);
862 	memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr));
863 	p += sizeof(struct dhcp_option_hdr);
864 	vendor_class.enterprise_number = htonl(OPENBSD_ENTERPRISENO);
865 	vendor_class.vendor_class_len = htons(vendor_class_len);
866 	memcpy(p, &vendor_class, sizeof(struct dhcp_vendor_class));
867 	p += sizeof(struct dhcp_vendor_class);
868 	/* Not a C-string, leave out \0 */
869 	memcpy(p, vendor_class_data, vendor_class_len);
870 	p += vendor_class_len;
871 
872 	len = p - dhcp_packet;
873 	return (len);
874 }
875 
876 void
send_packet(uint8_t message_type,struct iface * iface)877 send_packet(uint8_t message_type, struct iface *iface)
878 {
879 	ssize_t	 pkt_len;
880 	char	 ifnamebuf[IF_NAMESIZE], *if_name, *message_name;
881 
882 	if (!event_initialized(&iface->udpev)) {
883 		iface->send_solicit = 1;
884 		return;
885 	}
886 
887 	iface->send_solicit = 0;
888 
889 	if ((if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf))
890 	    == NULL)
891 		return; /* iface went away, nothing to do */
892 
893 	switch (message_type) {
894 	case DHCPSOLICIT:
895 		message_name = "Soliciting";
896 		break;
897 	case DHCPREQUEST:
898 		message_name = "Requesting";
899 		break;
900 	case DHCPRENEW:
901 		message_name = "Renewing";
902 		break;
903 	case DHCPREBIND:
904 		message_name = "Rebinding";
905 		break;
906 	default:
907 		message_name = NULL;
908 		break;
909 	}
910 
911 	if (message_name)
912 		log_info("%s lease on %s", message_name, if_name);
913 
914 	pkt_len = build_packet(message_type, iface, if_name);
915 
916 	dst.sin6_scope_id = iface->ifinfo.if_index;
917 
918 	if (sendto(EVENT_FD(&iface->udpev), dhcp_packet, pkt_len, 0,
919 	    (struct sockaddr *)&dst, sizeof(dst)) == -1)
920 		log_warn("sendto");
921 }
922 
923 struct iface*
get_iface_by_id(uint32_t if_index)924 get_iface_by_id(uint32_t if_index)
925 {
926 	struct iface	*iface;
927 
928 	LIST_FOREACH (iface, &interfaces, entries) {
929 		if (iface->ifinfo.if_index == if_index)
930 			return (iface);
931 	}
932 
933 	return (NULL);
934 }
935 
936 struct iface*
get_iface_by_name(const char * if_name)937 get_iface_by_name(const char *if_name)
938 {
939 	uint32_t ifidx = if_nametoindex(if_name);
940 
941 	if (ifidx == 0)
942 		return (NULL);
943 	return get_iface_by_id(ifidx);
944 }
945 
946 void
remove_iface(uint32_t if_index)947 remove_iface(uint32_t if_index)
948 {
949 	struct iface	*iface;
950 
951 	iface = get_iface_by_id(if_index);
952 
953 	if (iface == NULL)
954 		return;
955 
956 	LIST_REMOVE(iface, entries);
957 	if (event_initialized(&iface->udpev)) {
958 		event_del(&iface->udpev);
959 		close(EVENT_FD(&iface->udpev));
960 	}
961 	free(iface);
962 }
963 
964 void
set_udpsock(int udpsock,uint32_t if_index)965 set_udpsock(int udpsock, uint32_t if_index)
966 {
967 	struct iface	*iface;
968 
969 	iface = get_iface_by_id(if_index);
970 
971 	if (iface == NULL) {
972 		/*
973 		 * The interface disappeared while we were waiting for the
974 		 * parent process to open the udp socket.
975 		 */
976 		close(udpsock);
977 	} else if (event_initialized(&iface->udpev)) {
978 		/*
979 		 * XXX
980 		 * The autoconf flag is flapping and we have multiple udp
981 		 * sockets in flight. We don't need this one because we already
982 		 * got one.
983 		 */
984 		close(udpsock);
985 	} else {
986 		event_set(&iface->udpev, udpsock, EV_READ |
987 		    EV_PERSIST, udp_receive, iface);
988 		event_add(&iface->udpev, NULL);
989 		if (iface->send_solicit)
990 			send_packet(DHCPSOLICIT, iface);
991 	}
992 }
993 
994 struct iface_conf*
find_iface_conf(struct iface_conf_head * head,char * if_name)995 find_iface_conf(struct iface_conf_head *head, char *if_name)
996 {
997 	struct iface_conf	*iface_conf;
998 
999 	if (if_name == NULL)
1000 		return (NULL);
1001 
1002 	SIMPLEQ_FOREACH(iface_conf, head, entry) {
1003 		if (strcmp(iface_conf->name, if_name) == 0)
1004 			return iface_conf;
1005 	}
1006 	return (NULL);
1007 }
1008 
1009 int*
changed_ifaces(struct dhcp6leased_conf * oconf,struct dhcp6leased_conf * nconf)1010 changed_ifaces(struct dhcp6leased_conf *oconf, struct dhcp6leased_conf *nconf)
1011 {
1012 	struct iface_conf	*iface_conf, *oiface_conf;
1013 	int			*ret, if_index, count = 0, i = 0;
1014 
1015 	/*
1016 	 * Worst case: All old interfaces replaced with new interfaces.
1017 	 * This should still be a small number
1018 	 */
1019 	SIMPLEQ_FOREACH(iface_conf, &oconf->iface_list, entry)
1020 	    count++;
1021 	SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry)
1022 	    count++;
1023 
1024 	ret = calloc(count + 1, sizeof(int));
1025 
1026 	SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) {
1027 		if ((if_index = if_nametoindex(iface_conf->name)) == 0)
1028 			continue;
1029 		oiface_conf = find_iface_conf(&oconf->iface_list,
1030 		    iface_conf->name);
1031 		if (oiface_conf == NULL) {
1032 			/* new interface added to config */
1033 			ret[i++] = if_index;
1034 		} else if (iface_conf_cmp(iface_conf, oiface_conf) != 0) {
1035 			/* interface conf changed */
1036 			ret[i++] = if_index;
1037 		}
1038 	}
1039 	SIMPLEQ_FOREACH(oiface_conf, &oconf->iface_list, entry) {
1040 		if ((if_index = if_nametoindex(oiface_conf->name)) == 0)
1041 			continue;
1042 		if (find_iface_conf(&nconf->iface_list, oiface_conf->name) ==
1043 		    NULL) {
1044 			/* interface removed from config */
1045 			ret[i++] = if_index;
1046 		}
1047 	}
1048 	return ret;
1049 }
1050 
1051 int
iface_conf_cmp(struct iface_conf * a,struct iface_conf * b)1052 iface_conf_cmp(struct iface_conf *a, struct iface_conf *b)
1053 {
1054 	return 0;
1055 }
1056