bgpd.c revision 1.50
185587Sobrien/*	$OpenBSD: bgpd.c,v 1.50 2004/01/03 14:06:35 henning Exp $ */
285587Sobrien
385587Sobrien/*
485587Sobrien * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
585587Sobrien *
685587Sobrien * Permission to use, copy, modify, and distribute this software for any
785587Sobrien * purpose with or without fee is hereby granted, provided that the above
885587Sobrien * copyright notice and this permission notice appear in all copies.
985587Sobrien *
1085587Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1185587Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1285587Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1385587Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1485587Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1585587Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1685587Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1785587Sobrien */
1885587Sobrien
1985587Sobrien#include <sys/types.h>
2085587Sobrien#include <sys/socket.h>
2185587Sobrien#include <sys/wait.h>
2285587Sobrien#include <netinet/in.h>
2385587Sobrien#include <arpa/inet.h>
2485587Sobrien#include <err.h>
2585587Sobrien#include <errno.h>
2685587Sobrien#include <fcntl.h>
2785587Sobrien#include <poll.h>
2885587Sobrien#include <signal.h>
2985587Sobrien#include <stdio.h>
3085587Sobrien#include <stdlib.h>
3185587Sobrien#include <string.h>
3285587Sobrien#include <unistd.h>
3385587Sobrien
3485587Sobrien#include "mrt.h"
3585587Sobrien#include "bgpd.h"
3685587Sobrien
3785587Sobrienvoid	sighdlr(int);
3885587Sobrienvoid	usage(void);
3985587Sobrienint	main(int, char *[]);
4085587Sobrienint	reconfigure(char *, struct bgpd_config *, struct mrt_config *);
4185587Sobrienint	dispatch_imsg(struct imsgbuf *, int, struct mrt_config *);
4285587Sobrien
4385587Sobrienint			mrtfd = -1;
4485587Sobrienint			rfd = -1;
4585587Sobrienvolatile sig_atomic_t	mrtdump = 0;
4685587Sobrienvolatile sig_atomic_t	quit = 0;
4785587Sobrienvolatile sig_atomic_t	reconfig = 0;
4885587Sobrienstruct imsgbuf		ibuf_se;
4985587Sobrienstruct imsgbuf		ibuf_rde;
5085587Sobrien
5185587Sobrienvoid
5285587Sobriensighdlr(int sig)
5385587Sobrien{
5485587Sobrien	switch (sig) {
5585587Sobrien	case SIGTERM:
5685587Sobrien	case SIGINT:
5785587Sobrien	case SIGCHLD:
5885587Sobrien		quit = 1;
5985587Sobrien		break;
6085587Sobrien	case SIGHUP:
6185587Sobrien		reconfig = 1;
6285587Sobrien		break;
6385587Sobrien	case SIGALRM:
6485587Sobrien		mrtdump = 1;
6585587Sobrien		break;
6685587Sobrien	case SIGUSR1:
6785587Sobrien		mrtdump = 2;
6885587Sobrien		break;
6985587Sobrien	}
7085587Sobrien}
7185587Sobrien
7285587Sobrienvoid
7385587Sobrienusage(void)
7485587Sobrien{
7585587Sobrien	extern char *__progname;
7685587Sobrien
7785587Sobrien	fprintf(stderr, "usage: %s [-dnv] ", __progname);
7885587Sobrien	fprintf(stderr, "[-D macro=value] [-f file]\n");
7985587Sobrien	exit(1);
8085587Sobrien}
8185587Sobrien
8285587Sobrien#define POLL_MAX		8
8385587Sobrien#define PFD_PIPE_SESSION	0
8485587Sobrien#define PFD_PIPE_ROUTE		1
8585587Sobrien#define PFD_SOCK_ROUTE		2
8685587Sobrien#define PFD_MRT_START		3
8785587Sobrien
8885587Sobrienint
8985587Sobrienmain(int argc, char *argv[])
9085587Sobrien{
9185587Sobrien	struct bgpd_config	 conf;
9285587Sobrien	struct mrt_config	 mrtconf;
9385587Sobrien	struct mrtdump_config	*mconf, *(mrt[POLL_MAX]);
9485587Sobrien	struct pollfd		 pfd[POLL_MAX];
9585587Sobrien	pid_t			 io_pid = 0, rde_pid = 0;
9685587Sobrien	char			*conffile;
9785587Sobrien	int			 debug = 0;
9885587Sobrien	int			 ch, i, j, n, nfds, csock;
9985587Sobrien	int			 pipe_m2s[2];
10085587Sobrien	int			 pipe_m2r[2];
10185587Sobrien	int			 pipe_s2r[2];
10285587Sobrien
10385587Sobrien	conffile = CONFFILE;
10485587Sobrien	bgpd_process = PROC_MAIN;
10585587Sobrien
10685587Sobrien	log_init(1);		/* log to stderr until daemonized */
10785587Sobrien
10885587Sobrien	bzero(&conf, sizeof(conf));
10985587Sobrien	bzero(&mrtconf, sizeof(mrtconf));
11085587Sobrien	LIST_INIT(&mrtconf);
11185587Sobrien
11285587Sobrien	while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) {
11385587Sobrien		switch (ch) {
11485587Sobrien		case 'd':
11585587Sobrien			debug = 1;
11685587Sobrien			break;
11785587Sobrien		case 'D':
11885587Sobrien			if (cmdline_symset(optarg) < 0)
11985587Sobrien				logit(LOG_CRIT,
12085587Sobrien				    "could not parse macro definition %s",
12185587Sobrien				    optarg);
12285587Sobrien			break;
12385587Sobrien		case 'f':
12485587Sobrien			conffile = optarg;
12585587Sobrien			break;
12685587Sobrien		case 'n':
12785587Sobrien			conf.opts |= BGPD_OPT_NOACTION;
12885587Sobrien			break;
12985587Sobrien		case 'v':
13085587Sobrien			if (conf.opts & BGPD_OPT_VERBOSE)
13185587Sobrien				conf.opts |= BGPD_OPT_VERBOSE2;
13285587Sobrien			conf.opts |= BGPD_OPT_VERBOSE;
13385587Sobrien			break;
13485587Sobrien		default:
13585587Sobrien			usage();
13685587Sobrien			/* NOTREACHED */
13785587Sobrien		}
13885587Sobrien	}
13985587Sobrien
14085587Sobrien	if (parse_config(conffile, &conf, &mrtconf))
14185587Sobrien		exit(1);
14285587Sobrien
14385587Sobrien	if (conf.opts & BGPD_OPT_NOACTION) {
14485587Sobrien		fprintf(stderr, "configuration OK\n");
14585587Sobrien		exit(0);
14685587Sobrien	}
14785587Sobrien
14885587Sobrien	if (geteuid())
14985587Sobrien		errx(1, "need root privileges");
15085587Sobrien
15185587Sobrien	log_init(debug);
15285587Sobrien
15385587Sobrien	if (!debug)
15485587Sobrien		daemon(1, 0);
15585587Sobrien
15685587Sobrien	logit(LOG_INFO, "startup");
15785587Sobrien
15885587Sobrien	if (pipe(pipe_m2s) == -1)
15985587Sobrien		fatal("pipe");
16085587Sobrien	if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 ||
16185587Sobrien	    fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1)
16285587Sobrien		fatal("fcntl");
16385587Sobrien	if (pipe(pipe_m2r) == -1)
16485587Sobrien		fatal("pipe");
16585587Sobrien	if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 ||
16685587Sobrien	    fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1)
16785587Sobrien		fatal("fcntl");
16885587Sobrien	if (pipe(pipe_s2r) == -1)
16985587Sobrien		fatal("pipe");
17085587Sobrien	if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 ||
17185587Sobrien	    fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1)
17285587Sobrien		fatal("fcntl");
17385587Sobrien
17485587Sobrien	if ((csock = control_init()) == -1)
17585587Sobrien		fatalx("control socket setup failed");
17685587Sobrien
17785587Sobrien	/* fork children */
17885587Sobrien	rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r);
17985587Sobrien	io_pid = session_main(&conf, pipe_m2s, pipe_s2r);
18085587Sobrien
18185587Sobrien	setproctitle("parent");
18285587Sobrien
18385587Sobrien	signal(SIGTERM, sighdlr);
18485587Sobrien	signal(SIGINT, sighdlr);
18585587Sobrien	signal(SIGCHLD, sighdlr);
18685587Sobrien	signal(SIGHUP, sighdlr);
18785587Sobrien	signal(SIGALRM, sighdlr);
18885587Sobrien	signal(SIGUSR1, sighdlr);
18985587Sobrien
19085587Sobrien	close(pipe_m2s[1]);
19185587Sobrien	close(pipe_m2r[1]);
19285587Sobrien	close(pipe_s2r[0]);
19385587Sobrien	close(pipe_s2r[1]);
19485587Sobrien	close(csock);
19585587Sobrien
19685587Sobrien	imsg_init(&ibuf_se, pipe_m2s[0]);
19785587Sobrien	imsg_init(&ibuf_rde, pipe_m2r[0]);
19885587Sobrien	if ((rfd = kroute_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE))) == -1)
19985587Sobrien		quit = 1;
20085587Sobrien
20185587Sobrien	while (quit == 0) {
20285587Sobrien		pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock;
20385587Sobrien		pfd[PFD_PIPE_SESSION].events = POLLIN;
20485587Sobrien		if (ibuf_se.w.queued)
20585587Sobrien			pfd[PFD_PIPE_SESSION].events |= POLLOUT;
20685587Sobrien		pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock;
20785587Sobrien		pfd[PFD_PIPE_ROUTE].events = POLLIN;
20885587Sobrien		if (ibuf_rde.w.queued)
20985587Sobrien			pfd[PFD_PIPE_ROUTE].events |= POLLOUT;
21085587Sobrien		pfd[PFD_SOCK_ROUTE].fd = rfd;
21185587Sobrien		pfd[PFD_SOCK_ROUTE].events = POLLIN;
21285587Sobrien		i = PFD_MRT_START;
21385587Sobrien		LIST_FOREACH(mconf, &mrtconf, list)
21485587Sobrien			if (mconf->msgbuf.queued > 0) {
21585587Sobrien				pfd[i].fd = mconf->msgbuf.sock;
21685587Sobrien				pfd[i].events |= POLLOUT;
21785587Sobrien				mrt[i++] = mconf;
21885587Sobrien			}
21985587Sobrien
22085587Sobrien		if ((nfds = poll(pfd, i, INFTIM)) == -1)
22185587Sobrien			if (errno != EINTR) {
22285587Sobrien				log_err("poll error");
22385587Sobrien				quit = 1;
22485587Sobrien			}
22585587Sobrien
22685587Sobrien		if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT))
22785587Sobrien			if ((n = msgbuf_write(&ibuf_se.w)) < 0) {
22885587Sobrien				log_err("pipe write error (to SE)");
22985587Sobrien				quit = 1;
23085587Sobrien			}
23185587Sobrien
23285587Sobrien		if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT))
23385587Sobrien			if ((n = msgbuf_write(&ibuf_rde.w)) < 0) {
23485587Sobrien				log_err("pipe write error (to RDE)");
23585587Sobrien				quit = 1;
23685587Sobrien			}
23785587Sobrien
23885587Sobrien		if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) {
23985587Sobrien			nfds--;
24085587Sobrien			if (dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION,
24185587Sobrien			    &mrtconf) == -1)
24285587Sobrien				quit = 1;
24385587Sobrien		}
24485587Sobrien
24585587Sobrien		if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) {
24685587Sobrien			nfds--;
24785587Sobrien			if (dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE,
24885587Sobrien			    &mrtconf) == -1)
24985587Sobrien				quit = 1;
25085587Sobrien		}
25185587Sobrien
25285587Sobrien		if (nfds > 0 && pfd[PFD_SOCK_ROUTE].revents & POLLIN) {
25385587Sobrien			nfds--;
25485587Sobrien			if (kroute_dispatch_msg() == -1)
25585587Sobrien				quit = 1;
256107806Sobrien		}
25785587Sobrien
25885587Sobrien		for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) {
25985587Sobrien			if (pfd[j].revents & POLLOUT) {
26085587Sobrien				if ((n = msgbuf_write(&mrt[i]->msgbuf)) < 0) {
26185587Sobrien					log_err("pipe write error (MRT)");
26285587Sobrien					quit = 1;
26385587Sobrien				}
26485587Sobrien			}
26585587Sobrien		}
26685587Sobrien
26785587Sobrien		if (reconfig) {
26885587Sobrien			logit(LOG_CRIT, "rereading config");
26985587Sobrien			reconfigure(conffile, &conf, &mrtconf);
27085587Sobrien			LIST_FOREACH(mconf, &mrtconf, list)
27185587Sobrien				mrt_state(mconf, IMSG_NONE, &ibuf_rde);
27285587Sobrien			reconfig = 0;
27385587Sobrien		}
27485587Sobrien
27585587Sobrien		if (mrtdump == 1) {
27685587Sobrien			mrt_alrm(&mrtconf, &ibuf_rde);
277			mrtdump = 0;
278		} else if (mrtdump == 2) {
279			mrt_usr1(&mrtconf, &ibuf_rde);
280			mrtdump = 0;
281		}
282	}
283
284	signal(SIGCHLD, SIG_IGN);
285
286	if (io_pid)
287		kill(io_pid, SIGTERM);
288
289	if (rde_pid)
290		kill(rde_pid, SIGTERM);
291
292	do {
293		i = waitpid(-1, NULL, WNOHANG);
294	} while (i > 0 || (i == -1 && errno == EINTR));
295
296	control_cleanup();
297	kroute_shutdown();
298
299	logit(LOG_CRIT, "Terminating");
300	return (0);
301}
302
303int
304reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc)
305{
306	struct peer		*p;
307
308	if (parse_config(conffile, conf, mrtc)) {
309		logit(LOG_CRIT, "config file %s has errors, not reloading",
310		    conffile);
311		return (-1);
312	}
313
314	if (imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0,
315	    conf, sizeof(struct bgpd_config)) == -1)
316		return (-1);
317	if (imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0,
318	    conf, sizeof(struct bgpd_config)) == -1)
319		return (-1);
320	for (p = conf->peers; p != NULL; p = p->next) {
321		if (imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id,
322		    &p->conf, sizeof(struct peer_config)) == -1)
323			return (-1);
324		if (imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id,
325		    &p->conf, sizeof(struct peer_config)) == -1)
326			return (-1);
327	}
328	if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 ||
329	    imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1)
330		return (-1);
331
332	return (0);
333}
334
335/*
336 * XXX currently messages are only buffered for mrt files.
337 */
338int
339dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf)
340{
341	struct imsg		 imsg;
342	struct buf		*wbuf;
343	struct mrtdump_config	*m;
344	ssize_t			 len;
345	int			 n;
346	in_addr_t		 ina;
347
348	if ((n = imsg_read(ibuf)) == -1)
349		return (-1);
350
351	if (n == 0) {	/* connection closed */
352		logit(LOG_CRIT, "dispatch_imsg in main: pipe closed");
353		return (-1);
354	}
355
356	for (;;) {
357		if ((n = imsg_get(ibuf, &imsg)) == -1)
358			return (-1);
359
360		if (n == 0)
361			break;
362
363		switch (imsg.hdr.type) {
364		case IMSG_MRT_MSG:
365		case IMSG_MRT_END:
366			LIST_FOREACH(m, conf, list) {
367				if (m->id != imsg.hdr.peerid)
368					continue;
369				if (mrt_state(m, imsg.hdr.type, ibuf) == 0)
370					break;
371				if (m->msgbuf.sock == -1)
372					break;
373				len = imsg.hdr.len - IMSG_HEADER_SIZE;
374				wbuf = buf_open(len);
375				if (wbuf == NULL)
376					return (-1);
377				if (buf_add(wbuf, imsg.data, len) == -1) {
378					buf_free(wbuf);
379					return (-1);
380				}
381				if ((n = buf_close(&m->msgbuf, wbuf)) < 0) {
382					buf_free(wbuf);
383					return (-1);
384				}
385				break;
386			}
387			break;
388		case IMSG_KROUTE_CHANGE:
389			if (idx != PFD_PIPE_ROUTE)
390				logit(LOG_CRIT, "route request not from RDE");
391			else if (kroute_change(imsg.data))
392				return (-1);
393			break;
394		case IMSG_KROUTE_DELETE:
395			if (idx != PFD_PIPE_ROUTE)
396				logit(LOG_CRIT, "route request not from RDE");
397			else if (kroute_delete(imsg.data))
398				return (-1);
399			break;
400		case IMSG_NEXTHOP_ADD:
401			if (idx != PFD_PIPE_ROUTE)
402				logit(LOG_CRIT, "nexthop request not from RDE");
403			else {
404				memcpy(&ina, imsg.data, sizeof(ina));
405				if (kroute_nexthop_add(ina) == -1)
406					return (-1);
407			}
408			break;
409		case IMSG_NEXTHOP_REMOVE:
410			if (idx != PFD_PIPE_ROUTE)
411				logit(LOG_CRIT, "nexthop request not from RDE");
412			else {
413				memcpy(&ina, imsg.data, sizeof(ina));
414				kroute_nexthop_delete(ina);
415			}
416			break;
417		default:
418			break;
419		}
420		imsg_free(&imsg);
421	}
422	return (0);
423}
424
425void
426send_nexthop_update(struct kroute_nexthop *msg)
427{
428	char	*gw = NULL;
429
430	if (msg->gateway)
431		if (asprintf(&gw, ": via %s", log_ntoa(msg->gateway)) == -1) {
432			log_err("send_nexthop_update");
433			quit = 1;
434		}
435
436	logit(LOG_INFO, "nexthop %s now %s%s%s", log_ntoa(msg->nexthop),
437	    msg->valid ? "valid" : "invalid",
438	    msg->connected ? ": directly connected" : "",
439	    msg->gateway ? gw : "");
440
441	free(gw);
442
443	if (imsg_compose(&ibuf_rde, IMSG_NEXTHOP_UPDATE, 0,
444	    msg, sizeof(struct kroute_nexthop)) == -1)
445		quit = 1;
446}
447