| 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 | } |