xref: /openbsd/sbin/dhcpleased/dhcpleased.c (revision 4f8d227c)
1*4f8d227cSflorian /*	$OpenBSD: dhcpleased.c,v 1.30 2023/10/10 16:09:53 florian Exp $	*/
257419a7fSflorian 
357419a7fSflorian /*
457419a7fSflorian  * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
557419a7fSflorian  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
657419a7fSflorian  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
757419a7fSflorian  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
857419a7fSflorian  *
957419a7fSflorian  * Permission to use, copy, modify, and distribute this software for any
1057419a7fSflorian  * purpose with or without fee is hereby granted, provided that the above
1157419a7fSflorian  * copyright notice and this permission notice appear in all copies.
1257419a7fSflorian  *
1357419a7fSflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1457419a7fSflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1557419a7fSflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1657419a7fSflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1757419a7fSflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1857419a7fSflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1957419a7fSflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2057419a7fSflorian  */
2157419a7fSflorian #include <sys/types.h>
2257419a7fSflorian #include <sys/ioctl.h>
2357419a7fSflorian #include <sys/queue.h>
2457419a7fSflorian #include <sys/socket.h>
2557419a7fSflorian #include <sys/stat.h>
2657419a7fSflorian #include <sys/syslog.h>
2757419a7fSflorian #include <sys/sysctl.h>
2857419a7fSflorian #include <sys/uio.h>
2957419a7fSflorian #include <sys/wait.h>
3057419a7fSflorian 
3157419a7fSflorian #include <net/if.h>
3257419a7fSflorian #include <net/route.h>
335a55e518Sflorian #include <net/if_dl.h>
3457419a7fSflorian #include <netinet/in.h>
3557419a7fSflorian #include <netinet/if_ether.h>
3657419a7fSflorian #include <netinet/in_var.h>
3757419a7fSflorian 
3857419a7fSflorian #include <arpa/inet.h>
3957419a7fSflorian 
4057419a7fSflorian #include <err.h>
4157419a7fSflorian #include <errno.h>
4257419a7fSflorian #include <fcntl.h>
4357419a7fSflorian #include <event.h>
4457419a7fSflorian #include <ifaddrs.h>
4557419a7fSflorian #include <imsg.h>
4657419a7fSflorian #include <netdb.h>
4757419a7fSflorian #include <pwd.h>
4857419a7fSflorian #include <stddef.h>
4957419a7fSflorian #include <stdio.h>
5057419a7fSflorian #include <stdlib.h>
5157419a7fSflorian #include <string.h>
5257419a7fSflorian #include <signal.h>
5357419a7fSflorian #include <unistd.h>
5457419a7fSflorian 
5557419a7fSflorian #include "bpf.h"
5657419a7fSflorian #include "log.h"
5757419a7fSflorian #include "dhcpleased.h"
5857419a7fSflorian #include "frontend.h"
5957419a7fSflorian #include "engine.h"
6057419a7fSflorian #include "control.h"
6157419a7fSflorian 
6257419a7fSflorian enum dhcpleased_process {
6357419a7fSflorian 	PROC_MAIN,
6457419a7fSflorian 	PROC_ENGINE,
6557419a7fSflorian 	PROC_FRONTEND
6657419a7fSflorian };
6757419a7fSflorian 
6857419a7fSflorian __dead void	usage(void);
6957419a7fSflorian __dead void	main_shutdown(void);
7057419a7fSflorian 
7157419a7fSflorian void	main_sig_handler(int, short, void *);
7257419a7fSflorian 
7357419a7fSflorian static pid_t	start_child(enum dhcpleased_process, char *, int, int, int);
7457419a7fSflorian 
7557419a7fSflorian void	 main_dispatch_frontend(int, short, void *);
7657419a7fSflorian void	 main_dispatch_engine(int, short, void *);
7757419a7fSflorian void	 open_bpfsock(uint32_t);
7857419a7fSflorian void	 configure_interface(struct imsg_configure_interface *);
7957419a7fSflorian void	 deconfigure_interface(struct imsg_configure_interface *);
8057419a7fSflorian void	 propose_rdns(struct imsg_propose_rdns *);
81351dd593Sflorian void	 configure_routes(uint8_t, struct imsg_configure_interface *);
82351dd593Sflorian void	 configure_route(uint8_t, uint32_t, int, struct sockaddr_in *, struct
83351dd593Sflorian 	     sockaddr_in *, struct sockaddr_in *, struct sockaddr_in *, int);
846e93e3e9Sflorian void	 read_lease_file(struct imsg_ifinfo *);
8557419a7fSflorian 
8657419a7fSflorian static int	main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
8757419a7fSflorian int		main_imsg_compose_frontend(int, int, void *, uint16_t);
8857419a7fSflorian int		main_imsg_compose_engine(int, int, void *, uint16_t);
8957419a7fSflorian 
90a41cc082Sflorian #ifndef SMALL
91a41cc082Sflorian int		main_imsg_send_config(struct dhcpleased_conf *);
92a41cc082Sflorian #endif /* SMALL */
93a41cc082Sflorian int	main_reload(void);
94a41cc082Sflorian 
9557419a7fSflorian static struct imsgev	*iev_frontend;
9657419a7fSflorian static struct imsgev	*iev_engine;
9757419a7fSflorian 
98a41cc082Sflorian #ifndef SMALL
99a41cc082Sflorian struct dhcpleased_conf	*main_conf;
100a41cc082Sflorian #endif
1015b2dcb8fSdlg const char		 default_conffile[] = _PATH_CONF_FILE;
1025b2dcb8fSdlg const char		*conffile = default_conffile;
10357419a7fSflorian pid_t			 frontend_pid;
10457419a7fSflorian pid_t			 engine_pid;
10557419a7fSflorian 
106ae968ffdSflorian int			 routesock, ioctl_sock, rtm_seq, no_lease_files;
10757419a7fSflorian 
10857419a7fSflorian void
main_sig_handler(int sig,short event,void * arg)10957419a7fSflorian main_sig_handler(int sig, short event, void *arg)
11057419a7fSflorian {
11157419a7fSflorian 	/*
11257419a7fSflorian 	 * Normal signal handler rules don't apply because libevent
11357419a7fSflorian 	 * decouples for us.
11457419a7fSflorian 	 */
11557419a7fSflorian 
11657419a7fSflorian 	switch (sig) {
11757419a7fSflorian 	case SIGTERM:
11857419a7fSflorian 	case SIGINT:
11957419a7fSflorian 		main_shutdown();
120a41cc082Sflorian 	case SIGHUP:
121a41cc082Sflorian #ifndef SMALL
122a41cc082Sflorian 		if (main_reload() == -1)
123a41cc082Sflorian 			log_warnx("configuration reload failed");
124a41cc082Sflorian 		else
125a41cc082Sflorian 			log_debug("configuration reloaded");
126a41cc082Sflorian #endif /* SMALL */
127a41cc082Sflorian 		break;
12857419a7fSflorian 	default:
12957419a7fSflorian 		fatalx("unexpected signal");
13057419a7fSflorian 	}
13157419a7fSflorian }
13257419a7fSflorian 
13357419a7fSflorian __dead void
usage(void)13457419a7fSflorian usage(void)
13557419a7fSflorian {
13657419a7fSflorian 	extern char *__progname;
13757419a7fSflorian 
138a41cc082Sflorian 	fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n",
13957419a7fSflorian 	    __progname);
14057419a7fSflorian 	exit(1);
14157419a7fSflorian }
14257419a7fSflorian 
14357419a7fSflorian int
main(int argc,char * argv[])14457419a7fSflorian main(int argc, char *argv[])
14557419a7fSflorian {
146a41cc082Sflorian 	struct event		 ev_sigint, ev_sigterm, ev_sighup;
14757419a7fSflorian 	int			 ch;
14857419a7fSflorian 	int			 debug = 0, engine_flag = 0, frontend_flag = 0;
149a41cc082Sflorian 	int			 verbose = 0, no_action = 0;
15057419a7fSflorian 	char			*saved_argv0;
15157419a7fSflorian 	int			 pipe_main2frontend[2];
15257419a7fSflorian 	int			 pipe_main2engine[2];
153bc9eb55cSkn 	int			 frontend_routesock, rtfilter, lockfd;
15457419a7fSflorian 	int			 rtable_any = RTABLE_ANY;
155131c304bSflorian 	char			*csock = _PATH_DHCPLEASED_SOCKET;
15657419a7fSflorian #ifndef SMALL
15757419a7fSflorian 	int			 control_fd;
15857419a7fSflorian #endif /* SMALL */
15957419a7fSflorian 
16057419a7fSflorian 	log_init(1, LOG_DAEMON);	/* Log to stderr until daemonized. */
16157419a7fSflorian 	log_setverbose(1);
16257419a7fSflorian 
16357419a7fSflorian 	saved_argv0 = argv[0];
16457419a7fSflorian 	if (saved_argv0 == NULL)
16557419a7fSflorian 		saved_argv0 = "dhcpleased";
16657419a7fSflorian 
167a41cc082Sflorian 	while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) {
16857419a7fSflorian 		switch (ch) {
16957419a7fSflorian 		case 'd':
17057419a7fSflorian 			debug = 1;
17157419a7fSflorian 			break;
17257419a7fSflorian 		case 'E':
17357419a7fSflorian 			engine_flag = 1;
17457419a7fSflorian 			break;
17557419a7fSflorian 		case 'F':
17657419a7fSflorian 			frontend_flag = 1;
17757419a7fSflorian 			break;
178a41cc082Sflorian 		case 'f':
179a41cc082Sflorian 			conffile = optarg;
180a41cc082Sflorian 			break;
181a41cc082Sflorian 		case 'n':
182a41cc082Sflorian 			no_action = 1;
183a41cc082Sflorian 			break;
18457419a7fSflorian 		case 's':
18557419a7fSflorian 			csock = optarg;
18657419a7fSflorian 			break;
18757419a7fSflorian 		case 'v':
18857419a7fSflorian 			verbose++;
18957419a7fSflorian 			break;
19057419a7fSflorian 		default:
19157419a7fSflorian 			usage();
19257419a7fSflorian 		}
19357419a7fSflorian 	}
19457419a7fSflorian 
19557419a7fSflorian 	argc -= optind;
19657419a7fSflorian 	argv += optind;
19757419a7fSflorian 	if (argc > 0 || (engine_flag && frontend_flag))
19857419a7fSflorian 		usage();
19957419a7fSflorian 
20057419a7fSflorian 	if (engine_flag)
20157419a7fSflorian 		engine(debug, verbose);
20257419a7fSflorian 	else if (frontend_flag)
20357419a7fSflorian 		frontend(debug, verbose);
20457419a7fSflorian 
205a41cc082Sflorian #ifndef SMALL
206a41cc082Sflorian 	/* parse config file */
207a41cc082Sflorian 	if ((main_conf = parse_config(conffile)) == NULL)
208a41cc082Sflorian 		exit(1);
209a41cc082Sflorian 
210a41cc082Sflorian 	if (no_action) {
211a41cc082Sflorian 		if (verbose)
212a41cc082Sflorian 			print_config(main_conf);
213a41cc082Sflorian 		else
214a41cc082Sflorian 			fprintf(stderr, "configuration OK\n");
215a41cc082Sflorian 		exit(0);
216a41cc082Sflorian 	}
217a41cc082Sflorian #endif /* SMALL */
218a41cc082Sflorian 
21957419a7fSflorian 	/* Check for root privileges. */
22057419a7fSflorian 	if (geteuid())
22157419a7fSflorian 		errx(1, "need root privileges");
22257419a7fSflorian 
223bc9eb55cSkn 	lockfd = open(_PATH_LOCKFILE, O_CREAT|O_RDWR|O_EXLOCK|O_NONBLOCK, 0600);
2241c0cb702Skn 	if (lockfd == -1) {
2251c0cb702Skn 		if (errno == EAGAIN)
226bc9eb55cSkn 			errx(1, "already running");
2271c0cb702Skn 		err(1, "%s", _PATH_LOCKFILE);
2281c0cb702Skn 	}
229bc9eb55cSkn 
23057419a7fSflorian 	/* Check for assigned daemon user */
23157419a7fSflorian 	if (getpwnam(DHCPLEASED_USER) == NULL)
23257419a7fSflorian 		errx(1, "unknown user %s", DHCPLEASED_USER);
23357419a7fSflorian 
23457419a7fSflorian 	log_init(debug, LOG_DAEMON);
23557419a7fSflorian 	log_setverbose(verbose);
23657419a7fSflorian 
23757419a7fSflorian 	if (!debug)
23857419a7fSflorian 		daemon(0, 0);
23957419a7fSflorian 
24057419a7fSflorian 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
24157419a7fSflorian 	    PF_UNSPEC, pipe_main2frontend) == -1)
24257419a7fSflorian 		fatal("main2frontend socketpair");
24357419a7fSflorian 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
24457419a7fSflorian 	    PF_UNSPEC, pipe_main2engine) == -1)
24557419a7fSflorian 		fatal("main2engine socketpair");
24657419a7fSflorian 
24757419a7fSflorian 	/* Start children. */
24857419a7fSflorian 	engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1],
24957419a7fSflorian 	    debug, verbose);
25057419a7fSflorian 	frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
25157419a7fSflorian 	    pipe_main2frontend[1], debug, verbose);
25257419a7fSflorian 
25357419a7fSflorian 	log_procinit("main");
25457419a7fSflorian 
25557419a7fSflorian 	if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC |
25657419a7fSflorian 	    SOCK_NONBLOCK, AF_INET)) == -1)
25757419a7fSflorian 		fatal("route socket");
258fe9a5e47Sflorian 	shutdown(routesock, SHUT_RD);
25957419a7fSflorian 
26057419a7fSflorian 	event_init();
26157419a7fSflorian 
26257419a7fSflorian 	/* Setup signal handler. */
26357419a7fSflorian 	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
26457419a7fSflorian 	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
265a41cc082Sflorian 	signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
26657419a7fSflorian 	signal_add(&ev_sigint, NULL);
26757419a7fSflorian 	signal_add(&ev_sigterm, NULL);
268a41cc082Sflorian 	signal_add(&ev_sighup, NULL);
26957419a7fSflorian 	signal(SIGPIPE, SIG_IGN);
27057419a7fSflorian 
27157419a7fSflorian 	/* Setup pipes to children. */
27257419a7fSflorian 
27357419a7fSflorian 	if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL ||
27457419a7fSflorian 	    (iev_engine = malloc(sizeof(struct imsgev))) == NULL)
27557419a7fSflorian 		fatal(NULL);
27657419a7fSflorian 	imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
27757419a7fSflorian 	iev_frontend->handler = main_dispatch_frontend;
27857419a7fSflorian 	imsg_init(&iev_engine->ibuf, pipe_main2engine[0]);
27957419a7fSflorian 	iev_engine->handler = main_dispatch_engine;
28057419a7fSflorian 
28157419a7fSflorian 	/* Setup event handlers for pipes to engine & frontend. */
28257419a7fSflorian 	iev_frontend->events = EV_READ;
28357419a7fSflorian 	event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
28457419a7fSflorian 	    iev_frontend->events, iev_frontend->handler, iev_frontend);
28557419a7fSflorian 	event_add(&iev_frontend->ev, NULL);
28657419a7fSflorian 
28757419a7fSflorian 	iev_engine->events = EV_READ;
28857419a7fSflorian 	event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events,
28957419a7fSflorian 	    iev_engine->handler, iev_engine);
29057419a7fSflorian 	event_add(&iev_engine->ev, NULL);
29157419a7fSflorian 
29257419a7fSflorian 	if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf))
29357419a7fSflorian 		fatal("could not establish imsg links");
29457419a7fSflorian 
29557419a7fSflorian 	if ((ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
29657419a7fSflorian 		fatal("socket");
29757419a7fSflorian 
29857419a7fSflorian 	if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC,
29957419a7fSflorian 	    AF_INET)) == -1)
30057419a7fSflorian 		fatal("route socket");
30157419a7fSflorian 
302d3097762Sflorian 	rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) |
303d3097762Sflorian 	    ROUTE_FILTER(RTM_IFANNOUNCE);
30457419a7fSflorian 	if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER,
30557419a7fSflorian 	    &rtfilter, sizeof(rtfilter)) == -1)
30657419a7fSflorian 		fatal("setsockopt(ROUTE_MSGFILTER)");
30757419a7fSflorian 	if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER,
30857419a7fSflorian 	    &rtable_any, sizeof(rtable_any)) == -1)
30957419a7fSflorian 		fatal("setsockopt(ROUTE_TABLEFILTER)");
31057419a7fSflorian 
31157419a7fSflorian #ifndef SMALL
31257419a7fSflorian 	if ((control_fd = control_init(csock)) == -1)
3134b9fcc1bSflorian 		warnx("control socket setup failed");
31457419a7fSflorian #endif /* SMALL */
31557419a7fSflorian 
316a41cc082Sflorian 	if (unveil(conffile, "r") == -1)
317a41cc082Sflorian 		fatal("unveil %s", conffile);
31857419a7fSflorian 	if (unveil("/dev/bpf", "rw") == -1)
319f5208191Sflorian 		fatal("unveil /dev/bpf");
32057419a7fSflorian 
321ae968ffdSflorian 	if (unveil(_PATH_LEASE, "rwc") == -1) {
322ae968ffdSflorian 		no_lease_files = 1;
323ae968ffdSflorian 		log_warn("disabling lease files, unveil " _PATH_LEASE);
324ae968ffdSflorian 	}
32557419a7fSflorian 
32657419a7fSflorian 	if (unveil(NULL, NULL) == -1)
327bc5a8259Sbeck 		fatal("unveil");
32857419a7fSflorian #if notyet
32957419a7fSflorian 	if (pledge("stdio inet rpath wpath sendfd wroute bpf", NULL) == -1)
33057419a7fSflorian 		fatal("pledge");
33157419a7fSflorian #endif
33257419a7fSflorian 	main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0);
33357419a7fSflorian 
33457419a7fSflorian #ifndef SMALL
3354b9fcc1bSflorian 	if (control_fd != -1)
33657419a7fSflorian 		main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0);
337a41cc082Sflorian 	main_imsg_send_config(main_conf);
33857419a7fSflorian #endif /* SMALL */
33957419a7fSflorian 
34057419a7fSflorian 	main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0);
34157419a7fSflorian 
34257419a7fSflorian 	event_dispatch();
34357419a7fSflorian 
34457419a7fSflorian 	main_shutdown();
34557419a7fSflorian 	return (0);
34657419a7fSflorian }
34757419a7fSflorian 
34857419a7fSflorian __dead void
main_shutdown(void)34957419a7fSflorian main_shutdown(void)
35057419a7fSflorian {
35157419a7fSflorian 	pid_t	 pid;
35257419a7fSflorian 	int	 status;
35357419a7fSflorian 
35457419a7fSflorian 	/* Close pipes. */
35557419a7fSflorian 	msgbuf_clear(&iev_frontend->ibuf.w);
35657419a7fSflorian 	close(iev_frontend->ibuf.fd);
35757419a7fSflorian 	msgbuf_clear(&iev_engine->ibuf.w);
35857419a7fSflorian 	close(iev_engine->ibuf.fd);
35957419a7fSflorian 
360a41cc082Sflorian #ifndef SMALL
361a41cc082Sflorian 	config_clear(main_conf);
362a41cc082Sflorian #endif /* SMALL */
363a41cc082Sflorian 
36457419a7fSflorian 	log_debug("waiting for children to terminate");
36557419a7fSflorian 	do {
36657419a7fSflorian 		pid = wait(&status);
36757419a7fSflorian 		if (pid == -1) {
36857419a7fSflorian 			if (errno != EINTR && errno != ECHILD)
36957419a7fSflorian 				fatal("wait");
37057419a7fSflorian 		} else if (WIFSIGNALED(status))
37157419a7fSflorian 			log_warnx("%s terminated; signal %d",
37257419a7fSflorian 			    (pid == engine_pid) ? "engine" :
37357419a7fSflorian 			    "frontend", WTERMSIG(status));
37457419a7fSflorian 	} while (pid != -1 || (pid == -1 && errno == EINTR));
37557419a7fSflorian 
37657419a7fSflorian 	free(iev_frontend);
37757419a7fSflorian 	free(iev_engine);
37857419a7fSflorian 
37957419a7fSflorian 	log_info("terminating");
38057419a7fSflorian 	exit(0);
38157419a7fSflorian }
38257419a7fSflorian 
38357419a7fSflorian static pid_t
start_child(enum dhcpleased_process p,char * argv0,int fd,int debug,int verbose)38457419a7fSflorian start_child(enum dhcpleased_process p, char *argv0, int fd, int debug, int
38557419a7fSflorian     verbose)
38657419a7fSflorian {
38757419a7fSflorian 	char	*argv[7];
38857419a7fSflorian 	int	 argc = 0;
38957419a7fSflorian 	pid_t	 pid;
39057419a7fSflorian 
39157419a7fSflorian 	switch (pid = fork()) {
39257419a7fSflorian 	case -1:
39357419a7fSflorian 		fatal("cannot fork");
39457419a7fSflorian 	case 0:
39557419a7fSflorian 		break;
39657419a7fSflorian 	default:
39757419a7fSflorian 		close(fd);
39857419a7fSflorian 		return (pid);
39957419a7fSflorian 	}
40057419a7fSflorian 
40157419a7fSflorian 	if (fd != 3) {
40257419a7fSflorian 		if (dup2(fd, 3) == -1)
40357419a7fSflorian 			fatal("cannot setup imsg fd");
40457419a7fSflorian 	} else if (fcntl(fd, F_SETFD, 0) == -1)
40557419a7fSflorian 		fatal("cannot setup imsg fd");
40657419a7fSflorian 
40757419a7fSflorian 	argv[argc++] = argv0;
40857419a7fSflorian 	switch (p) {
40957419a7fSflorian 	case PROC_MAIN:
41057419a7fSflorian 		fatalx("Can not start main process");
41157419a7fSflorian 	case PROC_ENGINE:
41257419a7fSflorian 		argv[argc++] = "-E";
41357419a7fSflorian 		break;
41457419a7fSflorian 	case PROC_FRONTEND:
41557419a7fSflorian 		argv[argc++] = "-F";
41657419a7fSflorian 		break;
41757419a7fSflorian 	}
41857419a7fSflorian 	if (debug)
41957419a7fSflorian 		argv[argc++] = "-d";
42057419a7fSflorian 	if (verbose)
42157419a7fSflorian 		argv[argc++] = "-v";
42257419a7fSflorian 	if (verbose > 1)
42357419a7fSflorian 		argv[argc++] = "-v";
42457419a7fSflorian 	argv[argc++] = NULL;
42557419a7fSflorian 
42657419a7fSflorian 	execvp(argv0, argv);
42757419a7fSflorian 	fatal("execvp");
42857419a7fSflorian }
42957419a7fSflorian 
43057419a7fSflorian void
main_dispatch_frontend(int fd,short event,void * bula)43157419a7fSflorian main_dispatch_frontend(int fd, short event, void *bula)
43257419a7fSflorian {
43357419a7fSflorian 	struct imsgev		*iev = bula;
43457419a7fSflorian 	struct imsgbuf		*ibuf;
43557419a7fSflorian 	struct imsg		 imsg;
43657419a7fSflorian 	struct imsg_ifinfo	 imsg_ifinfo;
43757419a7fSflorian 	ssize_t			 n;
43857419a7fSflorian 	int			 shut = 0;
43957419a7fSflorian 	uint32_t		 if_index;
44057419a7fSflorian #ifndef	SMALL
44157419a7fSflorian 	int			 verbose;
44257419a7fSflorian #endif	/* SMALL */
44357419a7fSflorian 
44457419a7fSflorian 	ibuf = &iev->ibuf;
44557419a7fSflorian 
44657419a7fSflorian 	if (event & EV_READ) {
44757419a7fSflorian 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
44857419a7fSflorian 			fatal("imsg_read error");
44957419a7fSflorian 		if (n == 0)	/* Connection closed. */
45057419a7fSflorian 			shut = 1;
45157419a7fSflorian 	}
45257419a7fSflorian 	if (event & EV_WRITE) {
45357419a7fSflorian 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
45457419a7fSflorian 			fatal("msgbuf_write");
45557419a7fSflorian 		if (n == 0)	/* Connection closed. */
45657419a7fSflorian 			shut = 1;
45757419a7fSflorian 	}
45857419a7fSflorian 
45957419a7fSflorian 	for (;;) {
46057419a7fSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
46157419a7fSflorian 			fatal("imsg_get");
46257419a7fSflorian 		if (n == 0)	/* No more messages. */
46357419a7fSflorian 			break;
46457419a7fSflorian 
46557419a7fSflorian 		switch (imsg.hdr.type) {
46657419a7fSflorian 		case IMSG_OPEN_BPFSOCK:
46757419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
46857419a7fSflorian 				fatalx("%s: IMSG_OPEN_BPFSOCK wrong length: "
46957419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
47057419a7fSflorian 			memcpy(&if_index, imsg.data, sizeof(if_index));
47157419a7fSflorian 			open_bpfsock(if_index);
47257419a7fSflorian 			break;
47357419a7fSflorian #ifndef	SMALL
474a41cc082Sflorian 		case IMSG_CTL_RELOAD:
475a41cc082Sflorian 			if (main_reload() == -1)
476a41cc082Sflorian 				log_warnx("configuration reload failed");
477a41cc082Sflorian 			else
478a41cc082Sflorian 				log_warnx("configuration reloaded");
479a41cc082Sflorian 			break;
48057419a7fSflorian 		case IMSG_CTL_LOG_VERBOSE:
48157419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
48257419a7fSflorian 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
48357419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
48457419a7fSflorian 			memcpy(&verbose, imsg.data, sizeof(verbose));
48557419a7fSflorian 			log_setverbose(verbose);
48657419a7fSflorian 			break;
48757419a7fSflorian #endif	/* SMALL */
48857419a7fSflorian 		case IMSG_UPDATE_IF:
48957419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo))
49057419a7fSflorian 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
49157419a7fSflorian 				    __func__, IMSG_DATA_SIZE(imsg));
49257419a7fSflorian 			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
4936e93e3e9Sflorian 			read_lease_file(&imsg_ifinfo);
4946e93e3e9Sflorian 			main_imsg_compose_engine(IMSG_UPDATE_IF, -1,
4956e93e3e9Sflorian 			    &imsg_ifinfo, sizeof(imsg_ifinfo));
49657419a7fSflorian 			break;
49757419a7fSflorian 		default:
49857419a7fSflorian 			log_debug("%s: error handling imsg %d", __func__,
49957419a7fSflorian 			    imsg.hdr.type);
50057419a7fSflorian 			break;
50157419a7fSflorian 		}
50257419a7fSflorian 		imsg_free(&imsg);
50357419a7fSflorian 	}
50457419a7fSflorian 	if (!shut)
50557419a7fSflorian 		imsg_event_add(iev);
50657419a7fSflorian 	else {
50757419a7fSflorian 		/* This pipe is dead. Remove its event handler */
50857419a7fSflorian 		event_del(&iev->ev);
50957419a7fSflorian 		event_loopexit(NULL);
51057419a7fSflorian 	}
51157419a7fSflorian }
51257419a7fSflorian 
51357419a7fSflorian void
main_dispatch_engine(int fd,short event,void * bula)51457419a7fSflorian main_dispatch_engine(int fd, short event, void *bula)
51557419a7fSflorian {
51657419a7fSflorian 	struct imsgev			*iev = bula;
51757419a7fSflorian 	struct imsgbuf			*ibuf;
51857419a7fSflorian 	struct imsg			 imsg;
51957419a7fSflorian 	ssize_t				 n;
52057419a7fSflorian 	int				 shut = 0;
52157419a7fSflorian 
52257419a7fSflorian 	ibuf = &iev->ibuf;
52357419a7fSflorian 
52457419a7fSflorian 	if (event & EV_READ) {
52557419a7fSflorian 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
52657419a7fSflorian 			fatal("imsg_read error");
52757419a7fSflorian 		if (n == 0)	/* Connection closed. */
52857419a7fSflorian 			shut = 1;
52957419a7fSflorian 	}
53057419a7fSflorian 	if (event & EV_WRITE) {
53157419a7fSflorian 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
53257419a7fSflorian 			fatal("msgbuf_write");
53357419a7fSflorian 		if (n == 0)	/* Connection closed. */
53457419a7fSflorian 			shut = 1;
53557419a7fSflorian 	}
53657419a7fSflorian 
53757419a7fSflorian 	for (;;) {
53857419a7fSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
53957419a7fSflorian 			fatal("imsg_get");
54057419a7fSflorian 		if (n == 0)	/* No more messages. */
54157419a7fSflorian 			break;
54257419a7fSflorian 
54357419a7fSflorian 		switch (imsg.hdr.type) {
54457419a7fSflorian 		case IMSG_CONFIGURE_INTERFACE: {
54557419a7fSflorian 			struct imsg_configure_interface imsg_interface;
54657419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface))
54757419a7fSflorian 				fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
54857419a7fSflorian 				    "length: %lu", __func__,
54957419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
55057419a7fSflorian 			memcpy(&imsg_interface, imsg.data,
55157419a7fSflorian 			    sizeof(imsg_interface));
552351dd593Sflorian 			if (imsg_interface.routes_len >= MAX_DHCP_ROUTES)
553351dd593Sflorian 				fatalx("%s: too many routes in imsg", __func__);
55457419a7fSflorian 			configure_interface(&imsg_interface);
55557419a7fSflorian 			break;
55657419a7fSflorian 		}
55757419a7fSflorian 		case IMSG_DECONFIGURE_INTERFACE: {
55857419a7fSflorian 			struct imsg_configure_interface imsg_interface;
55957419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface))
56057419a7fSflorian 				fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
56157419a7fSflorian 				    "length: %lu", __func__,
56257419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
56357419a7fSflorian 			memcpy(&imsg_interface, imsg.data,
56457419a7fSflorian 			    sizeof(imsg_interface));
565351dd593Sflorian 			if (imsg_interface.routes_len >= MAX_DHCP_ROUTES)
566351dd593Sflorian 				fatalx("%s: too many routes in imsg", __func__);
56757419a7fSflorian 			deconfigure_interface(&imsg_interface);
56857419a7fSflorian 			main_imsg_compose_frontend(IMSG_CLOSE_UDPSOCK, -1,
56957419a7fSflorian 			    &imsg_interface.if_index,
57057419a7fSflorian 			    sizeof(imsg_interface.if_index));
57157419a7fSflorian 			break;
57257419a7fSflorian 		}
573c2bc6c6dSflorian 		case IMSG_WITHDRAW_ROUTES: {
574c2bc6c6dSflorian 			struct imsg_configure_interface imsg_interface;
575c2bc6c6dSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface))
576c2bc6c6dSflorian 				fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
577c2bc6c6dSflorian 				    "length: %lu", __func__,
578c2bc6c6dSflorian 				    IMSG_DATA_SIZE(imsg));
579c2bc6c6dSflorian 			memcpy(&imsg_interface, imsg.data,
580c2bc6c6dSflorian 			    sizeof(imsg_interface));
581c2bc6c6dSflorian 			if (imsg_interface.routes_len >= MAX_DHCP_ROUTES)
582c2bc6c6dSflorian 				fatalx("%s: too many routes in imsg", __func__);
583c2bc6c6dSflorian 			if (imsg_interface.routes_len > 0)
584c2bc6c6dSflorian 				configure_routes(RTM_DELETE, &imsg_interface);
585c2bc6c6dSflorian 			break;
586c2bc6c6dSflorian 		}
58757419a7fSflorian 		case IMSG_PROPOSE_RDNS: {
58857419a7fSflorian 			struct imsg_propose_rdns	 rdns;
58957419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(rdns))
59057419a7fSflorian 				fatalx("%s: IMSG_PROPOSE_RDNS wrong "
59157419a7fSflorian 				    "length: %lu", __func__,
59257419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
59357419a7fSflorian 			memcpy(&rdns, imsg.data, sizeof(rdns));
59457419a7fSflorian 			if ((2 + rdns.rdns_count * sizeof(struct in_addr)) >
59557419a7fSflorian 			    sizeof(struct sockaddr_rtdns))
59657419a7fSflorian 				fatalx("%s: rdns_count too big: %d", __func__,
59757419a7fSflorian 				    rdns.rdns_count);
59857419a7fSflorian 			propose_rdns(&rdns);
59957419a7fSflorian 			break;
60057419a7fSflorian 		}
60157419a7fSflorian 		case IMSG_WITHDRAW_RDNS: {
60257419a7fSflorian 			struct imsg_propose_rdns	 rdns;
60357419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(rdns))
604*4f8d227cSflorian 				fatalx("%s: IMSG_WITHDRAW_RDNS wrong "
60557419a7fSflorian 				    "length: %lu", __func__,
60657419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
60757419a7fSflorian 			memcpy(&rdns, imsg.data, sizeof(rdns));
60857419a7fSflorian 			if (rdns.rdns_count != 0)
60957419a7fSflorian 				fatalx("%s: expected rdns_count == 0: %d",
61057419a7fSflorian 				    __func__, rdns.rdns_count);
61157419a7fSflorian 			propose_rdns(&rdns);
61257419a7fSflorian 			break;
61357419a7fSflorian 		}
61457419a7fSflorian 		default:
61557419a7fSflorian 			log_debug("%s: error handling imsg %d", __func__,
61657419a7fSflorian 			    imsg.hdr.type);
61757419a7fSflorian 			break;
61857419a7fSflorian 		}
61957419a7fSflorian 		imsg_free(&imsg);
62057419a7fSflorian 	}
62157419a7fSflorian 	if (!shut)
62257419a7fSflorian 		imsg_event_add(iev);
62357419a7fSflorian 	else {
62457419a7fSflorian 		/* This pipe is dead. Remove its event handler. */
62557419a7fSflorian 		event_del(&iev->ev);
62657419a7fSflorian 		event_loopexit(NULL);
62757419a7fSflorian 	}
62857419a7fSflorian }
62957419a7fSflorian 
63057419a7fSflorian int
main_imsg_compose_frontend(int type,int fd,void * data,uint16_t datalen)63157419a7fSflorian main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen)
63257419a7fSflorian {
63357419a7fSflorian 	if (iev_frontend)
63457419a7fSflorian 		return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data,
63557419a7fSflorian 		    datalen));
63657419a7fSflorian 	else
63757419a7fSflorian 		return (-1);
63857419a7fSflorian }
63957419a7fSflorian 
64057419a7fSflorian int
main_imsg_compose_engine(int type,int fd,void * data,uint16_t datalen)64157419a7fSflorian main_imsg_compose_engine(int type, int fd, void *data, uint16_t datalen)
64257419a7fSflorian {
64357419a7fSflorian 	if (iev_engine)
64457419a7fSflorian 		return(imsg_compose_event(iev_engine, type, 0, 0, fd, data,
64557419a7fSflorian 		    datalen));
64657419a7fSflorian 	else
64757419a7fSflorian 		return (-1);
64857419a7fSflorian }
64957419a7fSflorian 
65057419a7fSflorian void
imsg_event_add(struct imsgev * iev)65157419a7fSflorian imsg_event_add(struct imsgev *iev)
65257419a7fSflorian {
65357419a7fSflorian 	iev->events = EV_READ;
65457419a7fSflorian 	if (iev->ibuf.w.queued)
65557419a7fSflorian 		iev->events |= EV_WRITE;
65657419a7fSflorian 
65757419a7fSflorian 	event_del(&iev->ev);
65857419a7fSflorian 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
65957419a7fSflorian 	event_add(&iev->ev, NULL);
66057419a7fSflorian }
66157419a7fSflorian 
66257419a7fSflorian int
imsg_compose_event(struct imsgev * iev,uint16_t type,uint32_t peerid,pid_t pid,int fd,void * data,uint16_t datalen)66357419a7fSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
66457419a7fSflorian     pid_t pid, int fd, void *data, uint16_t datalen)
66557419a7fSflorian {
66657419a7fSflorian 	int	ret;
66757419a7fSflorian 
66857419a7fSflorian 	if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data,
66957419a7fSflorian 	    datalen)) != -1)
67057419a7fSflorian 		imsg_event_add(iev);
67157419a7fSflorian 
67257419a7fSflorian 	return (ret);
67357419a7fSflorian }
67457419a7fSflorian 
67557419a7fSflorian static int
main_imsg_send_ipc_sockets(struct imsgbuf * frontend_buf,struct imsgbuf * engine_buf)67657419a7fSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
67757419a7fSflorian     struct imsgbuf *engine_buf)
67857419a7fSflorian {
67957419a7fSflorian 	int pipe_frontend2engine[2];
68057419a7fSflorian 
68157419a7fSflorian 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
68257419a7fSflorian 	    PF_UNSPEC, pipe_frontend2engine) == -1)
68357419a7fSflorian 		return (-1);
68457419a7fSflorian 
68557419a7fSflorian 	if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0,
68657419a7fSflorian 	    pipe_frontend2engine[0], NULL, 0) == -1)
68757419a7fSflorian 		return (-1);
68857419a7fSflorian 	imsg_flush(frontend_buf);
68957419a7fSflorian 	if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0,
69057419a7fSflorian 	    pipe_frontend2engine[1], NULL, 0) == -1)
69157419a7fSflorian 		return (-1);
69257419a7fSflorian 	imsg_flush(engine_buf);
69357419a7fSflorian 	return (0);
69457419a7fSflorian }
69557419a7fSflorian 
696a41cc082Sflorian #ifndef SMALL
697a41cc082Sflorian int
main_reload(void)698a41cc082Sflorian main_reload(void)
699a41cc082Sflorian {
700a41cc082Sflorian 	struct dhcpleased_conf *xconf;
701a41cc082Sflorian 
702a41cc082Sflorian 	if ((xconf = parse_config(conffile)) == NULL)
703a41cc082Sflorian 		return (-1);
704a41cc082Sflorian 
705a41cc082Sflorian 	if (main_imsg_send_config(xconf) == -1)
706a41cc082Sflorian 		return (-1);
707a41cc082Sflorian 
708a41cc082Sflorian 	merge_config(main_conf, xconf);
709a41cc082Sflorian 
710a41cc082Sflorian 	return (0);
711a41cc082Sflorian }
712a41cc082Sflorian 
713a41cc082Sflorian int
main_imsg_send_config(struct dhcpleased_conf * xconf)714a41cc082Sflorian main_imsg_send_config(struct dhcpleased_conf *xconf)
715a41cc082Sflorian {
716a41cc082Sflorian 	struct iface_conf	*iface_conf;
717a41cc082Sflorian 
718a41cc082Sflorian 	main_imsg_compose_frontend(IMSG_RECONF_CONF, -1, NULL, 0);
719a41cc082Sflorian 	main_imsg_compose_engine(IMSG_RECONF_CONF, -1, NULL, 0);
720a41cc082Sflorian 
721a41cc082Sflorian 	/* Send the interface list to the frontend & engine. */
722a41cc082Sflorian 	SIMPLEQ_FOREACH(iface_conf, &xconf->iface_list, entry) {
723a41cc082Sflorian 		main_imsg_compose_frontend(IMSG_RECONF_IFACE, -1, iface_conf,
724a41cc082Sflorian 		    sizeof(*iface_conf));
725a41cc082Sflorian 		main_imsg_compose_engine(IMSG_RECONF_IFACE, -1, iface_conf,
726a41cc082Sflorian 		    sizeof(*iface_conf));
727a41cc082Sflorian 		main_imsg_compose_frontend(IMSG_RECONF_VC_ID, -1,
728a41cc082Sflorian 		    iface_conf->vc_id, iface_conf->vc_id_len);
729a41cc082Sflorian 		main_imsg_compose_engine(IMSG_RECONF_VC_ID, -1,
730a41cc082Sflorian 		    iface_conf->vc_id, iface_conf->vc_id_len);
731a41cc082Sflorian 		main_imsg_compose_frontend(IMSG_RECONF_C_ID, -1,
732a41cc082Sflorian 		    iface_conf->c_id, iface_conf->c_id_len);
733a41cc082Sflorian 		main_imsg_compose_engine(IMSG_RECONF_C_ID, -1,
734a41cc082Sflorian 		    iface_conf->c_id, iface_conf->c_id_len);
735b3441518Sflorian 		if (iface_conf->h_name != NULL)
736b3441518Sflorian 			main_imsg_compose_frontend(IMSG_RECONF_H_NAME, -1,
737b3441518Sflorian 			    iface_conf->h_name, strlen(iface_conf->h_name) + 1);
738a41cc082Sflorian 	}
739a41cc082Sflorian 
740a41cc082Sflorian 	/* Config is now complete. */
741a41cc082Sflorian 	main_imsg_compose_frontend(IMSG_RECONF_END, -1, NULL, 0);
742a41cc082Sflorian 	main_imsg_compose_engine(IMSG_RECONF_END, -1, NULL, 0);
743a41cc082Sflorian 
744a41cc082Sflorian 	return (0);
745a41cc082Sflorian }
746a41cc082Sflorian #endif /* SMALL */
747a41cc082Sflorian 
74857419a7fSflorian void
configure_interface(struct imsg_configure_interface * imsg)74957419a7fSflorian configure_interface(struct imsg_configure_interface *imsg)
75057419a7fSflorian {
75157419a7fSflorian 	struct ifaliasreq	 ifaliasreq;
75257419a7fSflorian 	struct ifaddrs		*ifap, *ifa;
75357419a7fSflorian 	struct sockaddr_in	*req_sin_addr, *req_sin_mask;
75457419a7fSflorian 	int			 found = 0, udpsock, opt = 1, len, fd = -1;
75557419a7fSflorian 	char			*if_name;
756ebace80cSflorian 	char			 ip_ntop_buf[INET_ADDRSTRLEN];
757ebace80cSflorian 	char			 nextserver_ntop_buf[INET_ADDRSTRLEN];
75857419a7fSflorian 	char			 lease_buf[LEASE_SIZE];
759131c304bSflorian 	char			 lease_file_buf[sizeof(_PATH_LEASE) +
76057419a7fSflorian 	    IF_NAMESIZE];
761131c304bSflorian 	char			 tmpl[] = _PATH_LEASE"XXXXXXXXXX";
76257419a7fSflorian 
76357419a7fSflorian 	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
76457419a7fSflorian 
76557419a7fSflorian 	if_name = if_indextoname(imsg->if_index, ifaliasreq.ifra_name);
76657419a7fSflorian 	if (if_name == NULL) {
76757419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__,
76857419a7fSflorian 		    imsg->if_index);
76957419a7fSflorian 		return;
77057419a7fSflorian 	}
77157419a7fSflorian 
772e998cdbeSflorian 	log_debug("%s %s", __func__, if_name);
773e998cdbeSflorian 
77457419a7fSflorian 	if (getifaddrs(&ifap) != 0)
77557419a7fSflorian 		fatal("getifaddrs");
77657419a7fSflorian 
77757419a7fSflorian 	req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
77857419a7fSflorian 	req_sin_addr->sin_family = AF_INET;
77957419a7fSflorian 	req_sin_addr->sin_len = sizeof(*req_sin_addr);
78057419a7fSflorian 
78157419a7fSflorian 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
78257419a7fSflorian 		struct in_addr	 addr, mask;
78357419a7fSflorian 
78457419a7fSflorian 		if (strcmp(if_name, ifa->ifa_name) != 0)
78557419a7fSflorian 			continue;
78657419a7fSflorian 		if (ifa->ifa_addr == NULL)
78757419a7fSflorian 			continue;
78857419a7fSflorian 		if (ifa->ifa_addr->sa_family != AF_INET)
78957419a7fSflorian 			continue;
79057419a7fSflorian 
791b2b40540Sflorian 		addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
792b2b40540Sflorian 		mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
79357419a7fSflorian 
79457419a7fSflorian 		if (imsg->addr.s_addr == addr.s_addr) {
79557419a7fSflorian 			if (imsg->mask.s_addr == mask.s_addr)
79657419a7fSflorian 				found = 1;
79757419a7fSflorian 			else {
798b2b40540Sflorian 				req_sin_addr->sin_addr = addr;
79957419a7fSflorian 				if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq)
80057419a7fSflorian 				    == -1) {
80157419a7fSflorian 					if (errno != EADDRNOTAVAIL)
80257419a7fSflorian 						log_warn("SIOCDIFADDR");
80357419a7fSflorian 				}
80457419a7fSflorian 			}
80557419a7fSflorian 			break;
80657419a7fSflorian 		}
80757419a7fSflorian 	}
8083c46ceeaSotto 	freeifaddrs(ifap);
80957419a7fSflorian 
810b2b40540Sflorian 	req_sin_addr->sin_addr = imsg->addr;
81157419a7fSflorian 	if (!found) {
81257419a7fSflorian 		req_sin_mask = (struct sockaddr_in *)&ifaliasreq.ifra_mask;
81357419a7fSflorian 		req_sin_mask->sin_family = AF_INET;
81457419a7fSflorian 		req_sin_mask->sin_len = sizeof(*req_sin_mask);
815b2b40540Sflorian 		req_sin_mask->sin_addr = imsg->mask;
81657419a7fSflorian 		if (ioctl(ioctl_sock, SIOCAIFADDR, &ifaliasreq) == -1)
817db7d8776Sflorian 			log_warn("SIOCAIFADDR");
818665300f1Sstsp 	}
819351dd593Sflorian 	if (imsg->routes_len > 0)
820351dd593Sflorian 		configure_routes(RTM_ADD, imsg);
821665300f1Sstsp 
82257419a7fSflorian 	req_sin_addr->sin_port = ntohs(CLIENT_PORT);
82357419a7fSflorian 	if ((udpsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
82457419a7fSflorian 		log_warn("socket");
82557419a7fSflorian 		return;
82657419a7fSflorian 	}
82757419a7fSflorian 	if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, &opt,
82857419a7fSflorian 	    sizeof(opt)) == -1)
82957419a7fSflorian 		log_warn("setting SO_REUSEADDR on socket");
83057419a7fSflorian 
83157419a7fSflorian 	if (setsockopt(udpsock, SOL_SOCKET, SO_RTABLE, &imsg->rdomain,
83257419a7fSflorian 	    sizeof(imsg->rdomain)) == -1) {
83357419a7fSflorian 		/* we might race against removal of the rdomain */
83457419a7fSflorian 		log_warn("setsockopt SO_RTABLE");
83557419a7fSflorian 		close(udpsock);
83657419a7fSflorian 		return;
83757419a7fSflorian 	}
83857419a7fSflorian 
83957419a7fSflorian 	if (bind(udpsock, (struct sockaddr *)req_sin_addr,
84057419a7fSflorian 	    sizeof(*req_sin_addr)) == -1) {
84157419a7fSflorian 		close(udpsock);
84257419a7fSflorian 		return;
84357419a7fSflorian 	}
84457419a7fSflorian 
84557419a7fSflorian 	shutdown(udpsock, SHUT_RD);
846e998cdbeSflorian 
84757419a7fSflorian 	main_imsg_compose_frontend(IMSG_UDPSOCK, udpsock,
84857419a7fSflorian 	    &imsg->if_index, sizeof(imsg->if_index));
84957419a7fSflorian 
850ae968ffdSflorian 	if (no_lease_files)
851ae968ffdSflorian 		return;
852ae968ffdSflorian 
853ebace80cSflorian 	if (inet_ntop(AF_INET, &imsg->addr, ip_ntop_buf, sizeof(ip_ntop_buf)) ==
85457419a7fSflorian 	    NULL) {
85557419a7fSflorian 		log_warn("%s: inet_ntop", __func__);
85657419a7fSflorian 		return;
85757419a7fSflorian 	}
85857419a7fSflorian 
859ebace80cSflorian 	if (imsg->siaddr.s_addr == INADDR_ANY)
860ebace80cSflorian 		nextserver_ntop_buf[0] = '\0';
861ebace80cSflorian 	else {
862ebace80cSflorian 		if (inet_ntop(AF_INET, &imsg->siaddr, nextserver_ntop_buf,
863ebace80cSflorian 		    sizeof(nextserver_ntop_buf)) == NULL) {
864ebace80cSflorian 			log_warn("%s: inet_ntop", __func__);
865ebace80cSflorian 			return;
866ebace80cSflorian 		}
867ebace80cSflorian 	}
86857419a7fSflorian 	len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s",
869131c304bSflorian 	    _PATH_LEASE, if_name);
87057419a7fSflorian 	if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) {
87157419a7fSflorian 		log_warnx("%s: failed to encode lease path for %s", __func__,
87257419a7fSflorian 		    if_name);
87357419a7fSflorian 		return;
87457419a7fSflorian 	}
87557419a7fSflorian 
876ebace80cSflorian 	len = snprintf(lease_buf, sizeof(lease_buf),
877ebace80cSflorian 	    "%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n",
878ebace80cSflorian 	    LEASE_VERSION, LEASE_IP_PREFIX, ip_ntop_buf,
879ebace80cSflorian 	    LEASE_NEXTSERVER_PREFIX, nextserver_ntop_buf, LEASE_BOOTFILE_PREFIX,
880ebace80cSflorian 	    imsg->file, LEASE_HOSTNAME_PREFIX, imsg->hostname,
881ebace80cSflorian 	    LEASE_DOMAIN_PREFIX, imsg->domainname);
88257419a7fSflorian 	if ( len == -1 || (size_t) len >= sizeof(lease_buf)) {
88357419a7fSflorian 		log_warnx("%s: failed to encode lease for %s", __func__,
884ebace80cSflorian 		    ip_ntop_buf);
88557419a7fSflorian 		return;
88657419a7fSflorian 	}
88757419a7fSflorian 
88857419a7fSflorian 	if ((fd = mkstemp(tmpl)) == -1) {
88957419a7fSflorian 		log_warn("%s: mkstemp", __func__);
89057419a7fSflorian 		return;
89157419a7fSflorian 	}
89257419a7fSflorian 
89357419a7fSflorian 	if (write(fd, lease_buf, len) < len)
89457419a7fSflorian 		goto err;
89557419a7fSflorian 
89657419a7fSflorian 	if (fchmod(fd, 0644) == -1)
89757419a7fSflorian 		goto err;
89857419a7fSflorian 
89957419a7fSflorian 	if (close(fd) == -1)
90057419a7fSflorian 		goto err;
90157419a7fSflorian 	fd = -1;
90257419a7fSflorian 
90357419a7fSflorian 	if (rename(tmpl, lease_file_buf) == -1)
90457419a7fSflorian 		goto err;
90557419a7fSflorian 	return;
90657419a7fSflorian  err:
90757419a7fSflorian 	log_warn("%s", __func__);
90857419a7fSflorian 	if (fd != -1)
90957419a7fSflorian 		close(fd);
91057419a7fSflorian 	unlink(tmpl);
91157419a7fSflorian }
91257419a7fSflorian 
91357419a7fSflorian void
deconfigure_interface(struct imsg_configure_interface * imsg)91457419a7fSflorian deconfigure_interface(struct imsg_configure_interface *imsg)
91557419a7fSflorian {
91657419a7fSflorian 	struct ifaliasreq	 ifaliasreq;
91757419a7fSflorian 	struct sockaddr_in	*req_sin_addr;
91857419a7fSflorian 
91957419a7fSflorian 	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
92057419a7fSflorian 
921e9dce5e7Sflorian #if 0
922e9dce5e7Sflorian 	/*
923e9dce5e7Sflorian 	 * When two default routes have the same gateway the kernel always
924e9dce5e7Sflorian 	 * deletes the first which might be the wrong one. When we then
925e9dce5e7Sflorian 	 * deconfigure the IP address from the interface the kernel deletes
926e9dce5e7Sflorian 	 * all routes pointing out that interface and we end up with no
927e9dce5e7Sflorian 	 * default.
928e9dce5e7Sflorian 	 * This can happen with a wired & wireless interface on the same
929e9dce5e7Sflorian 	 * layer 2 network and the user issues ifconfig $WIFI inet -autoconf.
930e9dce5e7Sflorian 	 * Work around this issue by not deleting the default route and let
931e9dce5e7Sflorian 	 * the kernel handle it when we remove the IP address a few lines
932e9dce5e7Sflorian 	 * down.
933e9dce5e7Sflorian 	 */
934351dd593Sflorian 	if (imsg->routes_len > 0)
935351dd593Sflorian 		configure_routes(RTM_DELETE, imsg);
936e9dce5e7Sflorian #endif
9377bd66a84Sflorian 
93857419a7fSflorian 	if (if_indextoname(imsg->if_index, ifaliasreq.ifra_name) == NULL) {
93957419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__,
94057419a7fSflorian 		    imsg->if_index);
94157419a7fSflorian 		return;
94257419a7fSflorian 	}
94357419a7fSflorian 
944e998cdbeSflorian 	log_debug("%s %s", __func__, ifaliasreq.ifra_name);
945e998cdbeSflorian 
94657419a7fSflorian 	req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
94757419a7fSflorian 	req_sin_addr->sin_family = AF_INET;
94857419a7fSflorian 	req_sin_addr->sin_len = sizeof(*req_sin_addr);
94957419a7fSflorian 
950b2b40540Sflorian 	req_sin_addr->sin_addr = imsg->addr;
95157419a7fSflorian 	if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq) == -1) {
95257419a7fSflorian 		if (errno != EADDRNOTAVAIL)
95357419a7fSflorian 			log_warn("SIOCDIFADDR");
95457419a7fSflorian 	}
95557419a7fSflorian }
95657419a7fSflorian 
957351dd593Sflorian void
configure_routes(uint8_t rtm_type,struct imsg_configure_interface * imsg)958351dd593Sflorian configure_routes(uint8_t rtm_type, struct imsg_configure_interface *imsg)
959351dd593Sflorian {
960351dd593Sflorian 	struct sockaddr_in	 dst, mask, gw, ifa;
961351dd593Sflorian 	in_addr_t		 addrnet, gwnet;
962351dd593Sflorian 	int			 i;
963351dd593Sflorian 
964351dd593Sflorian 	memset(&ifa, 0, sizeof(ifa));
965351dd593Sflorian 	ifa.sin_family = AF_INET;
966351dd593Sflorian 	ifa.sin_len = sizeof(ifa);
967b2b40540Sflorian 	ifa.sin_addr = imsg->addr;
968351dd593Sflorian 
969351dd593Sflorian 	memset(&dst, 0, sizeof(dst));
970351dd593Sflorian 	dst.sin_family = AF_INET;
971351dd593Sflorian 	dst.sin_len = sizeof(dst);
972351dd593Sflorian 
973351dd593Sflorian 	memset(&mask, 0, sizeof(mask));
974351dd593Sflorian 	mask.sin_family = AF_INET;
975351dd593Sflorian 	mask.sin_len = sizeof(mask);
976351dd593Sflorian 
977351dd593Sflorian 	memset(&gw, 0, sizeof(gw));
978351dd593Sflorian 	gw.sin_family = AF_INET;
979351dd593Sflorian 	gw.sin_len = sizeof(gw);
980351dd593Sflorian 
981351dd593Sflorian 	addrnet = imsg->addr.s_addr & imsg->mask.s_addr;
982351dd593Sflorian 
983351dd593Sflorian 	for (i = 0; i < imsg->routes_len; i++) {
984b2b40540Sflorian 		dst.sin_addr = imsg->routes[i].dst;
985b2b40540Sflorian 		mask.sin_addr = imsg->routes[i].mask;
986b2b40540Sflorian 		gw.sin_addr = imsg->routes[i].gw;
987351dd593Sflorian 
988351dd593Sflorian 		if (gw.sin_addr.s_addr == INADDR_ANY) {
989351dd593Sflorian 			/* direct route */
990351dd593Sflorian 			configure_route(rtm_type, imsg->if_index,
991351dd593Sflorian 			    imsg->rdomain, &dst, &mask, &ifa, NULL,
992351dd593Sflorian 			    RTF_CLONING);
993351dd593Sflorian 		} else if (mask.sin_addr.s_addr == INADDR_ANY) {
994351dd593Sflorian 			/* default route */
995351dd593Sflorian 			gwnet =  gw.sin_addr.s_addr & imsg->mask.s_addr;
996351dd593Sflorian 			if (addrnet != gwnet) {
997351dd593Sflorian 				/*
998351dd593Sflorian 				 * The gateway for the default route is outside
999351dd593Sflorian 				 * the configured prefix. Install a direct
1000351dd593Sflorian 				 * cloning route for the gateway to make the
1001351dd593Sflorian 				 * default route reachable.
1002351dd593Sflorian 				 */
1003351dd593Sflorian 				mask.sin_addr.s_addr = 0xffffffff;
1004351dd593Sflorian 				configure_route(rtm_type, imsg->if_index,
1005351dd593Sflorian 				    imsg->rdomain, &gw, &mask, &ifa, NULL,
1006351dd593Sflorian 				    RTF_CLONING);
1007b2b40540Sflorian 				mask.sin_addr = imsg->routes[i].mask;
1008351dd593Sflorian 			}
1009351dd593Sflorian 
1010351dd593Sflorian 			if (gw.sin_addr.s_addr == ifa.sin_addr.s_addr) {
1011351dd593Sflorian 				/* directly connected default */
1012351dd593Sflorian 				configure_route(rtm_type, imsg->if_index,
1013351dd593Sflorian 				    imsg->rdomain, &dst, &mask, &gw, NULL, 0);
1014351dd593Sflorian 			} else {
1015351dd593Sflorian 				/* default route via gateway */
1016351dd593Sflorian 				configure_route(rtm_type, imsg->if_index,
1017351dd593Sflorian 				    imsg->rdomain, &dst, &mask, &gw, &ifa,
1018351dd593Sflorian 				    RTF_GATEWAY);
1019351dd593Sflorian 			}
1020351dd593Sflorian 		} else {
1021351dd593Sflorian 			/* non-default via gateway */
1022351dd593Sflorian 			configure_route(rtm_type, imsg->if_index, imsg->rdomain,
1023351dd593Sflorian 			    &dst, &mask, &gw, NULL, RTF_GATEWAY);
1024351dd593Sflorian 		}
1025351dd593Sflorian 	}
1026351dd593Sflorian }
1027351dd593Sflorian 
102857419a7fSflorian #define	ROUNDUP(a)	\
102957419a7fSflorian     (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
103057419a7fSflorian void
configure_route(uint8_t rtm_type,uint32_t if_index,int rdomain,struct sockaddr_in * dst,struct sockaddr_in * mask,struct sockaddr_in * gw,struct sockaddr_in * ifa,int rtm_flags)1031351dd593Sflorian configure_route(uint8_t rtm_type, uint32_t if_index, int rdomain, struct
1032351dd593Sflorian     sockaddr_in *dst, struct sockaddr_in *mask, struct sockaddr_in *gw,
1033351dd593Sflorian     struct sockaddr_in *ifa, int rtm_flags)
103457419a7fSflorian {
103557419a7fSflorian 	struct rt_msghdr		 rtm;
10365a55e518Sflorian 	struct sockaddr_dl		 ifp;
103757419a7fSflorian 	struct sockaddr_rtlabel		 rl;
10385a55e518Sflorian 	struct iovec			 iov[14];
103957419a7fSflorian 	long				 pad = 0;
104057419a7fSflorian 	int				 iovcnt = 0, padlen;
104157419a7fSflorian 
104257419a7fSflorian 	memset(&rtm, 0, sizeof(rtm));
104357419a7fSflorian 
104457419a7fSflorian 	rtm.rtm_version = RTM_VERSION;
104557419a7fSflorian 	rtm.rtm_type = rtm_type;
104657419a7fSflorian 	rtm.rtm_msglen = sizeof(rtm);
1047351dd593Sflorian 	rtm.rtm_index = if_index;
1048351dd593Sflorian 	rtm.rtm_tableid = rdomain;
104957419a7fSflorian 	rtm.rtm_seq = ++rtm_seq;
105057419a7fSflorian 	rtm.rtm_priority = RTP_NONE;
10515a55e518Sflorian 	rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP |
10525a55e518Sflorian 	    RTA_LABEL;
1053351dd593Sflorian 	rtm.rtm_flags = RTF_UP | RTF_STATIC | RTF_MPATH | rtm_flags;
1054351dd593Sflorian 
1055351dd593Sflorian 	if (ifa)
1056351dd593Sflorian 		rtm.rtm_addrs |= RTA_IFA;
105757419a7fSflorian 
105857419a7fSflorian 	iov[iovcnt].iov_base = &rtm;
105957419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rtm);
106057419a7fSflorian 
1061351dd593Sflorian 	iov[iovcnt].iov_base = dst;
1062351dd593Sflorian 	iov[iovcnt++].iov_len = dst->sin_len;
1063351dd593Sflorian 	rtm.rtm_msglen += dst->sin_len;
1064351dd593Sflorian 	padlen = ROUNDUP(dst->sin_len) - dst->sin_len;
106557419a7fSflorian 	if (padlen > 0) {
106657419a7fSflorian 		iov[iovcnt].iov_base = &pad;
106757419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
106857419a7fSflorian 		rtm.rtm_msglen += padlen;
106957419a7fSflorian 	}
107057419a7fSflorian 
1071351dd593Sflorian 	iov[iovcnt].iov_base = gw;
1072351dd593Sflorian 	iov[iovcnt++].iov_len = gw->sin_len;
1073351dd593Sflorian 	rtm.rtm_msglen += gw->sin_len;
1074351dd593Sflorian 	padlen = ROUNDUP(gw->sin_len) - gw->sin_len;
107557419a7fSflorian 	if (padlen > 0) {
107657419a7fSflorian 		iov[iovcnt].iov_base = &pad;
107757419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
107857419a7fSflorian 		rtm.rtm_msglen += padlen;
107957419a7fSflorian 	}
108057419a7fSflorian 
1081351dd593Sflorian 	iov[iovcnt].iov_base = mask;
1082351dd593Sflorian 	iov[iovcnt++].iov_len = mask->sin_len;
1083351dd593Sflorian 	rtm.rtm_msglen += mask->sin_len;
1084351dd593Sflorian 	padlen = ROUNDUP(mask->sin_len) - mask->sin_len;
108557419a7fSflorian 	if (padlen > 0) {
108657419a7fSflorian 		iov[iovcnt].iov_base = &pad;
108757419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
108857419a7fSflorian 		rtm.rtm_msglen += padlen;
108957419a7fSflorian 	}
109057419a7fSflorian 
10915a55e518Sflorian 	memset(&ifp, 0, sizeof(ifp));
10925a55e518Sflorian 	ifp.sdl_len = sizeof(struct sockaddr_dl);
10935a55e518Sflorian 	ifp.sdl_family = AF_LINK;
10945a55e518Sflorian 	ifp.sdl_index = if_index;
10955a55e518Sflorian 	iov[iovcnt].iov_base = &ifp;
10965a55e518Sflorian 	iov[iovcnt++].iov_len = sizeof(ifp);
10975a55e518Sflorian 	rtm.rtm_msglen += sizeof(ifp);
10985a55e518Sflorian 	padlen = ROUNDUP(sizeof(ifp)) - sizeof(ifp);
10995a55e518Sflorian 	if (padlen > 0) {
11005a55e518Sflorian 		iov[iovcnt].iov_base = &pad;
11015a55e518Sflorian 		iov[iovcnt++].iov_len = padlen;
11025a55e518Sflorian 		rtm.rtm_msglen += padlen;
11035a55e518Sflorian 	}
11045a55e518Sflorian 
1105351dd593Sflorian 	if (ifa) {
1106351dd593Sflorian 		iov[iovcnt].iov_base = ifa;
1107351dd593Sflorian 		iov[iovcnt++].iov_len = ifa->sin_len;
1108351dd593Sflorian 		rtm.rtm_msglen += ifa->sin_len;
1109351dd593Sflorian 		padlen = ROUNDUP(ifa->sin_len) - ifa->sin_len;
11100be69ef6Sflorian 		if (padlen > 0) {
11110be69ef6Sflorian 			iov[iovcnt].iov_base = &pad;
11120be69ef6Sflorian 			iov[iovcnt++].iov_len = padlen;
11130be69ef6Sflorian 			rtm.rtm_msglen += padlen;
11140be69ef6Sflorian 		}
1115351dd593Sflorian 	}
11160be69ef6Sflorian 
111757419a7fSflorian 	memset(&rl, 0, sizeof(rl));
111857419a7fSflorian 	rl.sr_len = sizeof(rl);
111957419a7fSflorian 	rl.sr_family = AF_UNSPEC;
112057419a7fSflorian 	(void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s",
112157419a7fSflorian 	    DHCPLEASED_RTA_LABEL);
112257419a7fSflorian 	iov[iovcnt].iov_base = &rl;
112357419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rl);
112457419a7fSflorian 	rtm.rtm_msglen += sizeof(rl);
112557419a7fSflorian 	padlen = ROUNDUP(sizeof(rl)) - sizeof(rl);
112657419a7fSflorian 	if (padlen > 0) {
112757419a7fSflorian 		iov[iovcnt].iov_base = &pad;
112857419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
112957419a7fSflorian 		rtm.rtm_msglen += padlen;
113057419a7fSflorian 	}
113157419a7fSflorian 
1132e81612d0Sflorian 	if (writev(routesock, iov, iovcnt) == -1) {
1133e81612d0Sflorian 		if (errno != EEXIST)
113457419a7fSflorian 			log_warn("failed to send route message");
113557419a7fSflorian 	}
1136e81612d0Sflorian }
113757419a7fSflorian 
113857419a7fSflorian #ifndef	SMALL
113957419a7fSflorian const char*
sin_to_str(struct sockaddr_in * sin)114057419a7fSflorian sin_to_str(struct sockaddr_in *sin)
114157419a7fSflorian {
114257419a7fSflorian 	static char hbuf[NI_MAXHOST];
114357419a7fSflorian 	int error;
114457419a7fSflorian 
114557419a7fSflorian 	error = getnameinfo((struct sockaddr *)sin, sin->sin_len, hbuf,
114657419a7fSflorian 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
114757419a7fSflorian 	if (error) {
114857419a7fSflorian 		log_warnx("%s", gai_strerror(error));
114957419a7fSflorian 		strlcpy(hbuf, "unknown", sizeof(hbuf));
115057419a7fSflorian 	}
115157419a7fSflorian 	return hbuf;
115257419a7fSflorian }
115357419a7fSflorian #endif	/* SMALL */
115457419a7fSflorian 
115557419a7fSflorian void
open_bpfsock(uint32_t if_index)115657419a7fSflorian open_bpfsock(uint32_t if_index)
115757419a7fSflorian {
115857419a7fSflorian 	int		 bpfsock;
115957419a7fSflorian 	char		 ifname[IF_NAMESIZE];
116057419a7fSflorian 
1161e998cdbeSflorian 	if (if_indextoname(if_index, ifname) == NULL) {
116257419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__, if_index);
116357419a7fSflorian 		return;
116457419a7fSflorian 	}
116557419a7fSflorian 
116657419a7fSflorian 	if ((bpfsock = get_bpf_sock(ifname)) == -1)
116757419a7fSflorian 		return;
116857419a7fSflorian 
116957419a7fSflorian 	main_imsg_compose_frontend(IMSG_BPFSOCK, bpfsock, &if_index,
117057419a7fSflorian 	    sizeof(if_index));
117157419a7fSflorian }
117257419a7fSflorian 
117357419a7fSflorian void
propose_rdns(struct imsg_propose_rdns * rdns)117457419a7fSflorian propose_rdns(struct imsg_propose_rdns *rdns)
117557419a7fSflorian {
117657419a7fSflorian 	struct rt_msghdr		 rtm;
117757419a7fSflorian 	struct sockaddr_rtdns		 rtdns;
117857419a7fSflorian 	struct iovec			 iov[3];
117957419a7fSflorian 	long				 pad = 0;
118057419a7fSflorian 	int				 iovcnt = 0, padlen;
118157419a7fSflorian 
118257419a7fSflorian 	memset(&rtm, 0, sizeof(rtm));
118357419a7fSflorian 
118457419a7fSflorian 	rtm.rtm_version = RTM_VERSION;
118557419a7fSflorian 	rtm.rtm_type = RTM_PROPOSAL;
118657419a7fSflorian 	rtm.rtm_msglen = sizeof(rtm);
118757419a7fSflorian 	rtm.rtm_tableid = rdns->rdomain;
118857419a7fSflorian 	rtm.rtm_index = rdns->if_index;
118957419a7fSflorian 	rtm.rtm_seq = ++rtm_seq;
119057419a7fSflorian 	rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT;
119157419a7fSflorian 	rtm.rtm_addrs = RTA_DNS;
119257419a7fSflorian 	rtm.rtm_flags = RTF_UP;
119357419a7fSflorian 
119457419a7fSflorian 	iov[iovcnt].iov_base = &rtm;
119557419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rtm);
119657419a7fSflorian 
119757419a7fSflorian 	memset(&rtdns, 0, sizeof(rtdns));
119857419a7fSflorian 	rtdns.sr_family = AF_INET;
119957419a7fSflorian 	rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in_addr);
1200*4f8d227cSflorian 	memcpy(rtdns.sr_dns, rdns->rdns, rtdns.sr_len - 2);
120157419a7fSflorian 
120257419a7fSflorian 	iov[iovcnt].iov_base = &rtdns;
120357419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rtdns);
120457419a7fSflorian 	rtm.rtm_msglen += sizeof(rtdns);
120557419a7fSflorian 	padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns);
120657419a7fSflorian 	if (padlen > 0) {
120757419a7fSflorian 		iov[iovcnt].iov_base = &pad;
120857419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
120957419a7fSflorian 		rtm.rtm_msglen += padlen;
121057419a7fSflorian 	}
121157419a7fSflorian 
121257419a7fSflorian 	if (writev(routesock, iov, iovcnt) == -1)
1213e81612d0Sflorian 		log_warn("failed to propose nameservers");
121457419a7fSflorian }
121557419a7fSflorian 
12166e93e3e9Sflorian void
read_lease_file(struct imsg_ifinfo * imsg_ifinfo)12176e93e3e9Sflorian read_lease_file(struct imsg_ifinfo *imsg_ifinfo)
121857419a7fSflorian {
12196e93e3e9Sflorian 	int	 len, fd;
122057419a7fSflorian 	char	 if_name[IF_NAMESIZE];
1221131c304bSflorian 	char	 lease_file_buf[sizeof(_PATH_LEASE) + IF_NAMESIZE];
122257419a7fSflorian 
1223ae968ffdSflorian 	if (no_lease_files)
1224ae968ffdSflorian 		return;
1225ae968ffdSflorian 
12266e93e3e9Sflorian 	memset(imsg_ifinfo->lease, 0, sizeof(imsg_ifinfo->lease));
12276e93e3e9Sflorian 
1228e998cdbeSflorian 	if (if_indextoname(imsg_ifinfo->if_index, if_name) == NULL) {
12296e93e3e9Sflorian 		log_warnx("%s: cannot find interface %d", __func__,
12306e93e3e9Sflorian 		    imsg_ifinfo->if_index);
12316e93e3e9Sflorian 		return;
123257419a7fSflorian 	}
123357419a7fSflorian 
123457419a7fSflorian 	len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s",
1235131c304bSflorian 	    _PATH_LEASE, if_name);
123657419a7fSflorian 	if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) {
123757419a7fSflorian 		log_warnx("%s: failed to encode lease path for %s", __func__,
123857419a7fSflorian 		    if_name);
12396e93e3e9Sflorian 		return;
124057419a7fSflorian 	}
124157419a7fSflorian 
12426e93e3e9Sflorian 	if ((fd = open(lease_file_buf, O_RDONLY)) == -1)
12436e93e3e9Sflorian 		return;
12446e93e3e9Sflorian 
12456e93e3e9Sflorian 	/* no need for error handling, we'll just do a DHCP discover */
12466e93e3e9Sflorian 	read(fd, imsg_ifinfo->lease, sizeof(imsg_ifinfo->lease) - 1);
12476e93e3e9Sflorian 	close(fd);
124857419a7fSflorian }
1249a41cc082Sflorian 
1250a41cc082Sflorian #ifndef SMALL
1251a41cc082Sflorian void
merge_config(struct dhcpleased_conf * conf,struct dhcpleased_conf * xconf)1252a41cc082Sflorian merge_config(struct dhcpleased_conf *conf, struct dhcpleased_conf *xconf)
1253a41cc082Sflorian {
1254a41cc082Sflorian 	struct iface_conf	*iface_conf;
1255a41cc082Sflorian 
1256a41cc082Sflorian 	/* Remove & discard existing interfaces. */
1257a41cc082Sflorian 	while ((iface_conf = SIMPLEQ_FIRST(&conf->iface_list)) != NULL) {
1258a41cc082Sflorian 		SIMPLEQ_REMOVE_HEAD(&conf->iface_list, entry);
1259a41cc082Sflorian 		free(iface_conf->vc_id);
1260a41cc082Sflorian 		free(iface_conf->c_id);
1261b3441518Sflorian 		free(iface_conf->h_name);
1262a41cc082Sflorian 		free(iface_conf);
1263a41cc082Sflorian 	}
1264a41cc082Sflorian 
1265a41cc082Sflorian 	/* Add new interfaces. */
1266a41cc082Sflorian 	SIMPLEQ_CONCAT(&conf->iface_list, &xconf->iface_list);
1267a41cc082Sflorian 
1268a41cc082Sflorian 	free(xconf);
1269a41cc082Sflorian }
1270a41cc082Sflorian 
1271a41cc082Sflorian struct dhcpleased_conf *
config_new_empty(void)1272a41cc082Sflorian config_new_empty(void)
1273a41cc082Sflorian {
1274a41cc082Sflorian 	struct dhcpleased_conf	*xconf;
1275a41cc082Sflorian 
1276a41cc082Sflorian 	xconf = calloc(1, sizeof(*xconf));
1277a41cc082Sflorian 	if (xconf == NULL)
1278a41cc082Sflorian 		fatal(NULL);
1279a41cc082Sflorian 
1280a41cc082Sflorian 	SIMPLEQ_INIT(&xconf->iface_list);
1281a41cc082Sflorian 
1282a41cc082Sflorian 	return (xconf);
1283a41cc082Sflorian }
1284a41cc082Sflorian 
1285a41cc082Sflorian void
config_clear(struct dhcpleased_conf * conf)1286a41cc082Sflorian config_clear(struct dhcpleased_conf *conf)
1287a41cc082Sflorian {
1288a41cc082Sflorian 	struct dhcpleased_conf	*xconf;
1289a41cc082Sflorian 
1290a41cc082Sflorian 	/* Merge current config with an empty config. */
1291a41cc082Sflorian 	xconf = config_new_empty();
1292a41cc082Sflorian 	merge_config(conf, xconf);
1293a41cc082Sflorian 
1294a41cc082Sflorian 	free(conf);
1295a41cc082Sflorian }
1296a41cc082Sflorian #endif /* SMALL */
1297