File: | src/usr.sbin/rad/engine.c |
Warning: | line 358, 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: engine.c,v 1.19 2021/05/13 11:22:15 florian Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2018 Florian Obser <florian@openbsd.org> | |||
5 | * Copyright (c) 2004, 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 | #include <sys/types.h> | |||
23 | #include <sys/queue.h> | |||
24 | #include <sys/socket.h> | |||
25 | #include <sys/syslog.h> | |||
26 | #include <sys/uio.h> | |||
27 | ||||
28 | #include <netinet/in.h> | |||
29 | #include <net/if.h> | |||
30 | #include <arpa/inet.h> | |||
31 | #include <netinet/icmp6.h> | |||
32 | ||||
33 | #include <errno(*__errno()).h> | |||
34 | #include <event.h> | |||
35 | #include <imsg.h> | |||
36 | #include <signal.h> | |||
37 | #include <stdlib.h> | |||
38 | #include <string.h> | |||
39 | #include <pwd.h> | |||
40 | #include <unistd.h> | |||
41 | ||||
42 | #include "log.h" | |||
43 | #include "rad.h" | |||
44 | #include "engine.h" | |||
45 | ||||
46 | struct engine_iface { | |||
47 | TAILQ_ENTRY(engine_iface)struct { struct engine_iface *tqe_next; struct engine_iface * *tqe_prev; } entry; | |||
48 | struct event timer; | |||
49 | uint32_t if_index; | |||
50 | }; | |||
51 | ||||
52 | TAILQ_HEAD(, engine_iface)struct { struct engine_iface *tqh_first; struct engine_iface * *tqh_last; } engine_interfaces; | |||
53 | ||||
54 | ||||
55 | __dead__attribute__((__noreturn__)) void engine_shutdown(void); | |||
56 | void engine_sig_handler(int sig, short, void *); | |||
57 | void engine_dispatch_frontend(int, short, void *); | |||
58 | void engine_dispatch_main(int, short, void *); | |||
59 | void parse_ra_rs(struct imsg_ra_rs *); | |||
60 | void parse_ra(struct imsg_ra_rs *); | |||
61 | void parse_rs(struct imsg_ra_rs *); | |||
62 | void update_iface(uint32_t); | |||
63 | void remove_iface(uint32_t); | |||
64 | struct engine_iface *find_engine_iface_by_id(uint32_t); | |||
65 | void iface_timeout(int, short, void *); | |||
66 | ||||
67 | struct rad_conf *engine_conf; | |||
68 | static struct imsgev *iev_frontend; | |||
69 | static struct imsgev *iev_main; | |||
70 | struct sockaddr_in6 all_nodes; | |||
71 | ||||
72 | void | |||
73 | engine_sig_handler(int sig, short event, void *arg) | |||
74 | { | |||
75 | /* | |||
76 | * Normal signal handler rules don't apply because libevent | |||
77 | * decouples for us. | |||
78 | */ | |||
79 | ||||
80 | switch (sig) { | |||
81 | case SIGINT2: | |||
82 | case SIGTERM15: | |||
83 | engine_shutdown(); | |||
84 | default: | |||
85 | fatalx("unexpected signal"); | |||
86 | } | |||
87 | } | |||
88 | ||||
89 | void | |||
90 | engine(int debug, int verbose) | |||
91 | { | |||
92 | struct event ev_sigint, ev_sigterm; | |||
93 | struct passwd *pw; | |||
94 | ||||
95 | engine_conf = config_new_empty(); | |||
96 | ||||
97 | log_init(debug, LOG_DAEMON(3<<3)); | |||
98 | log_setverbose(verbose); | |||
99 | ||||
100 | if ((pw = getpwnam(RAD_USER"_rad")) == NULL((void *)0)) | |||
101 | fatal("getpwnam"); | |||
102 | ||||
103 | if (chroot(pw->pw_dir) == -1) | |||
104 | fatal("chroot"); | |||
105 | if (chdir("/") == -1) | |||
106 | fatal("chdir(\"/\")"); | |||
107 | ||||
108 | setproctitle("%s", "engine"); | |||
109 | log_procinit("engine"); | |||
110 | ||||
111 | if (setgroups(1, &pw->pw_gid) || | |||
112 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || | |||
113 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) | |||
114 | fatal("can't drop privileges"); | |||
115 | ||||
116 | if (pledge("stdio recvfd", NULL((void *)0)) == -1) | |||
117 | fatal("pledge"); | |||
118 | ||||
119 | event_init(); | |||
120 | ||||
121 | /* Setup signal handler(s). */ | |||
122 | signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, engine_sig_handler, ( (void *)0)); | |||
123 | signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, engine_sig_handler, ((void *)0)); | |||
124 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); | |||
125 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); | |||
126 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); | |||
127 | signal(SIGHUP1, SIG_IGN(void (*)(int))1); | |||
128 | ||||
129 | /* Setup pipe and event handler to the main process. */ | |||
130 | if ((iev_main = malloc(sizeof(struct imsgev))) == NULL((void *)0)) | |||
131 | fatal(NULL((void *)0)); | |||
132 | ||||
133 | imsg_init(&iev_main->ibuf, 3); | |||
134 | iev_main->handler = engine_dispatch_main; | |||
135 | ||||
136 | /* Setup event handlers. */ | |||
137 | iev_main->events = EV_READ0x02; | |||
138 | event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, | |||
139 | iev_main->handler, iev_main); | |||
140 | event_add(&iev_main->ev, NULL((void *)0)); | |||
141 | ||||
142 | all_nodes.sin6_len = sizeof(all_nodes); | |||
143 | all_nodes.sin6_family = AF_INET624; | |||
144 | if (inet_pton(AF_INET624, "ff02::1", &all_nodes.sin6_addr) != 1) | |||
145 | fatal("inet_pton"); | |||
146 | ||||
147 | TAILQ_INIT(&engine_interfaces)do { (&engine_interfaces)->tqh_first = ((void *)0); (& engine_interfaces)->tqh_last = &(&engine_interfaces )->tqh_first; } while (0); | |||
148 | ||||
149 | event_dispatch(); | |||
150 | ||||
151 | engine_shutdown(); | |||
152 | } | |||
153 | ||||
154 | __dead__attribute__((__noreturn__)) void | |||
155 | engine_shutdown(void) | |||
156 | { | |||
157 | /* Close pipes. */ | |||
158 | msgbuf_clear(&iev_frontend->ibuf.w); | |||
159 | close(iev_frontend->ibuf.fd); | |||
160 | msgbuf_clear(&iev_main->ibuf.w); | |||
161 | close(iev_main->ibuf.fd); | |||
162 | ||||
163 | config_clear(engine_conf); | |||
164 | ||||
165 | free(iev_frontend); | |||
166 | free(iev_main); | |||
167 | ||||
168 | log_info("engine exiting"); | |||
169 | exit(0); | |||
170 | } | |||
171 | ||||
172 | int | |||
173 | engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) | |||
174 | { | |||
175 | return (imsg_compose_event(iev_frontend, type, 0, pid, -1, | |||
176 | data, datalen)); | |||
177 | } | |||
178 | ||||
179 | void | |||
180 | engine_dispatch_frontend(int fd, short event, void *bula) | |||
181 | { | |||
182 | struct imsgev *iev = bula; | |||
183 | struct imsgbuf *ibuf; | |||
184 | struct imsg imsg; | |||
185 | struct imsg_ra_rs ra_rs; | |||
186 | ssize_t n; | |||
187 | uint32_t if_index; | |||
188 | int shut = 0, verbose; | |||
189 | ||||
190 | ibuf = &iev->ibuf; | |||
191 | ||||
192 | if (event & EV_READ0x02) { | |||
193 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
194 | fatal("imsg_read error"); | |||
195 | if (n == 0) /* Connection closed. */ | |||
196 | shut = 1; | |||
197 | } | |||
198 | if (event & EV_WRITE0x04) { | |||
199 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
200 | fatal("msgbuf_write"); | |||
201 | if (n == 0) /* Connection closed. */ | |||
202 | shut = 1; | |||
203 | } | |||
204 | ||||
205 | for (;;) { | |||
206 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
207 | fatal("%s: imsg_get error", __func__); | |||
208 | if (n == 0) /* No more messages. */ | |||
209 | break; | |||
210 | ||||
211 | switch (imsg.hdr.type) { | |||
212 | case IMSG_RA_RS: | |||
213 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(ra_rs)) | |||
214 | fatalx("%s: IMSG_RA_RS wrong length: %lu", | |||
215 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
216 | memcpy(&ra_rs, imsg.data, sizeof(ra_rs)); | |||
217 | parse_ra_rs(&ra_rs); | |||
218 | break; | |||
219 | case IMSG_UPDATE_IF: | |||
220 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index)) | |||
221 | fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", | |||
222 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
223 | memcpy(&if_index, imsg.data, sizeof(if_index)); | |||
224 | update_iface(if_index); | |||
225 | break; | |||
226 | case IMSG_REMOVE_IF: | |||
227 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(if_index)) | |||
228 | fatalx("%s: IMSG_REMOVE_IF wrong length: %lu", | |||
229 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
230 | memcpy(&if_index, imsg.data, sizeof(if_index)); | |||
231 | remove_iface(if_index); | |||
232 | break; | |||
233 | case IMSG_CTL_LOG_VERBOSE: | |||
234 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose)) | |||
235 | fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " | |||
236 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
237 | memcpy(&verbose, imsg.data, sizeof(verbose)); | |||
238 | log_setverbose(verbose); | |||
239 | break; | |||
240 | default: | |||
241 | log_debug("%s: unexpected imsg %d", __func__, | |||
242 | imsg.hdr.type); | |||
243 | break; | |||
244 | } | |||
245 | imsg_free(&imsg); | |||
246 | } | |||
247 | if (!shut) | |||
248 | imsg_event_add(iev); | |||
249 | else { | |||
250 | /* This pipe is dead. Remove its event handler. */ | |||
251 | event_del(&iev->ev); | |||
252 | event_loopexit(NULL((void *)0)); | |||
253 | } | |||
254 | } | |||
255 | ||||
256 | void | |||
257 | engine_dispatch_main(int fd, short event, void *bula) | |||
258 | { | |||
259 | static struct rad_conf *nconf; | |||
260 | static struct ra_iface_conf *ra_iface_conf; | |||
| ||||
261 | static struct ra_options_conf *ra_options; | |||
262 | struct imsg imsg; | |||
263 | struct imsgev *iev = bula; | |||
264 | struct imsgbuf *ibuf; | |||
265 | struct ra_prefix_conf *ra_prefix_conf; | |||
266 | struct ra_rdnss_conf *ra_rdnss_conf; | |||
267 | struct ra_dnssl_conf *ra_dnssl_conf; | |||
268 | ssize_t n; | |||
269 | int shut = 0; | |||
270 | ||||
271 | ibuf = &iev->ibuf; | |||
272 | ||||
273 | if (event & EV_READ0x02) { | |||
274 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
275 | fatal("imsg_read error"); | |||
276 | if (n == 0) /* Connection closed. */ | |||
277 | shut = 1; | |||
278 | } | |||
279 | if (event & EV_WRITE0x04) { | |||
280 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
281 | fatal("msgbuf_write"); | |||
282 | if (n == 0) /* Connection closed. */ | |||
283 | shut = 1; | |||
284 | } | |||
285 | ||||
286 | for (;;) { | |||
287 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
288 | fatal("%s: imsg_get error", __func__); | |||
289 | if (n == 0) /* No more messages. */ | |||
290 | break; | |||
291 | ||||
292 | switch (imsg.hdr.type) { | |||
293 | case IMSG_SOCKET_IPC: | |||
294 | /* | |||
295 | * Setup pipe and event handler to the frontend | |||
296 | * process. | |||
297 | */ | |||
298 | if (iev_frontend) | |||
299 | fatalx("%s: received unexpected imsg fd " | |||
300 | "to engine", __func__); | |||
301 | ||||
302 | if ((fd = imsg.fd) == -1) | |||
303 | fatalx("%s: expected to receive imsg fd to " | |||
304 | "engine but didn't receive any", __func__); | |||
305 | ||||
306 | iev_frontend = malloc(sizeof(struct imsgev)); | |||
307 | if (iev_frontend == NULL((void *)0)) | |||
308 | fatal(NULL((void *)0)); | |||
309 | ||||
310 | imsg_init(&iev_frontend->ibuf, fd); | |||
311 | iev_frontend->handler = engine_dispatch_frontend; | |||
312 | iev_frontend->events = EV_READ0x02; | |||
313 | ||||
314 | event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, | |||
315 | iev_frontend->events, iev_frontend->handler, | |||
316 | iev_frontend); | |||
317 | event_add(&iev_frontend->ev, NULL((void *)0)); | |||
318 | break; | |||
319 | case IMSG_RECONF_CONF: | |||
320 | if (nconf != NULL((void *)0)) | |||
321 | fatalx("%s: IMSG_RECONF_CONF already in " | |||
322 | "progress", __func__); | |||
323 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct rad_conf)) | |||
324 | fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", | |||
325 | __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
326 | if ((nconf = malloc(sizeof(struct rad_conf))) == NULL((void *)0)) | |||
327 | fatal(NULL((void *)0)); | |||
328 | memcpy(nconf, imsg.data, sizeof(struct rad_conf)); | |||
329 | 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); | |||
330 | 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); | |||
331 | 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); | |||
332 | ra_options = &nconf->ra_options; | |||
333 | break; | |||
334 | case IMSG_RECONF_RA_IFACE: | |||
335 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
336 | ra_iface_conf)) | |||
337 | fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: " | |||
338 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
339 | if ((ra_iface_conf = malloc(sizeof(struct | |||
340 | ra_iface_conf))) == NULL((void *)0)) | |||
341 | fatal(NULL((void *)0)); | |||
342 | memcpy(ra_iface_conf, imsg.data, | |||
343 | sizeof(struct ra_iface_conf)); | |||
344 | ra_iface_conf->autoprefix = NULL((void *)0); | |||
345 | 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); | |||
346 | 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); | |||
347 | 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); | |||
348 | 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) | |||
349 | 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); | |||
350 | ra_options = &ra_iface_conf->ra_options; | |||
351 | break; | |||
352 | case IMSG_RECONF_RA_AUTOPREFIX: | |||
353 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
354 | ra_prefix_conf)) | |||
355 | fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong " | |||
356 | "length: %lu", __func__, | |||
357 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
358 | if ((ra_iface_conf->autoprefix = malloc(sizeof(struct | |||
| ||||
359 | ra_prefix_conf))) == NULL((void *)0)) | |||
360 | fatal(NULL((void *)0)); | |||
361 | memcpy(ra_iface_conf->autoprefix, imsg.data, | |||
362 | sizeof(struct ra_prefix_conf)); | |||
363 | break; | |||
364 | case IMSG_RECONF_RA_PREFIX: | |||
365 | if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
366 | ra_prefix_conf)) | |||
367 | fatalx("%s: IMSG_RECONF_RA_PREFIX wrong " | |||
368 | "length: %lu", __func__, | |||
369 | IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
370 | if ((ra_prefix_conf = malloc(sizeof(struct | |||
371 | ra_prefix_conf))) == NULL((void *)0)) | |||
372 | fatal(NULL((void *)0)); | |||
373 | memcpy(ra_prefix_conf, imsg.data, sizeof(struct | |||
374 | ra_prefix_conf)); | |||
375 | 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) | |||
376 | 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); | |||
377 | break; | |||
378 | case IMSG_RECONF_RA_RDNSS: | |||
379 | if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
380 | ra_rdnss_conf)) | |||
381 | fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: " | |||
382 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
383 | if ((ra_rdnss_conf = malloc(sizeof(struct | |||
384 | ra_rdnss_conf))) == NULL((void *)0)) | |||
385 | fatal(NULL((void *)0)); | |||
386 | memcpy(ra_rdnss_conf, imsg.data, sizeof(struct | |||
387 | ra_rdnss_conf)); | |||
388 | 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) | |||
389 | 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); | |||
390 | break; | |||
391 | case IMSG_RECONF_RA_DNSSL: | |||
392 | if(IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct | |||
393 | ra_dnssl_conf)) | |||
394 | fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: " | |||
395 | "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr))); | |||
396 | if ((ra_dnssl_conf = malloc(sizeof(struct | |||
397 | ra_dnssl_conf))) == NULL((void *)0)) | |||
398 | fatal(NULL((void *)0)); | |||
399 | memcpy(ra_dnssl_conf, imsg.data, sizeof(struct | |||
400 | ra_dnssl_conf)); | |||
401 | 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) | |||
402 | 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); | |||
403 | break; | |||
404 | case IMSG_RECONF_END: | |||
405 | if (nconf == NULL((void *)0)) | |||
406 | fatalx("%s: IMSG_RECONF_END without " | |||
407 | "IMSG_RECONF_CONF", __func__); | |||
408 | merge_config(engine_conf, nconf); | |||
409 | nconf = NULL((void *)0); | |||
410 | break; | |||
411 | default: | |||
412 | log_debug("%s: unexpected imsg %d", __func__, | |||
413 | imsg.hdr.type); | |||
414 | break; | |||
415 | } | |||
416 | imsg_free(&imsg); | |||
417 | } | |||
418 | if (!shut) | |||
419 | imsg_event_add(iev); | |||
420 | else { | |||
421 | /* This pipe is dead. Remove its event handler. */ | |||
422 | event_del(&iev->ev); | |||
423 | event_loopexit(NULL((void *)0)); | |||
424 | } | |||
425 | } | |||
426 | ||||
427 | ||||
428 | void | |||
429 | parse_ra_rs(struct imsg_ra_rs *ra_rs) | |||
430 | { | |||
431 | char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16]; | |||
432 | struct icmp6_hdr *hdr; | |||
433 | ||||
434 | hdr = (struct icmp6_hdr *) ra_rs->packet; | |||
435 | ||||
436 | switch (hdr->icmp6_type) { | |||
437 | case ND_ROUTER_ADVERT134: | |||
438 | parse_ra(ra_rs); | |||
439 | break; | |||
440 | case ND_ROUTER_SOLICIT133: | |||
441 | parse_rs(ra_rs); | |||
442 | break; | |||
443 | default: | |||
444 | log_warnx("unexpected icmp6_type: %d from %s on %s", | |||
445 | hdr->icmp6_type, inet_ntop(AF_INET624, &ra_rs->from.sin6_addr, | |||
446 | ntopbuf, INET6_ADDRSTRLEN46), if_indextoname(ra_rs->if_index, | |||
447 | ifnamebuf)); | |||
448 | break; | |||
449 | } | |||
450 | } | |||
451 | ||||
452 | void | |||
453 | parse_ra(struct imsg_ra_rs *ra) | |||
454 | { | |||
455 | char ntopbuf[INET6_ADDRSTRLEN46], ifnamebuf[IFNAMSIZ16]; | |||
456 | log_debug("got RA from %s on %s", | |||
457 | inet_ntop(AF_INET624, &ra->from.sin6_addr, ntopbuf, | |||
458 | INET6_ADDRSTRLEN46), if_indextoname(ra->if_index, | |||
459 | ifnamebuf)); | |||
460 | /* XXX not yet */ | |||
461 | } | |||
462 | ||||
463 | void | |||
464 | parse_rs(struct imsg_ra_rs *rs) | |||
465 | { | |||
466 | struct nd_router_solicit *nd_rs; | |||
467 | struct imsg_send_ra send_ra; | |||
468 | ssize_t len; | |||
469 | const char *hbuf; | |||
470 | char ifnamebuf[IFNAMSIZ16]; | |||
471 | uint8_t *p; | |||
472 | ||||
473 | hbuf = sin6_to_str(&rs->from); | |||
474 | ||||
475 | send_ra.if_index = rs->if_index; | |||
476 | memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); | |||
477 | ||||
478 | log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index, | |||
479 | ifnamebuf)); | |||
480 | ||||
481 | len = rs->len; | |||
482 | ||||
483 | if (!(IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr)(((&rs->from.sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&rs->from.sin6_addr)->__u6_addr .__u6_addr8[1] & 0xc0) == 0x80)) || | |||
484 | IN6_IS_ADDR_UNSPECIFIED(&rs->from.sin6_addr)((*(const u_int32_t *)(const void *)(&(&rs->from.sin6_addr )->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&rs->from.sin6_addr)->__u6_addr .__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void *)(&(&rs->from.sin6_addr)->__u6_addr.__u6_addr8 [8]) == 0) && (*(const u_int32_t *)(const void *)(& (&rs->from.sin6_addr)->__u6_addr.__u6_addr8[12]) == 0)))) { | |||
485 | log_warnx("RA from invalid address %s on %s", hbuf, | |||
486 | if_indextoname(rs->if_index, ifnamebuf)); | |||
487 | return; | |||
488 | } | |||
489 | ||||
490 | if ((size_t)len < sizeof(struct nd_router_solicit)) { | |||
491 | log_warnx("received too short message (%ld) from %s", len, | |||
492 | hbuf); | |||
493 | return; | |||
494 | } | |||
495 | ||||
496 | p = rs->packet; | |||
497 | nd_rs = (struct nd_router_solicit *)p; | |||
498 | len -= sizeof(struct nd_router_solicit); | |||
499 | p += sizeof(struct nd_router_solicit); | |||
500 | ||||
501 | if (nd_rs->nd_rs_codend_rs_hdr.icmp6_code != 0) { | |||
502 | log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_codend_rs_hdr.icmp6_code, | |||
503 | hbuf); | |||
504 | return; | |||
505 | } | |||
506 | while ((size_t)len >= sizeof(struct nd_opt_hdr)) { | |||
507 | struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; | |||
508 | ||||
509 | len -= sizeof(struct nd_opt_hdr); | |||
510 | p += sizeof(struct nd_opt_hdr); | |||
511 | ||||
512 | if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { | |||
513 | log_warnx("invalid option len: %u > %ld", | |||
514 | nd_opt_hdr->nd_opt_len, len); | |||
515 | return; | |||
516 | } | |||
517 | switch (nd_opt_hdr->nd_opt_type) { | |||
518 | case ND_OPT_SOURCE_LINKADDR1: | |||
519 | log_debug("got RS with source linkaddr option"); | |||
520 | memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to)); | |||
521 | break; | |||
522 | default: | |||
523 | log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); | |||
524 | break; | |||
525 | } | |||
526 | len -= nd_opt_hdr->nd_opt_len * 8 - 2; | |||
527 | p += nd_opt_hdr->nd_opt_len * 8 - 2; | |||
528 | } | |||
529 | engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, | |||
530 | sizeof(send_ra)); | |||
531 | } | |||
532 | ||||
533 | struct engine_iface* | |||
534 | find_engine_iface_by_id(uint32_t if_index) | |||
535 | { | |||
536 | struct engine_iface *engine_iface; | |||
537 | ||||
538 | TAILQ_FOREACH(engine_iface, &engine_interfaces, entry)for((engine_iface) = ((&engine_interfaces)->tqh_first) ; (engine_iface) != ((void *)0); (engine_iface) = ((engine_iface )->entry.tqe_next)) { | |||
539 | if (engine_iface->if_index == if_index) | |||
540 | return engine_iface; | |||
541 | } | |||
542 | return (NULL((void *)0)); | |||
543 | } | |||
544 | ||||
545 | void | |||
546 | update_iface(uint32_t if_index) | |||
547 | { | |||
548 | struct engine_iface *engine_iface; | |||
549 | struct timeval tv; | |||
550 | ||||
551 | if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL((void *)0)) { | |||
552 | engine_iface = calloc(1, sizeof(*engine_iface)); | |||
553 | engine_iface->if_index = if_index; | |||
554 | evtimer_set(&engine_iface->timer, iface_timeout, engine_iface)event_set(&engine_iface->timer, -1, 0, iface_timeout, engine_iface ); | |||
555 | TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry)do { (engine_iface)->entry.tqe_next = ((void *)0); (engine_iface )->entry.tqe_prev = (&engine_interfaces)->tqh_last; *(&engine_interfaces)->tqh_last = (engine_iface); (& engine_interfaces)->tqh_last = &(engine_iface)->entry .tqe_next; } while (0); | |||
556 | } | |||
557 | ||||
558 | tv.tv_sec = 0; | |||
559 | tv.tv_usec = arc4random_uniform(1000000); | |||
560 | evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv); | |||
561 | } | |||
562 | ||||
563 | void | |||
564 | remove_iface(uint32_t if_index) | |||
565 | { | |||
566 | struct engine_iface *engine_iface; | |||
567 | struct imsg_send_ra send_ra; | |||
568 | char if_name[IF_NAMESIZE16]; | |||
569 | ||||
570 | if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL((void *)0)) { | |||
571 | /* we don't know this interface, frontend can delete it */ | |||
572 | engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, | |||
573 | &if_index, sizeof(if_index)); | |||
574 | return; | |||
575 | } | |||
576 | ||||
577 | send_ra.if_index = engine_iface->if_index; | |||
578 | memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); | |||
579 | ||||
580 | TAILQ_REMOVE(&engine_interfaces, engine_iface, entry)do { if (((engine_iface)->entry.tqe_next) != ((void *)0)) ( engine_iface)->entry.tqe_next->entry.tqe_prev = (engine_iface )->entry.tqe_prev; else (&engine_interfaces)->tqh_last = (engine_iface)->entry.tqe_prev; *(engine_iface)->entry .tqe_prev = (engine_iface)->entry.tqe_next; ; ; } while (0 ); | |||
581 | evtimer_del(&engine_iface->timer)event_del(&engine_iface->timer); | |||
582 | ||||
583 | if (if_indextoname(if_index, if_name) != NULL((void *)0)) | |||
584 | engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, | |||
585 | sizeof(send_ra)); | |||
586 | engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, | |||
587 | &engine_iface->if_index, sizeof(engine_iface->if_index)); | |||
588 | free(engine_iface); | |||
589 | } | |||
590 | ||||
591 | void | |||
592 | iface_timeout(int fd, short events, void *arg) | |||
593 | { | |||
594 | struct engine_iface *engine_iface = (struct engine_iface *)arg; | |||
595 | struct imsg_send_ra send_ra; | |||
596 | struct timeval tv; | |||
597 | ||||
598 | tv.tv_sec = MIN_RTR_ADV_INTERVAL200 + | |||
599 | arc4random_uniform(MAX_RTR_ADV_INTERVAL600 - MIN_RTR_ADV_INTERVAL200); | |||
600 | tv.tv_usec = arc4random_uniform(1000000); | |||
601 | ||||
602 | log_debug("%s new timeout in %lld", __func__, tv.tv_sec); | |||
603 | ||||
604 | evtimer_add(&engine_iface->timer, &tv)event_add(&engine_iface->timer, &tv); | |||
605 | ||||
606 | send_ra.if_index = engine_iface->if_index; | |||
607 | memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); | |||
608 | engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, | |||
609 | sizeof(send_ra)); | |||
610 | } |