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') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
92 | struct 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 | ||||
101 | struct 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 | |||
117 | struct 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 | ||||
124 | TAILQ_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); | |||
127 | void frontend_sig_handler(int, short, void *); | |||
128 | void frontend_startup(void); | |||
129 | void icmp6_receive(int, short, void *); | |||
130 | void join_all_routers_mcast_group(struct ra_iface *); | |||
131 | void leave_all_routers_mcast_group(struct ra_iface *); | |||
132 | int get_link_state(char *); | |||
133 | int get_ifrdomain(char *); | |||
134 | void merge_ra_interface(char *, char *); | |||
135 | void merge_ra_interfaces(void); | |||
136 | struct ra_iface *find_ra_iface_by_id(uint32_t); | |||
137 | struct ra_iface *find_ra_iface_by_name(char *); | |||
138 | struct ra_iface_conf *find_ra_iface_conf(struct ra_iface_conf_head *, | |||
139 | char *); | |||
140 | struct ra_prefix_conf *find_ra_prefix_conf(struct ra_prefix_conf_head*, | |||
141 | struct in6_addr *, int); | |||
142 | struct icmp6_ev *get_icmp6ev_by_rdomain(int); | |||
143 | void unref_icmp6ev(struct ra_iface *); | |||
144 | void set_icmp6sock(int, int); | |||
145 | void add_new_prefix_to_ra_iface(struct ra_iface *r, | |||
146 | struct in6_addr *, int, struct ra_prefix_conf *); | |||
147 | void free_ra_iface(struct ra_iface *); | |||
148 | int in6_mask2prefixlen(struct in6_addr *); | |||
149 | void get_interface_prefixes(struct ra_iface *, | |||
150 | struct ra_prefix_conf *); | |||
151 | int interface_has_linklocal_address(char *); | |||
152 | void build_packet(struct ra_iface *); | |||
153 | void build_leaving_packet(struct ra_iface *); | |||
154 | void ra_output(struct ra_iface *, struct sockaddr_in6 *); | |||
155 | void get_rtaddrs(int, struct sockaddr *, | |||
156 | struct sockaddr **); | |||
157 | void route_receive(int, short, void *); | |||
158 | void handle_route_message(struct rt_msghdr *, | |||
159 | struct sockaddr **); | |||
160 | ||||
161 | struct rad_conf *frontend_conf; | |||
162 | static struct imsgev *iev_main; | |||
163 | static struct imsgev *iev_engine; | |||
164 | struct event ev_route; | |||
165 | int ioctlsock = -1, routesock = -1; | |||
166 | struct ipv6_mreq all_routers; | |||
167 | struct msghdr sndmhdr; | |||
168 | struct iovec sndiov[2]; | |||
169 | ||||
170 | void | |||
171 | frontend_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 | ||||
187 | void | |||
188 | frontend(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 | |||
266 | frontend_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 | ||||
285 | int | |||
286 | frontend_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 | ||||
292 | int | |||
293 | frontend_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 | ||||
299 | void | |||
300 | frontend_dispatch_main(int fd, short event, void *bula) | |||
301 | { | |||
302 | static struct rad_conf *nconf; | |||
303 | static struct ra_iface_conf *ra_iface_conf; | |||
| ||||
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) { | |||
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) { | |||
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 (;;) { | |||
328 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
329 | fatal("%s: imsg_get error", __func__); | |||
330 | if (n == 0) /* No more messages. */ | |||
331 | break; | |||
332 | ||||
333 | switch (imsg.hdr.type) { | |||
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 | |||
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 | |||
| ||||
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 | ||||
516 | void | |||
517 | frontend_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 | ||||
583 | void | |||
584 | frontend_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 | ||||
594 | void | |||
595 | icmp6_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 | ||||
674 | void | |||
675 | join_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 | ||||
686 | void | |||
687 | leave_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 | ||||
697 | struct ra_iface* | |||
698 | find_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 | ||||
709 | struct ra_iface* | |||
710 | find_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 | ||||
721 | struct ra_iface_conf* | |||
722 | find_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 | ||||
733 | int | |||
734 | get_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 | ||||
757 | int | |||
758 | get_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 | ||||
770 | void | |||
771 | merge_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 | ||||
839 | void | |||
840 | merge_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 | ||||
928 | void | |||
929 | free_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() */ | |||
945 | int | |||
946 | in6_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 | ||||
969 | int | |||
970 | interface_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 | ||||
1011 | void | |||
1012 | get_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 | ||||
1058 | struct ra_prefix_conf* | |||
1059 | find_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 | ||||
1073 | void | |||
1074 | add_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 | ||||
1099 | void | |||
1100 | build_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 | ||||
1290 | void | |||
1291 | build_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 | ||||
1303 | void | |||
1304 | ra_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 | ||||
1346 | void | |||
1347 | get_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 | ||||
1361 | void | |||
1362 | route_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 | ||||
1400 | void | |||
1401 | handle_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 | ||||
1420 | struct icmp6_ev* | |||
1421 | get_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 | ||||
1457 | void | |||
1458 | unref_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 | ||||
1474 | void | |||
1475 | set_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 | } |