Bug Summary

File:src/sbin/slaacd/frontend.c
Warning:line 1017, column 19
Access to field 'ipi6_ifindex' results in a dereference of a null pointer (loaded from variable 'pi')

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 frontend.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/sbin/slaacd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sbin/slaacd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/slaacd/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/sbin/slaacd/frontend.c
1/* $OpenBSD: frontend.c,v 1.65 2023/12/14 09:58:59 claudio 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/uio.h>
27
28#include <net/if.h>
29#include <net/if_dl.h>
30#include <net/if_types.h>
31#include <net/route.h>
32
33#include <arpa/inet.h>
34
35#include <netinet/in.h>
36#include <netinet/if_ether.h>
37#include <netinet6/nd6.h>
38#include <netinet6/in6_var.h>
39#include <netinet/ip6.h>
40#include <netinet6/ip6_var.h>
41#include <netinet/icmp6.h>
42
43#include <errno(*__errno()).h>
44#include <event.h>
45#include <ifaddrs.h>
46#include <imsg.h>
47#include <pwd.h>
48#include <signal.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53
54#include "log.h"
55#include "slaacd.h"
56#include "frontend.h"
57#include "control.h"
58
59#define ROUTE_SOCKET_BUF_SIZE16384 16384
60#define ALLROUTER"ff02::2" "ff02::2"
61
62struct icmp6_ev {
63 struct event ev;
64 uint8_t answer[1500];
65 struct msghdr rcvmhdr;
66 struct iovec rcviov[1];
67 struct sockaddr_in6 from;
68 int refcnt;
69};
70
71struct iface {
72 LIST_ENTRY(iface)struct { struct iface *le_next; struct iface **le_prev; } entries;
73 struct icmp6_ev *icmp6ev;
74 struct ether_addr hw_address;
75 uint32_t if_index;
76 int rdomain;
77 int send_solicitation;
78 int ll_tentative;
79};
80
81__dead__attribute__((__noreturn__)) void frontend_shutdown(void);
82void frontend_sig_handler(int, short, void *);
83void update_iface(uint32_t, char*);
84void frontend_startup(void);
85void route_receive(int, short, void *);
86void handle_route_message(struct rt_msghdr *, struct sockaddr **);
87void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
88void icmp6_receive(int, short, void *);
89int get_flags(char *);
90int get_xflags(char *);
91int get_ifrdomain(char *);
92struct iface *get_iface_by_id(uint32_t);
93void remove_iface(uint32_t);
94struct icmp6_ev *get_icmp6ev_by_rdomain(int);
95void unref_icmp6ev(struct iface *);
96void set_icmp6sock(int, int);
97void send_solicitation(uint32_t);
98#ifndef SMALL
99const char *flags_to_str(int);
100#endif /* SMALL */
101
102LIST_HEAD(, iface)struct { struct iface *lh_first; } interfaces;
103static struct imsgev *iev_main;
104static struct imsgev *iev_engine;
105struct event ev_route;
106struct msghdr sndmhdr;
107struct iovec sndiov[4];
108struct nd_router_solicit rs;
109struct nd_opt_hdr nd_opt_hdr;
110struct ether_addr nd_opt_source_link_addr;
111struct sockaddr_in6 dst;
112int ioctlsock;
113
114void
115frontend_sig_handler(int sig, short event, void *bula)
116{
117 /*
118 * Normal signal handler rules don't apply because libevent
119 * decouples for us.
120 */
121
122 switch (sig) {
123 case SIGINT2:
124 case SIGTERM15:
125 frontend_shutdown();
126 default:
127 fatalx("unexpected signal");
128 }
129}
130
131void
132frontend(int debug, int verbose)
133{
134 struct event ev_sigint, ev_sigterm;
135 struct passwd *pw;
136 struct in6_pktinfo *pi;
137 struct cmsghdr *cm;
138 size_t sndcmsglen;
139 int hoplimit = 255;
140 uint8_t *sndcmsgbuf;
141
142 log_init(debug, LOG_DAEMON(3<<3));
143 log_setverbose(verbose);
144
145 if ((pw = getpwnam(SLAACD_USER"_slaacd")) == NULL((void *)0))
146 fatal("getpwnam");
147
148 if (chdir("/") == -1)
149 fatal("chdir(\"/\")");
150
151 if (unveil("/", "") == -1)
152 fatal("unveil /");
153 if (unveil(NULL((void *)0), NULL((void *)0)) == -1)
154 fatal("unveil");
155
156 setproctitle("%s", "frontend");
157 log_procinit("frontend");
158
159 if ((ioctlsock = socket(AF_INET624, SOCK_DGRAM2 | SOCK_CLOEXEC0x8000, 0)) == -1)
160 fatal("socket");
161
162 if (setgroups(1, &pw->pw_gid) ||
163 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
164 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
165 fatal("can't drop privileges");
166
167 if (pledge("stdio unix recvfd route", NULL((void *)0)) == -1)
168 fatal("pledge");
169
170 event_init();
171
172 /* Setup signal handler. */
173 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, frontend_sig_handler,
((void *)0))
;
174 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, frontend_sig_handler
, ((void *)0))
;
175 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
176 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
177 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
178 signal(SIGHUP1, SIG_IGN(void (*)(int))1);
179
180 /* Setup pipe and event handler to the parent process. */
181 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL((void *)0))
182 fatal(NULL((void *)0));
183 imsg_init(&iev_main->ibuf, 3);
184 iev_main->handler = frontend_dispatch_main;
185 iev_main->events = EV_READ0x02;
186 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
187 iev_main->handler, iev_main);
188 event_add(&iev_main->ev, NULL((void *)0));
189
190 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(struct
in6_pktinfo)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)
))
+
191 CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int))
+ (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
192
193 if ((sndcmsgbuf = malloc(sndcmsglen)) == NULL((void *)0))
194 fatal("malloc");
195
196 rs.nd_rs_typend_rs_hdr.icmp6_type = ND_ROUTER_SOLICIT133;
197 rs.nd_rs_codend_rs_hdr.icmp6_code = 0;
198 rs.nd_rs_cksumnd_rs_hdr.icmp6_cksum = 0;
199 rs.nd_rs_reservednd_rs_hdr.icmp6_dataun.icmp6_un_data32[0] = 0;
200
201 nd_opt_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR1;
202 nd_opt_hdr.nd_opt_len = 1;
203
204 memset(&dst, 0, sizeof(dst));
205 dst.sin6_family = AF_INET624;
206 if (inet_pton(AF_INET624, ALLROUTER"ff02::2", &dst.sin6_addr.s6_addr__u6_addr.__u6_addr8) != 1)
207 fatal("inet_pton");
208
209 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
210 sndmhdr.msg_iov = sndiov;
211 sndmhdr.msg_iovlen = 3;
212 sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
213 sndmhdr.msg_controllen = sndcmsglen;
214
215 sndmhdr.msg_name = (caddr_t)&dst;
216 sndmhdr.msg_iov[0].iov_base = (caddr_t)&rs;
217 sndmhdr.msg_iov[0].iov_len = sizeof(rs);
218 sndmhdr.msg_iov[1].iov_base = (caddr_t)&nd_opt_hdr;
219 sndmhdr.msg_iov[1].iov_len = sizeof(nd_opt_hdr);
220 sndmhdr.msg_iov[2].iov_base = (caddr_t)&nd_opt_source_link_addr;
221 sndmhdr.msg_iov[2].iov_len = sizeof(nd_opt_source_link_addr);
222
223 cm = CMSG_FIRSTHDR(&sndmhdr)((&sndmhdr)->msg_controllen >= sizeof(struct cmsghdr
) ? (struct cmsghdr *)(&sndmhdr)->msg_control : (struct
cmsghdr *)((void *)0))
;
224
225 cm->cmsg_level = IPPROTO_IPV641;
226 cm->cmsg_type = IPV6_PKTINFO46;
227 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(struct in6_pktinfo)))
;
228 pi = (struct in6_pktinfo *)CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
229 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
230 pi->ipi6_ifindex = 0;
231
232 cm = CMSG_NXTHDR(&sndmhdr, cm)(((char *)(cm) + (((unsigned long)((cm)->cmsg_len) + (sizeof
(long) - 1)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof
(struct cmsghdr)) + (sizeof(long) - 1)) &~(sizeof(long) -
1)) > ((char *)(&sndmhdr)->msg_control) + (&sndmhdr
)->msg_controllen) ? (struct cmsghdr *)((void *)0) : (struct
cmsghdr *)((char *)(cm) + (((unsigned long)((cm)->cmsg_len
) + (sizeof(long) - 1)) &~(sizeof(long) - 1))))
;
233 cm->cmsg_level = IPPROTO_IPV641;
234 cm->cmsg_type = IPV6_HOPLIMIT47;
235 cm->cmsg_len = CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(int)))
;
236 memcpy(CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
, &hoplimit, sizeof(int));
237
238 LIST_INIT(&interfaces)do { ((&interfaces)->lh_first) = ((void *)0); } while (
0)
;
239
240 event_dispatch();
241
242 frontend_shutdown();
243}
244
245__dead__attribute__((__noreturn__)) void
246frontend_shutdown(void)
247{
248 /* Close pipes. */
249 msgbuf_write(&iev_engine->ibuf.w);
250 msgbuf_clear(&iev_engine->ibuf.w);
251 close(iev_engine->ibuf.fd);
252 msgbuf_write(&iev_main->ibuf.w);
253 msgbuf_clear(&iev_main->ibuf.w);
254 close(iev_main->ibuf.fd);
255
256 free(iev_engine);
257 free(iev_main);
258
259 log_info("frontend exiting");
260 exit(0);
261}
262
263int
264frontend_imsg_compose_main(int type, pid_t pid, void *data,
265 uint16_t datalen)
266{
267 return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
268 datalen));
269}
270
271int
272frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid,
273 void *data, uint16_t datalen)
274{
275 return (imsg_compose_event(iev_engine, type, peerid, pid, -1,
276 data, datalen));
277}
278
279void
280frontend_dispatch_main(int fd, short event, void *bula)
281{
282 struct imsg imsg;
283 struct imsgev *iev = bula;
284 struct imsgbuf *ibuf = &iev->ibuf;
285 ssize_t n;
286 int shut = 0, icmp6sock, rdomain;
287
288 if (event & EV_READ0x02) {
289 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
290 fatal("imsg_read error");
291 if (n == 0) /* Connection closed. */
292 shut = 1;
293 }
294 if (event & EV_WRITE0x04) {
295 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
296 fatal("msgbuf_write");
297 if (n == 0) /* Connection closed. */
298 shut = 1;
299 }
300
301 for (;;) {
302 if ((n = imsg_get(ibuf, &imsg)) == -1)
303 fatal("%s: imsg_get error", __func__);
304 if (n == 0) /* No more messages. */
305 break;
306
307 switch (imsg.hdr.type) {
308 case IMSG_SOCKET_IPC:
309 /*
310 * Setup pipe and event handler to the engine
311 * process.
312 */
313 if (iev_engine)
314 fatalx("%s: received unexpected imsg fd "
315 "to frontend", __func__);
316
317 if ((fd = imsg_get_fd(&imsg)) == -1)
318 fatalx("%s: expected to receive imsg fd to "
319 "frontend but didn't receive any",
320 __func__);
321
322 iev_engine = malloc(sizeof(struct imsgev));
323 if (iev_engine == NULL((void *)0))
324 fatal(NULL((void *)0));
325
326 imsg_init(&iev_engine->ibuf, fd);
327 iev_engine->handler = frontend_dispatch_engine;
328 iev_engine->events = EV_READ0x02;
329
330 event_set(&iev_engine->ev, iev_engine->ibuf.fd,
331 iev_engine->events, iev_engine->handler, iev_engine);
332 event_add(&iev_engine->ev, NULL((void *)0));
333 break;
334 case IMSG_ICMP6SOCK:
335 if ((icmp6sock = imsg_get_fd(&imsg)) == -1)
336 fatalx("%s: expected to receive imsg "
337 "ICMPv6 fd but didn't receive any",
338 __func__);
339 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdomain))
340 fatalx("%s: IMSG_ICMP6SOCK wrong length: "
341 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
342 memcpy(&rdomain, imsg.data, sizeof(rdomain));
343 set_icmp6sock(icmp6sock, rdomain);
344 break;
345 case IMSG_ROUTESOCK:
346 if ((fd = imsg_get_fd(&imsg)) == -1)
347 fatalx("%s: expected to receive imsg "
348 "routesocket fd but didn't receive any",
349 __func__);
350 event_set(&ev_route, fd, EV_READ0x02 | EV_PERSIST0x10,
351 route_receive, NULL((void *)0));
352 break;
353 case IMSG_STARTUP:
354 frontend_startup();
355 break;
356#ifndef SMALL
357 case IMSG_CONTROLFD:
358 if ((fd = imsg_get_fd(&imsg)) == -1)
359 fatalx("%s: expected to receive imsg "
360 "control fd but didn't receive any",
361 __func__);
362 /* Listen on control socket. */
363 control_listen(fd);
364 break;
365 case IMSG_CTL_END:
366 control_imsg_relay(&imsg);
367 break;
368#endif /* SMALL */
369 default:
370 log_debug("%s: error handling imsg %d", __func__,
371 imsg.hdr.type);
372 break;
373 }
374 imsg_free(&imsg);
375 }
376 if (!shut)
377 imsg_event_add(iev);
378 else {
379 /* This pipe is dead. Remove its event handler. */
380 event_del(&iev->ev);
381 event_loopexit(NULL((void *)0));
382 }
383}
384
385void
386frontend_dispatch_engine(int fd, short event, void *bula)
387{
388 struct imsgev *iev = bula;
389 struct imsgbuf *ibuf = &iev->ibuf;
390 struct imsg imsg;
391 ssize_t n;
392 int shut = 0;
393 uint32_t if_index;
394
395 if (event & EV_READ0x02) {
1
Assuming the condition is false
2
Taking false branch
396 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
397 fatal("imsg_read error");
398 if (n == 0) /* Connection closed. */
399 shut = 1;
400 }
401 if (event & EV_WRITE0x04) {
3
Assuming the condition is false
4
Taking false branch
402 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
403 fatal("msgbuf_write");
404 if (n == 0) /* Connection closed. */
405 shut = 1;
406 }
407
408 for (;;) {
5
Loop condition is true. Entering loop body
409 if ((n = imsg_get(ibuf, &imsg)) == -1)
6
Assuming the condition is false
7
Taking false branch
410 fatal("%s: imsg_get error", __func__);
411 if (n == 0) /* No more messages. */
8
Assuming 'n' is not equal to 0
9
Taking false branch
412 break;
413
414 switch (imsg.hdr.type) {
10
Control jumps to 'case IMSG_CTL_SEND_SOLICITATION:' at line 430
415#ifndef SMALL
416 case IMSG_CTL_END:
417 case IMSG_CTL_SHOW_INTERFACE_INFO:
418 case IMSG_CTL_SHOW_INTERFACE_INFO_RA:
419 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX:
420 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS:
421 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS:
422 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL:
423 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
424 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
425 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS:
426 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL:
427 control_imsg_relay(&imsg);
428 break;
429#endif /* SMALL */
430 case IMSG_CTL_SEND_SOLICITATION:
431 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index))
11
Assuming the condition is false
12
Taking false branch
432 fatalx("%s: IMSG_CTL_SEND_SOLICITATION wrong "
433 "length: %lu", __func__,
434 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
435 if_index = *((uint32_t *)imsg.data);
436 send_solicitation(if_index);
13
Calling 'send_solicitation'
437 break;
438 default:
439 log_debug("%s: error handling imsg %d", __func__,
440 imsg.hdr.type);
441 break;
442 }
443 imsg_free(&imsg);
444 }
445 if (!shut)
446 imsg_event_add(iev);
447 else {
448 /* This pipe is dead. Remove its event handler. */
449 event_del(&iev->ev);
450 event_loopexit(NULL((void *)0));
451 }
452}
453
454int
455get_flags(char *if_name)
456{
457 struct ifreq ifr;
458
459 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
460 if (ioctl(ioctlsock, SIOCGIFFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((17)))
, (caddr_t)&ifr) == -1) {
461 log_warn("SIOCGIFFLAGS");
462 return -1;
463 }
464 return ifr.ifr_flagsifr_ifru.ifru_flags;
465}
466
467int
468get_xflags(char *if_name)
469{
470 struct ifreq ifr;
471
472 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
473 if (ioctl(ioctlsock, SIOCGIFXFLAGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((158)))
, (caddr_t)&ifr) == -1) {
474 log_warn("SIOCGIFXFLAGS");
475 return -1;
476 }
477 return ifr.ifr_flagsifr_ifru.ifru_flags;
478}
479
480int
481get_ifrdomain(char *if_name)
482{
483 struct ifreq ifr;
484
485 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
486 if (ioctl(ioctlsock, SIOCGIFRDOMAIN(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((160)))
, (caddr_t)&ifr) == -1) {
487 log_warn("SIOCGIFRDOMAIN");
488 return -1;
489 }
490 return ifr.ifr_rdomainidifr_ifru.ifru_metric;
491}
492
493void
494update_iface(uint32_t if_index, char* if_name)
495{
496 struct iface *iface;
497 struct ifaddrs *ifap, *ifa;
498 struct imsg_ifinfo imsg_ifinfo;
499 struct sockaddr_dl *sdl;
500 struct sockaddr_in6 *sin6;
501 struct in6_ifreq ifr6;
502 int flags, xflags, ifrdomain;
503
504 if ((flags = get_flags(if_name)) == -1 || (xflags =
505 get_xflags(if_name)) == -1)
506 return;
507
508 if (!(xflags & (IFXF_AUTOCONF60x20 | IFXF_AUTOCONF6TEMP0x4)))
509 return;
510
511 if((ifrdomain = get_ifrdomain(if_name)) == -1)
512 return;
513
514 iface = get_iface_by_id(if_index);
515
516 if (iface != NULL((void *)0)) {
517 if (iface->rdomain != ifrdomain) {
518 unref_icmp6ev(iface);
519 iface->rdomain = ifrdomain;
520 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain);
521 }
522 } else {
523 if ((iface = calloc(1, sizeof(*iface))) == NULL((void *)0))
524 fatal("calloc");
525 iface->if_index = if_index;
526 iface->rdomain = ifrdomain;
527 iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain);
528 iface->ll_tentative = 1;
529
530 LIST_INSERT_HEAD(&interfaces, iface, entries)do { if (((iface)->entries.le_next = (&interfaces)->
lh_first) != ((void *)0)) (&interfaces)->lh_first->
entries.le_prev = &(iface)->entries.le_next; (&interfaces
)->lh_first = (iface); (iface)->entries.le_prev = &
(&interfaces)->lh_first; } while (0)
;
531 }
532
533 memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo));
534
535 imsg_ifinfo.if_index = if_index;
536 imsg_ifinfo.rdomain = ifrdomain;
537 imsg_ifinfo.running = (flags & (IFF_UP0x1 | IFF_RUNNING0x40)) == (IFF_UP0x1 |
538 IFF_RUNNING0x40);
539 imsg_ifinfo.autoconf = (xflags & IFXF_AUTOCONF60x20);
540 imsg_ifinfo.temporary = (xflags & IFXF_AUTOCONF6TEMP0x4);
541 imsg_ifinfo.soii = !(xflags & IFXF_INET6_NOSOII0x40);
542
543 if (getifaddrs(&ifap) != 0)
544 fatal("getifaddrs");
545
546 for (ifa = ifap; ifa != NULL((void *)0); ifa = ifa->ifa_next) {
547 if (strcmp(if_name, ifa->ifa_name) != 0)
548 continue;
549 if (ifa->ifa_addr == NULL((void *)0))
550 continue;
551
552 switch(ifa->ifa_addr->sa_family) {
553 case AF_LINK18:
554 imsg_ifinfo.link_state =
555 ((struct if_data *)ifa->ifa_data)->ifi_link_state;
556 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
557 if (sdl->sdl_type != IFT_ETHER0x06 ||
558 sdl->sdl_alen != ETHER_ADDR_LEN6)
559 continue;
560 memcpy(iface->hw_address.ether_addr_octet,
561 LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen)), ETHER_ADDR_LEN6);
562 memcpy(imsg_ifinfo.hw_address.ether_addr_octet,
563 LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen)), ETHER_ADDR_LEN6);
564 case AF_INET624:
565 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
566#ifdef __KAME__
567 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(((&sin6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sin6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
&&
568 sin6->sin6_scope_id == 0) {
569 sin6->sin6_scope_id = ntohs(*(u_int16_t *)(__uint16_t)(__builtin_constant_p(*(u_int16_t *) &sin6->
sin6_addr.__u6_addr.__u6_addr8[2]) ? (__uint16_t)(((__uint16_t
)(*(u_int16_t *) &sin6->sin6_addr.__u6_addr.__u6_addr8
[2]) & 0xffU) << 8 | ((__uint16_t)(*(u_int16_t *) &
sin6->sin6_addr.__u6_addr.__u6_addr8[2]) & 0xff00U) >>
8) : __swap16md(*(u_int16_t *) &sin6->sin6_addr.__u6_addr
.__u6_addr8[2]))
570 &sin6->sin6_addr.s6_addr[2])(__uint16_t)(__builtin_constant_p(*(u_int16_t *) &sin6->
sin6_addr.__u6_addr.__u6_addr8[2]) ? (__uint16_t)(((__uint16_t
)(*(u_int16_t *) &sin6->sin6_addr.__u6_addr.__u6_addr8
[2]) & 0xffU) << 8 | ((__uint16_t)(*(u_int16_t *) &
sin6->sin6_addr.__u6_addr.__u6_addr8[2]) & 0xff00U) >>
8) : __swap16md(*(u_int16_t *) &sin6->sin6_addr.__u6_addr
.__u6_addr8[2]))
;
571 sin6->sin6_addr.s6_addr__u6_addr.__u6_addr8[2] =
572 sin6->sin6_addr.s6_addr__u6_addr.__u6_addr8[3] = 0;
573 }
574#endif
575 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(((&sin6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sin6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
) {
576 memcpy(&imsg_ifinfo.ll_address, sin6,
577 sizeof(imsg_ifinfo.ll_address));
578
579 if (!iface->ll_tentative)
580 break;
581
582 memset(&ifr6, 0, sizeof(ifr6));
583 strlcpy(ifr6.ifr_name, if_name,
584 sizeof(ifr6.ifr_name));
585 memcpy(&ifr6.ifr_addrifr_ifru.ifru_addr, sin6,
586 sizeof(ifr6.ifr_addrifr_ifru.ifru_addr));
587
588 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct in6_ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((73)))
,
589 (caddr_t)&ifr6) == -1) {
590 log_warn("SIOCGIFAFLAG_IN6");
591 break;
592 }
593
594 if (!(ifr6.ifr_ifru.ifru_flags6 &
595 IN6_IFF_TENTATIVE0x02)) {
596 iface->ll_tentative = 0;
597 if (iface->send_solicitation)
598 send_solicitation(
599 iface->if_index);
600 }
601 }
602 break;
603 default:
604 break;
605 }
606 }
607
608 freeifaddrs(ifap);
609
610 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo,
611 sizeof(imsg_ifinfo));
612}
613
614#ifndef SMALL
615const char*
616flags_to_str(int flags)
617{
618 static char buf[sizeof(" anycast tentative duplicated detached "
619 "deprecated autoconf temporary")];
620
621 buf[0] = '\0';
622 if (flags & IN6_IFF_ANYCAST0x01)
623 strlcat(buf, " anycast", sizeof(buf));
624 if (flags & IN6_IFF_TENTATIVE0x02)
625 strlcat(buf, " tentative", sizeof(buf));
626 if (flags & IN6_IFF_DUPLICATED0x04)
627 strlcat(buf, " duplicated", sizeof(buf));
628 if (flags & IN6_IFF_DETACHED0x08)
629 strlcat(buf, " detached", sizeof(buf));
630 if (flags & IN6_IFF_DEPRECATED0x10)
631 strlcat(buf, " deprecated", sizeof(buf));
632 if (flags & IN6_IFF_AUTOCONF0x40)
633 strlcat(buf, " autoconf", sizeof(buf));
634 if (flags & IN6_IFF_TEMPORARY0x80)
635 strlcat(buf, " temporary", sizeof(buf));
636
637 return (buf);
638}
639#endif /* SMALL */
640
641void
642frontend_startup(void)
643{
644 struct if_nameindex *ifnidxp, *ifnidx;
645
646 if (!event_initialized(&ev_route)((&ev_route)->ev_flags & 0x80))
647 fatalx("%s: did not receive a route socket from the main "
648 "process", __func__);
649
650 event_add(&ev_route, NULL((void *)0));
651
652 if ((ifnidxp = if_nameindex()) == NULL((void *)0))
653 fatalx("if_nameindex");
654
655 for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL((void *)0);
656 ifnidx++)
657 update_iface(ifnidx->if_index, ifnidx->if_name);
658
659 if_freenameindex(ifnidxp);
660}
661
662void
663route_receive(int fd, short events, void *arg)
664{
665 static uint8_t *buf;
666
667 struct rt_msghdr *rtm;
668 struct sockaddr *sa, *rti_info[RTAX_MAX15];
669 ssize_t n;
670
671 if (buf == NULL((void *)0)) {
672 buf = malloc(ROUTE_SOCKET_BUF_SIZE16384);
673 if (buf == NULL((void *)0))
674 fatal("malloc");
675 }
676 rtm = (struct rt_msghdr *)buf;
677 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE16384)) == -1) {
678 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
679 return;
680 log_warn("dispatch_rtmsg: read error");
681 return;
682 }
683
684 if (n == 0)
685 fatal("routing socket closed");
686
687 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
688 log_warnx("partial rtm of %zd in buffer", n);
689 return;
690 }
691
692 if (rtm->rtm_version != RTM_VERSION5)
693 return;
694
695 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
696 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
697
698 handle_route_message(rtm, rti_info);
699}
700
701void
702handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
703{
704 struct if_msghdr *ifm;
705 struct if_announcemsghdr *ifan;
706 struct imsg_del_addr del_addr;
707 struct imsg_del_route del_route;
708 struct imsg_dup_addr dup_addr;
709 struct sockaddr_rtlabel *rl;
710 struct sockaddr_in6 *sin6;
711 struct in6_ifreq ifr6;
712 struct in6_addr *in6;
713 int xflags, if_index;
714 char ifnamebuf[IFNAMSIZ16];
715 char *if_name;
716
717 switch (rtm->rtm_type) {
718 case RTM_IFINFO0xe:
719 ifm = (struct if_msghdr *)rtm;
720 if_index = ifm->ifm_index;
721 if_name = if_indextoname(if_index, ifnamebuf);
722 if (if_name == NULL((void *)0)) {
723 log_debug("RTM_IFINFO: lost if %d", if_index);
724 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
725 &if_index, sizeof(if_index));
726 remove_iface(if_index);
727 break;
728 }
729 xflags = get_xflags(if_name);
730 if (xflags == -1 || !(xflags & (IFXF_AUTOCONF60x20 |
731 IFXF_AUTOCONF6TEMP0x4))) {
732 log_debug("RTM_IFINFO: %s(%d) no(longer) autoconf6",
733 if_name, if_index);
734 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
735 0, &if_index, sizeof(if_index));
736 remove_iface(if_index);
737 } else {
738 update_iface(if_index, if_name);
739 }
740 break;
741 case RTM_IFANNOUNCE0xf:
742 ifan = (struct if_announcemsghdr *)rtm;
743 if_index = ifan->ifan_index;
744 if (ifan->ifan_what == IFAN_DEPARTURE1) {
745 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
746 &if_index, sizeof(if_index));
747 remove_iface(if_index);
748 }
749 break;
750 case RTM_NEWADDR0xc:
751 ifm = (struct if_msghdr *)rtm;
752 if_index = ifm->ifm_index;
753 if_name = if_indextoname(if_index, ifnamebuf);
754 if (if_name == NULL((void *)0)) {
755 log_debug("RTM_NEWADDR: lost if %d", if_index);
756 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
757 &if_index, sizeof(if_index));
758 remove_iface(if_index);
759 break;
760 }
761
762 log_debug("RTM_NEWADDR: %s[%u]", if_name, if_index);
763 update_iface(if_index, if_name);
764 break;
765 case RTM_DELADDR0xd:
766 ifm = (struct if_msghdr *)rtm;
767 if_index = ifm->ifm_index;
768 if_name = if_indextoname(if_index, ifnamebuf);
769 if (if_name == NULL((void *)0)) {
770 log_debug("RTM_DELADDR: lost if %d", if_index);
771 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
772 &if_index, sizeof(if_index));
773 remove_iface(if_index);
774 break;
775 }
776 if (rtm->rtm_addrs & RTA_IFA0x20 && rti_info[RTAX_IFA5]->sa_family
777 == AF_INET624) {
778 del_addr.if_index = if_index;
779 memcpy(&del_addr.addr, rti_info[RTAX_IFA5], sizeof(
780 del_addr.addr));
781 frontend_imsg_compose_engine(IMSG_DEL_ADDRESS,
782 0, 0, &del_addr, sizeof(del_addr));
783 log_debug("RTM_DELADDR: %s[%u]", if_name, if_index);
784 }
785 break;
786 case RTM_CHGADDRATTR0x14:
787 ifm = (struct if_msghdr *)rtm;
788 if_index = ifm->ifm_index;
789 if_name = if_indextoname(if_index, ifnamebuf);
790 if (if_name == NULL((void *)0)) {
791 log_debug("RTM_CHGADDRATTR: lost if %d", if_index);
792 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
793 &if_index, sizeof(if_index));
794 remove_iface(if_index);
795 break;
796 }
797 if (rtm->rtm_addrs & RTA_IFA0x20 && rti_info[RTAX_IFA5]->sa_family
798 == AF_INET624) {
799 sin6 = (struct sockaddr_in6 *) rti_info[RTAX_IFA5];
800
801 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(((&sin6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sin6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
) {
802 update_iface(if_index, if_name);
803 break;
804 }
805
806 memset(&ifr6, 0, sizeof(ifr6));
807 strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
808 memcpy(&ifr6.ifr_addrifr_ifru.ifru_addr, sin6, sizeof(ifr6.ifr_addrifr_ifru.ifru_addr));
809
810 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct in6_ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((73)))
, (caddr_t)&ifr6)
811 == -1) {
812 log_warn("SIOCGIFAFLAG_IN6");
813 break;
814 }
815
816#ifndef SMALL
817 log_debug("RTM_CHGADDRATTR: %s - %s",
818 sin6_to_str(sin6),
819 flags_to_str(ifr6.ifr_ifru.ifru_flags6));
820#endif /* SMALL */
821
822 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED0x04) {
823 dup_addr.if_index = if_index;
824 dup_addr.addr = *sin6;
825 frontend_imsg_compose_engine(IMSG_DUP_ADDRESS,
826 0, 0, &dup_addr, sizeof(dup_addr));
827 }
828
829 }
830 break;
831 case RTM_DELETE0x2:
832 ifm = (struct if_msghdr *)rtm;
833 if ((rtm->rtm_addrs & (RTA_DST0x1 | RTA_GATEWAY0x2 | RTA_LABEL0x400)) !=
834 (RTA_DST0x1 | RTA_GATEWAY0x2 | RTA_LABEL0x400))
835 break;
836 if (rti_info[RTAX_DST0]->sa_family != AF_INET624)
837 break;
838 if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)((*(const u_int32_t *)(const void *)(&(&((struct sockaddr_in6
*) rti_info[0])->sin6_addr)->__u6_addr.__u6_addr8[0]) ==
0) && (*(const u_int32_t *)(const void *)(&(&
((struct sockaddr_in6 *) rti_info[0])->sin6_addr)->__u6_addr
.__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void
*)(&(&((struct sockaddr_in6 *) rti_info[0])->sin6_addr
)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t
*)(const void *)(&(&((struct sockaddr_in6 *) rti_info
[0])->sin6_addr)->__u6_addr.__u6_addr8[12]) == 0))
839 rti_info[RTAX_DST])->sin6_addr)((*(const u_int32_t *)(const void *)(&(&((struct sockaddr_in6
*) rti_info[0])->sin6_addr)->__u6_addr.__u6_addr8[0]) ==
0) && (*(const u_int32_t *)(const void *)(&(&
((struct sockaddr_in6 *) rti_info[0])->sin6_addr)->__u6_addr
.__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void
*)(&(&((struct sockaddr_in6 *) rti_info[0])->sin6_addr
)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t
*)(const void *)(&(&((struct sockaddr_in6 *) rti_info
[0])->sin6_addr)->__u6_addr.__u6_addr8[12]) == 0))
)
840 break;
841 if (rti_info[RTAX_GATEWAY1]->sa_family != AF_INET624)
842 break;
843 if (rti_info[RTAX_LABEL10]->sa_len !=
844 sizeof(struct sockaddr_rtlabel))
845 break;
846
847 rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL10];
848 if (strcmp(rl->sr_label, SLAACD_RTA_LABEL"slaacd") != 0)
849 break;
850 if_index = ifm->ifm_index;
851 if_name = if_indextoname(if_index, ifnamebuf);
852 if (if_name == NULL((void *)0)) {
853 log_debug("RTM_DELETE: lost if %d", if_index);
854 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
855 &if_index, sizeof(if_index));
856 remove_iface(if_index);
857 break;
858 }
859
860 del_route.if_index = if_index;
861 memcpy(&del_route.gw, rti_info[RTAX_GATEWAY1],
862 sizeof(del_route.gw));
863 in6 = &del_route.gw.sin6_addr;
864#ifdef __KAME__
865 /* XXX from route(8) p_sockaddr() */
866 if ((IN6_IS_ADDR_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xfe) && (((in6
)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80))
||
867 IN6_IS_ADDR_MC_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))
||
868 IN6_IS_ADDR_MC_INTFACELOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x01))
) &&
869 del_route.gw.sin6_scope_id == 0) {
870 del_route.gw.sin6_scope_id =
871 (u_int32_t)ntohs(*(u_short *) &in6->s6_addr[2])(__uint16_t)(__builtin_constant_p(*(u_short *) &in6->__u6_addr
.__u6_addr8[2]) ? (__uint16_t)(((__uint16_t)(*(u_short *) &
in6->__u6_addr.__u6_addr8[2]) & 0xffU) << 8 | ((
__uint16_t)(*(u_short *) &in6->__u6_addr.__u6_addr8[2]
) & 0xff00U) >> 8) : __swap16md(*(u_short *) &in6
->__u6_addr.__u6_addr8[2]))
;
872 *(u_short *)&in6->s6_addr__u6_addr.__u6_addr8[2] = 0;
873 }
874#endif
875 frontend_imsg_compose_engine(IMSG_DEL_ROUTE,
876 0, 0, &del_route, sizeof(del_route));
877 log_debug("RTM_DELETE: %s[%u]", if_name,
878 ifm->ifm_index);
879
880 break;
881#ifndef SMALL
882 case RTM_PROPOSAL0x13:
883 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT62) {
884 log_debug("RTP_PROPOSAL_SOLICIT");
885 frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS,
886 0, 0, NULL((void *)0), 0);
887 }
888 break;
889#endif /* SMALL */
890 default:
891 log_debug("unexpected RTM: %d", rtm->rtm_type);
892 break;
893 }
894
895}
896
897#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
898 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
899
900void
901get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
902{
903 int i;
904
905 for (i = 0; i < RTAX_MAX15; i++) {
906 if (addrs & (1 << i)) {
907 rti_info[i] = sa;
908 sa = (struct sockaddr *)((char *)(sa) +
909 ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
);
910 } else
911 rti_info[i] = NULL((void *)0);
912 }
913}
914
915void
916icmp6_receive(int fd, short events, void *arg)
917{
918 struct imsg_ra ra;
919 struct icmp6_hdr *icmp6_hdr;
920 struct icmp6_ev *icmp6ev;
921 struct in6_pktinfo *pi = NULL((void *)0);
922 struct cmsghdr *cm;
923 ssize_t len;
924 int if_index = 0, *hlimp = NULL((void *)0);
925 char ntopbuf[INET6_ADDRSTRLEN46];
926#ifndef SMALL
927 char ifnamebuf[IFNAMSIZ16];
928#endif /* SMALL */
929
930 icmp6ev = arg;
931 if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) {
932 log_warn("recvmsg");
933 return;
934 }
935
936 if ((size_t)len < sizeof(struct icmp6_hdr))
937 return;
938
939 icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer;
940 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT134)
941 return;
942
943 /* extract optional information via Advanced API */
944 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr)((&icmp6ev->rcvmhdr)->msg_controllen >= sizeof(struct
cmsghdr) ? (struct cmsghdr *)(&icmp6ev->rcvmhdr)->
msg_control : (struct cmsghdr *)((void *)0))
; cm;
945 cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)(((char *)(cm) + (((unsigned long)((cm)->cmsg_len) + (sizeof
(long) - 1)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof
(struct cmsghdr)) + (sizeof(long) - 1)) &~(sizeof(long) -
1)) > ((char *)(&icmp6ev->rcvmhdr)->msg_control
) + (&icmp6ev->rcvmhdr)->msg_controllen) ? (struct cmsghdr
*)((void *)0) : (struct cmsghdr *)((char *)(cm) + (((unsigned
long)((cm)->cmsg_len) + (sizeof(long) - 1)) &~(sizeof
(long) - 1))))
) {
946 if (cm->cmsg_level == IPPROTO_IPV641 &&
947 cm->cmsg_type == IPV6_PKTINFO46 &&
948 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(struct in6_pktinfo)))
) {
949 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
);
950 if_index = pi->ipi6_ifindex;
951 }
952 if (cm->cmsg_level == IPPROTO_IPV641 &&
953 cm->cmsg_type == IPV6_HOPLIMIT47 &&
954 cm->cmsg_len == CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(int)))
)
955 hlimp = (int *)CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
956 }
957
958 if (if_index == 0) {
959 log_warnx("failed to get receiving interface");
960 return;
961 }
962
963 if (hlimp == NULL((void *)0)) {
964 log_warnx("failed to get receiving hop limit");
965 return;
966 }
967
968 if (*hlimp != 255) {
969 log_warnx("invalid RA with hop limit of %d from %s on %s",
970 *hlimp, inet_ntop(AF_INET624, &icmp6ev->from.sin6_addr,
971 ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(if_index,
972 ifnamebuf));
973 return;
974 }
975
976 if ((size_t)len > sizeof(ra.packet)) {
977 log_warnx("invalid RA with size %ld from %s on %s",
978 len, inet_ntop(AF_INET624, &icmp6ev->from.sin6_addr,
979 ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(if_index,
980 ifnamebuf));
981 return;
982 }
983 ra.if_index = if_index;
984 memcpy(&ra.from, &icmp6ev->from, sizeof(ra.from));
985 ra.len = len;
986 memcpy(ra.packet, icmp6ev->answer, len);
987
988 frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra));
989}
990
991void
992send_solicitation(uint32_t if_index)
993{
994 struct in6_pktinfo *pi;
995 struct cmsghdr *cm;
996 struct iface *iface;
997
998 log_debug("%s(%u)", __func__, if_index);
999
1000 if ((iface = get_iface_by_id(if_index)) == NULL((void *)0))
14
Assuming the condition is false
15
Taking false branch
1001 return;
1002
1003 if (!event_initialized(&iface->icmp6ev->ev)((&iface->icmp6ev->ev)->ev_flags & 0x80)) {
16
Assuming the condition is false
17
Taking false branch
1004 iface->send_solicitation = 1;
1005 return;
1006 } else if (iface->ll_tentative) {
18
Assuming field 'll_tentative' is 0
19
Taking false branch
1007 iface->send_solicitation = 1;
1008 return;
1009 }
1010
1011 iface->send_solicitation = 0;
1012
1013 dst.sin6_scope_id = if_index;
1014
1015 cm = CMSG_FIRSTHDR(&sndmhdr)((&sndmhdr)->msg_controllen >= sizeof(struct cmsghdr
) ? (struct cmsghdr *)(&sndmhdr)->msg_control : (struct
cmsghdr *)((void *)0))
;
20
Assuming the condition is false
21
'?' condition is false
22
Null pointer value stored to 'cm'
1016 pi = (struct in6_pktinfo *)CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
23
Null pointer value stored to 'pi'
1017 pi->ipi6_ifindex = if_index;
24
Access to field 'ipi6_ifindex' results in a dereference of a null pointer (loaded from variable 'pi')
1018
1019 memcpy(&nd_opt_source_link_addr, &iface->hw_address,
1020 sizeof(nd_opt_source_link_addr));
1021
1022 if (sendmsg(EVENT_FD(&iface->icmp6ev->ev)(int)(&iface->icmp6ev->ev)->ev_fd, &sndmhdr, 0) != sizeof(rs) +
1023 sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr))
1024 log_warn("sendmsg");
1025}
1026
1027struct iface*
1028get_iface_by_id(uint32_t if_index)
1029{
1030 struct iface *iface;
1031
1032 LIST_FOREACH (iface, &interfaces, entries)for((iface) = ((&interfaces)->lh_first); (iface)!= ((void
*)0); (iface) = ((iface)->entries.le_next))
{
1033 if (iface->if_index == if_index)
1034 return (iface);
1035 }
1036
1037 return (NULL((void *)0));
1038}
1039
1040void
1041remove_iface(uint32_t if_index)
1042{
1043 struct iface *iface;
1044
1045 iface = get_iface_by_id(if_index);
1046
1047 if (iface == NULL((void *)0))
1048 return;
1049
1050 LIST_REMOVE(iface, entries)do { if ((iface)->entries.le_next != ((void *)0)) (iface)->
entries.le_next->entries.le_prev = (iface)->entries.le_prev
; *(iface)->entries.le_prev = (iface)->entries.le_next;
; ; } while (0)
;
1051
1052 unref_icmp6ev(iface);
1053 free(iface);
1054}
1055
1056struct icmp6_ev*
1057get_icmp6ev_by_rdomain(int rdomain)
1058{
1059 struct iface *iface;
1060 struct icmp6_ev *icmp6ev = NULL((void *)0);
1061
1062 LIST_FOREACH (iface, &interfaces, entries)for((iface) = ((&interfaces)->lh_first); (iface)!= ((void
*)0); (iface) = ((iface)->entries.le_next))
{
1063 if (iface->rdomain == rdomain) {
1064 icmp6ev = iface->icmp6ev;
1065 break;
1066 }
1067 }
1068
1069 if (icmp6ev == NULL((void *)0)) {
1070 if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL((void *)0))
1071 fatal("calloc");
1072 icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer;
1073 icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer);
1074 icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from;
1075 icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from);
1076 icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov;
1077 icmp6ev->rcvmhdr.msg_iovlen = 1;
1078 icmp6ev->rcvmhdr.msg_controllen =
1079 CMSG_SPACE(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(struct
in6_pktinfo)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)
))
+
1080 CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int))
+ (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
1081 if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev->
1082 rcvmhdr.msg_controllen)) == NULL((void *)0))
1083 fatal("malloc");
1084 frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0,
1085 &rdomain, sizeof(rdomain));
1086 }
1087 icmp6ev->refcnt++;
1088 return (icmp6ev);
1089}
1090
1091void
1092unref_icmp6ev(struct iface *iface)
1093{
1094 struct icmp6_ev *icmp6ev = iface->icmp6ev;
1095
1096 iface->icmp6ev = NULL((void *)0);
1097
1098 if (icmp6ev != NULL((void *)0)) {
1099 icmp6ev->refcnt--;
1100 if (icmp6ev->refcnt == 0) {
1101 event_del(&icmp6ev->ev);
1102 close(EVENT_FD(&icmp6ev->ev)(int)(&icmp6ev->ev)->ev_fd);
1103 free(icmp6ev);
1104 }
1105 }
1106}
1107
1108void
1109set_icmp6sock(int icmp6sock, int rdomain)
1110{
1111 struct iface *iface;
1112
1113 LIST_FOREACH (iface, &interfaces, entries)for((iface) = ((&interfaces)->lh_first); (iface)!= ((void
*)0); (iface) = ((iface)->entries.le_next))
{
1114 if (!event_initialized(&iface->icmp6ev->ev)((&iface->icmp6ev->ev)->ev_flags & 0x80) && iface->rdomain
1115 == rdomain) {
1116 event_set(&iface->icmp6ev->ev, icmp6sock, EV_READ0x02 |
1117 EV_PERSIST0x10, icmp6_receive, iface->icmp6ev);
1118 event_add(&iface->icmp6ev->ev, NULL((void *)0));
1119 icmp6sock = -1;
1120 break;
1121 }
1122 }
1123
1124 if (icmp6sock != -1) {
1125 /*
1126 * The interface disappeared or changed rdomain while we were
1127 * waiting for the parent process to open the raw socket.
1128 */
1129 close(icmp6sock);
1130 return;
1131 }
1132
1133 LIST_FOREACH (iface, &interfaces, entries)for((iface) = ((&interfaces)->lh_first); (iface)!= ((void
*)0); (iface) = ((iface)->entries.le_next))
{
1134 if (event_initialized(&iface->icmp6ev->ev)((&iface->icmp6ev->ev)->ev_flags & 0x80) &&
1135 iface->send_solicitation)
1136 send_solicitation(iface->if_index);
1137 }
1138}