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