File: | src/usr.sbin/rad/rad.c |
Warning: | line 177, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: rad.c,v 1.27 2021/02/27 10:35:20 florian Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2018 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/queue.h> |
23 | #include <sys/socket.h> |
24 | #include <sys/syslog.h> |
25 | #include <sys/uio.h> |
26 | #include <sys/wait.h> |
27 | |
28 | #include <netinet/in.h> |
29 | #include <net/if.h> |
30 | #include <net/route.h> |
31 | #include <netinet/in.h> |
32 | #include <netinet/if_ether.h> |
33 | #include <netinet6/in6_var.h> |
34 | #include <netinet/icmp6.h> |
35 | |
36 | #include <err.h> |
37 | #include <errno(*__errno()).h> |
38 | #include <event.h> |
39 | #include <fcntl.h> |
40 | #include <imsg.h> |
41 | #include <netdb.h> |
42 | #include <pwd.h> |
43 | #include <stdio.h> |
44 | #include <stdlib.h> |
45 | #include <string.h> |
46 | #include <signal.h> |
47 | #include <unistd.h> |
48 | |
49 | #include "log.h" |
50 | #include "rad.h" |
51 | #include "frontend.h" |
52 | #include "engine.h" |
53 | #include "control.h" |
54 | |
55 | enum rad_process { |
56 | PROC_MAIN, |
57 | PROC_ENGINE, |
58 | PROC_FRONTEND |
59 | }; |
60 | |
61 | __dead__attribute__((__noreturn__)) void usage(void); |
62 | __dead__attribute__((__noreturn__)) void main_shutdown(void); |
63 | |
64 | void main_sig_handler(int, short, void *); |
65 | |
66 | static pid_t start_child(enum rad_process, char *, int, int, int); |
67 | |
68 | void main_dispatch_frontend(int, short, void *); |
69 | void main_dispatch_engine(int, short, void *); |
70 | void open_icmp6sock(int); |
71 | |
72 | static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); |
73 | static int main_imsg_send_config(struct rad_conf *); |
74 | |
75 | int main_reload(void); |
76 | int main_sendboth(enum imsg_type, void *, uint16_t); |
77 | |
78 | void in6_prefixlen2mask(struct in6_addr *, int len); |
79 | |
80 | struct rad_conf *main_conf; |
81 | static struct imsgev *iev_frontend; |
82 | static struct imsgev *iev_engine; |
83 | char *conffile; |
84 | pid_t frontend_pid; |
85 | pid_t engine_pid; |
86 | uint32_t cmd_opts; |
87 | |
88 | void |
89 | main_sig_handler(int sig, short event, void *arg) |
90 | { |
91 | /* |
92 | * Normal signal handler rules don't apply because libevent |
93 | * decouples for us. |
94 | */ |
95 | |
96 | switch (sig) { |
97 | case SIGTERM15: |
98 | case SIGINT2: |
99 | main_shutdown(); |
100 | break; |
101 | case SIGHUP1: |
102 | if (main_reload() == -1) |
103 | log_warnx("configuration reload failed"); |
104 | else |
105 | log_debug("configuration reloaded"); |
106 | break; |
107 | default: |
108 | fatalx("unexpected signal"); |
109 | } |
110 | } |
111 | |
112 | __dead__attribute__((__noreturn__)) void |
113 | usage(void) |
114 | { |
115 | extern char *__progname; |
116 | |
117 | fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-f file] [-s socket]\n", |
118 | __progname); |
119 | exit(1); |
120 | } |
121 | |
122 | int |
123 | main(int argc, char *argv[]) |
124 | { |
125 | struct event ev_sigint, ev_sigterm, ev_sighup; |
126 | int ch; |
127 | int debug = 0, engine_flag = 0, frontend_flag = 0; |
128 | char *saved_argv0; |
129 | int pipe_main2frontend[2]; |
130 | int pipe_main2engine[2]; |
131 | int frontend_routesock, rtfilter; |
132 | int rtable_any = RTABLE_ANY0xffffffff; |
133 | int control_fd; |
134 | char *csock; |
135 | |
136 | conffile = _PATH_CONF_FILE"/etc/rad.conf"; |
137 | csock = _PATH_RAD_SOCKET"/var/run/rad.sock"; |
138 | |
139 | log_init(1, LOG_DAEMON(3<<3)); /* Log to stderr until daemonized. */ |
140 | log_setverbose(1); |
141 | |
142 | saved_argv0 = argv[0]; |
143 | if (saved_argv0 == NULL((void *)0)) |
144 | saved_argv0 = "rad"; |
145 | |
146 | while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { |
147 | switch (ch) { |
148 | case 'd': |
149 | debug = 1; |
150 | break; |
151 | case 'E': |
152 | engine_flag = 1; |
153 | break; |
154 | case 'F': |
155 | frontend_flag = 1; |
156 | break; |
157 | case 'f': |
158 | conffile = optarg; |
159 | break; |
160 | case 'n': |
161 | cmd_opts |= OPT_NOACTION0x00000004; |
162 | break; |
163 | case 's': |
164 | csock = optarg; |
165 | break; |
166 | case 'v': |
167 | if (cmd_opts & OPT_VERBOSE0x00000001) |
168 | cmd_opts |= OPT_VERBOSE20x00000002; |
169 | cmd_opts |= OPT_VERBOSE0x00000001; |
170 | break; |
171 | default: |
172 | usage(); |
173 | } |
174 | } |
175 | |
176 | argc -= optind; |
177 | argv += optind; |
Value stored to 'argv' is never read | |
178 | if (argc > 0 || (engine_flag && frontend_flag)) |
179 | usage(); |
180 | |
181 | if (engine_flag) |
182 | engine(debug, cmd_opts & OPT_VERBOSE0x00000001); |
183 | else if (frontend_flag) |
184 | frontend(debug, cmd_opts & OPT_VERBOSE0x00000001); |
185 | |
186 | /* parse config file */ |
187 | if ((main_conf = parse_config(conffile)) == NULL((void *)0)) { |
188 | exit(1); |
189 | } |
190 | |
191 | if (cmd_opts & OPT_NOACTION0x00000004) { |
192 | if (cmd_opts & OPT_VERBOSE0x00000001) |
193 | print_config(main_conf); |
194 | else |
195 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
196 | exit(0); |
197 | } |
198 | |
199 | /* Check for root privileges. */ |
200 | if (geteuid()) |
201 | errx(1, "need root privileges"); |
202 | |
203 | /* Check for assigned daemon user */ |
204 | if (getpwnam(RAD_USER"_rad") == NULL((void *)0)) |
205 | errx(1, "unknown user %s", RAD_USER"_rad"); |
206 | |
207 | log_init(debug, LOG_DAEMON(3<<3)); |
208 | log_setverbose(cmd_opts & OPT_VERBOSE0x00000001); |
209 | |
210 | if (!debug) |
211 | daemon(1, 0); |
212 | |
213 | log_info("startup"); |
214 | |
215 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
216 | PF_UNSPEC0, pipe_main2frontend) == -1) |
217 | fatal("main2frontend socketpair"); |
218 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
219 | PF_UNSPEC0, pipe_main2engine) == -1) |
220 | fatal("main2engine socketpair"); |
221 | |
222 | /* Start children. */ |
223 | engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], |
224 | debug, cmd_opts & OPT_VERBOSE0x00000001); |
225 | frontend_pid = start_child(PROC_FRONTEND, saved_argv0, |
226 | pipe_main2frontend[1], debug, cmd_opts & OPT_VERBOSE0x00000001); |
227 | |
228 | log_procinit("main"); |
229 | |
230 | event_init(); |
231 | |
232 | /* Setup signal handler. */ |
233 | signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void *)0)); |
234 | signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, ( (void *)0)); |
235 | signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void *)0)); |
236 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); |
237 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); |
238 | signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0)); |
239 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); |
240 | |
241 | /* Setup pipes to children. */ |
242 | |
243 | if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL((void *)0) || |
244 | (iev_engine = malloc(sizeof(struct imsgev))) == NULL((void *)0)) |
245 | fatal(NULL((void *)0)); |
246 | imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); |
247 | iev_frontend->handler = main_dispatch_frontend; |
248 | imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); |
249 | iev_engine->handler = main_dispatch_engine; |
250 | |
251 | /* Setup event handlers for pipes to engine & frontend. */ |
252 | iev_frontend->events = EV_READ0x02; |
253 | event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, |
254 | iev_frontend->events, iev_frontend->handler, iev_frontend); |
255 | event_add(&iev_frontend->ev, NULL((void *)0)); |
256 | |
257 | iev_engine->events = EV_READ0x02; |
258 | event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, |
259 | iev_engine->handler, iev_engine); |
260 | event_add(&iev_engine->ev, NULL((void *)0)); |
261 | |
262 | if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) |
263 | fatal("could not establish imsg links"); |
264 | |
265 | if ((frontend_routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000, |
266 | AF_INET624)) == -1) |
267 | fatal("route socket"); |
268 | |
269 | rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_NEWADDR)(1 << (0xc)) | |
270 | ROUTE_FILTER(RTM_DELADDR)(1 << (0xd)) | ROUTE_FILTER(RTM_CHGADDRATTR)(1 << (0x14)); |
271 | if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_MSGFILTER1, |
272 | &rtfilter, sizeof(rtfilter)) == -1) |
273 | fatal("setsockopt(ROUTE_MSGFILTER)"); |
274 | if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_TABLEFILTER2, |
275 | &rtable_any, sizeof(rtable_any)) == -1) |
276 | fatal("setsockopt(ROUTE_TABLEFILTER)"); |
277 | |
278 | if ((control_fd = control_init(csock)) == -1) |
279 | fatalx("control socket setup failed"); |
280 | |
281 | main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, |
282 | NULL((void *)0), 0); |
283 | main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL((void *)0), 0); |
284 | main_imsg_send_config(main_conf); |
285 | |
286 | if (pledge("stdio inet rpath sendfd mcast wroute", NULL((void *)0)) == -1) |
287 | fatal("pledge"); |
288 | |
289 | main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL((void *)0), 0); |
290 | |
291 | event_dispatch(); |
292 | |
293 | main_shutdown(); |
294 | return (0); |
295 | } |
296 | |
297 | __dead__attribute__((__noreturn__)) void |
298 | main_shutdown(void) |
299 | { |
300 | pid_t pid; |
301 | int status; |
302 | |
303 | /* Close pipes. */ |
304 | msgbuf_clear(&iev_frontend->ibuf.w); |
305 | close(iev_frontend->ibuf.fd); |
306 | msgbuf_clear(&iev_engine->ibuf.w); |
307 | close(iev_engine->ibuf.fd); |
308 | |
309 | config_clear(main_conf); |
310 | |
311 | log_debug("waiting for children to terminate"); |
312 | do { |
313 | pid = wait(&status); |
314 | if (pid == -1) { |
315 | if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10) |
316 | fatal("wait"); |
317 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) |
318 | log_warnx("%s terminated; signal %d", |
319 | (pid == engine_pid) ? "engine" : |
320 | "frontend", WTERMSIG(status)(((status) & 0177))); |
321 | } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4)); |
322 | |
323 | free(iev_frontend); |
324 | free(iev_engine); |
325 | |
326 | log_info("terminating"); |
327 | exit(0); |
328 | } |
329 | |
330 | static pid_t |
331 | start_child(enum rad_process p, char *argv0, int fd, int debug, int verbose) |
332 | { |
333 | char *argv[6]; |
334 | int argc = 0; |
335 | pid_t pid; |
336 | |
337 | switch (pid = fork()) { |
338 | case -1: |
339 | fatal("cannot fork"); |
340 | case 0: |
341 | break; |
342 | default: |
343 | close(fd); |
344 | return (pid); |
345 | } |
346 | |
347 | if (fd != 3) { |
348 | if (dup2(fd, 3) == -1) |
349 | fatal("cannot setup imsg fd"); |
350 | } else if (fcntl(fd, F_SETFD2, 0) == -1) |
351 | fatal("cannot setup imsg fd"); |
352 | |
353 | argv[argc++] = argv0; |
354 | switch (p) { |
355 | case PROC_MAIN: |
356 | fatalx("Can not start main process"); |
357 | case PROC_ENGINE: |
358 | argv[argc++] = "-E"; |
359 | break; |
360 | case PROC_FRONTEND: |
361 | argv[argc++] = "-F"; |
362 | break; |
363 | } |
364 | if (debug) |
365 | argv[argc++] = "-d"; |
366 | if (verbose) |
367 | argv[argc++] = "-v"; |
368 | argv[argc++] = NULL((void *)0); |
369 | |
370 | execvp(argv0, argv); |
371 | fatal("execvp"); |
372 | } |
373 | |
374 | void |
375 | main_dispatch_frontend(int fd, short event, void *bula) |
376 | { |
377 | struct imsgev *iev = bula; |
378 | struct imsgbuf *ibuf; |
379 | struct imsg imsg; |
380 | ssize_t n; |
381 | int shut = 0, verbose; |
382 | int rdomain; |
383 | |
384 | ibuf = &iev->ibuf; |
385 | |
386 | if (event & EV_READ0x02) { |
387 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) |
388 | fatal("imsg_read error"); |
389 | if (n == 0) /* Connection closed. */ |
390 | shut = 1; |
391 | } |
392 | if (event & EV_WRITE0x04) { |
393 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) |
394 | fatal("msgbuf_write"); |
395 | if (n == 0) /* Connection closed. */ |
396 | shut = 1; |
397 | } |
398 | |
399 | for (;;) { |
400 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
401 | fatal("imsg_get"); |
402 | if (n == 0) /* No more messages. */ |
403 | break; |
404 | |
405 | switch (imsg.hdr.type) { |
406 | case IMSG_OPEN_ICMP6SOCK: |
407 | log_debug("IMSG_OPEN_ICMP6SOCK"); |
408 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdomain)) |
409 | fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: " |
410 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
411 | memcpy(&rdomain, imsg.data, sizeof(rdomain)); |
412 | open_icmp6sock(rdomain); |
413 | break; |
414 | case IMSG_CTL_RELOAD: |
415 | if (main_reload() == -1) |
416 | log_warnx("configuration reload failed"); |
417 | else |
418 | log_warnx("configuration reloaded"); |
419 | break; |
420 | case IMSG_CTL_LOG_VERBOSE: |
421 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose)) |
422 | fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " |
423 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
424 | memcpy(&verbose, imsg.data, sizeof(verbose)); |
425 | log_setverbose(verbose); |
426 | break; |
427 | default: |
428 | log_debug("%s: error handling imsg %d", __func__, |
429 | imsg.hdr.type); |
430 | break; |
431 | } |
432 | imsg_free(&imsg); |
433 | } |
434 | if (!shut) |
435 | imsg_event_add(iev); |
436 | else { |
437 | /* This pipe is dead. Remove its event handler */ |
438 | event_del(&iev->ev); |
439 | event_loopexit(NULL((void *)0)); |
440 | } |
441 | } |
442 | |
443 | void |
444 | main_dispatch_engine(int fd, short event, void *bula) |
445 | { |
446 | struct imsgev *iev = bula; |
447 | struct imsgbuf *ibuf; |
448 | struct imsg imsg; |
449 | ssize_t n; |
450 | int shut = 0; |
451 | |
452 | ibuf = &iev->ibuf; |
453 | |
454 | if (event & EV_READ0x02) { |
455 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) |
456 | fatal("imsg_read error"); |
457 | if (n == 0) /* Connection closed. */ |
458 | shut = 1; |
459 | } |
460 | if (event & EV_WRITE0x04) { |
461 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) |
462 | fatal("msgbuf_write"); |
463 | if (n == 0) /* Connection closed. */ |
464 | shut = 1; |
465 | } |
466 | |
467 | for (;;) { |
468 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
469 | fatal("imsg_get"); |
470 | if (n == 0) /* No more messages. */ |
471 | break; |
472 | |
473 | switch (imsg.hdr.type) { |
474 | default: |
475 | log_debug("%s: error handling imsg %d", __func__, |
476 | imsg.hdr.type); |
477 | break; |
478 | } |
479 | imsg_free(&imsg); |
480 | } |
481 | if (!shut) |
482 | imsg_event_add(iev); |
483 | else { |
484 | /* This pipe is dead. Remove its event handler. */ |
485 | event_del(&iev->ev); |
486 | event_loopexit(NULL((void *)0)); |
487 | } |
488 | } |
489 | |
490 | int |
491 | main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) |
492 | { |
493 | if (iev_frontend) |
494 | return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, |
495 | datalen)); |
496 | else |
497 | return (-1); |
498 | } |
499 | |
500 | void |
501 | main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) |
502 | { |
503 | if (iev_engine) |
504 | imsg_compose_event(iev_engine, type, 0, pid, -1, data, |
505 | datalen); |
506 | } |
507 | |
508 | void |
509 | imsg_event_add(struct imsgev *iev) |
510 | { |
511 | iev->events = EV_READ0x02; |
512 | if (iev->ibuf.w.queued) |
513 | iev->events |= EV_WRITE0x04; |
514 | |
515 | event_del(&iev->ev); |
516 | event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); |
517 | event_add(&iev->ev, NULL((void *)0)); |
518 | } |
519 | |
520 | int |
521 | imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, |
522 | pid_t pid, int fd, void *data, uint16_t datalen) |
523 | { |
524 | int ret; |
525 | |
526 | if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, |
527 | datalen)) != -1) |
528 | imsg_event_add(iev); |
529 | |
530 | return (ret); |
531 | } |
532 | |
533 | static int |
534 | main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, |
535 | struct imsgbuf *engine_buf) |
536 | { |
537 | int pipe_frontend2engine[2]; |
538 | |
539 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
540 | PF_UNSPEC0, pipe_frontend2engine) == -1) |
541 | return (-1); |
542 | |
543 | if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, |
544 | pipe_frontend2engine[0], NULL((void *)0), 0) == -1) |
545 | return (-1); |
546 | if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, |
547 | pipe_frontend2engine[1], NULL((void *)0), 0) == -1) |
548 | return (-1); |
549 | |
550 | return (0); |
551 | } |
552 | |
553 | int |
554 | main_reload(void) |
555 | { |
556 | struct rad_conf *xconf; |
557 | |
558 | if ((xconf = parse_config(conffile)) == NULL((void *)0)) |
559 | return (-1); |
560 | |
561 | if (main_imsg_send_config(xconf) == -1) |
562 | return (-1); |
563 | |
564 | merge_config(main_conf, xconf); |
565 | |
566 | return (0); |
567 | } |
568 | |
569 | int |
570 | main_imsg_send_config(struct rad_conf *xconf) |
571 | { |
572 | struct ra_iface_conf *ra_iface_conf; |
573 | struct ra_prefix_conf *ra_prefix_conf; |
574 | struct ra_rdnss_conf *ra_rdnss_conf; |
575 | struct ra_dnssl_conf *ra_dnssl_conf; |
576 | |
577 | /* Send fixed part of config to children. */ |
578 | if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) |
579 | return (-1); |
580 | |
581 | /* send global dns options to children */ |
582 | SIMPLEQ_FOREACH(ra_rdnss_conf, &xconf->ra_options.ra_rdnss_list,for((ra_rdnss_conf) = ((&xconf->ra_options.ra_rdnss_list )->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf ) = ((ra_rdnss_conf)->entry.sqe_next)) |
583 | entry)for((ra_rdnss_conf) = ((&xconf->ra_options.ra_rdnss_list )->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf ) = ((ra_rdnss_conf)->entry.sqe_next)) { |
584 | if (main_sendboth(IMSG_RECONF_RA_RDNSS, ra_rdnss_conf, |
585 | sizeof(*ra_rdnss_conf)) == -1) |
586 | return (-1); |
587 | } |
588 | SIMPLEQ_FOREACH(ra_dnssl_conf, &xconf->ra_options.ra_dnssl_list,for((ra_dnssl_conf) = ((&xconf->ra_options.ra_dnssl_list )->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf ) = ((ra_dnssl_conf)->entry.sqe_next)) |
589 | entry)for((ra_dnssl_conf) = ((&xconf->ra_options.ra_dnssl_list )->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf ) = ((ra_dnssl_conf)->entry.sqe_next)) { |
590 | if (main_sendboth(IMSG_RECONF_RA_DNSSL, ra_dnssl_conf, |
591 | sizeof(*ra_dnssl_conf)) == -1) |
592 | return (-1); |
593 | } |
594 | |
595 | /* Send the interface list to children. */ |
596 | SIMPLEQ_FOREACH(ra_iface_conf, &xconf->ra_iface_list, entry)for((ra_iface_conf) = ((&xconf->ra_iface_list)->sqh_first ); (ra_iface_conf) != ((void *)0); (ra_iface_conf) = ((ra_iface_conf )->entry.sqe_next)) { |
597 | if (main_sendboth(IMSG_RECONF_RA_IFACE, ra_iface_conf, |
598 | sizeof(*ra_iface_conf)) == -1) |
599 | return (-1); |
600 | if (ra_iface_conf->autoprefix) { |
601 | if (main_sendboth(IMSG_RECONF_RA_AUTOPREFIX, |
602 | ra_iface_conf->autoprefix, |
603 | sizeof(*ra_iface_conf->autoprefix)) == -1) |
604 | return (-1); |
605 | } |
606 | SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface_conf->ra_prefix_list,for((ra_prefix_conf) = ((&ra_iface_conf->ra_prefix_list )->sqh_first); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf ) = ((ra_prefix_conf)->entry.sqe_next)) |
607 | entry)for((ra_prefix_conf) = ((&ra_iface_conf->ra_prefix_list )->sqh_first); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf ) = ((ra_prefix_conf)->entry.sqe_next)) { |
608 | if (main_sendboth(IMSG_RECONF_RA_PREFIX, |
609 | ra_prefix_conf, sizeof(*ra_prefix_conf)) == -1) |
610 | return (-1); |
611 | } |
612 | SIMPLEQ_FOREACH(ra_rdnss_conf,for((ra_rdnss_conf) = ((&ra_iface_conf->ra_options.ra_rdnss_list )->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf ) = ((ra_rdnss_conf)->entry.sqe_next)) |
613 | &ra_iface_conf->ra_options.ra_rdnss_list, entry)for((ra_rdnss_conf) = ((&ra_iface_conf->ra_options.ra_rdnss_list )->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf ) = ((ra_rdnss_conf)->entry.sqe_next)) { |
614 | if (main_sendboth(IMSG_RECONF_RA_RDNSS, ra_rdnss_conf, |
615 | sizeof(*ra_rdnss_conf)) == -1) |
616 | return (-1); |
617 | } |
618 | SIMPLEQ_FOREACH(ra_dnssl_conf,for((ra_dnssl_conf) = ((&ra_iface_conf->ra_options.ra_dnssl_list )->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf ) = ((ra_dnssl_conf)->entry.sqe_next)) |
619 | &ra_iface_conf->ra_options.ra_dnssl_list, entry)for((ra_dnssl_conf) = ((&ra_iface_conf->ra_options.ra_dnssl_list )->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf ) = ((ra_dnssl_conf)->entry.sqe_next)) { |
620 | if (main_sendboth(IMSG_RECONF_RA_DNSSL, ra_dnssl_conf, |
621 | sizeof(*ra_dnssl_conf)) == -1) |
622 | return (-1); |
623 | } |
624 | } |
625 | |
626 | /* Tell children the revised config is now complete. */ |
627 | if (main_sendboth(IMSG_RECONF_END, NULL((void *)0), 0) == -1) |
628 | return (-1); |
629 | |
630 | return (0); |
631 | } |
632 | |
633 | int |
634 | main_sendboth(enum imsg_type type, void *buf, uint16_t len) |
635 | { |
636 | if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) |
637 | return (-1); |
638 | if (imsg_compose_event(iev_engine, type, 0, 0, -1, buf, len) == -1) |
639 | return (-1); |
640 | return (0); |
641 | } |
642 | |
643 | void |
644 | free_ra_iface_conf(struct ra_iface_conf *ra_iface_conf) |
645 | { |
646 | struct ra_prefix_conf *prefix; |
647 | |
648 | if (!ra_iface_conf) |
649 | return; |
650 | |
651 | free(ra_iface_conf->autoprefix); |
652 | |
653 | while ((prefix = SIMPLEQ_FIRST(&ra_iface_conf->ra_prefix_list)((&ra_iface_conf->ra_prefix_list)->sqh_first)) != |
654 | NULL((void *)0)) { |
655 | SIMPLEQ_REMOVE_HEAD(&ra_iface_conf->ra_prefix_list, entry)do { if (((&ra_iface_conf->ra_prefix_list)->sqh_first = (&ra_iface_conf->ra_prefix_list)->sqh_first-> entry.sqe_next) == ((void *)0)) (&ra_iface_conf->ra_prefix_list )->sqh_last = &(&ra_iface_conf->ra_prefix_list) ->sqh_first; } while (0); |
656 | free(prefix); |
657 | } |
658 | |
659 | free_dns_options(&ra_iface_conf->ra_options); |
660 | |
661 | free(ra_iface_conf); |
662 | } |
663 | |
664 | void |
665 | free_dns_options(struct ra_options_conf *ra_options) |
666 | { |
667 | struct ra_rdnss_conf *ra_rdnss; |
668 | struct ra_dnssl_conf *ra_dnssl; |
669 | |
670 | while ((ra_rdnss = SIMPLEQ_FIRST(&ra_options->ra_rdnss_list)((&ra_options->ra_rdnss_list)->sqh_first)) != NULL((void *)0)) { |
671 | SIMPLEQ_REMOVE_HEAD(&ra_options->ra_rdnss_list, entry)do { if (((&ra_options->ra_rdnss_list)->sqh_first = (&ra_options->ra_rdnss_list)->sqh_first->entry. sqe_next) == ((void *)0)) (&ra_options->ra_rdnss_list) ->sqh_last = &(&ra_options->ra_rdnss_list)-> sqh_first; } while (0); |
672 | free(ra_rdnss); |
673 | } |
674 | ra_options->rdnss_count = 0; |
675 | |
676 | while ((ra_dnssl = SIMPLEQ_FIRST(&ra_options->ra_dnssl_list)((&ra_options->ra_dnssl_list)->sqh_first)) != NULL((void *)0)) { |
677 | SIMPLEQ_REMOVE_HEAD(&ra_options->ra_dnssl_list, entry)do { if (((&ra_options->ra_dnssl_list)->sqh_first = (&ra_options->ra_dnssl_list)->sqh_first->entry. sqe_next) == ((void *)0)) (&ra_options->ra_dnssl_list) ->sqh_last = &(&ra_options->ra_dnssl_list)-> sqh_first; } while (0); |
678 | free(ra_dnssl); |
679 | } |
680 | ra_options->dnssl_len = 0; |
681 | } |
682 | |
683 | void |
684 | merge_config(struct rad_conf *conf, struct rad_conf *xconf) |
685 | { |
686 | struct ra_iface_conf *ra_iface_conf; |
687 | |
688 | /* Remove & discard existing interfaces. */ |
689 | while ((ra_iface_conf = SIMPLEQ_FIRST(&conf->ra_iface_list)((&conf->ra_iface_list)->sqh_first)) != NULL((void *)0)) { |
690 | SIMPLEQ_REMOVE_HEAD(&conf->ra_iface_list, entry)do { if (((&conf->ra_iface_list)->sqh_first = (& conf->ra_iface_list)->sqh_first->entry.sqe_next) == ( (void *)0)) (&conf->ra_iface_list)->sqh_last = & (&conf->ra_iface_list)->sqh_first; } while (0); |
691 | free_ra_iface_conf(ra_iface_conf); |
692 | } |
693 | free_dns_options(&conf->ra_options); |
694 | |
695 | conf->ra_options = xconf->ra_options; |
696 | SIMPLEQ_INIT(&conf->ra_options.ra_rdnss_list)do { (&conf->ra_options.ra_rdnss_list)->sqh_first = ((void *)0); (&conf->ra_options.ra_rdnss_list)->sqh_last = &(&conf->ra_options.ra_rdnss_list)->sqh_first ; } while (0); |
697 | SIMPLEQ_INIT(&conf->ra_options.ra_dnssl_list)do { (&conf->ra_options.ra_dnssl_list)->sqh_first = ((void *)0); (&conf->ra_options.ra_dnssl_list)->sqh_last = &(&conf->ra_options.ra_dnssl_list)->sqh_first ; } while (0); |
698 | |
699 | /* Add new interfaces. */ |
700 | SIMPLEQ_CONCAT(&conf->ra_iface_list, &xconf->ra_iface_list)do { if (!((((&xconf->ra_iface_list))->sqh_first) == ((void *)0))) { *(&conf->ra_iface_list)->sqh_last = (&xconf->ra_iface_list)->sqh_first; (&conf-> ra_iface_list)->sqh_last = (&xconf->ra_iface_list)-> sqh_last; do { ((&xconf->ra_iface_list))->sqh_first = ((void *)0); ((&xconf->ra_iface_list))->sqh_last = &((&xconf->ra_iface_list))->sqh_first; } while (0); } } while (0); |
701 | |
702 | /* Add dns options */ |
703 | SIMPLEQ_CONCAT(&conf->ra_options.ra_rdnss_list,do { if (!((((&xconf->ra_options.ra_rdnss_list))->sqh_first ) == ((void *)0))) { *(&conf->ra_options.ra_rdnss_list )->sqh_last = (&xconf->ra_options.ra_rdnss_list)-> sqh_first; (&conf->ra_options.ra_rdnss_list)->sqh_last = (&xconf->ra_options.ra_rdnss_list)->sqh_last; do { ((&xconf->ra_options.ra_rdnss_list))->sqh_first = ((void *)0); ((&xconf->ra_options.ra_rdnss_list))-> sqh_last = &((&xconf->ra_options.ra_rdnss_list))-> sqh_first; } while (0); } } while (0) |
704 | &xconf->ra_options.ra_rdnss_list)do { if (!((((&xconf->ra_options.ra_rdnss_list))->sqh_first ) == ((void *)0))) { *(&conf->ra_options.ra_rdnss_list )->sqh_last = (&xconf->ra_options.ra_rdnss_list)-> sqh_first; (&conf->ra_options.ra_rdnss_list)->sqh_last = (&xconf->ra_options.ra_rdnss_list)->sqh_last; do { ((&xconf->ra_options.ra_rdnss_list))->sqh_first = ((void *)0); ((&xconf->ra_options.ra_rdnss_list))-> sqh_last = &((&xconf->ra_options.ra_rdnss_list))-> sqh_first; } while (0); } } while (0); |
705 | SIMPLEQ_CONCAT(&conf->ra_options.ra_dnssl_list,do { if (!((((&xconf->ra_options.ra_dnssl_list))->sqh_first ) == ((void *)0))) { *(&conf->ra_options.ra_dnssl_list )->sqh_last = (&xconf->ra_options.ra_dnssl_list)-> sqh_first; (&conf->ra_options.ra_dnssl_list)->sqh_last = (&xconf->ra_options.ra_dnssl_list)->sqh_last; do { ((&xconf->ra_options.ra_dnssl_list))->sqh_first = ((void *)0); ((&xconf->ra_options.ra_dnssl_list))-> sqh_last = &((&xconf->ra_options.ra_dnssl_list))-> sqh_first; } while (0); } } while (0) |
706 | &xconf->ra_options.ra_dnssl_list)do { if (!((((&xconf->ra_options.ra_dnssl_list))->sqh_first ) == ((void *)0))) { *(&conf->ra_options.ra_dnssl_list )->sqh_last = (&xconf->ra_options.ra_dnssl_list)-> sqh_first; (&conf->ra_options.ra_dnssl_list)->sqh_last = (&xconf->ra_options.ra_dnssl_list)->sqh_last; do { ((&xconf->ra_options.ra_dnssl_list))->sqh_first = ((void *)0); ((&xconf->ra_options.ra_dnssl_list))-> sqh_last = &((&xconf->ra_options.ra_dnssl_list))-> sqh_first; } while (0); } } while (0); |
707 | free(xconf); |
708 | } |
709 | |
710 | struct rad_conf * |
711 | config_new_empty(void) |
712 | { |
713 | struct rad_conf *xconf; |
714 | |
715 | xconf = calloc(1, sizeof(*xconf)); |
716 | if (xconf == NULL((void *)0)) |
717 | fatal(NULL((void *)0)); |
718 | |
719 | SIMPLEQ_INIT(&xconf->ra_iface_list)do { (&xconf->ra_iface_list)->sqh_first = ((void *) 0); (&xconf->ra_iface_list)->sqh_last = &(& xconf->ra_iface_list)->sqh_first; } while (0); |
720 | |
721 | xconf->ra_options.dfr = 1; |
722 | xconf->ra_options.cur_hl = 0; |
723 | xconf->ra_options.m_flag = 0; |
724 | xconf->ra_options.o_flag = 0; |
725 | xconf->ra_options.router_lifetime = ADV_DEFAULT_LIFETIME3 * 600; |
726 | xconf->ra_options.reachable_time = 0; |
727 | xconf->ra_options.retrans_timer = 0; |
728 | xconf->ra_options.mtu = 0; |
729 | xconf->ra_options.rdns_lifetime = DEFAULT_RDNS_LIFETIME600 * 1.5; |
730 | SIMPLEQ_INIT(&xconf->ra_options.ra_rdnss_list)do { (&xconf->ra_options.ra_rdnss_list)->sqh_first = ((void *)0); (&xconf->ra_options.ra_rdnss_list)->sqh_last = &(&xconf->ra_options.ra_rdnss_list)->sqh_first ; } while (0); |
731 | SIMPLEQ_INIT(&xconf->ra_options.ra_dnssl_list)do { (&xconf->ra_options.ra_dnssl_list)->sqh_first = ((void *)0); (&xconf->ra_options.ra_dnssl_list)->sqh_last = &(&xconf->ra_options.ra_dnssl_list)->sqh_first ; } while (0); |
732 | |
733 | return (xconf); |
734 | } |
735 | |
736 | void |
737 | config_clear(struct rad_conf *conf) |
738 | { |
739 | struct rad_conf *xconf; |
740 | |
741 | /* Merge current config with an empty config. */ |
742 | xconf = config_new_empty(); |
743 | merge_config(conf, xconf); |
744 | |
745 | free(conf); |
746 | } |
747 | |
748 | void |
749 | mask_prefix(struct in6_addr* in6, int len) |
750 | { |
751 | uint8_t bitmask[8] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe}; |
752 | int i, skip; |
753 | |
754 | if (len < 0 || len > 128) |
755 | fatalx("invalid prefix length: %d", len); |
756 | |
757 | skip = len / 8; |
758 | |
759 | if (skip < 16) |
760 | in6->s6_addr__u6_addr.__u6_addr8[skip] &= bitmask[len % 8]; |
761 | |
762 | for (i = skip + 1; i < 16; i++) |
763 | in6->s6_addr__u6_addr.__u6_addr8[i] = 0; |
764 | } |
765 | |
766 | const char* |
767 | sin6_to_str(struct sockaddr_in6 *sin6) |
768 | { |
769 | static char hbuf[NI_MAXHOST256]; |
770 | int error; |
771 | |
772 | error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf, |
773 | sizeof(hbuf), NULL((void *)0), 0, NI_NUMERICHOST1 | NI_NUMERICSERV2); |
774 | if (error) { |
775 | log_warnx("%s", gai_strerror(error)); |
776 | strlcpy(hbuf, "unknown", sizeof(hbuf)); |
777 | } |
778 | return hbuf; |
779 | } |
780 | |
781 | const char* |
782 | in6_to_str(struct in6_addr *in6) |
783 | { |
784 | |
785 | struct sockaddr_in6 sin6; |
786 | |
787 | memset(&sin6, 0, sizeof(sin6)); |
788 | sin6.sin6_len = sizeof(sin6); |
789 | sin6.sin6_family = AF_INET624; |
790 | sin6.sin6_addr = *in6; |
791 | |
792 | return (sin6_to_str(&sin6)); |
793 | } |
794 | |
795 | void |
796 | open_icmp6sock(int rdomain) |
797 | { |
798 | int icmp6sock, on = 1, off = 0; |
799 | |
800 | log_debug("%s: %d", __func__, rdomain); |
801 | |
802 | if ((icmp6sock = socket(AF_INET624, SOCK_RAW3 | SOCK_CLOEXEC0x8000, |
803 | IPPROTO_ICMPV658)) == -1) |
804 | fatal("ICMPv6 socket"); |
805 | |
806 | if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVPKTINFO36, &on, |
807 | sizeof(on)) == -1) |
808 | fatal("IPV6_RECVPKTINFO"); |
809 | |
810 | if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVHOPLIMIT37, &on, |
811 | sizeof(on)) == -1) |
812 | fatal("IPV6_RECVHOPLIMIT"); |
813 | |
814 | if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_MULTICAST_LOOP11, &off, |
815 | sizeof(off)) == -1) |
816 | fatal("IPV6_RECVHOPLIMIT"); |
817 | |
818 | if (setsockopt(icmp6sock, SOL_SOCKET0xffff, SO_RTABLE0x1021, &rdomain, |
819 | sizeof(rdomain)) == -1) { |
820 | /* we might race against removal of the rdomain */ |
821 | log_warn("setsockopt SO_RTABLE"); |
822 | close(icmp6sock); |
823 | return; |
824 | } |
825 | |
826 | main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain, |
827 | sizeof(rdomain)); |
828 | } |