1 /* $OpenBSD: engine.c,v 1.55 2024/11/21 13:35:20 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
5 * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/syslog.h>
26 #include <sys/uio.h>
27 #include <sys/mbuf.h>
28
29 #include <net/if.h>
30 #include <net/route.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
33 #include <netinet/if_ether.h>
34 #include <netinet/ip.h>
35 #include <netinet/udp.h>
36
37 #include <errno.h>
38 #include <event.h>
39 #include <imsg.h>
40 #include <pwd.h>
41 #include <signal.h>
42 #include <stddef.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <vis.h>
49
50 #include "checksum.h"
51 #include "log.h"
52 #include "dhcpleased.h"
53 #include "engine.h"
54
55 /*
56 * RFC 2131 4.1 p23 has "SHOULD be 4 seconds", we are a bit more aggressive,
57 * networks are faster these days.
58 */
59 #define START_EXP_BACKOFF 1
60 #define MAX_EXP_BACKOFF_SLOW 64 /* RFC 2131 4.1 p23 */
61 #define MAX_EXP_BACKOFF_FAST 2
62 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
63
64 enum if_state {
65 IF_DOWN,
66 IF_INIT,
67 /* IF_SELECTING, */
68 IF_REQUESTING,
69 IF_BOUND,
70 IF_RENEWING,
71 IF_REBINDING,
72 /* IF_INIT_REBOOT, */
73 IF_REBOOTING,
74 IF_IPV6_ONLY,
75 };
76
77 const char* if_state_name[] = {
78 "Down",
79 "Init",
80 /* "Selecting", */
81 "Requesting",
82 "Bound",
83 "Renewing",
84 "Rebinding",
85 /* "Init-Reboot", */
86 "Rebooting",
87 "IPv6 only",
88 };
89
90 struct dhcpleased_iface {
91 LIST_ENTRY(dhcpleased_iface) entries;
92 enum if_state state;
93 struct event timer;
94 struct timeval timo;
95 uint32_t if_index;
96 int rdomain;
97 int running;
98 struct ether_addr hw_address;
99 int link_state;
100 uint32_t cur_mtu;
101 uint32_t xid;
102 struct timespec request_time;
103 struct in_addr server_identifier;
104 struct in_addr dhcp_server; /* for unicast */
105 struct in_addr requested_ip;
106 struct in_addr mask;
107 struct in_addr siaddr;
108 char file[4 * DHCP_FILE_LEN + 1];
109 char hostname[4 * 255 + 1];
110 char domainname[4 * 255 + 1];
111 struct dhcp_route prev_routes[MAX_DHCP_ROUTES];
112 int prev_routes_len;
113 struct dhcp_route routes[MAX_DHCP_ROUTES];
114 int routes_len;
115 struct in_addr nameservers[MAX_RDNS_COUNT];
116 uint32_t lease_time;
117 uint32_t renewal_time;
118 uint32_t rebinding_time;
119 uint32_t ipv6_only_time;
120 };
121
122 LIST_HEAD(, dhcpleased_iface) dhcpleased_interfaces;
123
124 __dead void engine_shutdown(void);
125 void engine_sig_handler(int sig, short, void *);
126 void engine_dispatch_frontend(int, short, void *);
127 void engine_dispatch_main(int, short, void *);
128 #ifndef SMALL
129 void send_interface_info(struct dhcpleased_iface *, pid_t);
130 void engine_showinfo_ctl(pid_t, uint32_t);
131 #endif /* SMALL */
132 void engine_update_iface(struct imsg_ifinfo *);
133 struct dhcpleased_iface *get_dhcpleased_iface_by_id(uint32_t);
134 void remove_dhcpleased_iface(uint32_t);
135 void parse_dhcp(struct dhcpleased_iface *,
136 struct imsg_dhcp *);
137 void state_transition(struct dhcpleased_iface *, enum
138 if_state);
139 void iface_timeout(int, short, void *);
140 void request_dhcp_discover(struct dhcpleased_iface *);
141 void request_dhcp_request(struct dhcpleased_iface *);
142 void log_lease(struct dhcpleased_iface *, int);
143 void log_rdns(struct dhcpleased_iface *, int);
144 void send_configure_interface(struct dhcpleased_iface *);
145 void send_rdns_proposal(struct dhcpleased_iface *);
146 void send_deconfigure_interface(struct dhcpleased_iface *);
147 void send_rdns_withdraw(struct dhcpleased_iface *);
148 void send_routes_withdraw(struct dhcpleased_iface *);
149 void parse_lease(struct dhcpleased_iface *,
150 struct imsg_ifinfo *);
151 int engine_imsg_compose_main(int, pid_t, void *, uint16_t);
152 void log_dhcp_hdr(struct dhcp_hdr *);
153 const char *dhcp_message_type2str(uint8_t);
154
155 #ifndef SMALL
156 struct dhcpleased_conf *engine_conf;
157 #endif /* SMALL */
158
159 static struct imsgev *iev_frontend;
160 static struct imsgev *iev_main;
161 int64_t proposal_id;
162
163 void
engine_sig_handler(int sig,short event,void * arg)164 engine_sig_handler(int sig, short event, void *arg)
165 {
166 /*
167 * Normal signal handler rules don't apply because libevent
168 * decouples for us.
169 */
170
171 switch (sig) {
172 case SIGINT:
173 case SIGTERM:
174 engine_shutdown();
175 default:
176 fatalx("unexpected signal");
177 }
178 }
179
180 void
engine(int debug,int verbose)181 engine(int debug, int verbose)
182 {
183 struct event ev_sigint, ev_sigterm;
184 struct passwd *pw;
185
186 #ifndef SMALL
187 engine_conf = config_new_empty();
188 #endif /* SMALL */
189
190 log_init(debug, LOG_DAEMON);
191 log_setverbose(verbose);
192
193 if ((pw = getpwnam(DHCPLEASED_USER)) == NULL)
194 fatal("getpwnam");
195
196 if (chdir("/") == -1)
197 fatal("chdir(\"/\")");
198
199 if (unveil("/", "") == -1)
200 fatal("unveil /");
201 if (unveil(NULL, NULL) == -1)
202 fatal("unveil");
203
204 setproctitle("%s", "engine");
205 log_procinit("engine");
206
207 if (setgroups(1, &pw->pw_gid) ||
208 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
209 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
210 fatal("can't drop privileges");
211
212 if (pledge("stdio recvfd", NULL) == -1)
213 fatal("pledge");
214
215 event_init();
216
217 /* Setup signal handler(s). */
218 signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
219 signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
220 signal_add(&ev_sigint, NULL);
221 signal_add(&ev_sigterm, NULL);
222 signal(SIGPIPE, SIG_IGN);
223 signal(SIGHUP, SIG_IGN);
224
225 /* Setup pipe and event handler to the main process. */
226 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
227 fatal(NULL);
228
229 if (imsgbuf_init(&iev_main->ibuf, 3) == -1)
230 fatal(NULL);
231 imsgbuf_allow_fdpass(&iev_main->ibuf);
232 iev_main->handler = engine_dispatch_main;
233
234 /* Setup event handlers. */
235 iev_main->events = EV_READ;
236 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
237 iev_main->handler, iev_main);
238 event_add(&iev_main->ev, NULL);
239
240 LIST_INIT(&dhcpleased_interfaces);
241
242 event_dispatch();
243
244 engine_shutdown();
245 }
246
247 __dead void
engine_shutdown(void)248 engine_shutdown(void)
249 {
250 /* Close pipes. */
251 imsgbuf_clear(&iev_frontend->ibuf);
252 close(iev_frontend->ibuf.fd);
253 imsgbuf_clear(&iev_main->ibuf);
254 close(iev_main->ibuf.fd);
255
256 free(iev_frontend);
257 free(iev_main);
258
259 log_info("engine exiting");
260 exit(0);
261 }
262
263 int
engine_imsg_compose_frontend(int type,pid_t pid,void * data,uint16_t datalen)264 engine_imsg_compose_frontend(int type, pid_t pid, void *data,
265 uint16_t datalen)
266 {
267 return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
268 data, datalen));
269 }
270
271 int
engine_imsg_compose_main(int type,pid_t pid,void * data,uint16_t datalen)272 engine_imsg_compose_main(int type, pid_t pid, void *data,
273 uint16_t datalen)
274 {
275 return (imsg_compose_event(iev_main, type, 0, pid, -1,
276 data, datalen));
277 }
278
279 void
engine_dispatch_frontend(int fd,short event,void * bula)280 engine_dispatch_frontend(int fd, short event, void *bula)
281 {
282 struct imsgev *iev = bula;
283 struct imsgbuf *ibuf = &iev->ibuf;
284 struct imsg imsg;
285 struct dhcpleased_iface *iface;
286 ssize_t n;
287 int shut = 0;
288 #ifndef SMALL
289 int verbose;
290 #endif /* SMALL */
291 uint32_t if_index, type;
292
293 if (event & EV_READ) {
294 if ((n = imsgbuf_read(ibuf)) == -1)
295 fatal("imsgbuf_read error");
296 if (n == 0) /* Connection closed. */
297 shut = 1;
298 }
299 if (event & EV_WRITE) {
300 if (imsgbuf_write(ibuf) == -1) {
301 if (errno == EPIPE) /* Connection closed. */
302 shut = 1;
303 else
304 fatal("imsgbuf_write");
305 }
306 }
307
308 for (;;) {
309 if ((n = imsg_get(ibuf, &imsg)) == -1)
310 fatal("%s: imsg_get error", __func__);
311 if (n == 0) /* No more messages. */
312 break;
313
314 type = imsg_get_type(&imsg);
315
316 switch (type) {
317 #ifndef SMALL
318 case IMSG_CTL_LOG_VERBOSE:
319 if (imsg_get_data(&imsg, &verbose,
320 sizeof(verbose)) == -1)
321 fatalx("%s: invalid %s", __func__, i2s(type));
322
323 log_setverbose(verbose);
324 break;
325 case IMSG_CTL_SHOW_INTERFACE_INFO:
326 if (imsg_get_data(&imsg, &if_index,
327 sizeof(if_index)) == -1)
328 fatalx("%s: invalid %s", __func__, i2s(type));
329
330 engine_showinfo_ctl(imsg_get_pid(&imsg), if_index);
331 break;
332 case IMSG_REQUEST_REBOOT:
333 if (imsg_get_data(&imsg, &if_index,
334 sizeof(if_index)) == -1)
335 fatalx("%s: invalid %s", __func__, i2s(type));
336
337 iface = get_dhcpleased_iface_by_id(if_index);
338 if (iface != NULL) {
339 switch (iface->state) {
340 case IF_DOWN:
341 break;
342 case IF_INIT:
343 case IF_REQUESTING:
344 state_transition(iface, iface->state);
345 break;
346 case IF_RENEWING:
347 case IF_REBINDING:
348 case IF_REBOOTING:
349 case IF_BOUND:
350 case IF_IPV6_ONLY:
351 state_transition(iface, IF_REBOOTING);
352 break;
353 }
354 }
355 break;
356 #endif /* SMALL */
357 case IMSG_REMOVE_IF:
358 if (imsg_get_data(&imsg, &if_index,
359 sizeof(if_index)) == -1)
360 fatalx("%s: invalid %s", __func__, i2s(type));
361
362 remove_dhcpleased_iface(if_index);
363 break;
364 case IMSG_DHCP: {
365 struct imsg_dhcp imsg_dhcp;
366
367 if (imsg_get_data(&imsg, &imsg_dhcp,
368 sizeof(imsg_dhcp)) == -1)
369 fatalx("%s: invalid %s", __func__, i2s(type));
370
371 iface = get_dhcpleased_iface_by_id(imsg_dhcp.if_index);
372 if (iface != NULL)
373 parse_dhcp(iface, &imsg_dhcp);
374 break;
375 }
376 case IMSG_REPROPOSE_RDNS:
377 LIST_FOREACH (iface, &dhcpleased_interfaces, entries)
378 send_rdns_proposal(iface);
379 break;
380 default:
381 log_debug("%s: unexpected imsg %d", __func__, type);
382 break;
383 }
384 imsg_free(&imsg);
385 }
386 if (!shut)
387 imsg_event_add(iev);
388 else {
389 /* This pipe is dead. Remove its event handler. */
390 event_del(&iev->ev);
391 event_loopexit(NULL);
392 }
393 }
394
395 void
engine_dispatch_main(int fd,short event,void * bula)396 engine_dispatch_main(int fd, short event, void *bula)
397 {
398 #ifndef SMALL
399 static struct dhcpleased_conf *nconf;
400 static struct iface_conf *iface_conf;
401 #endif /* SMALL */
402 struct imsg imsg;
403 struct imsgev *iev = bula;
404 struct imsgbuf *ibuf = &iev->ibuf;
405 struct imsg_ifinfo imsg_ifinfo;
406 ssize_t n;
407 uint32_t type;
408 int shut = 0;
409
410 if (event & EV_READ) {
411 if ((n = imsgbuf_read(ibuf)) == -1)
412 fatal("imsgbuf_read error");
413 if (n == 0) /* Connection closed. */
414 shut = 1;
415 }
416 if (event & EV_WRITE) {
417 if (imsgbuf_write(ibuf) == -1) {
418 if (errno == EPIPE) /* Connection closed. */
419 shut = 1;
420 else
421 fatal("imsgbuf_write");
422 }
423 }
424
425 for (;;) {
426 if ((n = imsg_get(ibuf, &imsg)) == -1)
427 fatal("%s: imsg_get error", __func__);
428 if (n == 0) /* No more messages. */
429 break;
430
431 type = imsg_get_type(&imsg);
432
433 switch (type) {
434 case IMSG_SOCKET_IPC:
435 /*
436 * Setup pipe and event handler to the frontend
437 * process.
438 */
439 if (iev_frontend)
440 fatalx("%s: received unexpected imsg fd "
441 "to engine", __func__);
442
443 if ((fd = imsg_get_fd(&imsg)) == -1)
444 fatalx("%s: expected to receive imsg fd to "
445 "engine but didn't receive any", __func__);
446
447 iev_frontend = malloc(sizeof(struct imsgev));
448 if (iev_frontend == NULL)
449 fatal(NULL);
450
451 if (imsgbuf_init(&iev_frontend->ibuf, fd) == -1)
452 fatal(NULL);
453 iev_frontend->handler = engine_dispatch_frontend;
454 iev_frontend->events = EV_READ;
455
456 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
457 iev_frontend->events, iev_frontend->handler,
458 iev_frontend);
459 event_add(&iev_frontend->ev, NULL);
460
461 if (pledge("stdio", NULL) == -1)
462 fatal("pledge");
463
464 break;
465 case IMSG_UPDATE_IF:
466 if (imsg_get_data(&imsg, &imsg_ifinfo,
467 sizeof(imsg_ifinfo)) == -1)
468 fatalx("%s: invalid %s", __func__, i2s(type));
469 if (imsg_ifinfo.lease[LEASE_SIZE - 1] != '\0')
470 fatalx("Invalid lease");
471
472 engine_update_iface(&imsg_ifinfo);
473 break;
474 #ifndef SMALL
475 case IMSG_RECONF_CONF:
476 if (nconf != NULL)
477 fatalx("%s: IMSG_RECONF_CONF already in "
478 "progress", __func__);
479 if ((nconf = malloc(sizeof(struct dhcpleased_conf))) ==
480 NULL)
481 fatal(NULL);
482 SIMPLEQ_INIT(&nconf->iface_list);
483 break;
484 case IMSG_RECONF_IFACE:
485 if ((iface_conf = malloc(sizeof(struct iface_conf)))
486 == NULL)
487 fatal(NULL);
488
489 if (imsg_get_data(&imsg, iface_conf,
490 sizeof(struct iface_conf)) == -1)
491 fatalx("%s: invalid %s", __func__, i2s(type));
492
493 iface_conf->vc_id = NULL;
494 iface_conf->vc_id_len = 0;
495 iface_conf->c_id = NULL;
496 iface_conf->c_id_len = 0;
497 iface_conf->h_name = NULL;
498 SIMPLEQ_INSERT_TAIL(&nconf->iface_list,
499 iface_conf, entry);
500 break;
501 case IMSG_RECONF_VC_ID:
502 if (iface_conf == NULL)
503 fatalx("%s: %s without IMSG_RECONF_IFACE",
504 __func__, i2s(type));
505 if (iface_conf->vc_id != NULL)
506 fatalx("%s: multiple %s for the same interface",
507 __func__, i2s(type));
508 if ((iface_conf->vc_id_len = imsg_get_len(&imsg))
509 > 255 + 2 || iface_conf->vc_id_len == 0)
510 fatalx("%s: invalid %s", __func__, i2s(type));
511 if ((iface_conf->vc_id = malloc(iface_conf->vc_id_len))
512 == NULL)
513 fatal(NULL);
514 if (imsg_get_data(&imsg, iface_conf->vc_id,
515 iface_conf->vc_id_len) == -1)
516 fatalx("%s: invalid %s", __func__, i2s(type));
517 break;
518 case IMSG_RECONF_C_ID:
519 if (iface_conf == NULL)
520 fatalx("%s: %s without IMSG_RECONF_IFACE",
521 __func__, i2s(type));
522 if (iface_conf->c_id != NULL)
523 fatalx("%s: multiple %s for the same interface",
524 __func__, i2s(type));
525 if ((iface_conf->c_id_len = imsg_get_len(&imsg))
526 > 255 + 2 || iface_conf->c_id_len == 0)
527 fatalx("%s: invalid %s", __func__, i2s(type));
528 if ((iface_conf->c_id = malloc(iface_conf->c_id_len))
529 == NULL)
530 fatal(NULL);
531 if (imsg_get_data(&imsg, iface_conf->c_id,
532 iface_conf->c_id_len) == -1)
533 fatalx("%s: invalid %s", __func__, i2s(type));
534 break;
535 case IMSG_RECONF_H_NAME: {
536 size_t len;
537
538 if (iface_conf == NULL)
539 fatalx("%s: %s without IMSG_RECONF_IFACE",
540 __func__, i2s(type));
541 if (iface_conf->h_name != NULL)
542 fatalx("%s: multiple %s for the same interface",
543 __func__, i2s(type));
544 if ((len = imsg_get_len(&imsg)) > 256 || len == 0)
545 fatalx("%s: invalid %s", __func__, i2s(type));
546 if ((iface_conf->h_name = malloc(len)) == NULL)
547 fatal(NULL);
548 if (imsg_get_data(&imsg, iface_conf->h_name, len) == -1)
549 fatalx("%s: invalid %s", __func__, i2s(type));
550 if (iface_conf->h_name[len - 1] != '\0')
551 fatalx("Invalid hostname");
552 break;
553 }
554 case IMSG_RECONF_END: {
555 struct dhcpleased_iface *iface;
556 int *ifaces;
557 int i, if_index;
558 char *if_name;
559 char ifnamebuf[IF_NAMESIZE];
560
561 if (nconf == NULL)
562 fatalx("%s: %s without IMSG_RECONF_CONF",
563 __func__, i2s(type));
564
565 ifaces = changed_ifaces(engine_conf, nconf);
566 merge_config(engine_conf, nconf);
567 nconf = NULL;
568 for (i = 0; ifaces[i] != 0; i++) {
569 if_index = ifaces[i];
570 if_name = if_indextoname(if_index, ifnamebuf);
571 iface = get_dhcpleased_iface_by_id(if_index);
572 if (if_name == NULL || iface == NULL)
573 continue;
574 iface_conf = find_iface_conf(
575 &engine_conf->iface_list, if_name);
576 if (iface_conf == NULL)
577 continue;
578 if (iface_conf->ignore & IGN_DNS)
579 send_rdns_withdraw(iface);
580 if (iface_conf->ignore & IGN_ROUTES)
581 send_routes_withdraw(iface);
582 }
583 free(ifaces);
584 break;
585 }
586 #endif /* SMALL */
587 default:
588 log_debug("%s: unexpected imsg %d", __func__, type);
589 break;
590 }
591 imsg_free(&imsg);
592 }
593 if (!shut)
594 imsg_event_add(iev);
595 else {
596 /* This pipe is dead. Remove its event handler. */
597 event_del(&iev->ev);
598 event_loopexit(NULL);
599 }
600 }
601
602 #ifndef SMALL
603 void
send_interface_info(struct dhcpleased_iface * iface,pid_t pid)604 send_interface_info(struct dhcpleased_iface *iface, pid_t pid)
605 {
606 struct ctl_engine_info cei;
607
608 memset(&cei, 0, sizeof(cei));
609 cei.if_index = iface->if_index;
610 cei.running = iface->running;
611 cei.link_state = iface->link_state;
612 strlcpy(cei.state, if_state_name[iface->state], sizeof(cei.state));
613 memcpy(&cei.request_time, &iface->request_time,
614 sizeof(cei.request_time));
615 cei.server_identifier = iface->server_identifier;
616 cei.dhcp_server = iface->dhcp_server;
617 cei.requested_ip = iface->requested_ip;
618 cei.mask = iface->mask;
619 cei.routes_len = iface->routes_len;
620 memcpy(cei.routes, iface->routes, sizeof(cei.routes));
621 memcpy(cei.nameservers, iface->nameservers, sizeof(cei.nameservers));
622 cei.lease_time = iface->lease_time;
623 cei.renewal_time = iface->renewal_time;
624 cei.rebinding_time = iface->rebinding_time;
625 engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
626 sizeof(cei));
627 }
628
629 void
engine_showinfo_ctl(pid_t pid,uint32_t if_index)630 engine_showinfo_ctl(pid_t pid, uint32_t if_index)
631 {
632 struct dhcpleased_iface *iface;
633
634 if ((iface = get_dhcpleased_iface_by_id(if_index)) != NULL)
635 send_interface_info(iface, pid);
636 else
637 engine_imsg_compose_frontend(IMSG_CTL_END, pid, NULL, 0);
638 }
639 #endif /* SMALL */
640
641 void
engine_update_iface(struct imsg_ifinfo * imsg_ifinfo)642 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo)
643 {
644 struct dhcpleased_iface *iface;
645 int need_refresh = 0;
646
647 iface = get_dhcpleased_iface_by_id(imsg_ifinfo->if_index);
648
649 if (iface == NULL) {
650 if ((iface = calloc(1, sizeof(*iface))) == NULL)
651 fatal("calloc");
652 iface->state = IF_DOWN;
653 iface->xid = arc4random();
654 iface->timo.tv_usec = arc4random_uniform(1000000);
655 evtimer_set(&iface->timer, iface_timeout, iface);
656 iface->if_index = imsg_ifinfo->if_index;
657 iface->rdomain = imsg_ifinfo->rdomain;
658 iface->running = imsg_ifinfo->running;
659 iface->link_state = imsg_ifinfo->link_state;
660 iface->requested_ip.s_addr = INADDR_ANY;
661 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
662 sizeof(struct ether_addr));
663 LIST_INSERT_HEAD(&dhcpleased_interfaces, iface, entries);
664 need_refresh = 1;
665 } else {
666 if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address,
667 sizeof(struct ether_addr)) != 0) {
668 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
669 sizeof(struct ether_addr));
670 need_refresh = 1;
671 }
672 if (imsg_ifinfo->rdomain != iface->rdomain) {
673 iface->rdomain = imsg_ifinfo->rdomain;
674 need_refresh = 1;
675 }
676 if (imsg_ifinfo->running != iface->running) {
677 iface->running = imsg_ifinfo->running;
678 need_refresh = 1;
679 }
680
681 if (imsg_ifinfo->link_state != iface->link_state) {
682 iface->link_state = imsg_ifinfo->link_state;
683 need_refresh = 1;
684 }
685 }
686
687 if (!need_refresh)
688 return;
689
690 if (iface->running && LINK_STATE_IS_UP(iface->link_state)) {
691 if (iface->requested_ip.s_addr == INADDR_ANY)
692 parse_lease(iface, imsg_ifinfo);
693
694 if (iface->requested_ip.s_addr == INADDR_ANY)
695 state_transition(iface, IF_INIT);
696 else
697 state_transition(iface, IF_REBOOTING);
698 } else
699 state_transition(iface, IF_DOWN);
700 }
701 struct dhcpleased_iface*
get_dhcpleased_iface_by_id(uint32_t if_index)702 get_dhcpleased_iface_by_id(uint32_t if_index)
703 {
704 struct dhcpleased_iface *iface;
705 LIST_FOREACH (iface, &dhcpleased_interfaces, entries) {
706 if (iface->if_index == if_index)
707 return (iface);
708 }
709
710 return (NULL);
711 }
712
713 void
remove_dhcpleased_iface(uint32_t if_index)714 remove_dhcpleased_iface(uint32_t if_index)
715 {
716 struct dhcpleased_iface *iface;
717
718 iface = get_dhcpleased_iface_by_id(if_index);
719
720 if (iface == NULL)
721 return;
722
723 send_rdns_withdraw(iface);
724 send_deconfigure_interface(iface);
725 LIST_REMOVE(iface, entries);
726 evtimer_del(&iface->timer);
727 free(iface);
728 }
729
730 void
parse_dhcp(struct dhcpleased_iface * iface,struct imsg_dhcp * dhcp)731 parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
732 {
733 static uint8_t cookie[] = DHCP_COOKIE;
734 static struct ether_addr bcast_mac;
735 #ifndef SMALL
736 struct iface_conf *iface_conf;
737 #endif /* SMALL */
738 struct ether_header *eh;
739 struct ether_addr ether_src, ether_dst;
740 struct ip *ip;
741 struct udphdr *udp;
742 struct dhcp_hdr *dhcp_hdr;
743 struct in_addr server_identifier, subnet_mask;
744 struct in_addr nameservers[MAX_RDNS_COUNT];
745 struct dhcp_route routes[MAX_DHCP_ROUTES];
746 size_t rem, i;
747 uint32_t sum, usum, lease_time = 0, renewal_time = 0;
748 uint32_t rebinding_time = 0;
749 uint32_t ipv6_only_time = 0;
750 uint8_t *p, dho = DHO_PAD, dho_len, slen;
751 uint8_t dhcp_message_type = 0;
752 int routes_len = 0, routers = 0, csr = 0;
753 char from[sizeof("xx:xx:xx:xx:xx:xx")];
754 char to[sizeof("xx:xx:xx:xx:xx:xx")];
755 char hbuf_src[INET_ADDRSTRLEN];
756 char hbuf_dst[INET_ADDRSTRLEN];
757 char hbuf[INET_ADDRSTRLEN];
758 char domainname[4 * 255 + 1];
759 char hostname[4 * 255 + 1];
760 char ifnamebuf[IF_NAMESIZE], *if_name;
761
762 if (bcast_mac.ether_addr_octet[0] == 0)
763 memset(bcast_mac.ether_addr_octet, 0xff, ETHER_ADDR_LEN);
764
765 if_name = if_indextoname(iface->if_index, ifnamebuf);
766
767 #ifndef SMALL
768 iface_conf = find_iface_conf(&engine_conf->iface_list, if_name);
769 #endif /* SMALL*/
770
771 memset(hbuf_src, 0, sizeof(hbuf_src));
772 memset(hbuf_dst, 0, sizeof(hbuf_dst));
773
774 p = dhcp->packet;
775 rem = dhcp->len;
776
777 if (rem < sizeof(*eh)) {
778 log_warnx("%s: message too short", __func__);
779 return;
780 }
781 eh = (struct ether_header *)p;
782 memcpy(ether_src.ether_addr_octet, eh->ether_shost,
783 sizeof(ether_src.ether_addr_octet));
784 strlcpy(from, ether_ntoa(ðer_src), sizeof(from));
785 memcpy(ether_dst.ether_addr_octet, eh->ether_dhost,
786 sizeof(ether_dst.ether_addr_octet));
787 strlcpy(to, ether_ntoa(ðer_dst), sizeof(to));
788 p += sizeof(*eh);
789 rem -= sizeof(*eh);
790
791 if (memcmp(ðer_dst, &iface->hw_address, sizeof(ether_dst)) != 0 &&
792 memcmp(ðer_dst, &bcast_mac, sizeof(ether_dst)) != 0)
793 return ; /* silently ignore packet not for us */
794
795 if (rem < sizeof(*ip))
796 goto too_short;
797
798 if (log_getverbose() > 1)
799 log_debug("%s, from: %s, to: %s", __func__, from, to);
800
801 ip = (struct ip *)p;
802
803 if (rem < (size_t)ip->ip_hl << 2)
804 goto too_short;
805
806 if ((dhcp->csumflags & M_IPV4_CSUM_IN_OK) == 0 &&
807 wrapsum(checksum((uint8_t *)ip, ip->ip_hl << 2, 0)) != 0) {
808 log_warnx("%s: bad IP checksum", __func__);
809 return;
810 }
811 if (rem < ntohs(ip->ip_len))
812 goto too_short;
813
814 p += ip->ip_hl << 2;
815 rem -= ip->ip_hl << 2;
816
817 if (inet_ntop(AF_INET, &ip->ip_src, hbuf_src, sizeof(hbuf_src)) == NULL)
818 hbuf_src[0] = '\0';
819 if (inet_ntop(AF_INET, &ip->ip_dst, hbuf_dst, sizeof(hbuf_dst)) == NULL)
820 hbuf_dst[0] = '\0';
821
822 #ifndef SMALL
823 if (iface_conf != NULL) {
824 for (i = 0; (int)i < iface_conf->ignore_servers_len; i++) {
825 if (iface_conf->ignore_servers[i].s_addr ==
826 ip->ip_src.s_addr) {
827 log_debug("ignoring server %s", hbuf_src);
828 return;
829 }
830 }
831 }
832 #endif /* SMALL */
833
834 if (rem < sizeof(*udp))
835 goto too_short;
836
837 udp = (struct udphdr *)p;
838 if (rem < ntohs(udp->uh_ulen))
839 goto too_short;
840
841 if (rem > ntohs(udp->uh_ulen)) {
842 if (log_getverbose() > 1) {
843 log_debug("%s: accepting packet with %lu bytes of data"
844 " after udp payload", __func__, rem -
845 ntohs(udp->uh_ulen));
846 }
847 rem = ntohs(udp->uh_ulen);
848 }
849
850 p += sizeof(*udp);
851 rem -= sizeof(*udp);
852
853 if ((dhcp->csumflags & M_UDP_CSUM_IN_OK) == 0) {
854 usum = udp->uh_sum;
855 udp->uh_sum = 0;
856
857 sum = wrapsum(checksum((uint8_t *)udp, sizeof(*udp),
858 checksum(p, rem,
859 checksum((uint8_t *)&ip->ip_src, 2 * sizeof(ip->ip_src),
860 IPPROTO_UDP + ntohs(udp->uh_ulen)))));
861
862 if (usum != 0 && usum != sum) {
863 log_warnx("%s: bad UDP checksum", __func__);
864 return;
865 }
866 }
867
868 if (log_getverbose() > 1) {
869 log_debug("%s: %s:%d -> %s:%d", __func__, hbuf_src,
870 ntohs(udp->uh_sport), hbuf_dst, ntohs(udp->uh_dport));
871 }
872
873 if (rem < sizeof(*dhcp_hdr))
874 goto too_short;
875
876 dhcp_hdr = (struct dhcp_hdr *)p;
877 p += sizeof(*dhcp_hdr);
878 rem -= sizeof(*dhcp_hdr);
879
880 dhcp_hdr->sname[DHCP_SNAME_LEN -1 ] = '\0'; /* ensure it's a string */
881 dhcp_hdr->file[DHCP_FILE_LEN -1 ] = '\0'; /* ensure it's a string */
882
883 if (log_getverbose() > 1)
884 log_dhcp_hdr(dhcp_hdr);
885
886 if (dhcp_hdr->op != DHCP_BOOTREPLY) {
887 log_warnx("%s: ignoring non-reply packet", __func__);
888 return;
889 }
890
891 if (ntohl(dhcp_hdr->xid) != iface->xid)
892 return; /* silently ignore wrong xid */
893
894 if (rem < sizeof(cookie))
895 goto too_short;
896
897 if (memcmp(p, cookie, sizeof(cookie)) != 0) {
898 log_warnx("%s: no dhcp cookie in packet from %s", __func__,
899 from);
900 return;
901 }
902 p += sizeof(cookie);
903 rem -= sizeof(cookie);
904
905 memset(&server_identifier, 0, sizeof(server_identifier));
906 memset(&subnet_mask, 0, sizeof(subnet_mask));
907 memset(&routes, 0, sizeof(routes));
908 memset(&nameservers, 0, sizeof(nameservers));
909 memset(hostname, 0, sizeof(hostname));
910 memset(domainname, 0, sizeof(domainname));
911
912 while (rem > 0 && dho != DHO_END) {
913 dho = *p;
914 p += 1;
915 rem -= 1;
916 /* only DHO_END and DHO_PAD are 1 byte long without length */
917 if (dho == DHO_PAD || dho == DHO_END)
918 dho_len = 0;
919 else {
920 if (rem == 0)
921 goto too_short; /* missing option length */
922 dho_len = *p;
923 p += 1;
924 rem -= 1;
925 if (rem < dho_len)
926 goto too_short;
927 }
928
929 switch (dho) {
930 case DHO_PAD:
931 if (log_getverbose() > 1)
932 log_debug("DHO_PAD");
933 break;
934 case DHO_END:
935 if (log_getverbose() > 1)
936 log_debug("DHO_END");
937 break;
938 case DHO_DHCP_MESSAGE_TYPE:
939 if (dho_len != 1)
940 goto wrong_length;
941 dhcp_message_type = *p;
942 if (log_getverbose() > 1) {
943 log_debug("DHO_DHCP_MESSAGE_TYPE: %s",
944 dhcp_message_type2str(dhcp_message_type));
945 }
946 p += dho_len;
947 rem -= dho_len;
948 break;
949 case DHO_DHCP_SERVER_IDENTIFIER:
950 if (dho_len != sizeof(server_identifier))
951 goto wrong_length;
952 memcpy(&server_identifier, p,
953 sizeof(server_identifier));
954 if (log_getverbose() > 1) {
955 log_debug("DHO_DHCP_SERVER_IDENTIFIER: %s",
956 inet_ntop(AF_INET, &server_identifier,
957 hbuf, sizeof(hbuf)));
958 }
959 p += dho_len;
960 rem -= dho_len;
961 break;
962 case DHO_DHCP_LEASE_TIME:
963 if (dho_len != sizeof(lease_time))
964 goto wrong_length;
965 memcpy(&lease_time, p, sizeof(lease_time));
966 lease_time = ntohl(lease_time);
967 if (log_getverbose() > 1) {
968 log_debug("DHO_DHCP_LEASE_TIME %us",
969 lease_time);
970 }
971 p += dho_len;
972 rem -= dho_len;
973 break;
974 case DHO_SUBNET_MASK:
975 if (dho_len != sizeof(subnet_mask))
976 goto wrong_length;
977 memcpy(&subnet_mask, p, sizeof(subnet_mask));
978 if (log_getverbose() > 1) {
979 log_debug("DHO_SUBNET_MASK: %s",
980 inet_ntop(AF_INET, &subnet_mask, hbuf,
981 sizeof(hbuf)));
982 }
983 p += dho_len;
984 rem -= dho_len;
985 break;
986 case DHO_ROUTERS:
987 if (dho_len < sizeof(routes[routes_len].gw))
988 goto wrong_length;
989 if (dho_len % sizeof(routes[routes_len].gw) != 0)
990 goto wrong_length;
991
992 /*
993 * Ignore routers option if classless static routes
994 * are present (RFC3442).
995 */
996 if (!csr) {
997 routers = 1;
998 while (routes_len < MAX_DHCP_ROUTES &&
999 dho_len > 0) {
1000 memcpy(&routes[routes_len].gw, p,
1001 sizeof(routes[routes_len].gw));
1002 if (log_getverbose() > 1) {
1003 log_debug("DHO_ROUTER: %s",
1004 inet_ntop(AF_INET,
1005 &routes[routes_len].gw,
1006 hbuf, sizeof(hbuf)));
1007 }
1008 p += sizeof(routes[routes_len].gw);
1009 rem -= sizeof(routes[routes_len].gw);
1010 dho_len -=
1011 sizeof(routes[routes_len].gw);
1012 routes_len++;
1013 }
1014 }
1015 if (dho_len != 0) {
1016 /* ignore > MAX_DHCP_ROUTES routes */
1017 p += dho_len;
1018 rem -= dho_len;
1019 }
1020 break;
1021 case DHO_DOMAIN_NAME_SERVERS:
1022 if (dho_len < sizeof(nameservers[0]))
1023 goto wrong_length;
1024 if (dho_len % sizeof(nameservers[0]) != 0)
1025 goto wrong_length;
1026 /* we limit ourself to 8 nameservers for proposals */
1027 memcpy(&nameservers, p, MINIMUM(sizeof(nameservers),
1028 dho_len));
1029 if (log_getverbose() > 1) {
1030 for (i = 0; i < MINIMUM(sizeof(nameservers),
1031 dho_len / sizeof(nameservers[0])); i++) {
1032 log_debug("DHO_DOMAIN_NAME_SERVERS: %s "
1033 "(%lu/%lu)", inet_ntop(AF_INET,
1034 &nameservers[i], hbuf,
1035 sizeof(hbuf)), i + 1,
1036 dho_len / sizeof(nameservers[0]));
1037 }
1038 }
1039 p += dho_len;
1040 rem -= dho_len;
1041 break;
1042 case DHO_HOST_NAME:
1043 if (dho_len < 1) {
1044 /*
1045 * Protocol violation: minimum length is 1;
1046 * pretend the option is not there
1047 */
1048 break;
1049 }
1050 /* MUST delete trailing NUL, per RFC 2132 */
1051 slen = dho_len;
1052 while (slen > 0 && p[slen - 1] == '\0')
1053 slen--;
1054 /* slen might be 0 here, pretend option is not there. */
1055 strvisx(hostname, p, slen, VIS_SAFE);
1056 if (log_getverbose() > 1)
1057 log_debug("DHO_HOST_NAME: %s", hostname);
1058 p += dho_len;
1059 rem -= dho_len;
1060 break;
1061 case DHO_DOMAIN_NAME:
1062 if (dho_len < 1) {
1063 /*
1064 * Protocol violation: minimum length is 1;
1065 * pretend the option is not there
1066 */
1067 break;
1068 }
1069 /* MUST delete trailing NUL, per RFC 2132 */
1070 slen = dho_len;
1071 while (slen > 0 && p[slen - 1] == '\0')
1072 slen--;
1073 /* slen might be 0 here, pretend option is not there. */
1074 strvisx(domainname, p, slen, VIS_SAFE);
1075 if (log_getverbose() > 1)
1076 log_debug("DHO_DOMAIN_NAME: %s", domainname);
1077 p += dho_len;
1078 rem -= dho_len;
1079 break;
1080 case DHO_DHCP_RENEWAL_TIME:
1081 if (dho_len != sizeof(renewal_time))
1082 goto wrong_length;
1083 memcpy(&renewal_time, p, sizeof(renewal_time));
1084 renewal_time = ntohl(renewal_time);
1085 if (log_getverbose() > 1) {
1086 log_debug("DHO_DHCP_RENEWAL_TIME %us",
1087 renewal_time);
1088 }
1089 p += dho_len;
1090 rem -= dho_len;
1091 break;
1092 case DHO_DHCP_REBINDING_TIME:
1093 if (dho_len != sizeof(rebinding_time))
1094 goto wrong_length;
1095 memcpy(&rebinding_time, p, sizeof(rebinding_time));
1096 rebinding_time = ntohl(rebinding_time);
1097 if (log_getverbose() > 1) {
1098 log_debug("DHO_DHCP_REBINDING_TIME %us",
1099 rebinding_time);
1100 }
1101 p += dho_len;
1102 rem -= dho_len;
1103 break;
1104 case DHO_DHCP_CLIENT_IDENTIFIER:
1105 /* the server is supposed to echo this back to us */
1106 #ifndef SMALL
1107 if (iface_conf != NULL && iface_conf->c_id_len > 0) {
1108 if (dho_len != iface_conf->c_id[1]) {
1109 log_warnx("wrong "
1110 "DHO_DHCP_CLIENT_IDENTIFIER");
1111 return;
1112 }
1113 if (memcmp(p, &iface_conf->c_id[2], dho_len) !=
1114 0) {
1115 log_warnx("wrong "
1116 "DHO_DHCP_CLIENT_IDENTIFIER");
1117 return;
1118 }
1119 } else
1120 #endif /* SMALL */
1121 {
1122 if (dho_len != 1 + sizeof(iface->hw_address))
1123 goto wrong_length;
1124 if (*p != HTYPE_ETHER) {
1125 log_warnx("DHO_DHCP_CLIENT_IDENTIFIER: "
1126 "wrong type");
1127 return;
1128 }
1129 if (memcmp(p + 1, &iface->hw_address,
1130 sizeof(iface->hw_address)) != 0) {
1131 log_warnx("wrong "
1132 "DHO_DHCP_CLIENT_IDENTIFIER");
1133 return;
1134 }
1135 }
1136 p += dho_len;
1137 rem -= dho_len;
1138 break;
1139 case DHO_CLASSLESS_STATIC_ROUTES: {
1140 int prefixlen, compressed_prefixlen;
1141
1142 csr = 1;
1143 if (routers) {
1144 /*
1145 * Ignore routers option if classless static
1146 * routes are present (RFC3442).
1147 */
1148 routers = 0;
1149 routes_len = 0;
1150 }
1151 while (routes_len < MAX_DHCP_ROUTES && dho_len > 0) {
1152 prefixlen = *p;
1153 p += 1;
1154 rem -= 1;
1155 dho_len -= 1;
1156
1157 if (prefixlen < 0 || prefixlen > 32) {
1158 log_warnx("%s: invalid prefixlen: %d",
1159 __func__, prefixlen);
1160 return;
1161 }
1162
1163 if (prefixlen > 0)
1164 routes[routes_len].mask.s_addr =
1165 htonl(0xffffffff << (32 -
1166 prefixlen));
1167 else
1168 routes[routes_len].mask.s_addr =
1169 INADDR_ANY;
1170
1171 compressed_prefixlen = (prefixlen + 7) / 8;
1172 if (dho_len < compressed_prefixlen)
1173 goto wrong_length;
1174
1175 memcpy(&routes[routes_len].dst, p,
1176 compressed_prefixlen);
1177 p += compressed_prefixlen;
1178 rem -= compressed_prefixlen;
1179 dho_len -= compressed_prefixlen;
1180
1181 if (dho_len < sizeof(routes[routes_len].gw))
1182 goto wrong_length;
1183
1184 memcpy(&routes[routes_len].gw, p,
1185 sizeof(routes[routes_len].gw));
1186 p += sizeof(routes[routes_len].gw);
1187 rem -= sizeof(routes[routes_len].gw);
1188 dho_len -= sizeof(routes[routes_len].gw);
1189
1190 routes_len++;
1191 }
1192
1193 if (dho_len != 0) {
1194 /* ignore > MAX_DHCP_ROUTES routes */
1195 p += dho_len;
1196 rem -= dho_len;
1197 }
1198 break;
1199 }
1200 case DHO_IPV6_ONLY_PREFERRED:
1201 if (dho_len != sizeof(ipv6_only_time))
1202 goto wrong_length;
1203 memcpy(&ipv6_only_time, p, sizeof(ipv6_only_time));
1204 ipv6_only_time = ntohl(ipv6_only_time);
1205 if (log_getverbose() > 1) {
1206 log_debug("DHO_IPV6_ONLY_PREFERRED %us",
1207 ipv6_only_time);
1208 }
1209 p += dho_len;
1210 rem -= dho_len;
1211 break;
1212 default:
1213 if (log_getverbose() > 1)
1214 log_debug("DHO_%u, len: %u", dho, dho_len);
1215 p += dho_len;
1216 rem -= dho_len;
1217 }
1218
1219 }
1220 while (rem != 0) {
1221 if (*p != DHO_PAD)
1222 break;
1223 p++;
1224 rem--;
1225 }
1226 if (rem != 0)
1227 log_debug("%s: %lu bytes garbage data from %s", __func__, rem,
1228 from);
1229
1230 log_debug("%s on %s from %s/%s to %s/%s",
1231 dhcp_message_type2str(dhcp_message_type), if_name == NULL ? "?" :
1232 if_name, from, hbuf_src, to, hbuf_dst);
1233
1234 switch (dhcp_message_type) {
1235 case DHCPOFFER:
1236 if (iface->state != IF_INIT) {
1237 log_debug("ignoring unexpected DHCPOFFER");
1238 return;
1239 }
1240 if (server_identifier.s_addr == INADDR_ANY &&
1241 dhcp_hdr->yiaddr.s_addr == INADDR_ANY) {
1242 log_warnx("%s: did not receive server identifier or "
1243 "offered IP address", __func__);
1244 return;
1245 }
1246 #ifndef SMALL
1247 if (iface_conf != NULL && iface_conf->prefer_ipv6 &&
1248 ipv6_only_time > 0) {
1249 iface->ipv6_only_time = ipv6_only_time;
1250 state_transition(iface, IF_IPV6_ONLY);
1251 break;
1252 }
1253 #endif
1254 iface->server_identifier = server_identifier;
1255 iface->dhcp_server = server_identifier;
1256 iface->requested_ip = dhcp_hdr->yiaddr;
1257 state_transition(iface, IF_REQUESTING);
1258 break;
1259 case DHCPACK:
1260 switch (iface->state) {
1261 case IF_REQUESTING:
1262 case IF_RENEWING:
1263 case IF_REBINDING:
1264 case IF_REBOOTING:
1265 break;
1266 default:
1267 log_debug("ignoring unexpected DHCPACK");
1268 return;
1269 }
1270 if (server_identifier.s_addr == INADDR_ANY &&
1271 dhcp_hdr->yiaddr.s_addr == INADDR_ANY) {
1272 log_warnx("%s: did not receive server identifier or "
1273 "offered IP address", __func__);
1274 return;
1275 }
1276 if (lease_time == 0) {
1277 log_warnx("%s no lease time from %s", __func__, from);
1278 return;
1279 }
1280 if (subnet_mask.s_addr == INADDR_ANY) {
1281 log_warnx("%s: no subnetmask received from %s",
1282 __func__, from);
1283 return;
1284 }
1285
1286 /* Defaults if we didn't receive renewal or rebinding time. */
1287 if (renewal_time == 0)
1288 renewal_time = lease_time / 2;
1289 if (rebinding_time == 0)
1290 rebinding_time = lease_time - (lease_time / 8);
1291
1292 /* RFC 2131 4.4.5 */
1293 /* Ignore invalid T1/T2 options */
1294 if (renewal_time >= rebinding_time) {
1295 log_warnx("%s: renewal_time(%u) >= rebinding_time(%u) "
1296 "from %s: using defaults",
1297 __func__, renewal_time, rebinding_time, from);
1298 renewal_time = rebinding_time = 0;
1299 } else if (rebinding_time >= lease_time) {
1300 log_warnx("%s: rebinding_time(%u) >= lease_time(%u) "
1301 "from %s: using defaults",
1302 __func__, rebinding_time, lease_time, from);
1303 renewal_time = rebinding_time = 0;
1304 }
1305
1306 /* Defaults if we received wrong renewal or rebinding time. */
1307 if (renewal_time == 0)
1308 renewal_time = lease_time / 2;
1309 if (rebinding_time == 0)
1310 rebinding_time = lease_time - (lease_time / 8);
1311
1312 clock_gettime(CLOCK_MONOTONIC, &iface->request_time);
1313 iface->server_identifier = server_identifier;
1314 iface->dhcp_server = server_identifier;
1315 iface->requested_ip = dhcp_hdr->yiaddr;
1316 iface->mask = subnet_mask;
1317 #ifndef SMALL
1318 if (iface_conf != NULL && iface_conf->ignore & IGN_ROUTES) {
1319 iface->routes_len = 0;
1320 memset(iface->routes, 0, sizeof(iface->routes));
1321 } else
1322 #endif /* SMALL */
1323 {
1324 iface->prev_routes_len = iface->routes_len;
1325 memcpy(iface->prev_routes, iface->routes,
1326 sizeof(iface->prev_routes));
1327 iface->routes_len = routes_len;
1328 memcpy(iface->routes, routes, sizeof(iface->routes));
1329 }
1330 iface->lease_time = lease_time;
1331 iface->renewal_time = renewal_time;
1332 iface->rebinding_time = rebinding_time;
1333
1334 #ifndef SMALL
1335 if (iface_conf != NULL && iface_conf->ignore & IGN_DNS) {
1336 memset(iface->nameservers, 0,
1337 sizeof(iface->nameservers));
1338 } else
1339 #endif /* SMALL */
1340 {
1341 memcpy(iface->nameservers, nameservers,
1342 sizeof(iface->nameservers));
1343 }
1344
1345 iface->siaddr = dhcp_hdr->siaddr;
1346
1347 /* we made sure this is a string futher up */
1348 strnvis(iface->file, dhcp_hdr->file, sizeof(iface->file),
1349 VIS_SAFE);
1350
1351 strlcpy(iface->domainname, domainname,
1352 sizeof(iface->domainname));
1353 strlcpy(iface->hostname, hostname, sizeof(iface->hostname));
1354 #ifndef SMALL
1355 if (iface_conf != NULL && iface_conf->prefer_ipv6 &&
1356 ipv6_only_time > 0) {
1357 iface->ipv6_only_time = ipv6_only_time;
1358 state_transition(iface, IF_IPV6_ONLY);
1359 break;
1360 }
1361 #endif
1362 state_transition(iface, IF_BOUND);
1363 break;
1364 case DHCPNAK:
1365 switch (iface->state) {
1366 case IF_REQUESTING:
1367 case IF_RENEWING:
1368 case IF_REBINDING:
1369 case IF_REBOOTING:
1370 break;
1371 default:
1372 log_debug("ignoring unexpected DHCPNAK");
1373 return;
1374 }
1375
1376 state_transition(iface, IF_INIT);
1377 break;
1378 default:
1379 log_warnx("%s: unimplemented message type %d", __func__,
1380 dhcp_message_type);
1381 break;
1382 }
1383 return;
1384 too_short:
1385 log_warnx("%s: message from %s too short", __func__, from);
1386 return;
1387 wrong_length:
1388 log_warnx("%s: received option %d with wrong length: %d", __func__,
1389 dho, dho_len);
1390 return;
1391 }
1392
1393 /* XXX check valid transitions */
1394 void
state_transition(struct dhcpleased_iface * iface,enum if_state new_state)1395 state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
1396 {
1397 enum if_state old_state = iface->state;
1398 struct timespec now, res;
1399 char ifnamebuf[IF_NAMESIZE], *if_name;
1400
1401 iface->state = new_state;
1402
1403 switch (new_state) {
1404 case IF_DOWN:
1405 if (iface->requested_ip.s_addr == INADDR_ANY) {
1406 /* nothing to do until iface comes up */
1407 iface->timo.tv_sec = -1;
1408 break;
1409 }
1410 if (old_state == IF_DOWN) {
1411 /* nameservers already withdrawn when if went down */
1412 send_deconfigure_interface(iface);
1413 /* nothing more to do until iface comes back */
1414 iface->timo.tv_sec = -1;
1415 } else {
1416 send_rdns_withdraw(iface);
1417 clock_gettime(CLOCK_MONOTONIC, &now);
1418 timespecsub(&now, &iface->request_time, &res);
1419 iface->timo.tv_sec = iface->lease_time - res.tv_sec;
1420 if (iface->timo.tv_sec < 0)
1421 iface->timo.tv_sec = 0; /* deconfigure now */
1422 }
1423 break;
1424 case IF_INIT:
1425 switch (old_state) {
1426 case IF_INIT:
1427 if (iface->timo.tv_sec < MAX_EXP_BACKOFF_SLOW)
1428 iface->timo.tv_sec *= 2;
1429 break;
1430 case IF_REQUESTING:
1431 case IF_RENEWING:
1432 case IF_REBINDING:
1433 case IF_REBOOTING:
1434 /* lease expired, got DHCPNAK or timeout: delete IP */
1435 send_rdns_withdraw(iface);
1436 send_deconfigure_interface(iface);
1437 /* fall through */
1438 case IF_DOWN:
1439 case IF_IPV6_ONLY:
1440 iface->timo.tv_sec = START_EXP_BACKOFF;
1441 iface->xid = arc4random();
1442 break;
1443 case IF_BOUND:
1444 fatalx("invalid transition Bound -> Init");
1445 break;
1446 }
1447 request_dhcp_discover(iface);
1448 break;
1449 case IF_REBOOTING:
1450 if (old_state == IF_REBOOTING)
1451 iface->timo.tv_sec *= 2;
1452 else {
1453 iface->timo.tv_sec = START_EXP_BACKOFF;
1454 iface->xid = arc4random();
1455 }
1456 request_dhcp_request(iface);
1457 break;
1458 case IF_REQUESTING:
1459 if (old_state == IF_REQUESTING)
1460 iface->timo.tv_sec *= 2;
1461 else
1462 iface->timo.tv_sec = START_EXP_BACKOFF;
1463 request_dhcp_request(iface);
1464 break;
1465 case IF_BOUND:
1466 iface->timo.tv_sec = iface->renewal_time;
1467 if (old_state == IF_REQUESTING || old_state == IF_REBOOTING) {
1468 send_configure_interface(iface);
1469 send_rdns_proposal(iface);
1470 }
1471 break;
1472 case IF_RENEWING:
1473 if (old_state == IF_BOUND) {
1474 iface->timo.tv_sec = (iface->rebinding_time -
1475 iface->renewal_time) / 2; /* RFC 2131 4.4.5 */
1476 iface->xid = arc4random();
1477 } else
1478 iface->timo.tv_sec /= 2;
1479
1480 if (iface->timo.tv_sec < 60)
1481 iface->timo.tv_sec = 60;
1482 request_dhcp_request(iface);
1483 break;
1484 case IF_REBINDING:
1485 if (old_state == IF_RENEWING) {
1486 iface->timo.tv_sec = (iface->lease_time -
1487 iface->rebinding_time) / 2; /* RFC 2131 4.4.5 */
1488 } else
1489 iface->timo.tv_sec /= 2;
1490 request_dhcp_request(iface);
1491 break;
1492 case IF_IPV6_ONLY:
1493 switch (old_state) {
1494 case IF_REQUESTING:
1495 case IF_RENEWING:
1496 case IF_REBINDING:
1497 case IF_REBOOTING:
1498 /* going IPv6 only: delete legacy IP */
1499 send_rdns_withdraw(iface);
1500 send_deconfigure_interface(iface);
1501 /* fall through */
1502 case IF_INIT:
1503 case IF_DOWN:
1504 case IF_IPV6_ONLY:
1505 iface->timo.tv_sec = iface->ipv6_only_time;
1506 break;
1507 case IF_BOUND:
1508 fatalx("invalid transition Bound -> IPv6 only");
1509 break;
1510 }
1511 }
1512
1513 if_name = if_indextoname(iface->if_index, ifnamebuf);
1514 log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1515 "?" : if_name, if_state_name[old_state], if_state_name[new_state],
1516 iface->timo.tv_sec);
1517
1518 if (iface->timo.tv_sec == -1) {
1519 if (evtimer_pending(&iface->timer, NULL))
1520 evtimer_del(&iface->timer);
1521 } else
1522 evtimer_add(&iface->timer, &iface->timo);
1523 }
1524
1525 void
iface_timeout(int fd,short events,void * arg)1526 iface_timeout(int fd, short events, void *arg)
1527 {
1528 struct dhcpleased_iface *iface = (struct dhcpleased_iface *)arg;
1529 struct timespec now, res;
1530
1531 log_debug("%s[%d]: %s", __func__, iface->if_index,
1532 if_state_name[iface->state]);
1533
1534 switch (iface->state) {
1535 case IF_DOWN:
1536 state_transition(iface, IF_DOWN);
1537 break;
1538 case IF_INIT:
1539 state_transition(iface, IF_INIT);
1540 break;
1541 case IF_REBOOTING:
1542 if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_FAST)
1543 state_transition(iface, IF_INIT);
1544 else
1545 state_transition(iface, IF_REBOOTING);
1546 break;
1547 case IF_REQUESTING:
1548 if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_SLOW)
1549 state_transition(iface, IF_INIT);
1550 else
1551 state_transition(iface, IF_REQUESTING);
1552 break;
1553 case IF_BOUND:
1554 state_transition(iface, IF_RENEWING);
1555 break;
1556 case IF_RENEWING:
1557 clock_gettime(CLOCK_MONOTONIC, &now);
1558 timespecsub(&now, &iface->request_time, &res);
1559 log_debug("%s: res.tv_sec: %lld, rebinding_time: %u", __func__,
1560 res.tv_sec, iface->rebinding_time);
1561 if (res.tv_sec >= iface->rebinding_time)
1562 state_transition(iface, IF_REBINDING);
1563 else
1564 state_transition(iface, IF_RENEWING);
1565 break;
1566 case IF_REBINDING:
1567 clock_gettime(CLOCK_MONOTONIC, &now);
1568 timespecsub(&now, &iface->request_time, &res);
1569 log_debug("%s: res.tv_sec: %lld, lease_time: %u", __func__,
1570 res.tv_sec, iface->lease_time);
1571 if (res.tv_sec > iface->lease_time)
1572 state_transition(iface, IF_INIT);
1573 else
1574 state_transition(iface, IF_REBINDING);
1575 break;
1576 case IF_IPV6_ONLY:
1577 state_transition(iface, IF_REQUESTING);
1578 break;
1579 }
1580 }
1581
1582 void
request_dhcp_discover(struct dhcpleased_iface * iface)1583 request_dhcp_discover(struct dhcpleased_iface *iface)
1584 {
1585 struct imsg_req_dhcp imsg;
1586
1587 memset(&imsg, 0, sizeof(imsg));
1588
1589 imsg.if_index = iface->if_index;
1590 imsg.xid = iface->xid;
1591
1592 /*
1593 * similar to RFC 2131 4.3.6, Table 4 for DHCPDISCOVER
1594 * ------------------------------
1595 * | | INIT |
1596 * ------------------------------
1597 * |broad/unicast | broadcast |
1598 * |server-ip | MUST NOT |
1599 * |requested-ip | MAY |
1600 * |ciaddr | zero |
1601 * ------------------------------
1602 *
1603 * Leaving everything at 0 from the memset results in this table with
1604 * requested-ip not set.
1605 */
1606
1607 engine_imsg_compose_frontend(IMSG_SEND_DISCOVER, 0, &imsg, sizeof(imsg));
1608 }
1609
1610 void
request_dhcp_request(struct dhcpleased_iface * iface)1611 request_dhcp_request(struct dhcpleased_iface *iface)
1612 {
1613 struct imsg_req_dhcp imsg;
1614
1615 imsg.if_index = iface->if_index;
1616 imsg.xid = iface->xid;
1617
1618 /*
1619 * RFC 2131 4.3.6, Table 4
1620 * ---------------------------------------------------------------------
1621 * | |REBOOTING |REQUESTING |RENEWING |REBINDING |
1622 * ---------------------------------------------------------------------
1623 * |broad/unicast |broadcast |broadcast |unicast |broadcast |
1624 * |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT |
1625 * |requested-ip |MUST |MUST |MUST NOT |MUST NOT |
1626 * |ciaddr |zero |zero |IP address |IP address|
1627 * ---------------------------------------------------------------------
1628 */
1629 switch (iface->state) {
1630 case IF_DOWN:
1631 fatalx("invalid state IF_DOWN in %s", __func__);
1632 break;
1633 case IF_INIT:
1634 fatalx("invalid state IF_INIT in %s", __func__);
1635 break;
1636 case IF_BOUND:
1637 fatalx("invalid state IF_BOUND in %s", __func__);
1638 break;
1639 case IF_REBOOTING:
1640 imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast */
1641 imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT */
1642 imsg.requested_ip = iface->requested_ip; /* MUST */
1643 imsg.ciaddr.s_addr = INADDR_ANY; /* zero */
1644 break;
1645 case IF_REQUESTING:
1646 imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast */
1647 imsg.server_identifier =
1648 iface->server_identifier; /* MUST */
1649 imsg.requested_ip = iface->requested_ip; /* MUST */
1650 imsg.ciaddr.s_addr = INADDR_ANY; /* zero */
1651 break;
1652 case IF_RENEWING:
1653 imsg.dhcp_server = iface->dhcp_server; /* unicast */
1654 imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT */
1655 imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT */
1656 imsg.ciaddr = iface->requested_ip; /* IP address */
1657 break;
1658 case IF_REBINDING:
1659 imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast */
1660 imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT */
1661 imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT */
1662 imsg.ciaddr = iface->requested_ip; /* IP address */
1663 break;
1664 case IF_IPV6_ONLY:
1665 fatalx("invalid state IF_IPV6_ONLY in %s", __func__);
1666 break;
1667 }
1668
1669 engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg, sizeof(imsg));
1670 }
1671
1672 void
log_lease(struct dhcpleased_iface * iface,int deconfigure)1673 log_lease(struct dhcpleased_iface *iface, int deconfigure)
1674 {
1675 char hbuf_lease[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN];
1676 char ifnamebuf[IF_NAMESIZE], *if_name;
1677
1678 if_name = if_indextoname(iface->if_index, ifnamebuf);
1679 inet_ntop(AF_INET, &iface->requested_ip, hbuf_lease,
1680 sizeof(hbuf_lease));
1681 inet_ntop(AF_INET, &iface->server_identifier, hbuf_server,
1682 sizeof(hbuf_server));
1683
1684
1685 if (deconfigure)
1686 log_info("deleting %s from %s (lease from %s)", hbuf_lease,
1687 if_name == NULL ? "?" : if_name, hbuf_server);
1688 else
1689 log_info("adding %s to %s (lease from %s)", hbuf_lease,
1690 if_name == NULL ? "?" : if_name, hbuf_server);
1691 }
1692
1693 void
send_configure_interface(struct dhcpleased_iface * iface)1694 send_configure_interface(struct dhcpleased_iface *iface)
1695 {
1696 struct imsg_configure_interface imsg;
1697 int i, j, found;
1698
1699 log_lease(iface, 0);
1700
1701 memset(&imsg, 0, sizeof(imsg));
1702 imsg.if_index = iface->if_index;
1703 imsg.rdomain = iface->rdomain;
1704 imsg.addr = iface->requested_ip;
1705 imsg.mask = iface->mask;
1706 imsg.siaddr = iface->siaddr;
1707 strlcpy(imsg.file, iface->file, sizeof(imsg.file));
1708 strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
1709 strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
1710 for (i = 0; i < iface->prev_routes_len; i++) {
1711 found = 0;
1712 for (j = 0; j < iface->routes_len; j++) {
1713 if (memcmp(&iface->prev_routes[i], &iface->routes[j],
1714 sizeof(struct dhcp_route)) == 0) {
1715 found = 1;
1716 break;
1717 }
1718 }
1719 if (!found)
1720 imsg.routes[imsg.routes_len++] = iface->prev_routes[i];
1721 }
1722 if (imsg.routes_len > 0)
1723 engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg,
1724 sizeof(imsg));
1725 imsg.routes_len = iface->routes_len;
1726 memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
1727 engine_imsg_compose_main(IMSG_CONFIGURE_INTERFACE, 0, &imsg,
1728 sizeof(imsg));
1729 }
1730
1731 void
send_deconfigure_interface(struct dhcpleased_iface * iface)1732 send_deconfigure_interface(struct dhcpleased_iface *iface)
1733 {
1734 struct imsg_configure_interface imsg;
1735
1736 if (iface->requested_ip.s_addr == INADDR_ANY)
1737 return;
1738
1739 log_lease(iface, 1);
1740
1741 imsg.if_index = iface->if_index;
1742 imsg.rdomain = iface->rdomain;
1743 imsg.addr = iface->requested_ip;
1744 imsg.mask = iface->mask;
1745 imsg.siaddr = iface->siaddr;
1746 strlcpy(imsg.file, iface->file, sizeof(imsg.file));
1747 strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
1748 strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
1749 imsg.routes_len = iface->routes_len;
1750 memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
1751 engine_imsg_compose_main(IMSG_DECONFIGURE_INTERFACE, 0, &imsg,
1752 sizeof(imsg));
1753
1754 iface->server_identifier.s_addr = INADDR_ANY;
1755 iface->dhcp_server.s_addr = INADDR_ANY;
1756 iface->requested_ip.s_addr = INADDR_ANY;
1757 iface->mask.s_addr = INADDR_ANY;
1758 iface->routes_len = 0;
1759 memset(iface->routes, 0, sizeof(iface->routes));
1760 }
1761
1762 void
send_routes_withdraw(struct dhcpleased_iface * iface)1763 send_routes_withdraw(struct dhcpleased_iface *iface)
1764 {
1765 struct imsg_configure_interface imsg;
1766
1767 if (iface->requested_ip.s_addr == INADDR_ANY || iface->routes_len == 0)
1768 return;
1769
1770 imsg.if_index = iface->if_index;
1771 imsg.rdomain = iface->rdomain;
1772 imsg.addr = iface->requested_ip;
1773 imsg.mask = iface->mask;
1774 imsg.siaddr = iface->siaddr;
1775 strlcpy(imsg.file, iface->file, sizeof(imsg.file));
1776 strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
1777 strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
1778 imsg.routes_len = iface->routes_len;
1779 memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
1780 engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg,
1781 sizeof(imsg));
1782 }
1783
1784 void
log_rdns(struct dhcpleased_iface * iface,int withdraw)1785 log_rdns(struct dhcpleased_iface *iface, int withdraw)
1786 {
1787 int i;
1788 char hbuf_rdns[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN];
1789 char ifnamebuf[IF_NAMESIZE], *if_name, *rdns_buf = NULL, *tmp_buf;
1790
1791 if_name = if_indextoname(iface->if_index, ifnamebuf);
1792
1793 inet_ntop(AF_INET, &iface->server_identifier, hbuf_server,
1794 sizeof(hbuf_server));
1795
1796 for (i = 0; i < MAX_RDNS_COUNT && iface->nameservers[i].s_addr !=
1797 INADDR_ANY; i++) {
1798 inet_ntop(AF_INET, &iface->nameservers[i], hbuf_rdns,
1799 sizeof(hbuf_rdns));
1800 tmp_buf = rdns_buf;
1801 if (asprintf(&rdns_buf, "%s %s", tmp_buf ? tmp_buf : "",
1802 hbuf_rdns) < 0) {
1803 rdns_buf = NULL;
1804 break;
1805 }
1806 free(tmp_buf);
1807 }
1808
1809 if (rdns_buf != NULL) {
1810 if (withdraw) {
1811 log_info("deleting nameservers%s (lease from %s on %s)",
1812 rdns_buf, hbuf_server, if_name == NULL ? "?" :
1813 if_name);
1814 } else {
1815 log_info("adding nameservers%s (lease from %s on %s)",
1816 rdns_buf, hbuf_server, if_name == NULL ? "?" :
1817 if_name);
1818 }
1819 free(rdns_buf);
1820 }
1821 }
1822
1823 void
send_rdns_proposal(struct dhcpleased_iface * iface)1824 send_rdns_proposal(struct dhcpleased_iface *iface)
1825 {
1826 struct imsg_propose_rdns imsg;
1827
1828 log_rdns(iface, 0);
1829
1830 memset(&imsg, 0, sizeof(imsg));
1831
1832 imsg.if_index = iface->if_index;
1833 imsg.rdomain = iface->rdomain;
1834 for (imsg.rdns_count = 0; imsg.rdns_count < MAX_RDNS_COUNT &&
1835 iface->nameservers[imsg.rdns_count].s_addr != INADDR_ANY;
1836 imsg.rdns_count++)
1837 ;
1838 memcpy(imsg.rdns, iface->nameservers, sizeof(imsg.rdns));
1839 engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &imsg, sizeof(imsg));
1840 }
1841
1842 void
send_rdns_withdraw(struct dhcpleased_iface * iface)1843 send_rdns_withdraw(struct dhcpleased_iface *iface)
1844 {
1845 struct imsg_propose_rdns imsg;
1846
1847 log_rdns(iface, 1);
1848
1849 memset(&imsg, 0, sizeof(imsg));
1850
1851 imsg.if_index = iface->if_index;
1852 imsg.rdomain = iface->rdomain;
1853 engine_imsg_compose_main(IMSG_WITHDRAW_RDNS, 0, &imsg, sizeof(imsg));
1854 memset(iface->nameservers, 0, sizeof(iface->nameservers));
1855 }
1856
1857 void
parse_lease(struct dhcpleased_iface * iface,struct imsg_ifinfo * imsg_ifinfo)1858 parse_lease(struct dhcpleased_iface *iface, struct imsg_ifinfo *imsg_ifinfo)
1859 {
1860 char *p, *p1;
1861
1862 iface->requested_ip.s_addr = INADDR_ANY;
1863
1864 if ((p = strstr(imsg_ifinfo->lease, LEASE_IP_PREFIX)) == NULL)
1865 return;
1866
1867 p += sizeof(LEASE_IP_PREFIX) - 1;
1868 if ((p1 = strchr(p, '\n')) == NULL)
1869 return;
1870 *p1 = '\0';
1871
1872 if (inet_pton(AF_INET, p, &iface->requested_ip) != 1)
1873 iface->requested_ip.s_addr = INADDR_ANY;
1874 }
1875
1876 void
log_dhcp_hdr(struct dhcp_hdr * dhcp_hdr)1877 log_dhcp_hdr(struct dhcp_hdr *dhcp_hdr)
1878 {
1879 #ifndef SMALL
1880 char hbuf[INET_ADDRSTRLEN];
1881
1882 log_debug("dhcp_hdr op: %s (%d)", dhcp_hdr->op == DHCP_BOOTREQUEST ?
1883 "Boot Request" : dhcp_hdr->op == DHCP_BOOTREPLY ? "Boot Reply" :
1884 "Unknown", dhcp_hdr->op);
1885 log_debug("dhcp_hdr htype: %s (%d)", dhcp_hdr->htype == 1 ? "Ethernet":
1886 "Unknown", dhcp_hdr->htype);
1887 log_debug("dhcp_hdr hlen: %d", dhcp_hdr->hlen);
1888 log_debug("dhcp_hdr hops: %d", dhcp_hdr->hops);
1889 log_debug("dhcp_hdr xid: 0x%x", ntohl(dhcp_hdr->xid));
1890 log_debug("dhcp_hdr secs: %u", dhcp_hdr->secs);
1891 log_debug("dhcp_hdr flags: 0x%x", dhcp_hdr->flags);
1892 log_debug("dhcp_hdr ciaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->ciaddr,
1893 hbuf, sizeof(hbuf)));
1894 log_debug("dhcp_hdr yiaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->yiaddr,
1895 hbuf, sizeof(hbuf)));
1896 log_debug("dhcp_hdr siaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->siaddr,
1897 hbuf, sizeof(hbuf)));
1898 log_debug("dhcp_hdr giaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->giaddr,
1899 hbuf, sizeof(hbuf)));
1900 log_debug("dhcp_hdr chaddr: %02x:%02x:%02x:%02x:%02x:%02x "
1901 "(%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x)",
1902 dhcp_hdr->chaddr[0], dhcp_hdr->chaddr[1], dhcp_hdr->chaddr[2],
1903 dhcp_hdr->chaddr[3], dhcp_hdr->chaddr[4], dhcp_hdr->chaddr[5],
1904 dhcp_hdr->chaddr[6], dhcp_hdr->chaddr[7], dhcp_hdr->chaddr[8],
1905 dhcp_hdr->chaddr[9], dhcp_hdr->chaddr[10], dhcp_hdr->chaddr[11],
1906 dhcp_hdr->chaddr[12], dhcp_hdr->chaddr[13], dhcp_hdr->chaddr[14],
1907 dhcp_hdr->chaddr[15]);
1908 /* ignore sname and file, if we ever print it use strvis(3) */
1909 #endif
1910 }
1911
1912 const char *
dhcp_message_type2str(uint8_t dhcp_message_type)1913 dhcp_message_type2str(uint8_t dhcp_message_type)
1914 {
1915 switch (dhcp_message_type) {
1916 case DHCPDISCOVER:
1917 return "DHCPDISCOVER";
1918 case DHCPOFFER:
1919 return "DHCPOFFER";
1920 case DHCPREQUEST:
1921 return "DHCPREQUEST";
1922 case DHCPDECLINE:
1923 return "DHCPDECLINE";
1924 case DHCPACK:
1925 return "DHCPACK";
1926 case DHCPNAK:
1927 return "DHCPNAK";
1928 case DHCPRELEASE:
1929 return "DHCPRELEASE";
1930 case DHCPINFORM:
1931 return "DHCPINFORM";
1932 default:
1933 return "Unknown";
1934 }
1935 }
1936