Bug Summary

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