xref: /openbsd/sbin/dhcpleased/frontend.c (revision 57419a7f)
1*57419a7fSflorian /*	$OpenBSD: frontend.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/syslog.h>
26*57419a7fSflorian #include <sys/uio.h>
27*57419a7fSflorian 
28*57419a7fSflorian #include <net/bpf.h>
29*57419a7fSflorian #include <net/if.h>
30*57419a7fSflorian #include <net/if_dl.h>
31*57419a7fSflorian #include <net/if_types.h>
32*57419a7fSflorian #include <net/route.h>
33*57419a7fSflorian 
34*57419a7fSflorian #include <netinet/ip.h>
35*57419a7fSflorian #include <netinet/udp.h>
36*57419a7fSflorian 
37*57419a7fSflorian #include <arpa/inet.h>
38*57419a7fSflorian 
39*57419a7fSflorian #include <netinet/in.h>
40*57419a7fSflorian #include <netinet/if_ether.h>
41*57419a7fSflorian 
42*57419a7fSflorian #include <errno.h>
43*57419a7fSflorian #include <event.h>
44*57419a7fSflorian #include <ifaddrs.h>
45*57419a7fSflorian #include <imsg.h>
46*57419a7fSflorian #include <pwd.h>
47*57419a7fSflorian #include <signal.h>
48*57419a7fSflorian #include <stdio.h>
49*57419a7fSflorian #include <stdlib.h>
50*57419a7fSflorian #include <string.h>
51*57419a7fSflorian #include <unistd.h>
52*57419a7fSflorian 
53*57419a7fSflorian #include "bpf.h"
54*57419a7fSflorian #include "log.h"
55*57419a7fSflorian #include "dhcpleased.h"
56*57419a7fSflorian #include "frontend.h"
57*57419a7fSflorian #include "control.h"
58*57419a7fSflorian #include "checksum.h"
59*57419a7fSflorian 
60*57419a7fSflorian #define	ROUTE_SOCKET_BUF_SIZE	16384
61*57419a7fSflorian 
62*57419a7fSflorian struct bpf_ev {
63*57419a7fSflorian 	struct event		 ev;
64*57419a7fSflorian 	uint8_t			 buf[BPFLEN];
65*57419a7fSflorian };
66*57419a7fSflorian 
67*57419a7fSflorian struct iface           {
68*57419a7fSflorian 	LIST_ENTRY(iface)	 entries;
69*57419a7fSflorian 	struct bpf_ev		 bpfev;
70*57419a7fSflorian 	struct ether_addr	 hw_address;
71*57419a7fSflorian 	uint32_t		 if_index;
72*57419a7fSflorian 	int			 rdomain;
73*57419a7fSflorian 	int			 send_discover;
74*57419a7fSflorian 	uint32_t		 xid;
75*57419a7fSflorian 	struct in_addr		 requested_ip;
76*57419a7fSflorian 	struct in_addr		 server_identifier;
77*57419a7fSflorian 	struct in_addr		 dhcp_server;
78*57419a7fSflorian 	int			 udpsock;
79*57419a7fSflorian };
80*57419a7fSflorian 
81*57419a7fSflorian __dead void	 frontend_shutdown(void);
82*57419a7fSflorian void		 frontend_sig_handler(int, short, void *);
83*57419a7fSflorian void		 update_iface(uint32_t, char*);
84*57419a7fSflorian void		 frontend_startup(void);
85*57419a7fSflorian void		 route_receive(int, short, void *);
86*57419a7fSflorian void		 handle_route_message(struct rt_msghdr *, struct sockaddr **);
87*57419a7fSflorian void		 get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
88*57419a7fSflorian void		 bpf_receive(int, short, void *);
89*57419a7fSflorian int		 get_flags(char *);
90*57419a7fSflorian int		 get_xflags(char *);
91*57419a7fSflorian int		 get_ifrdomain(char *);
92*57419a7fSflorian struct iface	*get_iface_by_id(uint32_t);
93*57419a7fSflorian void		 remove_iface(uint32_t);
94*57419a7fSflorian void		 set_bpfsock(int, uint32_t);
95*57419a7fSflorian ssize_t		 build_packet(uint8_t, uint32_t, struct ether_addr *, struct
96*57419a7fSflorian 		     in_addr *, struct in_addr *);
97*57419a7fSflorian void		 send_discover(struct iface *);
98*57419a7fSflorian void		 send_request(struct iface *);
99*57419a7fSflorian void		 bpf_send_packet(struct iface *, uint8_t *, ssize_t);
100*57419a7fSflorian void		 udp_send_packet(struct iface *, uint8_t *, ssize_t);
101*57419a7fSflorian 
102*57419a7fSflorian LIST_HEAD(, iface)		 interfaces;
103*57419a7fSflorian static struct imsgev		*iev_main;
104*57419a7fSflorian static struct imsgev		*iev_engine;
105*57419a7fSflorian struct event			 ev_route;
106*57419a7fSflorian int				 ioctlsock;
107*57419a7fSflorian 
108*57419a7fSflorian uint8_t				 dhcp_packet[1500];
109*57419a7fSflorian 
110*57419a7fSflorian void
111*57419a7fSflorian frontend_sig_handler(int sig, short event, void *bula)
112*57419a7fSflorian {
113*57419a7fSflorian 	/*
114*57419a7fSflorian 	 * Normal signal handler rules don't apply because libevent
115*57419a7fSflorian 	 * decouples for us.
116*57419a7fSflorian 	 */
117*57419a7fSflorian 
118*57419a7fSflorian 	switch (sig) {
119*57419a7fSflorian 	case SIGINT:
120*57419a7fSflorian 	case SIGTERM:
121*57419a7fSflorian 		frontend_shutdown();
122*57419a7fSflorian 	default:
123*57419a7fSflorian 		fatalx("unexpected signal");
124*57419a7fSflorian 	}
125*57419a7fSflorian }
126*57419a7fSflorian 
127*57419a7fSflorian void
128*57419a7fSflorian frontend(int debug, int verbose)
129*57419a7fSflorian {
130*57419a7fSflorian 	struct event		 ev_sigint, ev_sigterm;
131*57419a7fSflorian 	struct passwd		*pw;
132*57419a7fSflorian 
133*57419a7fSflorian 	log_init(debug, LOG_DAEMON);
134*57419a7fSflorian 	log_setverbose(verbose);
135*57419a7fSflorian 
136*57419a7fSflorian 	if ((pw = getpwnam(DHCPLEASED_USER)) == NULL)
137*57419a7fSflorian 		fatal("getpwnam");
138*57419a7fSflorian 
139*57419a7fSflorian 	if (chroot(pw->pw_dir) == -1)
140*57419a7fSflorian 		fatal("chroot");
141*57419a7fSflorian 	if (chdir("/") == -1)
142*57419a7fSflorian 		fatal("chdir(\"/\")");
143*57419a7fSflorian 
144*57419a7fSflorian 	setproctitle("%s", "frontend");
145*57419a7fSflorian 	log_procinit("frontend");
146*57419a7fSflorian 
147*57419a7fSflorian 	if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
148*57419a7fSflorian 		fatal("socket");
149*57419a7fSflorian 
150*57419a7fSflorian 	if (setgroups(1, &pw->pw_gid) ||
151*57419a7fSflorian 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
152*57419a7fSflorian 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
153*57419a7fSflorian 		fatal("can't drop privileges");
154*57419a7fSflorian 
155*57419a7fSflorian 	if (pledge("stdio unix recvfd route", NULL) == -1)
156*57419a7fSflorian 		fatal("pledge");
157*57419a7fSflorian 	event_init();
158*57419a7fSflorian 
159*57419a7fSflorian 	/* Setup signal handler. */
160*57419a7fSflorian 	signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL);
161*57419a7fSflorian 	signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL);
162*57419a7fSflorian 	signal_add(&ev_sigint, NULL);
163*57419a7fSflorian 	signal_add(&ev_sigterm, NULL);
164*57419a7fSflorian 	signal(SIGPIPE, SIG_IGN);
165*57419a7fSflorian 	signal(SIGHUP, SIG_IGN);
166*57419a7fSflorian 
167*57419a7fSflorian 	/* Setup pipe and event handler to the parent process. */
168*57419a7fSflorian 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
169*57419a7fSflorian 		fatal(NULL);
170*57419a7fSflorian 	imsg_init(&iev_main->ibuf, 3);
171*57419a7fSflorian 	iev_main->handler = frontend_dispatch_main;
172*57419a7fSflorian 	iev_main->events = EV_READ;
173*57419a7fSflorian 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
174*57419a7fSflorian 	    iev_main->handler, iev_main);
175*57419a7fSflorian 	event_add(&iev_main->ev, NULL);
176*57419a7fSflorian 
177*57419a7fSflorian 	LIST_INIT(&interfaces);
178*57419a7fSflorian 	event_dispatch();
179*57419a7fSflorian 
180*57419a7fSflorian 	frontend_shutdown();
181*57419a7fSflorian }
182*57419a7fSflorian 
183*57419a7fSflorian __dead void
184*57419a7fSflorian frontend_shutdown(void)
185*57419a7fSflorian {
186*57419a7fSflorian 	/* Close pipes. */
187*57419a7fSflorian 	msgbuf_write(&iev_engine->ibuf.w);
188*57419a7fSflorian 	msgbuf_clear(&iev_engine->ibuf.w);
189*57419a7fSflorian 	close(iev_engine->ibuf.fd);
190*57419a7fSflorian 	msgbuf_write(&iev_main->ibuf.w);
191*57419a7fSflorian 	msgbuf_clear(&iev_main->ibuf.w);
192*57419a7fSflorian 	close(iev_main->ibuf.fd);
193*57419a7fSflorian 
194*57419a7fSflorian 	free(iev_engine);
195*57419a7fSflorian 	free(iev_main);
196*57419a7fSflorian 
197*57419a7fSflorian 	log_info("frontend exiting");
198*57419a7fSflorian 	exit(0);
199*57419a7fSflorian }
200*57419a7fSflorian 
201*57419a7fSflorian int
202*57419a7fSflorian frontend_imsg_compose_main(int type, pid_t pid, void *data,
203*57419a7fSflorian     uint16_t datalen)
204*57419a7fSflorian {
205*57419a7fSflorian 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
206*57419a7fSflorian 	    datalen));
207*57419a7fSflorian }
208*57419a7fSflorian 
209*57419a7fSflorian int
210*57419a7fSflorian frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid,
211*57419a7fSflorian     void *data, uint16_t datalen)
212*57419a7fSflorian {
213*57419a7fSflorian 	return (imsg_compose_event(iev_engine, type, peerid, pid, -1,
214*57419a7fSflorian 	    data, datalen));
215*57419a7fSflorian }
216*57419a7fSflorian 
217*57419a7fSflorian void
218*57419a7fSflorian frontend_dispatch_main(int fd, short event, void *bula)
219*57419a7fSflorian {
220*57419a7fSflorian 	struct imsg		 imsg;
221*57419a7fSflorian 	struct imsgev		*iev = bula;
222*57419a7fSflorian 	struct imsgbuf		*ibuf = &iev->ibuf;
223*57419a7fSflorian 	struct iface		*iface;
224*57419a7fSflorian 	ssize_t			 n;
225*57419a7fSflorian 	int			 shut = 0, bpfsock, if_index, udpsock;
226*57419a7fSflorian 
227*57419a7fSflorian 	if (event & EV_READ) {
228*57419a7fSflorian 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
229*57419a7fSflorian 			fatal("imsg_read error");
230*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
231*57419a7fSflorian 			shut = 1;
232*57419a7fSflorian 	}
233*57419a7fSflorian 	if (event & EV_WRITE) {
234*57419a7fSflorian 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
235*57419a7fSflorian 			fatal("msgbuf_write");
236*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
237*57419a7fSflorian 			shut = 1;
238*57419a7fSflorian 	}
239*57419a7fSflorian 
240*57419a7fSflorian 	for (;;) {
241*57419a7fSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
242*57419a7fSflorian 			fatal("%s: imsg_get error", __func__);
243*57419a7fSflorian 		if (n == 0)	/* No more messages. */
244*57419a7fSflorian 			break;
245*57419a7fSflorian 
246*57419a7fSflorian 		switch (imsg.hdr.type) {
247*57419a7fSflorian 		case IMSG_SOCKET_IPC:
248*57419a7fSflorian 			/*
249*57419a7fSflorian 			 * Setup pipe and event handler to the engine
250*57419a7fSflorian 			 * process.
251*57419a7fSflorian 			 */
252*57419a7fSflorian 			if (iev_engine)
253*57419a7fSflorian 				fatalx("%s: received unexpected imsg fd "
254*57419a7fSflorian 				    "to frontend", __func__);
255*57419a7fSflorian 
256*57419a7fSflorian 			if ((fd = imsg.fd) == -1)
257*57419a7fSflorian 				fatalx("%s: expected to receive imsg fd to "
258*57419a7fSflorian 				   "frontend but didn't receive any",
259*57419a7fSflorian 				   __func__);
260*57419a7fSflorian 
261*57419a7fSflorian 			iev_engine = malloc(sizeof(struct imsgev));
262*57419a7fSflorian 			if (iev_engine == NULL)
263*57419a7fSflorian 				fatal(NULL);
264*57419a7fSflorian 
265*57419a7fSflorian 			imsg_init(&iev_engine->ibuf, fd);
266*57419a7fSflorian 			iev_engine->handler = frontend_dispatch_engine;
267*57419a7fSflorian 			iev_engine->events = EV_READ;
268*57419a7fSflorian 
269*57419a7fSflorian 			event_set(&iev_engine->ev, iev_engine->ibuf.fd,
270*57419a7fSflorian 			iev_engine->events, iev_engine->handler, iev_engine);
271*57419a7fSflorian 			event_add(&iev_engine->ev, NULL);
272*57419a7fSflorian 			break;
273*57419a7fSflorian 		case IMSG_BPFSOCK:
274*57419a7fSflorian 			if ((bpfsock = imsg.fd) == -1)
275*57419a7fSflorian 				fatalx("%s: expected to receive imsg "
276*57419a7fSflorian 				    "bpf fd but didn't receive any",
277*57419a7fSflorian 				    __func__);
278*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
279*57419a7fSflorian 				fatalx("%s: IMSG_BPFSOCK wrong length: "
280*57419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
281*57419a7fSflorian 			memcpy(&if_index, imsg.data, sizeof(if_index));
282*57419a7fSflorian 			set_bpfsock(bpfsock, if_index);
283*57419a7fSflorian 			break;
284*57419a7fSflorian 		case IMSG_UDPSOCK:
285*57419a7fSflorian 			if ((udpsock = imsg.fd) == -1)
286*57419a7fSflorian 				fatalx("%s: expected to receive imsg "
287*57419a7fSflorian 				    "udpsocket fd but didn't receive any",
288*57419a7fSflorian 				    __func__);
289*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
290*57419a7fSflorian 				fatalx("%s: IMSG_UDPSOCK wrong length: "
291*57419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
292*57419a7fSflorian 			memcpy(&if_index, imsg.data, sizeof(if_index));
293*57419a7fSflorian 			if ((iface = get_iface_by_id(if_index)) == NULL) {
294*57419a7fSflorian 				close(fd);
295*57419a7fSflorian 				break;
296*57419a7fSflorian 			}
297*57419a7fSflorian 			if (iface->udpsock != -1)
298*57419a7fSflorian 				fatalx("%s: received unexpected udpsocket",
299*57419a7fSflorian 				    __func__);
300*57419a7fSflorian 			iface->udpsock = udpsock;
301*57419a7fSflorian 			break;
302*57419a7fSflorian 		case IMSG_CLOSE_UDPSOCK:
303*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
304*57419a7fSflorian 				fatalx("%s: IMSG_UDPSOCK wrong length: "
305*57419a7fSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
306*57419a7fSflorian 			memcpy(&if_index, imsg.data, sizeof(if_index));
307*57419a7fSflorian 			if ((iface = get_iface_by_id(if_index)) != NULL &&
308*57419a7fSflorian 			    iface->udpsock != -1) {
309*57419a7fSflorian 				close(iface->udpsock);
310*57419a7fSflorian 				iface->udpsock = -1;
311*57419a7fSflorian 			}
312*57419a7fSflorian 			break;
313*57419a7fSflorian 		case IMSG_ROUTESOCK:
314*57419a7fSflorian 			if ((fd = imsg.fd) == -1)
315*57419a7fSflorian 				fatalx("%s: expected to receive imsg "
316*57419a7fSflorian 				    "routesocket fd but didn't receive any",
317*57419a7fSflorian 				    __func__);
318*57419a7fSflorian 			event_set(&ev_route, fd, EV_READ | EV_PERSIST,
319*57419a7fSflorian 			    route_receive, NULL);
320*57419a7fSflorian 			break;
321*57419a7fSflorian 		case IMSG_STARTUP:
322*57419a7fSflorian 			frontend_startup();
323*57419a7fSflorian 			break;
324*57419a7fSflorian #ifndef	SMALL
325*57419a7fSflorian 		case IMSG_CONTROLFD:
326*57419a7fSflorian 			if ((fd = imsg.fd) == -1)
327*57419a7fSflorian 				fatalx("%s: expected to receive imsg "
328*57419a7fSflorian 				    "control fd but didn't receive any",
329*57419a7fSflorian 				    __func__);
330*57419a7fSflorian 			/* Listen on control socket. */
331*57419a7fSflorian 			control_listen(fd);
332*57419a7fSflorian 			break;
333*57419a7fSflorian 		case IMSG_CTL_END:
334*57419a7fSflorian 			control_imsg_relay(&imsg);
335*57419a7fSflorian 			break;
336*57419a7fSflorian #endif	/* SMALL */
337*57419a7fSflorian 		default:
338*57419a7fSflorian 			log_debug("%s: error handling imsg %d", __func__,
339*57419a7fSflorian 			    imsg.hdr.type);
340*57419a7fSflorian 			break;
341*57419a7fSflorian 		}
342*57419a7fSflorian 		imsg_free(&imsg);
343*57419a7fSflorian 	}
344*57419a7fSflorian 	if (!shut)
345*57419a7fSflorian 		imsg_event_add(iev);
346*57419a7fSflorian 	else {
347*57419a7fSflorian 		/* This pipe is dead. Remove its event handler. */
348*57419a7fSflorian 		event_del(&iev->ev);
349*57419a7fSflorian 		event_loopexit(NULL);
350*57419a7fSflorian 	}
351*57419a7fSflorian }
352*57419a7fSflorian 
353*57419a7fSflorian void
354*57419a7fSflorian frontend_dispatch_engine(int fd, short event, void *bula)
355*57419a7fSflorian {
356*57419a7fSflorian 	struct imsgev		*iev = bula;
357*57419a7fSflorian 	struct imsgbuf		*ibuf = &iev->ibuf;
358*57419a7fSflorian 	struct imsg		 imsg;
359*57419a7fSflorian 	struct iface		*iface;
360*57419a7fSflorian 	ssize_t			 n;
361*57419a7fSflorian 	int			 shut = 0;
362*57419a7fSflorian 
363*57419a7fSflorian 	if (event & EV_READ) {
364*57419a7fSflorian 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
365*57419a7fSflorian 			fatal("imsg_read error");
366*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
367*57419a7fSflorian 			shut = 1;
368*57419a7fSflorian 	}
369*57419a7fSflorian 	if (event & EV_WRITE) {
370*57419a7fSflorian 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
371*57419a7fSflorian 			fatal("msgbuf_write");
372*57419a7fSflorian 		if (n == 0)	/* Connection closed. */
373*57419a7fSflorian 			shut = 1;
374*57419a7fSflorian 	}
375*57419a7fSflorian 
376*57419a7fSflorian 	for (;;) {
377*57419a7fSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
378*57419a7fSflorian 			fatal("%s: imsg_get error", __func__);
379*57419a7fSflorian 		if (n == 0)	/* No more messages. */
380*57419a7fSflorian 			break;
381*57419a7fSflorian 
382*57419a7fSflorian 		switch (imsg.hdr.type) {
383*57419a7fSflorian #ifndef	SMALL
384*57419a7fSflorian 		case IMSG_CTL_END:
385*57419a7fSflorian 		case IMSG_CTL_SHOW_INTERFACE_INFO:
386*57419a7fSflorian 			control_imsg_relay(&imsg);
387*57419a7fSflorian 			break;
388*57419a7fSflorian #endif	/* SMALL */
389*57419a7fSflorian 		case IMSG_SEND_DISCOVER: {
390*57419a7fSflorian 			struct imsg_req_discover	 imsg_req_discover;
391*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_discover))
392*57419a7fSflorian 				fatalx("%s: IMSG_SEND_DISCOVER wrong "
393*57419a7fSflorian 				    "length: %lu", __func__,
394*57419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
395*57419a7fSflorian 			memcpy(&imsg_req_discover, imsg.data,
396*57419a7fSflorian 			    sizeof(imsg_req_discover));
397*57419a7fSflorian 			iface = get_iface_by_id(imsg_req_discover.if_index);
398*57419a7fSflorian 			if (iface != NULL) {
399*57419a7fSflorian 				iface->xid = imsg_req_discover.xid;
400*57419a7fSflorian 				send_discover(iface);
401*57419a7fSflorian 			}
402*57419a7fSflorian 			break;
403*57419a7fSflorian 		}
404*57419a7fSflorian 		case IMSG_SEND_REQUEST: {
405*57419a7fSflorian 			struct imsg_req_request	 imsg_req_request;
406*57419a7fSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_request))
407*57419a7fSflorian 				fatalx("%s: IMSG_SEND_REQUEST wrong "
408*57419a7fSflorian 				    "length: %lu", __func__,
409*57419a7fSflorian 				    IMSG_DATA_SIZE(imsg));
410*57419a7fSflorian 			memcpy(&imsg_req_request, imsg.data,
411*57419a7fSflorian 			    sizeof(imsg_req_request));
412*57419a7fSflorian 			iface = get_iface_by_id(imsg_req_request.if_index);
413*57419a7fSflorian 			if (iface != NULL) {
414*57419a7fSflorian 				iface->xid = imsg_req_request.xid;
415*57419a7fSflorian 				iface->requested_ip.s_addr =
416*57419a7fSflorian 				    imsg_req_request.requested_ip.s_addr;
417*57419a7fSflorian 				iface->server_identifier.s_addr =
418*57419a7fSflorian 				    imsg_req_request.server_identifier.s_addr;
419*57419a7fSflorian 				iface->dhcp_server.s_addr =
420*57419a7fSflorian 				    imsg_req_request.dhcp_server.s_addr;
421*57419a7fSflorian 				send_request(iface);
422*57419a7fSflorian 			}
423*57419a7fSflorian 			break;
424*57419a7fSflorian 		}
425*57419a7fSflorian 		default:
426*57419a7fSflorian 			log_debug("%s: error handling imsg %d", __func__,
427*57419a7fSflorian 			    imsg.hdr.type);
428*57419a7fSflorian 			break;
429*57419a7fSflorian 		}
430*57419a7fSflorian 		imsg_free(&imsg);
431*57419a7fSflorian 	}
432*57419a7fSflorian 	if (!shut)
433*57419a7fSflorian 		imsg_event_add(iev);
434*57419a7fSflorian 	else {
435*57419a7fSflorian 		/* This pipe is dead. Remove its event handler. */
436*57419a7fSflorian 		event_del(&iev->ev);
437*57419a7fSflorian 		event_loopexit(NULL);
438*57419a7fSflorian 	}
439*57419a7fSflorian }
440*57419a7fSflorian 
441*57419a7fSflorian int
442*57419a7fSflorian get_flags(char *if_name)
443*57419a7fSflorian {
444*57419a7fSflorian 	struct ifreq		 ifr;
445*57419a7fSflorian 
446*57419a7fSflorian 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
447*57419a7fSflorian 	if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
448*57419a7fSflorian 		log_warn("SIOCGIFFLAGS");
449*57419a7fSflorian 		return -1;
450*57419a7fSflorian 	}
451*57419a7fSflorian 	return ifr.ifr_flags;
452*57419a7fSflorian }
453*57419a7fSflorian 
454*57419a7fSflorian int
455*57419a7fSflorian get_xflags(char *if_name)
456*57419a7fSflorian {
457*57419a7fSflorian 	struct ifreq		 ifr;
458*57419a7fSflorian 
459*57419a7fSflorian 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
460*57419a7fSflorian 	if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) {
461*57419a7fSflorian 		log_warn("SIOCGIFXFLAGS");
462*57419a7fSflorian 		return -1;
463*57419a7fSflorian 	}
464*57419a7fSflorian 	return ifr.ifr_flags;
465*57419a7fSflorian }
466*57419a7fSflorian 
467*57419a7fSflorian int
468*57419a7fSflorian get_ifrdomain(char *if_name)
469*57419a7fSflorian {
470*57419a7fSflorian 	struct ifreq		 ifr;
471*57419a7fSflorian 
472*57419a7fSflorian 	strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
473*57419a7fSflorian 	if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) {
474*57419a7fSflorian 		log_warn("SIOCGIFRDOMAIN");
475*57419a7fSflorian 		return -1;
476*57419a7fSflorian 	}
477*57419a7fSflorian 	return ifr.ifr_rdomainid;
478*57419a7fSflorian }
479*57419a7fSflorian 
480*57419a7fSflorian void
481*57419a7fSflorian update_iface(uint32_t if_index, char* if_name)
482*57419a7fSflorian {
483*57419a7fSflorian 	struct iface		*iface;
484*57419a7fSflorian 	struct imsg_ifinfo	 imsg_ifinfo;
485*57419a7fSflorian 	struct ifaddrs		*ifap, *ifa;
486*57419a7fSflorian 	struct sockaddr_dl	*sdl;
487*57419a7fSflorian 	int			 flags, xflags, ifrdomain;
488*57419a7fSflorian 
489*57419a7fSflorian 	if ((flags = get_flags(if_name)) == -1 || (xflags =
490*57419a7fSflorian 	    get_xflags(if_name)) == -1)
491*57419a7fSflorian 		return;
492*57419a7fSflorian 
493*57419a7fSflorian 	if (!(xflags & IFXF_AUTOCONF4))
494*57419a7fSflorian 		return;
495*57419a7fSflorian 
496*57419a7fSflorian 	if((ifrdomain = get_ifrdomain(if_name)) == -1)
497*57419a7fSflorian 		return;
498*57419a7fSflorian 
499*57419a7fSflorian 	iface = get_iface_by_id(if_index);
500*57419a7fSflorian 
501*57419a7fSflorian 	if (iface != NULL) {
502*57419a7fSflorian 		if (iface->rdomain != ifrdomain) {
503*57419a7fSflorian 			iface->rdomain = ifrdomain;
504*57419a7fSflorian 			if (iface->udpsock != -1) {
505*57419a7fSflorian 				close(iface->udpsock);
506*57419a7fSflorian 				iface->udpsock = -1;
507*57419a7fSflorian 			}
508*57419a7fSflorian 		}
509*57419a7fSflorian 	} else {
510*57419a7fSflorian 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
511*57419a7fSflorian 			fatal("calloc");
512*57419a7fSflorian 		iface->if_index = if_index;
513*57419a7fSflorian 		iface->rdomain = ifrdomain;
514*57419a7fSflorian 		iface->udpsock = -1;
515*57419a7fSflorian 		LIST_INSERT_HEAD(&interfaces, iface, entries);
516*57419a7fSflorian 		frontend_imsg_compose_main(IMSG_OPEN_BPFSOCK, 0,
517*57419a7fSflorian 		    &if_index, sizeof(if_index));
518*57419a7fSflorian 	}
519*57419a7fSflorian 
520*57419a7fSflorian 	memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo));
521*57419a7fSflorian 
522*57419a7fSflorian 	imsg_ifinfo.if_index = if_index;
523*57419a7fSflorian 	imsg_ifinfo.rdomain = ifrdomain;
524*57419a7fSflorian 
525*57419a7fSflorian 	imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP |
526*57419a7fSflorian 	    IFF_RUNNING);
527*57419a7fSflorian 
528*57419a7fSflorian 
529*57419a7fSflorian 	if (getifaddrs(&ifap) != 0)
530*57419a7fSflorian 		fatal("getifaddrs");
531*57419a7fSflorian 
532*57419a7fSflorian 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
533*57419a7fSflorian 		if (strcmp(if_name, ifa->ifa_name) != 0)
534*57419a7fSflorian 			continue;
535*57419a7fSflorian 		if (ifa->ifa_addr == NULL)
536*57419a7fSflorian 			continue;
537*57419a7fSflorian 
538*57419a7fSflorian 		switch(ifa->ifa_addr->sa_family) {
539*57419a7fSflorian 		case AF_LINK:
540*57419a7fSflorian 			imsg_ifinfo.link_state =
541*57419a7fSflorian 			    ((struct if_data *)ifa->ifa_data)->ifi_link_state;
542*57419a7fSflorian 			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
543*57419a7fSflorian 			if (sdl->sdl_type != IFT_ETHER ||
544*57419a7fSflorian 			    sdl->sdl_alen != ETHER_ADDR_LEN)
545*57419a7fSflorian 				continue;
546*57419a7fSflorian 			memcpy(iface->hw_address.ether_addr_octet,
547*57419a7fSflorian 			    LLADDR(sdl), ETHER_ADDR_LEN);
548*57419a7fSflorian 			goto out;
549*57419a7fSflorian 		default:
550*57419a7fSflorian 			break;
551*57419a7fSflorian 		}
552*57419a7fSflorian 	}
553*57419a7fSflorian  out:
554*57419a7fSflorian 	freeifaddrs(ifap);
555*57419a7fSflorian 
556*57419a7fSflorian 	memcpy(&imsg_ifinfo.hw_address, &iface->hw_address,
557*57419a7fSflorian 	    sizeof(imsg_ifinfo.hw_address));
558*57419a7fSflorian 
559*57419a7fSflorian 	frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo,
560*57419a7fSflorian 	    sizeof(imsg_ifinfo));
561*57419a7fSflorian }
562*57419a7fSflorian 
563*57419a7fSflorian void
564*57419a7fSflorian frontend_startup(void)
565*57419a7fSflorian {
566*57419a7fSflorian 	struct if_nameindex	*ifnidxp, *ifnidx;
567*57419a7fSflorian 
568*57419a7fSflorian 	if (!event_initialized(&ev_route))
569*57419a7fSflorian 		fatalx("%s: did not receive a route socket from the main "
570*57419a7fSflorian 		    "process", __func__);
571*57419a7fSflorian 
572*57419a7fSflorian 	event_add(&ev_route, NULL);
573*57419a7fSflorian 
574*57419a7fSflorian 	if ((ifnidxp = if_nameindex()) == NULL)
575*57419a7fSflorian 		fatalx("if_nameindex");
576*57419a7fSflorian 
577*57419a7fSflorian 	for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL;
578*57419a7fSflorian 	    ifnidx++)
579*57419a7fSflorian 		update_iface(ifnidx->if_index, ifnidx->if_name);
580*57419a7fSflorian 
581*57419a7fSflorian 	if_freenameindex(ifnidxp);
582*57419a7fSflorian }
583*57419a7fSflorian 
584*57419a7fSflorian void
585*57419a7fSflorian route_receive(int fd, short events, void *arg)
586*57419a7fSflorian {
587*57419a7fSflorian 	static uint8_t			 *buf;
588*57419a7fSflorian 
589*57419a7fSflorian 	struct rt_msghdr		*rtm;
590*57419a7fSflorian 	struct sockaddr			*sa, *rti_info[RTAX_MAX];
591*57419a7fSflorian 	ssize_t				 n;
592*57419a7fSflorian 
593*57419a7fSflorian 	if (buf == NULL) {
594*57419a7fSflorian 		buf = malloc(ROUTE_SOCKET_BUF_SIZE);
595*57419a7fSflorian 		if (buf == NULL)
596*57419a7fSflorian 			fatal("malloc");
597*57419a7fSflorian 	}
598*57419a7fSflorian 	rtm = (struct rt_msghdr *)buf;
599*57419a7fSflorian 	if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
600*57419a7fSflorian 		if (errno == EAGAIN || errno == EINTR)
601*57419a7fSflorian 			return;
602*57419a7fSflorian 		log_warn("dispatch_rtmsg: read error");
603*57419a7fSflorian 		return;
604*57419a7fSflorian 	}
605*57419a7fSflorian 
606*57419a7fSflorian 	if (n == 0)
607*57419a7fSflorian 		fatal("routing socket closed");
608*57419a7fSflorian 
609*57419a7fSflorian 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
610*57419a7fSflorian 		log_warnx("partial rtm of %zd in buffer", n);
611*57419a7fSflorian 		return;
612*57419a7fSflorian 	}
613*57419a7fSflorian 
614*57419a7fSflorian 	if (rtm->rtm_version != RTM_VERSION)
615*57419a7fSflorian 		return;
616*57419a7fSflorian 
617*57419a7fSflorian 	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
618*57419a7fSflorian 	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
619*57419a7fSflorian 
620*57419a7fSflorian 	handle_route_message(rtm, rti_info);
621*57419a7fSflorian }
622*57419a7fSflorian 
623*57419a7fSflorian void
624*57419a7fSflorian handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
625*57419a7fSflorian {
626*57419a7fSflorian 	struct if_msghdr		*ifm;
627*57419a7fSflorian 	int				 xflags, if_index;
628*57419a7fSflorian 	char				 ifnamebuf[IFNAMSIZ];
629*57419a7fSflorian 	char				*if_name;
630*57419a7fSflorian 
631*57419a7fSflorian 	switch (rtm->rtm_type) {
632*57419a7fSflorian 	case RTM_IFINFO:
633*57419a7fSflorian 		ifm = (struct if_msghdr *)rtm;
634*57419a7fSflorian 		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
635*57419a7fSflorian 		if (if_name == NULL) {
636*57419a7fSflorian 			log_debug("RTM_IFINFO: lost if %d", ifm->ifm_index);
637*57419a7fSflorian 			if_index = ifm->ifm_index;
638*57419a7fSflorian 			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
639*57419a7fSflorian 			    &if_index, sizeof(if_index));
640*57419a7fSflorian 			remove_iface(if_index);
641*57419a7fSflorian 		} else {
642*57419a7fSflorian 			xflags = get_xflags(if_name);
643*57419a7fSflorian 			if (xflags == -1 || !(xflags & IFXF_AUTOCONF4)) {
644*57419a7fSflorian 				log_debug("RTM_IFINFO: %s(%d) no(longer) "
645*57419a7fSflorian 				   "autoconf4", if_name, ifm->ifm_index);
646*57419a7fSflorian 				if_index = ifm->ifm_index;
647*57419a7fSflorian 				frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
648*57419a7fSflorian 				    0, &if_index, sizeof(if_index));
649*57419a7fSflorian 			} else {
650*57419a7fSflorian 				update_iface(ifm->ifm_index, if_name);
651*57419a7fSflorian 			}
652*57419a7fSflorian 		}
653*57419a7fSflorian 		break;
654*57419a7fSflorian 	case RTM_NEWADDR:
655*57419a7fSflorian 		ifm = (struct if_msghdr *)rtm;
656*57419a7fSflorian 		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
657*57419a7fSflorian 		log_debug("RTM_NEWADDR: %s[%u]", if_name, ifm->ifm_index);
658*57419a7fSflorian 		update_iface(ifm->ifm_index, if_name);
659*57419a7fSflorian 		break;
660*57419a7fSflorian 	case RTM_PROPOSAL:
661*57419a7fSflorian 		if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) {
662*57419a7fSflorian 			log_debug("RTP_PROPOSAL_SOLICIT");
663*57419a7fSflorian 			frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS,
664*57419a7fSflorian 			    0, 0, NULL, 0);
665*57419a7fSflorian 		}
666*57419a7fSflorian 		break;
667*57419a7fSflorian 	default:
668*57419a7fSflorian 		log_debug("unexpected RTM: %d", rtm->rtm_type);
669*57419a7fSflorian 		break;
670*57419a7fSflorian 	}
671*57419a7fSflorian 
672*57419a7fSflorian }
673*57419a7fSflorian 
674*57419a7fSflorian #define ROUNDUP(a) \
675*57419a7fSflorian 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
676*57419a7fSflorian 
677*57419a7fSflorian void
678*57419a7fSflorian get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
679*57419a7fSflorian {
680*57419a7fSflorian 	int	i;
681*57419a7fSflorian 
682*57419a7fSflorian 	for (i = 0; i < RTAX_MAX; i++) {
683*57419a7fSflorian 		if (addrs & (1 << i)) {
684*57419a7fSflorian 			rti_info[i] = sa;
685*57419a7fSflorian 			sa = (struct sockaddr *)((char *)(sa) +
686*57419a7fSflorian 			    ROUNDUP(sa->sa_len));
687*57419a7fSflorian 		} else
688*57419a7fSflorian 			rti_info[i] = NULL;
689*57419a7fSflorian 	}
690*57419a7fSflorian }
691*57419a7fSflorian 
692*57419a7fSflorian void
693*57419a7fSflorian bpf_receive(int fd, short events, void *arg)
694*57419a7fSflorian {
695*57419a7fSflorian 	struct bpf_hdr		*hdr;
696*57419a7fSflorian 	struct imsg_dhcp	 imsg_dhcp;
697*57419a7fSflorian 	struct iface		*iface;
698*57419a7fSflorian 	ssize_t			 len, rem;
699*57419a7fSflorian 	uint8_t			*p;
700*57419a7fSflorian 
701*57419a7fSflorian 	iface = (struct iface *)arg;
702*57419a7fSflorian 
703*57419a7fSflorian 	log_debug("%s: fd: %d", __func__, fd);
704*57419a7fSflorian 	if ((len = read(fd, iface->bpfev.buf, BPFLEN)) == -1) {
705*57419a7fSflorian 		log_warn("read");
706*57419a7fSflorian 		return;
707*57419a7fSflorian 	}
708*57419a7fSflorian 	/* XXX len = 0 */
709*57419a7fSflorian 	log_debug("%s: %ld", __func__, len);
710*57419a7fSflorian 
711*57419a7fSflorian 	memset(&imsg_dhcp, 0, sizeof(imsg_dhcp));
712*57419a7fSflorian 	imsg_dhcp.if_index = iface->if_index;
713*57419a7fSflorian 
714*57419a7fSflorian 	rem = len;
715*57419a7fSflorian 	p = iface->bpfev.buf;
716*57419a7fSflorian 
717*57419a7fSflorian 	while (rem > 0) {
718*57419a7fSflorian 		if ((size_t)rem < sizeof(*hdr)) {
719*57419a7fSflorian 			log_warnx("packet too short");
720*57419a7fSflorian 			return;
721*57419a7fSflorian 		}
722*57419a7fSflorian 		hdr = (struct bpf_hdr *)p;
723*57419a7fSflorian 		if (hdr->bh_caplen != hdr->bh_datalen) {
724*57419a7fSflorian 			log_warnx("skipping truncated packet");
725*57419a7fSflorian 			goto cont;
726*57419a7fSflorian 		}
727*57419a7fSflorian 		if (rem < hdr->bh_hdrlen + hdr->bh_caplen)
728*57419a7fSflorian 			/* we are done */
729*57419a7fSflorian 			break;
730*57419a7fSflorian 		if (hdr->bh_caplen > sizeof(imsg_dhcp.packet)) {
731*57419a7fSflorian 			log_warn("packet too big");
732*57419a7fSflorian 			goto cont;
733*57419a7fSflorian 		}
734*57419a7fSflorian 		memcpy(&imsg_dhcp.packet, p + hdr->bh_hdrlen, hdr->bh_caplen);
735*57419a7fSflorian 		imsg_dhcp.len = hdr->bh_caplen;
736*57419a7fSflorian 		frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp,
737*57419a7fSflorian 		    sizeof(imsg_dhcp));
738*57419a7fSflorian  cont:
739*57419a7fSflorian 		p += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
740*57419a7fSflorian 		rem -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
741*57419a7fSflorian 
742*57419a7fSflorian 	}
743*57419a7fSflorian }
744*57419a7fSflorian 
745*57419a7fSflorian ssize_t
746*57419a7fSflorian build_packet(uint8_t message_type, uint32_t xid, struct ether_addr *hw_address,
747*57419a7fSflorian     struct in_addr *requested_ip, struct in_addr *server_identifier)
748*57419a7fSflorian {
749*57419a7fSflorian 	static uint8_t	 dhcp_cookie[] = DHCP_COOKIE;
750*57419a7fSflorian 	static uint8_t	 dhcp_message_type[] = {DHO_DHCP_MESSAGE_TYPE, 1,
751*57419a7fSflorian 		DHCPDISCOVER};
752*57419a7fSflorian 	static uint8_t	 dhcp_hostname[255] = {DHO_HOST_NAME, 0 /*, ... */};
753*57419a7fSflorian 	static uint8_t	 dhcp_client_id[] = {DHO_DHCP_CLIENT_IDENTIFIER, 7,
754*57419a7fSflorian 		HTYPE_ETHER, 0, 0, 0, 0, 0, 0};
755*57419a7fSflorian 	static uint8_t	 dhcp_req_list[] = {DHO_DHCP_PARAMETER_REQUEST_LIST,
756*57419a7fSflorian 		8, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS,
757*57419a7fSflorian 		DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS,
758*57419a7fSflorian 		DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES};
759*57419a7fSflorian 	static uint8_t	 dhcp_requested_address[] = {DHO_DHCP_REQUESTED_ADDRESS,
760*57419a7fSflorian 		4, 0, 0, 0, 0};
761*57419a7fSflorian 	static uint8_t	 dhcp_server_identifier[] = {DHO_DHCP_SERVER_IDENTIFIER,
762*57419a7fSflorian 		4, 0, 0, 0, 0};
763*57419a7fSflorian 	struct dhcp_hdr	*hdr;
764*57419a7fSflorian 	uint8_t		*p;
765*57419a7fSflorian 	char		*c;
766*57419a7fSflorian 
767*57419a7fSflorian 	memset(dhcp_packet, 0, sizeof(dhcp_packet));
768*57419a7fSflorian 	dhcp_message_type[2] = message_type;
769*57419a7fSflorian 	p = dhcp_packet;
770*57419a7fSflorian 	hdr = (struct dhcp_hdr *)p;
771*57419a7fSflorian 	hdr->op = DHCP_BOOTREQUEST;
772*57419a7fSflorian 	hdr->htype = HTYPE_ETHER;
773*57419a7fSflorian 	hdr->hlen = 6;
774*57419a7fSflorian 	hdr->hops = 0;
775*57419a7fSflorian 	hdr->xid = xid;
776*57419a7fSflorian 	hdr->secs = 0;
777*57419a7fSflorian 	memcpy(hdr->chaddr, hw_address, sizeof(*hw_address));
778*57419a7fSflorian 	p += sizeof(struct dhcp_hdr);
779*57419a7fSflorian 	memcpy(p, dhcp_cookie, sizeof(dhcp_cookie));
780*57419a7fSflorian 	p += sizeof(dhcp_cookie);
781*57419a7fSflorian 	memcpy(p, dhcp_message_type, sizeof(dhcp_message_type));
782*57419a7fSflorian 	p += sizeof(dhcp_message_type);
783*57419a7fSflorian 	if (gethostname(dhcp_hostname + 2, sizeof(dhcp_hostname) - 2) == 0) {
784*57419a7fSflorian 		if ((c = strchr(dhcp_hostname + 2, '.')) != NULL)
785*57419a7fSflorian 			*c = '\0';
786*57419a7fSflorian 		dhcp_hostname[1] = strlen(dhcp_hostname + 2);
787*57419a7fSflorian 		memcpy(p, dhcp_hostname, dhcp_hostname[1] + 2);
788*57419a7fSflorian 		p += dhcp_hostname[1] + 2;
789*57419a7fSflorian 	}
790*57419a7fSflorian 	memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address));
791*57419a7fSflorian 	memcpy(p, dhcp_client_id, sizeof(dhcp_client_id));
792*57419a7fSflorian 	p += sizeof(dhcp_client_id);
793*57419a7fSflorian 	memcpy(p, dhcp_req_list, sizeof(dhcp_req_list));
794*57419a7fSflorian 	p += sizeof(dhcp_req_list);
795*57419a7fSflorian 
796*57419a7fSflorian 	if (message_type == DHCPREQUEST) {
797*57419a7fSflorian 		memcpy(dhcp_requested_address + 2, requested_ip,
798*57419a7fSflorian 		    sizeof(*requested_ip));
799*57419a7fSflorian 		memcpy(p, dhcp_requested_address,
800*57419a7fSflorian 		    sizeof(dhcp_requested_address));
801*57419a7fSflorian 		p += sizeof(dhcp_requested_address);
802*57419a7fSflorian 
803*57419a7fSflorian 		if (server_identifier->s_addr != INADDR_ANY) {
804*57419a7fSflorian 			memcpy(dhcp_server_identifier + 2, server_identifier,
805*57419a7fSflorian 			    sizeof(*server_identifier));
806*57419a7fSflorian 			memcpy(p, dhcp_server_identifier,
807*57419a7fSflorian 			    sizeof(dhcp_server_identifier));
808*57419a7fSflorian 			p += sizeof(dhcp_server_identifier);
809*57419a7fSflorian 		}
810*57419a7fSflorian 	}
811*57419a7fSflorian 
812*57419a7fSflorian 	*p = DHO_END;
813*57419a7fSflorian 	p += 1;
814*57419a7fSflorian 
815*57419a7fSflorian 	return (p - dhcp_packet);
816*57419a7fSflorian }
817*57419a7fSflorian 
818*57419a7fSflorian void
819*57419a7fSflorian send_discover(struct iface *iface)
820*57419a7fSflorian {
821*57419a7fSflorian 	ssize_t	 pkt_len;
822*57419a7fSflorian 
823*57419a7fSflorian 	if (!event_initialized(&iface->bpfev.ev)) {
824*57419a7fSflorian 		iface->send_discover = 1;
825*57419a7fSflorian 		return;
826*57419a7fSflorian 	}
827*57419a7fSflorian 	iface->send_discover = 0;
828*57419a7fSflorian 	log_debug("%s", __func__);
829*57419a7fSflorian 	pkt_len = build_packet(DHCPDISCOVER, iface->xid, &iface->hw_address,
830*57419a7fSflorian 	    &iface->requested_ip, NULL);
831*57419a7fSflorian 	log_debug("%s, pkt_len: %ld", __func__, pkt_len);
832*57419a7fSflorian 	bpf_send_packet(iface, dhcp_packet, pkt_len);
833*57419a7fSflorian }
834*57419a7fSflorian 
835*57419a7fSflorian void
836*57419a7fSflorian send_request(struct iface *iface)
837*57419a7fSflorian {
838*57419a7fSflorian 	ssize_t	 pkt_len;
839*57419a7fSflorian 
840*57419a7fSflorian 	pkt_len = build_packet(DHCPREQUEST, iface->xid, &iface->hw_address,
841*57419a7fSflorian 	    &iface->requested_ip, &iface->server_identifier);
842*57419a7fSflorian 	log_debug("%s, pkt_len: %ld", __func__, pkt_len);
843*57419a7fSflorian 	if (iface->dhcp_server.s_addr != INADDR_ANY)
844*57419a7fSflorian 		udp_send_packet(iface, dhcp_packet, pkt_len);
845*57419a7fSflorian 	else
846*57419a7fSflorian 		bpf_send_packet(iface, dhcp_packet, pkt_len);
847*57419a7fSflorian }
848*57419a7fSflorian 
849*57419a7fSflorian void
850*57419a7fSflorian udp_send_packet(struct iface *iface, uint8_t *packet, ssize_t len)
851*57419a7fSflorian {
852*57419a7fSflorian 	struct sockaddr_in	to;
853*57419a7fSflorian 
854*57419a7fSflorian 	log_debug("%s", __func__);
855*57419a7fSflorian 	memset(&to, 0, sizeof(to));
856*57419a7fSflorian 	to.sin_family = AF_INET;
857*57419a7fSflorian 	to.sin_len = sizeof(to);
858*57419a7fSflorian 	to.sin_addr.s_addr = iface->dhcp_server.s_addr;
859*57419a7fSflorian 	to.sin_port = ntohs(SERVER_PORT);
860*57419a7fSflorian 
861*57419a7fSflorian 	if (sendto(iface->udpsock, packet, len, 0, (struct sockaddr *)&to,
862*57419a7fSflorian 	    sizeof(to)) == -1)
863*57419a7fSflorian 		log_warn("sendto");
864*57419a7fSflorian }
865*57419a7fSflorian void
866*57419a7fSflorian bpf_send_packet(struct iface *iface, uint8_t *packet, ssize_t len)
867*57419a7fSflorian {
868*57419a7fSflorian 	struct iovec		 iov[4];
869*57419a7fSflorian 	struct ether_header	 eh;
870*57419a7fSflorian 	struct ip		 ip;
871*57419a7fSflorian 	struct udphdr		 udp;
872*57419a7fSflorian 	ssize_t			 total, result;
873*57419a7fSflorian 	int			 iovcnt = 0, i;
874*57419a7fSflorian 
875*57419a7fSflorian 	memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
876*57419a7fSflorian 	memcpy(eh.ether_shost, &iface->hw_address, sizeof(eh.ether_dhost));
877*57419a7fSflorian 	eh.ether_type = htons(ETHERTYPE_IP);
878*57419a7fSflorian 	iov[0].iov_base = &eh;
879*57419a7fSflorian 	iov[0].iov_len = sizeof(eh);
880*57419a7fSflorian 	iovcnt++;
881*57419a7fSflorian 
882*57419a7fSflorian 	ip.ip_v = 4;
883*57419a7fSflorian 	ip.ip_hl = 5;
884*57419a7fSflorian 	ip.ip_tos = IPTOS_LOWDELAY;
885*57419a7fSflorian 	ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
886*57419a7fSflorian 	ip.ip_id = 0;
887*57419a7fSflorian 	ip.ip_off = 0;
888*57419a7fSflorian 	ip.ip_ttl = 128;
889*57419a7fSflorian 	ip.ip_p = IPPROTO_UDP;
890*57419a7fSflorian 	ip.ip_sum = 0;
891*57419a7fSflorian 	ip.ip_src.s_addr = 0;
892*57419a7fSflorian 	ip.ip_dst.s_addr = INADDR_BROADCAST;
893*57419a7fSflorian 	ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
894*57419a7fSflorian 	iov[iovcnt].iov_base = &ip;
895*57419a7fSflorian 	iov[iovcnt].iov_len = sizeof(ip);
896*57419a7fSflorian 	iovcnt++;
897*57419a7fSflorian 
898*57419a7fSflorian 	udp.uh_sport = htons(CLIENT_PORT);
899*57419a7fSflorian 	udp.uh_dport = htons(SERVER_PORT);
900*57419a7fSflorian 	udp.uh_ulen = htons(sizeof(udp) + len);
901*57419a7fSflorian 	udp.uh_sum = 0;
902*57419a7fSflorian 	udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
903*57419a7fSflorian 	    checksum((unsigned char *)packet, len,
904*57419a7fSflorian 	    checksum((unsigned char *)&ip.ip_src,
905*57419a7fSflorian 	    2 * sizeof(ip.ip_src),
906*57419a7fSflorian 	    IPPROTO_UDP + (uint32_t)ntohs(udp.uh_ulen)))));
907*57419a7fSflorian 	iov[iovcnt].iov_base = &udp;
908*57419a7fSflorian 	iov[iovcnt].iov_len = sizeof(udp);
909*57419a7fSflorian 	iovcnt++;
910*57419a7fSflorian 
911*57419a7fSflorian 	iov[iovcnt].iov_base = packet;
912*57419a7fSflorian 	iov[iovcnt].iov_len = len;
913*57419a7fSflorian 	iovcnt++;
914*57419a7fSflorian 
915*57419a7fSflorian 	total = 0;
916*57419a7fSflorian 	for (i = 0; i < iovcnt; i++)
917*57419a7fSflorian 		total += iov[i].iov_len;
918*57419a7fSflorian 
919*57419a7fSflorian 	result = writev(EVENT_FD(&iface->bpfev.ev), iov, iovcnt);
920*57419a7fSflorian 	if (result == -1)
921*57419a7fSflorian 		log_warn("%s: writev", __func__);
922*57419a7fSflorian 	else if (result < total) {
923*57419a7fSflorian 		log_warnx("%s, writev: %zd of %zd bytes", __func__, result,
924*57419a7fSflorian 		    total);
925*57419a7fSflorian 	}
926*57419a7fSflorian }
927*57419a7fSflorian 
928*57419a7fSflorian struct iface*
929*57419a7fSflorian get_iface_by_id(uint32_t if_index)
930*57419a7fSflorian {
931*57419a7fSflorian 	struct iface	*iface;
932*57419a7fSflorian 
933*57419a7fSflorian 	LIST_FOREACH (iface, &interfaces, entries) {
934*57419a7fSflorian 		if (iface->if_index == if_index)
935*57419a7fSflorian 			return (iface);
936*57419a7fSflorian 	}
937*57419a7fSflorian 
938*57419a7fSflorian 	return (NULL);
939*57419a7fSflorian }
940*57419a7fSflorian 
941*57419a7fSflorian void
942*57419a7fSflorian remove_iface(uint32_t if_index)
943*57419a7fSflorian {
944*57419a7fSflorian 	struct iface	*iface;
945*57419a7fSflorian 
946*57419a7fSflorian 	iface = get_iface_by_id(if_index);
947*57419a7fSflorian 
948*57419a7fSflorian 	if (iface == NULL)
949*57419a7fSflorian 		return;
950*57419a7fSflorian 
951*57419a7fSflorian 	LIST_REMOVE(iface, entries);
952*57419a7fSflorian 	event_del(&iface->bpfev.ev);
953*57419a7fSflorian 	close(EVENT_FD(&iface->bpfev.ev));
954*57419a7fSflorian 	if (iface->udpsock != -1)
955*57419a7fSflorian 		close(iface->udpsock);
956*57419a7fSflorian 	free(iface);
957*57419a7fSflorian }
958*57419a7fSflorian 
959*57419a7fSflorian void
960*57419a7fSflorian set_bpfsock(int bpfsock, uint32_t if_index)
961*57419a7fSflorian {
962*57419a7fSflorian 	struct iface	*iface;
963*57419a7fSflorian 
964*57419a7fSflorian 	log_debug("%s: %d fd: %d", __func__, if_index, bpfsock);
965*57419a7fSflorian 
966*57419a7fSflorian 	if ((iface = get_iface_by_id(if_index)) == NULL) {
967*57419a7fSflorian 		/*
968*57419a7fSflorian 		 * The interface disappeared while we were waiting for the
969*57419a7fSflorian 		 * parent process to open the raw socket.
970*57419a7fSflorian 		 */
971*57419a7fSflorian 		close(bpfsock);
972*57419a7fSflorian 	} else {
973*57419a7fSflorian 		event_set(&iface->bpfev.ev, bpfsock, EV_READ |
974*57419a7fSflorian 		    EV_PERSIST, bpf_receive, iface);
975*57419a7fSflorian 		event_add(&iface->bpfev.ev, NULL);
976*57419a7fSflorian 		if (iface->send_discover)
977*57419a7fSflorian 			send_discover(iface);
978*57419a7fSflorian 	}
979*57419a7fSflorian }
980