Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name bgpd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -I /usr/src/usr.sbin/bgpd -internal-isystem /usr/local/lib/clang/13.0.0/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 -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/bgpd/bgpd.c
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
41void sighdlr(int);
42__dead__attribute__((__noreturn__)) void usage(void);
43int main(int, char *[]);
44pid_t start_child(enum bgpd_process, char *, int, int, int);
45int send_filterset(struct imsgbuf *, struct filter_set_head *);
46int reconfigure(char *, struct bgpd_config *);
47int send_config(struct bgpd_config *);
48int dispatch_imsg(struct imsgbuf *, int, struct bgpd_config *);
49int control_setup(struct bgpd_config *);
50static void getsockpair(int [2]);
51int imsg_send_sockets(struct imsgbuf *, struct imsgbuf *,
52 struct imsgbuf *);
53void bgpd_rtr_connect(struct rtr_config *);
54void bgpd_rtr_connect_done(int, struct bgpd_config *);
55
56int cflags;
57volatile sig_atomic_t mrtdump;
58volatile sig_atomic_t quit;
59volatile sig_atomic_t reconfig;
60pid_t reconfpid;
61int reconfpending;
62struct imsgbuf *ibuf_se;
63struct imsgbuf *ibuf_rde;
64struct imsgbuf *ibuf_rtr;
65struct rib_names ribnames = SIMPLEQ_HEAD_INITIALIZER(ribnames){ ((void *)0), &(ribnames).sqh_first };
66char *cname;
67char *rcname;
68
69struct 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
75TAILQ_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 };
77u_int connect_cnt;
78#define MAX_CONNECT_CNT32 32
79
80void
81sighdlr(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
99usage(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
116int cmd_opts;
117
118int
119main(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);
1
'pfd' initialized to a null pointer value
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))
2
Assuming 'saved_argv0' is not equal to NULL
3
Taking false branch
147 saved_argv0 = "bgpd";
148
149 while ((ch = getopt(argc, argv, "cdD:f:nRSTvV")) != -1) {
4
Assuming the condition is false
5
Loop condition is false. Execution continues on line 191
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;
193 if (argc > 0)
6
Assuming 'argc' is <= 0
7
Taking false branch
194 usage();
195
196 if (cmd_opts & BGPD_OPT_NOACTION0x0004) {
8
Assuming the condition is false
9
Taking false branch
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) {
10
Control jumps to 'case PROC_MAIN:' at line 214
214 case PROC_MAIN:
215 break;
11
Execution continues on line 227
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())
12
Assuming the condition is false
13
Taking false branch
228 errx(1, "need root privileges");
229
230 if (getpwnam(BGPD_USER"_bgpd") == NULL((void *)0))
14
Assuming the condition is false
15
Taking false branch
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)) {
16
Assuming the condition is false
17
Taking false branch
234 log_warnx("config file %s has errors", conffile);
235 exit(1);
236 }
237
238 if (prepare_listeners(conf) == -1)
18
Assuming the condition is false
19
Taking false branch
239 exit(1);
240
241 log_init(debug, LOG_DAEMON(3<<3));
242 log_setverbose(cmd_opts & BGPD_OPT_VERBOSE0x0001);
243
244 if (!debug
19.1
'debug' is 0
)
20
Taking true branch
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) ||
21
Assuming the condition is false
24
Taking false branch
269 (ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL((void *)0) ||
22
Assuming the condition is false
270 (ibuf_rtr = malloc(sizeof(struct imsgbuf))) == NULL((void *)0))
23
Assuming the condition is false
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)
25
Assuming the condition is false
26
Taking false branch
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 */
294BROKEN 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))
27
Taking false branch
300 fatal("could not establish imsg links");
301 /* control setup needs to happen late since it sends imsgs */
302 if (control_setup(conf) == -1)
28
Taking false branch
303 quit = 1;
304 if (send_config(conf) != 0)
29
Assuming the condition is false
30
Taking false branch
305 quit = 1;
306 if (pftable_clear_all() != 0)
31
Assuming the condition is false
32
Taking false branch
307 quit = 1;
308
309 while (quit == 0) {
33
Assuming 'quit' is equal to 0
34
Loop condition is true. Entering loop body
310 if (pfd_elms < PFD_CONNECT_START5 + connect_cnt) {
35
Assuming the condition is false
36
Taking false branch
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;
37
Dereference of null pointer
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
498pid_t
499start_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
545int
546send_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
557int
558reconfigure(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
583int
584send_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
794int
795dispatch_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
1065void
1066send_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
1089void
1090send_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
1095int
1096send_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
1114int
1115bgpd_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
1140int
1141control_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
1187void
1188set_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
1200int
1201handle_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
1233static void
1234getsockpair(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
1270int
1271imsg_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
1305void
1306bgpd_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
1360void
1361bgpd_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
1404fail:
1405 close(fd);
1406 free(ce);
1407}