Bug Summary

File:src/usr.sbin/rad/frontend.c
Warning:line 401, column 35
Access to field 'autoprefix' results in a dereference of a null pointer (loaded from variable 'ra_iface_conf')

Annotated Source Code

Press '?' to see keyboard shortcuts

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