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