File: | src/usr.sbin/bgpd/bgpd.c |
Warning: | line 192, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: bgpd.c,v 1.239 2021/07/20 12:07:46 claudio Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/types.h> |
20 | #include <sys/socket.h> |
21 | #include <sys/wait.h> |
22 | #include <netinet/in.h> |
23 | #include <arpa/inet.h> |
24 | #include <err.h> |
25 | #include <errno(*__errno()).h> |
26 | #include <fcntl.h> |
27 | #include <poll.h> |
28 | #include <pwd.h> |
29 | #include <signal.h> |
30 | #include <stdio.h> |
31 | #include <stdlib.h> |
32 | #include <string.h> |
33 | #include <syslog.h> |
34 | #include <unistd.h> |
35 | |
36 | #include "bgpd.h" |
37 | #include "session.h" |
38 | #include "log.h" |
39 | #include "version.h" |
40 | |
41 | void sighdlr(int); |
42 | __dead__attribute__((__noreturn__)) void usage(void); |
43 | int main(int, char *[]); |
44 | pid_t start_child(enum bgpd_process, char *, int, int, int); |
45 | int send_filterset(struct imsgbuf *, struct filter_set_head *); |
46 | int reconfigure(char *, struct bgpd_config *); |
47 | int send_config(struct bgpd_config *); |
48 | int dispatch_imsg(struct imsgbuf *, int, struct bgpd_config *); |
49 | int control_setup(struct bgpd_config *); |
50 | static void getsockpair(int [2]); |
51 | int imsg_send_sockets(struct imsgbuf *, struct imsgbuf *, |
52 | struct imsgbuf *); |
53 | void bgpd_rtr_connect(struct rtr_config *); |
54 | void bgpd_rtr_connect_done(int, struct bgpd_config *); |
55 | |
56 | int cflags; |
57 | volatile sig_atomic_t mrtdump; |
58 | volatile sig_atomic_t quit; |
59 | volatile sig_atomic_t reconfig; |
60 | pid_t reconfpid; |
61 | int reconfpending; |
62 | struct imsgbuf *ibuf_se; |
63 | struct imsgbuf *ibuf_rde; |
64 | struct imsgbuf *ibuf_rtr; |
65 | struct rib_names ribnames = SIMPLEQ_HEAD_INITIALIZER(ribnames){ ((void *)0), &(ribnames).sqh_first }; |
66 | char *cname; |
67 | char *rcname; |
68 | |
69 | struct connect_elm { |
70 | TAILQ_ENTRY(connect_elm)struct { struct connect_elm *tqe_next; struct connect_elm **tqe_prev ; } entry; |
71 | u_int32_t id; |
72 | int fd; |
73 | }; |
74 | |
75 | TAILQ_HEAD( ,connect_elm)struct { struct connect_elm *tqh_first; struct connect_elm ** tqh_last; } connect_queue = \ |
76 | TAILQ_HEAD_INITIALIZER(connect_queue){ ((void *)0), &(connect_queue).tqh_first }; |
77 | u_int connect_cnt; |
78 | #define MAX_CONNECT_CNT32 32 |
79 | |
80 | void |
81 | sighdlr(int sig) |
82 | { |
83 | switch (sig) { |
84 | case SIGTERM15: |
85 | case SIGINT2: |
86 | quit = 1; |
87 | break; |
88 | case SIGHUP1: |
89 | reconfig = 1; |
90 | break; |
91 | case SIGALRM14: |
92 | case SIGUSR130: |
93 | mrtdump = 1; |
94 | break; |
95 | } |
96 | } |
97 | |
98 | __dead__attribute__((__noreturn__)) void |
99 | usage(void) |
100 | { |
101 | extern char *__progname; |
102 | |
103 | fprintf(stderr(&__sF[2]), "usage: %s [-cdnvV] [-D macro=value] [-f file]\n", |
104 | __progname); |
105 | exit(1); |
106 | } |
107 | |
108 | #define PFD_PIPE_SESSION0 0 |
109 | #define PFD_PIPE_RDE1 1 |
110 | #define PFD_PIPE_RTR2 2 |
111 | #define PFD_SOCK_ROUTE3 3 |
112 | #define PFD_SOCK_PFKEY4 4 |
113 | #define PFD_CONNECT_START5 5 |
114 | #define MAX_TIMEOUT3600 3600 |
115 | |
116 | int cmd_opts; |
117 | |
118 | int |
119 | main(int argc, char *argv[]) |
120 | { |
121 | struct bgpd_config *conf; |
122 | enum bgpd_process proc = PROC_MAIN; |
123 | struct rde_rib *rr; |
124 | struct peer *p; |
125 | struct pollfd *pfd = NULL((void *)0); |
126 | struct connect_elm *ce; |
127 | time_t timeout; |
128 | pid_t se_pid = 0, rde_pid = 0, rtr_pid = 0, pid; |
129 | char *conffile; |
130 | char *saved_argv0; |
131 | u_int pfd_elms = 0, npfd, i; |
132 | int debug = 0; |
133 | int rfd, keyfd; |
134 | int ch, status; |
135 | int pipe_m2s[2]; |
136 | int pipe_m2r[2]; |
137 | int pipe_m2roa[2]; |
138 | |
139 | conffile = CONFFILE"/etc/bgpd.conf"; |
140 | |
141 | log_init(1, LOG_DAEMON(3<<3)); /* log to stderr until daemonized */ |
142 | log_procinit(log_procnames[PROC_MAIN]); |
143 | log_setverbose(1); |
144 | |
145 | saved_argv0 = argv[0]; |
146 | if (saved_argv0 == NULL((void *)0)) |
147 | saved_argv0 = "bgpd"; |
148 | |
149 | while ((ch = getopt(argc, argv, "cdD:f:nRSTvV")) != -1) { |
150 | switch (ch) { |
151 | case 'c': |
152 | cmd_opts |= BGPD_OPT_FORCE_DEMOTE0x0008; |
153 | break; |
154 | case 'd': |
155 | debug = 1; |
156 | break; |
157 | case 'D': |
158 | if (cmdline_symset(optarg) < 0) |
159 | log_warnx("could not parse macro definition %s", |
160 | optarg); |
161 | break; |
162 | case 'f': |
163 | conffile = optarg; |
164 | break; |
165 | case 'n': |
166 | cmd_opts |= BGPD_OPT_NOACTION0x0004; |
167 | break; |
168 | case 'v': |
169 | if (cmd_opts & BGPD_OPT_VERBOSE0x0001) |
170 | cmd_opts |= BGPD_OPT_VERBOSE20x0002; |
171 | cmd_opts |= BGPD_OPT_VERBOSE0x0001; |
172 | break; |
173 | case 'R': |
174 | proc = PROC_RDE; |
175 | break; |
176 | case 'S': |
177 | proc = PROC_SE; |
178 | break; |
179 | case 'T': |
180 | proc = PROC_RTR; |
181 | break; |
182 | case 'V': |
183 | fprintf(stderr(&__sF[2]), "OpenBGPD %s\n", BGPD_VERSION"7.2"); |
184 | return 0; |
185 | default: |
186 | usage(); |
187 | /* NOTREACHED */ |
188 | } |
189 | } |
190 | |
191 | argc -= optind; |
192 | argv += optind; |
Value stored to 'argv' is never read | |
193 | if (argc > 0) |
194 | usage(); |
195 | |
196 | if (cmd_opts & BGPD_OPT_NOACTION0x0004) { |
197 | if ((conf = parse_config(conffile, NULL((void *)0), NULL((void *)0))) == NULL((void *)0)) |
198 | exit(1); |
199 | |
200 | if (cmd_opts & BGPD_OPT_VERBOSE0x0001) |
201 | print_config(conf, &ribnames); |
202 | else |
203 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
204 | |
205 | while ((rr = SIMPLEQ_FIRST(&ribnames)((&ribnames)->sqh_first)) != NULL((void *)0)) { |
206 | SIMPLEQ_REMOVE_HEAD(&ribnames, entry)do { if (((&ribnames)->sqh_first = (&ribnames)-> sqh_first->entry.sqe_next) == ((void *)0)) (&ribnames) ->sqh_last = &(&ribnames)->sqh_first; } while ( 0); |
207 | free(rr); |
208 | } |
209 | free_config(conf); |
210 | exit(0); |
211 | } |
212 | |
213 | switch (proc) { |
214 | case PROC_MAIN: |
215 | break; |
216 | case PROC_RDE: |
217 | rde_main(debug, cmd_opts & BGPD_OPT_VERBOSE0x0001); |
218 | /* NOTREACHED */ |
219 | case PROC_SE: |
220 | session_main(debug, cmd_opts & BGPD_OPT_VERBOSE0x0001); |
221 | /* NOTREACHED */ |
222 | case PROC_RTR: |
223 | rtr_main(debug, cmd_opts & BGPD_OPT_VERBOSE0x0001); |
224 | /* NOTREACHED */ |
225 | } |
226 | |
227 | if (geteuid()) |
228 | errx(1, "need root privileges"); |
229 | |
230 | if (getpwnam(BGPD_USER"_bgpd") == NULL((void *)0)) |
231 | errx(1, "unknown user %s", BGPD_USER"_bgpd"); |
232 | |
233 | if ((conf = parse_config(conffile, NULL((void *)0), NULL((void *)0))) == NULL((void *)0)) { |
234 | log_warnx("config file %s has errors", conffile); |
235 | exit(1); |
236 | } |
237 | |
238 | if (prepare_listeners(conf) == -1) |
239 | exit(1); |
240 | |
241 | log_init(debug, LOG_DAEMON(3<<3)); |
242 | log_setverbose(cmd_opts & BGPD_OPT_VERBOSE0x0001); |
243 | |
244 | if (!debug) |
245 | daemon(1, 0); |
246 | |
247 | log_info("startup"); |
248 | |
249 | getsockpair(pipe_m2s); |
250 | getsockpair(pipe_m2r); |
251 | getsockpair(pipe_m2roa); |
252 | |
253 | /* fork children */ |
254 | rde_pid = start_child(PROC_RDE, saved_argv0, pipe_m2r[1], debug, |
255 | cmd_opts & BGPD_OPT_VERBOSE0x0001); |
256 | se_pid = start_child(PROC_SE, saved_argv0, pipe_m2s[1], debug, |
257 | cmd_opts & BGPD_OPT_VERBOSE0x0001); |
258 | rtr_pid = start_child(PROC_RTR, saved_argv0, pipe_m2roa[1], debug, |
259 | cmd_opts & BGPD_OPT_VERBOSE0x0001); |
260 | |
261 | signal(SIGTERM15, sighdlr); |
262 | signal(SIGINT2, sighdlr); |
263 | signal(SIGHUP1, sighdlr); |
264 | signal(SIGALRM14, sighdlr); |
265 | signal(SIGUSR130, sighdlr); |
266 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); |
267 | |
268 | if ((ibuf_se = malloc(sizeof(struct imsgbuf))) == NULL((void *)0) || |
269 | (ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL((void *)0) || |
270 | (ibuf_rtr = malloc(sizeof(struct imsgbuf))) == NULL((void *)0)) |
271 | fatal(NULL((void *)0)); |
272 | imsg_init(ibuf_se, pipe_m2s[0]); |
273 | imsg_init(ibuf_rde, pipe_m2r[0]); |
274 | imsg_init(ibuf_rtr, pipe_m2roa[0]); |
275 | mrt_init(ibuf_rde, ibuf_se); |
276 | if (kr_init(&rfd) == -1) |
277 | quit = 1; |
278 | keyfd = pfkey_init(); |
279 | |
280 | /* |
281 | * rpath, read config file |
282 | * cpath, unlink control socket |
283 | * fattr, chmod on control socket |
284 | * wpath, needed if we are doing mrt dumps |
285 | * |
286 | * pledge placed here because kr_init() does a setsockopt on the |
287 | * routing socket thats not allowed at all. |
288 | */ |
289 | #if 0 |
290 | /* |
291 | * disabled because we do ioctls on /dev/pf and SIOCSIFGATTR |
292 | * this needs some redesign of bgpd to be fixed. |
293 | */ |
294 | BROKEN if (pledge("stdio rpath wpath cpath fattr unix route recvfd sendfd", |
295 | NULL((void *)0)) == -1) |
296 | fatal("pledge"); |
297 | #endif |
298 | |
299 | if (imsg_send_sockets(ibuf_se, ibuf_rde, ibuf_rtr)) |
300 | fatal("could not establish imsg links"); |
301 | /* control setup needs to happen late since it sends imsgs */ |
302 | if (control_setup(conf) == -1) |
303 | quit = 1; |
304 | if (send_config(conf) != 0) |
305 | quit = 1; |
306 | if (pftable_clear_all() != 0) |
307 | quit = 1; |
308 | |
309 | while (quit == 0) { |
310 | if (pfd_elms < PFD_CONNECT_START5 + connect_cnt) { |
311 | struct pollfd *newp; |
312 | |
313 | if ((newp = reallocarray(pfd, |
314 | PFD_CONNECT_START5 + connect_cnt, |
315 | sizeof(struct pollfd))) == NULL((void *)0)) { |
316 | log_warn("could not resize pfd from %u -> %u" |
317 | " entries", pfd_elms, PFD_CONNECT_START5 + |
318 | connect_cnt); |
319 | fatalx("exiting"); |
320 | } |
321 | pfd = newp; |
322 | pfd_elms = PFD_CONNECT_START5 + connect_cnt; |
323 | } |
324 | bzero(pfd, sizeof(struct pollfd) * pfd_elms); |
325 | |
326 | timeout = mrt_timeout(conf->mrt); |
327 | |
328 | pfd[PFD_SOCK_ROUTE3].fd = rfd; |
329 | pfd[PFD_SOCK_ROUTE3].events = POLLIN0x0001; |
330 | |
331 | pfd[PFD_SOCK_PFKEY4].fd = keyfd; |
332 | pfd[PFD_SOCK_PFKEY4].events = POLLIN0x0001; |
333 | |
334 | set_pollfd(&pfd[PFD_PIPE_SESSION0], ibuf_se); |
335 | set_pollfd(&pfd[PFD_PIPE_RDE1], ibuf_rde); |
336 | set_pollfd(&pfd[PFD_PIPE_RTR2], ibuf_rtr); |
337 | |
338 | npfd = PFD_CONNECT_START5; |
339 | TAILQ_FOREACH(ce, &connect_queue, entry)for((ce) = ((&connect_queue)->tqh_first); (ce) != ((void *)0); (ce) = ((ce)->entry.tqe_next)) { |
340 | pfd[npfd].fd = ce->fd; |
341 | pfd[npfd++].events = POLLOUT0x0004; |
342 | if (npfd > pfd_elms) |
343 | fatalx("polli pfd overflow"); |
344 | } |
345 | |
346 | if (timeout < 0 || timeout > MAX_TIMEOUT3600) |
347 | timeout = MAX_TIMEOUT3600; |
348 | if (poll(pfd, npfd, timeout * 1000) == -1) |
349 | if (errno(*__errno()) != EINTR4) { |
350 | log_warn("poll error"); |
351 | quit = 1; |
352 | } |
353 | |
354 | if (handle_pollfd(&pfd[PFD_PIPE_SESSION0], ibuf_se) == -1) { |
355 | log_warnx("main: Lost connection to SE"); |
356 | msgbuf_clear(&ibuf_se->w); |
357 | free(ibuf_se); |
358 | ibuf_se = NULL((void *)0); |
359 | quit = 1; |
360 | } else { |
361 | if (dispatch_imsg(ibuf_se, PFD_PIPE_SESSION0, conf) == |
362 | -1) |
363 | quit = 1; |
364 | } |
365 | |
366 | if (handle_pollfd(&pfd[PFD_PIPE_RDE1], ibuf_rde) == -1) { |
367 | log_warnx("main: Lost connection to RDE"); |
368 | msgbuf_clear(&ibuf_rde->w); |
369 | free(ibuf_rde); |
370 | ibuf_rde = NULL((void *)0); |
371 | quit = 1; |
372 | } else { |
373 | if (dispatch_imsg(ibuf_rde, PFD_PIPE_RDE1, conf) == -1) |
374 | quit = 1; |
375 | } |
376 | |
377 | if (handle_pollfd(&pfd[PFD_PIPE_RTR2], ibuf_rtr) == -1) { |
378 | log_warnx("main: Lost connection to RTR"); |
379 | msgbuf_clear(&ibuf_rtr->w); |
380 | free(ibuf_rtr); |
381 | ibuf_rtr = NULL((void *)0); |
382 | quit = 1; |
383 | } else { |
384 | if (dispatch_imsg(ibuf_rtr, PFD_PIPE_RTR2, conf) == -1) |
385 | quit = 1; |
386 | } |
387 | |
388 | if (pfd[PFD_SOCK_ROUTE3].revents & POLLIN0x0001) { |
389 | if (kr_dispatch_msg(conf->default_tableid) == -1) |
390 | quit = 1; |
391 | } |
392 | |
393 | if (pfd[PFD_SOCK_PFKEY4].revents & POLLIN0x0001) { |
394 | if (pfkey_read(keyfd, NULL((void *)0)) == -1) { |
395 | log_warnx("pfkey_read failed, exiting..."); |
396 | quit = 1; |
397 | } |
398 | } |
399 | |
400 | for (i = PFD_CONNECT_START5; i < npfd; i++) |
401 | if (pfd[i].revents != 0) |
402 | bgpd_rtr_connect_done(pfd[i].fd, conf); |
403 | |
404 | if (reconfig) { |
405 | u_int error; |
406 | |
407 | reconfig = 0; |
408 | switch (reconfigure(conffile, conf)) { |
409 | case -1: /* fatal error */ |
410 | quit = 1; |
411 | break; |
412 | case 0: /* all OK */ |
413 | error = 0; |
414 | break; |
415 | case 2: |
416 | log_info("previous reload still running"); |
417 | error = CTL_RES_PENDING; |
418 | break; |
419 | default: /* parse error */ |
420 | log_warnx("config file %s has errors, " |
421 | "not reloading", conffile); |
422 | error = CTL_RES_PARSE_ERROR; |
423 | break; |
424 | } |
425 | if (reconfpid != 0) { |
426 | send_imsg_session(IMSG_CTL_RESULT, reconfpid, |
427 | &error, sizeof(error)); |
428 | reconfpid = 0; |
429 | } |
430 | } |
431 | |
432 | if (mrtdump) { |
433 | mrtdump = 0; |
434 | mrt_handler(conf->mrt); |
435 | } |
436 | } |
437 | |
438 | /* close pipes */ |
439 | if (ibuf_se) { |
440 | msgbuf_clear(&ibuf_se->w); |
441 | close(ibuf_se->fd); |
442 | free(ibuf_se); |
443 | ibuf_se = NULL((void *)0); |
444 | } |
445 | if (ibuf_rde) { |
446 | msgbuf_clear(&ibuf_rde->w); |
447 | close(ibuf_rde->fd); |
448 | free(ibuf_rde); |
449 | ibuf_rde = NULL((void *)0); |
450 | } |
451 | if (ibuf_rtr) { |
452 | msgbuf_clear(&ibuf_rtr->w); |
453 | close(ibuf_rtr->fd); |
454 | free(ibuf_rtr); |
455 | ibuf_rtr = NULL((void *)0); |
456 | } |
457 | |
458 | /* cleanup kernel data structures */ |
459 | carp_demote_shutdown(); |
460 | kr_shutdown(conf->fib_priority, conf->default_tableid); |
461 | pftable_clear_all(); |
462 | |
463 | RB_FOREACH(p, peer_head, &conf->peers)for ((p) = peer_head_RB_MINMAX(&conf->peers, -1); (p) != ((void *)0); (p) = peer_head_RB_NEXT(p)) |
464 | pfkey_remove(p); |
465 | |
466 | while ((rr = SIMPLEQ_FIRST(&ribnames)((&ribnames)->sqh_first)) != NULL((void *)0)) { |
467 | SIMPLEQ_REMOVE_HEAD(&ribnames, entry)do { if (((&ribnames)->sqh_first = (&ribnames)-> sqh_first->entry.sqe_next) == ((void *)0)) (&ribnames) ->sqh_last = &(&ribnames)->sqh_first; } while ( 0); |
468 | free(rr); |
469 | } |
470 | free_config(conf); |
471 | |
472 | log_debug("waiting for children to terminate"); |
473 | do { |
474 | pid = wait(&status); |
475 | if (pid == -1) { |
476 | if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10) |
477 | fatal("wait"); |
478 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) { |
479 | char *name = "unknown process"; |
480 | if (pid == rde_pid) |
481 | name = "route decision engine"; |
482 | else if (pid == se_pid) |
483 | name = "session engine"; |
484 | else if (pid == rtr_pid) |
485 | name = "rtr engine"; |
486 | log_warnx("%s terminated; signal %d", name, |
487 | WTERMSIG(status)(((status) & 0177))); |
488 | } |
489 | } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4)); |
490 | |
491 | free(rcname); |
492 | free(cname); |
493 | |
494 | log_info("terminating"); |
495 | return (0); |
496 | } |
497 | |
498 | pid_t |
499 | start_child(enum bgpd_process p, char *argv0, int fd, int debug, int verbose) |
500 | { |
501 | char *argv[5]; |
502 | int argc = 0; |
503 | pid_t pid; |
504 | |
505 | switch (pid = fork()) { |
506 | case -1: |
507 | fatal("cannot fork"); |
508 | case 0: |
509 | break; |
510 | default: |
511 | close(fd); |
512 | return (pid); |
513 | } |
514 | |
515 | if (fd != 3) { |
516 | if (dup2(fd, 3) == -1) |
517 | fatal("cannot setup imsg fd"); |
518 | } else if (fcntl(fd, F_SETFD2, 0) == -1) |
519 | fatal("cannot setup imsg fd"); |
520 | |
521 | argv[argc++] = argv0; |
522 | switch (p) { |
523 | case PROC_MAIN: |
524 | fatalx("Can not start main process"); |
525 | case PROC_RDE: |
526 | argv[argc++] = "-R"; |
527 | break; |
528 | case PROC_SE: |
529 | argv[argc++] = "-S"; |
530 | break; |
531 | case PROC_RTR: |
532 | argv[argc++] = "-T"; |
533 | break; |
534 | } |
535 | if (debug) |
536 | argv[argc++] = "-d"; |
537 | if (verbose) |
538 | argv[argc++] = "-v"; |
539 | argv[argc++] = NULL((void *)0); |
540 | |
541 | execvp(argv0, argv); |
542 | fatal("execvp"); |
543 | } |
544 | |
545 | int |
546 | send_filterset(struct imsgbuf *i, struct filter_set_head *set) |
547 | { |
548 | struct filter_set *s; |
549 | |
550 | TAILQ_FOREACH(s, set, entry)for((s) = ((set)->tqh_first); (s) != ((void *)0); (s) = (( s)->entry.tqe_next)) |
551 | if (imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, |
552 | sizeof(struct filter_set)) == -1) |
553 | return (-1); |
554 | return (0); |
555 | } |
556 | |
557 | int |
558 | reconfigure(char *conffile, struct bgpd_config *conf) |
559 | { |
560 | struct bgpd_config *new_conf; |
561 | |
562 | if (reconfpending) |
563 | return (2); |
564 | |
565 | log_info("rereading config"); |
566 | if ((new_conf = parse_config(conffile, &conf->peers, |
567 | &conf->rtrs)) == NULL((void *)0)) |
568 | return (1); |
569 | |
570 | merge_config(conf, new_conf); |
571 | |
572 | if (prepare_listeners(conf) == -1) { |
573 | return (1); |
574 | } |
575 | |
576 | if (control_setup(conf) == -1) { |
577 | return (1); |
578 | } |
579 | |
580 | return send_config(conf); |
581 | } |
582 | |
583 | int |
584 | send_config(struct bgpd_config *conf) |
585 | { |
586 | struct peer *p; |
587 | struct filter_rule *r; |
588 | struct listen_addr *la; |
589 | struct rde_rib *rr; |
590 | struct l3vpn *vpn; |
591 | struct as_set *aset; |
592 | struct prefixset *ps; |
593 | struct prefixset_item *psi, *npsi; |
594 | struct roa *roa, *nroa; |
595 | struct rtr_config *rtr; |
596 | |
597 | reconfpending = 3; /* one per child */ |
598 | |
599 | expand_networks(conf); |
600 | |
601 | cflags = conf->flags; |
602 | |
603 | /* start reconfiguration */ |
604 | if (imsg_compose(ibuf_se, IMSG_RECONF_CONF, 0, 0, -1, |
605 | conf, sizeof(*conf)) == -1) |
606 | return (-1); |
607 | if (imsg_compose(ibuf_rde, IMSG_RECONF_CONF, 0, 0, -1, |
608 | conf, sizeof(*conf)) == -1) |
609 | return (-1); |
610 | if (imsg_compose(ibuf_rtr, IMSG_RECONF_CONF, 0, 0, -1, |
611 | conf, sizeof(*conf)) == -1) |
612 | return (-1); |
613 | |
614 | TAILQ_FOREACH(la, conf->listen_addrs, entry)for((la) = ((conf->listen_addrs)->tqh_first); (la) != ( (void *)0); (la) = ((la)->entry.tqe_next)) { |
615 | if (imsg_compose(ibuf_se, IMSG_RECONF_LISTENER, 0, 0, la->fd, |
616 | la, sizeof(*la)) == -1) |
617 | return (-1); |
618 | la->fd = -1; |
619 | } |
620 | |
621 | /* adjust fib syncing on reload */ |
622 | ktable_preload(); |
623 | |
624 | /* RIBs for the RDE */ |
625 | while ((rr = SIMPLEQ_FIRST(&ribnames)((&ribnames)->sqh_first))) { |
626 | SIMPLEQ_REMOVE_HEAD(&ribnames, entry)do { if (((&ribnames)->sqh_first = (&ribnames)-> sqh_first->entry.sqe_next) == ((void *)0)) (&ribnames) ->sqh_last = &(&ribnames)->sqh_first; } while ( 0); |
627 | if (ktable_update(rr->rtableid, rr->name, rr->flags, |
628 | conf->fib_priority) == -1) { |
629 | log_warnx("failed to load rdomain %d", |
630 | rr->rtableid); |
631 | return (-1); |
632 | } |
633 | if (imsg_compose(ibuf_rde, IMSG_RECONF_RIB, 0, 0, -1, |
634 | rr, sizeof(*rr)) == -1) |
635 | return (-1); |
636 | free(rr); |
637 | } |
638 | |
639 | /* send peer list to the SE */ |
640 | RB_FOREACH(p, peer_head, &conf->peers)for ((p) = peer_head_RB_MINMAX(&conf->peers, -1); (p) != ((void *)0); (p) = peer_head_RB_NEXT(p)) { |
641 | if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1, |
642 | &p->conf, sizeof(p->conf)) == -1) |
643 | return (-1); |
644 | |
645 | if (p->reconf_action == RECONF_REINIT) |
646 | if (pfkey_establish(p) == -1) |
647 | log_peer_warnx(&p->conf, "pfkey setup failed"); |
648 | } |
649 | |
650 | /* networks go via kroute to the RDE */ |
651 | kr_net_reload(conf->default_tableid, 0, &conf->networks); |
652 | |
653 | /* prefixsets for filters in the RDE */ |
654 | while ((ps = SIMPLEQ_FIRST(&conf->prefixsets)((&conf->prefixsets)->sqh_first)) != NULL((void *)0)) { |
655 | SIMPLEQ_REMOVE_HEAD(&conf->prefixsets, entry)do { if (((&conf->prefixsets)->sqh_first = (&conf ->prefixsets)->sqh_first->entry.sqe_next) == ((void * )0)) (&conf->prefixsets)->sqh_last = &(&conf ->prefixsets)->sqh_first; } while (0); |
656 | if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET, 0, 0, -1, |
657 | ps->name, sizeof(ps->name)) == -1) |
658 | return (-1); |
659 | RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi)for ((psi) = prefixset_tree_RB_MINMAX(&ps->psitems, -1 ); ((psi) != ((void *)0)) && ((npsi) = prefixset_tree_RB_NEXT (psi), 1); (psi) = (npsi)) { |
660 | RB_REMOVE(prefixset_tree, &ps->psitems, psi)prefixset_tree_RB_REMOVE(&ps->psitems, psi); |
661 | if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM, |
662 | 0, 0, -1, psi, sizeof(*psi)) == -1) |
663 | return (-1); |
664 | free(psi); |
665 | } |
666 | free(ps); |
667 | } |
668 | |
669 | /* originsets for filters in the RDE */ |
670 | while ((ps = SIMPLEQ_FIRST(&conf->originsets)((&conf->originsets)->sqh_first)) != NULL((void *)0)) { |
671 | SIMPLEQ_REMOVE_HEAD(&conf->originsets, entry)do { if (((&conf->originsets)->sqh_first = (&conf ->originsets)->sqh_first->entry.sqe_next) == ((void * )0)) (&conf->originsets)->sqh_last = &(&conf ->originsets)->sqh_first; } while (0); |
672 | if (imsg_compose(ibuf_rde, IMSG_RECONF_ORIGIN_SET, 0, 0, -1, |
673 | ps->name, sizeof(ps->name)) == -1) |
674 | return (-1); |
675 | RB_FOREACH_SAFE(roa, roa_tree, &ps->roaitems, nroa)for ((roa) = roa_tree_RB_MINMAX(&ps->roaitems, -1); (( roa) != ((void *)0)) && ((nroa) = roa_tree_RB_NEXT(roa ), 1); (roa) = (nroa)) { |
676 | RB_REMOVE(roa_tree, &ps->roaitems, roa)roa_tree_RB_REMOVE(&ps->roaitems, roa); |
677 | if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0, |
678 | -1, roa, sizeof(*roa)) == -1) |
679 | return (-1); |
680 | free(roa); |
681 | } |
682 | free(ps); |
683 | } |
684 | |
685 | /* roa table and rtr config are sent to the RTR engine */ |
686 | RB_FOREACH_SAFE(roa, roa_tree, &conf->roa, nroa)for ((roa) = roa_tree_RB_MINMAX(&conf->roa, -1); ((roa ) != ((void *)0)) && ((nroa) = roa_tree_RB_NEXT(roa), 1); (roa) = (nroa)) { |
687 | RB_REMOVE(roa_tree, &conf->roa, roa)roa_tree_RB_REMOVE(&conf->roa, roa); |
688 | if (imsg_compose(ibuf_rtr, IMSG_RECONF_ROA_ITEM, 0, 0, |
689 | -1, roa, sizeof(*roa)) == -1) |
690 | return (-1); |
691 | free(roa); |
692 | } |
693 | SIMPLEQ_FOREACH(rtr, &conf->rtrs, entry)for((rtr) = ((&conf->rtrs)->sqh_first); (rtr) != (( void *)0); (rtr) = ((rtr)->entry.sqe_next)) { |
694 | if (imsg_compose(ibuf_rtr, IMSG_RECONF_RTR_CONFIG, rtr->id, |
695 | 0, -1, rtr->descr, sizeof(rtr->descr)) == -1) |
696 | return (-1); |
697 | } |
698 | |
699 | /* as-sets for filters in the RDE */ |
700 | while ((aset = SIMPLEQ_FIRST(&conf->as_sets)((&conf->as_sets)->sqh_first)) != NULL((void *)0)) { |
701 | struct ibuf *wbuf; |
702 | u_int32_t *as; |
703 | size_t i, l, n; |
704 | |
705 | SIMPLEQ_REMOVE_HEAD(&conf->as_sets, entry)do { if (((&conf->as_sets)->sqh_first = (&conf-> as_sets)->sqh_first->entry.sqe_next) == ((void *)0)) (& conf->as_sets)->sqh_last = &(&conf->as_sets) ->sqh_first; } while (0); |
706 | |
707 | as = set_get(aset->set, &n); |
708 | if ((wbuf = imsg_create(ibuf_rde, IMSG_RECONF_AS_SET, 0, 0, |
709 | sizeof(n) + sizeof(aset->name))) == NULL((void *)0)) |
710 | return -1; |
711 | if (imsg_add(wbuf, &n, sizeof(n)) == -1 || |
712 | imsg_add(wbuf, aset->name, sizeof(aset->name)) == -1) |
713 | return -1; |
714 | imsg_close(ibuf_rde, wbuf); |
715 | |
716 | for (i = 0; i < n; i += l) { |
717 | l = (n - i > 1024 ? 1024 : n - i); |
718 | if (imsg_compose(ibuf_rde, IMSG_RECONF_AS_SET_ITEMS, |
719 | 0, 0, -1, as + i, l * sizeof(*as)) == -1) |
720 | return -1; |
721 | } |
722 | |
723 | if (imsg_compose(ibuf_rde, IMSG_RECONF_AS_SET_DONE, 0, 0, -1, |
724 | NULL((void *)0), 0) == -1) |
725 | return -1; |
726 | |
727 | set_free(aset->set); |
728 | free(aset); |
729 | } |
730 | |
731 | /* filters for the RDE */ |
732 | while ((r = TAILQ_FIRST(conf->filters)((conf->filters)->tqh_first)) != NULL((void *)0)) { |
733 | TAILQ_REMOVE(conf->filters, r, entry)do { if (((r)->entry.tqe_next) != ((void *)0)) (r)->entry .tqe_next->entry.tqe_prev = (r)->entry.tqe_prev; else ( conf->filters)->tqh_last = (r)->entry.tqe_prev; *(r) ->entry.tqe_prev = (r)->entry.tqe_next; ; ; } while (0); |
734 | if (send_filterset(ibuf_rde, &r->set) == -1) |
735 | return (-1); |
736 | if (imsg_compose(ibuf_rde, IMSG_RECONF_FILTER, 0, 0, -1, |
737 | r, sizeof(struct filter_rule)) == -1) |
738 | return (-1); |
739 | filterset_free(&r->set); |
740 | free(r); |
741 | } |
742 | |
743 | while ((vpn = SIMPLEQ_FIRST(&conf->l3vpns)((&conf->l3vpns)->sqh_first)) != NULL((void *)0)) { |
744 | SIMPLEQ_REMOVE_HEAD(&conf->l3vpns, entry)do { if (((&conf->l3vpns)->sqh_first = (&conf-> l3vpns)->sqh_first->entry.sqe_next) == ((void *)0)) (& conf->l3vpns)->sqh_last = &(&conf->l3vpns)-> sqh_first; } while (0); |
745 | if (ktable_update(vpn->rtableid, vpn->descr, vpn->flags, |
746 | conf->fib_priority) == -1) { |
747 | log_warnx("failed to load rdomain %d", |
748 | vpn->rtableid); |
749 | return (-1); |
750 | } |
751 | /* networks go via kroute to the RDE */ |
752 | kr_net_reload(vpn->rtableid, vpn->rd, &vpn->net_l); |
753 | |
754 | if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN, 0, 0, -1, |
755 | vpn, sizeof(*vpn)) == -1) |
756 | return (-1); |
757 | |
758 | /* export targets */ |
759 | if (send_filterset(ibuf_rde, &vpn->export) == -1) |
760 | return (-1); |
761 | if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_EXPORT, 0, 0, |
762 | -1, NULL((void *)0), 0) == -1) |
763 | return (-1); |
764 | filterset_free(&vpn->export); |
765 | |
766 | /* import targets */ |
767 | if (send_filterset(ibuf_rde, &vpn->import) == -1) |
768 | return (-1); |
769 | if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_IMPORT, 0, 0, |
770 | -1, NULL((void *)0), 0) == -1) |
771 | return (-1); |
772 | filterset_free(&vpn->import); |
773 | |
774 | if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_DONE, 0, 0, |
775 | -1, NULL((void *)0), 0) == -1) |
776 | return (-1); |
777 | |
778 | free(vpn); |
779 | } |
780 | |
781 | /* send a drain message to know when all messages where processed */ |
782 | if (imsg_compose(ibuf_se, IMSG_RECONF_DRAIN, 0, 0, -1, NULL((void *)0), 0) == -1) |
783 | return (-1); |
784 | if (imsg_compose(ibuf_rde, IMSG_RECONF_DRAIN, 0, 0, -1, NULL((void *)0), 0) == -1) |
785 | return (-1); |
786 | if (imsg_compose(ibuf_rtr, IMSG_RECONF_DRAIN, 0, 0, -1, NULL((void *)0), 0) == -1) |
787 | return (-1); |
788 | |
789 | /* mrt changes can be sent out of bound */ |
790 | mrt_reconfigure(conf->mrt); |
791 | return (0); |
792 | } |
793 | |
794 | int |
795 | dispatch_imsg(struct imsgbuf *ibuf, int idx, struct bgpd_config *conf) |
796 | { |
797 | struct imsg imsg; |
798 | struct peer *p; |
799 | struct rtr_config *r; |
800 | ssize_t n; |
801 | int rv, verbose; |
802 | |
803 | rv = 0; |
804 | while (ibuf) { |
805 | if ((n = imsg_get(ibuf, &imsg)) == -1) |
806 | return (-1); |
807 | |
808 | if (n == 0) |
809 | break; |
810 | |
811 | switch (imsg.hdr.type) { |
812 | case IMSG_KROUTE_CHANGE: |
813 | if (idx != PFD_PIPE_RDE1) |
814 | log_warnx("route request not from RDE"); |
815 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
816 | sizeof(struct kroute_full)) |
817 | log_warnx("wrong imsg len"); |
818 | else if (kr_change(imsg.hdr.peerid, imsg.data, |
819 | conf->fib_priority)) |
820 | rv = -1; |
821 | break; |
822 | case IMSG_KROUTE_DELETE: |
823 | if (idx != PFD_PIPE_RDE1) |
824 | log_warnx("route request not from RDE"); |
825 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
826 | sizeof(struct kroute_full)) |
827 | log_warnx("wrong imsg len"); |
828 | else if (kr_delete(imsg.hdr.peerid, imsg.data, |
829 | conf->fib_priority)) |
830 | rv = -1; |
831 | break; |
832 | case IMSG_KROUTE_FLUSH: |
833 | if (idx != PFD_PIPE_RDE1) |
834 | log_warnx("route request not from RDE"); |
835 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) |
836 | log_warnx("wrong imsg len"); |
837 | else if (kr_flush(imsg.hdr.peerid)) |
838 | rv = -1; |
839 | break; |
840 | case IMSG_NEXTHOP_ADD: |
841 | if (idx != PFD_PIPE_RDE1) |
842 | log_warnx("nexthop request not from RDE"); |
843 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
844 | sizeof(struct bgpd_addr)) |
845 | log_warnx("wrong imsg len"); |
846 | else if (kr_nexthop_add(imsg.hdr.peerid, imsg.data, |
847 | conf) == -1) |
848 | rv = -1; |
849 | break; |
850 | case IMSG_NEXTHOP_REMOVE: |
851 | if (idx != PFD_PIPE_RDE1) |
852 | log_warnx("nexthop request not from RDE"); |
853 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
854 | sizeof(struct bgpd_addr)) |
855 | log_warnx("wrong imsg len"); |
856 | else |
857 | kr_nexthop_delete(imsg.hdr.peerid, imsg.data, |
858 | conf); |
859 | break; |
860 | case IMSG_PFTABLE_ADD: |
861 | if (idx != PFD_PIPE_RDE1) |
862 | log_warnx("pftable request not from RDE"); |
863 | else |
864 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
865 | sizeof(struct pftable_msg)) |
866 | log_warnx("wrong imsg len"); |
867 | else if (pftable_addr_add(imsg.data) != 0) |
868 | rv = -1; |
869 | break; |
870 | case IMSG_PFTABLE_REMOVE: |
871 | if (idx != PFD_PIPE_RDE1) |
872 | log_warnx("pftable request not from RDE"); |
873 | else |
874 | if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
875 | sizeof(struct pftable_msg)) |
876 | log_warnx("wrong imsg len"); |
877 | else if (pftable_addr_remove(imsg.data) != 0) |
878 | rv = -1; |
879 | break; |
880 | case IMSG_PFTABLE_COMMIT: |
881 | if (idx != PFD_PIPE_RDE1) |
882 | log_warnx("pftable request not from RDE"); |
883 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) |
884 | log_warnx("wrong imsg len"); |
885 | else if (pftable_commit() != 0) |
886 | rv = -1; |
887 | break; |
888 | case IMSG_PFKEY_RELOAD: |
889 | if (idx != PFD_PIPE_SESSION0) { |
890 | log_warnx("pfkey reload request not from SE"); |
891 | break; |
892 | } |
893 | p = getpeerbyid(conf, imsg.hdr.peerid); |
894 | if (p != NULL((void *)0)) { |
895 | if (pfkey_establish(p) == -1) |
896 | log_peer_warnx(&p->conf, |
897 | "pfkey setup failed"); |
898 | } |
899 | break; |
900 | case IMSG_CTL_RELOAD: |
901 | if (idx != PFD_PIPE_SESSION0) |
902 | log_warnx("reload request not from SE"); |
903 | else { |
904 | reconfig = 1; |
905 | reconfpid = imsg.hdr.pid; |
906 | if (imsg.hdr.len == IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
907 | REASON_LEN256 && ((char *)imsg.data)[0]) |
908 | log_info("reload due to: %s", |
909 | log_reason(imsg.data)); |
910 | } |
911 | break; |
912 | case IMSG_CTL_FIB_COUPLE: |
913 | if (idx != PFD_PIPE_SESSION0) |
914 | log_warnx("couple request not from SE"); |
915 | else |
916 | kr_fib_couple(imsg.hdr.peerid, |
917 | conf->fib_priority); |
918 | break; |
919 | case IMSG_CTL_FIB_DECOUPLE: |
920 | if (idx != PFD_PIPE_SESSION0) |
921 | log_warnx("decouple request not from SE"); |
922 | else |
923 | kr_fib_decouple(imsg.hdr.peerid, |
924 | conf->fib_priority); |
925 | break; |
926 | case IMSG_CTL_KROUTE: |
927 | case IMSG_CTL_KROUTE_ADDR: |
928 | case IMSG_CTL_SHOW_NEXTHOP: |
929 | case IMSG_CTL_SHOW_INTERFACE: |
930 | case IMSG_CTL_SHOW_FIB_TABLES: |
931 | if (idx != PFD_PIPE_SESSION0) |
932 | log_warnx("kroute request not from SE"); |
933 | else |
934 | kr_show_route(&imsg); |
935 | break; |
936 | case IMSG_IFINFO: |
937 | if (idx != PFD_PIPE_SESSION0) |
938 | log_warnx("IFINFO request not from SE"); |
939 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + IFNAMSIZ16) |
940 | log_warnx("IFINFO request with wrong len"); |
941 | else |
942 | kr_ifinfo(imsg.data); |
943 | break; |
944 | case IMSG_DEMOTE: |
945 | if (idx != PFD_PIPE_SESSION0) |
946 | log_warnx("demote request not from SE"); |
947 | else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
948 | sizeof(struct demote_msg)) |
949 | log_warnx("DEMOTE request with wrong len"); |
950 | else { |
951 | struct demote_msg *msg; |
952 | |
953 | msg = imsg.data; |
954 | carp_demote_set(msg->demote_group, msg->level); |
955 | } |
956 | break; |
957 | case IMSG_CTL_LOG_VERBOSE: |
958 | /* already checked by SE */ |
959 | memcpy(&verbose, imsg.data, sizeof(verbose)); |
960 | log_setverbose(verbose); |
961 | break; |
962 | case IMSG_RECONF_DONE: |
963 | if (reconfpending == 0) { |
964 | log_warnx("unexpected RECONF_DONE received"); |
965 | break; |
966 | } |
967 | if (idx == PFD_PIPE_SESSION0) { |
968 | imsg_compose(ibuf_rtr, IMSG_RECONF_DONE, 0, |
969 | 0, -1, NULL((void *)0), 0); |
970 | } else if (idx == PFD_PIPE_RTR2) { |
971 | imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, |
972 | 0, -1, NULL((void *)0), 0); |
973 | |
974 | /* finally fix kroute information */ |
975 | ktable_postload(conf->fib_priority); |
976 | |
977 | /* redistribute list needs to be reloaded too */ |
978 | kr_reload(); |
979 | } |
980 | reconfpending--; |
981 | break; |
982 | case IMSG_RECONF_DRAIN: |
983 | if (reconfpending == 0) { |
984 | log_warnx("unexpected RECONF_DRAIN received"); |
985 | break; |
986 | } |
987 | reconfpending--; |
988 | if (reconfpending == 0) { |
989 | /* |
990 | * SE goes first to bring templated neighbors |
991 | * in sync. |
992 | */ |
993 | imsg_compose(ibuf_se, IMSG_RECONF_DONE, 0, |
994 | 0, -1, NULL((void *)0), 0); |
995 | reconfpending = 3; /* expecting 2 DONE msg */ |
996 | } |
997 | break; |
998 | case IMSG_SOCKET_CONN: |
999 | if (idx != PFD_PIPE_RTR2) { |
1000 | log_warnx("connect request not from RTR"); |
1001 | } else { |
1002 | SIMPLEQ_FOREACH(r, &conf->rtrs, entry)for((r) = ((&conf->rtrs)->sqh_first); (r) != ((void *)0); (r) = ((r)->entry.sqe_next)) { |
1003 | if (imsg.hdr.peerid == r->id) |
1004 | break; |
1005 | } |
1006 | if (r == NULL((void *)0)) |
1007 | log_warnx("unknown rtr id %d", |
1008 | imsg.hdr.peerid); |
1009 | else |
1010 | bgpd_rtr_connect(r); |
1011 | } |
1012 | break; |
1013 | case IMSG_CTL_SHOW_RTR: |
1014 | if (idx == PFD_PIPE_SESSION0) { |
1015 | SIMPLEQ_FOREACH(r, &conf->rtrs, entry)for((r) = ((&conf->rtrs)->sqh_first); (r) != ((void *)0); (r) = ((r)->entry.sqe_next)) { |
1016 | imsg_compose(ibuf_rtr, imsg.hdr.type, |
1017 | r->id, imsg.hdr.pid, -1, NULL((void *)0), 0); |
1018 | } |
1019 | imsg_compose(ibuf_rtr, IMSG_CTL_END, |
1020 | 0, imsg.hdr.pid, -1, NULL((void *)0), 0); |
1021 | } else if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + |
1022 | sizeof(struct ctl_show_rtr)) { |
1023 | log_warnx("IMSG_CTL_SHOW_RTR with wrong len"); |
1024 | } else if (idx == PFD_PIPE_RTR2) { |
1025 | SIMPLEQ_FOREACH(r, &conf->rtrs, entry)for((r) = ((&conf->rtrs)->sqh_first); (r) != ((void *)0); (r) = ((r)->entry.sqe_next)) { |
1026 | if (imsg.hdr.peerid == r->id) |
1027 | break; |
1028 | } |
1029 | if (r != NULL((void *)0)) { |
1030 | struct ctl_show_rtr *msg; |
1031 | msg = imsg.data; |
1032 | strlcpy(msg->descr, r->descr, |
1033 | sizeof(msg->descr)); |
1034 | msg->local_addr = r->local_addr; |
1035 | msg->remote_addr = r->remote_addr; |
1036 | msg->remote_port = r->remote_port; |
1037 | |
1038 | imsg_compose(ibuf_se, imsg.hdr.type, |
1039 | imsg.hdr.peerid, imsg.hdr.pid, |
1040 | -1, imsg.data, |
1041 | imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)); |
1042 | } |
1043 | } |
1044 | break; |
1045 | case IMSG_CTL_END: |
1046 | case IMSG_CTL_SHOW_TIMER: |
1047 | if (idx != PFD_PIPE_RTR2) { |
1048 | log_warnx("connect request not from RTR"); |
1049 | break; |
1050 | } |
1051 | imsg_compose(ibuf_se, imsg.hdr.type, imsg.hdr.peerid, |
1052 | imsg.hdr.pid, -1, imsg.data, |
1053 | imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)); |
1054 | break; |
1055 | default: |
1056 | break; |
1057 | } |
1058 | imsg_free(&imsg); |
1059 | if (rv != 0) |
1060 | return (rv); |
1061 | } |
1062 | return (0); |
1063 | } |
1064 | |
1065 | void |
1066 | send_nexthop_update(struct kroute_nexthop *msg) |
1067 | { |
1068 | char *gw = NULL((void *)0); |
1069 | |
1070 | if (msg->gateway.aid) |
1071 | if (asprintf(&gw, ": via %s", |
1072 | log_addr(&msg->gateway)) == -1) { |
1073 | log_warn("send_nexthop_update"); |
1074 | quit = 1; |
1075 | } |
1076 | |
1077 | log_debug("nexthop %s now %s%s%s", log_addr(&msg->nexthop), |
1078 | msg->valid ? "valid" : "invalid", |
1079 | msg->connected ? ": directly connected" : "", |
1080 | msg->gateway.aid ? gw : ""); |
1081 | |
1082 | free(gw); |
1083 | |
1084 | if (imsg_compose(ibuf_rde, IMSG_NEXTHOP_UPDATE, 0, 0, -1, |
1085 | msg, sizeof(struct kroute_nexthop)) == -1) |
1086 | quit = 1; |
1087 | } |
1088 | |
1089 | void |
1090 | send_imsg_session(int type, pid_t pid, void *data, u_int16_t datalen) |
1091 | { |
1092 | imsg_compose(ibuf_se, type, 0, pid, -1, data, datalen); |
1093 | } |
1094 | |
1095 | int |
1096 | send_network(int type, struct network_config *net, struct filter_set_head *h) |
1097 | { |
1098 | if (quit) |
1099 | return (0); |
1100 | if (imsg_compose(ibuf_rde, type, 0, 0, -1, net, |
1101 | sizeof(struct network_config)) == -1) |
1102 | return (-1); |
1103 | /* networks that get deleted don't need to send the filter set */ |
1104 | if (type == IMSG_NETWORK_REMOVE) |
1105 | return (0); |
1106 | if (send_filterset(ibuf_rde, h) == -1) |
1107 | return (-1); |
1108 | if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1, NULL((void *)0), 0) == -1) |
1109 | return (-1); |
1110 | |
1111 | return (0); |
1112 | } |
1113 | |
1114 | int |
1115 | bgpd_filternexthop(struct kroute *kr, struct kroute6 *kr6) |
1116 | { |
1117 | /* kernel routes are never filtered */ |
1118 | if (kr && kr->flags & F_KERNEL0x0002 && kr->prefixlen != 0) |
1119 | return (0); |
1120 | if (kr6 && kr6->flags & F_KERNEL0x0002 && kr6->prefixlen != 0) |
1121 | return (0); |
1122 | |
1123 | if (cflags & BGPD_FLAG_NEXTHOP_BGP0x0010) { |
1124 | if (kr && kr->flags & F_BGPD_INSERTED0x0001) |
1125 | return (0); |
1126 | if (kr6 && kr6->flags & F_BGPD_INSERTED0x0001) |
1127 | return (0); |
1128 | } |
1129 | |
1130 | if (cflags & BGPD_FLAG_NEXTHOP_DEFAULT0x0020) { |
1131 | if (kr && kr->prefixlen == 0) |
1132 | return (0); |
1133 | if (kr6 && kr6->prefixlen == 0) |
1134 | return (0); |
1135 | } |
1136 | |
1137 | return (1); |
1138 | } |
1139 | |
1140 | int |
1141 | control_setup(struct bgpd_config *conf) |
1142 | { |
1143 | int fd, restricted; |
1144 | |
1145 | /* control socket is outside chroot */ |
1146 | if (!cname || strcmp(cname, conf->csock)) { |
1147 | if (cname) { |
1148 | free(cname); |
1149 | } |
1150 | if ((cname = strdup(conf->csock)) == NULL((void *)0)) |
1151 | fatal("strdup"); |
1152 | if (control_check(cname) == -1) |
1153 | return (-1); |
1154 | if ((fd = control_init(0, cname)) == -1) |
1155 | fatalx("control socket setup failed"); |
1156 | if (control_listen(fd) == -1) |
1157 | fatalx("control socket setup failed"); |
1158 | restricted = 0; |
1159 | if (imsg_compose(ibuf_se, IMSG_RECONF_CTRL, 0, 0, fd, |
1160 | &restricted, sizeof(restricted)) == -1) |
1161 | return (-1); |
1162 | } |
1163 | if (!conf->rcsock) { |
1164 | /* remove restricted socket */ |
1165 | free(rcname); |
1166 | rcname = NULL((void *)0); |
1167 | } else if (!rcname || strcmp(rcname, conf->rcsock)) { |
1168 | if (rcname) { |
1169 | free(rcname); |
1170 | } |
1171 | if ((rcname = strdup(conf->rcsock)) == NULL((void *)0)) |
1172 | fatal("strdup"); |
1173 | if (control_check(rcname) == -1) |
1174 | return (-1); |
1175 | if ((fd = control_init(1, rcname)) == -1) |
1176 | fatalx("control socket setup failed"); |
1177 | if (control_listen(fd) == -1) |
1178 | fatalx("control socket setup failed"); |
1179 | restricted = 1; |
1180 | if (imsg_compose(ibuf_se, IMSG_RECONF_CTRL, 0, 0, fd, |
1181 | &restricted, sizeof(restricted)) == -1) |
1182 | return (-1); |
1183 | } |
1184 | return (0); |
1185 | } |
1186 | |
1187 | void |
1188 | set_pollfd(struct pollfd *pfd, struct imsgbuf *i) |
1189 | { |
1190 | if (i == NULL((void *)0) || i->fd == -1) { |
1191 | pfd->fd = -1; |
1192 | return; |
1193 | } |
1194 | pfd->fd = i->fd; |
1195 | pfd->events = POLLIN0x0001; |
1196 | if (i->w.queued > 0) |
1197 | pfd->events |= POLLOUT0x0004; |
1198 | } |
1199 | |
1200 | int |
1201 | handle_pollfd(struct pollfd *pfd, struct imsgbuf *i) |
1202 | { |
1203 | ssize_t n; |
1204 | |
1205 | if (i == NULL((void *)0)) |
1206 | return (0); |
1207 | |
1208 | if (pfd->revents & POLLOUT0x0004) |
1209 | if (msgbuf_write(&i->w) <= 0 && errno(*__errno()) != EAGAIN35) { |
1210 | log_warn("imsg write error"); |
1211 | close(i->fd); |
1212 | i->fd = -1; |
1213 | return (-1); |
1214 | } |
1215 | |
1216 | if (pfd->revents & POLLIN0x0001) { |
1217 | if ((n = imsg_read(i)) == -1 && errno(*__errno()) != EAGAIN35) { |
1218 | log_warn("imsg read error"); |
1219 | close(i->fd); |
1220 | i->fd = -1; |
1221 | return (-1); |
1222 | } |
1223 | if (n == 0) { |
1224 | log_warnx("peer closed imsg connection"); |
1225 | close(i->fd); |
1226 | i->fd = -1; |
1227 | return (-1); |
1228 | } |
1229 | } |
1230 | return (0); |
1231 | } |
1232 | |
1233 | static void |
1234 | getsockpair(int pipe[2]) |
1235 | { |
1236 | int bsize, i; |
1237 | |
1238 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, |
1239 | PF_UNSPEC0, pipe) == -1) |
1240 | fatal("socketpair"); |
1241 | |
1242 | for (i = 0; i < 2; i++) { |
1243 | for (bsize = MAX_SOCK_BUF(4 * 65535); bsize >= 16 * 1024; bsize /= 2) { |
1244 | if (setsockopt(pipe[i], SOL_SOCKET0xffff, SO_RCVBUF0x1002, |
1245 | &bsize, sizeof(bsize)) == -1) { |
1246 | if (errno(*__errno()) != ENOBUFS55) |
1247 | fatal("setsockopt(SO_RCVBUF, %d)", |
1248 | bsize); |
1249 | log_warn("setsockopt(SO_RCVBUF, %d)", bsize); |
1250 | continue; |
1251 | } |
1252 | break; |
1253 | } |
1254 | } |
1255 | for (i = 0; i < 2; i++) { |
1256 | for (bsize = MAX_SOCK_BUF(4 * 65535); bsize >= 16 * 1024; bsize /= 2) { |
1257 | if (setsockopt(pipe[i], SOL_SOCKET0xffff, SO_SNDBUF0x1001, |
1258 | &bsize, sizeof(bsize)) == -1) { |
1259 | if (errno(*__errno()) != ENOBUFS55) |
1260 | fatal("setsockopt(SO_SNDBUF, %d)", |
1261 | bsize); |
1262 | log_warn("setsockopt(SO_SNDBUF, %d)", bsize); |
1263 | continue; |
1264 | } |
1265 | break; |
1266 | } |
1267 | } |
1268 | } |
1269 | |
1270 | int |
1271 | imsg_send_sockets(struct imsgbuf *se, struct imsgbuf *rde, struct imsgbuf *roa) |
1272 | { |
1273 | int pipe_s2r[2]; |
1274 | int pipe_s2r_ctl[2]; |
1275 | int pipe_r2r[2]; |
1276 | |
1277 | getsockpair(pipe_s2r); |
1278 | getsockpair(pipe_s2r_ctl); |
1279 | getsockpair(pipe_r2r); |
1280 | |
1281 | if (imsg_compose(se, IMSG_SOCKET_CONN, 0, 0, pipe_s2r[0], |
1282 | NULL((void *)0), 0) == -1) |
1283 | return (-1); |
1284 | if (imsg_compose(rde, IMSG_SOCKET_CONN, 0, 0, pipe_s2r[1], |
1285 | NULL((void *)0), 0) == -1) |
1286 | return (-1); |
1287 | |
1288 | if (imsg_compose(se, IMSG_SOCKET_CONN_CTL, 0, 0, pipe_s2r_ctl[0], |
1289 | NULL((void *)0), 0) == -1) |
1290 | return (-1); |
1291 | if (imsg_compose(rde, IMSG_SOCKET_CONN_CTL, 0, 0, pipe_s2r_ctl[1], |
1292 | NULL((void *)0), 0) == -1) |
1293 | return (-1); |
1294 | |
1295 | if (imsg_compose(roa, IMSG_SOCKET_CONN_RTR, 0, 0, pipe_r2r[0], |
1296 | NULL((void *)0), 0) == -1) |
1297 | return (-1); |
1298 | if (imsg_compose(rde, IMSG_SOCKET_CONN_RTR, 0, 0, pipe_r2r[1], |
1299 | NULL((void *)0), 0) == -1) |
1300 | return (-1); |
1301 | |
1302 | return (0); |
1303 | } |
1304 | |
1305 | void |
1306 | bgpd_rtr_connect(struct rtr_config *r) |
1307 | { |
1308 | struct connect_elm *ce; |
1309 | struct sockaddr *sa; |
1310 | socklen_t len; |
1311 | |
1312 | if (connect_cnt >= MAX_CONNECT_CNT32) { |
1313 | log_warnx("rtr %s: too many concurrent connection requests", |
1314 | r->descr); |
1315 | return; |
1316 | } |
1317 | |
1318 | if ((ce = calloc(1, sizeof(*ce))) == NULL((void *)0)) { |
1319 | log_warn("rtr %s", r->descr); |
1320 | return; |
1321 | } |
1322 | |
1323 | ce->id = r->id; |
1324 | ce->fd = socket(aid2af(r->remote_addr.aid), |
1325 | SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, IPPROTO_TCP6); |
1326 | if (ce->fd == -1) { |
1327 | log_warn("rtr %s", r->descr); |
1328 | free(ce); |
1329 | return; |
1330 | } |
1331 | |
1332 | if ((sa = addr2sa(&r->local_addr, 0, &len)) != NULL((void *)0)) { |
1333 | if (bind(ce->fd, sa, len) == -1) { |
1334 | log_warn("rtr %s: bind to %s", r->descr, |
1335 | log_addr(&r->local_addr)); |
1336 | close(ce->fd); |
1337 | free(ce); |
1338 | return; |
1339 | } |
1340 | } |
1341 | |
1342 | sa = addr2sa(&r->remote_addr, r->remote_port, &len); |
1343 | if (connect(ce->fd, sa, len) == -1) { |
1344 | if (errno(*__errno()) != EINPROGRESS36) { |
1345 | log_warn("rtr %s: connect to %s:%u", r->descr, |
1346 | log_addr(&r->remote_addr), r->remote_port); |
1347 | close(ce->fd); |
1348 | free(ce); |
1349 | return; |
1350 | } |
1351 | TAILQ_INSERT_TAIL(&connect_queue, ce, entry)do { (ce)->entry.tqe_next = ((void *)0); (ce)->entry.tqe_prev = (&connect_queue)->tqh_last; *(&connect_queue)-> tqh_last = (ce); (&connect_queue)->tqh_last = &(ce )->entry.tqe_next; } while (0); |
1352 | connect_cnt++; |
1353 | return; |
1354 | } |
1355 | |
1356 | imsg_compose(ibuf_rtr, IMSG_SOCKET_CONN, ce->id, 0, ce->fd, NULL((void *)0), 0); |
1357 | free(ce); |
1358 | } |
1359 | |
1360 | void |
1361 | bgpd_rtr_connect_done(int fd, struct bgpd_config *conf) |
1362 | { |
1363 | struct rtr_config *r; |
1364 | struct connect_elm *ce; |
1365 | int error = 0; |
1366 | socklen_t len; |
1367 | |
1368 | TAILQ_FOREACH(ce, &connect_queue, entry)for((ce) = ((&connect_queue)->tqh_first); (ce) != ((void *)0); (ce) = ((ce)->entry.tqe_next)) { |
1369 | if (ce->fd == fd) |
1370 | break; |
1371 | } |
1372 | if (ce == NULL((void *)0)) |
1373 | fatalx("connect entry not found"); |
1374 | |
1375 | TAILQ_REMOVE(&connect_queue, ce, entry)do { if (((ce)->entry.tqe_next) != ((void *)0)) (ce)->entry .tqe_next->entry.tqe_prev = (ce)->entry.tqe_prev; else ( &connect_queue)->tqh_last = (ce)->entry.tqe_prev; * (ce)->entry.tqe_prev = (ce)->entry.tqe_next; ; ; } while (0); |
1376 | connect_cnt--; |
1377 | |
1378 | SIMPLEQ_FOREACH(r, &conf->rtrs, entry)for((r) = ((&conf->rtrs)->sqh_first); (r) != ((void *)0); (r) = ((r)->entry.sqe_next)) { |
1379 | if (ce->id == r->id) |
1380 | break; |
1381 | } |
1382 | if (r == NULL((void *)0)) { |
1383 | log_warnx("rtr id %d no longer exists", ce->id); |
1384 | goto fail; |
1385 | } |
1386 | |
1387 | len = sizeof(error); |
1388 | if (getsockopt(fd, SOL_SOCKET0xffff, SO_ERROR0x1007, &error, &len) == -1) { |
1389 | log_warn("rtr %s: getsockopt SO_ERROR", r->descr); |
1390 | goto fail; |
1391 | } |
1392 | |
1393 | if (error != 0) { |
1394 | errno(*__errno()) = error; |
1395 | log_warn("rtr %s: connect to %s:%u", r->descr, |
1396 | log_addr(&r->remote_addr), r->remote_port); |
1397 | goto fail; |
1398 | } |
1399 | |
1400 | imsg_compose(ibuf_rtr, IMSG_SOCKET_CONN, ce->id, 0, ce->fd, NULL((void *)0), 0); |
1401 | free(ce); |
1402 | return; |
1403 | |
1404 | fail: |
1405 | close(fd); |
1406 | free(ce); |
1407 | } |