Bug Summary

File:src/usr.sbin/rad/frontend.c
Warning:line 390, 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 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/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/frontend.c
1/* $OpenBSD: frontend.c,v 1.39 2021/01/19 16:54:48 florian Exp $ */
2
3/*
4 * Copyright (c) 2018 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
22/*
23 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. Neither the name of the project nor the names of its contributors
35 * may be used to endorse or promote products derived from this software
36 * without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 */
50
51#include <sys/types.h>
52#include <sys/ioctl.h>
53#include <sys/queue.h>
54#include <sys/socket.h>
55#include <sys/syslog.h>
56#include <sys/uio.h>
57
58#include <net/if.h>
59#include <net/if_types.h>
60#include <net/route.h>
61
62#include <arpa/inet.h>
63
64#include <netinet/in.h>
65#include <netinet/if_ether.h>
66#include <netinet6/nd6.h>
67#include <netinet6/in6_var.h>
68#include <netinet/ip6.h>
69#include <netinet6/ip6_var.h>
70#include <netinet/icmp6.h>
71
72#include <ctype.h>
73#include <errno(*__errno()).h>
74#include <event.h>
75#include <ifaddrs.h>
76#include <imsg.h>
77#include <pwd.h>
78#include <signal.h>
79#include <stdio.h>
80#include <stdlib.h>
81#include <string.h>
82#include <unistd.h>
83
84#include "log.h"
85#include "rad.h"
86#include "frontend.h"
87#include "control.h"
88
89#define RA_MAX_SIZE1500 1500
90#define ROUTE_SOCKET_BUF_SIZE16384 16384
91
92struct icmp6_ev {
93 struct event ev;
94 uint8_t answer[1500];
95 struct msghdr rcvmhdr;
96 struct iovec rcviov[1];
97 struct sockaddr_in6 from;
98 int refcnt;
99};
100
101struct ra_iface {
102 TAILQ_ENTRY(ra_iface)struct { struct ra_iface *tqe_next; struct ra_iface **tqe_prev
; }
entry;
103 struct icmp6_ev *icmp6ev;
104 struct ra_prefix_conf_head prefixes;
105 char name[IF_NAMESIZE16];
106 char conf_name[IF_NAMESIZE16];
107 uint32_t if_index;
108 int rdomain;
109 int removed;
110 int link_state;
111 int prefix_count;
112 size_t datalen;
113 uint8_t data[RA_MAX_SIZE1500];
114};
115
116TAILQ_HEAD(, ra_iface)struct { struct ra_iface *tqh_first; struct ra_iface **tqh_last
; }
ra_interfaces;
117
118__dead__attribute__((__noreturn__)) void frontend_shutdown(void);
119void frontend_sig_handler(int, short, void *);
120void frontend_startup(void);
121void icmp6_receive(int, short, void *);
122void join_all_routers_mcast_group(struct ra_iface *);
123void leave_all_routers_mcast_group(struct ra_iface *);
124int get_link_state(char *);
125int get_ifrdomain(char *);
126void merge_ra_interface(char *, char *);
127void merge_ra_interfaces(void);
128struct ra_iface *find_ra_iface_by_id(uint32_t);
129struct ra_iface *find_ra_iface_by_name(char *);
130struct ra_iface_conf *find_ra_iface_conf(struct ra_iface_conf_head *,
131 char *);
132struct ra_prefix_conf *find_ra_prefix_conf(struct ra_prefix_conf_head*,
133 struct in6_addr *, int);
134struct icmp6_ev *get_icmp6ev_by_rdomain(int);
135void unref_icmp6ev(struct ra_iface *);
136void set_icmp6sock(int, int);
137void add_new_prefix_to_ra_iface(struct ra_iface *r,
138 struct in6_addr *, int, struct ra_prefix_conf *);
139void free_ra_iface(struct ra_iface *);
140int in6_mask2prefixlen(struct in6_addr *);
141void get_interface_prefixes(struct ra_iface *,
142 struct ra_prefix_conf *);
143int interface_has_linklocal_address(char *);
144void build_packet(struct ra_iface *);
145void build_leaving_packet(struct ra_iface *);
146void ra_output(struct ra_iface *, struct sockaddr_in6 *);
147void get_rtaddrs(int, struct sockaddr *,
148 struct sockaddr **);
149void route_receive(int, short, void *);
150void handle_route_message(struct rt_msghdr *,
151 struct sockaddr **);
152
153struct rad_conf *frontend_conf;
154static struct imsgev *iev_main;
155static struct imsgev *iev_engine;
156struct event ev_route;
157int ioctlsock = -1, routesock = -1;
158struct ipv6_mreq all_routers;
159struct msghdr sndmhdr;
160struct iovec sndiov[2];
161
162void
163frontend_sig_handler(int sig, short event, void *bula)
164{
165 /*
166 * Normal signal handler rules don't apply because libevent
167 * decouples for us.
168 */
169
170 switch (sig) {
171 case SIGINT2:
172 case SIGTERM15:
173 frontend_shutdown();
174 default:
175 fatalx("unexpected signal");
176 }
177}
178
179void
180frontend(int debug, int verbose)
181{
182 struct event ev_sigint, ev_sigterm;
183 struct passwd *pw;
184 size_t sndcmsgbuflen;
185 uint8_t *sndcmsgbuf = NULL((void *)0);
186
187 frontend_conf = config_new_empty();
188
189 log_init(debug, LOG_DAEMON(3<<3));
190 log_setverbose(verbose);
191
192 if ((pw = getpwnam(RAD_USER"_rad")) == NULL((void *)0))
193 fatal("getpwnam");
194
195 if (chroot(pw->pw_dir) == -1)
196 fatal("chroot");
197 if (chdir("/") == -1)
198 fatal("chdir(\"/\")");
199
200 setproctitle("%s", "frontend");
201 log_procinit("frontend");
202
203 if (setgroups(1, &pw->pw_gid) ||
204 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
205 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
206 fatal("can't drop privileges");
207
208 /* XXX pass in from main */
209 if ((ioctlsock = socket(AF_INET624, SOCK_DGRAM2 | SOCK_CLOEXEC0x8000, 0)) == -1)
210 fatal("socket");
211
212 if (pledge("stdio inet unix recvfd route mcast", NULL((void *)0)) == -1)
213 fatal("pledge");
214
215 event_init();
216
217 /* Setup signal handler. */
218 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, frontend_sig_handler,
((void *)0))
;
219 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, frontend_sig_handler
, ((void *)0))
;
220 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
221 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
222 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
223 signal(SIGHUP1, SIG_IGN(void (*)(int))1);
224
225 /* Setup pipe and event handler to the parent process. */
226 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL((void *)0))
227 fatal(NULL((void *)0));
228 imsg_init(&iev_main->ibuf, 3);
229 iev_main->handler = frontend_dispatch_main;
230 iev_main->events = EV_READ0x02;
231 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
232 iev_main->handler, iev_main);
233 event_add(&iev_main->ev, NULL((void *)0));
234
235 if (inet_pton(AF_INET624, "ff02::2",
236 &all_routers.ipv6mr_multiaddr.s6_addr__u6_addr.__u6_addr8) == -1)
237 fatal("inet_pton");
238
239 sndcmsgbuflen = 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)
))
+
240 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)))
;
241 if ((sndcmsgbuf = malloc(sndcmsgbuflen)) == NULL((void *)0))
242 fatal("%s", __func__);
243
244 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
245 sndmhdr.msg_iov = sndiov;
246 sndmhdr.msg_iovlen = 1;
247 sndmhdr.msg_control = sndcmsgbuf;
248 sndmhdr.msg_controllen = sndcmsgbuflen;
249
250 TAILQ_INIT(&ra_interfaces)do { (&ra_interfaces)->tqh_first = ((void *)0); (&
ra_interfaces)->tqh_last = &(&ra_interfaces)->tqh_first
; } while (0)
;
251
252 event_dispatch();
253
254 frontend_shutdown();
255}
256
257__dead__attribute__((__noreturn__)) void
258frontend_shutdown(void)
259{
260 /* Close pipes. */
261 msgbuf_write(&iev_engine->ibuf.w);
262 msgbuf_clear(&iev_engine->ibuf.w);
263 close(iev_engine->ibuf.fd);
264 msgbuf_write(&iev_main->ibuf.w);
265 msgbuf_clear(&iev_main->ibuf.w);
266 close(iev_main->ibuf.fd);
267
268 config_clear(frontend_conf);
269
270 free(iev_engine);
271 free(iev_main);
272
273 log_info("frontend exiting");
274 exit(0);
275}
276
277int
278frontend_imsg_compose_main(int type, pid_t pid, void *data, uint16_t datalen)
279{
280 return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
281 datalen));
282}
283
284int
285frontend_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen)
286{
287 return (imsg_compose_event(iev_engine, type, 0, pid, -1, data,
288 datalen));
289}
290
291void
292frontend_dispatch_main(int fd, short event, void *bula)
293{
294 static struct rad_conf *nconf;
295 static struct ra_iface_conf *ra_iface_conf;
1
'ra_iface_conf' initialized to a null pointer value
296 static struct ra_options_conf *ra_options;
297 struct imsg imsg;
298 struct imsgev *iev = bula;
299 struct imsgbuf *ibuf = &iev->ibuf;
300 struct ra_prefix_conf *ra_prefix_conf;
301 struct ra_rdnss_conf *ra_rdnss_conf;
302 struct ra_dnssl_conf *ra_dnssl_conf;
303 int n, shut = 0, icmp6sock, rdomain;
304
305 if (event & EV_READ0x02) {
2
Assuming the condition is false
3
Taking false branch
306 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
307 fatal("imsg_read error");
308 if (n == 0) /* Connection closed. */
309 shut = 1;
310 }
311 if (event & EV_WRITE0x04) {
4
Assuming the condition is false
5
Taking false branch
312 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
313 fatal("msgbuf_write");
314 if (n == 0) /* Connection closed. */
315 shut = 1;
316 }
317
318 for (;;) {
6
Loop condition is true. Entering loop body
319 if ((n = imsg_get(ibuf, &imsg)) == -1)
7
Assuming the condition is false
8
Taking false branch
320 fatal("%s: imsg_get error", __func__);
321 if (n == 0) /* No more messages. */
9
Assuming 'n' is not equal to 0
10
Taking false branch
322 break;
323
324 switch (imsg.hdr.type) {
11
Control jumps to 'case IMSG_RECONF_RA_AUTOPREFIX:' at line 384
325 case IMSG_SOCKET_IPC:
326 /*
327 * Setup pipe and event handler to the engine
328 * process.
329 */
330 if (iev_engine)
331 fatalx("%s: received unexpected imsg fd to "
332 "frontend", __func__);
333 if ((fd = imsg.fd) == -1)
334 fatalx("%s: expected to receive imsg fd to "
335 "frontend but didn't receive any",
336 __func__);
337
338 iev_engine = malloc(sizeof(struct imsgev));
339 if (iev_engine == NULL((void *)0))
340 fatal(NULL((void *)0));
341
342 imsg_init(&iev_engine->ibuf, fd);
343 iev_engine->handler = frontend_dispatch_engine;
344 iev_engine->events = EV_READ0x02;
345
346 event_set(&iev_engine->ev, iev_engine->ibuf.fd,
347 iev_engine->events, iev_engine->handler, iev_engine);
348 event_add(&iev_engine->ev, NULL((void *)0));
349 break;
350 case IMSG_RECONF_CONF:
351 if (nconf != NULL((void *)0))
352 fatalx("%s: IMSG_RECONF_CONF already in "
353 "progress", __func__);
354 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct rad_conf))
355 fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
356 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
357 if ((nconf = malloc(sizeof(struct rad_conf))) ==
358 NULL((void *)0))
359 fatal(NULL((void *)0));
360 memcpy(nconf, imsg.data, sizeof(struct rad_conf));
361 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)
;
362 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)
;
363 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)
;
364 ra_options = &nconf->ra_options;
365 break;
366 case IMSG_RECONF_RA_IFACE:
367 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
368 ra_iface_conf))
369 fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: "
370 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
371 if ((ra_iface_conf = malloc(sizeof(struct
372 ra_iface_conf))) == NULL((void *)0))
373 fatal(NULL((void *)0));
374 memcpy(ra_iface_conf, imsg.data, sizeof(struct
375 ra_iface_conf));
376 ra_iface_conf->autoprefix = NULL((void *)0);
377 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)
;
378 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)
;
379 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)
;
380 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)
381 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)
;
382 ra_options = &ra_iface_conf->ra_options;
383 break;
384 case IMSG_RECONF_RA_AUTOPREFIX:
385 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
12
Assuming the condition is false
13
Taking false branch
386 ra_prefix_conf))
387 fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong "
388 "length: %lu", __func__,
389 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
390 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')
391 ra_prefix_conf))) == NULL((void *)0))
392 fatal(NULL((void *)0));
393 memcpy(ra_iface_conf->autoprefix, imsg.data,
394 sizeof(struct ra_prefix_conf));
395 break;
396 case IMSG_RECONF_RA_PREFIX:
397 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
398 ra_prefix_conf))
399 fatalx("%s: IMSG_RECONF_RA_PREFIX wrong "
400 "length: %lu", __func__,
401 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
402 if ((ra_prefix_conf = malloc(sizeof(struct
403 ra_prefix_conf))) == NULL((void *)0))
404 fatal(NULL((void *)0));
405 memcpy(ra_prefix_conf, imsg.data,
406 sizeof(struct ra_prefix_conf));
407 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)
408 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)
;
409 break;
410 case IMSG_RECONF_RA_RDNSS:
411 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
412 ra_rdnss_conf))
413 fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: "
414 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
415 if ((ra_rdnss_conf = malloc(sizeof(struct
416 ra_rdnss_conf))) == NULL((void *)0))
417 fatal(NULL((void *)0));
418 memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
419 ra_rdnss_conf));
420 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)
421 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)
;
422 break;
423 case IMSG_RECONF_RA_DNSSL:
424 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct
425 ra_dnssl_conf))
426 fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: "
427 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
428 if ((ra_dnssl_conf = malloc(sizeof(struct
429 ra_dnssl_conf))) == NULL((void *)0))
430 fatal(NULL((void *)0));
431 memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
432 ra_dnssl_conf));
433 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)
434 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)
;
435 break;
436 case IMSG_RECONF_END:
437 if (nconf == NULL((void *)0))
438 fatalx("%s: IMSG_RECONF_END without "
439 "IMSG_RECONF_CONF", __func__);
440 merge_config(frontend_conf, nconf);
441 merge_ra_interfaces();
442 nconf = NULL((void *)0);
443 break;
444 case IMSG_ICMP6SOCK:
445 if ((icmp6sock = imsg.fd) == -1)
446 fatalx("%s: expected to receive imsg "
447 "ICMPv6 fd but didn't receive any",
448 __func__);
449 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdomain))
450 fatalx("%s: IMSG_ICMP6SOCK wrong length: "
451 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
452 memcpy(&rdomain, imsg.data, sizeof(rdomain));
453 set_icmp6sock(icmp6sock, rdomain);
454 break;
455 case IMSG_ROUTESOCK:
456 if (routesock != -1)
457 fatalx("%s: received unexpected routesock fd",
458 __func__);
459 if ((routesock = imsg.fd) == -1)
460 fatalx("%s: expected to receive imsg "
461 "routesocket fd but didn't receive any",
462 __func__);
463 event_set(&ev_route, routesock, EV_READ0x02 | EV_PERSIST0x10,
464 route_receive, NULL((void *)0));
465 break;
466 case IMSG_STARTUP:
467 frontend_startup();
468 break;
469 case IMSG_CONTROLFD:
470 if ((fd = imsg.fd) == -1)
471 fatalx("%s: expected to receive imsg "
472 "control fd but didn't receive any",
473 __func__);
474 /* Listen on control socket. */
475 control_listen(fd);
476 break;
477 default:
478 log_debug("%s: error handling imsg %d", __func__,
479 imsg.hdr.type);
480 break;
481 }
482 imsg_free(&imsg);
483 }
484 if (!shut)
485 imsg_event_add(iev);
486 else {
487 /* This pipe is dead. Remove its event handler. */
488 event_del(&iev->ev);
489 event_loopexit(NULL((void *)0));
490 }
491}
492
493void
494frontend_dispatch_engine(int fd, short event, void *bula)
495{
496 struct imsgev *iev = bula;
497 struct imsgbuf *ibuf = &iev->ibuf;
498 struct imsg imsg;
499 struct imsg_send_ra send_ra;
500 struct ra_iface *ra_iface;
501 uint32_t if_index;
502 int n, shut = 0;
503
504 if (event & EV_READ0x02) {
505 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
506 fatal("imsg_read error");
507 if (n == 0) /* Connection closed. */
508 shut = 1;
509 }
510 if (event & EV_WRITE0x04) {
511 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
512 fatal("msgbuf_write");
513 if (n == 0) /* Connection closed. */
514 shut = 1;
515 }
516
517 for (;;) {
518 if ((n = imsg_get(ibuf, &imsg)) == -1)
519 fatal("%s: imsg_get error", __func__);
520 if (n == 0) /* No more messages. */
521 break;
522
523 switch (imsg.hdr.type) {
524 case IMSG_SEND_RA:
525 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(send_ra))
526 fatalx("%s: IMSG_SEND_RA wrong length: %lu",
527 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
528 memcpy(&send_ra, imsg.data, sizeof(send_ra));
529 ra_iface = find_ra_iface_by_id(send_ra.if_index);
530 if (ra_iface)
531 ra_output(ra_iface, &send_ra.to);
532 break;
533 case IMSG_REMOVE_IF:
534 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index))
535 fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
536 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
537 memcpy(&if_index, imsg.data, sizeof(if_index));
538 ra_iface = find_ra_iface_by_id(if_index);
539 if (ra_iface) {
540 TAILQ_REMOVE(&ra_interfaces, ra_iface, entry)do { if (((ra_iface)->entry.tqe_next) != ((void *)0)) (ra_iface
)->entry.tqe_next->entry.tqe_prev = (ra_iface)->entry
.tqe_prev; else (&ra_interfaces)->tqh_last = (ra_iface
)->entry.tqe_prev; *(ra_iface)->entry.tqe_prev = (ra_iface
)->entry.tqe_next; ; ; } while (0)
;
541 free_ra_iface(ra_iface);
542 }
543 break;
544 default:
545 log_debug("%s: error handling imsg %d", __func__,
546 imsg.hdr.type);
547 break;
548 }
549 imsg_free(&imsg);
550 }
551 if (!shut)
552 imsg_event_add(iev);
553 else {
554 /* This pipe is dead. Remove its event handler. */
555 event_del(&iev->ev);
556 event_loopexit(NULL((void *)0));
557 }
558}
559
560void
561frontend_startup(void)
562{
563 if (!event_initialized(&ev_route)((&ev_route)->ev_flags & 0x80))
564 fatalx("%s: did not receive a route socket from the main "
565 "process", __func__);
566
567 event_add(&ev_route, NULL((void *)0));
568}
569
570
571void
572icmp6_receive(int fd, short events, void *arg)
573{
574 struct icmp6_ev *icmp6ev;
575 struct icmp6_hdr *icmp6_hdr;
576 struct imsg_ra_rs ra_rs;
577 struct in6_pktinfo *pi = NULL((void *)0);
578 struct cmsghdr *cm;
579 ssize_t len;
580 int if_index = 0, *hlimp = NULL((void *)0);
581 char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16];
582
583 icmp6ev = arg;
584 if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) {
585 log_warn("recvmsg");
586 return;
587 }
588
589 if ((size_t)len < sizeof(struct icmp6_hdr))
590 return;
591
592 icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer;
593 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT134 &&
594 icmp6_hdr->icmp6_type != ND_ROUTER_SOLICIT133)
595 return;
596
597 /* extract optional information via Advanced API */
598 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;
599 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))))
) {
600 if (cm->cmsg_level == IPPROTO_IPV641 &&
601 cm->cmsg_type == IPV6_PKTINFO46 &&
602 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(struct in6_pktinfo)))
) {
603 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
);
604 if_index = pi->ipi6_ifindex;
605 }
606 if (cm->cmsg_level == IPPROTO_IPV641 &&
607 cm->cmsg_type == IPV6_HOPLIMIT47 &&
608 cm->cmsg_len == CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(int)))
)
609 hlimp = (int *)CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
610 }
611
612 if (if_index == 0) {
613 log_warnx("failed to get receiving interface");
614 return;
615 }
616
617 if (hlimp == NULL((void *)0)) {
618 log_warnx("failed to get receiving hop limit");
619 return;
620 }
621
622 if (*hlimp != 255) {
623 log_warnx("invalid RA or RS with hop limit of %d from %s on %s",
624 *hlimp, inet_ntop(AF_INET624, &icmp6ev->from.sin6_addr,
625 ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(if_index,
626 ifnamebuf));
627 return;
628 }
629
630 log_debug("RA or RS with hop limit of %d from %s on %s",
631 *hlimp, inet_ntop(AF_INET624, &icmp6ev->from.sin6_addr,
632 ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(if_index,
633 ifnamebuf));
634
635 if ((size_t)len > sizeof(ra_rs.packet)) {
636 log_warnx("invalid RA or RS with size %ld from %s on %s",
637 len, inet_ntop(AF_INET624, &icmp6ev->from.sin6_addr,
638 ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(if_index,
639 ifnamebuf));
640 return;
641 }
642
643 ra_rs.if_index = if_index;
644 memcpy(&ra_rs.from, &icmp6ev->from, sizeof(ra_rs.from));
645 ra_rs.len = len;
646 memcpy(ra_rs.packet, icmp6ev->answer, len);
647
648 frontend_imsg_compose_engine(IMSG_RA_RS, 0, &ra_rs, sizeof(ra_rs));
649}
650
651void
652join_all_routers_mcast_group(struct ra_iface *ra_iface)
653{
654 if (!event_initialized(&ra_iface->icmp6ev->ev)((&ra_iface->icmp6ev->ev)->ev_flags & 0x80))
655 return;
656 log_debug("joining multicast group on %s", ra_iface->name);
657 all_routers.ipv6mr_interface = ra_iface->if_index;
658 if (setsockopt(EVENT_FD(&ra_iface->icmp6ev->ev)(int)(&ra_iface->icmp6ev->ev)->ev_fd, IPPROTO_IPV641,
659 IPV6_JOIN_GROUP12, &all_routers, sizeof(all_routers)) == -1)
660 fatal("IPV6_JOIN_GROUP(%s)", ra_iface->name);
661}
662
663void
664leave_all_routers_mcast_group(struct ra_iface *ra_iface)
665{
666 if (!event_initialized(&ra_iface->icmp6ev->ev)((&ra_iface->icmp6ev->ev)->ev_flags & 0x80))
667 return;
668 log_debug("leaving multicast group on %s", ra_iface->name);
669 all_routers.ipv6mr_interface = ra_iface->if_index;
670 setsockopt(EVENT_FD(&ra_iface->icmp6ev->ev)(int)(&ra_iface->icmp6ev->ev)->ev_fd, IPPROTO_IPV641,
671 IPV6_LEAVE_GROUP13, &all_routers, sizeof(all_routers));
672}
673
674struct ra_iface*
675find_ra_iface_by_id(uint32_t if_index)
676{
677 struct ra_iface *ra_iface;
678
679 TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
{
680 if (ra_iface->if_index == if_index)
681 return ra_iface;
682 }
683 return (NULL((void *)0));
684}
685
686struct ra_iface*
687find_ra_iface_by_name(char *if_name)
688{
689 struct ra_iface *ra_iface;
690
691 TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
{
692 if (strcmp(ra_iface->name, if_name) == 0)
693 return ra_iface;
694 }
695 return (NULL((void *)0));
696}
697
698struct ra_iface_conf*
699find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name)
700{
701 struct ra_iface_conf *ra_iface_conf;
702
703 SIMPLEQ_FOREACH(ra_iface_conf, head, entry)for((ra_iface_conf) = ((head)->sqh_first); (ra_iface_conf)
!= ((void *)0); (ra_iface_conf) = ((ra_iface_conf)->entry
.sqe_next))
{
704 if (strcmp(ra_iface_conf->name, if_name) == 0)
705 return ra_iface_conf;
706 }
707 return (NULL((void *)0));
708}
709
710int
711get_link_state(char *if_name)
712{
713 struct ifaddrs *ifap, *ifa;
714 int ls = LINK_STATE_UNKNOWN0;
715
716 if (getifaddrs(&ifap) != 0) {
717 log_warn("getifaddrs");
718 return LINK_STATE_UNKNOWN0;
719 }
720 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
721 if (ifa->ifa_addr == NULL((void *)0) ||
722 ifa->ifa_addr->sa_family != AF_LINK18)
723 continue;
724 if (strcmp(if_name, ifa->ifa_name) != 0)
725 continue;
726
727 ls = ((struct if_data*)ifa->ifa_data)->ifi_link_state;
728 break;
729 }
730 freeifaddrs(ifap);
731 return ls;
732}
733
734int
735get_ifrdomain(char *if_name)
736{
737 struct ifreq ifr;
738
739 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
740 if (ioctl(ioctlsock, SIOCGIFRDOMAIN(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((160)))
, (caddr_t)&ifr) == -1) {
741 log_warn("SIOCGIFRDOMAIN");
742 return -1;
743 }
744 return ifr.ifr_rdomainidifr_ifru.ifru_metric;
745}
746
747void
748merge_ra_interface(char *name, char *conf_name)
749{
750 struct ra_iface *ra_iface;
751 uint32_t if_index;
752 int link_state, has_linklocal, ifrdomain;
753
754 link_state = get_link_state(name);
755 has_linklocal = interface_has_linklocal_address(name);
756 ifrdomain = get_ifrdomain(name);
757
758 if ((ra_iface = find_ra_iface_by_name(name)) != NULL((void *)0)) {
759 ra_iface->link_state = link_state;
760 if (!LINK_STATE_IS_UP(link_state)((link_state) >= 4 || (link_state) == 0)) {
761 log_debug("%s down, removing", name);
762 ra_iface->removed = 1;
763 } else if (!has_linklocal) {
764 log_debug("%s has no IPv6 link-local address, "
765 "removing", name);
766 ra_iface->removed = 1;
767 } else if (ifrdomain == -1) {
768 log_debug("can't get rdomain for %s, removing", name);
769 ra_iface->removed = 1;
770 } else if (ra_iface->rdomain != ifrdomain) {
771 leave_all_routers_mcast_group(ra_iface);
772 unref_icmp6ev(ra_iface);
773 ra_iface->rdomain = ifrdomain;
774 ra_iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain);
775 join_all_routers_mcast_group(ra_iface);
776 ra_iface->removed = 0;
777 } else {
778 log_debug("keeping interface %s", name);
779 ra_iface->removed = 0;
780 }
781 return;
782 }
783
784 if (!LINK_STATE_IS_UP(link_state)((link_state) >= 4 || (link_state) == 0)) {
785 log_debug("%s down, ignoring", name);
786 return;
787 }
788
789 if (!has_linklocal) {
790 log_debug("%s has no IPv6 link-local address, ignoring", name);
791 return;
792 }
793
794 log_debug("new interface %s", name);
795 if ((if_index = if_nametoindex(name)) == 0)
796 return;
797
798 log_debug("adding interface %s", name);
799 if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL((void *)0))
800 fatal("%s", __func__);
801
802 strlcpy(ra_iface->name, name, sizeof(ra_iface->name));
803 strlcpy(ra_iface->conf_name, conf_name,
804 sizeof(ra_iface->conf_name));
805
806 ra_iface->if_index = if_index;
807 ra_iface->rdomain = ifrdomain;
808
809 SIMPLEQ_INIT(&ra_iface->prefixes)do { (&ra_iface->prefixes)->sqh_first = ((void *)0)
; (&ra_iface->prefixes)->sqh_last = &(&ra_iface
->prefixes)->sqh_first; } while (0)
;
810
811 ra_iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain);
812 join_all_routers_mcast_group(ra_iface);
813 TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry)do { (ra_iface)->entry.tqe_next = ((void *)0); (ra_iface)->
entry.tqe_prev = (&ra_interfaces)->tqh_last; *(&ra_interfaces
)->tqh_last = (ra_iface); (&ra_interfaces)->tqh_last
= &(ra_iface)->entry.tqe_next; } while (0)
;
814}
815
816void
817merge_ra_interfaces(void)
818{
819 struct ra_iface_conf *ra_iface_conf;
820 struct ra_prefix_conf *ra_prefix_conf;
821 struct ra_iface *ra_iface;
822 struct ifgroupreq ifgr;
823 struct ifg_req *ifg;
824 char *conf_name;
825 unsigned int len;
826
827 TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
828 ra_iface->removed = 1;
829
830 SIMPLEQ_FOREACH(ra_iface_conf, &frontend_conf->ra_iface_list, entry)for((ra_iface_conf) = ((&frontend_conf->ra_iface_list)
->sqh_first); (ra_iface_conf) != ((void *)0); (ra_iface_conf
) = ((ra_iface_conf)->entry.sqe_next))
{
831 conf_name = ra_iface_conf->name;
832
833 /* check if network interface or group */
834 if (isdigit((unsigned char)conf_name[strlen(conf_name) - 1])) {
835 merge_ra_interface(conf_name, conf_name);
836 } else {
837 log_debug("interface group %s", conf_name);
838
839 memset(&ifgr, 0, sizeof(ifgr));
840 strlcpy(ifgr.ifgr_name, conf_name,
841 sizeof(ifgr.ifgr_name));
842 if (ioctl(ioctlsock, SIOCGIFGMEMB(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifgroupreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((138)))
,
843 (caddr_t)&ifgr) == -1)
844 continue;
845
846 len = ifgr.ifgr_len;
847 if ((ifgr.ifgr_groupsifgr_ifgru.ifgru_groups = calloc(1, len)) == NULL((void *)0))
848 fatal("%s: calloc", __func__);
849 if (ioctl(ioctlsock, SIOCGIFGMEMB(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifgroupreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((138)))
,
850 (caddr_t)&ifgr) == -1) {
851 log_debug("group %s without members",
852 conf_name);
853 free(ifgr.ifgr_groupsifgr_ifgru.ifgru_groups);
854 continue;
855 }
856
857 for (ifg = ifgr.ifgr_groupsifgr_ifgru.ifgru_groups;
858 (ifg != NULL((void *)0)) && (len >= sizeof(struct ifg_req));
859 ifg++) {
860 len -= sizeof(struct ifg_req);
861 merge_ra_interface(ifg->ifgrq_memberifgrq_ifgrqu.ifgrqu_member,
862 conf_name);
863 }
864 free(ifgr.ifgr_groupsifgr_ifgru.ifgru_groups);
865 }
866 }
867
868 TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
{
869 while ((ra_prefix_conf = SIMPLEQ_FIRST(&ra_iface->prefixes)((&ra_iface->prefixes)->sqh_first))
870 != NULL((void *)0)) {
871 SIMPLEQ_REMOVE_HEAD(&ra_iface->prefixes,do { if (((&ra_iface->prefixes)->sqh_first = (&
ra_iface->prefixes)->sqh_first->entry.sqe_next) == (
(void *)0)) (&ra_iface->prefixes)->sqh_last = &
(&ra_iface->prefixes)->sqh_first; } while (0)
872 entry)do { if (((&ra_iface->prefixes)->sqh_first = (&
ra_iface->prefixes)->sqh_first->entry.sqe_next) == (
(void *)0)) (&ra_iface->prefixes)->sqh_last = &
(&ra_iface->prefixes)->sqh_first; } while (0)
;
873 free(ra_prefix_conf);
874 }
875 ra_iface->prefix_count = 0;
876
877 if (ra_iface->removed) {
878 log_debug("iface removed: %s", ra_iface->name);
879 build_leaving_packet(ra_iface);
880 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
881 &ra_iface->if_index, sizeof(ra_iface->if_index));
882 continue;
883 }
884
885 ra_iface_conf = find_ra_iface_conf(
886 &frontend_conf->ra_iface_list, ra_iface->conf_name);
887
888 log_debug("add static prefixes for %s", ra_iface->name);
889
890 SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface_conf->ra_prefix_list,for((ra_prefix_conf) = ((&ra_iface_conf->ra_prefix_list
)->sqh_first); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf
) = ((ra_prefix_conf)->entry.sqe_next))
891 entry)for((ra_prefix_conf) = ((&ra_iface_conf->ra_prefix_list
)->sqh_first); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf
) = ((ra_prefix_conf)->entry.sqe_next))
{
892 add_new_prefix_to_ra_iface(ra_iface,
893 &ra_prefix_conf->prefix,
894 ra_prefix_conf->prefixlen, ra_prefix_conf);
895 }
896
897 if (ra_iface_conf->autoprefix)
898 get_interface_prefixes(ra_iface,
899 ra_iface_conf->autoprefix);
900
901 build_packet(ra_iface);
902 }
903}
904
905void
906free_ra_iface(struct ra_iface *ra_iface)
907{
908 struct ra_prefix_conf *prefix;
909
910 leave_all_routers_mcast_group(ra_iface);
911
912 while ((prefix = SIMPLEQ_FIRST(&ra_iface->prefixes)((&ra_iface->prefixes)->sqh_first)) != NULL((void *)0)) {
913 SIMPLEQ_REMOVE_HEAD(&ra_iface->prefixes, entry)do { if (((&ra_iface->prefixes)->sqh_first = (&
ra_iface->prefixes)->sqh_first->entry.sqe_next) == (
(void *)0)) (&ra_iface->prefixes)->sqh_last = &
(&ra_iface->prefixes)->sqh_first; } while (0)
;
914 free(prefix);
915 }
916
917 unref_icmp6ev(ra_iface);
918 free(ra_iface);
919}
920
921/* from kame via ifconfig, where it's called prefix() */
922int
923in6_mask2prefixlen(struct in6_addr *in6)
924{
925 u_char *nam = (u_char *)in6;
926 int byte, bit, plen = 0, size = sizeof(struct in6_addr);
927
928 for (byte = 0; byte < size; byte++, plen += 8)
929 if (nam[byte] != 0xff)
930 break;
931 if (byte == size)
932 return (plen);
933 for (bit = 7; bit != 0; bit--, plen++)
934 if (!(nam[byte] & (1 << bit)))
935 break;
936 for (; bit != 0; bit--)
937 if (nam[byte] & (1 << bit))
938 return (0);
939 byte++;
940 for (; byte < size; byte++)
941 if (nam[byte])
942 return (0);
943 return (plen);
944}
945
946int
947interface_has_linklocal_address(char *name)
948{
949 struct ifaddrs *ifap, *ifa;
950 struct sockaddr_in6 *sin6;
951 struct in6_ifreq ifr6;
952 int ret = 0;
953
954 if (getifaddrs(&ifap) != 0)
955 fatal("getifaddrs");
956
957 for (ifa = ifap; ifa != NULL((void *)0); ifa = ifa->ifa_next) {
958 if (strcmp(name, ifa->ifa_name) != 0)
959 continue;
960 if (ifa->ifa_addr == NULL((void *)0) ||
961 ifa->ifa_addr->sa_family != AF_INET624)
962 continue;
963
964 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
965
966 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))
)
967 continue;
968
969 memset(&ifr6, 0, sizeof(ifr6));
970 strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
971 memcpy(&ifr6.ifr_addrifr_ifru.ifru_addr, sin6, sizeof(ifr6.ifr_addrifr_ifru.ifru_addr));
972 if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct in6_ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((73)))
, (caddr_t)&ifr6) == -1) {
973 log_warn("SIOCGIFAFLAG_IN6");
974 continue;
975 }
976
977 if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_TENTATIVE0x02 |
978 IN6_IFF_DUPLICATED0x04))
979 continue;
980
981 ret = 1;
982 break;
983 }
984 freeifaddrs(ifap);
985 return (ret);
986}
987
988void
989get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf
990 *autoprefix)
991{
992 struct in6_ifreq ifr6;
993 struct ifaddrs *ifap, *ifa;
994 struct sockaddr_in6 *sin6;
995 int prefixlen;
996
997 log_debug("%s: %s", __func__, ra_iface->name);
998
999 if (getifaddrs(&ifap) != 0)
1000 fatal("getifaddrs");
1001
1002 for (ifa = ifap; ifa != NULL((void *)0); ifa = ifa->ifa_next) {
1003 if (strcmp(ra_iface->name, ifa->ifa_name) != 0)
1004 continue;
1005 if (ifa->ifa_addr == NULL((void *)0) ||
1006 ifa->ifa_addr->sa_family != AF_INET624)
1007 continue;
1008
1009 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1010
1011 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))
)
1012 continue;
1013
1014 memset(&ifr6, 0, sizeof(ifr6));
1015 strlcpy(ifr6.ifr_name, ra_iface->name, sizeof(ifr6.ifr_name));
1016 memcpy(&ifr6.ifr_addrifr_ifru.ifru_addr, sin6, sizeof(ifr6.ifr_addrifr_ifru.ifru_addr));
1017
1018 if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct in6_ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((37)))
, (caddr_t)&ifr6) == -1)
1019 continue; /* addr got deleted while we were looking */
1020
1021 prefixlen = in6_mask2prefixlen(&((struct sockaddr_in6 *)
1022 &ifr6.ifr_addrifr_ifru.ifru_addr)->sin6_addr);
1023
1024 if (prefixlen == 128)
1025 continue;
1026
1027 mask_prefix(&sin6->sin6_addr, prefixlen);
1028
1029 add_new_prefix_to_ra_iface(ra_iface, &sin6->sin6_addr,
1030 prefixlen, autoprefix);
1031 }
1032 freeifaddrs(ifap);
1033}
1034
1035struct ra_prefix_conf*
1036find_ra_prefix_conf(struct ra_prefix_conf_head* head, struct in6_addr *prefix,
1037 int prefixlen)
1038{
1039 struct ra_prefix_conf *ra_prefix_conf;
1040
1041 SIMPLEQ_FOREACH(ra_prefix_conf, head, entry)for((ra_prefix_conf) = ((head)->sqh_first); (ra_prefix_conf
) != ((void *)0); (ra_prefix_conf) = ((ra_prefix_conf)->entry
.sqe_next))
{
1042 if (ra_prefix_conf->prefixlen == prefixlen &&
1043 memcmp(&ra_prefix_conf->prefix, prefix, sizeof(*prefix)) ==
1044 0)
1045 return (ra_prefix_conf);
1046 }
1047 return (NULL((void *)0));
1048}
1049
1050void
1051add_new_prefix_to_ra_iface(struct ra_iface *ra_iface, struct in6_addr *addr,
1052 int prefixlen, struct ra_prefix_conf *ra_prefix_conf)
1053{
1054 struct ra_prefix_conf *new_ra_prefix_conf;
1055
1056 if (find_ra_prefix_conf(&ra_iface->prefixes, addr, prefixlen)) {
1057 log_debug("ignoring duplicate %s/%d prefix",
1058 in6_to_str(addr), prefixlen);
1059 return;
1060 }
1061
1062 log_debug("adding %s/%d prefix", in6_to_str(addr), prefixlen);
1063
1064 if ((new_ra_prefix_conf = calloc(1, sizeof(*ra_prefix_conf))) == NULL((void *)0))
1065 fatal("%s", __func__);
1066 new_ra_prefix_conf->prefix = *addr;
1067 new_ra_prefix_conf->prefixlen = prefixlen;
1068 new_ra_prefix_conf->vltime = ra_prefix_conf->vltime;
1069 new_ra_prefix_conf->pltime = ra_prefix_conf->pltime;
1070 new_ra_prefix_conf->aflag = ra_prefix_conf->aflag;
1071 new_ra_prefix_conf->lflag = ra_prefix_conf->lflag;
1072 SIMPLEQ_INSERT_TAIL(&ra_iface->prefixes, new_ra_prefix_conf, entry)do { (new_ra_prefix_conf)->entry.sqe_next = ((void *)0); *
(&ra_iface->prefixes)->sqh_last = (new_ra_prefix_conf
); (&ra_iface->prefixes)->sqh_last = &(new_ra_prefix_conf
)->entry.sqe_next; } while (0)
;
1073 ra_iface->prefix_count++;
1074}
1075
1076void
1077build_packet(struct ra_iface *ra_iface)
1078{
1079 struct nd_router_advert *ra;
1080 struct nd_opt_mtu *ndopt_mtu;
1081 struct nd_opt_prefix_info *ndopt_pi;
1082 struct ra_iface_conf *ra_iface_conf;
1083 struct ra_options_conf *ra_options_conf;
1084 struct ra_prefix_conf *ra_prefix_conf;
1085 struct nd_opt_rdnss *ndopt_rdnss;
1086 struct nd_opt_dnssl *ndopt_dnssl;
1087 struct ra_rdnss_conf *ra_rdnss;
1088 struct ra_dnssl_conf *ra_dnssl;
1089 size_t len, label_len;
1090 uint8_t *p, buf[RA_MAX_SIZE1500];
1091 char *label_start, *label_end;
1092
1093 ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
1094 ra_iface->conf_name);
1095 ra_options_conf = &ra_iface_conf->ra_options;
1096
1097 len = sizeof(*ra);
1098 if (ra_options_conf->mtu > 0)
1099 len += sizeof(*ndopt_mtu);
1100 len += sizeof(*ndopt_pi) * ra_iface->prefix_count;
1101 if (ra_iface_conf->ra_options.rdnss_count > 0)
1102 len += sizeof(*ndopt_rdnss) +
1103 ra_iface_conf->ra_options.rdnss_count *
1104 sizeof(struct in6_addr);
1105
1106 if (ra_iface_conf->ra_options.dnssl_len > 0)
1107 /* round up to 8 byte boundary */
1108 len += sizeof(*ndopt_dnssl) +
1109 ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7);
1110
1111 if (len > sizeof(ra_iface->data))
1112 fatalx("%s: packet too big", __func__); /* XXX send multiple */
1113
1114 p = buf;
1115
1116 ra = (struct nd_router_advert *)p;
1117
1118 memset(ra, 0, sizeof(*ra));
1119
1120 ra->nd_ra_typend_ra_hdr.icmp6_type = ND_ROUTER_ADVERT134;
1121 ra->nd_ra_curhoplimitnd_ra_hdr.icmp6_dataun.icmp6_un_data8[0] = ra_options_conf->cur_hl;
1122 if (ra_options_conf->m_flag)
1123 ra->nd_ra_flags_reservednd_ra_hdr.icmp6_dataun.icmp6_un_data8[1] |= ND_RA_FLAG_MANAGED0x80;
1124 if (ra_options_conf->o_flag)
1125 ra->nd_ra_flags_reservednd_ra_hdr.icmp6_dataun.icmp6_un_data8[1] |= ND_RA_FLAG_OTHER0x40;
1126 if (ra_iface->removed)
1127 /* tell clients that we are no longer a default router */
1128 ra->nd_ra_router_lifetimend_ra_hdr.icmp6_dataun.icmp6_un_data16[1] = 0;
1129 else if (ra_options_conf->dfr) {
1130 ra->nd_ra_router_lifetimend_ra_hdr.icmp6_dataun.icmp6_un_data16[1] =
1131 htons(ra_options_conf->router_lifetime)(__uint16_t)(__builtin_constant_p(ra_options_conf->router_lifetime
) ? (__uint16_t)(((__uint16_t)(ra_options_conf->router_lifetime
) & 0xffU) << 8 | ((__uint16_t)(ra_options_conf->
router_lifetime) & 0xff00U) >> 8) : __swap16md(ra_options_conf
->router_lifetime))
;
1132 }
1133 ra->nd_ra_reachable = htonl(ra_options_conf->reachable_time)(__uint32_t)(__builtin_constant_p(ra_options_conf->reachable_time
) ? (__uint32_t)(((__uint32_t)(ra_options_conf->reachable_time
) & 0xff) << 24 | ((__uint32_t)(ra_options_conf->
reachable_time) & 0xff00) << 8 | ((__uint32_t)(ra_options_conf
->reachable_time) & 0xff0000) >> 8 | ((__uint32_t
)(ra_options_conf->reachable_time) & 0xff000000) >>
24) : __swap32md(ra_options_conf->reachable_time))
;
1134 ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer)(__uint32_t)(__builtin_constant_p(ra_options_conf->retrans_timer
) ? (__uint32_t)(((__uint32_t)(ra_options_conf->retrans_timer
) & 0xff) << 24 | ((__uint32_t)(ra_options_conf->
retrans_timer) & 0xff00) << 8 | ((__uint32_t)(ra_options_conf
->retrans_timer) & 0xff0000) >> 8 | ((__uint32_t
)(ra_options_conf->retrans_timer) & 0xff000000) >>
24) : __swap32md(ra_options_conf->retrans_timer))
;
1135 p += sizeof(*ra);
1136
1137 if (ra_options_conf->mtu > 0) {
1138 ndopt_mtu = (struct nd_opt_mtu *)p;
1139 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU5;
1140 ndopt_mtu->nd_opt_mtu_len = 1;
1141 ndopt_mtu->nd_opt_mtu_reserved = 0;
1142 ndopt_mtu->nd_opt_mtu_mtu = htonl(ra_options_conf->mtu)(__uint32_t)(__builtin_constant_p(ra_options_conf->mtu) ? (
__uint32_t)(((__uint32_t)(ra_options_conf->mtu) & 0xff
) << 24 | ((__uint32_t)(ra_options_conf->mtu) & 0xff00
) << 8 | ((__uint32_t)(ra_options_conf->mtu) & 0xff0000
) >> 8 | ((__uint32_t)(ra_options_conf->mtu) & 0xff000000
) >> 24) : __swap32md(ra_options_conf->mtu))
;
1143 p += sizeof(*ndopt_mtu);
1144 }
1145
1146 SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface->prefixes, entry)for((ra_prefix_conf) = ((&ra_iface->prefixes)->sqh_first
); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf) = ((ra_prefix_conf
)->entry.sqe_next))
{
1147 ndopt_pi = (struct nd_opt_prefix_info *)p;
1148 memset(ndopt_pi, 0, sizeof(*ndopt_pi));
1149 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION3;
1150 ndopt_pi->nd_opt_pi_len = 4;
1151 ndopt_pi->nd_opt_pi_prefix_len = ra_prefix_conf->prefixlen;
1152 if (ra_prefix_conf->lflag)
1153 ndopt_pi->nd_opt_pi_flags_reserved |=
1154 ND_OPT_PI_FLAG_ONLINK0x80;
1155 if (ra_prefix_conf->aflag)
1156 ndopt_pi->nd_opt_pi_flags_reserved |=
1157 ND_OPT_PI_FLAG_AUTO0x40;
1158 ndopt_pi->nd_opt_pi_valid_time = htonl(ra_prefix_conf->vltime)(__uint32_t)(__builtin_constant_p(ra_prefix_conf->vltime) ?
(__uint32_t)(((__uint32_t)(ra_prefix_conf->vltime) & 0xff
) << 24 | ((__uint32_t)(ra_prefix_conf->vltime) &
0xff00) << 8 | ((__uint32_t)(ra_prefix_conf->vltime
) & 0xff0000) >> 8 | ((__uint32_t)(ra_prefix_conf->
vltime) & 0xff000000) >> 24) : __swap32md(ra_prefix_conf
->vltime))
;
1159 ndopt_pi->nd_opt_pi_preferred_time =
1160 htonl(ra_prefix_conf->pltime)(__uint32_t)(__builtin_constant_p(ra_prefix_conf->pltime) ?
(__uint32_t)(((__uint32_t)(ra_prefix_conf->pltime) & 0xff
) << 24 | ((__uint32_t)(ra_prefix_conf->pltime) &
0xff00) << 8 | ((__uint32_t)(ra_prefix_conf->pltime
) & 0xff0000) >> 8 | ((__uint32_t)(ra_prefix_conf->
pltime) & 0xff000000) >> 24) : __swap32md(ra_prefix_conf
->pltime))
;
1161 ndopt_pi->nd_opt_pi_prefix = ra_prefix_conf->prefix;
1162
1163 p += sizeof(*ndopt_pi);
1164 }
1165
1166 if (ra_iface_conf->ra_options.rdnss_count > 0) {
1167 ndopt_rdnss = (struct nd_opt_rdnss *)p;
1168 ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS25;
1169 ndopt_rdnss->nd_opt_rdnss_len = 1 +
1170 ra_iface_conf->ra_options.rdnss_count * 2;
1171 ndopt_rdnss->nd_opt_rdnss_reserved = 0;
1172 ndopt_rdnss->nd_opt_rdnss_lifetime =
1173 htonl(ra_iface_conf->ra_options.rdns_lifetime)(__uint32_t)(__builtin_constant_p(ra_iface_conf->ra_options
.rdns_lifetime) ? (__uint32_t)(((__uint32_t)(ra_iface_conf->
ra_options.rdns_lifetime) & 0xff) << 24 | ((__uint32_t
)(ra_iface_conf->ra_options.rdns_lifetime) & 0xff00) <<
8 | ((__uint32_t)(ra_iface_conf->ra_options.rdns_lifetime
) & 0xff0000) >> 8 | ((__uint32_t)(ra_iface_conf->
ra_options.rdns_lifetime) & 0xff000000) >> 24) : __swap32md
(ra_iface_conf->ra_options.rdns_lifetime))
;
1174 p += sizeof(struct nd_opt_rdnss);
1175 SIMPLEQ_FOREACH(ra_rdnss,for((ra_rdnss) = ((&ra_iface_conf->ra_options.ra_rdnss_list
)->sqh_first); (ra_rdnss) != ((void *)0); (ra_rdnss) = ((ra_rdnss
)->entry.sqe_next))
1176 &ra_iface_conf->ra_options.ra_rdnss_list, entry)for((ra_rdnss) = ((&ra_iface_conf->ra_options.ra_rdnss_list
)->sqh_first); (ra_rdnss) != ((void *)0); (ra_rdnss) = ((ra_rdnss
)->entry.sqe_next))
{
1177 memcpy(p, &ra_rdnss->rdnss, sizeof(ra_rdnss->rdnss));
1178 p += sizeof(ra_rdnss->rdnss);
1179 }
1180 }
1181
1182 if (ra_iface_conf->ra_options.dnssl_len > 0) {
1183 ndopt_dnssl = (struct nd_opt_dnssl *)p;
1184 ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL31;
1185 /* round up to 8 byte boundary */
1186 ndopt_dnssl->nd_opt_dnssl_len = 1 +
1187 ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7) / 8;
1188 ndopt_dnssl->nd_opt_dnssl_reserved = 0;
1189 ndopt_dnssl->nd_opt_dnssl_lifetime =
1190 htonl(ra_iface_conf->ra_options.rdns_lifetime)(__uint32_t)(__builtin_constant_p(ra_iface_conf->ra_options
.rdns_lifetime) ? (__uint32_t)(((__uint32_t)(ra_iface_conf->
ra_options.rdns_lifetime) & 0xff) << 24 | ((__uint32_t
)(ra_iface_conf->ra_options.rdns_lifetime) & 0xff00) <<
8 | ((__uint32_t)(ra_iface_conf->ra_options.rdns_lifetime
) & 0xff0000) >> 8 | ((__uint32_t)(ra_iface_conf->
ra_options.rdns_lifetime) & 0xff000000) >> 24) : __swap32md
(ra_iface_conf->ra_options.rdns_lifetime))
;
1191 p += sizeof(struct nd_opt_dnssl);
1192
1193 SIMPLEQ_FOREACH(ra_dnssl,for((ra_dnssl) = ((&ra_iface_conf->ra_options.ra_dnssl_list
)->sqh_first); (ra_dnssl) != ((void *)0); (ra_dnssl) = ((ra_dnssl
)->entry.sqe_next))
1194 &ra_iface_conf->ra_options.ra_dnssl_list, entry)for((ra_dnssl) = ((&ra_iface_conf->ra_options.ra_dnssl_list
)->sqh_first); (ra_dnssl) != ((void *)0); (ra_dnssl) = ((ra_dnssl
)->entry.sqe_next))
{
1195 label_start = ra_dnssl->search;
1196 while ((label_end = strchr(label_start, '.')) != NULL((void *)0)) {
1197 label_len = label_end - label_start;
1198 *p++ = label_len;
1199 memcpy(p, label_start, label_len);
1200 p += label_len;
1201 label_start = label_end + 1;
1202 }
1203 *p++ = '\0'; /* last dot */
1204 }
1205 /* zero pad */
1206 while (((uintptr_t)p) % 8 != 0)
1207 *p++ = '\0';
1208 }
1209
1210 if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len)
1211 != 0) {
1212 memcpy(ra_iface->data, buf, len);
1213 ra_iface->datalen = len;
1214 /* packet changed; tell engine to send new advertisments */
1215 if (event_initialized(&ra_iface->icmp6ev->ev)((&ra_iface->icmp6ev->ev)->ev_flags & 0x80))
1216 frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0,
1217 &ra_iface->if_index, sizeof(ra_iface->if_index));
1218 }
1219}
1220
1221void
1222build_leaving_packet(struct ra_iface *ra_iface)
1223{
1224 struct nd_router_advert ra;
1225 size_t len;
1226
1227 len = sizeof(ra);
1228
1229 memset(&ra, 0, sizeof(ra));
1230
1231 ra.nd_ra_typend_ra_hdr.icmp6_type = ND_ROUTER_ADVERT134;
1232
1233 memcpy(ra_iface->data, &ra, sizeof(ra));
1234 ra_iface->datalen = sizeof(ra);
1235}
1236
1237void
1238ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
1239{
1240
1241 struct cmsghdr *cm;
1242 struct in6_pktinfo *pi;
1243 ssize_t len;
1244 int hoplimit = 255;
1245
1246 if (!LINK_STATE_IS_UP(ra_iface->link_state)((ra_iface->link_state) >= 4 || (ra_iface->link_state
) == 0)
)
1247 return;
1248
1249 sndmhdr.msg_name = to;
1250 sndmhdr.msg_iov[0].iov_base = ra_iface->data;
1251 sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;
1252
1253 cm = CMSG_FIRSTHDR(&sndmhdr)((&sndmhdr)->msg_controllen >= sizeof(struct cmsghdr
) ? (struct cmsghdr *)(&sndmhdr)->msg_control : (struct
cmsghdr *)((void *)0))
;
1254 /* specify the outgoing interface */
1255 cm->cmsg_level = IPPROTO_IPV641;
1256 cm->cmsg_type = IPV6_PKTINFO46;
1257 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(struct in6_pktinfo)))
;
1258 pi = (struct in6_pktinfo *)CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
1259 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
1260 pi->ipi6_ifindex = ra_iface->if_index;
1261
1262 /* specify the hop limit of the packet */
1263 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))))
;
1264 cm->cmsg_level = IPPROTO_IPV641;
1265 cm->cmsg_type = IPV6_HOPLIMIT47;
1266 cm->cmsg_len = CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(int)))
;
1267 memcpy(CMSG_DATA(cm)((unsigned char *)(cm) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
, &hoplimit, sizeof(int));
1268
1269 log_debug("send RA on %s", ra_iface->name);
1270
1271 len = sendmsg(EVENT_FD(&ra_iface->icmp6ev->ev)(int)(&ra_iface->icmp6ev->ev)->ev_fd, &sndmhdr, 0);
1272 if (len == -1)
1273 log_warn("sendmsg on %s", ra_iface->name);
1274
1275}
1276
1277#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
1278 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1279
1280void
1281get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1282{
1283 int i;
1284
1285 for (i = 0; i < RTAX_MAX15; i++) {
1286 if (addrs & (1 << i)) {
1287 rti_info[i] = sa;
1288 sa = (struct sockaddr *)((char *)(sa) +
1289 ROUNDUP(sa->sa_len)((sa->sa_len) > 0 ? (1 + (((sa->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
);
1290 } else
1291 rti_info[i] = NULL((void *)0);
1292 }
1293}
1294
1295void
1296route_receive(int fd, short events, void *arg)
1297{
1298 static uint8_t *buf;
1299
1300 struct rt_msghdr *rtm;
1301 struct sockaddr *sa, *rti_info[RTAX_MAX15];
1302 ssize_t n;
1303
1304 if (buf == NULL((void *)0)) {
1305 buf = malloc(ROUTE_SOCKET_BUF_SIZE16384);
1306 if (buf == NULL((void *)0))
1307 fatal("malloc");
1308 }
1309 rtm = (struct rt_msghdr *)buf;
1310 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE16384)) == -1) {
1311 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
1312 return;
1313 log_warn("dispatch_rtmsg: read error");
1314 return;
1315 }
1316
1317 if (n == 0)
1318 fatal("routing socket closed");
1319
1320 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
1321 log_warnx("partial rtm of %zd in buffer", n);
1322 return;
1323 }
1324
1325 if (rtm->rtm_version != RTM_VERSION5)
1326 return;
1327
1328 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
1329 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1330
1331 handle_route_message(rtm, rti_info);
1332}
1333
1334void
1335handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
1336{
1337 switch (rtm->rtm_type) {
1338 case RTM_IFINFO0xe:
1339 case RTM_NEWADDR0xc:
1340 case RTM_DELADDR0xd:
1341 case RTM_CHGADDRATTR0x14:
1342 /*
1343 * do the same thing as after a config reload when interfaces
1344 * change or IPv6 addresses show up / disappear
1345 */
1346 merge_ra_interfaces();
1347 break;
1348 default:
1349 log_debug("unexpected RTM: %d", rtm->rtm_type);
1350 break;
1351 }
1352}
1353
1354struct icmp6_ev*
1355get_icmp6ev_by_rdomain(int rdomain)
1356{
1357 struct ra_iface *ra_iface;
1358 struct icmp6_ev *icmp6ev = NULL((void *)0);
1359
1360 TAILQ_FOREACH (ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
{
1361 if (ra_iface->rdomain == rdomain) {
1362 icmp6ev = ra_iface->icmp6ev;
1363 break;
1364 }
1365 }
1366
1367 if (icmp6ev == NULL((void *)0)) {
1368 if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL((void *)0))
1369 fatal("calloc");
1370
1371 icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer;
1372 icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer);
1373 icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from;
1374 icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from);
1375 icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov;
1376 icmp6ev->rcvmhdr.msg_iovlen = 1;
1377 icmp6ev->rcvmhdr.msg_controllen =
1378 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)
))
+
1379 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)))
;
1380 if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev->
1381 rcvmhdr.msg_controllen)) == NULL((void *)0))
1382 fatal("malloc");
1383 frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0,
1384 &rdomain, sizeof(rdomain));
1385 }
1386
1387 icmp6ev->refcnt++;
1388 return (icmp6ev);
1389}
1390
1391void
1392unref_icmp6ev(struct ra_iface *ra_iface)
1393{
1394 struct icmp6_ev *icmp6ev = ra_iface->icmp6ev;
1395
1396 ra_iface->icmp6ev = NULL((void *)0);
1397
1398 if (icmp6ev != NULL((void *)0)) {
1399 icmp6ev->refcnt--;
1400 if (icmp6ev->refcnt == 0) {
1401 event_del(&icmp6ev->ev);
1402 close(EVENT_FD(&icmp6ev->ev)(int)(&icmp6ev->ev)->ev_fd);
1403 free(icmp6ev);
1404 }
1405 }
1406}
1407
1408void
1409set_icmp6sock(int icmp6sock, int rdomain)
1410{
1411 struct ra_iface *ra_iface;
1412
1413 TAILQ_FOREACH (ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
{
1414 if (!event_initialized(&ra_iface->icmp6ev->ev)((&ra_iface->icmp6ev->ev)->ev_flags & 0x80) &&
1415 ra_iface->rdomain == rdomain) {
1416 event_set(&ra_iface->icmp6ev->ev, icmp6sock, EV_READ0x02 |
1417 EV_PERSIST0x10, icmp6_receive, ra_iface->icmp6ev);
1418 event_add(&ra_iface->icmp6ev->ev, NULL((void *)0));
1419 icmp6sock = -1;
1420 break;
1421 }
1422 }
1423
1424 if (icmp6sock != -1) {
1425 /*
1426 * The interface disappeared or changed rdomain while we were
1427 * waiting for the parent process to open the raw socket.
1428 */
1429 close(icmp6sock);
1430 return;
1431 }
1432
1433 TAILQ_FOREACH (ra_iface, &ra_interfaces, entry)for((ra_iface) = ((&ra_interfaces)->tqh_first); (ra_iface
) != ((void *)0); (ra_iface) = ((ra_iface)->entry.tqe_next
))
{
1434 if (ra_iface->rdomain == rdomain) {
1435 join_all_routers_mcast_group(ra_iface);
1436 frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0,
1437 &ra_iface->if_index, sizeof(ra_iface->if_index));
1438 }
1439 }
1440}