Bug Summary

File:src/usr.sbin/bgpd/bgpd.c
Warning:line 329, column 26
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

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