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