Bug Summary

File:src/sbin/dhcpleased/dhcpleased.c
Warning:line 194, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dhcpleased.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/dhcpleased/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/dhcpleased -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/dhcpleased/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/dhcpleased/dhcpleased.c
1/* $OpenBSD: dhcpleased.c,v 1.23 2022/01/04 06:20:37 florian Exp $ */
2
3/*
4 * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21#include <sys/types.h>
22#include <sys/ioctl.h>
23#include <sys/queue.h>
24#include <sys/socket.h>
25#include <sys/stat.h>
26#include <sys/syslog.h>
27#include <sys/sysctl.h>
28#include <sys/uio.h>
29#include <sys/wait.h>
30
31#include <net/if.h>
32#include <net/route.h>
33#include <netinet/in.h>
34#include <netinet/if_ether.h>
35#include <netinet/in_var.h>
36
37#include <arpa/inet.h>
38
39#include <err.h>
40#include <errno(*__errno()).h>
41#include <fcntl.h>
42#include <event.h>
43#include <ifaddrs.h>
44#include <imsg.h>
45#include <netdb.h>
46#include <pwd.h>
47#include <stddef.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <signal.h>
52#include <unistd.h>
53
54#include "bpf.h"
55#include "log.h"
56#include "dhcpleased.h"
57#include "frontend.h"
58#include "engine.h"
59#include "control.h"
60
61enum dhcpleased_process {
62 PROC_MAIN,
63 PROC_ENGINE,
64 PROC_FRONTEND
65};
66
67__dead__attribute__((__noreturn__)) void usage(void);
68__dead__attribute__((__noreturn__)) void main_shutdown(void);
69
70void main_sig_handler(int, short, void *);
71
72static pid_t start_child(enum dhcpleased_process, char *, int, int, int);
73
74void main_dispatch_frontend(int, short, void *);
75void main_dispatch_engine(int, short, void *);
76void open_bpfsock(uint32_t);
77void configure_interface(struct imsg_configure_interface *);
78void deconfigure_interface(struct imsg_configure_interface *);
79void propose_rdns(struct imsg_propose_rdns *);
80void configure_routes(uint8_t, struct imsg_configure_interface *);
81void configure_route(uint8_t, uint32_t, int, struct sockaddr_in *, struct
82 sockaddr_in *, struct sockaddr_in *, struct sockaddr_in *, int);
83void read_lease_file(struct imsg_ifinfo *);
84
85static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
86int main_imsg_compose_frontend(int, int, void *, uint16_t);
87int main_imsg_compose_engine(int, int, void *, uint16_t);
88
89#ifndef SMALL
90int main_imsg_send_config(struct dhcpleased_conf *);
91#endif /* SMALL */
92int main_reload(void);
93
94static struct imsgev *iev_frontend;
95static struct imsgev *iev_engine;
96
97#ifndef SMALL
98struct dhcpleased_conf *main_conf;
99#endif
100char *conffile;
101pid_t frontend_pid;
102pid_t engine_pid;
103
104int routesock, ioctl_sock, rtm_seq, no_lease_files;
105
106void
107main_sig_handler(int sig, short event, void *arg)
108{
109 /*
110 * Normal signal handler rules don't apply because libevent
111 * decouples for us.
112 */
113
114 switch (sig) {
115 case SIGTERM15:
116 case SIGINT2:
117 main_shutdown();
118 case SIGHUP1:
119#ifndef SMALL
120 if (main_reload() == -1)
121 log_warnx("configuration reload failed");
122 else
123 log_debug("configuration reloaded");
124#endif /* SMALL */
125 break;
126 default:
127 fatalx("unexpected signal");
128 }
129}
130
131__dead__attribute__((__noreturn__)) void
132usage(void)
133{
134 extern char *__progname;
135
136 fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-f file] [-s socket]\n",
137 __progname);
138 exit(1);
139}
140
141int
142main(int argc, char *argv[])
143{
144 struct event ev_sigint, ev_sigterm, ev_sighup;
145 int ch;
146 int debug = 0, engine_flag = 0, frontend_flag = 0;
147 int verbose = 0, no_action = 0;
148 char *saved_argv0;
149 int pipe_main2frontend[2];
150 int pipe_main2engine[2];
151 int frontend_routesock, rtfilter, lockfd;
152 int rtable_any = RTABLE_ANY0xffffffff;
153 char *csock = _PATH_DHCPLEASED_SOCKET"/dev/dhcpleased.sock";
154#ifndef SMALL
155 int control_fd;
156#endif /* SMALL */
157
158 log_init(1, LOG_DAEMON(3<<3)); /* Log to stderr until daemonized. */
159 log_setverbose(1);
160
161 saved_argv0 = argv[0];
162 if (saved_argv0 == NULL((void*)0))
163 saved_argv0 = "dhcpleased";
164
165 while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) {
166 switch (ch) {
167 case 'd':
168 debug = 1;
169 break;
170 case 'E':
171 engine_flag = 1;
172 break;
173 case 'F':
174 frontend_flag = 1;
175 break;
176 case 'f':
177 conffile = optarg;
178 break;
179 case 'n':
180 no_action = 1;
181 break;
182 case 's':
183 csock = optarg;
184 break;
185 case 'v':
186 verbose++;
187 break;
188 default:
189 usage();
190 }
191 }
192
193 argc -= optind;
194 argv += optind;
Value stored to 'argv' is never read
195 if (argc > 0 || (engine_flag && frontend_flag))
196 usage();
197
198 if (engine_flag)
199 engine(debug, verbose);
200 else if (frontend_flag)
201 frontend(debug, verbose);
202
203#ifndef SMALL
204 /* parse config file */
205 if ((main_conf = parse_config(conffile)) == NULL((void*)0))
206 exit(1);
207
208 if (no_action) {
209 if (verbose)
210 print_config(main_conf);
211 else
212 fprintf(stderr(&__sF[2]), "configuration OK\n");
213 exit(0);
214 }
215#endif /* SMALL */
216
217 /* Check for root privileges. */
218 if (geteuid())
219 errx(1, "need root privileges");
220
221 lockfd = open(_PATH_LOCKFILE"/dev/dhcpleased.lock", O_CREAT0x0200|O_RDWR0x0002|O_EXLOCK0x0020|O_NONBLOCK0x0004, 0600);
222 if (lockfd == -1)
223 errx(1, "already running");
224
225 /* Check for assigned daemon user */
226 if (getpwnam(DHCPLEASED_USER"_dhcp") == NULL((void*)0))
227 errx(1, "unknown user %s", DHCPLEASED_USER"_dhcp");
228
229 log_init(debug, LOG_DAEMON(3<<3));
230 log_setverbose(verbose);
231
232 if (!debug)
233 daemon(0, 0);
234
235 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
236 PF_UNSPEC0, pipe_main2frontend) == -1)
237 fatal("main2frontend socketpair");
238 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
239 PF_UNSPEC0, pipe_main2engine) == -1)
240 fatal("main2engine socketpair");
241
242 /* Start children. */
243 engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1],
244 debug, verbose);
245 frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
246 pipe_main2frontend[1], debug, verbose);
247
248 log_procinit("main");
249
250 if ((routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000 |
251 SOCK_NONBLOCK0x4000, AF_INET2)) == -1)
252 fatal("route socket");
253 shutdown(SHUT_RD0, routesock);
254
255 event_init();
256
257 /* Setup signal handler. */
258 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void
*)0))
;
259 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, (
(void*)0))
;
260 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void
*)0))
;
261 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void*)0));
262 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void*)0));
263 signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void*)0));
264 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
265
266 /* Setup pipes to children. */
267
268 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL((void*)0) ||
269 (iev_engine = malloc(sizeof(struct imsgev))) == NULL((void*)0))
270 fatal(NULL((void*)0));
271 imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
272 iev_frontend->handler = main_dispatch_frontend;
273 imsg_init(&iev_engine->ibuf, pipe_main2engine[0]);
274 iev_engine->handler = main_dispatch_engine;
275
276 /* Setup event handlers for pipes to engine & frontend. */
277 iev_frontend->events = EV_READ0x02;
278 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
279 iev_frontend->events, iev_frontend->handler, iev_frontend);
280 event_add(&iev_frontend->ev, NULL((void*)0));
281
282 iev_engine->events = EV_READ0x02;
283 event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events,
284 iev_engine->handler, iev_engine);
285 event_add(&iev_engine->ev, NULL((void*)0));
286
287 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf))
288 fatal("could not establish imsg links");
289
290 if ((ioctl_sock = socket(AF_INET2, SOCK_DGRAM2 | SOCK_CLOEXEC0x8000, 0)) == -1)
291 fatal("socket");
292
293 if ((frontend_routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000,
294 AF_INET2)) == -1)
295 fatal("route socket");
296
297 rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13)) |
298 ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf));
299 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_MSGFILTER1,
300 &rtfilter, sizeof(rtfilter)) == -1)
301 fatal("setsockopt(ROUTE_MSGFILTER)");
302 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_TABLEFILTER2,
303 &rtable_any, sizeof(rtable_any)) == -1)
304 fatal("setsockopt(ROUTE_TABLEFILTER)");
305
306#ifndef SMALL
307 if ((control_fd = control_init(csock)) == -1)
308 warnx("control socket setup failed");
309#endif /* SMALL */
310
311 if (conffile != NULL((void*)0)) {
312 if (unveil(conffile, "r") == -1)
313 fatal("unveil %s", conffile);
314 } else {
315 if (unveil(_PATH_CONF_FILE"/etc/dhcpleased.conf", "r") == -1)
316 fatal("unveil %s", _PATH_CONF_FILE"/etc/dhcpleased.conf");
317 }
318 if (unveil("/dev/bpf", "rw") == -1)
319 fatal("unveil /dev/bpf");
320
321 if (unveil(_PATH_LEASE"/var/db/dhcpleased/", "rwc") == -1) {
322 no_lease_files = 1;
323 log_warn("disabling lease files, unveil " _PATH_LEASE"/var/db/dhcpleased/");
324 }
325
326 if (unveil(NULL((void*)0), NULL((void*)0)) == -1)
327 fatal("unveil");
328#if notyet
329 if (pledge("stdio inet rpath wpath sendfd wroute bpf", NULL((void*)0)) == -1)
330 fatal("pledge");
331#endif
332 main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL((void*)0), 0);
333
334#ifndef SMALL
335 if (control_fd != -1)
336 main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL((void*)0), 0);
337 main_imsg_send_config(main_conf);
338#endif /* SMALL */
339
340 main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL((void*)0), 0);
341
342 event_dispatch();
343
344 main_shutdown();
345 return (0);
346}
347
348__dead__attribute__((__noreturn__)) void
349main_shutdown(void)
350{
351 pid_t pid;
352 int status;
353
354 /* Close pipes. */
355 msgbuf_clear(&iev_frontend->ibuf.w);
356 close(iev_frontend->ibuf.fd);
357 msgbuf_clear(&iev_engine->ibuf.w);
358 close(iev_engine->ibuf.fd);
359
360#ifndef SMALL
361 config_clear(main_conf);
362#endif /* SMALL */
363
364 log_debug("waiting for children to terminate");
365 do {
366 pid = wait(&status);
367 if (pid == -1) {
368 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10)
369 fatal("wait");
370 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
371 log_warnx("%s terminated; signal %d",
372 (pid == engine_pid) ? "engine" :
373 "frontend", WTERMSIG(status)(((status) & 0177)));
374 } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4));
375
376 free(iev_frontend);
377 free(iev_engine);
378
379 log_info("terminating");
380 exit(0);
381}
382
383static pid_t
384start_child(enum dhcpleased_process p, char *argv0, int fd, int debug, int
385 verbose)
386{
387 char *argv[7];
388 int argc = 0;
389 pid_t pid;
390
391 switch (pid = fork()) {
392 case -1:
393 fatal("cannot fork");
394 case 0:
395 break;
396 default:
397 close(fd);
398 return (pid);
399 }
400
401 if (fd != 3) {
402 if (dup2(fd, 3) == -1)
403 fatal("cannot setup imsg fd");
404 } else if (fcntl(fd, F_SETFD2, 0) == -1)
405 fatal("cannot setup imsg fd");
406
407 argv[argc++] = argv0;
408 switch (p) {
409 case PROC_MAIN:
410 fatalx("Can not start main process");
411 case PROC_ENGINE:
412 argv[argc++] = "-E";
413 break;
414 case PROC_FRONTEND:
415 argv[argc++] = "-F";
416 break;
417 }
418 if (debug)
419 argv[argc++] = "-d";
420 if (verbose)
421 argv[argc++] = "-v";
422 if (verbose > 1)
423 argv[argc++] = "-v";
424 argv[argc++] = NULL((void*)0);
425
426 execvp(argv0, argv);
427 fatal("execvp");
428}
429
430void
431main_dispatch_frontend(int fd, short event, void *bula)
432{
433 struct imsgev *iev = bula;
434 struct imsgbuf *ibuf;
435 struct imsg imsg;
436 struct imsg_ifinfo imsg_ifinfo;
437 ssize_t n;
438 int shut = 0;
439 uint32_t if_index;
440#ifndef SMALL
441 int verbose;
442#endif /* SMALL */
443
444 ibuf = &iev->ibuf;
445
446 if (event & EV_READ0x02) {
447 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
448 fatal("imsg_read error");
449 if (n == 0) /* Connection closed. */
450 shut = 1;
451 }
452 if (event & EV_WRITE0x04) {
453 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
454 fatal("msgbuf_write");
455 if (n == 0) /* Connection closed. */
456 shut = 1;
457 }
458
459 for (;;) {
460 if ((n = imsg_get(ibuf, &imsg)) == -1)
461 fatal("imsg_get");
462 if (n == 0) /* No more messages. */
463 break;
464
465 switch (imsg.hdr.type) {
466 case IMSG_OPEN_BPFSOCK:
467 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index))
468 fatalx("%s: IMSG_OPEN_BPFSOCK wrong length: "
469 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
470 memcpy(&if_index, imsg.data, sizeof(if_index));
471 open_bpfsock(if_index);
472 break;
473#ifndef SMALL
474 case IMSG_CTL_RELOAD:
475 if (main_reload() == -1)
476 log_warnx("configuration reload failed");
477 else
478 log_warnx("configuration reloaded");
479 break;
480 case IMSG_CTL_LOG_VERBOSE:
481 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose))
482 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
483 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
484 memcpy(&verbose, imsg.data, sizeof(verbose));
485 log_setverbose(verbose);
486 break;
487#endif /* SMALL */
488 case IMSG_UPDATE_IF:
489 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_ifinfo))
490 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
491 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
492 memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
493 read_lease_file(&imsg_ifinfo);
494 main_imsg_compose_engine(IMSG_UPDATE_IF, -1,
495 &imsg_ifinfo, sizeof(imsg_ifinfo));
496 break;
497 default:
498 log_debug("%s: error handling imsg %d", __func__,
499 imsg.hdr.type);
500 break;
501 }
502 imsg_free(&imsg);
503 }
504 if (!shut)
505 imsg_event_add(iev);
506 else {
507 /* This pipe is dead. Remove its event handler */
508 event_del(&iev->ev);
509 event_loopexit(NULL((void*)0));
510 }
511}
512
513void
514main_dispatch_engine(int fd, short event, void *bula)
515{
516 struct imsgev *iev = bula;
517 struct imsgbuf *ibuf;
518 struct imsg imsg;
519 ssize_t n;
520 int shut = 0;
521
522 ibuf = &iev->ibuf;
523
524 if (event & EV_READ0x02) {
525 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
526 fatal("imsg_read error");
527 if (n == 0) /* Connection closed. */
528 shut = 1;
529 }
530 if (event & EV_WRITE0x04) {
531 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
532 fatal("msgbuf_write");
533 if (n == 0) /* Connection closed. */
534 shut = 1;
535 }
536
537 for (;;) {
538 if ((n = imsg_get(ibuf, &imsg)) == -1)
539 fatal("imsg_get");
540 if (n == 0) /* No more messages. */
541 break;
542
543 switch (imsg.hdr.type) {
544 case IMSG_CONFIGURE_INTERFACE: {
545 struct imsg_configure_interface imsg_interface;
546 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_interface))
547 fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
548 "length: %lu", __func__,
549 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
550 memcpy(&imsg_interface, imsg.data,
551 sizeof(imsg_interface));
552 if (imsg_interface.routes_len >= MAX_DHCP_ROUTES256)
553 fatalx("%s: too many routes in imsg", __func__);
554 configure_interface(&imsg_interface);
555 break;
556 }
557 case IMSG_DECONFIGURE_INTERFACE: {
558 struct imsg_configure_interface imsg_interface;
559 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_interface))
560 fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
561 "length: %lu", __func__,
562 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
563 memcpy(&imsg_interface, imsg.data,
564 sizeof(imsg_interface));
565 if (imsg_interface.routes_len >= MAX_DHCP_ROUTES256)
566 fatalx("%s: too many routes in imsg", __func__);
567 deconfigure_interface(&imsg_interface);
568 main_imsg_compose_frontend(IMSG_CLOSE_UDPSOCK, -1,
569 &imsg_interface.if_index,
570 sizeof(imsg_interface.if_index));
571 break;
572 }
573 case IMSG_WITHDRAW_ROUTES: {
574 struct imsg_configure_interface imsg_interface;
575 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_interface))
576 fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
577 "length: %lu", __func__,
578 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
579 memcpy(&imsg_interface, imsg.data,
580 sizeof(imsg_interface));
581 if (imsg_interface.routes_len >= MAX_DHCP_ROUTES256)
582 fatalx("%s: too many routes in imsg", __func__);
583 if (imsg_interface.routes_len > 0)
584 configure_routes(RTM_DELETE0x2, &imsg_interface);
585 break;
586 }
587 case IMSG_PROPOSE_RDNS: {
588 struct imsg_propose_rdns rdns;
589 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdns))
590 fatalx("%s: IMSG_PROPOSE_RDNS wrong "
591 "length: %lu", __func__,
592 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
593 memcpy(&rdns, imsg.data, sizeof(rdns));
594 if ((2 + rdns.rdns_count * sizeof(struct in_addr)) >
595 sizeof(struct sockaddr_rtdns))
596 fatalx("%s: rdns_count too big: %d", __func__,
597 rdns.rdns_count);
598 propose_rdns(&rdns);
599 break;
600 }
601 case IMSG_WITHDRAW_RDNS: {
602 struct imsg_propose_rdns rdns;
603 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdns))
604 fatalx("%s: IMSG_PROPOSE_RDNS wrong "
605 "length: %lu", __func__,
606 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
607 memcpy(&rdns, imsg.data, sizeof(rdns));
608 if (rdns.rdns_count != 0)
609 fatalx("%s: expected rdns_count == 0: %d",
610 __func__, rdns.rdns_count);
611 propose_rdns(&rdns);
612 break;
613 }
614 default:
615 log_debug("%s: error handling imsg %d", __func__,
616 imsg.hdr.type);
617 break;
618 }
619 imsg_free(&imsg);
620 }
621 if (!shut)
622 imsg_event_add(iev);
623 else {
624 /* This pipe is dead. Remove its event handler. */
625 event_del(&iev->ev);
626 event_loopexit(NULL((void*)0));
627 }
628}
629
630int
631main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen)
632{
633 if (iev_frontend)
634 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data,
635 datalen));
636 else
637 return (-1);
638}
639
640int
641main_imsg_compose_engine(int type, int fd, void *data, uint16_t datalen)
642{
643 if (iev_engine)
644 return(imsg_compose_event(iev_engine, type, 0, 0, fd, data,
645 datalen));
646 else
647 return (-1);
648}
649
650void
651imsg_event_add(struct imsgev *iev)
652{
653 iev->events = EV_READ0x02;
654 if (iev->ibuf.w.queued)
655 iev->events |= EV_WRITE0x04;
656
657 event_del(&iev->ev);
658 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
659 event_add(&iev->ev, NULL((void*)0));
660}
661
662int
663imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
664 pid_t pid, int fd, void *data, uint16_t datalen)
665{
666 int ret;
667
668 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data,
669 datalen)) != -1)
670 imsg_event_add(iev);
671
672 return (ret);
673}
674
675static int
676main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
677 struct imsgbuf *engine_buf)
678{
679 int pipe_frontend2engine[2];
680
681 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
682 PF_UNSPEC0, pipe_frontend2engine) == -1)
683 return (-1);
684
685 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0,
686 pipe_frontend2engine[0], NULL((void*)0), 0) == -1)
687 return (-1);
688 imsg_flush(frontend_buf);
689 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0,
690 pipe_frontend2engine[1], NULL((void*)0), 0) == -1)
691 return (-1);
692 imsg_flush(engine_buf);
693 return (0);
694}
695
696#ifndef SMALL
697int
698main_reload(void)
699{
700 struct dhcpleased_conf *xconf;
701
702 if ((xconf = parse_config(conffile)) == NULL((void*)0))
703 return (-1);
704
705 if (main_imsg_send_config(xconf) == -1)
706 return (-1);
707
708 merge_config(main_conf, xconf);
709
710 return (0);
711}
712
713int
714main_imsg_send_config(struct dhcpleased_conf *xconf)
715{
716 struct iface_conf *iface_conf;
717
718 main_imsg_compose_frontend(IMSG_RECONF_CONF, -1, NULL((void*)0), 0);
719 main_imsg_compose_engine(IMSG_RECONF_CONF, -1, NULL((void*)0), 0);
720
721 /* Send the interface list to the frontend & engine. */
722 SIMPLEQ_FOREACH(iface_conf, &xconf->iface_list, entry)for((iface_conf) = ((&xconf->iface_list)->sqh_first
); (iface_conf) != ((void*)0); (iface_conf) = ((iface_conf)->
entry.sqe_next))
{
723 main_imsg_compose_frontend(IMSG_RECONF_IFACE, -1, iface_conf,
724 sizeof(*iface_conf));
725 main_imsg_compose_engine(IMSG_RECONF_IFACE, -1, iface_conf,
726 sizeof(*iface_conf));
727 main_imsg_compose_frontend(IMSG_RECONF_VC_ID, -1,
728 iface_conf->vc_id, iface_conf->vc_id_len);
729 main_imsg_compose_engine(IMSG_RECONF_VC_ID, -1,
730 iface_conf->vc_id, iface_conf->vc_id_len);
731 main_imsg_compose_frontend(IMSG_RECONF_C_ID, -1,
732 iface_conf->c_id, iface_conf->c_id_len);
733 main_imsg_compose_engine(IMSG_RECONF_C_ID, -1,
734 iface_conf->c_id, iface_conf->c_id_len);
735 if (iface_conf->h_name != NULL((void*)0))
736 main_imsg_compose_frontend(IMSG_RECONF_H_NAME, -1,
737 iface_conf->h_name, strlen(iface_conf->h_name) + 1);
738 }
739
740 /* Config is now complete. */
741 main_imsg_compose_frontend(IMSG_RECONF_END, -1, NULL((void*)0), 0);
742 main_imsg_compose_engine(IMSG_RECONF_END, -1, NULL((void*)0), 0);
743
744 return (0);
745}
746#endif /* SMALL */
747
748void
749configure_interface(struct imsg_configure_interface *imsg)
750{
751 struct ifaliasreq ifaliasreq;
752 struct ifaddrs *ifap, *ifa;
753 struct sockaddr_in *req_sin_addr, *req_sin_mask;
754 int found = 0, udpsock, opt = 1, len, fd = -1;
755 char *if_name;
756 char ip_ntop_buf[INET_ADDRSTRLEN16];
757 char nextserver_ntop_buf[INET_ADDRSTRLEN16];
758 char lease_buf[LEASE_SIZE4096];
759 char lease_file_buf[sizeof(_PATH_LEASE"/var/db/dhcpleased/") +
760 IF_NAMESIZE16];
761 char tmpl[] = _PATH_LEASE"/var/db/dhcpleased/""XXXXXXXXXX";
762
763 memset(&ifaliasreq, 0, sizeof(ifaliasreq));
764
765 if_name = if_indextoname(imsg->if_index, ifaliasreq.ifra_name);
766 if (if_name == NULL((void*)0)) {
767 log_warnx("%s: cannot find interface %d", __func__,
768 imsg->if_index);
769 return;
770 }
771
772 log_debug("%s %s", __func__, if_name);
773
774 if (getifaddrs(&ifap) != 0)
775 fatal("getifaddrs");
776
777 req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addrifra_ifrau.ifrau_addr;
778 req_sin_addr->sin_family = AF_INET2;
779 req_sin_addr->sin_len = sizeof(*req_sin_addr);
780
781 for (ifa = ifap; ifa != NULL((void*)0); ifa = ifa->ifa_next) {
782 struct in_addr addr, mask;
783
784 if (strcmp(if_name, ifa->ifa_name) != 0)
785 continue;
786 if (ifa->ifa_addr == NULL((void*)0))
787 continue;
788 if (ifa->ifa_addr->sa_family != AF_INET2)
789 continue;
790
791 addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
792 mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
793
794 if (imsg->addr.s_addr == addr.s_addr) {
795 if (imsg->mask.s_addr == mask.s_addr)
796 found = 1;
797 else {
798 req_sin_addr->sin_addr = addr;
799 if (ioctl(ioctl_sock, SIOCDIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((25)))
, &ifaliasreq)
800 == -1) {
801 if (errno(*__errno()) != EADDRNOTAVAIL49)
802 log_warn("SIOCDIFADDR");
803 }
804 }
805 break;
806 }
807 }
808
809 req_sin_addr->sin_addr = imsg->addr;
810 if (!found) {
811 req_sin_mask = (struct sockaddr_in *)&ifaliasreq.ifra_mask;
812 req_sin_mask->sin_family = AF_INET2;
813 req_sin_mask->sin_len = sizeof(*req_sin_mask);
814 req_sin_mask->sin_addr = imsg->mask;
815 if (ioctl(ioctl_sock, SIOCAIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifaliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
, &ifaliasreq) == -1)
816 log_warn("SIOCAIFADDR");
817 }
818 if (imsg->routes_len > 0)
819 configure_routes(RTM_ADD0x1, imsg);
820
821 req_sin_addr->sin_port = ntohs(CLIENT_PORT)(__uint16_t)(__builtin_constant_p(68) ? (__uint16_t)(((__uint16_t
)(68) & 0xffU) << 8 | ((__uint16_t)(68) & 0xff00U
) >> 8) : __swap16md(68))
;
822 if ((udpsock = socket(AF_INET2, SOCK_DGRAM2, 0)) == -1) {
823 log_warn("socket");
824 return;
825 }
826 if (setsockopt(udpsock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, &opt,
827 sizeof(opt)) == -1)
828 log_warn("setting SO_REUSEADDR on socket");
829
830 if (setsockopt(udpsock, SOL_SOCKET0xffff, SO_RTABLE0x1021, &imsg->rdomain,
831 sizeof(imsg->rdomain)) == -1) {
832 /* we might race against removal of the rdomain */
833 log_warn("setsockopt SO_RTABLE");
834 close(udpsock);
835 return;
836 }
837
838 if (bind(udpsock, (struct sockaddr *)req_sin_addr,
839 sizeof(*req_sin_addr)) == -1) {
840 close(udpsock);
841 return;
842 }
843
844 shutdown(udpsock, SHUT_RD0);
845
846 main_imsg_compose_frontend(IMSG_UDPSOCK, udpsock,
847 &imsg->if_index, sizeof(imsg->if_index));
848
849 if (no_lease_files)
850 return;
851
852 if (inet_ntop(AF_INET2, &imsg->addr, ip_ntop_buf, sizeof(ip_ntop_buf)) ==
853 NULL((void*)0)) {
854 log_warn("%s: inet_ntop", __func__);
855 return;
856 }
857
858 if (imsg->siaddr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)))
859 nextserver_ntop_buf[0] = '\0';
860 else {
861 if (inet_ntop(AF_INET2, &imsg->siaddr, nextserver_ntop_buf,
862 sizeof(nextserver_ntop_buf)) == NULL((void*)0)) {
863 log_warn("%s: inet_ntop", __func__);
864 return;
865 }
866 }
867 len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s",
868 _PATH_LEASE"/var/db/dhcpleased/", if_name);
869 if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) {
870 log_warnx("%s: failed to encode lease path for %s", __func__,
871 if_name);
872 return;
873 }
874
875 len = snprintf(lease_buf, sizeof(lease_buf),
876 "%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n",
877 LEASE_VERSION"version: 2", LEASE_IP_PREFIX"ip: ", ip_ntop_buf,
878 LEASE_NEXTSERVER_PREFIX"next-server: ", nextserver_ntop_buf, LEASE_BOOTFILE_PREFIX"filename: ",
879 imsg->file, LEASE_HOSTNAME_PREFIX"host-name: ", imsg->hostname,
880 LEASE_DOMAIN_PREFIX"domain-name: ", imsg->domainname);
881 if ( len == -1 || (size_t) len >= sizeof(lease_buf)) {
882 log_warnx("%s: failed to encode lease for %s", __func__,
883 ip_ntop_buf);
884 return;
885 }
886
887 if ((fd = mkstemp(tmpl)) == -1) {
888 log_warn("%s: mkstemp", __func__);
889 return;
890 }
891
892 if (write(fd, lease_buf, len) < len)
893 goto err;
894
895 if (fchmod(fd, 0644) == -1)
896 goto err;
897
898 if (close(fd) == -1)
899 goto err;
900 fd = -1;
901
902 if (rename(tmpl, lease_file_buf) == -1)
903 goto err;
904 return;
905 err:
906 log_warn("%s", __func__);
907 if (fd != -1)
908 close(fd);
909 unlink(tmpl);
910}
911
912void
913deconfigure_interface(struct imsg_configure_interface *imsg)
914{
915 struct ifaliasreq ifaliasreq;
916 struct sockaddr_in *req_sin_addr;
917
918 memset(&ifaliasreq, 0, sizeof(ifaliasreq));
919
920 if (imsg->routes_len > 0)
921 configure_routes(RTM_DELETE0x2, imsg);
922
923 if (if_indextoname(imsg->if_index, ifaliasreq.ifra_name) == NULL((void*)0)) {
924 log_warnx("%s: cannot find interface %d", __func__,
925 imsg->if_index);
926 return;
927 }
928
929 log_debug("%s %s", __func__, ifaliasreq.ifra_name);
930
931 req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addrifra_ifrau.ifrau_addr;
932 req_sin_addr->sin_family = AF_INET2;
933 req_sin_addr->sin_len = sizeof(*req_sin_addr);
934
935 req_sin_addr->sin_addr = imsg->addr;
936 if (ioctl(ioctl_sock, SIOCDIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((25)))
, &ifaliasreq) == -1) {
937 if (errno(*__errno()) != EADDRNOTAVAIL49)
938 log_warn("SIOCDIFADDR");
939 }
940}
941
942void
943configure_routes(uint8_t rtm_type, struct imsg_configure_interface *imsg)
944{
945 struct sockaddr_in dst, mask, gw, ifa;
946 in_addr_t addrnet, gwnet;
947 int i;
948
949 memset(&ifa, 0, sizeof(ifa));
950 ifa.sin_family = AF_INET2;
951 ifa.sin_len = sizeof(ifa);
952 ifa.sin_addr = imsg->addr;
953
954 memset(&dst, 0, sizeof(dst));
955 dst.sin_family = AF_INET2;
956 dst.sin_len = sizeof(dst);
957
958 memset(&mask, 0, sizeof(mask));
959 mask.sin_family = AF_INET2;
960 mask.sin_len = sizeof(mask);
961
962 memset(&gw, 0, sizeof(gw));
963 gw.sin_family = AF_INET2;
964 gw.sin_len = sizeof(gw);
965
966 addrnet = imsg->addr.s_addr & imsg->mask.s_addr;
967
968 for (i = 0; i < imsg->routes_len; i++) {
969 dst.sin_addr = imsg->routes[i].dst;
970 mask.sin_addr = imsg->routes[i].mask;
971 gw.sin_addr = imsg->routes[i].gw;
972
973 if (gw.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) {
974 /* direct route */
975 configure_route(rtm_type, imsg->if_index,
976 imsg->rdomain, &dst, &mask, &ifa, NULL((void*)0),
977 RTF_CLONING0x100);
978 } else if (mask.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) {
979 /* default route */
980 gwnet = gw.sin_addr.s_addr & imsg->mask.s_addr;
981 if (addrnet != gwnet) {
982 /*
983 * The gateway for the default route is outside
984 * the configured prefix. Install a direct
985 * cloning route for the gateway to make the
986 * default route reachable.
987 */
988 mask.sin_addr.s_addr = 0xffffffff;
989 configure_route(rtm_type, imsg->if_index,
990 imsg->rdomain, &gw, &mask, &ifa, NULL((void*)0),
991 RTF_CLONING0x100);
992 mask.sin_addr = imsg->routes[i].mask;
993 }
994
995 if (gw.sin_addr.s_addr == ifa.sin_addr.s_addr) {
996 /* directly connected default */
997 configure_route(rtm_type, imsg->if_index,
998 imsg->rdomain, &dst, &mask, &gw, NULL((void*)0), 0);
999 } else {
1000 /* default route via gateway */
1001 configure_route(rtm_type, imsg->if_index,
1002 imsg->rdomain, &dst, &mask, &gw, &ifa,
1003 RTF_GATEWAY0x2);
1004 }
1005 } else {
1006 /* non-default via gateway */
1007 configure_route(rtm_type, imsg->if_index, imsg->rdomain,
1008 &dst, &mask, &gw, NULL((void*)0), RTF_GATEWAY0x2);
1009 }
1010 }
1011}
1012
1013#define ROUNDUP(a)(((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) -
1))) : (a))
\
1014 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
1015void
1016configure_route(uint8_t rtm_type, uint32_t if_index, int rdomain, struct
1017 sockaddr_in *dst, struct sockaddr_in *mask, struct sockaddr_in *gw,
1018 struct sockaddr_in *ifa, int rtm_flags)
1019{
1020 struct rt_msghdr rtm;
1021 struct sockaddr_rtlabel rl;
1022 struct iovec iov[12];
1023 long pad = 0;
1024 int iovcnt = 0, padlen;
1025
1026 memset(&rtm, 0, sizeof(rtm));
1027
1028 rtm.rtm_version = RTM_VERSION5;
1029 rtm.rtm_type = rtm_type;
1030 rtm.rtm_msglen = sizeof(rtm);
1031 rtm.rtm_index = if_index;
1032 rtm.rtm_tableid = rdomain;
1033 rtm.rtm_seq = ++rtm_seq;
1034 rtm.rtm_priority = RTP_NONE0;
1035 rtm.rtm_addrs = RTA_DST0x1 | RTA_GATEWAY0x2 | RTA_NETMASK0x4 | RTA_LABEL0x400;
1036 rtm.rtm_flags = RTF_UP0x1 | RTF_STATIC0x800 | RTF_MPATH0x40000 | rtm_flags;
1037
1038 if (ifa)
1039 rtm.rtm_addrs |= RTA_IFA0x20;
1040
1041 iov[iovcnt].iov_base = &rtm;
1042 iov[iovcnt++].iov_len = sizeof(rtm);
1043
1044 iov[iovcnt].iov_base = dst;
1045 iov[iovcnt++].iov_len = dst->sin_len;
1046 rtm.rtm_msglen += dst->sin_len;
1047 padlen = ROUNDUP(dst->sin_len)(((dst->sin_len) & (sizeof(long) - 1)) ? (1 + ((dst->
sin_len) | (sizeof(long) - 1))) : (dst->sin_len))
- dst->sin_len;
1048 if (padlen > 0) {
1049 iov[iovcnt].iov_base = &pad;
1050 iov[iovcnt++].iov_len = padlen;
1051 rtm.rtm_msglen += padlen;
1052 }
1053
1054 iov[iovcnt].iov_base = gw;
1055 iov[iovcnt++].iov_len = gw->sin_len;
1056 rtm.rtm_msglen += gw->sin_len;
1057 padlen = ROUNDUP(gw->sin_len)(((gw->sin_len) & (sizeof(long) - 1)) ? (1 + ((gw->
sin_len) | (sizeof(long) - 1))) : (gw->sin_len))
- gw->sin_len;
1058 if (padlen > 0) {
1059 iov[iovcnt].iov_base = &pad;
1060 iov[iovcnt++].iov_len = padlen;
1061 rtm.rtm_msglen += padlen;
1062 }
1063
1064 iov[iovcnt].iov_base = mask;
1065 iov[iovcnt++].iov_len = mask->sin_len;
1066 rtm.rtm_msglen += mask->sin_len;
1067 padlen = ROUNDUP(mask->sin_len)(((mask->sin_len) & (sizeof(long) - 1)) ? (1 + ((mask->
sin_len) | (sizeof(long) - 1))) : (mask->sin_len))
- mask->sin_len;
1068 if (padlen > 0) {
1069 iov[iovcnt].iov_base = &pad;
1070 iov[iovcnt++].iov_len = padlen;
1071 rtm.rtm_msglen += padlen;
1072 }
1073
1074 if (ifa) {
1075 iov[iovcnt].iov_base = ifa;
1076 iov[iovcnt++].iov_len = ifa->sin_len;
1077 rtm.rtm_msglen += ifa->sin_len;
1078 padlen = ROUNDUP(ifa->sin_len)(((ifa->sin_len) & (sizeof(long) - 1)) ? (1 + ((ifa->
sin_len) | (sizeof(long) - 1))) : (ifa->sin_len))
- ifa->sin_len;
1079 if (padlen > 0) {
1080 iov[iovcnt].iov_base = &pad;
1081 iov[iovcnt++].iov_len = padlen;
1082 rtm.rtm_msglen += padlen;
1083 }
1084 }
1085
1086 memset(&rl, 0, sizeof(rl));
1087 rl.sr_len = sizeof(rl);
1088 rl.sr_family = AF_UNSPEC0;
1089 (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s",
1090 DHCPLEASED_RTA_LABEL"dhcpleased");
1091 iov[iovcnt].iov_base = &rl;
1092 iov[iovcnt++].iov_len = sizeof(rl);
1093 rtm.rtm_msglen += sizeof(rl);
1094 padlen = ROUNDUP(sizeof(rl))(((sizeof(rl)) & (sizeof(long) - 1)) ? (1 + ((sizeof(rl))
| (sizeof(long) - 1))) : (sizeof(rl)))
- sizeof(rl);
1095 if (padlen > 0) {
1096 iov[iovcnt].iov_base = &pad;
1097 iov[iovcnt++].iov_len = padlen;
1098 rtm.rtm_msglen += padlen;
1099 }
1100
1101 if (writev(routesock, iov, iovcnt) == -1) {
1102 if (errno(*__errno()) != EEXIST17)
1103 log_warn("failed to send route message");
1104 }
1105}
1106
1107#ifndef SMALL
1108const char*
1109sin_to_str(struct sockaddr_in *sin)
1110{
1111 static char hbuf[NI_MAXHOST256];
1112 int error;
1113
1114 error = getnameinfo((struct sockaddr *)sin, sin->sin_len, hbuf,
1115 sizeof(hbuf), NULL((void*)0), 0, NI_NUMERICHOST1 | NI_NUMERICSERV2);
1116 if (error) {
1117 log_warnx("%s", gai_strerror(error));
1118 strlcpy(hbuf, "unknown", sizeof(hbuf));
1119 }
1120 return hbuf;
1121}
1122#endif /* SMALL */
1123
1124void
1125open_bpfsock(uint32_t if_index)
1126{
1127 int bpfsock;
1128 char ifname[IF_NAMESIZE16];
1129
1130 if (if_indextoname(if_index, ifname) == NULL((void*)0)) {
1131 log_warnx("%s: cannot find interface %d", __func__, if_index);
1132 return;
1133 }
1134
1135 if ((bpfsock = get_bpf_sock(ifname)) == -1)
1136 return;
1137
1138 main_imsg_compose_frontend(IMSG_BPFSOCK, bpfsock, &if_index,
1139 sizeof(if_index));
1140}
1141
1142void
1143propose_rdns(struct imsg_propose_rdns *rdns)
1144{
1145 struct rt_msghdr rtm;
1146 struct sockaddr_rtdns rtdns;
1147 struct iovec iov[3];
1148 long pad = 0;
1149 int iovcnt = 0, padlen;
1150
1151 memset(&rtm, 0, sizeof(rtm));
1152
1153 rtm.rtm_version = RTM_VERSION5;
1154 rtm.rtm_type = RTM_PROPOSAL0x13;
1155 rtm.rtm_msglen = sizeof(rtm);
1156 rtm.rtm_tableid = rdns->rdomain;
1157 rtm.rtm_index = rdns->if_index;
1158 rtm.rtm_seq = ++rtm_seq;
1159 rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT58;
1160 rtm.rtm_addrs = RTA_DNS0x1000;
1161 rtm.rtm_flags = RTF_UP0x1;
1162
1163 iov[iovcnt].iov_base = &rtm;
1164 iov[iovcnt++].iov_len = sizeof(rtm);
1165
1166 memset(&rtdns, 0, sizeof(rtdns));
1167 rtdns.sr_family = AF_INET2;
1168 rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in_addr);
1169 memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns));
1170
1171 iov[iovcnt].iov_base = &rtdns;
1172 iov[iovcnt++].iov_len = sizeof(rtdns);
1173 rtm.rtm_msglen += sizeof(rtdns);
1174 padlen = ROUNDUP(sizeof(rtdns))(((sizeof(rtdns)) & (sizeof(long) - 1)) ? (1 + ((sizeof(rtdns
)) | (sizeof(long) - 1))) : (sizeof(rtdns)))
- sizeof(rtdns);
1175 if (padlen > 0) {
1176 iov[iovcnt].iov_base = &pad;
1177 iov[iovcnt++].iov_len = padlen;
1178 rtm.rtm_msglen += padlen;
1179 }
1180
1181 if (writev(routesock, iov, iovcnt) == -1)
1182 log_warn("failed to propose nameservers");
1183}
1184
1185void
1186read_lease_file(struct imsg_ifinfo *imsg_ifinfo)
1187{
1188 int len, fd;
1189 char if_name[IF_NAMESIZE16];
1190 char lease_file_buf[sizeof(_PATH_LEASE"/var/db/dhcpleased/") + IF_NAMESIZE16];
1191
1192 if (no_lease_files)
1193 return;
1194
1195 memset(imsg_ifinfo->lease, 0, sizeof(imsg_ifinfo->lease));
1196
1197 if (if_indextoname(imsg_ifinfo->if_index, if_name) == NULL((void*)0)) {
1198 log_warnx("%s: cannot find interface %d", __func__,
1199 imsg_ifinfo->if_index);
1200 return;
1201 }
1202
1203 len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s",
1204 _PATH_LEASE"/var/db/dhcpleased/", if_name);
1205 if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) {
1206 log_warnx("%s: failed to encode lease path for %s", __func__,
1207 if_name);
1208 return;
1209 }
1210
1211 if ((fd = open(lease_file_buf, O_RDONLY0x0000)) == -1)
1212 return;
1213
1214 /* no need for error handling, we'll just do a DHCP discover */
1215 read(fd, imsg_ifinfo->lease, sizeof(imsg_ifinfo->lease) - 1);
1216 close(fd);
1217}
1218
1219#ifndef SMALL
1220void
1221merge_config(struct dhcpleased_conf *conf, struct dhcpleased_conf *xconf)
1222{
1223 struct iface_conf *iface_conf;
1224
1225 /* Remove & discard existing interfaces. */
1226 while ((iface_conf = SIMPLEQ_FIRST(&conf->iface_list)((&conf->iface_list)->sqh_first)) != NULL((void*)0)) {
1227 SIMPLEQ_REMOVE_HEAD(&conf->iface_list, entry)do { if (((&conf->iface_list)->sqh_first = (&conf
->iface_list)->sqh_first->entry.sqe_next) == ((void*
)0)) (&conf->iface_list)->sqh_last = &(&conf
->iface_list)->sqh_first; } while (0)
;
1228 free(iface_conf->vc_id);
1229 free(iface_conf->c_id);
1230 free(iface_conf->h_name);
1231 free(iface_conf);
1232 }
1233
1234 /* Add new interfaces. */
1235 SIMPLEQ_CONCAT(&conf->iface_list, &xconf->iface_list)do { if (!((((&xconf->iface_list))->sqh_first) == (
(void*)0))) { *(&conf->iface_list)->sqh_last = (&
xconf->iface_list)->sqh_first; (&conf->iface_list
)->sqh_last = (&xconf->iface_list)->sqh_last; do
{ ((&xconf->iface_list))->sqh_first = ((void*)0); (
(&xconf->iface_list))->sqh_last = &((&xconf
->iface_list))->sqh_first; } while (0); } } while (0)
;
1236
1237 free(xconf);
1238}
1239
1240struct dhcpleased_conf *
1241config_new_empty(void)
1242{
1243 struct dhcpleased_conf *xconf;
1244
1245 xconf = calloc(1, sizeof(*xconf));
1246 if (xconf == NULL((void*)0))
1247 fatal(NULL((void*)0));
1248
1249 SIMPLEQ_INIT(&xconf->iface_list)do { (&xconf->iface_list)->sqh_first = ((void*)0); (
&xconf->iface_list)->sqh_last = &(&xconf->
iface_list)->sqh_first; } while (0)
;
1250
1251 return (xconf);
1252}
1253
1254void
1255config_clear(struct dhcpleased_conf *conf)
1256{
1257 struct dhcpleased_conf *xconf;
1258
1259 /* Merge current config with an empty config. */
1260 xconf = config_new_empty();
1261 merge_config(conf, xconf);
1262
1263 free(conf);
1264}
1265#endif /* SMALL */