Bug Summary

File:src/usr.sbin/rad/engine.c
Warning:line 358, 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.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name engine.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -I /usr/src/usr.sbin/rad -internal-isystem /usr/local/lib/clang/13.0.0/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 -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/rad/engine.c
1/* $OpenBSD: engine.c,v 1.19 2021/05/13 11:22:15 florian 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/uio.h>
27
28#include <netinet/in.h>
29#include <net/if.h>
30#include <arpa/inet.h>
31#include <netinet/icmp6.h>
32
33#include <errno(*__errno()).h>
34#include <event.h>
35#include <imsg.h>
36#include <signal.h>
37#include <stdlib.h>
38#include <string.h>
39#include <pwd.h>
40#include <unistd.h>
41
42#include "log.h"
43#include "rad.h"
44#include "engine.h"
45
46struct engine_iface {
47 TAILQ_ENTRY(engine_iface)struct { struct engine_iface *tqe_next; struct engine_iface *
*tqe_prev; }
entry;
48 struct event timer;
49 uint32_t if_index;
50};
51
52TAILQ_HEAD(, engine_iface)struct { struct engine_iface *tqh_first; struct engine_iface *
*tqh_last; }
engine_interfaces;
53
54
55__dead__attribute__((__noreturn__)) void engine_shutdown(void);
56void engine_sig_handler(int sig, short, void *);
57void engine_dispatch_frontend(int, short, void *);
58void engine_dispatch_main(int, short, void *);
59void parse_ra_rs(struct imsg_ra_rs *);
60void parse_ra(struct imsg_ra_rs *);
61void parse_rs(struct imsg_ra_rs *);
62void update_iface(uint32_t);
63void remove_iface(uint32_t);
64struct engine_iface *find_engine_iface_by_id(uint32_t);
65void iface_timeout(int, short, void *);
66
67struct rad_conf *engine_conf;
68static struct imsgev *iev_frontend;
69static struct imsgev *iev_main;
70struct sockaddr_in6 all_nodes;
71
72void
73engine_sig_handler(int sig, short event, void *arg)
74{
75 /*
76 * Normal signal handler rules don't apply because libevent
77 * decouples for us.
78 */
79
80 switch (sig) {
81 case SIGINT2:
82 case SIGTERM15:
83 engine_shutdown();
84 default:
85 fatalx("unexpected signal");
86 }
87}
88
89void
90engine(int debug, int verbose)
91{
92 struct event ev_sigint, ev_sigterm;
93 struct passwd *pw;
94
95 engine_conf = config_new_empty();
96
97 log_init(debug, LOG_DAEMON(3<<3));
98 log_setverbose(verbose);
99
100 if ((pw = getpwnam(RAD_USER"_rad")) == NULL((void *)0))
101 fatal("getpwnam");
102
103 if (chroot(pw->pw_dir) == -1)
104 fatal("chroot");
105 if (chdir("/") == -1)
106 fatal("chdir(\"/\")");
107
108 setproctitle("%s", "engine");
109 log_procinit("engine");
110
111 if (setgroups(1, &pw->pw_gid) ||
112 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
113 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
114 fatal("can't drop privileges");
115
116 if (pledge("stdio recvfd", NULL((void *)0)) == -1)
117 fatal("pledge");
118
119 event_init();
120
121 /* Setup signal handler(s). */
122 signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, engine_sig_handler, (
(void *)0))
;
123 signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, engine_sig_handler,
((void *)0))
;
124 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
125 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
126 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
127 signal(SIGHUP1, SIG_IGN(void (*)(int))1);
128
129 /* Setup pipe and event handler to the main process. */
130 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL((void *)0))
131 fatal(NULL((void *)0));
132
133 imsg_init(&iev_main->ibuf, 3);
134 iev_main->handler = engine_dispatch_main;
135
136 /* Setup event handlers. */
137 iev_main->events = EV_READ0x02;
138 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
139 iev_main->handler, iev_main);
140 event_add(&iev_main->ev, NULL((void *)0));
141
142 all_nodes.sin6_len = sizeof(all_nodes);
143 all_nodes.sin6_family = AF_INET624;
144 if (inet_pton(AF_INET624, "ff02::1", &all_nodes.sin6_addr) != 1)
145 fatal("inet_pton");
146
147 TAILQ_INIT(&engine_interfaces)do { (&engine_interfaces)->tqh_first = ((void *)0); (&
engine_interfaces)->tqh_last = &(&engine_interfaces
)->tqh_first; } while (0)
;
148
149 event_dispatch();
150
151 engine_shutdown();
152}
153
154__dead__attribute__((__noreturn__)) void
155engine_shutdown(void)
156{
157 /* Close pipes. */
158 msgbuf_clear(&iev_frontend->ibuf.w);
159 close(iev_frontend->ibuf.fd);
160 msgbuf_clear(&iev_main->ibuf.w);
161 close(iev_main->ibuf.fd);
162
163 config_clear(engine_conf);
164
165 free(iev_frontend);
166 free(iev_main);
167
168 log_info("engine exiting");
169 exit(0);
170}
171
172int
173engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen)
174{
175 return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
176 data, datalen));
177}
178
179void
180engine_dispatch_frontend(int fd, short event, void *bula)
181{
182 struct imsgev *iev = bula;
183 struct imsgbuf *ibuf;
184 struct imsg imsg;
185 struct imsg_ra_rs ra_rs;
186 ssize_t n;
187 uint32_t if_index;
188 int shut = 0, verbose;
189
190 ibuf = &iev->ibuf;
191
192 if (event & EV_READ0x02) {
193 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
194 fatal("imsg_read error");
195 if (n == 0) /* Connection closed. */
196 shut = 1;
197 }
198 if (event & EV_WRITE0x04) {
199 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
200 fatal("msgbuf_write");
201 if (n == 0) /* Connection closed. */
202 shut = 1;
203 }
204
205 for (;;) {
206 if ((n = imsg_get(ibuf, &imsg)) == -1)
207 fatal("%s: imsg_get error", __func__);
208 if (n == 0) /* No more messages. */
209 break;
210
211 switch (imsg.hdr.type) {
212 case IMSG_RA_RS:
213 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(ra_rs))
214 fatalx("%s: IMSG_RA_RS wrong length: %lu",
215 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
216 memcpy(&ra_rs, imsg.data, sizeof(ra_rs));
217 parse_ra_rs(&ra_rs);
218 break;
219 case IMSG_UPDATE_IF:
220 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index))
221 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
222 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
223 memcpy(&if_index, imsg.data, sizeof(if_index));
224 update_iface(if_index);
225 break;
226 case IMSG_REMOVE_IF:
227 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index))
228 fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
229 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
230 memcpy(&if_index, imsg.data, sizeof(if_index));
231 remove_iface(if_index);
232 break;
233 case IMSG_CTL_LOG_VERBOSE:
234 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose))
235 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
236 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
237 memcpy(&verbose, imsg.data, sizeof(verbose));
238 log_setverbose(verbose);
239 break;
240 default:
241 log_debug("%s: unexpected imsg %d", __func__,
242 imsg.hdr.type);
243 break;
244 }
245 imsg_free(&imsg);
246 }
247 if (!shut)
248 imsg_event_add(iev);
249 else {
250 /* This pipe is dead. Remove its event handler. */
251 event_del(&iev->ev);
252 event_loopexit(NULL((void *)0));
253 }
254}
255
256void
257engine_dispatch_main(int fd, short event, void *bula)
258{
259 static struct rad_conf *nconf;
260 static struct ra_iface_conf *ra_iface_conf;
1
'ra_iface_conf' initialized to a null pointer value
261 static struct ra_options_conf *ra_options;
262 struct imsg imsg;
263 struct imsgev *iev = bula;
264 struct imsgbuf *ibuf;
265 struct ra_prefix_conf *ra_prefix_conf;
266 struct ra_rdnss_conf *ra_rdnss_conf;
267 struct ra_dnssl_conf *ra_dnssl_conf;
268 ssize_t n;
269 int shut = 0;
270
271 ibuf = &iev->ibuf;
272
273 if (event & EV_READ0x02) {
2
Assuming the condition is false
3
Taking false branch
274 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
275 fatal("imsg_read error");
276 if (n == 0) /* Connection closed. */
277 shut = 1;
278 }
279 if (event & EV_WRITE0x04) {
4
Assuming the condition is false
5
Taking false branch
280 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
281 fatal("msgbuf_write");
282 if (n == 0) /* Connection closed. */
283 shut = 1;
284 }
285
286 for (;;) {
6
Loop condition is true. Entering loop body
287 if ((n = imsg_get(ibuf, &imsg)) == -1)
7
Assuming the condition is false
8
Taking false branch
288 fatal("%s: imsg_get error", __func__);
289 if (n == 0) /* No more messages. */
9
Assuming 'n' is not equal to 0
10
Taking false branch
290 break;
291
292 switch (imsg.hdr.type) {
11
Control jumps to 'case IMSG_RECONF_RA_AUTOPREFIX:' at line 352
293 case IMSG_SOCKET_IPC:
294 /*
295 * Setup pipe and event handler to the frontend
296 * process.
297 */
298 if (iev_frontend)
299 fatalx("%s: received unexpected imsg fd "
300 "to engine", __func__);
301
302 if ((fd = imsg.fd) == -1)
303 fatalx("%s: expected to receive imsg fd to "
304 "engine but didn't receive any", __func__);
305
306 iev_frontend = malloc(sizeof(struct imsgev));
307 if (iev_frontend == NULL((void *)0))
308 fatal(NULL((void *)0));
309
310 imsg_init(&iev_frontend->ibuf, fd);
311 iev_frontend->handler = engine_dispatch_frontend;
312 iev_frontend->events = EV_READ0x02;
313
314 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
315 iev_frontend->events, iev_frontend->handler,
316 iev_frontend);
317 event_add(&iev_frontend->ev, NULL((void *)0));
318 break;
319 case IMSG_RECONF_CONF:
320 if (nconf != NULL((void *)0))
321 fatalx("%s: IMSG_RECONF_CONF already in "
322 "progress", __func__);
323 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct rad_conf))
324 fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
325 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
326 if ((nconf = malloc(sizeof(struct rad_conf))) == NULL((void *)0))
327 fatal(NULL((void *)0));
328 memcpy(nconf, imsg.data, sizeof(struct rad_conf));
329 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)
;
330 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)
;
331 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)
;
332 ra_options = &nconf->ra_options;
333 break;
334 case IMSG_RECONF_RA_IFACE:
335 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
336 ra_iface_conf))
337 fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: "
338 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
339 if ((ra_iface_conf = malloc(sizeof(struct
340 ra_iface_conf))) == NULL((void *)0))
341 fatal(NULL((void *)0));
342 memcpy(ra_iface_conf, imsg.data,
343 sizeof(struct ra_iface_conf));
344 ra_iface_conf->autoprefix = NULL((void *)0);
345 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)
;
346 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)
;
347 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)
;
348 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)
349 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)
;
350 ra_options = &ra_iface_conf->ra_options;
351 break;
352 case IMSG_RECONF_RA_AUTOPREFIX:
353 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
12
Assuming the condition is false
13
Taking false branch
354 ra_prefix_conf))
355 fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong "
356 "length: %lu", __func__,
357 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
358 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')
359 ra_prefix_conf))) == NULL((void *)0))
360 fatal(NULL((void *)0));
361 memcpy(ra_iface_conf->autoprefix, imsg.data,
362 sizeof(struct ra_prefix_conf));
363 break;
364 case IMSG_RECONF_RA_PREFIX:
365 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
366 ra_prefix_conf))
367 fatalx("%s: IMSG_RECONF_RA_PREFIX wrong "
368 "length: %lu", __func__,
369 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
370 if ((ra_prefix_conf = malloc(sizeof(struct
371 ra_prefix_conf))) == NULL((void *)0))
372 fatal(NULL((void *)0));
373 memcpy(ra_prefix_conf, imsg.data, sizeof(struct
374 ra_prefix_conf));
375 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)
376 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)
;
377 break;
378 case IMSG_RECONF_RA_RDNSS:
379 if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
380 ra_rdnss_conf))
381 fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: "
382 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
383 if ((ra_rdnss_conf = malloc(sizeof(struct
384 ra_rdnss_conf))) == NULL((void *)0))
385 fatal(NULL((void *)0));
386 memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
387 ra_rdnss_conf));
388 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)
389 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)
;
390 break;
391 case IMSG_RECONF_RA_DNSSL:
392 if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
393 ra_dnssl_conf))
394 fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: "
395 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
396 if ((ra_dnssl_conf = malloc(sizeof(struct
397 ra_dnssl_conf))) == NULL((void *)0))
398 fatal(NULL((void *)0));
399 memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
400 ra_dnssl_conf));
401 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)
402 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)
;
403 break;
404 case IMSG_RECONF_END:
405 if (nconf == NULL((void *)0))
406 fatalx("%s: IMSG_RECONF_END without "
407 "IMSG_RECONF_CONF", __func__);
408 merge_config(engine_conf, nconf);
409 nconf = NULL((void *)0);
410 break;
411 default:
412 log_debug("%s: unexpected imsg %d", __func__,
413 imsg.hdr.type);
414 break;
415 }
416 imsg_free(&imsg);
417 }
418 if (!shut)
419 imsg_event_add(iev);
420 else {
421 /* This pipe is dead. Remove its event handler. */
422 event_del(&iev->ev);
423 event_loopexit(NULL((void *)0));
424 }
425}
426
427
428void
429parse_ra_rs(struct imsg_ra_rs *ra_rs)
430{
431 char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16];
432 struct icmp6_hdr *hdr;
433
434 hdr = (struct icmp6_hdr *) ra_rs->packet;
435
436 switch (hdr->icmp6_type) {
437 case ND_ROUTER_ADVERT134:
438 parse_ra(ra_rs);
439 break;
440 case ND_ROUTER_SOLICIT133:
441 parse_rs(ra_rs);
442 break;
443 default:
444 log_warnx("unexpected icmp6_type: %d from %s on %s",
445 hdr->icmp6_type, inet_ntop(AF_INET624, &ra_rs->from.sin6_addr,
446 ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(ra_rs->if_index,
447 ifnamebuf));
448 break;
449 }
450}
451
452void
453parse_ra(struct imsg_ra_rs *ra)
454{
455 char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16];
456 log_debug("got RA from %s on %s",
457 inet_ntop(AF_INET624, &ra->from.sin6_addr, ntopbuf,
458 INET6_ADDRSTRLEN46), if_indextoname(ra->if_index,
459 ifnamebuf));
460 /* XXX not yet */
461}
462
463void
464parse_rs(struct imsg_ra_rs *rs)
465{
466 struct nd_router_solicit *nd_rs;
467 struct imsg_send_ra send_ra;
468 ssize_t len;
469 const char *hbuf;
470 char ifnamebuf[IFNAMSIZ16];
471 uint8_t *p;
472
473 hbuf = sin6_to_str(&rs->from);
474
475 send_ra.if_index = rs->if_index;
476 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
477
478 log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index,
479 ifnamebuf));
480
481 len = rs->len;
482
483 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))
||
484 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))
)) {
485 log_warnx("RA from invalid address %s on %s", hbuf,
486 if_indextoname(rs->if_index, ifnamebuf));
487 return;
488 }
489
490 if ((size_t)len < sizeof(struct nd_router_solicit)) {
491 log_warnx("received too short message (%ld) from %s", len,
492 hbuf);
493 return;
494 }
495
496 p = rs->packet;
497 nd_rs = (struct nd_router_solicit *)p;
498 len -= sizeof(struct nd_router_solicit);
499 p += sizeof(struct nd_router_solicit);
500
501 if (nd_rs->nd_rs_codend_rs_hdr.icmp6_code != 0) {
502 log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_codend_rs_hdr.icmp6_code,
503 hbuf);
504 return;
505 }
506 while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
507 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
508
509 len -= sizeof(struct nd_opt_hdr);
510 p += sizeof(struct nd_opt_hdr);
511
512 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
513 log_warnx("invalid option len: %u > %ld",
514 nd_opt_hdr->nd_opt_len, len);
515 return;
516 }
517 switch (nd_opt_hdr->nd_opt_type) {
518 case ND_OPT_SOURCE_LINKADDR1:
519 log_debug("got RS with source linkaddr option");
520 memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to));
521 break;
522 default:
523 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
524 break;
525 }
526 len -= nd_opt_hdr->nd_opt_len * 8 - 2;
527 p += nd_opt_hdr->nd_opt_len * 8 - 2;
528 }
529 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
530 sizeof(send_ra));
531}
532
533struct engine_iface*
534find_engine_iface_by_id(uint32_t if_index)
535{
536 struct engine_iface *engine_iface;
537
538 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))
{
539 if (engine_iface->if_index == if_index)
540 return engine_iface;
541 }
542 return (NULL((void *)0));
543}
544
545void
546update_iface(uint32_t if_index)
547{
548 struct engine_iface *engine_iface;
549 struct timeval tv;
550
551 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL((void *)0)) {
552 engine_iface = calloc(1, sizeof(*engine_iface));
553 engine_iface->if_index = if_index;
554 evtimer_set(&engine_iface->timer, iface_timeout, engine_iface)event_set(&engine_iface->timer, -1, 0, iface_timeout, engine_iface
)
;
555 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)
;
556 }
557
558 tv.tv_sec = 0;
559 tv.tv_usec = arc4random_uniform(1000000);
560 evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv);
561}
562
563void
564remove_iface(uint32_t if_index)
565{
566 struct engine_iface *engine_iface;
567 struct imsg_send_ra send_ra;
568 char if_name[IF_NAMESIZE16];
569
570 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL((void *)0)) {
571 /* we don't know this interface, frontend can delete it */
572 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0,
573 &if_index, sizeof(if_index));
574 return;
575 }
576
577 send_ra.if_index = engine_iface->if_index;
578 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
579
580 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
)
;
581 evtimer_del(&engine_iface->timer)event_del(&engine_iface->timer);
582
583 if (if_indextoname(if_index, if_name) != NULL((void *)0))
584 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
585 sizeof(send_ra));
586 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0,
587 &engine_iface->if_index, sizeof(engine_iface->if_index));
588 free(engine_iface);
589}
590
591void
592iface_timeout(int fd, short events, void *arg)
593{
594 struct engine_iface *engine_iface = (struct engine_iface *)arg;
595 struct imsg_send_ra send_ra;
596 struct timeval tv;
597
598 tv.tv_sec = MIN_RTR_ADV_INTERVAL200 +
599 arc4random_uniform(MAX_RTR_ADV_INTERVAL600 - MIN_RTR_ADV_INTERVAL200);
600 tv.tv_usec = arc4random_uniform(1000000);
601
602 log_debug("%s new timeout in %lld", __func__, tv.tv_sec);
603
604 evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv);
605
606 send_ra.if_index = engine_iface->if_index;
607 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
608 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
609 sizeof(send_ra));
610}