| File: | src/usr.sbin/eigrpd/eigrpd.c |
| Warning: | line 571, column 7 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: eigrpd.c,v 1.28 2021/01/19 10:53:25 claudio Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2015 Renato Westphal <renato@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 | #include <sys/types.h> | |||
| 23 | #include <sys/wait.h> | |||
| 24 | #include <sys/sysctl.h> | |||
| 25 | ||||
| 26 | #include <err.h> | |||
| 27 | #include <errno(*__errno()).h> | |||
| 28 | #include <fcntl.h> | |||
| 29 | #include <pwd.h> | |||
| 30 | #include <signal.h> | |||
| 31 | #include <stdio.h> | |||
| 32 | #include <stdlib.h> | |||
| 33 | #include <string.h> | |||
| 34 | #include <unistd.h> | |||
| 35 | ||||
| 36 | #include "eigrpd.h" | |||
| 37 | #include "eigrpe.h" | |||
| 38 | #include "rde.h" | |||
| 39 | #include "log.h" | |||
| 40 | ||||
| 41 | static void main_sig_handler(int, short, void *); | |||
| 42 | static __dead__attribute__((__noreturn__)) void usage(void); | |||
| 43 | static __dead__attribute__((__noreturn__)) void eigrpd_shutdown(void); | |||
| 44 | static pid_t start_child(enum eigrpd_process, char *, int, int, int, | |||
| 45 | char *); | |||
| 46 | static void main_dispatch_eigrpe(int, short, void *); | |||
| 47 | static void main_dispatch_rde(int, short, void *); | |||
| 48 | static int main_imsg_send_ipc_sockets(struct imsgbuf *, | |||
| 49 | struct imsgbuf *); | |||
| 50 | static int main_imsg_send_config(struct eigrpd_conf *); | |||
| 51 | static int eigrp_reload(void); | |||
| 52 | static int eigrp_sendboth(enum imsg_type, void *, uint16_t); | |||
| 53 | static void merge_instances(struct eigrpd_conf *, struct eigrp *, | |||
| 54 | struct eigrp *); | |||
| 55 | ||||
| 56 | struct eigrpd_conf *eigrpd_conf; | |||
| 57 | ||||
| 58 | static char *conffile; | |||
| 59 | static struct imsgev *iev_eigrpe; | |||
| 60 | static struct imsgev *iev_rde; | |||
| 61 | static pid_t eigrpe_pid; | |||
| 62 | static pid_t rde_pid; | |||
| 63 | ||||
| 64 | /* ARGSUSED */ | |||
| 65 | static void | |||
| 66 | main_sig_handler(int sig, short event, void *arg) | |||
| 67 | { | |||
| 68 | /* signal handler rules don't apply, libevent decouples for us */ | |||
| 69 | switch (sig) { | |||
| 70 | case SIGTERM15: | |||
| 71 | case SIGINT2: | |||
| 72 | eigrpd_shutdown(); | |||
| 73 | /* NOTREACHED */ | |||
| 74 | case SIGHUP1: | |||
| 75 | if (eigrp_reload() == -1) | |||
| 76 | log_warnx("configuration reload failed"); | |||
| 77 | else | |||
| 78 | log_debug("configuration reloaded"); | |||
| 79 | break; | |||
| 80 | default: | |||
| 81 | fatalx("unexpected signal"); | |||
| 82 | /* NOTREACHED */ | |||
| 83 | } | |||
| 84 | } | |||
| 85 | ||||
| 86 | static __dead__attribute__((__noreturn__)) void | |||
| 87 | usage(void) | |||
| 88 | { | |||
| 89 | extern char *__progname; | |||
| 90 | ||||
| 91 | fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-D macro=value]" | |||
| 92 | " [-f file] [-s socket]\n", | |||
| 93 | __progname); | |||
| 94 | exit(1); | |||
| 95 | } | |||
| 96 | ||||
| 97 | struct eigrpd_global global; | |||
| 98 | ||||
| 99 | int | |||
| 100 | main(int argc, char *argv[]) | |||
| 101 | { | |||
| 102 | struct event ev_sigint, ev_sigterm, ev_sighup; | |||
| 103 | char *saved_argv0; | |||
| 104 | int ch; | |||
| 105 | int debug = 0, rflag = 0, eflag = 0; | |||
| 106 | int ipforwarding; | |||
| 107 | int mib[4]; | |||
| 108 | size_t len; | |||
| 109 | char *sockname; | |||
| 110 | int pipe_parent2eigrpe[2]; | |||
| 111 | int pipe_parent2rde[2]; | |||
| 112 | ||||
| 113 | conffile = CONF_FILE"/etc/eigrpd.conf"; | |||
| 114 | log_procname = "parent"; | |||
| 115 | sockname = EIGRPD_SOCKET"/var/run/eigrpd.sock"; | |||
| 116 | ||||
| 117 | log_init(1); /* log to stderr until daemonized */ | |||
| 118 | log_verbose(1); | |||
| 119 | ||||
| 120 | saved_argv0 = argv[0]; | |||
| 121 | if (saved_argv0 == NULL((void *)0)) | |||
| 122 | saved_argv0 = "eigrpd"; | |||
| 123 | ||||
| 124 | while ((ch = getopt(argc, argv, "dD:f:ns:vRE")) != -1) { | |||
| 125 | switch (ch) { | |||
| 126 | case 'd': | |||
| 127 | debug = 1; | |||
| 128 | break; | |||
| 129 | case 'D': | |||
| 130 | if (cmdline_symset(optarg) < 0) | |||
| 131 | log_warnx("could not parse macro definition %s", | |||
| 132 | optarg); | |||
| 133 | break; | |||
| 134 | case 'f': | |||
| 135 | conffile = optarg; | |||
| 136 | break; | |||
| 137 | case 'n': | |||
| 138 | global.cmd_opts |= EIGRPD_OPT_NOACTION0x00000004; | |||
| 139 | break; | |||
| 140 | case 's': | |||
| 141 | sockname = optarg; | |||
| 142 | break; | |||
| 143 | case 'v': | |||
| 144 | if (global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001) | |||
| 145 | global.cmd_opts |= EIGRPD_OPT_VERBOSE20x00000002; | |||
| 146 | global.cmd_opts |= EIGRPD_OPT_VERBOSE0x00000001; | |||
| 147 | break; | |||
| 148 | case 'R': | |||
| 149 | rflag = 1; | |||
| 150 | break; | |||
| 151 | case 'E': | |||
| 152 | eflag = 1; | |||
| 153 | break; | |||
| 154 | default: | |||
| 155 | usage(); | |||
| 156 | /* NOTREACHED */ | |||
| 157 | } | |||
| 158 | } | |||
| 159 | ||||
| 160 | argc -= optind; | |||
| 161 | argv += optind; | |||
| 162 | if (argc > 0 || (rflag && eflag)) | |||
| 163 | usage(); | |||
| 164 | ||||
| 165 | if (rflag) | |||
| 166 | rde(debug, global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001); | |||
| 167 | else if (eflag) | |||
| 168 | eigrpe(debug, global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001, sockname); | |||
| 169 | ||||
| 170 | mib[0] = CTL_NET4; | |||
| 171 | mib[1] = PF_INET2; | |||
| 172 | mib[2] = IPPROTO_IP0; | |||
| 173 | mib[3] = IPCTL_FORWARDING1; | |||
| 174 | len = sizeof(ipforwarding); | |||
| 175 | if (sysctl(mib, 4, &ipforwarding, &len, NULL((void *)0), 0) == -1) | |||
| 176 | log_warn("sysctl"); | |||
| 177 | ||||
| 178 | if (ipforwarding != 1) | |||
| 179 | log_warnx("WARNING: IP forwarding NOT enabled"); | |||
| 180 | ||||
| 181 | /* fetch interfaces early */ | |||
| 182 | kif_init(); | |||
| 183 | ||||
| 184 | /* parse config file */ | |||
| 185 | if ((eigrpd_conf = parse_config(conffile)) == NULL((void *)0)) { | |||
| 186 | kif_clear(); | |||
| 187 | exit(1); | |||
| 188 | } | |||
| 189 | ||||
| 190 | if (global.cmd_opts & EIGRPD_OPT_NOACTION0x00000004) { | |||
| 191 | if (global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001) | |||
| 192 | print_config(eigrpd_conf); | |||
| 193 | else | |||
| 194 | fprintf(stderr(&__sF[2]), "configuration OK\n"); | |||
| 195 | kif_clear(); | |||
| 196 | exit(0); | |||
| 197 | } | |||
| 198 | ||||
| 199 | /* check for root privileges */ | |||
| 200 | if (geteuid()) | |||
| 201 | errx(1, "need root privileges"); | |||
| 202 | ||||
| 203 | /* check for eigrpd user */ | |||
| 204 | if (getpwnam(EIGRPD_USER"_eigrpd") == NULL((void *)0)) | |||
| 205 | errx(1, "unknown user %s", EIGRPD_USER"_eigrpd"); | |||
| 206 | ||||
| 207 | log_init(debug); | |||
| 208 | log_verbose(global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001); | |||
| 209 | ||||
| 210 | if (!debug) | |||
| 211 | daemon(1, 0); | |||
| 212 | ||||
| 213 | log_info("startup"); | |||
| 214 | ||||
| 215 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, | |||
| 216 | PF_UNSPEC0, pipe_parent2eigrpe) == -1) | |||
| 217 | fatal("socketpair"); | |||
| 218 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, | |||
| 219 | PF_UNSPEC0, pipe_parent2rde) == -1) | |||
| 220 | fatal("socketpair"); | |||
| 221 | ||||
| 222 | /* start children */ | |||
| 223 | rde_pid = start_child(PROC_RDE_ENGINE, saved_argv0, pipe_parent2rde[1], | |||
| 224 | debug, global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001, NULL((void *)0)); | |||
| 225 | eigrpe_pid = start_child(PROC_EIGRP_ENGINE, saved_argv0, | |||
| 226 | pipe_parent2eigrpe[1], debug, global.cmd_opts & EIGRPD_OPT_VERBOSE0x00000001, | |||
| 227 | sockname); | |||
| 228 | ||||
| 229 | event_init(); | |||
| 230 | ||||
| 231 | /* setup signal handler */ | |||
| 232 | signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void *)0)); | |||
| 233 | signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, ( (void *)0)); | |||
| 234 | signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void *)0)); | |||
| 235 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); | |||
| 236 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); | |||
| 237 | signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0)); | |||
| 238 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); | |||
| 239 | ||||
| 240 | /* setup pipes to children */ | |||
| 241 | if ((iev_eigrpe = malloc(sizeof(struct imsgev))) == NULL((void *)0) || | |||
| 242 | (iev_rde = malloc(sizeof(struct imsgev))) == NULL((void *)0)) | |||
| 243 | fatal(NULL((void *)0)); | |||
| 244 | imsg_init(&iev_eigrpe->ibuf, pipe_parent2eigrpe[0]); | |||
| 245 | iev_eigrpe->handler = main_dispatch_eigrpe; | |||
| 246 | imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]); | |||
| 247 | iev_rde->handler = main_dispatch_rde; | |||
| 248 | ||||
| 249 | /* setup event handler */ | |||
| 250 | iev_eigrpe->events = EV_READ0x02; | |||
| 251 | event_set(&iev_eigrpe->ev, iev_eigrpe->ibuf.fd, iev_eigrpe->events, | |||
| 252 | iev_eigrpe->handler, iev_eigrpe); | |||
| 253 | event_add(&iev_eigrpe->ev, NULL((void *)0)); | |||
| 254 | ||||
| 255 | iev_rde->events = EV_READ0x02; | |||
| 256 | event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, | |||
| 257 | iev_rde->handler, iev_rde); | |||
| 258 | event_add(&iev_rde->ev, NULL((void *)0)); | |||
| 259 | ||||
| 260 | if (main_imsg_send_ipc_sockets(&iev_eigrpe->ibuf, &iev_rde->ibuf)) | |||
| 261 | fatal("could not establish imsg links"); | |||
| 262 | main_imsg_send_config(eigrpd_conf); | |||
| 263 | ||||
| 264 | /* notify eigrpe about existing interfaces and addresses */ | |||
| 265 | kif_redistribute(); | |||
| 266 | ||||
| 267 | if (kr_init(!(eigrpd_conf->flags & EIGRPD_FLAG_NO_FIB_UPDATE0x0001), | |||
| 268 | eigrpd_conf->rdomain) == -1) | |||
| 269 | fatalx("kr_init failed"); | |||
| 270 | ||||
| 271 | if (pledge("stdio rpath inet sendfd", NULL((void *)0)) == -1) | |||
| 272 | fatal("pledge"); | |||
| 273 | ||||
| 274 | event_dispatch(); | |||
| 275 | ||||
| 276 | eigrpd_shutdown(); | |||
| 277 | /* NOTREACHED */ | |||
| 278 | return (0); | |||
| 279 | } | |||
| 280 | ||||
| 281 | static __dead__attribute__((__noreturn__)) void | |||
| 282 | eigrpd_shutdown(void) | |||
| 283 | { | |||
| 284 | pid_t pid; | |||
| 285 | int status; | |||
| 286 | ||||
| 287 | /* close pipes */ | |||
| 288 | msgbuf_clear(&iev_eigrpe->ibuf.w); | |||
| 289 | close(iev_eigrpe->ibuf.fd); | |||
| 290 | msgbuf_clear(&iev_rde->ibuf.w); | |||
| 291 | close(iev_rde->ibuf.fd); | |||
| 292 | ||||
| 293 | kr_shutdown(); | |||
| 294 | config_clear(eigrpd_conf, PROC_MAIN); | |||
| 295 | ||||
| 296 | log_debug("waiting for children to terminate"); | |||
| 297 | do { | |||
| 298 | pid = wait(&status); | |||
| 299 | if (pid == -1) { | |||
| 300 | if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10) | |||
| 301 | fatal("wait"); | |||
| 302 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) | |||
| 303 | log_warnx("%s terminated; signal %d", | |||
| 304 | (pid == rde_pid) ? "route decision engine" : | |||
| 305 | "eigrp engine", WTERMSIG(status)(((status) & 0177))); | |||
| 306 | } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4)); | |||
| 307 | ||||
| 308 | free(iev_eigrpe); | |||
| 309 | free(iev_rde); | |||
| 310 | ||||
| 311 | log_info("terminating"); | |||
| 312 | exit(0); | |||
| 313 | } | |||
| 314 | ||||
| 315 | static pid_t | |||
| 316 | start_child(enum eigrpd_process p, char *argv0, int fd, int debug, int verbose, | |||
| 317 | char *sockname) | |||
| 318 | { | |||
| 319 | char *argv[7]; | |||
| 320 | int argc = 0; | |||
| 321 | pid_t pid; | |||
| 322 | ||||
| 323 | switch (pid = fork()) { | |||
| 324 | case -1: | |||
| 325 | fatal("cannot fork"); | |||
| 326 | case 0: | |||
| 327 | break; | |||
| 328 | default: | |||
| 329 | close(fd); | |||
| 330 | return (pid); | |||
| 331 | } | |||
| 332 | ||||
| 333 | if (fd != 3) { | |||
| 334 | if (dup2(fd, 3) == -1) | |||
| 335 | fatal("cannot setup imsg fd"); | |||
| 336 | } else if (fcntl(fd, F_SETFD2, 0) == -1) | |||
| 337 | fatal("cannot setup imsg fd"); | |||
| 338 | ||||
| 339 | argv[argc++] = argv0; | |||
| 340 | switch (p) { | |||
| 341 | case PROC_MAIN: | |||
| 342 | fatalx("Can not start main process"); | |||
| 343 | case PROC_RDE_ENGINE: | |||
| 344 | argv[argc++] = "-R"; | |||
| 345 | break; | |||
| 346 | case PROC_EIGRP_ENGINE: | |||
| 347 | argv[argc++] = "-E"; | |||
| 348 | break; | |||
| 349 | } | |||
| 350 | if (debug) | |||
| 351 | argv[argc++] = "-d"; | |||
| 352 | if (verbose) | |||
| 353 | argv[argc++] = "-v"; | |||
| 354 | if (sockname) { | |||
| 355 | argv[argc++] = "-s"; | |||
| 356 | argv[argc++] = sockname; | |||
| 357 | } | |||
| 358 | argv[argc++] = NULL((void *)0); | |||
| 359 | ||||
| 360 | execvp(argv0, argv); | |||
| 361 | fatal("execvp"); | |||
| 362 | } | |||
| 363 | ||||
| 364 | /* imsg handling */ | |||
| 365 | /* ARGSUSED */ | |||
| 366 | static void | |||
| 367 | main_dispatch_eigrpe(int fd, short event, void *bula) | |||
| 368 | { | |||
| 369 | struct imsgev *iev = bula; | |||
| 370 | struct imsgbuf *ibuf; | |||
| 371 | struct imsg imsg; | |||
| 372 | ssize_t n; | |||
| 373 | int shut = 0, verbose; | |||
| 374 | ||||
| 375 | ibuf = &iev->ibuf; | |||
| 376 | ||||
| 377 | if (event & EV_READ0x02) { | |||
| ||||
| 378 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
| 379 | fatal("imsg_read error"); | |||
| 380 | if (n == 0) /* connection closed */ | |||
| 381 | shut = 1; | |||
| 382 | } | |||
| 383 | if (event & EV_WRITE0x04) { | |||
| 384 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
| 385 | fatal("msgbuf_write"); | |||
| 386 | if (n == 0) /* connection closed */ | |||
| 387 | shut = 1; | |||
| 388 | } | |||
| 389 | ||||
| 390 | for (;;) { | |||
| 391 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
| 392 | fatal("imsg_get"); | |||
| 393 | ||||
| 394 | if (n == 0) | |||
| 395 | break; | |||
| 396 | ||||
| 397 | switch (imsg.hdr.type) { | |||
| 398 | case IMSG_CTL_RELOAD: | |||
| 399 | if (eigrp_reload() == -1) | |||
| 400 | log_warnx("configuration reload failed"); | |||
| 401 | else | |||
| 402 | log_debug("configuration reloaded"); | |||
| 403 | break; | |||
| 404 | case IMSG_CTL_FIB_COUPLE: | |||
| 405 | kr_fib_couple(); | |||
| 406 | break; | |||
| 407 | case IMSG_CTL_FIB_DECOUPLE: | |||
| 408 | kr_fib_decouple(); | |||
| 409 | break; | |||
| 410 | case IMSG_CTL_KROUTE: | |||
| 411 | kr_show_route(&imsg); | |||
| 412 | break; | |||
| 413 | case IMSG_CTL_IFINFO: | |||
| 414 | if (imsg.hdr.len == IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) | |||
| 415 | kr_ifinfo(NULL((void *)0), imsg.hdr.pid); | |||
| 416 | else if (imsg.hdr.len == IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + IFNAMSIZ16) | |||
| 417 | kr_ifinfo(imsg.data, imsg.hdr.pid); | |||
| 418 | else | |||
| 419 | log_warnx("IFINFO request with wrong len"); | |||
| 420 | break; | |||
| 421 | case IMSG_CTL_LOG_VERBOSE: | |||
| 422 | /* already checked by eigrpe */ | |||
| 423 | memcpy(&verbose, imsg.data, sizeof(verbose)); | |||
| 424 | log_verbose(verbose); | |||
| 425 | break; | |||
| 426 | default: | |||
| 427 | log_debug("%s: error handling imsg %d", __func__, | |||
| 428 | imsg.hdr.type); | |||
| 429 | break; | |||
| 430 | } | |||
| 431 | imsg_free(&imsg); | |||
| 432 | } | |||
| 433 | if (!shut) | |||
| 434 | imsg_event_add(iev); | |||
| 435 | else { | |||
| 436 | /* this pipe is dead, so remove the event handler */ | |||
| 437 | event_del(&iev->ev); | |||
| 438 | event_loopexit(NULL((void *)0)); | |||
| 439 | } | |||
| 440 | } | |||
| 441 | ||||
| 442 | /* ARGSUSED */ | |||
| 443 | static void | |||
| 444 | main_dispatch_rde(int fd, short event, void *bula) | |||
| 445 | { | |||
| 446 | struct imsgev *iev = bula; | |||
| 447 | struct imsgbuf *ibuf; | |||
| 448 | struct imsg imsg; | |||
| 449 | ssize_t n; | |||
| 450 | int shut = 0; | |||
| 451 | ||||
| 452 | ibuf = &iev->ibuf; | |||
| 453 | ||||
| 454 | if (event & EV_READ0x02) { | |||
| 455 | if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35) | |||
| 456 | fatal("imsg_read error"); | |||
| 457 | if (n == 0) /* connection closed */ | |||
| 458 | shut = 1; | |||
| 459 | } | |||
| 460 | if (event & EV_WRITE0x04) { | |||
| 461 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35) | |||
| 462 | fatal("msgbuf_write"); | |||
| 463 | if (n == 0) /* connection closed */ | |||
| 464 | shut = 1; | |||
| 465 | } | |||
| 466 | ||||
| 467 | for (;;) { | |||
| 468 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |||
| 469 | fatal("imsg_get"); | |||
| 470 | ||||
| 471 | if (n == 0) | |||
| 472 | break; | |||
| 473 | ||||
| 474 | switch (imsg.hdr.type) { | |||
| 475 | case IMSG_KROUTE_CHANGE: | |||
| 476 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != | |||
| 477 | sizeof(struct kroute)) | |||
| 478 | fatalx("invalid size of IMSG_KROUTE_CHANGE"); | |||
| 479 | if (kr_change(imsg.data)) | |||
| 480 | log_warnx("%s: error changing route", __func__); | |||
| 481 | break; | |||
| 482 | case IMSG_KROUTE_DELETE: | |||
| 483 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != | |||
| 484 | sizeof(struct kroute)) | |||
| 485 | fatalx("invalid size of IMSG_KROUTE_DELETE"); | |||
| 486 | if (kr_delete(imsg.data)) | |||
| 487 | log_warnx("%s: error deleting route", __func__); | |||
| 488 | break; | |||
| 489 | ||||
| 490 | default: | |||
| 491 | log_debug("%s: error handling imsg %d", __func__, | |||
| 492 | imsg.hdr.type); | |||
| 493 | break; | |||
| 494 | } | |||
| 495 | imsg_free(&imsg); | |||
| 496 | } | |||
| 497 | if (!shut) | |||
| 498 | imsg_event_add(iev); | |||
| 499 | else { | |||
| 500 | /* this pipe is dead, so remove the event handler */ | |||
| 501 | event_del(&iev->ev); | |||
| 502 | event_loopexit(NULL((void *)0)); | |||
| 503 | } | |||
| 504 | } | |||
| 505 | ||||
| 506 | int | |||
| 507 | main_imsg_compose_eigrpe(int type, pid_t pid, void *data, uint16_t datalen) | |||
| 508 | { | |||
| 509 | if (iev_eigrpe == NULL((void *)0)) | |||
| 510 | return (-1); | |||
| 511 | return (imsg_compose_event(iev_eigrpe, type, 0, pid, -1, data, datalen)); | |||
| 512 | } | |||
| 513 | ||||
| 514 | int | |||
| 515 | main_imsg_compose_rde(int type, pid_t pid, void *data, uint16_t datalen) | |||
| 516 | { | |||
| 517 | if (iev_rde == NULL((void *)0)) | |||
| 518 | return (-1); | |||
| 519 | return (imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen)); | |||
| 520 | } | |||
| 521 | ||||
| 522 | void | |||
| 523 | imsg_event_add(struct imsgev *iev) | |||
| 524 | { | |||
| 525 | iev->events = EV_READ0x02; | |||
| 526 | if (iev->ibuf.w.queued) | |||
| 527 | iev->events |= EV_WRITE0x04; | |||
| 528 | ||||
| 529 | event_del(&iev->ev); | |||
| 530 | event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); | |||
| 531 | event_add(&iev->ev, NULL((void *)0)); | |||
| 532 | } | |||
| 533 | ||||
| 534 | int | |||
| 535 | imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, | |||
| 536 | pid_t pid, int fd, void *data, uint16_t datalen) | |||
| 537 | { | |||
| 538 | int ret; | |||
| 539 | ||||
| 540 | if ((ret = imsg_compose(&iev->ibuf, type, peerid, | |||
| 541 | pid, fd, data, datalen)) != -1) | |||
| 542 | imsg_event_add(iev); | |||
| 543 | return (ret); | |||
| 544 | } | |||
| 545 | ||||
| 546 | static int | |||
| 547 | main_imsg_send_ipc_sockets(struct imsgbuf *eigrpe_buf, struct imsgbuf *rde_buf) | |||
| 548 | { | |||
| 549 | int pipe_eigrpe2rde[2]; | |||
| 550 | ||||
| 551 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, | |||
| 552 | PF_UNSPEC0, pipe_eigrpe2rde) == -1) | |||
| 553 | return (-1); | |||
| 554 | ||||
| 555 | if (imsg_compose(eigrpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[0], | |||
| 556 | NULL((void *)0), 0) == -1) | |||
| 557 | return (-1); | |||
| 558 | if (imsg_compose(rde_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[1], | |||
| 559 | NULL((void *)0), 0) == -1) | |||
| 560 | return (-1); | |||
| 561 | ||||
| 562 | return (0); | |||
| 563 | } | |||
| 564 | ||||
| 565 | struct eigrp * | |||
| 566 | eigrp_find(struct eigrpd_conf *xconf, int af, uint16_t as) | |||
| 567 | { | |||
| 568 | struct eigrp *eigrp; | |||
| 569 | ||||
| 570 | TAILQ_FOREACH(eigrp, &xconf->instances, entry)for((eigrp) = ((&xconf->instances)->tqh_first); (eigrp ) != ((void *)0); (eigrp) = ((eigrp)->entry.tqe_next)) | |||
| 571 | if (eigrp->af == af && eigrp->as == as) | |||
| ||||
| 572 | return (eigrp); | |||
| 573 | ||||
| 574 | return (NULL((void *)0)); | |||
| 575 | } | |||
| 576 | ||||
| 577 | static int | |||
| 578 | main_imsg_send_config(struct eigrpd_conf *xconf) | |||
| 579 | { | |||
| 580 | struct eigrp *eigrp; | |||
| 581 | struct eigrp_iface *ei; | |||
| 582 | ||||
| 583 | if (eigrp_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) | |||
| 584 | return (-1); | |||
| 585 | ||||
| 586 | TAILQ_FOREACH(eigrp, &xconf->instances, entry)for((eigrp) = ((&xconf->instances)->tqh_first); (eigrp ) != ((void *)0); (eigrp) = ((eigrp)->entry.tqe_next)) { | |||
| 587 | if (eigrp_sendboth(IMSG_RECONF_INSTANCE, eigrp, | |||
| 588 | sizeof(*eigrp)) == -1) | |||
| 589 | return (-1); | |||
| 590 | ||||
| 591 | TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry)for((ei) = ((&eigrp->ei_list)->tqh_first); (ei) != ( (void *)0); (ei) = ((ei)->e_entry.tqe_next)) { | |||
| 592 | if (eigrp_sendboth(IMSG_RECONF_IFACE, ei->iface, | |||
| 593 | sizeof(struct iface)) == -1) | |||
| 594 | return (-1); | |||
| 595 | ||||
| 596 | if (eigrp_sendboth(IMSG_RECONF_EIGRP_IFACE, ei, | |||
| 597 | sizeof(*ei)) == -1) | |||
| 598 | return (-1); | |||
| 599 | } | |||
| 600 | } | |||
| 601 | ||||
| 602 | if (eigrp_sendboth(IMSG_RECONF_END, NULL((void *)0), 0) == -1) | |||
| 603 | return (-1); | |||
| 604 | ||||
| 605 | return (0); | |||
| 606 | } | |||
| 607 | ||||
| 608 | static int | |||
| 609 | eigrp_reload(void) | |||
| 610 | { | |||
| 611 | struct eigrpd_conf *xconf; | |||
| 612 | ||||
| 613 | if ((xconf = parse_config(conffile)) == NULL((void *)0)) | |||
| 614 | return (-1); | |||
| 615 | ||||
| 616 | if (main_imsg_send_config(xconf) == -1) | |||
| 617 | return (-1); | |||
| 618 | ||||
| 619 | merge_config(eigrpd_conf, xconf, PROC_MAIN); | |||
| 620 | ||||
| 621 | return (0); | |||
| 622 | } | |||
| 623 | ||||
| 624 | static int | |||
| 625 | eigrp_sendboth(enum imsg_type type, void *buf, uint16_t len) | |||
| 626 | { | |||
| 627 | if (main_imsg_compose_eigrpe(type, 0, buf, len) == -1) | |||
| 628 | return (-1); | |||
| 629 | if (main_imsg_compose_rde(type, 0, buf, len) == -1) | |||
| 630 | return (-1); | |||
| 631 | return (0); | |||
| 632 | } | |||
| 633 | ||||
| 634 | void | |||
| 635 | merge_config(struct eigrpd_conf *conf, struct eigrpd_conf *xconf, | |||
| 636 | enum eigrpd_process proc) | |||
| 637 | { | |||
| 638 | struct iface *iface, *itmp, *xi; | |||
| 639 | struct eigrp *eigrp, *etmp, *xe; | |||
| 640 | ||||
| 641 | conf->rtr_id = xconf->rtr_id; | |||
| 642 | conf->flags = xconf->flags; | |||
| 643 | conf->rdomain= xconf->rdomain; | |||
| 644 | conf->fib_priority_internal = xconf->fib_priority_internal; | |||
| 645 | conf->fib_priority_external = xconf->fib_priority_external; | |||
| 646 | conf->fib_priority_summary = xconf->fib_priority_summary; | |||
| 647 | ||||
| 648 | /* merge instances */ | |||
| 649 | TAILQ_FOREACH_SAFE(eigrp, &conf->instances, entry, etmp)for ((eigrp) = ((&conf->instances)->tqh_first); (eigrp ) != ((void *)0) && ((etmp) = ((eigrp)->entry.tqe_next ), 1); (eigrp) = (etmp)) { | |||
| 650 | /* find deleted instances */ | |||
| 651 | if ((xe = eigrp_find(xconf, eigrp->af, eigrp->as)) == NULL((void *)0)) { | |||
| 652 | TAILQ_REMOVE(&conf->instances, eigrp, entry)do { if (((eigrp)->entry.tqe_next) != ((void *)0)) (eigrp) ->entry.tqe_next->entry.tqe_prev = (eigrp)->entry.tqe_prev ; else (&conf->instances)->tqh_last = (eigrp)->entry .tqe_prev; *(eigrp)->entry.tqe_prev = (eigrp)->entry.tqe_next ; ; ; } while (0); | |||
| 653 | ||||
| 654 | switch (proc) { | |||
| 655 | case PROC_RDE_ENGINE: | |||
| 656 | rde_instance_del(eigrp); | |||
| 657 | break; | |||
| 658 | case PROC_EIGRP_ENGINE: | |||
| 659 | eigrpe_instance_del(eigrp); | |||
| 660 | break; | |||
| 661 | case PROC_MAIN: | |||
| 662 | free(eigrp); | |||
| 663 | break; | |||
| 664 | } | |||
| 665 | } | |||
| 666 | } | |||
| 667 | TAILQ_FOREACH_SAFE(xe, &xconf->instances, entry, etmp)for ((xe) = ((&xconf->instances)->tqh_first); (xe) != ((void *)0) && ((etmp) = ((xe)->entry.tqe_next), 1 ); (xe) = (etmp)) { | |||
| 668 | /* find new instances */ | |||
| 669 | if ((eigrp = eigrp_find(conf, xe->af, xe->as)) == NULL((void *)0)) { | |||
| 670 | TAILQ_REMOVE(&xconf->instances, xe, entry)do { if (((xe)->entry.tqe_next) != ((void *)0)) (xe)->entry .tqe_next->entry.tqe_prev = (xe)->entry.tqe_prev; else ( &xconf->instances)->tqh_last = (xe)->entry.tqe_prev ; *(xe)->entry.tqe_prev = (xe)->entry.tqe_next; ; ; } while (0); | |||
| 671 | TAILQ_INSERT_TAIL(&conf->instances, xe, entry)do { (xe)->entry.tqe_next = ((void *)0); (xe)->entry.tqe_prev = (&conf->instances)->tqh_last; *(&conf->instances )->tqh_last = (xe); (&conf->instances)->tqh_last = &(xe)->entry.tqe_next; } while (0); | |||
| 672 | ||||
| 673 | switch (proc) { | |||
| 674 | case PROC_RDE_ENGINE: | |||
| 675 | rde_instance_init(xe); | |||
| 676 | break; | |||
| 677 | case PROC_EIGRP_ENGINE: | |||
| 678 | eigrpe_instance_init(xe); | |||
| 679 | break; | |||
| 680 | case PROC_MAIN: | |||
| 681 | break; | |||
| 682 | } | |||
| 683 | continue; | |||
| 684 | } | |||
| 685 | ||||
| 686 | /* update existing instances */ | |||
| 687 | merge_instances(conf, eigrp, xe); | |||
| 688 | } | |||
| 689 | ||||
| 690 | /* merge interfaces */ | |||
| 691 | TAILQ_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp)for ((iface) = ((&conf->iface_list)->tqh_first); (iface ) != ((void *)0) && ((itmp) = ((iface)->entry.tqe_next ), 1); (iface) = (itmp)) { | |||
| 692 | /* find deleted ifaces */ | |||
| 693 | if ((xi = if_lookup(xconf, iface->ifindex)) == NULL((void *)0)) { | |||
| 694 | TAILQ_REMOVE(&conf->iface_list, iface, entry)do { if (((iface)->entry.tqe_next) != ((void *)0)) (iface) ->entry.tqe_next->entry.tqe_prev = (iface)->entry.tqe_prev ; else (&conf->iface_list)->tqh_last = (iface)-> entry.tqe_prev; *(iface)->entry.tqe_prev = (iface)->entry .tqe_next; ; ; } while (0); | |||
| 695 | free(iface); | |||
| 696 | } | |||
| 697 | } | |||
| 698 | TAILQ_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp)for ((xi) = ((&xconf->iface_list)->tqh_first); (xi) != ((void *)0) && ((itmp) = ((xi)->entry.tqe_next ), 1); (xi) = (itmp)) { | |||
| 699 | /* find new ifaces */ | |||
| 700 | if ((iface = if_lookup(conf, xi->ifindex)) == NULL((void *)0)) { | |||
| 701 | TAILQ_REMOVE(&xconf->iface_list, xi, entry)do { if (((xi)->entry.tqe_next) != ((void *)0)) (xi)->entry .tqe_next->entry.tqe_prev = (xi)->entry.tqe_prev; else ( &xconf->iface_list)->tqh_last = (xi)->entry.tqe_prev ; *(xi)->entry.tqe_prev = (xi)->entry.tqe_next; ; ; } while (0); | |||
| 702 | TAILQ_INSERT_TAIL(&conf->iface_list, xi, entry)do { (xi)->entry.tqe_next = ((void *)0); (xi)->entry.tqe_prev = (&conf->iface_list)->tqh_last; *(&conf->iface_list )->tqh_last = (xi); (&conf->iface_list)->tqh_last = &(xi)->entry.tqe_next; } while (0); | |||
| 703 | continue; | |||
| 704 | } | |||
| 705 | ||||
| 706 | /* TODO update existing ifaces */ | |||
| 707 | } | |||
| 708 | ||||
| 709 | /* resend addresses to activate new interfaces */ | |||
| 710 | if (proc == PROC_MAIN) | |||
| 711 | kif_redistribute(); | |||
| 712 | ||||
| 713 | free(xconf); | |||
| 714 | } | |||
| 715 | ||||
| 716 | static void | |||
| 717 | merge_instances(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct eigrp *xe) | |||
| 718 | { | |||
| 719 | /* TODO */ | |||
| 720 | } | |||
| 721 | ||||
| 722 | struct eigrpd_conf * | |||
| 723 | config_new_empty(void) | |||
| 724 | { | |||
| 725 | struct eigrpd_conf *xconf; | |||
| 726 | ||||
| 727 | xconf = calloc(1, sizeof(*xconf)); | |||
| 728 | if (xconf == NULL((void *)0)) | |||
| 729 | fatal(NULL((void *)0)); | |||
| 730 | ||||
| 731 | TAILQ_INIT(&xconf->instances)do { (&xconf->instances)->tqh_first = ((void *)0); ( &xconf->instances)->tqh_last = &(&xconf-> instances)->tqh_first; } while (0); | |||
| 732 | TAILQ_INIT(&xconf->iface_list)do { (&xconf->iface_list)->tqh_first = ((void *)0); (&xconf->iface_list)->tqh_last = &(&xconf-> iface_list)->tqh_first; } while (0); | |||
| 733 | ||||
| 734 | return (xconf); | |||
| 735 | } | |||
| 736 | ||||
| 737 | void | |||
| 738 | config_clear(struct eigrpd_conf *conf, enum eigrpd_process proc) | |||
| 739 | { | |||
| 740 | struct eigrpd_conf *xconf; | |||
| 741 | ||||
| 742 | /* merge current config with an empty config */ | |||
| 743 | xconf = config_new_empty(); | |||
| 744 | merge_config(conf, xconf, proc); | |||
| 745 | ||||
| 746 | free(conf); | |||
| 747 | } |