File: | src/usr.sbin/rad/engine.c |
Warning: | line 365, column 35 Access to field 'autoprefix' results in a dereference of a null pointer (loaded from variable 'ra_iface_conf') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: engine.c,v 1.22 2023/12/14 11:09:34 claudio Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2018 Florian Obser <florian@openbsd.org> | |||
5 | * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> | |||
6 | * Copyright (c) 2004 Esben Norby <norby@openbsd.org> | |||
7 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |||
8 | * | |||
9 | * Permission to use, copy, modify, and distribute this software for any | |||
10 | * purpose with or without fee is hereby granted, provided that the above | |||
11 | * copyright notice and this permission notice appear in all copies. | |||
12 | * | |||
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
20 | */ | |||
21 | ||||
22 | #include <sys/types.h> | |||
23 | #include <sys/queue.h> | |||
24 | #include <sys/socket.h> | |||
25 | #include <sys/syslog.h> | |||
26 | #include <sys/time.h> | |||
27 | #include <sys/uio.h> | |||
28 | ||||
29 | #include <netinet/in.h> | |||
30 | #include <net/if.h> | |||
31 | #include <arpa/inet.h> | |||
32 | #include <netinet/icmp6.h> | |||
33 | ||||
34 | #include <errno(*__errno()).h> | |||
35 | #include <event.h> | |||
36 | #include <imsg.h> | |||
37 | #include <pwd.h> | |||
38 | #include <signal.h> | |||
39 | #include <stdlib.h> | |||
40 | #include <string.h> | |||
41 | #include <time.h> | |||
42 | #include <unistd.h> | |||
43 | ||||
44 | #include "log.h" | |||
45 | #include "rad.h" | |||
46 | #include "engine.h" | |||
47 | ||||
48 | struct engine_iface { | |||
49 | TAILQ_ENTRY(engine_iface)struct { struct engine_iface *tqe_next; struct engine_iface * *tqe_prev; } entry; | |||
50 | struct event timer; | |||
51 | struct timespec last_ra; | |||
52 | uint32_t if_index; | |||
53 | int ras_delayed; | |||
54 | }; | |||
55 | ||||
56 | TAILQ_HEAD(, engine_iface)struct { struct engine_iface *tqh_first; struct engine_iface * *tqh_last; } engine_interfaces; | |||
57 | ||||
58 | ||||
59 | __dead__attribute__((__noreturn__)) void engine_shutdown(void); | |||
60 | void engine_sig_handler(int sig, short, void *); | |||
61 | void engine_dispatch_frontend(int, short, void *); | |||
62 | void engine_dispatch_main(int, short, void *); | |||
63 | void parse_ra_rs(struct imsg_ra_rs *); | |||
64 | void parse_ra(struct imsg_ra_rs *); | |||
65 | void parse_rs(struct imsg_ra_rs *); | |||
66 | void update_iface(uint32_t); | |||
67 | void remove_iface(uint32_t); | |||
68 | struct engine_iface *find_engine_iface_by_id(uint32_t); | |||
69 | void iface_timeout(int, short, void *); | |||
70 | ||||
71 | struct rad_conf *engine_conf; | |||
72 | static struct imsgev *iev_frontend; | |||
73 | static struct imsgev *iev_main; | |||
74 | struct sockaddr_in6 all_nodes; | |||
75 | ||||
76 | void | |||
77 | engine_sig_handler(int sig, short event, void *arg) | |||
78 | { | |||
79 | /* | |||
80 | * Normal signal handler rules don't apply because libevent | |||
81 | * decouples for us. | |||
82 | */ | |||
83 | ||||
84 | switch (sig) { | |||
85 | case SIGINT2: | |||
86 | case SIGTERM15: | |||
87 | engine_shutdown(); | |||
88 | default: | |||
89 | fatalx("unexpected signal"); | |||
90 | } | |||
91 | } | |||
92 | ||||
93 | void | |||
94 | engine(int debug, int verbose) | |||
95 | { | |||
96 | struct event ev_sigint, ev_sigterm; | |||
97 | struct passwd *pw; | |||
98 | ||||
99 | engine_conf = config_new_empty(); | |||
100 | ||||
101 | log_init(debug, LOG_DAEMON(3<<3)); | |||
102 | log_setverbose(verbose); | |||
103 | ||||
104 | if ((pw = getpwnam(RAD_USER"_rad")) == NULL((void *)0)) | |||
105 | fatal("getpwnam"); | |||
106 | ||||
107 | if (chroot(pw->pw_dir) == -1) | |||
108 | fatal("chroot"); | |||
109 | if (chdir("/") == -1) | |||
110 | fatal("chdir(\"/\")"); | |||
111 | ||||
112 | setproctitle("%s", "engine"); | |||
113 | log_procinit("engine"); | |||
114 | ||||
115 | if (setgroups(1, &pw->pw_gid) || | |||
116 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || | |||
117 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) | |||
118 | fatal("can't drop privileges"); | |||
119 | ||||
120 | if (pledge("stdio recvfd", NULL((void *)0)) == -1) | |||
121 | fatal("pledge"); | |||
122 | ||||
123 | event_init(); | |||
124 | ||||
125 | /* Setup signal handler(s). */ | |||
126 | signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, engine_sig_handler, ( (void *)0)); | |||
127 | signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, engine_sig_handler, ((void *)0)); | |||
128 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); | |||
129 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); | |||
130 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); | |||
131 | signal(SIGHUP1, SIG_IGN(void (*)(int))1); | |||
132 | ||||
133 | /* Setup pipe and event handler to the main process. */ | |||
134 | if ((iev_main = malloc(sizeof(struct imsgev))) == NULL((void *)0)) | |||
135 | fatal(NULL((void *)0)); | |||
136 | ||||
137 | imsg_init(&iev_main->ibuf, 3); | |||
138 | iev_main->handler = engine_dispatch_main; | |||
139 | ||||
140 | /* Setup event handlers. */ | |||
141 | iev_main->events = EV_READ0x02; | |||
142 | event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, | |||
143 | iev_main->handler, iev_main); | |||
144 | event_add(&iev_main->ev, NULL((void *)0)); | |||
145 | ||||
146 | all_nodes.sin6_len = sizeof(all_nodes); | |||
147 | all_nodes.sin6_family = AF_INET624; | |||
148 | if (inet_pton(AF_INET624, "ff02::1", &all_nodes.sin6_addr) != 1) | |||
149 | fatal("inet_pton"); | |||
150 | ||||
151 | TAILQ_INIT(&engine_interfaces)do { (&engine_interfaces)->tqh_first = ((void *)0); (& engine_interfaces)->tqh_last = &(&engine_interfaces )->tqh_first; } while (0); | |||
152 | ||||
153 | event_dispatch(); | |||
154 | ||||
155 | engine_shutdown(); | |||
156 | } | |||
157 | ||||
158 | __dead__attribute__((__noreturn__)) void | |||
159 | engine_shutdown(void) | |||
160 | { | |||
161 | /* Close pipes. */ | |||
162 | msgbuf_clear(&iev_frontend->ibuf.w); | |||
163 | close(iev_frontend->ibuf.fd); | |||
164 | msgbuf_clear(&iev_main->ibuf.w); | |||
165 | close(iev_main->ibuf.fd); | |||
166 | ||||
167 | config_clear(engine_conf); | |||
168 | ||||
169 | free(iev_frontend); | |||
170 | free(iev_main); | |||
171 | ||||
172 | log_info("engine exiting"); | |||
173 | exit(0); | |||
174 | } | |||
175 | ||||
176 | int | |||
177 | engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) | |||
178 | { | |||
179 | return (imsg_compose_event(iev_frontend, type, 0, pid, -1, | |||
180 | data, datalen)); | |||
181 | } | |||
182 | ||||
183 | void | |||
184 | engine_dispatch_frontend(int fd, short event, void *bula) | |||
185 | { | |||
186 | struct imsgev *iev = bula; | |||
187 | struct imsgbuf *ibuf; | |||
188 | struct imsg imsg; | |||
189 | struct imsg_ra_rs ra_rs; | |||
190 | ssize_t n; | |||
191 | uint32_t if_index; | |||
192 | int shut = 0, verbose; | |||
193 | ||||
194 | ibuf = &iev->ibuf; | |||
195 | ||||
196 | if (event & EV_READ0x02) { | |||
197 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
198 | fatal("imsg_read error"); | |||
199 | if (n == 0) /* Connection closed. */ | |||
200 | shut = 1; | |||
201 | } | |||
202 | if (event & EV_WRITE0x04) { | |||
203 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
204 | fatal("msgbuf_write"); | |||
205 | if (n == 0) /* Connection closed. */ | |||
206 | shut = 1; | |||
207 | } | |||
208 | ||||
209 | for (;;) { | |||
210 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
211 | fatal("%s: imsg_get error", __func__); | |||
212 | if (n == 0) /* No more messages. */ | |||
213 | break; | |||
214 | ||||
215 | switch (imsg.hdr.type) { | |||
216 | case IMSG_RA_RS: | |||
217 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(ra_rs)) | |||
218 | fatalx("%s: IMSG_RA_RS wrong length: %lu", | |||
219 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
220 | memcpy(&ra_rs, imsg.data, sizeof(ra_rs)); | |||
221 | parse_ra_rs(&ra_rs); | |||
222 | break; | |||
223 | case IMSG_UPDATE_IF: | |||
224 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index)) | |||
225 | fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", | |||
226 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
227 | memcpy(&if_index, imsg.data, sizeof(if_index)); | |||
228 | update_iface(if_index); | |||
229 | break; | |||
230 | case IMSG_REMOVE_IF: | |||
231 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index)) | |||
232 | fatalx("%s: IMSG_REMOVE_IF wrong length: %lu", | |||
233 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
234 | memcpy(&if_index, imsg.data, sizeof(if_index)); | |||
235 | remove_iface(if_index); | |||
236 | break; | |||
237 | case IMSG_CTL_LOG_VERBOSE: | |||
238 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose)) | |||
239 | fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " | |||
240 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
241 | memcpy(&verbose, imsg.data, sizeof(verbose)); | |||
242 | log_setverbose(verbose); | |||
243 | break; | |||
244 | default: | |||
245 | log_debug("%s: unexpected imsg %d", __func__, | |||
246 | imsg.hdr.type); | |||
247 | break; | |||
248 | } | |||
249 | imsg_free(&imsg); | |||
250 | } | |||
251 | if (!shut) | |||
252 | imsg_event_add(iev); | |||
253 | else { | |||
254 | /* This pipe is dead. Remove its event handler. */ | |||
255 | event_del(&iev->ev); | |||
256 | event_loopexit(NULL((void *)0)); | |||
257 | } | |||
258 | } | |||
259 | ||||
260 | void | |||
261 | engine_dispatch_main(int fd, short event, void *bula) | |||
262 | { | |||
263 | static struct rad_conf *nconf; | |||
264 | static struct ra_iface_conf *ra_iface_conf; | |||
| ||||
265 | static struct ra_options_conf *ra_options; | |||
266 | struct imsg imsg; | |||
267 | struct imsgev *iev = bula; | |||
268 | struct imsgbuf *ibuf; | |||
269 | struct ra_prefix_conf *ra_prefix_conf; | |||
270 | struct ra_rdnss_conf *ra_rdnss_conf; | |||
271 | struct ra_dnssl_conf *ra_dnssl_conf; | |||
272 | struct ra_pref64_conf *pref64; | |||
273 | ssize_t n; | |||
274 | int shut = 0; | |||
275 | ||||
276 | ibuf = &iev->ibuf; | |||
277 | ||||
278 | if (event & EV_READ0x02) { | |||
279 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
280 | fatal("imsg_read error"); | |||
281 | if (n == 0) /* Connection closed. */ | |||
282 | shut = 1; | |||
283 | } | |||
284 | if (event & EV_WRITE0x04) { | |||
285 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
286 | fatal("msgbuf_write"); | |||
287 | if (n == 0) /* Connection closed. */ | |||
288 | shut = 1; | |||
289 | } | |||
290 | ||||
291 | for (;;) { | |||
292 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
293 | fatal("%s: imsg_get error", __func__); | |||
294 | if (n == 0) /* No more messages. */ | |||
295 | break; | |||
296 | ||||
297 | switch (imsg.hdr.type) { | |||
298 | case IMSG_SOCKET_IPC: | |||
299 | /* | |||
300 | * Setup pipe and event handler to the frontend | |||
301 | * process. | |||
302 | */ | |||
303 | if (iev_frontend) | |||
304 | fatalx("%s: received unexpected imsg fd " | |||
305 | "to engine", __func__); | |||
306 | ||||
307 | if ((fd = imsg_get_fd(&imsg)) == -1) | |||
308 | fatalx("%s: expected to receive imsg fd to " | |||
309 | "engine but didn't receive any", __func__); | |||
310 | ||||
311 | iev_frontend = malloc(sizeof(struct imsgev)); | |||
312 | if (iev_frontend == NULL((void *)0)) | |||
313 | fatal(NULL((void *)0)); | |||
314 | ||||
315 | imsg_init(&iev_frontend->ibuf, fd); | |||
316 | iev_frontend->handler = engine_dispatch_frontend; | |||
317 | iev_frontend->events = EV_READ0x02; | |||
318 | ||||
319 | event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, | |||
320 | iev_frontend->events, iev_frontend->handler, | |||
321 | iev_frontend); | |||
322 | event_add(&iev_frontend->ev, NULL((void *)0)); | |||
323 | break; | |||
324 | case IMSG_RECONF_CONF: | |||
325 | if (nconf != NULL((void *)0)) | |||
326 | fatalx("%s: IMSG_RECONF_CONF already in " | |||
327 | "progress", __func__); | |||
328 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct rad_conf)) | |||
329 | fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", | |||
330 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
331 | if ((nconf = malloc(sizeof(struct rad_conf))) == NULL((void *)0)) | |||
332 | fatal(NULL((void *)0)); | |||
333 | memcpy(nconf, imsg.data, sizeof(struct rad_conf)); | |||
334 | SIMPLEQ_INIT(&nconf->ra_iface_list)do { (&nconf->ra_iface_list)->sqh_first = ((void *) 0); (&nconf->ra_iface_list)->sqh_last = &(& nconf->ra_iface_list)->sqh_first; } while (0); | |||
335 | SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list)do { (&nconf->ra_options.ra_rdnss_list)->sqh_first = ((void *)0); (&nconf->ra_options.ra_rdnss_list)->sqh_last = &(&nconf->ra_options.ra_rdnss_list)->sqh_first ; } while (0); | |||
336 | SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list)do { (&nconf->ra_options.ra_dnssl_list)->sqh_first = ((void *)0); (&nconf->ra_options.ra_dnssl_list)->sqh_last = &(&nconf->ra_options.ra_dnssl_list)->sqh_first ; } while (0); | |||
337 | SIMPLEQ_INIT(&nconf->ra_options.ra_pref64_list)do { (&nconf->ra_options.ra_pref64_list)->sqh_first = ((void *)0); (&nconf->ra_options.ra_pref64_list)-> sqh_last = &(&nconf->ra_options.ra_pref64_list)-> sqh_first; } while (0); | |||
338 | ra_options = &nconf->ra_options; | |||
339 | break; | |||
340 | case IMSG_RECONF_RA_IFACE: | |||
341 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
342 | ra_iface_conf)) | |||
343 | fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: " | |||
344 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
345 | if ((ra_iface_conf = malloc(sizeof(struct | |||
346 | ra_iface_conf))) == NULL((void *)0)) | |||
347 | fatal(NULL((void *)0)); | |||
348 | memcpy(ra_iface_conf, imsg.data, | |||
349 | sizeof(struct ra_iface_conf)); | |||
350 | ra_iface_conf->autoprefix = NULL((void *)0); | |||
351 | SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list)do { (&ra_iface_conf->ra_prefix_list)->sqh_first = ( (void *)0); (&ra_iface_conf->ra_prefix_list)->sqh_last = &(&ra_iface_conf->ra_prefix_list)->sqh_first ; } while (0); | |||
352 | SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list)do { (&ra_iface_conf->ra_options.ra_rdnss_list)->sqh_first = ((void *)0); (&ra_iface_conf->ra_options.ra_rdnss_list )->sqh_last = &(&ra_iface_conf->ra_options.ra_rdnss_list )->sqh_first; } while (0); | |||
353 | SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list)do { (&ra_iface_conf->ra_options.ra_dnssl_list)->sqh_first = ((void *)0); (&ra_iface_conf->ra_options.ra_dnssl_list )->sqh_last = &(&ra_iface_conf->ra_options.ra_dnssl_list )->sqh_first; } while (0); | |||
354 | SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_pref64_list)do { (&ra_iface_conf->ra_options.ra_pref64_list)->sqh_first = ((void *)0); (&ra_iface_conf->ra_options.ra_pref64_list )->sqh_last = &(&ra_iface_conf->ra_options.ra_pref64_list )->sqh_first; } while (0); | |||
355 | SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,do { (ra_iface_conf)->entry.sqe_next = ((void *)0); *(& nconf->ra_iface_list)->sqh_last = (ra_iface_conf); (& nconf->ra_iface_list)->sqh_last = &(ra_iface_conf)-> entry.sqe_next; } while (0) | |||
356 | ra_iface_conf, entry)do { (ra_iface_conf)->entry.sqe_next = ((void *)0); *(& nconf->ra_iface_list)->sqh_last = (ra_iface_conf); (& nconf->ra_iface_list)->sqh_last = &(ra_iface_conf)-> entry.sqe_next; } while (0); | |||
357 | ra_options = &ra_iface_conf->ra_options; | |||
358 | break; | |||
359 | case IMSG_RECONF_RA_AUTOPREFIX: | |||
360 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
361 | ra_prefix_conf)) | |||
362 | fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong " | |||
363 | "length: %lu", __func__, | |||
364 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
365 | if ((ra_iface_conf->autoprefix = malloc(sizeof(struct | |||
| ||||
366 | ra_prefix_conf))) == NULL((void *)0)) | |||
367 | fatal(NULL((void *)0)); | |||
368 | memcpy(ra_iface_conf->autoprefix, imsg.data, | |||
369 | sizeof(struct ra_prefix_conf)); | |||
370 | break; | |||
371 | case IMSG_RECONF_RA_PREFIX: | |||
372 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
373 | ra_prefix_conf)) | |||
374 | fatalx("%s: IMSG_RECONF_RA_PREFIX wrong " | |||
375 | "length: %lu", __func__, | |||
376 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
377 | if ((ra_prefix_conf = malloc(sizeof(struct | |||
378 | ra_prefix_conf))) == NULL((void *)0)) | |||
379 | fatal(NULL((void *)0)); | |||
380 | memcpy(ra_prefix_conf, imsg.data, sizeof(struct | |||
381 | ra_prefix_conf)); | |||
382 | SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,do { (ra_prefix_conf)->entry.sqe_next = ((void *)0); *(& ra_iface_conf->ra_prefix_list)->sqh_last = (ra_prefix_conf ); (&ra_iface_conf->ra_prefix_list)->sqh_last = & (ra_prefix_conf)->entry.sqe_next; } while (0) | |||
383 | ra_prefix_conf, entry)do { (ra_prefix_conf)->entry.sqe_next = ((void *)0); *(& ra_iface_conf->ra_prefix_list)->sqh_last = (ra_prefix_conf ); (&ra_iface_conf->ra_prefix_list)->sqh_last = & (ra_prefix_conf)->entry.sqe_next; } while (0); | |||
384 | break; | |||
385 | case IMSG_RECONF_RA_RDNSS: | |||
386 | if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
387 | ra_rdnss_conf)) | |||
388 | fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: " | |||
389 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
390 | if ((ra_rdnss_conf = malloc(sizeof(struct | |||
391 | ra_rdnss_conf))) == NULL((void *)0)) | |||
392 | fatal(NULL((void *)0)); | |||
393 | memcpy(ra_rdnss_conf, imsg.data, sizeof(struct | |||
394 | ra_rdnss_conf)); | |||
395 | SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list,do { (ra_rdnss_conf)->entry.sqe_next = ((void *)0); *(& ra_options->ra_rdnss_list)->sqh_last = (ra_rdnss_conf); (&ra_options->ra_rdnss_list)->sqh_last = &(ra_rdnss_conf )->entry.sqe_next; } while (0) | |||
396 | ra_rdnss_conf, entry)do { (ra_rdnss_conf)->entry.sqe_next = ((void *)0); *(& ra_options->ra_rdnss_list)->sqh_last = (ra_rdnss_conf); (&ra_options->ra_rdnss_list)->sqh_last = &(ra_rdnss_conf )->entry.sqe_next; } while (0); | |||
397 | break; | |||
398 | case IMSG_RECONF_RA_DNSSL: | |||
399 | if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
400 | ra_dnssl_conf)) | |||
401 | fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: " | |||
402 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
403 | if ((ra_dnssl_conf = malloc(sizeof(struct | |||
404 | ra_dnssl_conf))) == NULL((void *)0)) | |||
405 | fatal(NULL((void *)0)); | |||
406 | memcpy(ra_dnssl_conf, imsg.data, sizeof(struct | |||
407 | ra_dnssl_conf)); | |||
408 | SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,do { (ra_dnssl_conf)->entry.sqe_next = ((void *)0); *(& ra_options->ra_dnssl_list)->sqh_last = (ra_dnssl_conf); (&ra_options->ra_dnssl_list)->sqh_last = &(ra_dnssl_conf )->entry.sqe_next; } while (0) | |||
409 | ra_dnssl_conf, entry)do { (ra_dnssl_conf)->entry.sqe_next = ((void *)0); *(& ra_options->ra_dnssl_list)->sqh_last = (ra_dnssl_conf); (&ra_options->ra_dnssl_list)->sqh_last = &(ra_dnssl_conf )->entry.sqe_next; } while (0); | |||
410 | break; | |||
411 | case IMSG_RECONF_RA_PREF64: | |||
412 | if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
413 | ra_pref64_conf)) | |||
414 | fatalx("%s: IMSG_RECONF_RA_PREF64 wrong length: " | |||
415 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
416 | if ((pref64 = malloc(sizeof(struct ra_pref64_conf))) == | |||
417 | NULL((void *)0)) | |||
418 | fatal(NULL((void *)0)); | |||
419 | memcpy(pref64, imsg.data, sizeof(struct ra_pref64_conf)); | |||
420 | SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64,do { (pref64)->entry.sqe_next = ((void *)0); *(&ra_options ->ra_pref64_list)->sqh_last = (pref64); (&ra_options ->ra_pref64_list)->sqh_last = &(pref64)->entry.sqe_next ; } while (0) | |||
421 | entry)do { (pref64)->entry.sqe_next = ((void *)0); *(&ra_options ->ra_pref64_list)->sqh_last = (pref64); (&ra_options ->ra_pref64_list)->sqh_last = &(pref64)->entry.sqe_next ; } while (0); | |||
422 | break; | |||
423 | case IMSG_RECONF_END: | |||
424 | if (nconf == NULL((void *)0)) | |||
425 | fatalx("%s: IMSG_RECONF_END without " | |||
426 | "IMSG_RECONF_CONF", __func__); | |||
427 | merge_config(engine_conf, nconf); | |||
428 | nconf = NULL((void *)0); | |||
429 | break; | |||
430 | default: | |||
431 | log_debug("%s: unexpected imsg %d", __func__, | |||
432 | imsg.hdr.type); | |||
433 | break; | |||
434 | } | |||
435 | imsg_free(&imsg); | |||
436 | } | |||
437 | if (!shut) | |||
438 | imsg_event_add(iev); | |||
439 | else { | |||
440 | /* This pipe is dead. Remove its event handler. */ | |||
441 | event_del(&iev->ev); | |||
442 | event_loopexit(NULL((void *)0)); | |||
443 | } | |||
444 | } | |||
445 | ||||
446 | ||||
447 | void | |||
448 | parse_ra_rs(struct imsg_ra_rs *ra_rs) | |||
449 | { | |||
450 | char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16]; | |||
451 | struct icmp6_hdr *hdr; | |||
452 | ||||
453 | hdr = (struct icmp6_hdr *) ra_rs->packet; | |||
454 | ||||
455 | switch (hdr->icmp6_type) { | |||
456 | case ND_ROUTER_ADVERT134: | |||
457 | parse_ra(ra_rs); | |||
458 | break; | |||
459 | case ND_ROUTER_SOLICIT133: | |||
460 | parse_rs(ra_rs); | |||
461 | break; | |||
462 | default: | |||
463 | log_warnx("unexpected icmp6_type: %d from %s on %s", | |||
464 | hdr->icmp6_type, inet_ntop(AF_INET624, &ra_rs->from.sin6_addr, | |||
465 | ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(ra_rs->if_index, | |||
466 | ifnamebuf)); | |||
467 | break; | |||
468 | } | |||
469 | } | |||
470 | ||||
471 | void | |||
472 | parse_ra(struct imsg_ra_rs *ra) | |||
473 | { | |||
474 | char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16]; | |||
475 | log_debug("got RA from %s on %s", | |||
476 | inet_ntop(AF_INET624, &ra->from.sin6_addr, ntopbuf, | |||
477 | INET6_ADDRSTRLEN46), if_indextoname(ra->if_index, | |||
478 | ifnamebuf)); | |||
479 | /* XXX not yet */ | |||
480 | } | |||
481 | ||||
482 | void | |||
483 | parse_rs(struct imsg_ra_rs *rs) | |||
484 | { | |||
485 | struct nd_router_solicit *nd_rs; | |||
486 | struct engine_iface *engine_iface; | |||
487 | ssize_t len; | |||
488 | int unicast_ra = 0; | |||
489 | const char *hbuf; | |||
490 | char ifnamebuf[IFNAMSIZ16]; | |||
491 | uint8_t *p; | |||
492 | ||||
493 | hbuf = sin6_to_str(&rs->from); | |||
494 | ||||
495 | log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index, | |||
496 | ifnamebuf)); | |||
497 | ||||
498 | if ((engine_iface = find_engine_iface_by_id(rs->if_index)) == NULL((void *)0)) | |||
499 | return; | |||
500 | ||||
501 | len = rs->len; | |||
502 | ||||
503 | if (!(IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr)(((&rs->from.sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&rs->from.sin6_addr)->__u6_addr .__u6_addr8[1] & 0xc0) == 0x80)) || | |||
504 | IN6_IS_ADDR_UNSPECIFIED(&rs->from.sin6_addr)((*(const u_int32_t *)(const void *)(&(&rs->from.sin6_addr )->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&rs->from.sin6_addr)->__u6_addr .__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void *)(&(&rs->from.sin6_addr)->__u6_addr.__u6_addr8 [8]) == 0) && (*(const u_int32_t *)(const void *)(& (&rs->from.sin6_addr)->__u6_addr.__u6_addr8[12]) == 0)))) { | |||
505 | log_warnx("RA from invalid address %s on %s", hbuf, | |||
506 | if_indextoname(rs->if_index, ifnamebuf)); | |||
507 | return; | |||
508 | } | |||
509 | ||||
510 | if ((size_t)len < sizeof(struct nd_router_solicit)) { | |||
511 | log_warnx("received too short message (%ld) from %s", len, | |||
512 | hbuf); | |||
513 | return; | |||
514 | } | |||
515 | ||||
516 | p = rs->packet; | |||
517 | nd_rs = (struct nd_router_solicit *)p; | |||
518 | len -= sizeof(struct nd_router_solicit); | |||
519 | p += sizeof(struct nd_router_solicit); | |||
520 | ||||
521 | if (nd_rs->nd_rs_codend_rs_hdr.icmp6_code != 0) { | |||
522 | log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_codend_rs_hdr.icmp6_code, | |||
523 | hbuf); | |||
524 | return; | |||
525 | } | |||
526 | while ((size_t)len >= sizeof(struct nd_opt_hdr)) { | |||
527 | struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; | |||
528 | ||||
529 | len -= sizeof(struct nd_opt_hdr); | |||
530 | p += sizeof(struct nd_opt_hdr); | |||
531 | ||||
532 | if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { | |||
533 | log_warnx("invalid option len: %u > %ld", | |||
534 | nd_opt_hdr->nd_opt_len, len); | |||
535 | return; | |||
536 | } | |||
537 | switch (nd_opt_hdr->nd_opt_type) { | |||
538 | case ND_OPT_SOURCE_LINKADDR1: | |||
539 | log_debug("got RS with source linkaddr option"); | |||
540 | unicast_ra = 1; | |||
541 | break; | |||
542 | default: | |||
543 | log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); | |||
544 | break; | |||
545 | } | |||
546 | len -= nd_opt_hdr->nd_opt_len * 8 - 2; | |||
547 | p += nd_opt_hdr->nd_opt_len * 8 - 2; | |||
548 | } | |||
549 | ||||
550 | if (unicast_ra) { | |||
551 | struct imsg_send_ra send_ra; | |||
552 | ||||
553 | send_ra.if_index = rs->if_index; | |||
554 | memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to)); | |||
555 | engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, | |||
556 | sizeof(send_ra)); | |||
557 | } else { | |||
558 | struct timespec now, diff, ra_delay = {MIN_DELAY_BETWEEN_RAS3, 0}; | |||
559 | struct timeval tv = {0, 0}; | |||
560 | ||||
561 | /* a multicast RA is already scheduled within the next 3 seconds */ | |||
562 | if (engine_iface->ras_delayed) | |||
563 | return; | |||
564 | ||||
565 | engine_iface->ras_delayed = 1; | |||
566 | clock_gettime(CLOCK_MONOTONIC3, &now); | |||
567 | timespecsub(&now, &engine_iface->last_ra, &diff)do { (&diff)->tv_sec = (&now)->tv_sec - (&engine_iface ->last_ra)->tv_sec; (&diff)->tv_nsec = (&now )->tv_nsec - (&engine_iface->last_ra)->tv_nsec; if ((&diff)->tv_nsec < 0) { (&diff)->tv_sec--; (&diff)->tv_nsec += 1000000000L; } } while (0); | |||
568 | ||||
569 | if (timespeccmp(&diff, &ra_delay, <)(((&diff)->tv_sec == (&ra_delay)->tv_sec) ? ((& diff)->tv_nsec < (&ra_delay)->tv_nsec) : ((& diff)->tv_sec < (&ra_delay)->tv_sec))) { | |||
570 | timespecsub(&ra_delay, &diff, &ra_delay)do { (&ra_delay)->tv_sec = (&ra_delay)->tv_sec - (&diff)->tv_sec; (&ra_delay)->tv_nsec = (& ra_delay)->tv_nsec - (&diff)->tv_nsec; if ((&ra_delay )->tv_nsec < 0) { (&ra_delay)->tv_sec--; (&ra_delay )->tv_nsec += 1000000000L; } } while (0); | |||
571 | TIMESPEC_TO_TIMEVAL(&tv, &ra_delay)do { (&tv)->tv_sec = (&ra_delay)->tv_sec; (& tv)->tv_usec = (&ra_delay)->tv_nsec / 1000; } while (0); | |||
572 | } | |||
573 | ||||
574 | tv.tv_usec = arc4random_uniform(MAX_RA_DELAY_TIME500 * 1000); | |||
575 | evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv); | |||
576 | } | |||
577 | } | |||
578 | ||||
579 | struct engine_iface* | |||
580 | find_engine_iface_by_id(uint32_t if_index) | |||
581 | { | |||
582 | struct engine_iface *engine_iface; | |||
583 | ||||
584 | TAILQ_FOREACH(engine_iface, &engine_interfaces, entry)for((engine_iface) = ((&engine_interfaces)->tqh_first) ; (engine_iface) != ((void *)0); (engine_iface) = ((engine_iface )->entry.tqe_next)) { | |||
585 | if (engine_iface->if_index == if_index) | |||
586 | return engine_iface; | |||
587 | } | |||
588 | return (NULL((void *)0)); | |||
589 | } | |||
590 | ||||
591 | void | |||
592 | update_iface(uint32_t if_index) | |||
593 | { | |||
594 | struct engine_iface *engine_iface; | |||
595 | struct timeval tv; | |||
596 | ||||
597 | if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL((void *)0)) { | |||
598 | engine_iface = calloc(1, sizeof(*engine_iface)); | |||
599 | engine_iface->if_index = if_index; | |||
600 | evtimer_set(&engine_iface->timer, iface_timeout, engine_iface)event_set(&engine_iface->timer, -1, 0, iface_timeout, engine_iface ); | |||
601 | TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry)do { (engine_iface)->entry.tqe_next = ((void *)0); (engine_iface )->entry.tqe_prev = (&engine_interfaces)->tqh_last; *(&engine_interfaces)->tqh_last = (engine_iface); (& engine_interfaces)->tqh_last = &(engine_iface)->entry .tqe_next; } while (0); | |||
602 | } | |||
603 | ||||
604 | tv.tv_sec = 0; | |||
605 | tv.tv_usec = arc4random_uniform(1000000); | |||
606 | evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv); | |||
607 | } | |||
608 | ||||
609 | void | |||
610 | remove_iface(uint32_t if_index) | |||
611 | { | |||
612 | struct engine_iface *engine_iface; | |||
613 | struct imsg_send_ra send_ra; | |||
614 | char if_name[IF_NAMESIZE16]; | |||
615 | ||||
616 | if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL((void *)0)) { | |||
617 | /* we don't know this interface, frontend can delete it */ | |||
618 | engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, | |||
619 | &if_index, sizeof(if_index)); | |||
620 | return; | |||
621 | } | |||
622 | ||||
623 | send_ra.if_index = engine_iface->if_index; | |||
624 | memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); | |||
625 | ||||
626 | TAILQ_REMOVE(&engine_interfaces, engine_iface, entry)do { if (((engine_iface)->entry.tqe_next) != ((void *)0)) ( engine_iface)->entry.tqe_next->entry.tqe_prev = (engine_iface )->entry.tqe_prev; else (&engine_interfaces)->tqh_last = (engine_iface)->entry.tqe_prev; *(engine_iface)->entry .tqe_prev = (engine_iface)->entry.tqe_next; ; ; } while (0 ); | |||
627 | evtimer_del(&engine_iface->timer)event_del(&engine_iface->timer); | |||
628 | ||||
629 | if (if_indextoname(if_index, if_name) != NULL((void *)0)) | |||
630 | engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, | |||
631 | sizeof(send_ra)); | |||
632 | engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, | |||
633 | &engine_iface->if_index, sizeof(engine_iface->if_index)); | |||
634 | free(engine_iface); | |||
635 | } | |||
636 | ||||
637 | void | |||
638 | iface_timeout(int fd, short events, void *arg) | |||
639 | { | |||
640 | struct engine_iface *engine_iface = (struct engine_iface *)arg; | |||
641 | struct imsg_send_ra send_ra; | |||
642 | struct timeval tv; | |||
643 | ||||
644 | tv.tv_sec = MIN_RTR_ADV_INTERVAL200 + | |||
645 | arc4random_uniform(MAX_RTR_ADV_INTERVAL600 - MIN_RTR_ADV_INTERVAL200); | |||
646 | tv.tv_usec = arc4random_uniform(1000000); | |||
647 | ||||
648 | log_debug("%s new timeout in %lld", __func__, tv.tv_sec); | |||
649 | ||||
650 | evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv); | |||
651 | ||||
652 | send_ra.if_index = engine_iface->if_index; | |||
653 | memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); | |||
654 | engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, | |||
655 | sizeof(send_ra)); | |||
656 | clock_gettime(CLOCK_MONOTONIC3, &engine_iface->last_ra); | |||
657 | engine_iface->ras_delayed = 0; | |||
658 | } |