xref: /openbsd/sbin/dhcpleased/dhcpleased.c (revision 57419a7f)
1*57419a7fSflorian /*	$OpenBSD: dhcpleased.c,v 1.1 2021/02/26 16:16:37 florian Exp $	*/
2*57419a7fSflorian 
3*57419a7fSflorian /*
4*57419a7fSflorian  * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
5*57419a7fSflorian  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6*57419a7fSflorian  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7*57419a7fSflorian  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8*57419a7fSflorian  *
9*57419a7fSflorian  * Permission to use, copy, modify, and distribute this software for any
10*57419a7fSflorian  * purpose with or without fee is hereby granted, provided that the above
11*57419a7fSflorian  * copyright notice and this permission notice appear in all copies.
12*57419a7fSflorian  *
13*57419a7fSflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14*57419a7fSflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15*57419a7fSflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16*57419a7fSflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17*57419a7fSflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18*57419a7fSflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19*57419a7fSflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20*57419a7fSflorian  */
21*57419a7fSflorian #include <sys/types.h>
22*57419a7fSflorian #include <sys/ioctl.h>
23*57419a7fSflorian #include <sys/queue.h>
24*57419a7fSflorian #include <sys/socket.h>
25*57419a7fSflorian #include <sys/stat.h>
26*57419a7fSflorian #include <sys/syslog.h>
27*57419a7fSflorian #include <sys/sysctl.h>
28*57419a7fSflorian #include <sys/uio.h>
29*57419a7fSflorian #include <sys/wait.h>
30*57419a7fSflorian 
31*57419a7fSflorian #include <net/if.h>
32*57419a7fSflorian #include <net/route.h>
33*57419a7fSflorian #include <netinet/in.h>
34*57419a7fSflorian #include <netinet/if_ether.h>
35*57419a7fSflorian #include <netinet/in_var.h>
36*57419a7fSflorian 
37*57419a7fSflorian #include <arpa/inet.h>
38*57419a7fSflorian 
39*57419a7fSflorian #include <err.h>
40*57419a7fSflorian #include <errno.h>
41*57419a7fSflorian #include <fcntl.h>
42*57419a7fSflorian #include <event.h>
43*57419a7fSflorian #include <ifaddrs.h>
44*57419a7fSflorian #include <imsg.h>
45*57419a7fSflorian #include <netdb.h>
46*57419a7fSflorian #include <pwd.h>
47*57419a7fSflorian #include <stddef.h>
48*57419a7fSflorian #include <stdio.h>
49*57419a7fSflorian #include <stdlib.h>
50*57419a7fSflorian #include <string.h>
51*57419a7fSflorian #include <signal.h>
52*57419a7fSflorian #include <unistd.h>
53*57419a7fSflorian 
54*57419a7fSflorian #include "bpf.h"
55*57419a7fSflorian #include "log.h"
56*57419a7fSflorian #include "dhcpleased.h"
57*57419a7fSflorian #include "frontend.h"
58*57419a7fSflorian #include "engine.h"
59*57419a7fSflorian #include "control.h"
60*57419a7fSflorian 
61*57419a7fSflorian enum dhcpleased_process {
62*57419a7fSflorian 	PROC_MAIN,
63*57419a7fSflorian 	PROC_ENGINE,
64*57419a7fSflorian 	PROC_FRONTEND
65*57419a7fSflorian };
66*57419a7fSflorian 
67*57419a7fSflorian __dead void	usage(void);
68*57419a7fSflorian __dead void	main_shutdown(void);
69*57419a7fSflorian 
70*57419a7fSflorian void	main_sig_handler(int, short, void *);
71*57419a7fSflorian 
72*57419a7fSflorian static pid_t	start_child(enum dhcpleased_process, char *, int, int, int);
73*57419a7fSflorian 
74*57419a7fSflorian void	 main_dispatch_frontend(int, short, void *);
75*57419a7fSflorian void	 main_dispatch_engine(int, short, void *);
76*57419a7fSflorian void	 open_bpfsock(uint32_t);
77*57419a7fSflorian void	 configure_interface(struct imsg_configure_interface *);
78*57419a7fSflorian void	 deconfigure_interface(struct imsg_configure_interface *);
79*57419a7fSflorian void	 propose_rdns(struct imsg_propose_rdns *);
80*57419a7fSflorian void	 configure_gateway(struct imsg_configure_interface *, uint8_t);
81*57419a7fSflorian int	 open_lease_file(int);
82*57419a7fSflorian 
83*57419a7fSflorian static int	main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
84*57419a7fSflorian int		main_imsg_compose_frontend(int, int, void *, uint16_t);
85*57419a7fSflorian int		main_imsg_compose_engine(int, int, void *, uint16_t);
86*57419a7fSflorian 
87*57419a7fSflorian static struct imsgev	*iev_frontend;
88*57419a7fSflorian static struct imsgev	*iev_engine;
89*57419a7fSflorian 
90*57419a7fSflorian pid_t			 frontend_pid;
91*57419a7fSflorian pid_t			 engine_pid;
92*57419a7fSflorian 
93*57419a7fSflorian int			 routesock, ioctl_sock, rtm_seq = 0;
94*57419a7fSflorian 
95*57419a7fSflorian void
96*57419a7fSflorian main_sig_handler(int sig, short event, void *arg)
97*57419a7fSflorian {
98*57419a7fSflorian 	/*
99*57419a7fSflorian 	 * Normal signal handler rules don't apply because libevent
100*57419a7fSflorian 	 * decouples for us.
101*57419a7fSflorian 	 */
102*57419a7fSflorian 
103*57419a7fSflorian 	switch (sig) {
104*57419a7fSflorian 	case SIGTERM:
105*57419a7fSflorian 	case SIGINT:
106*57419a7fSflorian 		main_shutdown();
107*57419a7fSflorian 	default:
108*57419a7fSflorian 		fatalx("unexpected signal");
109*57419a7fSflorian 	}
110*57419a7fSflorian }
111*57419a7fSflorian 
112*57419a7fSflorian __dead void
113*57419a7fSflorian usage(void)
114*57419a7fSflorian {
115*57419a7fSflorian 	extern char *__progname;
116*57419a7fSflorian 
117*57419a7fSflorian 	fprintf(stderr, "usage: %s [-dv] [-s socket]\n",
118*57419a7fSflorian 	    __progname);
119*57419a7fSflorian 	exit(1);
120*57419a7fSflorian }
121*57419a7fSflorian 
122*57419a7fSflorian int
123*57419a7fSflorian main(int argc, char *argv[])
124*57419a7fSflorian {
125*57419a7fSflorian 	struct event		 ev_sigint, ev_sigterm;
126*57419a7fSflorian 	int			 ch;
127*57419a7fSflorian 	int			 debug = 0, engine_flag = 0, frontend_flag = 0;
128*57419a7fSflorian 	int			 verbose = 0;
129*57419a7fSflorian 	char			*saved_argv0;
130*57419a7fSflorian 	int			 pipe_main2frontend[2];
131*57419a7fSflorian 	int			 pipe_main2engine[2];
132*57419a7fSflorian 	int			 frontend_routesock, rtfilter;
133*57419a7fSflorian 	int			 rtable_any = RTABLE_ANY;
134*57419a7fSflorian 	char			*csock = DHCPLEASED_SOCKET;
135*57419a7fSflorian #ifndef SMALL
136*57419a7fSflorian 	int			 control_fd;
137*57419a7fSflorian #endif /* SMALL */
138*57419a7fSflorian 
139*57419a7fSflorian 	log_init(1, LOG_DAEMON);	/* Log to stderr until daemonized. */
140*57419a7fSflorian 	log_setverbose(1);
141*57419a7fSflorian 
142*57419a7fSflorian 	saved_argv0 = argv[0];
143*57419a7fSflorian 	if (saved_argv0 == NULL)
144*57419a7fSflorian 		saved_argv0 = "dhcpleased";
145*57419a7fSflorian 
146*57419a7fSflorian 	while ((ch = getopt(argc, argv, "dEFs:v")) != -1) {
147*57419a7fSflorian 		switch (ch) {
148*57419a7fSflorian 		case 'd':
149*57419a7fSflorian 			debug = 1;
150*57419a7fSflorian 			break;
151*57419a7fSflorian 		case 'E':
152*57419a7fSflorian 			engine_flag = 1;
153*57419a7fSflorian 			break;
154*57419a7fSflorian 		case 'F':
155*57419a7fSflorian 			frontend_flag = 1;
156*57419a7fSflorian 			break;
157*57419a7fSflorian 		case 's':
158*57419a7fSflorian 			csock = optarg;
159*57419a7fSflorian 			break;
160*57419a7fSflorian 		case 'v':
161*57419a7fSflorian 			verbose++;
162*57419a7fSflorian 			break;
163*57419a7fSflorian 		default:
164*57419a7fSflorian 			usage();
165*57419a7fSflorian 		}
166*57419a7fSflorian 	}
167*57419a7fSflorian 
168*57419a7fSflorian 	argc -= optind;
169*57419a7fSflorian 	argv += optind;
170*57419a7fSflorian 	if (argc > 0 || (engine_flag && frontend_flag))
171*57419a7fSflorian 		usage();
172*57419a7fSflorian 
173*57419a7fSflorian 	if (engine_flag)
174*57419a7fSflorian 		engine(debug, verbose);
175*57419a7fSflorian 	else if (frontend_flag)
176*57419a7fSflorian 		frontend(debug, verbose);
177*57419a7fSflorian 
178*57419a7fSflorian 	/* Check for root privileges. */
179*57419a7fSflorian 	if (geteuid())
180*57419a7fSflorian 		errx(1, "need root privileges");
181*57419a7fSflorian 
182*57419a7fSflorian 	/* Check for assigned daemon user */
183*57419a7fSflorian 	if (getpwnam(DHCPLEASED_USER) == NULL)
184*57419a7fSflorian 		errx(1, "unknown user %s", DHCPLEASED_USER);
185*57419a7fSflorian 
186*57419a7fSflorian 	log_init(debug, LOG_DAEMON);
187*57419a7fSflorian 	log_setverbose(verbose);
188*57419a7fSflorian 
189*57419a7fSflorian 	if (!debug)
190*57419a7fSflorian 		daemon(0, 0);
191*57419a7fSflorian 
192*57419a7fSflorian 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
193*57419a7fSflorian 	    PF_UNSPEC, pipe_main2frontend) == -1)
194*57419a7fSflorian 		fatal("main2frontend socketpair");
195*57419a7fSflorian 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
196*57419a7fSflorian 	    PF_UNSPEC, pipe_main2engine) == -1)
197*57419a7fSflorian 		fatal("main2engine socketpair");
198*57419a7fSflorian 
199*57419a7fSflorian 	/* Start children. */
200*57419a7fSflorian 	engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1],
201*57419a7fSflorian 	    debug, verbose);
202*57419a7fSflorian 	frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
203*57419a7fSflorian 	    pipe_main2frontend[1], debug, verbose);
204*57419a7fSflorian 
205*57419a7fSflorian 	log_procinit("main");
206*57419a7fSflorian 
207*57419a7fSflorian 	if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC |
208*57419a7fSflorian 	    SOCK_NONBLOCK, AF_INET)) == -1)
209*57419a7fSflorian 		fatal("route socket");
210*57419a7fSflorian 	shutdown(SHUT_RD, routesock);
211*57419a7fSflorian 
212*57419a7fSflorian 	event_init();
213*57419a7fSflorian 
214*57419a7fSflorian 	/* Setup signal handler. */
215*57419a7fSflorian 	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
216*57419a7fSflorian 	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
217*57419a7fSflorian 	signal_add(&ev_sigint, NULL);
218*57419a7fSflorian 	signal_add(&ev_sigterm, NULL);
219*57419a7fSflorian 	signal(SIGPIPE, SIG_IGN);
220*57419a7fSflorian 	signal(SIGHUP, SIG_IGN);
221*57419a7fSflorian 
222*57419a7fSflorian 	/* Setup pipes to children. */
223*57419a7fSflorian 
224*57419a7fSflorian 	if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL ||
225*57419a7fSflorian 	    (iev_engine = malloc(sizeof(struct imsgev))) == NULL)
226*57419a7fSflorian 		fatal(NULL);
227*57419a7fSflorian 	imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
228*57419a7fSflorian 	iev_frontend->handler = main_dispatch_frontend;
229*57419a7fSflorian 	imsg_init(&iev_engine->ibuf, pipe_main2engine[0]);
230*57419a7fSflorian 	iev_engine->handler = main_dispatch_engine;
231*57419a7fSflorian 
232*57419a7fSflorian 	/* Setup event handlers for pipes to engine & frontend. */
233*57419a7fSflorian 	iev_frontend->events = EV_READ;
234*57419a7fSflorian 	event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
235*57419a7fSflorian 	    iev_frontend->events, iev_frontend->handler, iev_frontend);
236*57419a7fSflorian 	event_add(&iev_frontend->ev, NULL);
237*57419a7fSflorian 
238*57419a7fSflorian 	iev_engine->events = EV_READ;
239*57419a7fSflorian 	event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events,
240*57419a7fSflorian 	    iev_engine->handler, iev_engine);
241*57419a7fSflorian 	event_add(&iev_engine->ev, NULL);
242*57419a7fSflorian 
243*57419a7fSflorian 	if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf))
244*57419a7fSflorian 		fatal("could not establish imsg links");
245*57419a7fSflorian 
246*57419a7fSflorian 	if ((ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
247*57419a7fSflorian 		fatal("socket");
248*57419a7fSflorian 
249*57419a7fSflorian 	if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC,
250*57419a7fSflorian 	    AF_INET)) == -1)
251*57419a7fSflorian 		fatal("route socket");
252*57419a7fSflorian 
253*57419a7fSflorian 	rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) |
254*57419a7fSflorian 	    ROUTE_FILTER(RTM_PROPOSAL);
255*57419a7fSflorian 	if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER,
256*57419a7fSflorian 	    &rtfilter, sizeof(rtfilter)) == -1)
257*57419a7fSflorian 		fatal("setsockopt(ROUTE_MSGFILTER)");
258*57419a7fSflorian 	if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER,
259*57419a7fSflorian 	    &rtable_any, sizeof(rtable_any)) == -1)
260*57419a7fSflorian 		fatal("setsockopt(ROUTE_TABLEFILTER)");
261*57419a7fSflorian 
262*57419a7fSflorian #ifndef SMALL
263*57419a7fSflorian 	if ((control_fd = control_init(csock)) == -1)
264*57419a7fSflorian 		fatalx("control socket setup failed");
265*57419a7fSflorian #endif /* SMALL */
266*57419a7fSflorian 
267*57419a7fSflorian 	if (unveil("/dev/bpf", "rw") == -1)
268*57419a7fSflorian 		fatal("unveil");
269*57419a7fSflorian 
270*57419a7fSflorian 	if (unveil(LEASE_PATH, "rwc") == -1)
271*57419a7fSflorian 		fatal("unveil");
272*57419a7fSflorian 
273*57419a7fSflorian 	if (unveil(NULL, NULL) == -1)
274*57419a7fSflorian 		fatal("unveil");
275*57419a7fSflorian #if notyet
276*57419a7fSflorian 	if (pledge("stdio inet rpath wpath sendfd wroute bpf", NULL) == -1)
277*57419a7fSflorian 		fatal("pledge");
278*57419a7fSflorian #endif
279*57419a7fSflorian 	main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0);
280*57419a7fSflorian 
281*57419a7fSflorian #ifndef SMALL
282*57419a7fSflorian 	main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0);
283*57419a7fSflorian #endif /* SMALL */
284*57419a7fSflorian 
285*57419a7fSflorian 	main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0);
286*57419a7fSflorian 
287*57419a7fSflorian 	event_dispatch();
288*57419a7fSflorian 
289*57419a7fSflorian 	main_shutdown();
290*57419a7fSflorian 	return (0);
291*57419a7fSflorian }
292*57419a7fSflorian 
293*57419a7fSflorian __dead void
294*57419a7fSflorian main_shutdown(void)
295*57419a7fSflorian {
296*57419a7fSflorian 	pid_t	 pid;
297*57419a7fSflorian 	int	 status;
298*57419a7fSflorian 
299*57419a7fSflorian 	/* Close pipes. */
300*57419a7fSflorian 	msgbuf_clear(&iev_frontend->ibuf.w);
301*57419a7fSflorian 	close(iev_frontend->ibuf.fd);
302*57419a7fSflorian 	msgbuf_clear(&iev_engine->ibuf.w);
303*57419a7fSflorian 	close(iev_engine->ibuf.fd);
304*57419a7fSflorian 
305*57419a7fSflorian 	log_debug("waiting for children to terminate");
306*57419a7fSflorian 	do {
307*57419a7fSflorian 		pid = wait(&status);
308*57419a7fSflorian 		if (pid == -1) {
309*57419a7fSflorian 			if (errno != EINTR && errno != ECHILD)
310*57419a7fSflorian 				fatal("wait");
311*57419a7fSflorian 		} else if (WIFSIGNALED(status))
312*57419a7fSflorian 			log_warnx("%s terminated; signal %d",
313*57419a7fSflorian 			    (pid == engine_pid) ? "engine" :
314*57419a7fSflorian 			    "frontend", WTERMSIG(status));
315*57419a7fSflorian 	} while (pid != -1 || (pid == -1 && errno == EINTR));
316*57419a7fSflorian 
317*57419a7fSflorian 	free(iev_frontend);
318*57419a7fSflorian 	free(iev_engine);
319*57419a7fSflorian 
320*57419a7fSflorian 	log_info("terminating");
321*57419a7fSflorian 	exit(0);
322*57419a7fSflorian }
323*57419a7fSflorian 
324*57419a7fSflorian static pid_t
325*57419a7fSflorian start_child(enum dhcpleased_process p, char *argv0, int fd, int debug, int
326*57419a7fSflorian     verbose)
327*57419a7fSflorian {
328*57419a7fSflorian 	char	*argv[7];
329*57419a7fSflorian 	int	 argc = 0;
330*57419a7fSflorian 	pid_t	 pid;
331*57419a7fSflorian 
332*57419a7fSflorian 	switch (pid = fork()) {
333*57419a7fSflorian 	case -1:
334*57419a7fSflorian 		fatal("cannot fork");
335*57419a7fSflorian 	case 0:
336*57419a7fSflorian 		break;
337*57419a7fSflorian 	default:
338*57419a7fSflorian 		close(fd);
339*57419a7fSflorian 		return (pid);
340*57419a7fSflorian 	}
341*57419a7fSflorian 
342*57419a7fSflorian 	if (fd != 3) {
343*57419a7fSflorian 		if (dup2(fd, 3) == -1)
344*57419a7fSflorian 			fatal("cannot setup imsg fd");
345*57419a7fSflorian 	} else if (fcntl(fd, F_SETFD, 0) == -1)
346*57419a7fSflorian 		fatal("cannot setup imsg fd");
347*57419a7fSflorian 
348*57419a7fSflorian 	argv[argc++] = argv0;
349*57419a7fSflorian 	switch (p) {
350*57419a7fSflorian 	case PROC_MAIN:
351*57419a7fSflorian 		fatalx("Can not start main process");
352*57419a7fSflorian 	case PROC_ENGINE:
353*57419a7fSflorian 		argv[argc++] = "-E";
354*57419a7fSflorian 		break;
355*57419a7fSflorian 	case PROC_FRONTEND:
356*57419a7fSflorian 		argv[argc++] = "-F";
357*57419a7fSflorian 		break;
358*57419a7fSflorian 	}
359*57419a7fSflorian 	if (debug)
360*57419a7fSflorian 		argv[argc++] = "-d";
361*57419a7fSflorian 	if (verbose)
362*57419a7fSflorian 		argv[argc++] = "-v";
363*57419a7fSflorian 	if (verbose > 1)
364*57419a7fSflorian 		argv[argc++] = "-v";
365*57419a7fSflorian 	argv[argc++] = NULL;
366*57419a7fSflorian 
367*57419a7fSflorian 	execvp(argv0, argv);
368*57419a7fSflorian 	fatal("execvp");
369*57419a7fSflorian }
370*57419a7fSflorian 
371*57419a7fSflorian void
372*57419a7fSflorian main_dispatch_frontend(int fd, short event, void *bula)
373*57419a7fSflorian {
374*57419a7fSflorian 	struct imsgev		*iev = bula;
375*57419a7fSflorian 	struct imsgbuf		*ibuf;
376*57419a7fSflorian 	struct imsg		 imsg;
377*57419a7fSflorian 	struct imsg_ifinfo	 imsg_ifinfo;
378*57419a7fSflorian 	ssize_t			 n;
379*57419a7fSflorian 	int			 shut = 0;
380*57419a7fSflorian 	uint32_t		 if_index;
381*57419a7fSflorian #ifndef	SMALL
382*57419a7fSflorian 	int			 verbose;
383*57419a7fSflorian #endif	/* SMALL */
384*57419a7fSflorian 
385*57419a7fSflorian 	ibuf = &iev->ibuf;
386*57419a7fSflorian 
387*57419a7fSflorian 	if (event & EV_READ) {
388*57419a7fSflorian 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
389*57419a7fSflorian 			fatal("imsg_read error");
390*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
391*57419a7fSflorian 			shut = 1;
392*57419a7fSflorian 	}
393*57419a7fSflorian 	if (event & EV_WRITE) {
394*57419a7fSflorian 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
395*57419a7fSflorian 			fatal("msgbuf_write");
396*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
397*57419a7fSflorian 			shut = 1;
398*57419a7fSflorian 	}
399*57419a7fSflorian 
400*57419a7fSflorian 	for (;;) {
401*57419a7fSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
402*57419a7fSflorian 			fatal("imsg_get");
403*57419a7fSflorian 		if (n == 0)	/* No more messages. */
404*57419a7fSflorian 			break;
405*57419a7fSflorian 
406*57419a7fSflorian 		switch (imsg.hdr.type) {
407*57419a7fSflorian 		case IMSG_OPEN_BPFSOCK:
408*57419a7fSflorian 			log_debug("IMSG_OPEN_BPFSOCK");
409*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
410*57419a7fSflorian 				fatalx("%s: IMSG_OPEN_BPFSOCK wrong length: "
411*57419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
412*57419a7fSflorian 			memcpy(&if_index, imsg.data, sizeof(if_index));
413*57419a7fSflorian 			open_bpfsock(if_index);
414*57419a7fSflorian                         break;
415*57419a7fSflorian #ifndef	SMALL
416*57419a7fSflorian 		case IMSG_CTL_LOG_VERBOSE:
417*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
418*57419a7fSflorian 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
419*57419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
420*57419a7fSflorian 			memcpy(&verbose, imsg.data, sizeof(verbose));
421*57419a7fSflorian 			log_setverbose(verbose);
422*57419a7fSflorian 			break;
423*57419a7fSflorian #endif	/* SMALL */
424*57419a7fSflorian 		case IMSG_UPDATE_IF:
425*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo))
426*57419a7fSflorian 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
427*57419a7fSflorian 				    __func__, IMSG_DATA_SIZE(imsg));
428*57419a7fSflorian 			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
429*57419a7fSflorian 			main_imsg_compose_engine(IMSG_UPDATE_IF,
430*57419a7fSflorian 			    open_lease_file(imsg_ifinfo.if_index), &imsg_ifinfo,
431*57419a7fSflorian 			    sizeof(imsg_ifinfo));
432*57419a7fSflorian 			break;
433*57419a7fSflorian 		default:
434*57419a7fSflorian 			log_debug("%s: error handling imsg %d", __func__,
435*57419a7fSflorian 			    imsg.hdr.type);
436*57419a7fSflorian 			break;
437*57419a7fSflorian 		}
438*57419a7fSflorian 		imsg_free(&imsg);
439*57419a7fSflorian 	}
440*57419a7fSflorian 	if (!shut)
441*57419a7fSflorian 		imsg_event_add(iev);
442*57419a7fSflorian 	else {
443*57419a7fSflorian 		/* This pipe is dead. Remove its event handler */
444*57419a7fSflorian 		event_del(&iev->ev);
445*57419a7fSflorian 		event_loopexit(NULL);
446*57419a7fSflorian 	}
447*57419a7fSflorian }
448*57419a7fSflorian 
449*57419a7fSflorian void
450*57419a7fSflorian main_dispatch_engine(int fd, short event, void *bula)
451*57419a7fSflorian {
452*57419a7fSflorian 	struct imsgev			*iev = bula;
453*57419a7fSflorian 	struct imsgbuf			*ibuf;
454*57419a7fSflorian 	struct imsg			 imsg;
455*57419a7fSflorian 	ssize_t				 n;
456*57419a7fSflorian 	int				 shut = 0;
457*57419a7fSflorian 
458*57419a7fSflorian 	ibuf = &iev->ibuf;
459*57419a7fSflorian 
460*57419a7fSflorian 	if (event & EV_READ) {
461*57419a7fSflorian 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
462*57419a7fSflorian 			fatal("imsg_read error");
463*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
464*57419a7fSflorian 			shut = 1;
465*57419a7fSflorian 	}
466*57419a7fSflorian 	if (event & EV_WRITE) {
467*57419a7fSflorian 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
468*57419a7fSflorian 			fatal("msgbuf_write");
469*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
470*57419a7fSflorian 			shut = 1;
471*57419a7fSflorian 	}
472*57419a7fSflorian 
473*57419a7fSflorian 	for (;;) {
474*57419a7fSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
475*57419a7fSflorian 			fatal("imsg_get");
476*57419a7fSflorian 		if (n == 0)	/* No more messages. */
477*57419a7fSflorian 			break;
478*57419a7fSflorian 
479*57419a7fSflorian 		switch (imsg.hdr.type) {
480*57419a7fSflorian 		case IMSG_CONFIGURE_INTERFACE: {
481*57419a7fSflorian 			struct imsg_configure_interface imsg_interface;
482*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface))
483*57419a7fSflorian 				fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
484*57419a7fSflorian 				    "length: %lu", __func__,
485*57419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
486*57419a7fSflorian 			memcpy(&imsg_interface, imsg.data,
487*57419a7fSflorian 			    sizeof(imsg_interface));
488*57419a7fSflorian 			configure_interface(&imsg_interface);
489*57419a7fSflorian 			break;
490*57419a7fSflorian 		}
491*57419a7fSflorian 		case IMSG_DECONFIGURE_INTERFACE: {
492*57419a7fSflorian 			struct imsg_configure_interface imsg_interface;
493*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface))
494*57419a7fSflorian 				fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
495*57419a7fSflorian 				    "length: %lu", __func__,
496*57419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
497*57419a7fSflorian 			memcpy(&imsg_interface, imsg.data,
498*57419a7fSflorian 			    sizeof(imsg_interface));
499*57419a7fSflorian 			deconfigure_interface(&imsg_interface);
500*57419a7fSflorian 			main_imsg_compose_frontend(IMSG_CLOSE_UDPSOCK, -1,
501*57419a7fSflorian 			    &imsg_interface.if_index,
502*57419a7fSflorian 			    sizeof(imsg_interface.if_index));
503*57419a7fSflorian 			break;
504*57419a7fSflorian 		}
505*57419a7fSflorian 		case IMSG_PROPOSE_RDNS: {
506*57419a7fSflorian 			struct imsg_propose_rdns	 rdns;
507*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(rdns))
508*57419a7fSflorian 				fatalx("%s: IMSG_PROPOSE_RDNS wrong "
509*57419a7fSflorian 				    "length: %lu", __func__,
510*57419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
511*57419a7fSflorian 			memcpy(&rdns, imsg.data, sizeof(rdns));
512*57419a7fSflorian 			if ((2 + rdns.rdns_count * sizeof(struct in_addr)) >
513*57419a7fSflorian 			    sizeof(struct sockaddr_rtdns))
514*57419a7fSflorian 				fatalx("%s: rdns_count too big: %d", __func__,
515*57419a7fSflorian 				    rdns.rdns_count);
516*57419a7fSflorian 			propose_rdns(&rdns);
517*57419a7fSflorian 			break;
518*57419a7fSflorian 		}
519*57419a7fSflorian 		case IMSG_WITHDRAW_RDNS: {
520*57419a7fSflorian 			struct imsg_propose_rdns	 rdns;
521*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(rdns))
522*57419a7fSflorian 				fatalx("%s: IMSG_PROPOSE_RDNS wrong "
523*57419a7fSflorian 				    "length: %lu", __func__,
524*57419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
525*57419a7fSflorian 			memcpy(&rdns, imsg.data, sizeof(rdns));
526*57419a7fSflorian 			if (rdns.rdns_count != 0)
527*57419a7fSflorian 				fatalx("%s: expected rdns_count == 0: %d",
528*57419a7fSflorian 				    __func__, rdns.rdns_count);
529*57419a7fSflorian 			propose_rdns(&rdns);
530*57419a7fSflorian 			break;
531*57419a7fSflorian 		}
532*57419a7fSflorian 		default:
533*57419a7fSflorian 			log_debug("%s: error handling imsg %d", __func__,
534*57419a7fSflorian 			    imsg.hdr.type);
535*57419a7fSflorian 			break;
536*57419a7fSflorian 		}
537*57419a7fSflorian 		imsg_free(&imsg);
538*57419a7fSflorian 	}
539*57419a7fSflorian 	if (!shut)
540*57419a7fSflorian 		imsg_event_add(iev);
541*57419a7fSflorian 	else {
542*57419a7fSflorian 		/* This pipe is dead. Remove its event handler. */
543*57419a7fSflorian 		event_del(&iev->ev);
544*57419a7fSflorian 		event_loopexit(NULL);
545*57419a7fSflorian 	}
546*57419a7fSflorian }
547*57419a7fSflorian 
548*57419a7fSflorian int
549*57419a7fSflorian main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen)
550*57419a7fSflorian {
551*57419a7fSflorian 	if (iev_frontend)
552*57419a7fSflorian 		return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data,
553*57419a7fSflorian 		    datalen));
554*57419a7fSflorian 	else
555*57419a7fSflorian 		return (-1);
556*57419a7fSflorian }
557*57419a7fSflorian 
558*57419a7fSflorian int
559*57419a7fSflorian main_imsg_compose_engine(int type, int fd, void *data, uint16_t datalen)
560*57419a7fSflorian {
561*57419a7fSflorian 	if (iev_engine)
562*57419a7fSflorian 		return(imsg_compose_event(iev_engine, type, 0, 0, fd, data,
563*57419a7fSflorian 		    datalen));
564*57419a7fSflorian 	else
565*57419a7fSflorian 		return (-1);
566*57419a7fSflorian }
567*57419a7fSflorian 
568*57419a7fSflorian void
569*57419a7fSflorian imsg_event_add(struct imsgev *iev)
570*57419a7fSflorian {
571*57419a7fSflorian 	iev->events = EV_READ;
572*57419a7fSflorian 	if (iev->ibuf.w.queued)
573*57419a7fSflorian 		iev->events |= EV_WRITE;
574*57419a7fSflorian 
575*57419a7fSflorian 	event_del(&iev->ev);
576*57419a7fSflorian 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
577*57419a7fSflorian 	event_add(&iev->ev, NULL);
578*57419a7fSflorian }
579*57419a7fSflorian 
580*57419a7fSflorian int
581*57419a7fSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
582*57419a7fSflorian     pid_t pid, int fd, void *data, uint16_t datalen)
583*57419a7fSflorian {
584*57419a7fSflorian 	int	ret;
585*57419a7fSflorian 
586*57419a7fSflorian 	if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data,
587*57419a7fSflorian 	    datalen)) != -1)
588*57419a7fSflorian 		imsg_event_add(iev);
589*57419a7fSflorian 
590*57419a7fSflorian 	return (ret);
591*57419a7fSflorian }
592*57419a7fSflorian 
593*57419a7fSflorian static int
594*57419a7fSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
595*57419a7fSflorian     struct imsgbuf *engine_buf)
596*57419a7fSflorian {
597*57419a7fSflorian 	int pipe_frontend2engine[2];
598*57419a7fSflorian 
599*57419a7fSflorian 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
600*57419a7fSflorian 	    PF_UNSPEC, pipe_frontend2engine) == -1)
601*57419a7fSflorian 		return (-1);
602*57419a7fSflorian 
603*57419a7fSflorian 	if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0,
604*57419a7fSflorian 	    pipe_frontend2engine[0], NULL, 0) == -1)
605*57419a7fSflorian 		return (-1);
606*57419a7fSflorian 	imsg_flush(frontend_buf);
607*57419a7fSflorian 	if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0,
608*57419a7fSflorian 	    pipe_frontend2engine[1], NULL, 0) == -1)
609*57419a7fSflorian 		return (-1);
610*57419a7fSflorian 	imsg_flush(engine_buf);
611*57419a7fSflorian 	return (0);
612*57419a7fSflorian }
613*57419a7fSflorian 
614*57419a7fSflorian void
615*57419a7fSflorian configure_interface(struct imsg_configure_interface *imsg)
616*57419a7fSflorian {
617*57419a7fSflorian 	struct ifaliasreq	 ifaliasreq;
618*57419a7fSflorian 	struct ifaddrs		*ifap, *ifa;
619*57419a7fSflorian 	struct sockaddr_in	*req_sin_addr, *req_sin_mask;
620*57419a7fSflorian 	int			 found = 0, udpsock, opt = 1, len, fd = -1;
621*57419a7fSflorian 	char			*if_name;
622*57419a7fSflorian 	char			 ntop_buf[INET_ADDRSTRLEN];
623*57419a7fSflorian 	char			 lease_buf[LEASE_SIZE];
624*57419a7fSflorian 	char			 lease_file_buf[sizeof(LEASE_PATH) +
625*57419a7fSflorian 	    IF_NAMESIZE];
626*57419a7fSflorian 	char			 tmpl[] = LEASE_PATH"XXXXXXXXXX";
627*57419a7fSflorian 
628*57419a7fSflorian 	log_debug("%s", __func__);
629*57419a7fSflorian 
630*57419a7fSflorian 	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
631*57419a7fSflorian 
632*57419a7fSflorian 	if_name = if_indextoname(imsg->if_index, ifaliasreq.ifra_name);
633*57419a7fSflorian 	if (if_name == NULL) {
634*57419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__,
635*57419a7fSflorian 		    imsg->if_index);
636*57419a7fSflorian 		return;
637*57419a7fSflorian 	}
638*57419a7fSflorian 
639*57419a7fSflorian 	if (getifaddrs(&ifap) != 0)
640*57419a7fSflorian 		fatal("getifaddrs");
641*57419a7fSflorian 
642*57419a7fSflorian 	req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
643*57419a7fSflorian 	req_sin_addr->sin_family = AF_INET;
644*57419a7fSflorian 	req_sin_addr->sin_len = sizeof(*req_sin_addr);
645*57419a7fSflorian 
646*57419a7fSflorian 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
647*57419a7fSflorian 		struct in_addr	 addr, mask;
648*57419a7fSflorian 
649*57419a7fSflorian 		if (strcmp(if_name, ifa->ifa_name) != 0)
650*57419a7fSflorian 			continue;
651*57419a7fSflorian 		if (ifa->ifa_addr == NULL)
652*57419a7fSflorian 			continue;
653*57419a7fSflorian 		if (ifa->ifa_addr->sa_family != AF_INET)
654*57419a7fSflorian 			continue;
655*57419a7fSflorian 
656*57419a7fSflorian 		addr.s_addr = ((struct sockaddr_in *)ifa->ifa_addr)
657*57419a7fSflorian 		    ->sin_addr.s_addr;
658*57419a7fSflorian 		mask.s_addr = ((struct sockaddr_in *)ifa->ifa_netmask)
659*57419a7fSflorian 		    ->sin_addr.s_addr;
660*57419a7fSflorian 
661*57419a7fSflorian 		if (imsg->addr.s_addr == addr.s_addr) {
662*57419a7fSflorian 			if (imsg->mask.s_addr == mask.s_addr)
663*57419a7fSflorian 				found = 1;
664*57419a7fSflorian 			else {
665*57419a7fSflorian 				req_sin_addr->sin_addr.s_addr = addr.s_addr;
666*57419a7fSflorian 				if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq)
667*57419a7fSflorian 				    == -1) {
668*57419a7fSflorian 					if (errno != EADDRNOTAVAIL)
669*57419a7fSflorian 						log_warn("SIOCDIFADDR");
670*57419a7fSflorian 				}
671*57419a7fSflorian 			}
672*57419a7fSflorian 			break;
673*57419a7fSflorian 		}
674*57419a7fSflorian 	}
675*57419a7fSflorian 
676*57419a7fSflorian 	req_sin_addr->sin_addr.s_addr = imsg->addr.s_addr;
677*57419a7fSflorian 	if (!found) {
678*57419a7fSflorian 		req_sin_mask = (struct sockaddr_in *)&ifaliasreq.ifra_mask;
679*57419a7fSflorian 		req_sin_mask->sin_family = AF_INET;
680*57419a7fSflorian 		req_sin_mask->sin_len = sizeof(*req_sin_mask);
681*57419a7fSflorian 		req_sin_mask->sin_addr.s_addr = imsg->mask.s_addr;
682*57419a7fSflorian 		if (ioctl(ioctl_sock, SIOCAIFADDR, &ifaliasreq) == -1)
683*57419a7fSflorian 			fatal("SIOCAIFADDR");
684*57419a7fSflorian 
685*57419a7fSflorian 		/* XXX check weird shit in dhclient/kroute.c set_routes() */
686*57419a7fSflorian 		if (imsg->router.s_addr != INADDR_ANY)
687*57419a7fSflorian 			configure_gateway(imsg, RTM_ADD);
688*57419a7fSflorian 	}
689*57419a7fSflorian 	req_sin_addr->sin_port = ntohs(CLIENT_PORT);
690*57419a7fSflorian 	if ((udpsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
691*57419a7fSflorian 		log_warn("socket");
692*57419a7fSflorian 		return;
693*57419a7fSflorian 	}
694*57419a7fSflorian 	if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, &opt,
695*57419a7fSflorian 	    sizeof(opt)) == -1)
696*57419a7fSflorian 		log_warn("setting SO_REUSEADDR on socket");
697*57419a7fSflorian 
698*57419a7fSflorian 	if (setsockopt(udpsock, SOL_SOCKET, SO_RTABLE, &imsg->rdomain,
699*57419a7fSflorian 	    sizeof(imsg->rdomain)) == -1) {
700*57419a7fSflorian 		/* we might race against removal of the rdomain */
701*57419a7fSflorian 		log_warn("setsockopt SO_RTABLE");
702*57419a7fSflorian 		close(udpsock);
703*57419a7fSflorian 		return;
704*57419a7fSflorian 	}
705*57419a7fSflorian 
706*57419a7fSflorian 	if (bind(udpsock, (struct sockaddr *)req_sin_addr,
707*57419a7fSflorian 	    sizeof(*req_sin_addr)) == -1) {
708*57419a7fSflorian 		close(udpsock);
709*57419a7fSflorian 		return;
710*57419a7fSflorian 	}
711*57419a7fSflorian 
712*57419a7fSflorian 	shutdown(udpsock, SHUT_RD);
713*57419a7fSflorian 	log_debug("%s: udpsock: %d", __func__, udpsock);
714*57419a7fSflorian 	main_imsg_compose_frontend(IMSG_UDPSOCK, udpsock,
715*57419a7fSflorian 	    &imsg->if_index, sizeof(imsg->if_index));
716*57419a7fSflorian 
717*57419a7fSflorian 	if (inet_ntop(AF_INET, &imsg->addr, ntop_buf, sizeof(ntop_buf)) ==
718*57419a7fSflorian 	    NULL) {
719*57419a7fSflorian 		log_warn("%s: inet_ntop", __func__);
720*57419a7fSflorian 		return;
721*57419a7fSflorian 	}
722*57419a7fSflorian 
723*57419a7fSflorian 	len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s",
724*57419a7fSflorian 	    LEASE_PATH, if_name);
725*57419a7fSflorian 	if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) {
726*57419a7fSflorian 		log_warnx("%s: failed to encode lease path for %s", __func__,
727*57419a7fSflorian 		    if_name);
728*57419a7fSflorian 		return;
729*57419a7fSflorian 	}
730*57419a7fSflorian 
731*57419a7fSflorian 	len = snprintf(lease_buf, sizeof(lease_buf), "%s%s\n", LEASE_PREFIX,
732*57419a7fSflorian 	    ntop_buf);
733*57419a7fSflorian 	if ( len == -1 || (size_t) len >= sizeof(lease_buf)) {
734*57419a7fSflorian 		log_warnx("%s: failed to encode lease for %s", __func__,
735*57419a7fSflorian 		    ntop_buf);
736*57419a7fSflorian 		return;
737*57419a7fSflorian 	}
738*57419a7fSflorian 
739*57419a7fSflorian 	if ((fd = mkstemp(tmpl)) == -1) {
740*57419a7fSflorian 		log_warn("%s: mkstemp", __func__);
741*57419a7fSflorian 		return;
742*57419a7fSflorian 	}
743*57419a7fSflorian 
744*57419a7fSflorian 	if (write(fd, lease_buf, len) < len)
745*57419a7fSflorian 		goto err;
746*57419a7fSflorian 
747*57419a7fSflorian 	if (fchmod(fd, 0644) == -1)
748*57419a7fSflorian 		goto err;
749*57419a7fSflorian 
750*57419a7fSflorian 	if (close(fd) == -1)
751*57419a7fSflorian 		goto err;
752*57419a7fSflorian 	fd = -1;
753*57419a7fSflorian 
754*57419a7fSflorian 	if (rename(tmpl, lease_file_buf) == -1)
755*57419a7fSflorian 		goto err;
756*57419a7fSflorian 	return;
757*57419a7fSflorian  err:
758*57419a7fSflorian 	log_warn("%s", __func__);
759*57419a7fSflorian 	if (fd != -1)
760*57419a7fSflorian 		close(fd);
761*57419a7fSflorian 	unlink(tmpl);
762*57419a7fSflorian }
763*57419a7fSflorian 
764*57419a7fSflorian void
765*57419a7fSflorian deconfigure_interface(struct imsg_configure_interface *imsg)
766*57419a7fSflorian {
767*57419a7fSflorian 	struct ifaliasreq	 ifaliasreq;
768*57419a7fSflorian 	struct sockaddr_in	*req_sin_addr;
769*57419a7fSflorian 
770*57419a7fSflorian 	log_debug("%s", __func__);
771*57419a7fSflorian 
772*57419a7fSflorian 	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
773*57419a7fSflorian 
774*57419a7fSflorian 	if (if_indextoname(imsg->if_index, ifaliasreq.ifra_name) == NULL) {
775*57419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__,
776*57419a7fSflorian 		    imsg->if_index);
777*57419a7fSflorian 		return;
778*57419a7fSflorian 	}
779*57419a7fSflorian 
780*57419a7fSflorian 	req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
781*57419a7fSflorian 	req_sin_addr->sin_family = AF_INET;
782*57419a7fSflorian 	req_sin_addr->sin_len = sizeof(*req_sin_addr);
783*57419a7fSflorian 
784*57419a7fSflorian 	req_sin_addr->sin_addr.s_addr = imsg->addr.s_addr;
785*57419a7fSflorian 	if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq) == -1) {
786*57419a7fSflorian 		if (errno != EADDRNOTAVAIL)
787*57419a7fSflorian 			log_warn("SIOCDIFADDR");
788*57419a7fSflorian 	}
789*57419a7fSflorian }
790*57419a7fSflorian 
791*57419a7fSflorian #define	ROUNDUP(a)	\
792*57419a7fSflorian     (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
793*57419a7fSflorian void
794*57419a7fSflorian configure_gateway(struct imsg_configure_interface *imsg, uint8_t rtm_type)
795*57419a7fSflorian {
796*57419a7fSflorian 	struct rt_msghdr		 rtm;
797*57419a7fSflorian 	struct sockaddr_rtlabel		 rl;
798*57419a7fSflorian 	struct sockaddr_in		 dst, gw, mask;
799*57419a7fSflorian 	struct iovec			 iov[10];
800*57419a7fSflorian 	long				 pad = 0;
801*57419a7fSflorian 	int				 iovcnt = 0, padlen;
802*57419a7fSflorian 
803*57419a7fSflorian 	memset(&rtm, 0, sizeof(rtm));
804*57419a7fSflorian 
805*57419a7fSflorian 	rtm.rtm_version = RTM_VERSION;
806*57419a7fSflorian 	rtm.rtm_type = rtm_type;
807*57419a7fSflorian 	rtm.rtm_msglen = sizeof(rtm);
808*57419a7fSflorian 	rtm.rtm_tableid = imsg->rdomain;
809*57419a7fSflorian 	rtm.rtm_index = imsg->if_index;
810*57419a7fSflorian 	rtm.rtm_seq = ++rtm_seq;
811*57419a7fSflorian 	rtm.rtm_priority = RTP_NONE;
812*57419a7fSflorian 	rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL;
813*57419a7fSflorian 	rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
814*57419a7fSflorian 
815*57419a7fSflorian 	iov[iovcnt].iov_base = &rtm;
816*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rtm);
817*57419a7fSflorian 
818*57419a7fSflorian 	memset(&dst, 0, sizeof(dst));
819*57419a7fSflorian 	dst.sin_family = AF_INET;
820*57419a7fSflorian 	dst.sin_len = sizeof(struct sockaddr_in);
821*57419a7fSflorian 
822*57419a7fSflorian 	iov[iovcnt].iov_base = &dst;
823*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(dst);
824*57419a7fSflorian 	rtm.rtm_msglen += sizeof(dst);
825*57419a7fSflorian 	padlen = ROUNDUP(sizeof(dst)) - sizeof(dst);
826*57419a7fSflorian 	if (padlen > 0) {
827*57419a7fSflorian 		iov[iovcnt].iov_base = &pad;
828*57419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
829*57419a7fSflorian 		rtm.rtm_msglen += padlen;
830*57419a7fSflorian 	}
831*57419a7fSflorian 
832*57419a7fSflorian 	memset(&gw, 0, sizeof(gw));
833*57419a7fSflorian 	memcpy(&gw.sin_addr, &imsg->router, sizeof(gw.sin_addr));
834*57419a7fSflorian 	gw.sin_family = AF_INET;
835*57419a7fSflorian 	gw.sin_len = sizeof(struct sockaddr_in);
836*57419a7fSflorian 	iov[iovcnt].iov_base = &gw;
837*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(gw);
838*57419a7fSflorian 	rtm.rtm_msglen += sizeof(gw);
839*57419a7fSflorian 	padlen = ROUNDUP(sizeof(gw)) - sizeof(gw);
840*57419a7fSflorian 	if (padlen > 0) {
841*57419a7fSflorian 		iov[iovcnt].iov_base = &pad;
842*57419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
843*57419a7fSflorian 		rtm.rtm_msglen += padlen;
844*57419a7fSflorian 	}
845*57419a7fSflorian 
846*57419a7fSflorian 	memset(&mask, 0, sizeof(mask));
847*57419a7fSflorian 	mask.sin_family = AF_INET;
848*57419a7fSflorian 	mask.sin_len = sizeof(struct sockaddr_in);
849*57419a7fSflorian 	iov[iovcnt].iov_base = &mask;
850*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(mask);
851*57419a7fSflorian 	rtm.rtm_msglen += sizeof(mask);
852*57419a7fSflorian 	padlen = ROUNDUP(sizeof(mask)) - sizeof(mask);
853*57419a7fSflorian 	if (padlen > 0) {
854*57419a7fSflorian 		iov[iovcnt].iov_base = &pad;
855*57419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
856*57419a7fSflorian 		rtm.rtm_msglen += padlen;
857*57419a7fSflorian 	}
858*57419a7fSflorian 
859*57419a7fSflorian 	memset(&rl, 0, sizeof(rl));
860*57419a7fSflorian 	rl.sr_len = sizeof(rl);
861*57419a7fSflorian 	rl.sr_family = AF_UNSPEC;
862*57419a7fSflorian 	(void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s",
863*57419a7fSflorian 	    DHCPLEASED_RTA_LABEL);
864*57419a7fSflorian 	iov[iovcnt].iov_base = &rl;
865*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rl);
866*57419a7fSflorian 	rtm.rtm_msglen += sizeof(rl);
867*57419a7fSflorian 	padlen = ROUNDUP(sizeof(rl)) - sizeof(rl);
868*57419a7fSflorian 	if (padlen > 0) {
869*57419a7fSflorian 		iov[iovcnt].iov_base = &pad;
870*57419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
871*57419a7fSflorian 		rtm.rtm_msglen += padlen;
872*57419a7fSflorian 	}
873*57419a7fSflorian 
874*57419a7fSflorian 	if (writev(routesock, iov, iovcnt) == -1)
875*57419a7fSflorian 		log_warn("failed to send route message");
876*57419a7fSflorian }
877*57419a7fSflorian 
878*57419a7fSflorian #ifndef	SMALL
879*57419a7fSflorian const char*
880*57419a7fSflorian sin_to_str(struct sockaddr_in *sin)
881*57419a7fSflorian {
882*57419a7fSflorian 	static char hbuf[NI_MAXHOST];
883*57419a7fSflorian 	int error;
884*57419a7fSflorian 
885*57419a7fSflorian 	error = getnameinfo((struct sockaddr *)sin, sin->sin_len, hbuf,
886*57419a7fSflorian 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
887*57419a7fSflorian 	if (error) {
888*57419a7fSflorian 		log_warnx("%s", gai_strerror(error));
889*57419a7fSflorian 		strlcpy(hbuf, "unknown", sizeof(hbuf));
890*57419a7fSflorian 	}
891*57419a7fSflorian 	return hbuf;
892*57419a7fSflorian }
893*57419a7fSflorian #endif	/* SMALL */
894*57419a7fSflorian 
895*57419a7fSflorian void
896*57419a7fSflorian open_bpfsock(uint32_t if_index)
897*57419a7fSflorian {
898*57419a7fSflorian 	int		 bpfsock;
899*57419a7fSflorian 	char		 ifname[IF_NAMESIZE];
900*57419a7fSflorian 
901*57419a7fSflorian 	log_debug("%s: %d", __func__, if_index);
902*57419a7fSflorian 
903*57419a7fSflorian 	if (if_indextoname(if_index, ifname) == 0) {
904*57419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__, if_index);
905*57419a7fSflorian 		return;
906*57419a7fSflorian 	}
907*57419a7fSflorian 
908*57419a7fSflorian 	if ((bpfsock = get_bpf_sock(ifname)) == -1)
909*57419a7fSflorian 		return;
910*57419a7fSflorian 
911*57419a7fSflorian 	main_imsg_compose_frontend(IMSG_BPFSOCK, bpfsock, &if_index,
912*57419a7fSflorian 	    sizeof(if_index));
913*57419a7fSflorian }
914*57419a7fSflorian 
915*57419a7fSflorian void
916*57419a7fSflorian propose_rdns(struct imsg_propose_rdns *rdns)
917*57419a7fSflorian {
918*57419a7fSflorian 	struct rt_msghdr		 rtm;
919*57419a7fSflorian 	struct sockaddr_rtdns		 rtdns;
920*57419a7fSflorian 	struct iovec			 iov[3];
921*57419a7fSflorian 	long				 pad = 0;
922*57419a7fSflorian 	int				 iovcnt = 0, padlen;
923*57419a7fSflorian 
924*57419a7fSflorian 	memset(&rtm, 0, sizeof(rtm));
925*57419a7fSflorian 
926*57419a7fSflorian 	rtm.rtm_version = RTM_VERSION;
927*57419a7fSflorian 	rtm.rtm_type = RTM_PROPOSAL;
928*57419a7fSflorian 	rtm.rtm_msglen = sizeof(rtm);
929*57419a7fSflorian 	rtm.rtm_tableid = rdns->rdomain;
930*57419a7fSflorian 	rtm.rtm_index = rdns->if_index;
931*57419a7fSflorian 	rtm.rtm_seq = ++rtm_seq;
932*57419a7fSflorian 	rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT;
933*57419a7fSflorian 	rtm.rtm_addrs = RTA_DNS;
934*57419a7fSflorian 	rtm.rtm_flags = RTF_UP;
935*57419a7fSflorian 
936*57419a7fSflorian 	iov[iovcnt].iov_base = &rtm;
937*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rtm);
938*57419a7fSflorian 
939*57419a7fSflorian 	memset(&rtdns, 0, sizeof(rtdns));
940*57419a7fSflorian 	rtdns.sr_family = AF_INET;
941*57419a7fSflorian 	rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in_addr);
942*57419a7fSflorian 	memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns));
943*57419a7fSflorian 
944*57419a7fSflorian 	iov[iovcnt].iov_base = &rtdns;
945*57419a7fSflorian 	iov[iovcnt++].iov_len = sizeof(rtdns);
946*57419a7fSflorian 	rtm.rtm_msglen += sizeof(rtdns);
947*57419a7fSflorian 	padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns);
948*57419a7fSflorian 	if (padlen > 0) {
949*57419a7fSflorian 		iov[iovcnt].iov_base = &pad;
950*57419a7fSflorian 		iov[iovcnt++].iov_len = padlen;
951*57419a7fSflorian 		rtm.rtm_msglen += padlen;
952*57419a7fSflorian 	}
953*57419a7fSflorian 
954*57419a7fSflorian 	if (writev(routesock, iov, iovcnt) == -1)
955*57419a7fSflorian 		log_warn("failed to send route message");
956*57419a7fSflorian }
957*57419a7fSflorian 
958*57419a7fSflorian int
959*57419a7fSflorian open_lease_file(int if_index)
960*57419a7fSflorian {
961*57419a7fSflorian 	int	 len;
962*57419a7fSflorian 	char	 if_name[IF_NAMESIZE];
963*57419a7fSflorian 	char	 lease_file_buf[sizeof(LEASE_PATH) + IF_NAMESIZE];
964*57419a7fSflorian 
965*57419a7fSflorian 	if (if_indextoname(if_index, if_name) == 0) {
966*57419a7fSflorian 		log_warnx("%s: cannot find interface %d", __func__, if_index);
967*57419a7fSflorian 		return -1;
968*57419a7fSflorian 	}
969*57419a7fSflorian 
970*57419a7fSflorian 	len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s",
971*57419a7fSflorian 	    LEASE_PATH, if_name);
972*57419a7fSflorian 	if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) {
973*57419a7fSflorian 		log_warnx("%s: failed to encode lease path for %s", __func__,
974*57419a7fSflorian 		    if_name);
975*57419a7fSflorian 		return -1;
976*57419a7fSflorian 	}
977*57419a7fSflorian 
978*57419a7fSflorian 	return (open(lease_file_buf, O_RDONLY));
979*57419a7fSflorian }
980