File: | src/sbin/dhcpleased/dhcpleased.c |
Warning: | line 194, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
61 | enum 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 | |
70 | void main_sig_handler(int, short, void *); |
71 | |
72 | static pid_t start_child(enum dhcpleased_process, char *, int, int, int); |
73 | |
74 | void main_dispatch_frontend(int, short, void *); |
75 | void main_dispatch_engine(int, short, void *); |
76 | void open_bpfsock(uint32_t); |
77 | void configure_interface(struct imsg_configure_interface *); |
78 | void deconfigure_interface(struct imsg_configure_interface *); |
79 | void propose_rdns(struct imsg_propose_rdns *); |
80 | void configure_routes(uint8_t, struct imsg_configure_interface *); |
81 | void configure_route(uint8_t, uint32_t, int, struct sockaddr_in *, struct |
82 | sockaddr_in *, struct sockaddr_in *, struct sockaddr_in *, int); |
83 | void read_lease_file(struct imsg_ifinfo *); |
84 | |
85 | static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); |
86 | int main_imsg_compose_frontend(int, int, void *, uint16_t); |
87 | int main_imsg_compose_engine(int, int, void *, uint16_t); |
88 | |
89 | #ifndef SMALL |
90 | int main_imsg_send_config(struct dhcpleased_conf *); |
91 | #endif /* SMALL */ |
92 | int main_reload(void); |
93 | |
94 | static struct imsgev *iev_frontend; |
95 | static struct imsgev *iev_engine; |
96 | |
97 | #ifndef SMALL |
98 | struct dhcpleased_conf *main_conf; |
99 | #endif |
100 | char *conffile; |
101 | pid_t frontend_pid; |
102 | pid_t engine_pid; |
103 | |
104 | int routesock, ioctl_sock, rtm_seq, no_lease_files; |
105 | |
106 | void |
107 | main_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 |
132 | usage(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 | |
141 | int |
142 | main(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 |
349 | main_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 | |
383 | static pid_t |
384 | start_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 | |
430 | void |
431 | main_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 | |
513 | void |
514 | main_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 | |
630 | int |
631 | main_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 | |
640 | int |
641 | main_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 | |
650 | void |
651 | imsg_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 | |
662 | int |
663 | imsg_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 | |
675 | static int |
676 | main_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 |
697 | int |
698 | main_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 | |
713 | int |
714 | main_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 | |
748 | void |
749 | configure_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 | |
912 | void |
913 | deconfigure_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 | |
942 | void |
943 | configure_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)) |
1015 | void |
1016 | configure_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 |
1108 | const char* |
1109 | sin_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 | |
1124 | void |
1125 | open_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 | |
1142 | void |
1143 | propose_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 | |
1185 | void |
1186 | read_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 |
1220 | void |
1221 | merge_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 | |
1240 | struct dhcpleased_conf * |
1241 | config_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 | |
1254 | void |
1255 | config_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 */ |