Bug Summary

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')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name engine.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/rad/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/rad -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/rad/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/rad/engine.c
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
48struct 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
56TAILQ_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);
60void engine_sig_handler(int sig, short, void *);
61void engine_dispatch_frontend(int, short, void *);
62void engine_dispatch_main(int, short, void *);
63void parse_ra_rs(struct imsg_ra_rs *);
64void parse_ra(struct imsg_ra_rs *);
65void parse_rs(struct imsg_ra_rs *);
66void update_iface(uint32_t);
67void remove_iface(uint32_t);
68struct engine_iface *find_engine_iface_by_id(uint32_t);
69void iface_timeout(int, short, void *);
70
71struct rad_conf *engine_conf;
72static struct imsgev *iev_frontend;
73static struct imsgev *iev_main;
74struct sockaddr_in6 all_nodes;
75
76void
77engine_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
93void
94engine(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
159engine_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
176int
177engine_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
183void
184engine_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
260void
261engine_dispatch_main(int fd, short event, void *bula)
262{
263 static struct rad_conf *nconf;
264 static struct ra_iface_conf *ra_iface_conf;
1
'ra_iface_conf' initialized to a null pointer value
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) {
2
Assuming the condition is false
3
Taking false branch
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) {
4
Assuming the condition is false
5
Taking false branch
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 (;;) {
6
Loop condition is true. Entering loop body
292 if ((n = imsg_get(ibuf, &imsg)) == -1)
7
Assuming the condition is false
8
Taking false branch
293 fatal("%s: imsg_get error", __func__);
294 if (n == 0) /* No more messages. */
9
Assuming 'n' is not equal to 0
10
Taking false branch
295 break;
296
297 switch (imsg.hdr.type) {
11
Control jumps to 'case IMSG_RECONF_RA_AUTOPREFIX:' at line 359
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
12
Assuming the condition is false
13
Taking false branch
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
14
Access to field 'autoprefix' results in a dereference of a null pointer (loaded from variable 'ra_iface_conf')
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
447void
448parse_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
471void
472parse_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
482void
483parse_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
579struct engine_iface*
580find_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
591void
592update_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
609void
610remove_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
637void
638iface_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}