summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEsben Norby <norby@cvs.openbsd.org>2006-10-18 16:11:59 +0000
committerEsben Norby <norby@cvs.openbsd.org>2006-10-18 16:11:59 +0000
commit63fb38a95ebcfbff09d5d7ed8780c5de268775ed (patch)
tree2649f6cd25876df8e41ae58c160def2f129cde5e
parent9898323e8078c0a28e2404083e37bbb23637a390 (diff)
Welcome ripd started by Michele Marchetto some time ago by using the imsg/three process framework of ospfd. He implemented most of the daemon with a little help and guidance from Claudio and I. Currently the daemon is more or less complete, with the exception of key lifetime and rollover. Not yet connected to the builds. OK claudio@
-rw-r--r--usr.sbin/ripd/message.c408
-rw-r--r--usr.sbin/ripd/ripd.c507
2 files changed, 915 insertions, 0 deletions
diff --git a/usr.sbin/ripd/message.c b/usr.sbin/ripd/message.c
new file mode 100644
index 00000000000..d8e1e75abbd
--- /dev/null
+++ b/usr.sbin/ripd/message.c
@@ -0,0 +1,408 @@
+/* $OpenBSD: message.c,v 1.1 2006/10/18 16:11:58 norby Exp $ */
+
+/*
+ * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <netinet/udp.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ripd.h"
+#include "rip.h"
+#include "ripe.h"
+#include "log.h"
+
+extern struct ripd_conf *oeconf;
+
+void delete_entry(struct rip_route *);
+
+/* timers */
+void
+report_timer(int fd, short event, void *arg)
+{
+ struct timeval tv;
+
+ ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0);
+
+ /* restart report timer */
+ timerclear(&tv);
+ tv.tv_sec = KEEPALIVE + arc4random() % OFFSET;
+ evtimer_add(&oeconf->report_timer, &tv);
+}
+
+int
+start_report_timer(void)
+{
+ struct timeval tv;
+
+ timerclear(&tv);
+ tv.tv_sec = KEEPALIVE + arc4random() % OFFSET;
+ return (evtimer_add(&oeconf->report_timer, &tv));
+}
+
+void
+add_entry(struct packet_head *r_list, struct rip_route *rr)
+{
+ struct packet_entry *re;
+
+ if (rr == NULL)
+ fatalx("add_entry: no route report");
+
+ if ((re = calloc(1, sizeof(*re))) == NULL)
+ fatal("add_response");
+
+ TAILQ_INSERT_TAIL(r_list, re, entry);
+ re->rr = rr;
+ rr->refcount++;
+}
+
+void
+delete_entry(struct rip_route *rr)
+{
+ if (--rr->refcount == 0)
+ free(rr);
+}
+
+int
+send_triggered_update(struct iface *iface, struct rip_route *rr)
+{
+ struct sockaddr_in dst;
+ struct buf *buf;
+ u_int16_t afi, route_tag;
+ u_int32_t address, netmask, nexthop, metric;
+
+ inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
+
+ dst.sin_port = htons(RIP_PORT);
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ if (iface->passive)
+ return (0);
+
+ if ((buf = buf_open(iface->mtu - sizeof(struct ip)
+ - sizeof(struct udphdr))) == NULL)
+ fatal("send_triggered_update");
+
+ gen_rip_hdr(buf, COMMAND_RESPONSE);
+
+ afi = htons(AF_INET);
+ route_tag = 0;
+
+ address = rr->address.s_addr;
+ netmask = rr->mask.s_addr;
+ nexthop = rr->nexthop.s_addr;
+ metric = htonl(rr->metric);
+
+ buf_add(buf, &afi, sizeof(afi));
+ buf_add(buf, &route_tag, sizeof(route_tag));
+ buf_add(buf, &address, sizeof(address));
+ buf_add(buf, &netmask, sizeof(netmask));
+ buf_add(buf, &nexthop, sizeof(nexthop));
+ buf_add(buf, &metric, sizeof(metric));
+
+ send_packet(iface, buf->buf, buf->wpos, &dst);
+ buf_free(buf);
+
+ return (0);
+}
+
+int
+send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
+{
+ struct buf *buf;
+ struct iface *iface;
+ struct packet_entry *entry;
+ struct sockaddr_in dst;
+ u_int8_t nentries;
+ u_int8_t single_entry = 0;
+ u_int32_t address, netmask, nexthop;
+ u_int16_t port, afi, route_tag;
+ u_int32_t metric;
+
+ if (i == NULL) {
+ /* directly to a nbr */
+ iface = nbr->iface;
+ dst.sin_addr = nbr->addr;
+ port = htons(nbr->port);
+ } else {
+ /* multicast on interface */
+ iface = i;
+ inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
+ port = htons(RIP_PORT);
+ }
+
+ dst.sin_port = port;
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ if (iface->passive)
+ return (0);
+
+ while (!TAILQ_EMPTY(r_list)) {
+ if ((buf = buf_open(iface->mtu - sizeof(struct ip)
+ - sizeof(struct udphdr))) == NULL)
+ fatal("send_request");
+
+ gen_rip_hdr(buf, COMMAND_REQUEST);
+
+ route_tag = 0;
+ nentries = 0;
+
+ if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head))
+ single_entry = 1;
+ while (((entry = TAILQ_FIRST(r_list)) != NULL) &&
+ nentries < 25) {
+ afi = htons(AF_INET);
+
+ address = entry->rr->address.s_addr;
+ netmask = entry->rr->mask.s_addr;
+ nexthop = entry->rr->nexthop.s_addr;
+ metric = htonl(entry->rr->metric);
+
+ if (metric == htonl(INFINITY) && single_entry)
+ afi = AF_UNSPEC;
+
+ buf_add(buf, &afi, sizeof(afi));
+ buf_add(buf, &route_tag, sizeof(route_tag));
+ buf_add(buf, &address, sizeof(address));
+ buf_add(buf, &netmask, sizeof(netmask));
+ buf_add(buf, &nexthop, sizeof(nexthop));
+ buf_add(buf, &metric, sizeof(metric));
+
+ TAILQ_REMOVE(r_list, entry, entry);
+ delete_entry(entry->rr);
+ free(entry);
+ nentries++;
+ }
+ send_packet(iface, buf->buf, buf->wpos, &dst);
+ buf_free(buf);
+ }
+
+ return (0);
+}
+
+int
+send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
+{
+ struct buf *buf;
+ struct iface *iface;
+ struct packet_entry *entry;
+ struct sockaddr_in dst;
+ u_int8_t nentries;
+ u_int16_t port, afi, route_tag;
+ u_int32_t address, netmask, nexthop;
+ u_int32_t metric;
+
+ if (i == NULL) {
+ /* directly to a nbr */
+ iface = nbr->iface;
+ dst.sin_addr = nbr->addr;
+ port = htons(nbr->port);
+ } else {
+ /* multicast on interface */
+ iface = i;
+ inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
+ port = htons(RIP_PORT);
+ }
+
+ dst.sin_port = port;
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ if (iface->passive)
+ return (0);
+
+ while (!TAILQ_EMPTY(r_list)) {
+ if ((buf = buf_open(iface->mtu - sizeof(struct ip)
+ - sizeof(struct udphdr))) == NULL)
+ fatal("send_response");
+
+ gen_rip_hdr(buf, COMMAND_RESPONSE);
+
+ afi = htons(AF_INET);
+ route_tag = 0;
+ nentries = 0;
+
+ if (iface->auth_type != AUTH_NONE) {
+ if (auth_gen(buf, iface) < 0)
+ return (-1);
+ nentries++;
+ }
+
+ while ((entry = TAILQ_FIRST(r_list)) != NULL &&
+ nentries < 25) {
+ address = entry->rr->address.s_addr;
+ netmask = entry->rr->mask.s_addr;
+ nexthop = entry->rr->nexthop.s_addr;
+ metric = htonl(entry->rr->metric);
+
+ if (entry->rr->ifindex == iface->ifindex) {
+ if (oeconf->options & OPT_SPLIT_HORIZON)
+ goto free;
+ else if (oeconf->options & OPT_SPLIT_POISONED)
+ metric = htonl(INFINITY);
+ }
+
+ buf_add(buf, &afi, sizeof(afi));
+ buf_add(buf, &route_tag, sizeof(route_tag));
+ buf_add(buf, &address, sizeof(address));
+ buf_add(buf, &netmask, sizeof(netmask));
+ buf_add(buf, &nexthop, sizeof(nexthop));
+ buf_add(buf, &metric, sizeof(metric));
+free:
+ TAILQ_REMOVE(r_list, entry, entry);
+ delete_entry(entry->rr);
+ free(entry);
+ nentries++;
+ }
+
+ if (iface->auth_type == AUTH_CRYPT)
+ auth_add_trailer(buf, iface);
+
+ send_packet(iface, buf->buf, buf->wpos, &dst);
+ buf_free(buf);
+ }
+
+ return (0);
+}
+
+void
+recv_request(struct iface *i, struct nbr *nbr, char *buf, u_int16_t len)
+{
+ struct rip_entry *e;
+ struct rip_route rr;
+ int l = len;
+
+ bzero(&rr, sizeof(rr));
+
+ if (len < RIP_ENTRY_LEN) {
+ log_debug("recv_request: bad packet size, interface %s",
+ i->name);
+ return;
+ }
+
+ /*
+ * XXX is it guaranteed that bus is properly aligned.
+ * If not this will bomb on strict aligenment archs.
+ * */
+ e = (struct rip_entry *)buf;
+
+ if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
+ log_debug("recv_request: packet too long\n");
+ return;
+ }
+
+ l -= RIP_ENTRY_LEN;
+
+ /*
+ * If there is exactly one entry in the request, and it has
+ * an address family identifier of zero and a metric of
+ * infinity (i.e., 16), then this is a request to send the
+ * entire routing table.
+ */
+ if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) {
+ ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid,
+ 0, NULL, 0);
+ return;
+ }
+
+ for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
+ if (e->AFI != AF_INET) {
+ log_debug("recv_request: AFI %d not supported\n",
+ e->AFI);
+ return;
+ }
+ rr.address.s_addr = e->address;
+ rr.mask.s_addr = e->mask;
+ rr.nexthop.s_addr = e->nexthop;
+ rr.metric = e->metric;
+ rr.ifindex = i->ifindex;
+
+ ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid,
+ 0, (void *)&rr, sizeof(rr));
+
+ e++;
+ }
+
+ ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid,
+ 0, NULL, 0);
+}
+
+void
+recv_response(struct iface *i, struct nbr *nbr, char *buf, u_int16_t len)
+{
+ struct rip_route r;
+ struct rip_entry *e;
+ int l;
+
+ if (len < RIP_ENTRY_LEN) {
+ log_debug("recv_response: bad packet size, interface %s",
+ i->name);
+ return;
+ }
+
+ /* We must double check the length, because the only entry
+ * can be stripped off by authentication code
+ */
+ if (len < RIP_ENTRY_LEN) {
+ /* If there are no entries, our work is finished here */
+ return;
+ }
+
+ /* XXX again */
+ e = (struct rip_entry *)buf;
+
+ if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
+ log_debug("recv_response: packet too long\n");
+ return;
+ }
+
+ l = len - sizeof(*e);
+
+ for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
+ if (ntohs(e->AFI) != AF_INET) {
+ log_debug("recv_response: AFI %d not supported\n",
+ e->AFI);
+ return;
+ }
+
+ r.address.s_addr = e->address;
+ r.mask.s_addr = e->mask;
+
+ if (e->nexthop == INADDR_ANY ||
+ ((i->addr.s_addr & i->mask.s_addr) !=
+ (e->nexthop & i->mask.s_addr)))
+ r.nexthop.s_addr = nbr->addr.s_addr;
+ else
+ r.nexthop.s_addr = e->nexthop;
+
+ r.metric = ntohl(e->metric);
+ r.ifindex = i->ifindex;
+
+ ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, (void *)&r,
+ sizeof(*e));
+
+ e++;
+ }
+}
diff --git a/usr.sbin/ripd/ripd.c b/usr.sbin/ripd/ripd.c
new file mode 100644
index 00000000000..f0fc22e2678
--- /dev/null
+++ b/usr.sbin/ripd/ripd.c
@@ -0,0 +1,507 @@
+/* $OpenBSD: ripd.c,v 1.1 2006/10/18 16:11:58 norby Exp $ */
+
+/*
+ * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <event.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "rip.h"
+#include "ripd.h"
+#include "ripe.h"
+#include "log.h"
+#include "control.h"
+#include "rde.h"
+
+__dead void usage(void);
+int check_child(pid_t, const char *);
+void main_sig_handler(int, short, void *);
+void ripd_shutdown(void);
+void main_dispatch_ripe(int, short, void *);
+void main_dispatch_rde(int, short, void *);
+int check_file_secrecy(int, const char *);
+
+int pipe_parent2ripe[2];
+int pipe_parent2rde[2];
+int pipe_ripe2rde[2];
+
+struct ripd_conf *conf = NULL;
+struct imsgbuf *ibuf_ripe;
+struct imsgbuf *ibuf_rde;
+
+pid_t ripe_pid = 0;
+pid_t rde_pid = 0;
+
+__dead void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-dnv] [-f file]\n", __progname);
+ exit(1);
+}
+
+/* ARGSUSED */
+void
+main_sig_handler(int sig, short event, void *arg)
+{
+ /*
+ * signal handler rules don't apply, libevent decouples for us
+ */
+
+ int die = 0;
+
+ switch (sig) {
+ case SIGTERM:
+ case SIGINT:
+ die = 1;
+ /* FALLTHROUGH */
+ case SIGCHLD:
+ if (check_child(ripe_pid, "rip engine")) {
+ ripe_pid = 0;
+ die = 1;
+ }
+ if (check_child(rde_pid, "route decision engine")) {
+ rde_pid = 0;
+ die = 1;
+ }
+ if (die)
+ ripd_shutdown();
+ break;
+ case SIGHUP:
+ /* reconfigure */
+ /* ... */
+ break;
+ default:
+ fatalx("unexpected signal");
+ /* NOTREACHED */
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup;
+ int mib[4];
+ int debug = 0;
+ int ipforwarding;
+ int ch;
+ int opts = 0;
+ char *conffile;
+ size_t len;
+
+ conffile = CONF_FILE;
+ ripd_process = PROC_MAIN;
+
+ while ((ch = getopt(argc, argv, "df:nv")) != -1) {
+ switch (ch) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'f':
+ conffile = optarg;
+ break;
+ case 'n':
+ opts |= RIPD_OPT_NOACTION;
+ break;
+ case 'v':
+ if (opts & RIPD_OPT_VERBOSE)
+ opts |= RIPD_OPT_VERBOSE2;
+ opts |= RIPD_OPT_VERBOSE;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ /* start logging */
+ log_init(debug);
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_IP;
+ mib[3] = IPCTL_FORWARDING;
+ len = sizeof(ipforwarding);
+ if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1)
+ err(1, "sysctl");
+
+ if (!ipforwarding)
+ log_warnx("WARNING: IP forwarding NOT enabled");
+
+ /* fetch interfaces early */
+ kif_init();
+
+ /* parse config file */
+ if ((conf = parse_config(conffile, opts)) == NULL )
+ exit(1);
+
+ if (conf->opts & RIPD_OPT_NOACTION) {
+ if (conf->opts & RIPD_OPT_VERBOSE)
+ print_config(conf);
+ else
+ fprintf(stderr, "configuration OK\n");
+ exit(0);
+ }
+
+ /* check for root privileges */
+ if (geteuid())
+ errx(1, "need root privileges");
+
+ /* check for ripd user */
+ if (getpwnam(RIPD_USER) == NULL)
+ errx(1, "unknown user %s", RIPD_USER);
+
+ if (!debug)
+ daemon(1, 0);
+
+ log_info("startup");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
+ pipe_parent2ripe) == -1)
+ fatal("socketpair");
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2rde) == -1)
+ fatal("socketpair");
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_ripe2rde) == -1)
+ fatal("socketpair");
+ session_socket_blockmode(pipe_parent2ripe[0], BM_NONBLOCK);
+ session_socket_blockmode(pipe_parent2ripe[1], BM_NONBLOCK);
+ session_socket_blockmode(pipe_parent2rde[0], BM_NONBLOCK);
+ session_socket_blockmode(pipe_parent2rde[1], BM_NONBLOCK);
+ session_socket_blockmode(pipe_ripe2rde[0], BM_NONBLOCK);
+ session_socket_blockmode(pipe_ripe2rde[1], BM_NONBLOCK);
+
+ /* start children */
+ rde_pid = rde(conf, pipe_parent2rde, pipe_ripe2rde, pipe_parent2ripe);
+ ripe_pid = ripe(conf, pipe_parent2ripe, pipe_ripe2rde, pipe_parent2rde);
+
+ /* show who we are */
+ setproctitle("parent");
+
+ event_init();
+
+ /* setup signal handler */
+ signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
+ signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
+ signal_set(&ev_sigchld, SIGINT, main_sig_handler, NULL);
+ signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal_add(&ev_sigchld, NULL);
+ signal_add(&ev_sighup, NULL);
+
+ /* setup pipes to children */
+ close(pipe_parent2ripe[1]);
+ close(pipe_parent2rde[1]);
+ close(pipe_ripe2rde[0]);
+ close(pipe_ripe2rde[1]);
+
+ if ((ibuf_ripe = malloc(sizeof(struct imsgbuf))) == NULL ||
+ (ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL)
+ fatal(NULL);
+ imsg_init(ibuf_ripe, pipe_parent2ripe[0], main_dispatch_ripe);
+ imsg_init(ibuf_rde, pipe_parent2rde[0], main_dispatch_rde);
+
+ /* setup event handler */
+ ibuf_ripe->events = EV_READ;
+ event_set(&ibuf_ripe->ev, ibuf_ripe->fd, ibuf_ripe->events,
+ ibuf_ripe->handler, ibuf_ripe);
+ event_add(&ibuf_ripe->ev, NULL);
+
+ ibuf_rde->events = EV_READ;
+ event_set(&ibuf_rde->ev, ibuf_rde->fd, ibuf_rde->events,
+ ibuf_rde->handler, ibuf_rde);
+ event_add(&ibuf_rde->ev, NULL);
+
+ if (kr_init(!(conf->flags & RIPD_FLAG_NO_FIB_UPDATE)) == -1)
+ fatalx("kr_init failed");
+
+ event_dispatch();
+
+ ripd_shutdown();
+ /* NOTREACHED */
+ return (0);
+}
+
+void
+ripd_shutdown(void)
+{
+ struct iface *i;
+ pid_t pid;
+
+ if (ripe_pid)
+ kill(ripe_pid, SIGTERM);
+
+ if (rde_pid)
+ kill(rde_pid, SIGTERM);
+
+ while ((i = LIST_FIRST(&conf->iface_list)) != NULL) {
+ LIST_REMOVE(i, entry);
+ if_del(i);
+ }
+
+ control_cleanup();
+ kr_shutdown();
+
+ do {
+ if ((pid = wait(NULL)) == -1 &&
+ errno != EINTR && errno != ECHILD)
+ fatal("wait");
+ } while (pid != -1 || (pid == -1 && errno == EINTR));
+
+ msgbuf_clear(&ibuf_ripe->w);
+ free(ibuf_ripe);
+ msgbuf_clear(&ibuf_rde->w);
+ free(ibuf_rde);
+ free(conf);
+
+ log_info("terminating");
+ exit(0);
+}
+
+int
+check_child(pid_t pid, const char *pname)
+{
+ int status;
+
+ if (waitpid(pid, &status, WNOHANG) > 0) {
+ if (WIFEXITED(status)) {
+ log_warnx("lost child: %s exited", pname);
+ return (1);
+ }
+ if (WIFSIGNALED(status)) {
+ log_warnx("lost child: %s terminated; signal %d",
+ pname, WTERMSIG(status));
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/* imsg handling */
+/* ARGSUSED */
+void
+main_dispatch_ripe(int fd, short event, void *bula)
+{
+ struct imsgbuf *ibuf = bula;
+ struct imsg imsg;
+ ssize_t n;
+
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal("imsg_read error");
+ if (n == 0) /* connection closed */
+ fatalx("pipe closed");
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(ibuf);
+ return;
+ default:
+ fatalx("unknown event");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_CTL_RELOAD:
+ /* XXX reconfig */
+ break;
+ case IMSG_CTL_FIB_COUPLE:
+ kr_fib_couple();
+ break;
+ case IMSG_CTL_FIB_DECOUPLE:
+ kr_fib_decouple();
+ break;
+ case IMSG_CTL_KROUTE:
+ case IMSG_CTL_KROUTE_ADDR:
+ kr_show_route(&imsg);
+ break;
+ case IMSG_CTL_IFINFO:
+ if (imsg.hdr.len == IMSG_HEADER_SIZE)
+ kr_ifinfo(NULL, imsg.hdr.pid);
+ else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ)
+ kr_ifinfo(imsg.data, imsg.hdr.pid);
+ else
+ log_warnx("IFINFO request with wrong len");
+ break;
+ default:
+ log_debug("main_dispatch_ripe: error handling imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(ibuf);
+}
+
+/* ARGSUSED */
+void
+main_dispatch_rde(int fd, short event, void *bula)
+{
+ struct imsgbuf *ibuf = bula;
+ struct imsg imsg;
+ ssize_t n;
+
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal("imsg_read error");
+ if (n == 0) /* connection closed */
+ fatalx("pipe closed");
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(ibuf);
+ return;
+ default:
+ fatalx("unknown event");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_KROUTE_CHANGE:
+ if (kr_change(imsg.data))
+ log_warn("main_dispatch_rde: error changing "
+ "route");
+ break;
+ case IMSG_KROUTE_DELETE:
+ if (kr_delete(imsg.data))
+ log_warn("main_dispatch_rde: error deleting "
+ "route");
+ break;
+ default:
+ log_debug("main_dispatch_rde: error handling imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(ibuf);
+}
+
+void
+main_imsg_compose_ripe(int type, pid_t pid, void *data, u_int16_t datalen)
+{
+ imsg_compose(ibuf_ripe, type, 0, pid, data, datalen);
+}
+
+void
+main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
+{
+ imsg_compose(ibuf_rde, type, 0, pid, data, datalen);
+}
+
+int
+check_file_secrecy(int fd, const char *fname)
+{
+ struct stat st;
+
+ if (fstat(fd, &st)) {
+ log_warn("cannot stat %s", fname);
+ return (-1);
+ }
+
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ log_warnx("%s: owner not root or current user", fname);
+ return (-1);
+ }
+
+ if (st.st_mode & (S_IRWXG | S_IRWXO)) {
+ log_warnx("%s: group/world readable/writeable", fname);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+rip_redistribute(struct kroute *kr)
+{
+ if (kr->flags & F_RIPD_INSERTED)
+ return (1);
+
+ /* XXX this is funky, it is not possible to distribute static and
+ * connected. OSPFD has a much better way to do this including rtlabel
+ * support
+ */
+ switch (conf->redistribute_flags) {
+ case REDISTRIBUTE_NONE:
+ return (0);
+ case REDISTRIBUTE_STATIC:
+ return (kr->flags & F_KERNEL ? 1 : 0);
+ case REDISTRIBUTE_CONNECTED:
+ return (kr->flags & F_CONNECTED ? 1 : 0);
+ case REDISTRIBUTE_DEFAULT:
+ if (kr->prefix.s_addr == INADDR_ANY &&
+ kr->netmask.s_addr == INADDR_ANY)
+ return (1);
+ else
+ return (0);
+ default:
+ fatalx("unknown redistribute type");
+ }
+}
+
+/* this needs to be added here so that ripctl can be used without libevent */
+void
+imsg_event_add(struct imsgbuf *ibuf)
+{
+ ibuf->events = EV_READ;
+ if (ibuf->w.queued)
+ ibuf->events |= EV_WRITE;
+
+ event_del(&ibuf->ev);
+ event_set(&ibuf->ev, ibuf->fd, ibuf->events, ibuf->handler, ibuf);
+ event_add(&ibuf->ev, NULL);
+}