File: | src/sbin/slaacd/slaacd.c |
Warning: | line 168, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: slaacd.c,v 1.64 2021/08/24 14:56:06 florian Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2017 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/syslog.h> |
26 | #include <sys/sysctl.h> |
27 | #include <sys/uio.h> |
28 | #include <sys/wait.h> |
29 | |
30 | #include <net/if.h> |
31 | #include <net/route.h> |
32 | #include <netinet/in.h> |
33 | #include <netinet/if_ether.h> |
34 | #include <netinet6/in6_var.h> |
35 | #include <netinet/icmp6.h> |
36 | |
37 | #include <err.h> |
38 | #include <errno(*__errno()).h> |
39 | #include <fcntl.h> |
40 | #include <event.h> |
41 | #include <imsg.h> |
42 | #include <netdb.h> |
43 | #include <pwd.h> |
44 | #include <stddef.h> |
45 | #include <stdio.h> |
46 | #include <stdlib.h> |
47 | #include <string.h> |
48 | #include <signal.h> |
49 | #include <unistd.h> |
50 | |
51 | #include "log.h" |
52 | #include "slaacd.h" |
53 | #include "frontend.h" |
54 | #include "engine.h" |
55 | #include "control.h" |
56 | |
57 | enum slaacd_process { |
58 | PROC_MAIN, |
59 | PROC_ENGINE, |
60 | PROC_FRONTEND |
61 | }; |
62 | |
63 | __dead__attribute__((__noreturn__)) void usage(void); |
64 | __dead__attribute__((__noreturn__)) void main_shutdown(void); |
65 | |
66 | void main_sig_handler(int, short, void *); |
67 | |
68 | static pid_t start_child(enum slaacd_process, char *, int, int, int); |
69 | |
70 | void main_dispatch_frontend(int, short, void *); |
71 | void main_dispatch_engine(int, short, void *); |
72 | void open_icmp6sock(int); |
73 | void configure_interface(struct imsg_configure_address *); |
74 | void delete_address(struct imsg_configure_address *); |
75 | void configure_gateway(struct imsg_configure_dfr *, uint8_t); |
76 | void add_gateway(struct imsg_configure_dfr *); |
77 | void delete_gateway(struct imsg_configure_dfr *); |
78 | void send_rdns_proposal(struct imsg_propose_rdns *); |
79 | int get_soiikey(uint8_t *); |
80 | |
81 | static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); |
82 | int main_imsg_compose_frontend(int, int, void *, uint16_t); |
83 | int main_imsg_compose_engine(int, pid_t, void *, uint16_t); |
84 | |
85 | static struct imsgev *iev_frontend; |
86 | static struct imsgev *iev_engine; |
87 | |
88 | pid_t frontend_pid; |
89 | pid_t engine_pid; |
90 | |
91 | int routesock, ioctl_sock, rtm_seq = 0; |
92 | |
93 | void |
94 | main_sig_handler(int sig, short event, void *arg) |
95 | { |
96 | /* |
97 | * Normal signal handler rules don't apply because libevent |
98 | * decouples for us. |
99 | */ |
100 | |
101 | switch (sig) { |
102 | case SIGTERM15: |
103 | case SIGINT2: |
104 | main_shutdown(); |
105 | default: |
106 | fatalx("unexpected signal"); |
107 | } |
108 | } |
109 | |
110 | __dead__attribute__((__noreturn__)) void |
111 | usage(void) |
112 | { |
113 | extern char *__progname; |
114 | |
115 | fprintf(stderr(&__sF[2]), "usage: %s [-dv] [-s socket]\n", |
116 | __progname); |
117 | exit(1); |
118 | } |
119 | |
120 | int |
121 | main(int argc, char *argv[]) |
122 | { |
123 | struct event ev_sigint, ev_sigterm; |
124 | int ch; |
125 | int debug = 0, engine_flag = 0, frontend_flag = 0; |
126 | int verbose = 0; |
127 | char *saved_argv0; |
128 | int pipe_main2frontend[2]; |
129 | int pipe_main2engine[2]; |
130 | int frontend_routesock, rtfilter, lockfd; |
131 | int rtable_any = RTABLE_ANY0xffffffff; |
132 | char *csock = _PATH_SLAACD_SOCKET"/dev/slaacd.sock"; |
133 | struct imsg_propose_rdns rdns; |
134 | #ifndef SMALL |
135 | int control_fd; |
136 | #endif /* SMALL */ |
137 | |
138 | log_init(1, LOG_DAEMON(3<<3)); /* Log to stderr until daemonized. */ |
139 | log_setverbose(1); |
140 | |
141 | saved_argv0 = argv[0]; |
142 | if (saved_argv0 == NULL((void*)0)) |
143 | saved_argv0 = "slaacd"; |
144 | |
145 | while ((ch = getopt(argc, argv, "dEFs:v")) != -1) { |
146 | switch (ch) { |
147 | case 'd': |
148 | debug = 1; |
149 | break; |
150 | case 'E': |
151 | engine_flag = 1; |
152 | break; |
153 | case 'F': |
154 | frontend_flag = 1; |
155 | break; |
156 | case 's': |
157 | csock = optarg; |
158 | break; |
159 | case 'v': |
160 | verbose++; |
161 | break; |
162 | default: |
163 | usage(); |
164 | } |
165 | } |
166 | |
167 | argc -= optind; |
168 | argv += optind; |
Value stored to 'argv' is never read | |
169 | if (argc > 0 || (engine_flag && frontend_flag)) |
170 | usage(); |
171 | |
172 | if (engine_flag) |
173 | engine(debug, verbose); |
174 | else if (frontend_flag) |
175 | frontend(debug, verbose); |
176 | |
177 | /* Check for root privileges. */ |
178 | if (geteuid()) |
179 | errx(1, "need root privileges"); |
180 | |
181 | lockfd = open(_PATH_LOCKFILE"/dev/slaacd.lock", O_CREAT0x0200|O_RDWR0x0002|O_EXLOCK0x0020|O_NONBLOCK0x0004, 0600); |
182 | if (lockfd == -1) |
183 | errx(1, "already running"); |
184 | |
185 | /* Check for assigned daemon user */ |
186 | if (getpwnam(SLAACD_USER"_slaacd") == NULL((void*)0)) |
187 | errx(1, "unknown user %s", SLAACD_USER"_slaacd"); |
188 | |
189 | log_init(debug, LOG_DAEMON(3<<3)); |
190 | log_setverbose(verbose); |
191 | |
192 | if (!debug) |
193 | daemon(0, 0); |
194 | |
195 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
196 | PF_UNSPEC0, pipe_main2frontend) == -1) |
197 | fatal("main2frontend socketpair"); |
198 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
199 | PF_UNSPEC0, pipe_main2engine) == -1) |
200 | fatal("main2engine socketpair"); |
201 | |
202 | /* Start children. */ |
203 | engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], |
204 | debug, verbose); |
205 | frontend_pid = start_child(PROC_FRONTEND, saved_argv0, |
206 | pipe_main2frontend[1], debug, verbose); |
207 | |
208 | log_procinit("main"); |
209 | |
210 | if ((routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000 | |
211 | SOCK_NONBLOCK0x4000, AF_INET624)) == -1) |
212 | fatal("route socket"); |
213 | shutdown(SHUT_RD0, routesock); |
214 | |
215 | event_init(); |
216 | |
217 | /* Setup signal handler. */ |
218 | signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void *)0)); |
219 | signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, ( (void*)0)); |
220 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void*)0)); |
221 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void*)0)); |
222 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); |
223 | signal(SIGHUP1, SIG_IGN(void (*)(int))1); |
224 | |
225 | /* Setup pipes to children. */ |
226 | |
227 | if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL((void*)0) || |
228 | (iev_engine = malloc(sizeof(struct imsgev))) == NULL((void*)0)) |
229 | fatal(NULL((void*)0)); |
230 | imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); |
231 | iev_frontend->handler = main_dispatch_frontend; |
232 | imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); |
233 | iev_engine->handler = main_dispatch_engine; |
234 | |
235 | /* Setup event handlers for pipes to engine & frontend. */ |
236 | iev_frontend->events = EV_READ0x02; |
237 | event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, |
238 | iev_frontend->events, iev_frontend->handler, iev_frontend); |
239 | event_add(&iev_frontend->ev, NULL((void*)0)); |
240 | |
241 | iev_engine->events = EV_READ0x02; |
242 | event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, |
243 | iev_engine->handler, iev_engine); |
244 | event_add(&iev_engine->ev, NULL((void*)0)); |
245 | |
246 | if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) |
247 | fatal("could not establish imsg links"); |
248 | |
249 | if ((ioctl_sock = socket(AF_INET624, SOCK_DGRAM2 | SOCK_CLOEXEC0x8000, 0)) == -1) |
250 | fatal("socket"); |
251 | |
252 | if ((frontend_routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000, |
253 | AF_INET624)) == -1) |
254 | fatal("route socket"); |
255 | |
256 | rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_NEWADDR)(1 << (0xc)) | |
257 | ROUTE_FILTER(RTM_DELADDR)(1 << (0xd)) | ROUTE_FILTER(RTM_DELETE)(1 << (0x2)) | |
258 | ROUTE_FILTER(RTM_CHGADDRATTR)(1 << (0x14)) | ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13)) | |
259 | ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf)); |
260 | if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_MSGFILTER1, |
261 | &rtfilter, sizeof(rtfilter)) == -1) |
262 | fatal("setsockopt(ROUTE_MSGFILTER)"); |
263 | if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_TABLEFILTER2, |
264 | &rtable_any, sizeof(rtable_any)) == -1) |
265 | fatal("setsockopt(ROUTE_TABLEFILTER)"); |
266 | |
267 | #ifndef SMALL |
268 | if ((control_fd = control_init(csock)) == -1) |
269 | warnx("control socket setup failed"); |
270 | #endif /* SMALL */ |
271 | |
272 | if (pledge("stdio inet sendfd wroute", NULL((void*)0)) == -1) |
273 | fatal("pledge"); |
274 | |
275 | main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL((void*)0), 0); |
276 | |
277 | #ifndef SMALL |
278 | if (control_fd != -1) |
279 | main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL((void*)0), 0); |
280 | #endif /* SMALL */ |
281 | |
282 | main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL((void*)0), 0); |
283 | |
284 | /* we are taking over, clear all previos slaac proposals */ |
285 | memset(&rdns, 0, sizeof(rdns)); |
286 | rdns.if_index = 0; |
287 | rdns.rdns_count = 0; |
288 | send_rdns_proposal(&rdns); |
289 | |
290 | event_dispatch(); |
291 | |
292 | main_shutdown(); |
293 | return (0); |
294 | } |
295 | |
296 | __dead__attribute__((__noreturn__)) void |
297 | main_shutdown(void) |
298 | { |
299 | pid_t pid; |
300 | int status; |
301 | |
302 | /* Close pipes. */ |
303 | msgbuf_clear(&iev_frontend->ibuf.w); |
304 | close(iev_frontend->ibuf.fd); |
305 | msgbuf_clear(&iev_engine->ibuf.w); |
306 | close(iev_engine->ibuf.fd); |
307 | |
308 | log_debug("waiting for children to terminate"); |
309 | do { |
310 | pid = wait(&status); |
311 | if (pid == -1) { |
312 | if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10) |
313 | fatal("wait"); |
314 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) |
315 | log_warnx("%s terminated; signal %d", |
316 | (pid == engine_pid) ? "engine" : |
317 | "frontend", WTERMSIG(status)(((status) & 0177))); |
318 | } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4)); |
319 | |
320 | free(iev_frontend); |
321 | free(iev_engine); |
322 | |
323 | log_info("terminating"); |
324 | exit(0); |
325 | } |
326 | |
327 | static pid_t |
328 | start_child(enum slaacd_process p, char *argv0, int fd, int debug, int verbose) |
329 | { |
330 | char *argv[7]; |
331 | int argc = 0; |
332 | pid_t pid; |
333 | |
334 | switch (pid = fork()) { |
335 | case -1: |
336 | fatal("cannot fork"); |
337 | case 0: |
338 | break; |
339 | default: |
340 | close(fd); |
341 | return (pid); |
342 | } |
343 | |
344 | if (fd != 3) { |
345 | if (dup2(fd, 3) == -1) |
346 | fatal("cannot setup imsg fd"); |
347 | } else if (fcntl(fd, F_SETFD2, 0) == -1) |
348 | fatal("cannot setup imsg fd"); |
349 | |
350 | argv[argc++] = argv0; |
351 | switch (p) { |
352 | case PROC_MAIN: |
353 | fatalx("Can not start main process"); |
354 | case PROC_ENGINE: |
355 | argv[argc++] = "-E"; |
356 | break; |
357 | case PROC_FRONTEND: |
358 | argv[argc++] = "-F"; |
359 | break; |
360 | } |
361 | if (debug) |
362 | argv[argc++] = "-d"; |
363 | if (verbose) |
364 | argv[argc++] = "-v"; |
365 | if (verbose > 1) |
366 | argv[argc++] = "-v"; |
367 | argv[argc++] = NULL((void*)0); |
368 | |
369 | execvp(argv0, argv); |
370 | fatal("execvp"); |
371 | } |
372 | |
373 | void |
374 | main_dispatch_frontend(int fd, short event, void *bula) |
375 | { |
376 | struct imsgev *iev = bula; |
377 | struct imsgbuf *ibuf; |
378 | struct imsg imsg; |
379 | struct imsg_ifinfo imsg_ifinfo; |
380 | ssize_t n; |
381 | int shut = 0; |
382 | int rdomain; |
383 | #ifndef SMALL |
384 | struct imsg_addrinfo imsg_addrinfo; |
385 | int verbose; |
386 | #endif /* SMALL */ |
387 | |
388 | ibuf = &iev->ibuf; |
389 | |
390 | if (event & EV_READ0x02) { |
391 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) |
392 | fatal("imsg_read error"); |
393 | if (n == 0) /* Connection closed. */ |
394 | shut = 1; |
395 | } |
396 | if (event & EV_WRITE0x04) { |
397 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) |
398 | fatal("msgbuf_write"); |
399 | if (n == 0) /* Connection closed. */ |
400 | shut = 1; |
401 | } |
402 | |
403 | for (;;) { |
404 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
405 | fatal("imsg_get"); |
406 | if (n == 0) /* No more messages. */ |
407 | break; |
408 | |
409 | switch (imsg.hdr.type) { |
410 | case IMSG_OPEN_ICMP6SOCK: |
411 | log_debug("IMSG_OPEN_ICMP6SOCK"); |
412 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdomain)) |
413 | fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: " |
414 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
415 | memcpy(&rdomain, imsg.data, sizeof(rdomain)); |
416 | open_icmp6sock(rdomain); |
417 | break; |
418 | #ifndef SMALL |
419 | case IMSG_CTL_LOG_VERBOSE: |
420 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose)) |
421 | fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " |
422 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
423 | memcpy(&verbose, imsg.data, sizeof(verbose)); |
424 | log_setverbose(verbose); |
425 | break; |
426 | case IMSG_UPDATE_ADDRESS: |
427 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_addrinfo)) |
428 | fatalx("%s: IMSG_UPDATE_ADDRESS wrong length: " |
429 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
430 | memcpy(&imsg_addrinfo, imsg.data, |
431 | sizeof(imsg_addrinfo)); |
432 | main_imsg_compose_engine(IMSG_UPDATE_ADDRESS, 0, |
433 | &imsg_addrinfo, sizeof(imsg_addrinfo)); |
434 | break; |
435 | #endif /* SMALL */ |
436 | case IMSG_UPDATE_IF: |
437 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_ifinfo)) |
438 | fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", |
439 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
440 | memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); |
441 | if (get_soiikey(imsg_ifinfo.soiikey) == -1) |
442 | log_warn("get_soiikey"); |
443 | else |
444 | main_imsg_compose_engine(IMSG_UPDATE_IF, 0, |
445 | &imsg_ifinfo, sizeof(imsg_ifinfo)); |
446 | break; |
447 | default: |
448 | log_debug("%s: error handling imsg %d", __func__, |
449 | imsg.hdr.type); |
450 | break; |
451 | } |
452 | imsg_free(&imsg); |
453 | } |
454 | if (!shut) |
455 | imsg_event_add(iev); |
456 | else { |
457 | /* This pipe is dead. Remove its event handler */ |
458 | event_del(&iev->ev); |
459 | event_loopexit(NULL((void*)0)); |
460 | } |
461 | } |
462 | |
463 | void |
464 | main_dispatch_engine(int fd, short event, void *bula) |
465 | { |
466 | struct imsgev *iev = bula; |
467 | struct imsgbuf *ibuf; |
468 | struct imsg imsg; |
469 | struct imsg_configure_address address; |
470 | struct imsg_configure_dfr dfr; |
471 | struct imsg_propose_rdns rdns; |
472 | ssize_t n; |
473 | int shut = 0; |
474 | |
475 | ibuf = &iev->ibuf; |
476 | |
477 | if (event & EV_READ0x02) { |
478 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) |
479 | fatal("imsg_read error"); |
480 | if (n == 0) /* Connection closed. */ |
481 | shut = 1; |
482 | } |
483 | if (event & EV_WRITE0x04) { |
484 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) |
485 | fatal("msgbuf_write"); |
486 | if (n == 0) /* Connection closed. */ |
487 | shut = 1; |
488 | } |
489 | |
490 | for (;;) { |
491 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
492 | fatal("imsg_get"); |
493 | if (n == 0) /* No more messages. */ |
494 | break; |
495 | |
496 | switch (imsg.hdr.type) { |
497 | case IMSG_CONFIGURE_ADDRESS: |
498 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(address)) |
499 | fatalx("%s: IMSG_CONFIGURE_ADDRESS wrong " |
500 | "length: %lu", __func__, |
501 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
502 | memcpy(&address, imsg.data, sizeof(address)); |
503 | configure_interface(&address); |
504 | break; |
505 | case IMSG_WITHDRAW_ADDRESS: |
506 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(address)) |
507 | fatalx("%s: IMSG_WITHDRAW_ADDRESS wrong " |
508 | "length: %lu", __func__, |
509 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
510 | memcpy(&address, imsg.data, sizeof(address)); |
511 | delete_address(&address); |
512 | break; |
513 | case IMSG_CONFIGURE_DFR: |
514 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(dfr)) |
515 | fatalx("%s: IMSG_CONFIGURE_DFR wrong " |
516 | "length: %lu", __func__, |
517 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
518 | memcpy(&dfr, imsg.data, sizeof(dfr)); |
519 | add_gateway(&dfr); |
520 | break; |
521 | case IMSG_WITHDRAW_DFR: |
522 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(dfr)) |
523 | fatalx("%s: IMSG_WITHDRAW_DFR wrong " |
524 | "length: %lu", __func__, |
525 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
526 | memcpy(&dfr, imsg.data, sizeof(dfr)); |
527 | delete_gateway(&dfr); |
528 | break; |
529 | case IMSG_PROPOSE_RDNS: |
530 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdns)) |
531 | fatalx("%s: IMSG_PROPOSE_RDNS wrong " |
532 | "length: %lu", __func__, |
533 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); |
534 | memcpy(&rdns, imsg.data, sizeof(rdns)); |
535 | if ((2 + rdns.rdns_count * sizeof(struct in6_addr)) > |
536 | sizeof(struct sockaddr_rtdns)) |
537 | fatalx("%s: rdns_count too big: %d", __func__, |
538 | rdns.rdns_count); |
539 | send_rdns_proposal(&rdns); |
540 | break; |
541 | default: |
542 | log_debug("%s: error handling imsg %d", __func__, |
543 | imsg.hdr.type); |
544 | break; |
545 | } |
546 | imsg_free(&imsg); |
547 | } |
548 | if (!shut) |
549 | imsg_event_add(iev); |
550 | else { |
551 | /* This pipe is dead. Remove its event handler. */ |
552 | event_del(&iev->ev); |
553 | event_loopexit(NULL((void*)0)); |
554 | } |
555 | } |
556 | |
557 | int |
558 | main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) |
559 | { |
560 | if (iev_frontend) |
561 | return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, |
562 | datalen)); |
563 | else |
564 | return (-1); |
565 | } |
566 | |
567 | int |
568 | main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) |
569 | { |
570 | if (iev_engine) |
571 | return(imsg_compose_event(iev_engine, type, 0, pid, -1, data, |
572 | datalen)); |
573 | else |
574 | return (-1); |
575 | } |
576 | |
577 | void |
578 | imsg_event_add(struct imsgev *iev) |
579 | { |
580 | iev->events = EV_READ0x02; |
581 | if (iev->ibuf.w.queued) |
582 | iev->events |= EV_WRITE0x04; |
583 | |
584 | event_del(&iev->ev); |
585 | event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); |
586 | event_add(&iev->ev, NULL((void*)0)); |
587 | } |
588 | |
589 | int |
590 | imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, |
591 | pid_t pid, int fd, void *data, uint16_t datalen) |
592 | { |
593 | int ret; |
594 | |
595 | if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, |
596 | datalen)) != -1) |
597 | imsg_event_add(iev); |
598 | |
599 | return (ret); |
600 | } |
601 | |
602 | static int |
603 | main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, |
604 | struct imsgbuf *engine_buf) |
605 | { |
606 | int pipe_frontend2engine[2]; |
607 | |
608 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
609 | PF_UNSPEC0, pipe_frontend2engine) == -1) |
610 | return (-1); |
611 | |
612 | if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, |
613 | pipe_frontend2engine[0], NULL((void*)0), 0) == -1) |
614 | return (-1); |
615 | imsg_flush(frontend_buf); |
616 | if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, |
617 | pipe_frontend2engine[1], NULL((void*)0), 0) == -1) |
618 | return (-1); |
619 | imsg_flush(engine_buf); |
620 | return (0); |
621 | } |
622 | |
623 | void |
624 | configure_interface(struct imsg_configure_address *address) |
625 | { |
626 | |
627 | struct in6_aliasreq in6_addreq; |
628 | time_t t; |
629 | char *if_name; |
630 | |
631 | memset(&in6_addreq, 0, sizeof(in6_addreq)); |
632 | |
633 | if_name = if_indextoname(address->if_index, in6_addreq.ifra_name); |
634 | if (if_name == NULL((void*)0)) { |
635 | log_warnx("%s: cannot find interface %d", __func__, |
636 | address->if_index); |
637 | return; |
638 | } |
639 | |
640 | memcpy(&in6_addreq.ifra_addrifra_ifrau.ifrau_addr, &address->addr, |
641 | sizeof(in6_addreq.ifra_addrifra_ifrau.ifrau_addr)); |
642 | memcpy(&in6_addreq.ifra_prefixmask.sin6_addr, &address->mask, |
643 | sizeof(in6_addreq.ifra_prefixmask.sin6_addr)); |
644 | in6_addreq.ifra_prefixmask.sin6_family = AF_INET624; |
645 | in6_addreq.ifra_prefixmask.sin6_len = |
646 | sizeof(in6_addreq.ifra_prefixmask); |
647 | |
648 | t = time(NULL((void*)0)); |
649 | |
650 | in6_addreq.ifra_lifetime.ia6t_expire = t + address->vltime; |
651 | in6_addreq.ifra_lifetime.ia6t_vltime = address->vltime; |
652 | |
653 | in6_addreq.ifra_lifetime.ia6t_preferred = t + address->pltime; |
654 | in6_addreq.ifra_lifetime.ia6t_pltime = address->pltime; |
655 | |
656 | in6_addreq.ifra_flags |= IN6_IFF_AUTOCONF0x40; |
657 | |
658 | if (address->temporary) |
659 | in6_addreq.ifra_flags |= IN6_IFF_TEMPORARY0x80; |
660 | |
661 | log_debug("%s: %s", __func__, if_name); |
662 | |
663 | if (ioctl(ioctl_sock, SIOCAIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_aliasreq) & 0x1fff) << 16) | ((('i')) << 8) | ((26))), &in6_addreq) == -1) |
664 | log_warn("SIOCAIFADDR_IN6"); |
665 | |
666 | if (address->mtu) { |
667 | struct ifreq ifr; |
668 | |
669 | strlcpy(ifr.ifr_name, in6_addreq.ifra_name, |
670 | sizeof(ifr.ifr_name)); |
671 | ifr.ifr_mtuifr_ifru.ifru_metric = address->mtu; |
672 | log_debug("Setting MTU to %d", ifr.ifr_mtuifr_ifru.ifru_metric); |
673 | |
674 | if (ioctl(ioctl_sock, SIOCSIFMTU((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((127))), &ifr) == -1) |
675 | log_warn("failed to set MTU"); |
676 | } |
677 | } |
678 | |
679 | void |
680 | delete_address(struct imsg_configure_address *address) |
681 | { |
682 | |
683 | struct in6_ifreq in6_ridreq; |
684 | char *if_name; |
685 | |
686 | memset(&in6_ridreq, 0, sizeof(in6_ridreq)); |
687 | |
688 | if_name = if_indextoname(address->if_index, in6_ridreq.ifr_name); |
689 | if (if_name == NULL((void*)0)) { |
690 | log_warnx("%s: cannot find interface %d", __func__, |
691 | address->if_index); |
692 | return; |
693 | } |
694 | |
695 | memcpy(&in6_ridreq.ifr_addrifr_ifru.ifru_addr, &address->addr, |
696 | sizeof(in6_ridreq.ifr_addrifr_ifru.ifru_addr)); |
697 | |
698 | log_debug("%s: %s", __func__, if_name); |
699 | |
700 | if (ioctl(ioctl_sock, SIOCDIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((25))), &in6_ridreq) == -1) |
701 | log_warn("%s: cannot remove address", __func__); |
702 | |
703 | } |
704 | |
705 | #define ROUNDUP(a)(((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) \ |
706 | (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) |
707 | |
708 | void |
709 | configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type) |
710 | { |
711 | struct rt_msghdr rtm; |
712 | struct sockaddr_rtlabel rl; |
713 | struct sockaddr_in6 dst, gw, mask; |
714 | struct iovec iov[10]; |
715 | long pad = 0; |
716 | int iovcnt = 0, padlen; |
717 | |
718 | memset(&rtm, 0, sizeof(rtm)); |
719 | |
720 | rtm.rtm_version = RTM_VERSION5; |
721 | rtm.rtm_type = rtm_type; |
722 | rtm.rtm_msglen = sizeof(rtm); |
723 | rtm.rtm_tableid = dfr->rdomain; |
724 | rtm.rtm_index = dfr->if_index; |
725 | rtm.rtm_seq = ++rtm_seq; |
726 | rtm.rtm_priority = RTP_NONE0; |
727 | rtm.rtm_addrs = RTA_DST0x1 | RTA_GATEWAY0x2 | RTA_NETMASK0x4 | RTA_LABEL0x400; |
728 | rtm.rtm_flags = RTF_UP0x1 | RTF_GATEWAY0x2 | RTF_STATIC0x800 | RTF_MPATH0x40000; |
729 | |
730 | iov[iovcnt].iov_base = &rtm; |
731 | iov[iovcnt++].iov_len = sizeof(rtm); |
732 | |
733 | memset(&dst, 0, sizeof(mask)); |
734 | dst.sin6_family = AF_INET624; |
735 | dst.sin6_len = sizeof(struct sockaddr_in6); |
736 | |
737 | iov[iovcnt].iov_base = &dst; |
738 | iov[iovcnt++].iov_len = sizeof(dst); |
739 | rtm.rtm_msglen += sizeof(dst); |
740 | padlen = ROUNDUP(sizeof(dst))(((sizeof(dst)) & (sizeof(long) - 1)) ? (1 + ((sizeof(dst )) | (sizeof(long) - 1))) : (sizeof(dst))) - sizeof(dst); |
741 | if (padlen > 0) { |
742 | iov[iovcnt].iov_base = &pad; |
743 | iov[iovcnt++].iov_len = padlen; |
744 | rtm.rtm_msglen += padlen; |
745 | } |
746 | |
747 | memcpy(&gw, &dfr->addr, sizeof(gw)); |
748 | #ifdef __KAME__ |
749 | /* from route(8) getaddr()*/ |
750 | *(u_int16_t *)& gw.sin6_addr.s6_addr__u6_addr.__u6_addr8[2] = htons(gw.sin6_scope_id)(__uint16_t)(__builtin_constant_p(gw.sin6_scope_id) ? (__uint16_t )(((__uint16_t)(gw.sin6_scope_id) & 0xffU) << 8 | ( (__uint16_t)(gw.sin6_scope_id) & 0xff00U) >> 8) : __swap16md (gw.sin6_scope_id)); |
751 | gw.sin6_scope_id = 0; |
752 | #endif |
753 | iov[iovcnt].iov_base = &gw; |
754 | iov[iovcnt++].iov_len = sizeof(gw); |
755 | rtm.rtm_msglen += sizeof(gw); |
756 | padlen = ROUNDUP(sizeof(gw))(((sizeof(gw)) & (sizeof(long) - 1)) ? (1 + ((sizeof(gw)) | (sizeof(long) - 1))) : (sizeof(gw))) - sizeof(gw); |
757 | if (padlen > 0) { |
758 | iov[iovcnt].iov_base = &pad; |
759 | iov[iovcnt++].iov_len = padlen; |
760 | rtm.rtm_msglen += padlen; |
761 | } |
762 | |
763 | memset(&mask, 0, sizeof(mask)); |
764 | mask.sin6_family = AF_INET624; |
765 | mask.sin6_len = sizeof(struct sockaddr_in6); |
766 | iov[iovcnt].iov_base = &mask; |
767 | iov[iovcnt++].iov_len = sizeof(mask); |
768 | rtm.rtm_msglen += sizeof(mask); |
769 | padlen = ROUNDUP(sizeof(mask))(((sizeof(mask)) & (sizeof(long) - 1)) ? (1 + ((sizeof(mask )) | (sizeof(long) - 1))) : (sizeof(mask))) - sizeof(mask); |
770 | if (padlen > 0) { |
771 | iov[iovcnt].iov_base = &pad; |
772 | iov[iovcnt++].iov_len = padlen; |
773 | rtm.rtm_msglen += padlen; |
774 | } |
775 | |
776 | memset(&rl, 0, sizeof(rl)); |
777 | rl.sr_len = sizeof(rl); |
778 | rl.sr_family = AF_UNSPEC0; |
779 | (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s", |
780 | SLAACD_RTA_LABEL"slaacd"); |
781 | iov[iovcnt].iov_base = &rl; |
782 | iov[iovcnt++].iov_len = sizeof(rl); |
783 | rtm.rtm_msglen += sizeof(rl); |
784 | padlen = ROUNDUP(sizeof(rl))(((sizeof(rl)) & (sizeof(long) - 1)) ? (1 + ((sizeof(rl)) | (sizeof(long) - 1))) : (sizeof(rl))) - sizeof(rl); |
785 | if (padlen > 0) { |
786 | iov[iovcnt].iov_base = &pad; |
787 | iov[iovcnt++].iov_len = padlen; |
788 | rtm.rtm_msglen += padlen; |
789 | } |
790 | |
791 | if (writev(routesock, iov, iovcnt) == -1) |
792 | log_warn("failed to send route message"); |
793 | } |
794 | |
795 | void |
796 | add_gateway(struct imsg_configure_dfr *dfr) |
797 | { |
798 | configure_gateway(dfr, RTM_ADD0x1); |
799 | } |
800 | |
801 | void |
802 | delete_gateway(struct imsg_configure_dfr *dfr) |
803 | { |
804 | configure_gateway(dfr, RTM_DELETE0x2); |
805 | } |
806 | |
807 | void |
808 | send_rdns_proposal(struct imsg_propose_rdns *rdns) |
809 | { |
810 | struct rt_msghdr rtm; |
811 | struct sockaddr_rtdns rtdns; |
812 | struct iovec iov[3]; |
813 | long pad = 0; |
814 | int iovcnt = 0, padlen; |
815 | |
816 | memset(&rtm, 0, sizeof(rtm)); |
817 | |
818 | rtm.rtm_version = RTM_VERSION5; |
819 | rtm.rtm_type = RTM_PROPOSAL0x13; |
820 | rtm.rtm_msglen = sizeof(rtm); |
821 | rtm.rtm_tableid = rdns->rdomain; |
822 | rtm.rtm_index = rdns->if_index; |
823 | rtm.rtm_seq = ++rtm_seq; |
824 | rtm.rtm_priority = RTP_PROPOSAL_SLAAC59; |
825 | rtm.rtm_addrs = RTA_DNS0x1000; |
826 | rtm.rtm_flags = RTF_UP0x1; |
827 | |
828 | iov[iovcnt].iov_base = &rtm; |
829 | iov[iovcnt++].iov_len = sizeof(rtm); |
830 | |
831 | memset(&rtdns, 0, sizeof(rtdns)); |
832 | rtdns.sr_family = AF_INET624; |
833 | rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in6_addr); |
834 | memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns)); |
835 | |
836 | iov[iovcnt].iov_base = &rtdns; |
837 | iov[iovcnt++].iov_len = sizeof(rtdns); |
838 | rtm.rtm_msglen += sizeof(rtdns); |
839 | padlen = ROUNDUP(sizeof(rtdns))(((sizeof(rtdns)) & (sizeof(long) - 1)) ? (1 + ((sizeof(rtdns )) | (sizeof(long) - 1))) : (sizeof(rtdns))) - sizeof(rtdns); |
840 | if (padlen > 0) { |
841 | iov[iovcnt].iov_base = &pad; |
842 | iov[iovcnt++].iov_len = padlen; |
843 | rtm.rtm_msglen += padlen; |
844 | } |
845 | |
846 | if (writev(routesock, iov, iovcnt) == -1) |
847 | log_warn("failed to send route message"); |
848 | } |
849 | |
850 | #ifndef SMALL |
851 | const char* |
852 | sin6_to_str(struct sockaddr_in6 *sin6) |
853 | { |
854 | static char hbuf[NI_MAXHOST256]; |
855 | int error; |
856 | |
857 | error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf, |
858 | sizeof(hbuf), NULL((void*)0), 0, NI_NUMERICHOST1 | NI_NUMERICSERV2); |
859 | if (error) { |
860 | log_warnx("%s", gai_strerror(error)); |
861 | strlcpy(hbuf, "unknown", sizeof(hbuf)); |
862 | } |
863 | return hbuf; |
864 | } |
865 | #endif /* SMALL */ |
866 | |
867 | int |
868 | get_soiikey(uint8_t *key) |
869 | { |
870 | int mib[4] = {CTL_NET4, PF_INET624, IPPROTO_IPV641, IPV6CTL_SOIIKEY54}; |
871 | size_t size = SLAACD_SOIIKEY_LEN16; |
872 | |
873 | return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL((void*)0), 0); |
874 | } |
875 | |
876 | void |
877 | open_icmp6sock(int rdomain) |
878 | { |
879 | int icmp6sock, on = 1; |
880 | |
881 | log_debug("%s: %d", __func__, rdomain); |
882 | |
883 | if ((icmp6sock = socket(AF_INET624, SOCK_RAW3 | SOCK_CLOEXEC0x8000, |
884 | IPPROTO_ICMPV658)) == -1) |
885 | fatal("ICMPv6 socket"); |
886 | |
887 | if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVPKTINFO36, &on, |
888 | sizeof(on)) == -1) |
889 | fatal("IPV6_RECVPKTINFO"); |
890 | |
891 | if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVHOPLIMIT37, &on, |
892 | sizeof(on)) == -1) |
893 | fatal("IPV6_RECVHOPLIMIT"); |
894 | |
895 | if (setsockopt(icmp6sock, SOL_SOCKET0xffff, SO_RTABLE0x1021, &rdomain, |
896 | sizeof(rdomain)) == -1) { |
897 | /* we might race against removal of the rdomain */ |
898 | log_warn("setsockopt SO_RTABLE"); |
899 | close(icmp6sock); |
900 | return; |
901 | } |
902 | |
903 | main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain, |
904 | sizeof(rdomain)); |
905 | } |