summaryrefslogtreecommitdiff
path: root/usr.sbin/relayd
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2011-05-19 08:56:50 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2011-05-19 08:56:50 +0000
commit31b1bbafe11da6e0dead1dd433eff2ab64ae8bb6 (patch)
tree911cab636cae40f30bbaab5a11769d79cf7f41b2 /usr.sbin/relayd
parent1e687a712e695c6cf93da2be7c3d01ef04f587cb (diff)
Fix reload support in relayd(8) by reimplementing large parts of the
daemon infrastructure. The previous design made it fairly hard to reload the complex data structures, especially relays and protocols. One of the reasons was that the privsep'd relayd processes had two ways of getting their configuration: 1) from memory after forking from the parent process and 2) and (partially) via imsgs after reload. The new implementation first forks the privsep'd children before the parents loads the configuration and sends it via imsgs to them; so it is only like 2) before. It is based on an approach that I first implemented for iked(8) and I also fixed many bugs in the code. Thanks to many testers including dlg@ sthen@ phessler@ ok pyr@ dlg@ sthen@
Diffstat (limited to 'usr.sbin/relayd')
-rw-r--r--usr.sbin/relayd/Makefile4
-rw-r--r--usr.sbin/relayd/check_tcp.c59
-rw-r--r--usr.sbin/relayd/config.c898
-rw-r--r--usr.sbin/relayd/control.c29
-rw-r--r--usr.sbin/relayd/hce.c78
-rw-r--r--usr.sbin/relayd/parse.y237
-rw-r--r--usr.sbin/relayd/pfe.c124
-rw-r--r--usr.sbin/relayd/pfe_filter.c19
-rw-r--r--usr.sbin/relayd/pfe_route.c51
-rw-r--r--usr.sbin/relayd/proc.c46
-rw-r--r--usr.sbin/relayd/relay.c206
-rw-r--r--usr.sbin/relayd/relayd.c522
-rw-r--r--usr.sbin/relayd/relayd.h138
-rw-r--r--usr.sbin/relayd/snmp.c92
14 files changed, 1741 insertions, 762 deletions
diff --git a/usr.sbin/relayd/Makefile b/usr.sbin/relayd/Makefile
index 158491944da..0ae2acc345b 100644
--- a/usr.sbin/relayd/Makefile
+++ b/usr.sbin/relayd/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.21 2011/05/09 12:08:47 reyk Exp $
+# $OpenBSD: Makefile,v 1.22 2011/05/19 08:56:49 reyk Exp $
PROG= relayd
SRCS= parse.y log.c control.c ssl.c ssl_privsep.c \
relayd.c pfe.c pfe_filter.c pfe_route.c hce.c relay.c \
relay_udp.c carp.c check_icmp.c check_tcp.c check_script.c \
- name2id.c snmp.c shuffle.c proc.c
+ name2id.c snmp.c shuffle.c proc.c config.c
MAN= relayd.8 relayd.conf.5
LDADD= -levent -lssl -lcrypto -lutil
diff --git a/usr.sbin/relayd/check_tcp.c b/usr.sbin/relayd/check_tcp.c
index 92bd2cef6f2..d960f0aa6a7 100644
--- a/usr.sbin/relayd/check_tcp.c
+++ b/usr.sbin/relayd/check_tcp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: check_tcp.c,v 1.40 2011/05/05 12:01:43 reyk Exp $ */
+/* $OpenBSD: check_tcp.c,v 1.41 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -38,7 +38,8 @@
#include "relayd.h"
void tcp_write(int, short, void *);
-void tcp_host_up(int, struct ctl_tcp_event *);
+void tcp_host_up(struct ctl_tcp_event *);
+void tcp_close(struct ctl_tcp_event *, int);
void tcp_send_req(int, short, void *);
void tcp_read_buf(int, short, void *);
@@ -99,14 +100,14 @@ check_tcp(struct ctl_tcp_event *cte)
cte->buf = NULL;
cte->host->up = HOST_UP;
+ cte->s = s;
event_del(&cte->ev);
event_set(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_write, cte);
event_add(&cte->ev, &tv);
return;
bad:
- close(s);
- cte->host->up = HOST_DOWN;
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, he);
}
@@ -118,8 +119,7 @@ tcp_write(int s, short event, void *arg)
socklen_t len;
if (event == EV_TIMEOUT) {
- close(s);
- cte->host->up = HOST_DOWN;
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, HCE_TCP_CONNECT_TIMEOUT);
return;
}
@@ -128,26 +128,36 @@ tcp_write(int s, short event, void *arg)
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len))
fatal("tcp_write: getsockopt");
if (err != 0) {
- close(s);
- cte->host->up = HOST_DOWN;
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, HCE_TCP_CONNECT_FAIL);
return;
}
cte->host->up = HOST_UP;
- tcp_host_up(s, cte);
+ tcp_host_up(cte);
}
void
-tcp_host_up(int s, struct ctl_tcp_event *cte)
+tcp_close(struct ctl_tcp_event *cte, int status)
{
- cte->s = s;
+ close(cte->s);
+ cte->s = -1;
+ if (status != 0)
+ cte->host->up = status;
+ if (cte->buf) {
+ ibuf_free(cte->buf);
+ cte->buf = NULL;
+ }
+}
+void
+tcp_host_up(struct ctl_tcp_event *cte)
+{
switch (cte->table->conf.check) {
case CHECK_TCP:
if (cte->table->conf.flags & F_SSL)
break;
- close(s);
+ tcp_close(cte, 0);
hce_notify_done(cte->host, HCE_TCP_CONNECT_OK);
return;
case CHECK_HTTP_CODE:
@@ -171,14 +181,14 @@ tcp_host_up(int s, struct ctl_tcp_event *cte)
if (cte->table->sendbuf != NULL) {
cte->req = cte->table->sendbuf;
- event_again(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
+ event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
&cte->tv_start, &cte->table->conf.timeout, cte);
return;
}
if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
fatalx("tcp_host_up: cannot create dynamic buffer");
- event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, tcp_read_buf,
+ event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, tcp_read_buf,
&cte->tv_start, &cte->table->conf.timeout, cte);
}
@@ -190,8 +200,7 @@ tcp_send_req(int s, short event, void *arg)
int len;
if (event == EV_TIMEOUT) {
- cte->host->up = HOST_DOWN;
- close(cte->s);
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, HCE_TCP_WRITE_TIMEOUT);
return;
}
@@ -202,8 +211,7 @@ tcp_send_req(int s, short event, void *arg)
if (errno == EAGAIN || errno == EINTR)
goto retry;
log_warnx("%s: cannot send request", __func__);
- cte->host->up = HOST_DOWN;
- close(cte->s);
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, HCE_TCP_WRITE_FAIL);
return;
}
@@ -230,9 +238,7 @@ tcp_read_buf(int s, short event, void *arg)
struct ctl_tcp_event *cte = arg;
if (event == EV_TIMEOUT) {
- cte->host->up = HOST_DOWN;
- ibuf_free(cte->buf);
- close(s);
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, HCE_TCP_READ_TIMEOUT);
return;
}
@@ -243,16 +249,13 @@ tcp_read_buf(int s, short event, void *arg)
case -1:
if (errno == EAGAIN || errno == EINTR)
goto retry;
- cte->host->up = HOST_DOWN;
- ibuf_free(cte->buf);
- close(cte->s);
+ tcp_close(cte, HOST_DOWN);
hce_notify_done(cte->host, HCE_TCP_READ_FAIL);
return;
case 0:
cte->host->up = HOST_DOWN;
(void)cte->validate_close(cte);
- close(cte->s);
- ibuf_free(cte->buf);
+ tcp_close(cte, 0);
hce_notify_done(cte->host, cte->host->he);
return;
default:
@@ -261,9 +264,7 @@ tcp_read_buf(int s, short event, void *arg)
if (cte->validate_read != NULL) {
if (cte->validate_read(cte) != 0)
goto retry;
-
- close(cte->s);
- ibuf_free(cte->buf);
+ tcp_close(cte, 0);
hce_notify_done(cte->host, cte->host->he);
return;
}
diff --git a/usr.sbin/relayd/config.c b/usr.sbin/relayd/config.c
new file mode 100644
index 00000000000..bb91b88c364
--- /dev/null
+++ b/usr.sbin/relayd/config.c
@@ -0,0 +1,898 @@
+/* $OpenBSD: config.c,v 1.1 2011/05/19 08:56:49 reyk Exp $ */
+
+/*
+ * Copyright (c) 2011 Reyk Floeter <reyk@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/stat.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+#include <openssl/ssl.h>
+
+#include "relayd.h"
+
+int
+config_init(struct relayd *env)
+{
+ struct privsep *ps = env->sc_ps;
+ u_int what;
+
+ /* Global configuration */
+ if (privsep_process == PROC_PARENT) {
+ env->sc_timeout.tv_sec = CHECK_TIMEOUT / 1000;
+ env->sc_timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000;
+ env->sc_interval.tv_sec = CHECK_INTERVAL;
+ env->sc_interval.tv_usec = 0;
+ env->sc_prefork_relay = RELAY_NUMPROC;
+ env->sc_statinterval.tv_sec = RELAY_STATINTERVAL;
+
+ ps->ps_what[PROC_PARENT] = CONFIG_ALL;
+ ps->ps_what[PROC_PFE] = CONFIG_ALL & ~CONFIG_PROTOS;
+ ps->ps_what[PROC_HCE] = CONFIG_TABLES;
+ ps->ps_what[PROC_RELAY] =
+ CONFIG_TABLES|CONFIG_RELAYS|CONFIG_PROTOS;
+ }
+
+ /* Other configuration */
+ what = ps->ps_what[privsep_process];
+ if (what & CONFIG_TABLES) {
+ if ((env->sc_tables =
+ calloc(1, sizeof(*env->sc_tables))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_tables);
+
+ memset(&env->sc_empty_table, 0, sizeof(env->sc_empty_table));
+ env->sc_empty_table.conf.id = EMPTY_TABLE;
+ env->sc_empty_table.conf.flags |= F_DISABLE;
+ (void)strlcpy(env->sc_empty_table.conf.name, "empty",
+ sizeof(env->sc_empty_table.conf.name));
+
+ }
+ if (what & CONFIG_RDRS) {
+ if ((env->sc_rdrs =
+ calloc(1, sizeof(*env->sc_rdrs))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_rdrs);
+
+ }
+ if (what & CONFIG_RELAYS) {
+ if ((env->sc_relays =
+ calloc(1, sizeof(*env->sc_relays))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_relays);
+ }
+ if (what & CONFIG_PROTOS) {
+ if ((env->sc_protos =
+ calloc(1, sizeof(*env->sc_protos))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_protos);
+
+ bzero(&env->sc_proto_default, sizeof(env->sc_proto_default));
+ env->sc_proto_default.id = EMPTY_ID;
+ env->sc_proto_default.flags = F_USED;
+ env->sc_proto_default.cache = RELAY_CACHESIZE;
+ env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
+ env->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
+ env->sc_proto_default.sslflags = SSLFLAG_DEFAULT;
+ (void)strlcpy(env->sc_proto_default.sslciphers,
+ SSLCIPHERS_DEFAULT,
+ sizeof(env->sc_proto_default.sslciphers));
+ env->sc_proto_default.type = RELAY_PROTO_TCP;
+ (void)strlcpy(env->sc_proto_default.name, "default",
+ sizeof(env->sc_proto_default.name));
+ RB_INIT(&env->sc_proto_default.request_tree);
+ RB_INIT(&env->sc_proto_default.response_tree);
+ }
+ if (what & CONFIG_RTS) {
+ if ((env->sc_rts =
+ calloc(1, sizeof(*env->sc_rts))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_rts);
+ }
+ if (what & CONFIG_ROUTES) {
+ if ((env->sc_routes =
+ calloc(1, sizeof(*env->sc_routes))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_routes);
+ }
+
+ return (0);
+}
+
+void
+config_purge(struct relayd *env, u_int reset)
+{
+ struct privsep *ps = env->sc_ps;
+ struct table *table;
+ struct rdr *rdr;
+ struct address *virt;
+ struct protocol *proto;
+ struct relay *rlay;
+ struct netroute *nr;
+ struct router *rt;
+ u_int what;
+
+ what = ps->ps_what[privsep_process] & reset;
+
+ if (what & CONFIG_TABLES && env->sc_tables != NULL) {
+ while ((table = TAILQ_FIRST(env->sc_tables)) != NULL)
+ purge_table(env->sc_tables, table);
+ env->sc_tablecount = 0;
+ }
+ if (what & CONFIG_RDRS && env->sc_rdrs != NULL) {
+ while ((rdr = TAILQ_FIRST(env->sc_rdrs)) != NULL) {
+ TAILQ_REMOVE(env->sc_rdrs, rdr, entry);
+ while ((virt = TAILQ_FIRST(&rdr->virts)) != NULL) {
+ TAILQ_REMOVE(&rdr->virts, virt, entry);
+ free(virt);
+ }
+ free(rdr);
+ }
+ env->sc_rdrcount = 0;
+ }
+ if (what & CONFIG_RELAYS && env->sc_relays != NULL) {
+ while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL)
+ purge_relay(env, rlay);
+ env->sc_relaycount = 0;
+ }
+ if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
+ while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
+ TAILQ_REMOVE(env->sc_protos, proto, entry);
+ purge_tree(&proto->request_tree);
+ purge_tree(&proto->response_tree);
+ if (proto->style != NULL)
+ free(proto->style);
+ free(proto);
+ }
+ env->sc_protocount = 0;
+ }
+ if (what & CONFIG_RTS && env->sc_rts != NULL) {
+ while ((rt = TAILQ_FIRST(env->sc_rts)) != NULL) {
+ TAILQ_REMOVE(env->sc_rts, rt, rt_entry);
+ while ((nr = TAILQ_FIRST(&rt->rt_netroutes)) != NULL) {
+ TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
+ TAILQ_REMOVE(env->sc_routes, nr, nr_route);
+ free(nr);
+ env->sc_routecount--;
+ }
+ free(rt);
+ }
+ env->sc_routercount = 0;
+ }
+ if (what & CONFIG_ROUTES && env->sc_routes != NULL) {
+ while ((nr = TAILQ_FIRST(env->sc_routes)) != NULL) {
+ if ((rt = nr->nr_router) != NULL)
+ TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
+ TAILQ_REMOVE(env->sc_routes, nr, nr_route);
+ free(nr);
+ }
+ env->sc_routecount = 0;
+ }
+}
+
+int
+config_setreset(struct relayd *env, u_int reset)
+{
+ struct privsep *ps = env->sc_ps;
+ int id;
+
+ for (id = 0; id < PROC_MAX; id++) {
+ if ((reset & ps->ps_what[id]) == 0 ||
+ id == privsep_process)
+ continue;
+ proc_compose_imsg(ps, id, -1, IMSG_CTL_RESET, -1,
+ &reset, sizeof(reset));
+ }
+
+ return (0);
+}
+
+int
+config_getreset(struct relayd *env, struct imsg *imsg)
+{
+ u_int mode;
+
+ IMSG_SIZE_CHECK(imsg, &mode);
+ memcpy(&mode, imsg->data, sizeof(mode));
+
+ config_purge(env, mode);
+
+ return (0);
+}
+
+int
+config_getcfg(struct relayd *env, struct imsg *imsg)
+{
+ struct privsep *ps = env->sc_ps;
+ struct table *tb;
+ struct host *h, *ph;
+ struct ctl_flags cf;
+
+ if (IMSG_DATA_SIZE(imsg) != sizeof(cf))
+ return (0); /* ignore */
+
+ /* Update runtime flags */
+ memcpy(&cf, imsg->data, sizeof(cf));
+ env->sc_opts = cf.cf_opts;
+ env->sc_flags = cf.cf_flags;
+
+ if (ps->ps_what[privsep_process] & CONFIG_TABLES) {
+ /* Update the tables */
+ TAILQ_FOREACH(tb, env->sc_tables, entry) {
+ TAILQ_FOREACH(h, &tb->hosts, entry) {
+ if (h->conf.parentid && (ph = host_find(env,
+ h->conf.parentid)) != NULL) {
+ SLIST_INSERT_HEAD(&ph->children,
+ h, child);
+ }
+ }
+ }
+ }
+
+ if (env->sc_flags & (F_SSL|F_SSLCLIENT))
+ ssl_init(env);
+
+ if (privsep_process != PROC_PARENT)
+ proc_compose_imsg(env->sc_ps, PROC_PARENT, -1,
+ IMSG_CFG_DONE, -1, NULL, 0);
+
+ return (0);
+}
+
+int
+config_settable(struct relayd *env, struct table *tb)
+{
+ struct privsep *ps = env->sc_ps;
+ struct host *host;
+ int id, c;
+ struct iovec iov[2];
+
+ for (id = 0; id < PROC_MAX; id++) {
+ if ((ps->ps_what[id] & CONFIG_TABLES) == 0 ||
+ id == privsep_process)
+ continue;
+
+ /* XXX need to send table to pfe for control socket */
+ if (id == PROC_HCE && tb->conf.check == CHECK_NOCHECK)
+ continue;
+
+ DPRINTF("%s: sending table %s %d to %s", __func__,
+ tb->conf.name, tb->conf.id, env->sc_ps->ps_title[id]);
+
+ c = 0;
+ iov[c].iov_base = &tb->conf;
+ iov[c++].iov_len = sizeof(tb->conf);
+ if (tb->sendbuf != NULL) {
+ iov[c].iov_base = tb->sendbuf;
+ iov[c++].iov_len = strlen(tb->sendbuf);
+ }
+
+ proc_composev_imsg(ps, id, -1, IMSG_CFG_TABLE, -1, iov, c);
+
+ TAILQ_FOREACH(host, &tb->hosts, entry) {
+ proc_compose_imsg(ps, id, -1, IMSG_CFG_HOST, -1,
+ &host->conf, sizeof(host->conf));
+ }
+ }
+
+ return (0);
+}
+
+int
+config_gettable(struct relayd *env, struct imsg *imsg)
+{
+ struct table *tb;
+ size_t sb;
+ u_int8_t *p = imsg->data;
+ size_t s;
+
+ if ((tb = calloc(1, sizeof(*tb))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, &tb->conf);
+ memcpy(&tb->conf, p, sizeof(tb->conf));
+ s = sizeof(tb->conf);
+
+ sb = IMSG_DATA_SIZE(imsg) - s;
+ if (sb > 0)
+ tb->sendbuf = get_string(p + s, sb);
+
+ TAILQ_INIT(&tb->hosts);
+ TAILQ_INSERT_TAIL(env->sc_tables, tb, entry);
+
+ env->sc_tablecount++;
+
+ DPRINTF("%s: %s %d received table %d (%s)", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ tb->conf.id, tb->conf.name);
+
+ return (0);
+}
+
+int
+config_gethost(struct relayd *env, struct imsg *imsg)
+{
+ struct table *tb;
+ struct host *host;
+
+ if ((host = calloc(1, sizeof(*host))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, &host->conf);
+ memcpy(&host->conf, imsg->data, sizeof(host->conf));
+
+ if (host_find(env, host->conf.id) != NULL) {
+ log_debug("%s: host %d already exists",
+ __func__, host->conf.id);
+ free(host);
+ return (-1);
+ }
+
+ if ((tb = table_find(env, host->conf.tableid)) == NULL) {
+ log_debug("%s: "
+ "received host for unknown table %d", __func__,
+ host->conf.tableid);
+ free(host);
+ return (-1);
+ }
+
+ host->tablename = tb->conf.name;
+ host->cte.s = -1;
+
+ SLIST_INIT(&host->children);
+ TAILQ_INSERT_TAIL(&tb->hosts, host, entry);
+
+ DPRINTF("%s: %s %d received host %s for table %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ host->conf.name, tb->conf.name);
+
+ return (0);
+}
+
+int
+config_setrdr(struct relayd *env, struct rdr *rdr)
+{
+ struct privsep *ps = env->sc_ps;
+ struct address *virt;
+ int id;
+
+ for (id = 0; id < PROC_MAX; id++) {
+ if ((ps->ps_what[id] & CONFIG_RDRS) == 0 ||
+ id == privsep_process)
+ continue;
+
+ DPRINTF("%s: sending rdr %s to %s", __func__,
+ rdr->conf.name, ps->ps_title[id]);
+
+ proc_compose_imsg(ps, id, -1, IMSG_CFG_RDR, -1,
+ &rdr->conf, sizeof(rdr->conf));
+
+ TAILQ_FOREACH(virt, &rdr->virts, entry) {
+ virt->rdrid = rdr->conf.id;
+ proc_compose_imsg(ps, id, -1, IMSG_CFG_VIRT, -1,
+ virt, sizeof(*virt));
+ }
+ }
+
+ return (0);
+}
+
+int
+config_getrdr(struct relayd *env, struct imsg *imsg)
+{
+ struct rdr *rdr;
+
+ if ((rdr = calloc(1, sizeof(*rdr))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, &rdr->conf);
+ memcpy(&rdr->conf, imsg->data, sizeof(rdr->conf));
+
+ if ((rdr->table = table_find(env, rdr->conf.table_id)) == NULL) {
+ log_debug("%s: table not found", __func__);
+ free(rdr);
+ return (-1);
+ }
+ if ((rdr->backup = table_find(env, rdr->conf.backup_id)) == NULL) {
+ rdr->conf.backup_id = EMPTY_TABLE;
+ rdr->backup = &env->sc_empty_table;
+ }
+
+ TAILQ_INIT(&rdr->virts);
+ TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry);
+
+ env->sc_rdrcount++;
+
+ DPRINTF("%s: %s %d received rdr %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ rdr->conf.name);
+
+ return (0);
+}
+
+int
+config_getvirt(struct relayd *env, struct imsg *imsg)
+{
+ struct rdr *rdr;
+ struct address *virt;
+
+ IMSG_SIZE_CHECK(imsg, virt);
+
+ if ((virt = calloc(1, sizeof(*virt))) == NULL)
+ return (-1);
+ memcpy(virt, imsg->data, sizeof(*virt));
+
+ if ((rdr = rdr_find(env, virt->rdrid)) == NULL) {
+ log_debug("%s: rdr not found", __func__);
+ free(virt);
+ return (-1);
+ }
+
+ TAILQ_INSERT_TAIL(&rdr->virts, virt, entry);
+
+ DPRINTF("%s: %s %d received address for rdr %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ rdr->conf.name);
+
+ return (0);
+}
+
+int
+config_setrt(struct relayd *env, struct router *rt)
+{
+ struct privsep *ps = env->sc_ps;
+ struct netroute *nr;
+ int id;
+
+ for (id = 0; id < PROC_MAX; id++) {
+ if ((ps->ps_what[id] & CONFIG_RTS) == 0 ||
+ id == privsep_process)
+ continue;
+
+ DPRINTF("%s: sending router %s to %s tbl %d", __func__,
+ rt->rt_conf.name, ps->ps_title[id], rt->rt_conf.gwtable);
+
+ proc_compose_imsg(ps, id, -1, IMSG_CFG_ROUTER, -1,
+ &rt->rt_conf, sizeof(rt->rt_conf));
+
+ TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) {
+ proc_compose_imsg(ps, id, -1, IMSG_CFG_ROUTE, -1,
+ &nr->nr_conf, sizeof(nr->nr_conf));
+ }
+ }
+
+ return (0);
+}
+
+int
+config_getrt(struct relayd *env, struct imsg *imsg)
+{
+ struct router *rt;
+
+ if ((rt = calloc(1, sizeof(*rt))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, &rt->rt_conf);
+ memcpy(&rt->rt_conf, imsg->data, sizeof(rt->rt_conf));
+
+ if ((rt->rt_gwtable = table_find(env, rt->rt_conf.gwtable)) == NULL) {
+ log_debug("%s: table not found", __func__);
+ free(rt);
+ return (-1);
+ }
+
+ TAILQ_INIT(&rt->rt_netroutes);
+ TAILQ_INSERT_TAIL(env->sc_rts, rt, rt_entry);
+
+ env->sc_routercount++;
+
+ DPRINTF("%s: %s %d received router %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ rt->rt_conf.name);
+
+ return (0);
+}
+
+int
+config_getroute(struct relayd *env, struct imsg *imsg)
+{
+ struct router *rt;
+ struct netroute *nr;
+
+ if ((nr = calloc(1, sizeof(*nr))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, &nr->nr_conf);
+ memcpy(&nr->nr_conf, imsg->data, sizeof(nr->nr_conf));
+
+ if (route_find(env, nr->nr_conf.id) != NULL) {
+ log_debug("%s: route %d already exists",
+ __func__, nr->nr_conf.id);
+ free(nr);
+ return (-1);
+ }
+
+ if ((rt = router_find(env, nr->nr_conf.routerid)) == NULL) {
+ log_debug("%s: received route for unknown router", __func__);
+ free(nr);
+ return (-1);
+ }
+
+ nr->nr_router = rt;
+
+ TAILQ_INSERT_TAIL(env->sc_routes, nr, nr_route);
+ TAILQ_INSERT_TAIL(&rt->rt_netroutes, nr, nr_entry);
+
+ env->sc_routecount++;
+
+ DPRINTF("%s: %s %d received route %d for router %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ nr->nr_conf.id, rt->rt_conf.name);
+
+ return (0);
+}
+
+int
+config_setproto(struct relayd *env, struct protocol *proto)
+{
+ struct privsep *ps = env->sc_ps;
+ int id;
+ struct iovec iov[2];
+ size_t c;
+
+ for (id = 0; id < PROC_MAX; id++) {
+ if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 ||
+ id == privsep_process)
+ continue;
+
+ DPRINTF("%s: sending protocol %s to %s", __func__,
+ proto->name, ps->ps_title[id]);
+
+ c = 0;
+ iov[c].iov_base = proto;
+ iov[c++].iov_len = sizeof(*proto);
+
+ if (proto->style != NULL) {
+ iov[c].iov_base = proto->style;
+ iov[c++].iov_len = strlen(proto->style);
+ }
+
+ /* XXX struct protocol should be split */
+ proc_composev_imsg(ps, id, -1, IMSG_CFG_PROTO, -1, iov, c);
+
+ /* Now send all the protocol key/value nodes */
+ if (config_setprotonode(env, id, proto,
+ RELAY_DIR_REQUEST) == -1 ||
+ config_setprotonode(env, id, proto,
+ RELAY_DIR_RESPONSE) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+config_getproto(struct relayd *env, struct imsg *imsg)
+{
+ struct protocol *proto;
+ size_t styl;
+
+ if ((proto = calloc(1, sizeof(*proto))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, proto);
+ memcpy(proto, imsg->data, sizeof(*proto));
+
+ styl = IMSG_DATA_SIZE(imsg) - sizeof(*proto);
+ if (styl > 0)
+ proto->style = get_string((char *)imsg->data +
+ sizeof(*proto), styl);
+
+ proto->request_nodes = 0;
+ proto->response_nodes = 0;
+ RB_INIT(&proto->request_tree);
+ RB_INIT(&proto->response_tree);
+
+ TAILQ_INSERT_TAIL(env->sc_protos, proto, entry);
+
+ env->sc_protocount++;
+
+ DPRINTF("%s: %s %d received protocol %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ proto->name);
+
+ return (0);
+}
+
+int
+config_setprotonode(struct relayd *env, enum privsep_procid id,
+ struct protocol *proto, enum direction dir)
+{
+ struct privsep *ps = env->sc_ps;
+ struct iovec iov[IOV_MAX];
+ size_t c, sz;
+ struct protonode *proot, *pn;
+ struct proto_tree *tree;
+
+ if (dir == RELAY_DIR_RESPONSE)
+ tree = &proto->response_tree;
+ else
+ tree = &proto->request_tree;
+
+ sz = c = 0;
+ RB_FOREACH(proot, proto_tree, tree) {
+ PROTONODE_FOREACH(pn, proot, entry) {
+ pn->conf.protoid = proto->id;
+ pn->conf.dir = dir;
+ pn->conf.keylen = pn->key ? strlen(pn->key) : 0;
+ pn->conf.valuelen = pn->value ? strlen(pn->value) : 0;
+ pn->conf.len = sizeof(*pn) +
+ pn->conf.keylen + pn->conf.valuelen;
+
+ if (pn->conf.len > (MAX_IMSGSIZE - IMSG_HEADER_SIZE))
+ return (-1);
+
+ if (c && ((c + 3) >= IOV_MAX || (sz + pn->conf.len) >
+ (MAX_IMSGSIZE - IMSG_HEADER_SIZE))) {
+ proc_composev_imsg(ps, id, -1,
+ IMSG_CFG_PROTONODE, -1, iov, c);
+ c = sz = 0;
+ }
+
+ iov[c].iov_base = pn;
+ iov[c++].iov_len = sizeof(*pn);
+ if (pn->conf.keylen) {
+ iov[c].iov_base = pn->key;
+ iov[c++].iov_len = pn->conf.keylen;
+ }
+ if (pn->conf.valuelen) {
+ iov[c].iov_base = pn->value;
+ iov[c++].iov_len = pn->conf.valuelen;
+ }
+ sz += pn->conf.len;
+ }
+ }
+
+ if (c && sz)
+ proc_composev_imsg(ps, id, -1, IMSG_CFG_PROTONODE, -1, iov, c);
+
+ return (0);
+}
+
+int
+config_getprotonode(struct relayd *env, struct imsg *imsg)
+{
+ struct protocol *proto = NULL;
+ struct protonode pn;
+ size_t z, s, c = 0;
+ u_int8_t *p = imsg->data;
+
+ bzero(&pn, sizeof(pn));
+
+ IMSG_SIZE_CHECK(imsg, &pn);
+ for (z = 0; z < (IMSG_DATA_SIZE(imsg) - sizeof(pn)); z += pn.conf.len) {
+ s = z;
+ memcpy(&pn, p + s, sizeof(pn));
+ s += sizeof(pn);
+
+ if ((proto = proto_find(env, pn.conf.protoid)) == NULL) {
+ log_debug("%s: unknown protocol %d", __func__,
+ pn.conf.protoid);
+ return (-1);
+ }
+
+ pn.key = pn.value = NULL;
+ bzero(&pn.entry, sizeof(pn.entry));
+ bzero(&pn.nodes, sizeof(pn.nodes));
+ bzero(&pn.head, sizeof(pn.head));
+
+ if (pn.conf.keylen) {
+ pn.key = get_string(p + s, pn.conf.keylen);
+ s += pn.conf.keylen;
+ }
+ if (pn.conf.valuelen) {
+ pn.value = get_string(p + s, pn.conf.valuelen);
+ s += pn.conf.valuelen;
+ }
+
+ if (protonode_add(pn.conf.dir, proto, &pn) == -1) {
+ log_debug("%s: failed to add protocol node", __func__);
+ return (-1);
+ }
+ c++;
+ }
+
+ if (!c)
+ return (0);
+
+ DPRINTF("%s: %s %d received %d nodes for protocol %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ c, proto->name);
+
+ return (0);
+}
+
+int
+config_setrelay(struct relayd *env, struct relay *rlay)
+{
+ struct privsep *ps = env->sc_ps;
+ int id;
+ int fd, n, m;
+ struct iovec iov[4];
+ size_t c;
+
+ /* opens listening sockets etc. */
+ if (relay_privinit(rlay) == -1)
+ return (-1);
+
+ for (id = 0; id < PROC_MAX; id++) {
+ if ((ps->ps_what[id] & CONFIG_RELAYS) == 0 ||
+ id == privsep_process)
+ continue;
+
+ DPRINTF("%s: sending relay %s to %s fd %d", __func__,
+ rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s);
+
+ c = 0;
+ iov[c].iov_base = &rlay->rl_conf;
+ iov[c++].iov_len = sizeof(rlay->rl_conf);
+ if (rlay->rl_conf.ssl_cert_len) {
+ iov[c].iov_base = rlay->rl_ssl_cert;
+ iov[c++].iov_len = rlay->rl_conf.ssl_cert_len;
+ }
+ if (rlay->rl_conf.ssl_key_len) {
+ iov[c].iov_base = rlay->rl_ssl_key;
+ iov[c++].iov_len = rlay->rl_conf.ssl_key_len;
+ }
+ if (rlay->rl_conf.ssl_ca_len) {
+ iov[c].iov_base = rlay->rl_ssl_ca;
+ iov[c++].iov_len = rlay->rl_conf.ssl_ca_len;
+ }
+
+ if (id == PROC_RELAY) {
+ /* XXX imsg code will close the fd after 1st call */
+ n = -1;
+ proc_range(ps, id, &n, &m);
+ for (n = 0; n < m; n++) {
+ if ((fd = dup(rlay->rl_s)) == -1)
+ return (-1);
+ proc_composev_imsg(ps, id, n,
+ IMSG_CFG_RELAY, fd, iov, c);
+ }
+ } else {
+ proc_composev_imsg(ps, id, -1, IMSG_CFG_RELAY, -1,
+ iov, c);
+ }
+ }
+
+ close(rlay->rl_s);
+ rlay->rl_s = -1;
+
+ return (0);
+}
+
+int
+config_getrelay(struct relayd *env, struct imsg *imsg)
+{
+ struct privsep *ps = env->sc_ps;
+ struct relay *rlay;
+ u_int8_t *p = imsg->data;
+ size_t s;
+
+ if ((rlay = calloc(1, sizeof(*rlay))) == NULL)
+ return (-1);
+
+ IMSG_SIZE_CHECK(imsg, &rlay->rl_conf);
+ memcpy(&rlay->rl_conf, p, sizeof(rlay->rl_conf));
+ s = sizeof(rlay->rl_conf);
+
+ rlay->rl_s = imsg->fd;
+
+ if (ps->ps_what[privsep_process] & CONFIG_PROTOS) {
+ if (rlay->rl_conf.proto == EMPTY_ID)
+ rlay->rl_proto = &env->sc_proto_default;
+ else if ((rlay->rl_proto =
+ proto_find(env, rlay->rl_conf.proto)) == NULL) {
+ log_debug("%s: unknown protocol", __func__);
+ goto fail;
+ }
+ }
+
+ if (rlay->rl_conf.dsttable != EMPTY_ID &&
+ (rlay->rl_dsttable = table_find(env,
+ rlay->rl_conf.dsttable)) == NULL) {
+ log_debug("%s: unknown table", __func__);
+ goto fail;
+ }
+
+ rlay->rl_backuptable = &env->sc_empty_table;
+ if (rlay->rl_conf.backuptable != EMPTY_ID &&
+ (rlay->rl_backuptable = table_find(env,
+ rlay->rl_conf.backuptable)) == NULL) {
+ log_debug("%s: unknown backup table", __func__);
+ goto fail;
+ }
+
+ if ((u_int)(IMSG_DATA_SIZE(imsg) - s) <
+ (rlay->rl_conf.ssl_cert_len +
+ rlay->rl_conf.ssl_key_len +
+ rlay->rl_conf.ssl_ca_len)) {
+ log_debug("%s: invalid message length", __func__);
+ goto fail;
+ }
+
+ if (rlay->rl_conf.ssl_cert_len) {
+ if ((rlay->rl_ssl_cert = get_data(p + s,
+ rlay->rl_conf.ssl_cert_len)) == NULL)
+ goto fail;
+ s += rlay->rl_conf.ssl_cert_len;
+ }
+ if (rlay->rl_conf.ssl_key_len) {
+ if ((rlay->rl_ssl_key = get_data(p + s,
+ rlay->rl_conf.ssl_key_len)) == NULL)
+ goto fail;
+ s += rlay->rl_conf.ssl_key_len;
+ }
+ if (rlay->rl_conf.ssl_ca_len) {
+ if ((rlay->rl_ssl_ca = get_data(p + s,
+ rlay->rl_conf.ssl_ca_len)) == NULL)
+ goto fail;
+ s += rlay->rl_conf.ssl_ca_len;
+ }
+
+ TAILQ_INSERT_TAIL(env->sc_relays, rlay, rl_entry);
+
+ env->sc_relaycount++;
+
+ DPRINTF("%s: %s %d received relay %s", __func__,
+ ps->ps_title[privsep_process], ps->ps_instance,
+ rlay->rl_conf.name);
+
+ return (0);
+
+ fail:
+ if (rlay->rl_ssl_cert)
+ free(rlay->rl_ssl_cert);
+ if (rlay->rl_ssl_key)
+ free(rlay->rl_ssl_key);
+ if (rlay->rl_ssl_ca)
+ free(rlay->rl_ssl_ca);
+ close(rlay->rl_s);
+ free(rlay);
+ return (-1);
+}
diff --git a/usr.sbin/relayd/control.c b/usr.sbin/relayd/control.c
index 9c9a3cc02e4..7397c34cc01 100644
--- a/usr.sbin/relayd/control.c
+++ b/usr.sbin/relayd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.38 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: control.c,v 1.39 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -327,8 +327,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
}
break;
case IMSG_CTL_SHUTDOWN:
- imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
- 0, 0, -1, NULL, 0);
+ case IMSG_CTL_RELOAD:
+ proc_forward_imsg(env->sc_ps, &imsg, PROC_PARENT, -1);
break;
case IMSG_CTL_POLL:
proc_compose_imsg(env->sc_ps, PROC_HCE, -1,
@@ -336,25 +336,6 @@ control_dispatch_imsg(int fd, short event, void *arg)
imsg_compose_event(&c->iev, IMSG_CTL_OK,
0, 0, -1, NULL, 0);
break;
- case IMSG_CTL_RELOAD:
- if (env->sc_prefork_relay > 0) {
- imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
- 0, 0, -1, NULL, 0);
- break;
- }
- proc_compose_imsg(env->sc_ps, PROC_PARENT, -1, IMSG_CTL_RELOAD,
- -1, NULL, 0);
- /*
- * we unconditionnaly return a CTL_OK imsg because
- * we have no choice.
- *
- * so in this case, the reply relayctl gets means
- * that the reload command has been set,
- * it doesn't say whether the command succeeded or not.
- */
- imsg_compose_event(&c->iev, IMSG_CTL_OK,
- 0, 0, -1, NULL, 0);
- break;
case IMSG_CTL_NOTIFY:
if (c->flags & CTL_CONN_NOTIFY) {
log_debug("%s: "
@@ -371,8 +352,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
memcpy(&verbose, imsg.data, sizeof(verbose));
- proc_forward_imsg(env->sc_ps, &imsg, PROC_PARENT, 0);
- proc_forward_imsg(env->sc_ps, &imsg, PROC_HCE, 0);
+ proc_forward_imsg(env->sc_ps, &imsg, PROC_PARENT, -1);
+ proc_forward_imsg(env->sc_ps, &imsg, PROC_HCE, -1);
proc_forward_imsg(env->sc_ps, &imsg, PROC_RELAY, -1);
memcpy(imsg.data, &verbose, sizeof(verbose));
diff --git a/usr.sbin/relayd/hce.c b/usr.sbin/relayd/hce.c
index ab80166c4bb..147b272bfde 100644
--- a/usr.sbin/relayd/hce.c
+++ b/usr.sbin/relayd/hce.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hce.c,v 1.59 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: hce.c,v 1.60 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -72,14 +72,15 @@ hce(struct privsep *ps, struct privsep_proc *p)
void
hce_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
- purge_config(env, PURGE_RDRS|PURGE_RELAYS|PURGE_PROTOS);
+ if (config_init(ps->ps_env) == -1)
+ fatal("failed to initialize configuration");
env->sc_id = getpid() & 0xffff;
/* Allow maximum available sockets for TCP checks */
socket_rlimit(-1);
- hce_setup_events();
+ snmp_init(env, PROC_PARENT);
}
void
@@ -88,18 +89,17 @@ hce_setup_events(void)
struct timeval tv;
struct table *table;
- snmp_init(env, PROC_PARENT);
-
- if (!TAILQ_EMPTY(env->sc_tables)) {
+ if (!(TAILQ_EMPTY(env->sc_tables) ||
+ event_initialized(&env->sc_ev))) {
evtimer_set(&env->sc_ev, hce_launch_checks, env);
bzero(&tv, sizeof(tv));
evtimer_add(&env->sc_ev, &tv);
}
if (env->sc_flags & F_SSL) {
- ssl_init(env);
TAILQ_FOREACH(table, env->sc_tables, entry) {
- if (!(table->conf.flags & F_SSL))
+ if (!(table->conf.flags & F_SSL) ||
+ table->ssl_ctx != NULL)
continue;
table->ssl_ctx = ssl_ctx_create(env);
}
@@ -116,8 +116,10 @@ hce_disable_events(void)
TAILQ_FOREACH(table, env->sc_tables, entry) {
TAILQ_FOREACH(host, &table->hosts, entry) {
host->he = HCE_ABORT;
- event_del(&host->cte.ev);
- close(host->cte.s);
+ if (event_initialized(&host->cte.ev)) {
+ event_del(&host->cte.ev);
+ close(host->cte.s);
+ }
}
}
if (env->sc_has_icmp) {
@@ -146,7 +148,11 @@ hce_launch_checks(int fd, short event, void *arg)
if ((host->flags & F_CHECK_DONE) == 0)
host->he = HCE_INTERVAL_TIMEOUT;
host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
- event_del(&host->cte.ev);
+ if (event_initialized(&host->cte.ev)) {
+ event_del(&host->cte.ev);
+ close(host->cte.s);
+ }
+ host->cte.s = -1;
}
}
@@ -331,9 +337,6 @@ int
hce_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
struct ctl_script scr;
- size_t len;
- static struct table *table = NULL;
- struct host *host, *parent;
switch (imsg->hdr.type) {
case IMSG_SCRIPT:
@@ -341,47 +344,22 @@ hce_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
bcopy(imsg->data, &scr, sizeof(scr));
script_done(env, &scr);
break;
- case IMSG_RECONF:
- IMSG_SIZE_CHECK(imsg, env);
- log_debug("%s: reloading configuration", __func__);
- hce_disable_events();
- purge_config(env, PURGE_TABLES);
- merge_config(env, (struct relayd *)imsg->data);
-
- env->sc_tables = calloc(1, sizeof(*env->sc_tables));
- if (env->sc_tables == NULL)
- fatal(NULL);
-
- TAILQ_INIT(env->sc_tables);
- break;
- case IMSG_RECONF_TABLE:
- if ((table = calloc(1, sizeof(*table))) == NULL)
- fatal(NULL);
- memcpy(&table->conf, imsg->data, sizeof(table->conf));
- TAILQ_INIT(&table->hosts);
- TAILQ_INSERT_TAIL(env->sc_tables, table, entry);
+ case IMSG_CFG_TABLE:
+ config_gettable(env, imsg);
break;
- case IMSG_RECONF_SENDBUF:
- len = imsg->hdr.len - IMSG_HEADER_SIZE;
- table->sendbuf = calloc(1, len);
- (void)strlcpy(table->sendbuf, (char *)imsg->data, len);
+ case IMSG_CFG_HOST:
+ config_gethost(env, imsg);
break;
- case IMSG_RECONF_HOST:
- if ((host = calloc(1, sizeof(*host))) == NULL)
- fatal(NULL);
- memcpy(&host->conf, imsg->data, sizeof(host->conf));
- host->tablename = table->conf.name;
- TAILQ_INSERT_TAIL(&table->hosts, host, entry);
- if (host->conf.parentid) {
- parent = host_find(env, host->conf.parentid);
- SLIST_INSERT_HEAD(&parent->children,
- host, child);
- }
+ case IMSG_SNMPSOCK:
+ snmp_getsock(env, imsg);
break;
- case IMSG_RECONF_END:
- log_warnx("%s: configuration reloaded", __func__);
+ case IMSG_CFG_DONE:
+ config_getcfg(env, imsg);
hce_setup_events();
break;
+ case IMSG_CTL_RESET:
+ config_getreset(env, imsg);
+ break;
default:
return (-1);
}
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index c03b54c4264..c3a5b5b5177 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.155 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.156 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -28,6 +28,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/queue.h>
+#include <sys/hash.h>
#include <net/if.h>
#include <net/pfvar.h>
@@ -86,6 +87,7 @@ char *symget(const char *);
struct relayd *conf = NULL;
static int errors = 0;
+static int loadcfg = 0;
objid_t last_rdr_id = 0;
objid_t last_table_id = 0;
objid_t last_host_id = 0;
@@ -114,6 +116,7 @@ int host_if(const char *, struct addresslist *,
int, struct portrange *, const char *, int);
int host(const char *, struct addresslist *,
int, struct portrange *, const char *, int);
+void host_free(struct addresslist *);
struct table *table_inherit(struct table *);
struct relay *relay_inherit(struct relay *, struct relay *);
@@ -323,28 +326,36 @@ varset : STRING '=' STRING {
sendbuf : NOTHING {
table->sendbuf = NULL;
- table->sendbuf_len = 0;
}
| STRING {
table->sendbuf = strdup($1);
if (table->sendbuf == NULL)
fatal("out of memory");
- table->sendbuf_len = strlen(table->sendbuf);
free($1);
}
;
main : INTERVAL NUMBER {
+ if (loadcfg)
+ break;
if ((conf->sc_interval.tv_sec = $2) < 0) {
yyerror("invalid interval: %d", $2);
YYERROR;
}
}
- | LOG loglevel { conf->sc_opts |= $2; }
+ | LOG loglevel {
+ if (loadcfg)
+ break;
+ conf->sc_opts |= $2;
+ }
| TIMEOUT timeout {
+ if (loadcfg)
+ break;
bcopy(&$2, &conf->sc_timeout, sizeof(struct timeval));
}
| PREFORK NUMBER {
+ if (loadcfg)
+ break;
if ($2 <= 0 || $2 > RELAY_MAXPROC) {
yyerror("invalid number of preforked "
"relays: %d", $2);
@@ -353,6 +364,8 @@ main : INTERVAL NUMBER {
conf->sc_prefork_relay = $2;
}
| DEMOTE STRING {
+ if (loadcfg)
+ break;
conf->sc_flags |= F_DEMOTE;
if (strlcpy(conf->sc_demote_group, $2,
sizeof(conf->sc_demote_group))
@@ -368,7 +381,11 @@ main : INTERVAL NUMBER {
YYERROR;
}
}
- | SEND TRAP { conf->sc_flags |= F_TRAP; }
+ | SEND TRAP {
+ if (loadcfg)
+ break;
+ conf->sc_flags |= F_TRAP;
+ }
;
loglevel : UPDATES { $$ = RELAYD_OPT_LOGUPDATE; }
@@ -379,6 +396,12 @@ rdr : REDIRECT STRING {
struct rdr *srv;
conf->sc_flags |= F_NEEDPF;
+
+ if (!loadcfg) {
+ free($2);
+ YYACCEPT;
+ }
+
TAILQ_FOREACH(srv, conf->sc_rdrs, entry)
if (!strcmp(srv->conf.name, $2))
break;
@@ -544,6 +567,11 @@ table : '<' STRING '>' {
tabledef : TABLE table {
struct table *tb;
+ if (!loadcfg) {
+ free($2);
+ YYACCEPT;
+ }
+
TAILQ_FOREACH(tb, conf->sc_tables, entry)
if (!strcmp(tb->conf.name, $2))
break;
@@ -701,7 +729,6 @@ tablecheck : ICMP { table->conf.check = CHECK_ICMP; }
free($3);
if (table->sendbuf == NULL)
fatal("out of memory");
- table->sendbuf_len = strlen(table->sendbuf);
}
| http_type STRING hostname digest {
if ($1) {
@@ -717,7 +744,6 @@ tablecheck : ICMP { table->conf.check = CHECK_ICMP; }
free($3);
if (table->sendbuf == NULL)
fatal("out of memory");
- table->sendbuf_len = strlen(table->sendbuf);
(void)strlcpy(table->conf.digest, $4.digest,
sizeof(table->conf.digest));
table->conf.digest_type = $4.type;
@@ -773,6 +799,11 @@ digest : DIGEST STRING
proto : relay_proto PROTO STRING {
struct protocol *p;
+ if (!loadcfg) {
+ free($3);
+ YYACCEPT;
+ }
+
if (strcmp($3, "default") == 0) {
p = &conf->sc_proto_default;
} else {
@@ -936,12 +967,14 @@ sslflags : SESSION CACHE sslcache { proto->cache = $3; }
free($2);
}
| CA FILENAME STRING {
- if (proto->sslca != NULL) {
- yyerror("sslca already specified");
+ if (strlcpy(proto->sslca, $3,
+ sizeof(proto->sslca)) >=
+ sizeof(proto->sslca)) {
+ yyerror("sslca truncated");
free($3);
YYERROR;
}
- proto->sslca = $3;
+ free($3);
}
| NO flag { proto->sslflags &= ~($2); }
| flag { proto->sslflags |= $1; }
@@ -1182,6 +1215,11 @@ sslcache : NUMBER {
relay : RELAY STRING {
struct relay *r;
+ if (!loadcfg) {
+ free($2);
+ YYACCEPT;
+ }
+
TAILQ_FOREACH(r, conf->sc_relays, rl_entry)
if (!strcmp(r->rl_conf.name, $2))
break;
@@ -1302,6 +1340,7 @@ relayoptsl : LISTEN ON STRING port optssl {
conf->sc_flags |= F_SSL;
}
tableport = h->port.val[0];
+ host_free(&al);
}
| forwardmode optsslclient TO forwardspec interface dstaf {
rlay->rl_conf.fwdmode = $1;
@@ -1384,6 +1423,7 @@ forwardspec : STRING port retry {
sizeof(rlay->rl_conf.dstss));
rlay->rl_conf.dstport = h->port.val[0];
rlay->rl_conf.dstretry = $3;
+ host_free(&al);
}
| NAT LOOKUP retry {
conf->sc_flags |= F_NEEDPF;
@@ -1398,7 +1438,6 @@ forwardspec : STRING port retry {
| tablespec {
if (rlay->rl_backuptable) {
yyerror("only one backup table is allowed");
- purge_table(conf->sc_tables, $1);
YYERROR;
}
if (rlay->rl_dsttable) {
@@ -1423,6 +1462,11 @@ dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; }
router : ROUTER STRING {
struct router *rt = NULL;
+ if (!loadcfg) {
+ free($2);
+ YYACCEPT;
+ }
+
conf->sc_flags |= F_NEEDRT;
TAILQ_FOREACH(rt, conf->sc_rts, rt_entry)
if (!strcmp(rt->rt_conf.name, $2))
@@ -1478,16 +1522,18 @@ routeopts_l : routeopts_l routeoptsl nl
routeoptsl : ROUTE address '/' NUMBER {
struct netroute *nr;
- if (router->rt_af == AF_UNSPEC)
- router->rt_af = $2.ss.ss_family;
- else if (router->rt_af != $2.ss.ss_family) {
+ if (router->rt_conf.af == AF_UNSPEC)
+ router->rt_conf.af = $2.ss.ss_family;
+ else if (router->rt_conf.af != $2.ss.ss_family) {
yyerror("router %s address family mismatch",
router->rt_conf.name);
YYERROR;
}
- if ((router->rt_af == AF_INET && ($4 > 32 || $4 < 0)) ||
- (router->rt_af == AF_INET6 && ($4 > 128 || $4 < 0))) {
+ if ((router->rt_conf.af == AF_INET &&
+ ($4 > 32 || $4 < 0)) ||
+ (router->rt_conf.af == AF_INET6 &&
+ ($4 > 128 || $4 < 0))) {
yyerror("invalid prefixlen %d", $4);
YYERROR;
}
@@ -1649,7 +1695,7 @@ hostflags : RETRY NUMBER {
;
address : STRING {
- struct address *a;
+ struct address *h;
struct addresslist al;
if (strlcpy($$.name, $1,
@@ -1666,9 +1712,9 @@ address : STRING {
YYERROR;
}
free($1);
- a = TAILQ_FIRST(&al);
- memcpy(&$$.ss, &a->ss, sizeof($$.ss));
- free(a);
+ h = TAILQ_FIRST(&al);
+ memcpy(&$$.ss, &h->ss, sizeof($$.ss));
+ host_free(&al);
}
;
@@ -2143,38 +2189,56 @@ popfile(void)
return (file ? 0 : EOF);
}
-struct relayd *
-parse_config(const char *filename, int opts)
+int
+parse_config(const char *filename, struct relayd *x_conf)
{
struct sym *sym, *next;
- struct table *nexttb;
- struct host *h, *ph;
- if ((conf = calloc(1, sizeof(*conf))) == NULL ||
- (conf->sc_tables = calloc(1, sizeof(*conf->sc_tables))) == NULL ||
- (conf->sc_relays = calloc(1, sizeof(*conf->sc_relays))) == NULL ||
- (conf->sc_protos = calloc(1, sizeof(*conf->sc_protos))) == NULL ||
- (conf->sc_routes = calloc(1, sizeof(*conf->sc_routes))) == NULL ||
- (conf->sc_rts = calloc(1, sizeof(*conf->sc_rts))) == NULL ||
- (conf->sc_rdrs = calloc(1, sizeof(*conf->sc_rdrs))) == NULL) {
- if (conf != NULL) {
- if (conf->sc_tables != NULL)
- free(conf->sc_tables);
- if (conf->sc_relays != NULL)
- free(conf->sc_relays);
- if (conf->sc_protos != NULL)
- free(conf->sc_protos);
- if (conf->sc_rdrs != NULL)
- free(conf->sc_rdrs);
- if (conf->sc_rts != NULL)
- free(conf->sc_rts);
- free(conf);
- }
- log_warn("%s: cannot allocate memory", __func__);
- return (NULL);
+ conf = x_conf;
+ if (config_init(conf) == -1) {
+ log_warn("%s: cannot initialize configuration", __func__);
+ return (-1);
}
errors = 0;
+
+ if ((file = pushfile(filename, 0)) == NULL)
+ return (-1);
+
+ topfile = file;
+ setservent(1);
+
+ yyparse();
+ errors = file->errors;
+ popfile();
+
+ endservent();
+ endprotoent();
+
+ /* Free macros */
+ for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
+ next = TAILQ_NEXT(sym, entry);
+ if (!sym->persist) {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+
+ return (errors ? -1 : 0);
+}
+
+int
+load_config(const char *filename, struct relayd *x_conf)
+{
+ struct sym *sym, *next;
+ struct table *nexttb;
+ struct host *h, *ph;
+
+ conf = x_conf;
+ loadcfg = 1;
+ errors = 0;
last_host_id = last_table_id = last_rdr_id = last_proto_id =
last_relay_id = last_rt_id = last_nr_id = 0;
@@ -2184,46 +2248,9 @@ parse_config(const char *filename, int opts)
proto = NULL;
router = NULL;
- TAILQ_INIT(conf->sc_rdrs);
- TAILQ_INIT(conf->sc_tables);
- TAILQ_INIT(conf->sc_protos);
- TAILQ_INIT(conf->sc_relays);
- TAILQ_INIT(conf->sc_rts);
- TAILQ_INIT(conf->sc_routes);
-
- memset(&conf->sc_empty_table, 0, sizeof(conf->sc_empty_table));
- conf->sc_empty_table.conf.id = EMPTY_TABLE;
- conf->sc_empty_table.conf.flags |= F_DISABLE;
- (void)strlcpy(conf->sc_empty_table.conf.name, "empty",
- sizeof(conf->sc_empty_table.conf.name));
-
- bzero(&conf->sc_proto_default, sizeof(conf->sc_proto_default));
- conf->sc_proto_default.flags = F_USED;
- conf->sc_proto_default.cache = RELAY_CACHESIZE;
- conf->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
- conf->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
- conf->sc_proto_default.sslflags = SSLFLAG_DEFAULT;
- (void)strlcpy(conf->sc_proto_default.sslciphers, SSLCIPHERS_DEFAULT,
- sizeof(conf->sc_proto_default.sslciphers));
- conf->sc_proto_default.type = RELAY_PROTO_TCP;
- (void)strlcpy(conf->sc_proto_default.name, "default",
- sizeof(conf->sc_proto_default.name));
- RB_INIT(&conf->sc_proto_default.request_tree);
- RB_INIT(&conf->sc_proto_default.response_tree);
-
- conf->sc_timeout.tv_sec = CHECK_TIMEOUT / 1000;
- conf->sc_timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000;
- conf->sc_interval.tv_sec = CHECK_INTERVAL;
- conf->sc_interval.tv_usec = 0;
- conf->sc_prefork_relay = RELAY_NUMPROC;
- conf->sc_statinterval.tv_sec = RELAY_STATINTERVAL;
- conf->sc_opts = opts;
- conf->sc_confpath = filename;
-
- if ((file = pushfile(filename, 0)) == NULL) {
- free(conf);
- return (NULL);
- }
+ if ((file = pushfile(filename, 0)) == NULL)
+ return (-1);
+
topfile = file;
setservent(1);
@@ -2322,12 +2349,7 @@ parse_config(const char *filename, int opts)
}
}
- if (errors) {
- free(conf);
- return (NULL);
- }
-
- return (conf);
+ return (errors ? -1 : 0);
}
int
@@ -2494,6 +2516,7 @@ host_dns(const char *s, struct addresslist *al, int max,
log_warnx("%s: interface name truncated",
__func__);
freeaddrinfo(res0);
+ free(h);
return (-1);
}
if (ipproto != -1)
@@ -2615,6 +2638,7 @@ host(const char *s, struct addresslist *al, int max,
sizeof(h->ifname)) {
log_warnx("%s: interface name truncated",
__func__);
+ free(h);
return (-1);
}
}
@@ -2628,6 +2652,17 @@ host(const char *s, struct addresslist *al, int max,
return (host_dns(s, al, max, port, ifname, ipproto));
}
+void
+host_free(struct addresslist *al)
+{
+ struct address *h;
+
+ while ((h = TAILQ_FIRST(al)) != NULL) {
+ TAILQ_REMOVE(al, h, entry);
+ free(h);
+ }
+}
+
struct table *
table_inherit(struct table *tb)
{
@@ -2638,23 +2673,21 @@ table_inherit(struct table *tb)
/* Get the table or table template */
if ((dsttb = table_findbyname(conf, tb->conf.name)) == NULL) {
yyerror("unknown table %s", tb->conf.name);
- purge_table(NULL, tb);
- return (NULL);
+ goto fail;
}
if (dsttb->conf.port != 0)
fatal("invalid table"); /* should not happen */
if (tb->conf.port == 0) {
yyerror("invalid port");
- purge_table(NULL, tb);
- return (NULL);
+ goto fail;
}
/* Check if a matching table already exists */
if (snprintf(pname, sizeof(pname), "%s:%u",
tb->conf.name, ntohs(tb->conf.port)) >= (int)sizeof(pname)) {
yyerror("invalid table name");
- return (NULL);
+ goto fail;
}
(void)strlcpy(tb->conf.name, pname, sizeof(tb->conf.name));
if ((oldtb = table_findbyconf(conf, tb)) != NULL) {
@@ -2666,8 +2699,7 @@ table_inherit(struct table *tb)
tb->conf.id = ++last_table_id;
if (last_table_id == INT_MAX) {
yyerror("too many tables defined");
- purge_table(NULL, tb);
- return (NULL);
+ goto fail;
}
tb->conf.flags |= dsttb->conf.flags;
@@ -2684,8 +2716,7 @@ table_inherit(struct table *tb)
h->conf.id = ++last_host_id;
if (last_host_id == INT_MAX) {
yyerror("too many hosts defined");
- purge_table(NULL, tb);
- return (NULL);
+ goto fail;
}
h->conf.tableid = tb->conf.id;
h->tablename = tb->conf.name;
@@ -2697,6 +2728,10 @@ table_inherit(struct table *tb)
TAILQ_INSERT_TAIL(conf->sc_tables, tb, entry);
return (tb);
+
+ fail:
+ purge_table(NULL, tb);
+ return (NULL);
}
struct relay *
diff --git a/usr.sbin/relayd/pfe.c b/usr.sbin/relayd/pfe.c
index ba3a6260390..4ed78c9f88d 100644
--- a/usr.sbin/relayd/pfe.c
+++ b/usr.sbin/relayd/pfe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfe.c,v 1.68 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: pfe.c,v 1.69 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -46,7 +46,7 @@ int pfe_dispatch_parent(int, struct privsep_proc *, struct imsg *);
int pfe_dispatch_hce(int, struct privsep_proc *, struct imsg *);
int pfe_dispatch_relay(int, struct privsep_proc *, struct imsg *);
-static struct relayd *env = NULL;
+static struct relayd *env = NULL;
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, pfe_dispatch_parent },
@@ -59,25 +59,23 @@ pfe(struct privsep *ps, struct privsep_proc *p)
{
env = ps->ps_env;
- init_filter(env);
- init_tables(env);
-
return (proc_run(ps, p, procs, nitems(procs), pfe_init, NULL));
}
void
pfe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
+ if (config_init(ps->ps_env) == -1)
+ fatal("failed to initialize configuration");
+
p->p_shutdown = pfe_shutdown;
- purge_config(env, PURGE_PROTOS);
- pfe_setup_events();
- pfe_sync();
}
void
pfe_shutdown(void)
{
flush_rulesets(env);
+ config_purge(env, CONFIG_ALL);
}
void
@@ -86,9 +84,11 @@ pfe_setup_events(void)
struct timeval tv;
/* Schedule statistics timer */
- evtimer_set(&env->sc_statev, pfe_statistics, NULL);
- bcopy(&env->sc_statinterval, &tv, sizeof(tv));
- evtimer_add(&env->sc_statev, &tv);
+ if (!event_initialized(&env->sc_statev)) {
+ evtimer_set(&env->sc_statev, pfe_statistics, NULL);
+ bcopy(&env->sc_statinterval, &tv, sizeof(tv));
+ evtimer_add(&env->sc_statev, &tv);
+ }
}
void
@@ -172,88 +172,43 @@ pfe_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
int
pfe_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
- static struct rdr *rdr = NULL;
- static struct table *table = NULL;
- struct host *host, *parent;
- struct address *virt;
-
switch (imsg->hdr.type) {
- case IMSG_RECONF:
- IMSG_SIZE_CHECK(imsg, env);
-
- log_debug("%s: reloading configuration", __func__);
-
- pfe_disable_events();
- purge_config(env, PURGE_RDRS|PURGE_TABLES);
- merge_config(env, (struct relayd *)imsg->data);
-
- /*
- * no relays when reconfiguring yet.
- */
- env->sc_relays = NULL;
- env->sc_protos = NULL;
-
- env->sc_tables = calloc(1, sizeof(*env->sc_tables));
- env->sc_rdrs = calloc(1, sizeof(*env->sc_rdrs));
- if (env->sc_tables == NULL || env->sc_rdrs == NULL)
- fatal(NULL);
-
- TAILQ_INIT(env->sc_tables);
- TAILQ_INIT(env->sc_rdrs);
+ case IMSG_CFG_TABLE:
+ config_gettable(env, imsg);
break;
- case IMSG_RECONF_TABLE:
- if ((table = calloc(1, sizeof(*table))) == NULL)
- fatal(NULL);
- memcpy(&table->conf, imsg->data, sizeof(table->conf));
- TAILQ_INIT(&table->hosts);
- TAILQ_INSERT_TAIL(env->sc_tables, table, entry);
+ case IMSG_CFG_HOST:
+ config_gethost(env, imsg);
break;
- case IMSG_RECONF_HOST:
- if ((host = calloc(1, sizeof(*host))) == NULL)
- fatal(NULL);
- memcpy(&host->conf, imsg->data, sizeof(host->conf));
- host->tablename = table->conf.name;
- TAILQ_INSERT_TAIL(&table->hosts, host, entry);
- if (host->conf.parentid) {
- parent = host_find(env, host->conf.parentid);
- SLIST_INSERT_HEAD(&parent->children,
- host, child);
- }
+ case IMSG_CFG_RDR:
+ config_getrdr(env, imsg);
break;
- case IMSG_RECONF_RDR:
- if ((rdr = calloc(1, sizeof(*rdr))) == NULL)
- fatal(NULL);
- memcpy(&rdr->conf, imsg->data,
- sizeof(rdr->conf));
- rdr->table = table_find(env,
- rdr->conf.table_id);
- if (rdr->conf.backup_id == EMPTY_TABLE)
- rdr->backup = &env->sc_empty_table;
- else
- rdr->backup = table_find(env,
- rdr->conf.backup_id);
- if (rdr->table == NULL || rdr->backup == NULL)
- fatal("pfe_dispatch_parent:"
- " corrupted configuration");
- log_debug("%s: redirect table %s, backup %s",
- __func__,
- rdr->table->conf.name,
- rdr->backup->conf.name);
- TAILQ_INIT(&rdr->virts);
- TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry);
+ case IMSG_CFG_VIRT:
+ config_getvirt(env, imsg);
+ break;
+ case IMSG_CFG_ROUTER:
+ config_getrt(env, imsg);
break;
- case IMSG_RECONF_VIRT:
- if ((virt = calloc(1, sizeof(*virt))) == NULL)
- fatal(NULL);
- memcpy(virt, imsg->data, sizeof(*virt));
- TAILQ_INSERT_TAIL(&rdr->virts, virt, entry);
+ case IMSG_CFG_ROUTE:
+ config_getroute(env, imsg);
break;
- case IMSG_RECONF_END:
- log_warnx("%s: configuration reloaded", __func__);
+ case IMSG_CFG_PROTO:
+ config_getproto(env, imsg);
+ break;
+ case IMSG_CFG_PROTONODE:
+ break;
+ case IMSG_CFG_RELAY:
+ config_getrelay(env, imsg);
+ break;
+ case IMSG_CFG_DONE:
+ config_getcfg(env, imsg);
+ init_filter(env, imsg->fd);
init_tables(env);
pfe_setup_events();
pfe_sync();
break;
+ case IMSG_CTL_RESET:
+ config_getreset(env, imsg);
+ break;
default:
return (-1);
}
@@ -741,6 +696,9 @@ pfe_sync(void)
}
TAILQ_FOREACH(table, env->sc_tables, entry) {
+ if (table->conf.check == CHECK_NOCHECK)
+ continue;
+
/*
* clean up change flag.
*/
diff --git a/usr.sbin/relayd/pfe_filter.c b/usr.sbin/relayd/pfe_filter.c
index 2fa53cdd3b8..02a528999b5 100644
--- a/usr.sbin/relayd/pfe_filter.c
+++ b/usr.sbin/relayd/pfe_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfe_filter.c,v 1.46 2011/05/05 12:01:44 reyk Exp $ */
+/* $OpenBSD: pfe_filter.c,v 1.47 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -33,6 +33,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
#include <openssl/ssl.h>
@@ -53,17 +54,21 @@ void kill_tables(struct relayd *);
int kill_srcnodes(struct relayd *, struct table *);
void
-init_filter(struct relayd *env)
+init_filter(struct relayd *env, int s)
{
struct pf_status status;
if (!(env->sc_flags & F_NEEDPF))
return;
- if ((env->sc_pf = calloc(1, sizeof(*(env->sc_pf)))) == NULL)
- fatal("calloc");
- if ((env->sc_pf->dev = open(PF_SOCKET, O_RDWR)) == -1)
- fatal("init_filter: cannot open pf socket");
+ if (s == -1)
+ fatalx("init_filter: invalid socket");
+ if (env->sc_pf == NULL) {
+ if ((env->sc_pf = calloc(1, sizeof(*(env->sc_pf)))) == NULL)
+ fatal("calloc");
+ } else
+ close(env->sc_pf->dev);
+ env->sc_pf->dev = s;
if (ioctl(env->sc_pf->dev, DIOCGETSTATUS, &status) == -1)
fatal("init_filter: DIOCGETSTATUS");
if (!status.running)
@@ -366,7 +371,7 @@ sync_ruleset(struct relayd *env, struct rdr *rdr, int enable)
char anchor[PF_ANCHOR_NAME_SIZE];
struct table *t = rdr->table;
- if (!(env->sc_flags & F_NEEDPF))
+ if ((env->sc_flags & F_NEEDPF) == 0)
return;
bzero(anchor, sizeof(anchor));
diff --git a/usr.sbin/relayd/pfe_route.c b/usr.sbin/relayd/pfe_route.c
index 0fae0dfd0a0..e0b5066eb40 100644
--- a/usr.sbin/relayd/pfe_route.c
+++ b/usr.sbin/relayd/pfe_route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfe_route.c,v 1.4 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: pfe_route.c,v 1.5 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2009 Reyk Floeter <reyk@openbsd.org>
@@ -96,9 +96,10 @@ sync_routes(struct relayd *env, struct router *rt)
HOST_ISUP(host->up) ? "up" : "down",
host->conf.priority);
- crt.id = nr->nr_conf.id;
- crt.hostid = host->conf.id;
crt.up = host->up;
+ memcpy(&crt.nr, &nr->nr_conf, sizeof(nr->nr_conf));
+ memcpy(&crt.host, &host->conf, sizeof(host->conf));
+ memcpy(&crt.rt, &rt->rt_conf, sizeof(rt->rt_conf));
proc_compose_imsg(env->sc_ps, PROC_PARENT, -1,
IMSG_RTMSG, -1, &crt, sizeof(crt));
@@ -115,19 +116,11 @@ pfe_route(struct relayd *env, struct ctl_netroute *crt)
struct sockaddr_in *s4;
struct sockaddr_in6 *s6;
size_t len = 0;
- struct netroute *nr;
- struct host *host;
char *gwname;
int i = 0;
- if ((nr = route_find(env, crt->id)) == NULL ||
- (host = host_find(env, crt->hostid)) == NULL) {
- log_debug("%s: invalid host or route id", __func__);
- return (-1);
- }
-
- gw = &host->conf.ss;
- gwname = host->conf.name;
+ gw = &crt->host.ss;
+ gwname = crt->host.name;
bzero(&rm, sizeof(rm));
bzero(&sr, sizeof(sr));
@@ -138,18 +131,18 @@ pfe_route(struct relayd *env, struct ctl_netroute *crt)
rm.rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH;
rm.rm_hdr.rtm_seq = env->sc_rtseq++;
rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
- rm.rm_hdr.rtm_tableid = nr->nr_router->rt_conf.rtable;
- rm.rm_hdr.rtm_priority = host->conf.priority;
+ rm.rm_hdr.rtm_tableid = crt->rt.rtable;
+ rm.rm_hdr.rtm_priority = crt->host.priority;
- if (strlen(nr->nr_router->rt_conf.label)) {
+ if (strlen(crt->rt.label)) {
rm.rm_hdr.rtm_addrs |= RTA_LABEL;
sr.sr_len = sizeof(sr);
if (snprintf(sr.sr_label, sizeof(sr.sr_label),
- "%s", nr->nr_router->rt_conf.label) == -1)
+ "%s", crt->rt.label) == -1)
goto bad;
}
- if (nr->nr_conf.ss.ss_family == AF_INET) {
+ if (crt->nr.ss.ss_family == AF_INET) {
rm.rm_hdr.rtm_msglen = len =
sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u4);
@@ -159,7 +152,7 @@ pfe_route(struct relayd *env, struct ctl_netroute *crt)
s4->sin_family = AF_INET;
s4->sin_len = sizeof(rm.rm_u.u4.rm_dst);
s4->sin_addr.s_addr =
- ((struct sockaddr_in *)&nr->nr_conf.ss)->sin_addr.s_addr;
+ ((struct sockaddr_in *)&crt->nr.ss)->sin_addr.s_addr;
s4 = &rm.rm_u.u4.rm_gateway;
s4->sin_family = AF_INET;
@@ -171,19 +164,19 @@ pfe_route(struct relayd *env, struct ctl_netroute *crt)
s4 = &rm.rm_u.u4.rm_netmask;
s4->sin_family = AF_INET;
s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask);
- if (nr->nr_conf.prefixlen)
+ if (crt->nr.prefixlen)
s4->sin_addr.s_addr =
- htonl(0xffffffff << (32 - nr->nr_conf.prefixlen));
- else if (nr->nr_conf.prefixlen < 0)
+ htonl(0xffffffff << (32 - crt->nr.prefixlen));
+ else if (crt->nr.prefixlen < 0)
rm.rm_hdr.rtm_flags |= RTF_HOST;
- } else if (nr->nr_conf.ss.ss_family == AF_INET6) {
+ } else if (crt->nr.ss.ss_family == AF_INET6) {
rm.rm_hdr.rtm_msglen = len =
sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6);
bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr));
s6 = &rm.rm_u.u6.rm_dst;
- bcopy(((struct sockaddr_in6 *)&nr->nr_conf.ss),
+ bcopy(((struct sockaddr_in6 *)&crt->nr.ss),
s6, sizeof(*s6));
s6->sin6_family = AF_INET6;
s6->sin6_len = sizeof(*s6);
@@ -197,14 +190,14 @@ pfe_route(struct relayd *env, struct ctl_netroute *crt)
s6 = &rm.rm_u.u6.rm_netmask;
s6->sin6_family = AF_INET6;
s6->sin6_len = sizeof(*s6);
- if (nr->nr_conf.prefixlen) {
- for (i = 0; i < nr->nr_conf.prefixlen / 8; i++)
+ if (crt->nr.prefixlen) {
+ for (i = 0; i < crt->nr.prefixlen / 8; i++)
s6->sin6_addr.s6_addr[i] = 0xff;
- i = nr->nr_conf.prefixlen % 8;
+ i = crt->nr.prefixlen % 8;
if (i)
- s6->sin6_addr.s6_addr[nr->nr_conf.prefixlen
+ s6->sin6_addr.s6_addr[crt->nr.prefixlen
/ 8] = 0xff00 >> i;
- } else if (nr->nr_conf.prefixlen < 0)
+ } else if (crt->nr.prefixlen < 0)
rm.rm_hdr.rtm_flags |= RTF_HOST;
} else
fatal("pfe_route: invalid address family");
diff --git a/usr.sbin/relayd/proc.c b/usr.sbin/relayd/proc.c
index 2bfb76a85be..7a0ddf0512f 100644
--- a/usr.sbin/relayd/proc.c
+++ b/usr.sbin/relayd/proc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.c,v 1.1 2011/05/09 12:09:58 reyk Exp $ */
+/* $OpenBSD: proc.c,v 1.2 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2010,2011 Reyk Floeter <reyk@openbsd.org>
@@ -105,6 +105,8 @@ proc_kill(struct privsep *ps)
do {
pid = waitpid(WAIT_ANY, NULL, 0);
} while (pid != -1 || (pid == -1 && errno == EINTR));
+
+ proc_clear(ps, 1);
}
void
@@ -134,6 +136,8 @@ proc_setup(struct privsep *ps)
fatal(NULL);
for (n = 0; n < count; n++) {
+ if (ps->ps_noaction)
+ continue;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
sockpair) == -1)
fatal("socketpair");
@@ -175,7 +179,8 @@ proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc)
ps->ps_instance == instance)
continue;
- close(ps->ps_pipes[i][j][n]);
+ if (!ps->ps_noaction)
+ close(ps->ps_pipes[i][j][n]);
ps->ps_pipes[i][j][n] = -1;
}
}
@@ -221,6 +226,35 @@ proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc)
}
void
+proc_clear(struct privsep *ps, int purge)
+{
+ u_int src = privsep_process, dst, n, count;
+
+ if (ps == NULL)
+ return;
+
+ for (dst = 0; dst < PROC_MAX; dst++) {
+ if (src == dst || ps->ps_ievs[dst] == NULL)
+ continue;
+
+ count = ps->ps_instances[src] * ps->ps_instances[dst];
+
+ for (n = 0; n < count; n++) {
+ if (ps->ps_pipes[src][dst][n] == -1)
+ continue;
+ if (purge) {
+ event_del(&(ps->ps_ievs[dst][n].ev));
+ imsg_clear(&(ps->ps_ievs[dst][n].ibuf));
+ close(ps->ps_pipes[src][dst][n]);
+ } else
+ imsg_flush(&(ps->ps_ievs[dst][n].ibuf));
+ }
+ if (purge)
+ free(ps->ps_ievs[dst]);
+ }
+}
+
+void
proc_shutdown(struct privsep_proc *p)
{
struct privsep *ps = p->p_ps;
@@ -231,6 +265,8 @@ proc_shutdown(struct privsep_proc *p)
if (p->p_shutdown != NULL)
(*p->p_shutdown)();
+ proc_clear(ps, 1);
+
log_info("%s exiting, pid %d", p->p_title, getpid());
_exit(0);
@@ -268,6 +304,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p,
u_int32_t seed[256];
u_int n;
+ if (ps->ps_noaction)
+ return (0);
+
switch (pid = fork()) {
case -1:
fatal("run_proc: cannot fork");
@@ -403,7 +442,7 @@ proc_dispatch(int fd, short event, void *arg)
if (n == 0)
break;
-#ifdef DEBUG
+#if DEBUG > 1
log_debug("%s: %s %d got imsg %d from %s %d",
__func__, title, ps->ps_instance + 1,
imsg.hdr.type, p->p_title, p->p_instance);
@@ -522,6 +561,7 @@ proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
if (imsg_compose_event(&ps->ps_ievs[id][n],
type, -1, 0, fd, data, datalen) == -1)
return (-1);
+
return (0);
}
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index d458a4de7a6..00d50e93a79 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.136 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.137 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -54,7 +54,6 @@ int relay_dispatch_pfe(int, struct privsep_proc *,
struct imsg *);
void relay_shutdown(void);
-void relay_privinit(void);
void relay_nodedebug(const char *, struct protonode *);
void relay_protodebug(struct relay *);
void relay_init(struct privsep *, struct privsep_proc *p, void *);
@@ -146,26 +145,13 @@ pid_t
relay(struct privsep *ps, struct privsep_proc *p)
{
env = ps->ps_env;
-
- /* Need root privileges for relay initialization */
- relay_privinit();
-
return (proc_run(ps, p, procs, nitems(procs), relay_init, NULL));
}
void
relay_shutdown(void)
{
- struct rsession *con;
-
- struct relay *rlay;
- TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
- if (rlay->rl_conf.flags & F_DISABLE)
- continue;
- close(rlay->rl_s);
- while ((con = SPLAY_ROOT(&rlay->rl_sessions)) != NULL)
- relay_close(con, "shutdown");
- }
+ config_purge(env, CONFIG_ALL);
usleep(200); /* XXX relay needs to shutdown last */
}
@@ -250,7 +236,8 @@ relay_protodebug(struct relay *rlay)
const char *name;
int i;
- fprintf(stderr, "protocol %d: name %s\n", proto->id, proto->name);
+ fprintf(stderr, "protocol %d: name %s\n",
+ proto->id, proto->name);
fprintf(stderr, "\tflags: %s, relay flags: %s\n",
printb_flags(proto->flags, F_BITS),
printb_flags(rlay->rl_conf.flags, F_BITS));
@@ -304,106 +291,56 @@ relay_protodebug(struct relay *rlay)
}
}
-void
-relay_privinit(void)
+int
+relay_privinit(struct relay *rlay)
{
- struct relay *rlay;
extern int debug;
- if (env->sc_flags & (F_SSL|F_SSLCLIENT))
- ssl_init(env);
+ log_debug("%s: adding relay %s", __func__, rlay->rl_conf.name);
- TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
- log_debug("%s: adding relay %s", __func__, rlay->rl_conf.name);
+ if (debug)
+ relay_protodebug(rlay);
- if (debug)
- relay_protodebug(rlay);
+ switch (rlay->rl_proto->type) {
+ case RELAY_PROTO_DNS:
+ relay_udp_privinit(env, rlay);
+ break;
+ case RELAY_PROTO_TCP:
+ case RELAY_PROTO_HTTP:
+ /* Use defaults */
+ break;
+ }
- switch (rlay->rl_proto->type) {
- case RELAY_PROTO_DNS:
- relay_udp_privinit(env, rlay);
- break;
- case RELAY_PROTO_TCP:
- case RELAY_PROTO_HTTP:
- /* Use defaults */
- break;
- }
+ if (rlay->rl_conf.flags & F_UDP)
+ rlay->rl_s = relay_udp_bind(&rlay->rl_conf.ss,
+ rlay->rl_conf.port, rlay->rl_proto);
+ else
+ rlay->rl_s = relay_socket_listen(&rlay->rl_conf.ss,
+ rlay->rl_conf.port, rlay->rl_proto);
+ if (rlay->rl_s == -1)
+ return (-1);
- if (rlay->rl_conf.flags & F_UDP)
- rlay->rl_s = relay_udp_bind(&rlay->rl_conf.ss,
- rlay->rl_conf.port, rlay->rl_proto);
- else
- rlay->rl_s = relay_socket_listen(&rlay->rl_conf.ss,
- rlay->rl_conf.port, rlay->rl_proto);
- if (rlay->rl_s == -1)
- fatal("relay_privinit: failed to listen");
- }
+ return (0);
}
void
relay_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
- struct relay *rlay;
- struct host *host;
struct timeval tv;
+ if (config_init(ps->ps_env) == -1)
+ fatal("failed to initialize configuration");
+
/* We use a custom shutdown callback */
p->p_shutdown = relay_shutdown;
- purge_config(env, PURGE_RDRS);
-
/* Unlimited file descriptors (use system limits) */
socket_rlimit(-1);
- TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
- if ((rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)) &&
- (rlay->rl_ssl_ctx = relay_ssl_ctx_create(rlay)) == NULL)
- fatal("relay_init: failed to create SSL context");
-
- if (rlay->rl_dsttable != NULL) {
- switch (rlay->rl_conf.dstmode) {
- case RELAY_DSTMODE_ROUNDROBIN:
- rlay->rl_dstkey = 0;
- break;
- case RELAY_DSTMODE_LOADBALANCE:
- case RELAY_DSTMODE_HASH:
- rlay->rl_dstkey =
- hash32_str(rlay->rl_conf.name, HASHINIT);
- rlay->rl_dstkey =
- hash32_str(rlay->rl_dsttable->conf.name,
- rlay->rl_dstkey);
- break;
- }
- rlay->rl_dstnhosts = 0;
- TAILQ_FOREACH(host, &rlay->rl_dsttable->hosts, entry) {
- if (rlay->rl_dstnhosts >= RELAY_MAXHOSTS)
- fatal("relay_init: "
- "too many hosts in table");
- host->idx = rlay->rl_dstnhosts;
- rlay->rl_dsthost[rlay->rl_dstnhosts++] = host;
- }
- log_info("adding %d hosts from table %s%s",
- rlay->rl_dstnhosts, rlay->rl_dsttable->conf.name,
- rlay->rl_dsttable->conf.check ? "" : " (no check)");
- }
-
- switch (rlay->rl_proto->type) {
- case RELAY_PROTO_DNS:
- relay_udp_init(rlay);
- break;
- case RELAY_PROTO_TCP:
- case RELAY_PROTO_HTTP:
- /* Use defaults */
- break;
- }
- }
-
/* Schedule statistics timer */
evtimer_set(&env->sc_statev, relay_statistics, NULL);
bcopy(&env->sc_statinterval, &tv, sizeof(tv));
evtimer_add(&env->sc_statev, &tv);
-
- relay_launch();
}
void
@@ -474,10 +411,52 @@ relay_statistics(int fd, short events, void *arg)
void
relay_launch(void)
{
- struct relay *rlay;
void (*callback)(int, short, void *);
+ struct relay *rlay;
+ struct host *host;
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
+ if ((rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)) &&
+ (rlay->rl_ssl_ctx = relay_ssl_ctx_create(rlay)) == NULL)
+ fatal("relay_init: failed to create SSL context");
+
+ if (rlay->rl_dsttable != NULL) {
+ switch (rlay->rl_conf.dstmode) {
+ case RELAY_DSTMODE_ROUNDROBIN:
+ rlay->rl_dstkey = 0;
+ break;
+ case RELAY_DSTMODE_LOADBALANCE:
+ case RELAY_DSTMODE_HASH:
+ rlay->rl_dstkey =
+ hash32_str(rlay->rl_conf.name, HASHINIT);
+ rlay->rl_dstkey =
+ hash32_str(rlay->rl_dsttable->conf.name,
+ rlay->rl_dstkey);
+ break;
+ }
+ rlay->rl_dstnhosts = 0;
+ TAILQ_FOREACH(host, &rlay->rl_dsttable->hosts, entry) {
+ if (rlay->rl_dstnhosts >= RELAY_MAXHOSTS)
+ fatal("relay_init: "
+ "too many hosts in table");
+ host->idx = rlay->rl_dstnhosts;
+ rlay->rl_dsthost[rlay->rl_dstnhosts++] = host;
+ }
+ log_info("adding %d hosts from table %s%s",
+ rlay->rl_dstnhosts, rlay->rl_dsttable->conf.name,
+ rlay->rl_dsttable->conf.check ? "" : " (no check)");
+ }
+
+ switch (rlay->rl_proto->type) {
+ case RELAY_PROTO_DNS:
+ relay_udp_init(rlay);
+ break;
+ case RELAY_PROTO_TCP:
+ case RELAY_PROTO_HTTP:
+ /* Use defaults */
+ break;
+ }
+
log_debug("%s: running relay %s", __func__,
rlay->rl_conf.name);
@@ -2320,7 +2299,7 @@ relay_close(struct rsession *con, const char *msg)
if (con->se_out.bev != NULL)
bufferevent_disable(con->se_out.bev, EV_READ|EV_WRITE);
- if (env->sc_opts & RELAYD_OPT_LOGUPDATE) {
+ if ((env->sc_opts & RELAYD_OPT_LOGUPDATE) && msg != NULL) {
bzero(&ibuf, sizeof(ibuf));
bzero(&obuf, sizeof(obuf));
(void)print_host(&con->se_in.ss, ibuf, sizeof(ibuf));
@@ -2531,6 +2510,27 @@ relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
bzero(&tv, sizeof(tv));
evtimer_add(&con->se_ev, &tv);
break;
+ case IMSG_CFG_TABLE:
+ config_gettable(env, imsg);
+ break;
+ case IMSG_CFG_HOST:
+ config_gethost(env, imsg);
+ break;
+ case IMSG_CFG_PROTO:
+ config_getproto(env, imsg);
+ break;
+ case IMSG_CFG_PROTONODE:
+ return (config_getprotonode(env, imsg));
+ case IMSG_CFG_RELAY:
+ config_getrelay(env, imsg);
+ break;
+ case IMSG_CFG_DONE:
+ config_getcfg(env, imsg);
+ relay_launch();
+ break;
+ case IMSG_CTL_RESET:
+ config_getreset(env, imsg);
+ break;
default:
return (-1);
}
@@ -2578,7 +2578,7 @@ relay_ssl_ctx_create(struct relay *rlay)
if ((rlay->rl_conf.flags & F_SSLCLIENT) &&
(rlay->rl_ssl_ca != NULL)) {
if (!ssl_ctx_load_verify_memory(ctx,
- rlay->rl_ssl_ca, rlay->rl_ssl_ca_len))
+ rlay->rl_ssl_ca, rlay->rl_conf.ssl_ca_len))
goto err;
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
}
@@ -2588,12 +2588,12 @@ relay_ssl_ctx_create(struct relay *rlay)
log_debug("%s: loading certificate", __func__);
if (!ssl_ctx_use_certificate_chain(ctx,
- rlay->rl_ssl_cert, rlay->rl_ssl_cert_len))
+ rlay->rl_ssl_cert, rlay->rl_conf.ssl_cert_len))
goto err;
log_debug("%s: loading private key", __func__);
if (!ssl_ctx_use_private_key(ctx, rlay->rl_ssl_key,
- rlay->rl_ssl_key_len))
+ rlay->rl_conf.ssl_key_len))
goto err;
if (!SSL_CTX_check_private_key(ctx))
goto err;
@@ -3070,7 +3070,7 @@ relay_load_file(const char *name, off_t *len)
close(fd);
- *len = size + 1;
+ *len = size;
return (buf);
fail:
@@ -3087,9 +3087,9 @@ relay_load_certfiles(struct relay *rlay)
char certfile[PATH_MAX];
char hbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
- if ((rlay->rl_conf.flags & F_SSLCLIENT) && (proto->sslca != NULL)) {
+ if ((rlay->rl_conf.flags & F_SSLCLIENT) && strlen(proto->sslca)) {
if ((rlay->rl_ssl_ca = relay_load_file(proto->sslca,
- &rlay->rl_ssl_ca_len)) == NULL)
+ &rlay->rl_conf.ssl_ca_len)) == NULL)
return (-1);
log_debug("%s: using ca %s", __func__, proto->sslca);
}
@@ -3104,7 +3104,7 @@ relay_load_certfiles(struct relay *rlay)
"/etc/ssl/%s.crt", hbuf) == -1)
return (-1);
if ((rlay->rl_ssl_cert = relay_load_file(certfile,
- &rlay->rl_ssl_cert_len)) == NULL)
+ &rlay->rl_conf.ssl_cert_len)) == NULL)
return (-1);
log_debug("%s: using certificate %s", __func__, certfile);
@@ -3112,7 +3112,7 @@ relay_load_certfiles(struct relay *rlay)
"/etc/ssl/private/%s.key", hbuf) == -1)
return -1;
if ((rlay->rl_ssl_key = relay_load_file(certfile,
- &rlay->rl_ssl_key_len)) == NULL)
+ &rlay->rl_conf.ssl_key_len)) == NULL)
return (-1);
log_debug("%s: using private key %s", __func__, certfile);
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index f3a70f57f49..8bc215646f5 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.102 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.103 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/resource.h>
+#include <sys/hash.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -30,6 +31,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <fcntl.h>
#include <getopt.h>
#include <err.h>
#include <errno.h>
@@ -46,16 +48,16 @@
__dead void usage(void);
+int parent_configure(struct relayd *);
+void parent_reload(struct relayd *, u_int, const char *);
void parent_sig_handler(int, short, void *);
void parent_shutdown(struct relayd *);
int parent_dispatch_pfe(int, struct privsep_proc *, struct imsg *);
int parent_dispatch_hce(int, struct privsep_proc *, struct imsg *);
int parent_dispatch_relay(int, struct privsep_proc *, struct imsg *);
-void reconfigure(void);
-void purge_tree(struct proto_tree *);
int bindany(struct ctl_bindany *);
-struct relayd *relayd_env;
+struct relayd *relayd_env;
static struct privsep_proc procs[] = {
{ "pfe", PROC_PFE, parent_dispatch_pfe, pfe },
@@ -112,7 +114,13 @@ parent_sig_handler(int sig, short event, void *arg)
parent_shutdown(ps->ps_env);
break;
case SIGHUP:
- reconfigure();
+ log_info("%s: reload requested with SIGHUP", __func__);
+
+ /*
+ * This is safe because libevent uses async signal handlers
+ * that run in the event loop and not in signal context.
+ */
+ parent_reload(ps->ps_env, CONFIG_RELOAD, NULL);
break;
case SIGPIPE:
/* ignore */
@@ -137,15 +145,11 @@ int
main(int argc, char *argv[])
{
int c;
- int debug;
- u_int32_t opts;
+ int debug = 0, verbose = 0;
+ u_int32_t opts = 0;
struct relayd *env;
struct privsep *ps;
- const char *conffile;
-
- opts = 0;
- debug = 0;
- conffile = CONF_FILE;
+ const char *conffile = CONF_FILE;
while ((c = getopt(argc, argv, "dD:nf:v")) != -1) {
switch (c) {
@@ -165,6 +169,7 @@ main(int argc, char *argv[])
conffile = optarg;
break;
case 'v':
+ verbose++;
opts |= RELAYD_OPT_VERBOSE;
break;
default:
@@ -179,18 +184,19 @@ main(int argc, char *argv[])
if (argc > 0)
usage();
- if ((env = parse_config(conffile, opts)) == NULL ||
+ if ((env = calloc(1, sizeof(*env))) == NULL ||
(ps = calloc(1, sizeof(*ps))) == NULL)
exit(1);
relayd_env = env;
env->sc_ps = ps;
ps->ps_env = env;
+ env->sc_conffile = conffile;
+ env->sc_opts = opts;
+
+ if (parse_config(env->sc_conffile, env) == -1)
+ exit(1);
- if (env->sc_opts & RELAYD_OPT_NOACTION) {
- fprintf(stderr, "configuration OK\n");
- exit(0);
- }
if (debug)
env->sc_opts |= RELAYD_OPT_LOGUPDATE;
@@ -203,13 +209,16 @@ main(int argc, char *argv[])
/* Configure the control socket */
ps->ps_csock.cs_name = RELAYD_SOCKET;
- if (!debug) {
- log_init(debug);
- if (daemon(1, 0) == -1)
- err(1, "failed to daemonize");
- }
+ log_init(debug);
+ log_verbose(verbose);
- log_info("startup");
+ if (!debug && daemon(1, 0) == -1)
+ err(1, "failed to daemonize");
+
+ if (env->sc_opts & RELAYD_OPT_NOACTION)
+ ps->ps_noaction = 1;
+ else
+ log_info("startup");
ps->ps_instances[PROC_RELAY] = env->sc_prefork_relay;
proc_init(ps, procs, nitems(procs));
@@ -231,241 +240,135 @@ main(int argc, char *argv[])
signal_add(&ps->ps_evsigpipe, NULL);
proc_config(ps, procs, nitems(procs));
+
+ if (load_config(env->sc_conffile, env) == -1) {
+ proc_kill(env->sc_ps);
+ exit(1);
+ }
+
+ if (env->sc_opts & RELAYD_OPT_NOACTION) {
+ fprintf(stderr, "configuration OK\n");
+ proc_kill(env->sc_ps);
+ exit(0);
+ }
+
+ if (env->sc_flags & (F_SSL|F_SSLCLIENT))
+ ssl_init(env);
+
+ if (parent_configure(env) == -1)
+ fatalx("configuration failed");
+
init_routes(env);
event_dispatch();
parent_shutdown(env);
/* NOTREACHED */
+
return (0);
}
-void
-parent_shutdown(struct relayd *env)
+int
+parent_configure(struct relayd *env)
{
- proc_kill(env->sc_ps);
- control_cleanup(&env->sc_ps->ps_csock);
- carp_demote_shutdown();
- if (env->sc_flags & F_DEMOTE)
- carp_demote_reset(env->sc_demote_group, 128);
+ struct table *tb;
+ struct rdr *rdr;
+ struct router *rt;
+ struct protocol *proto;
+ struct relay *rlay;
+ int id;
+ struct ctl_flags cf;
+ int s, ret = -1;
- free(env->sc_ps);
- free(env);
+ TAILQ_FOREACH(tb, env->sc_tables, entry)
+ config_settable(env, tb);
+ TAILQ_FOREACH(rdr, env->sc_rdrs, entry)
+ config_setrdr(env, rdr);
+ TAILQ_FOREACH(rt, env->sc_rts, rt_entry)
+ config_setrt(env, rt);
+ TAILQ_FOREACH(proto, env->sc_protos, entry)
+ config_setproto(env, proto);
+ TAILQ_FOREACH(rlay, env->sc_relays, rl_entry)
+ config_setrelay(env, rlay);
- log_info("parent terminating, pid %d", getpid());
+ for (id = 0; id < PROC_MAX; id++) {
+ if (id == privsep_process)
+ continue;
+ cf.cf_opts = env->sc_opts;
+ cf.cf_flags = env->sc_flags;
+
+ if ((env->sc_flags & F_NEEDPF) && id == PROC_PFE) {
+ /* Send pf socket to the pf engine */
+ if ((s = open(PF_SOCKET, O_RDWR)) == -1) {
+ log_debug("%s: cannot open pf socket",
+ __func__);
+ goto done;
+ }
+ } else
+ s = -1;
- exit(0);
-}
+ env->sc_reload++;
+ proc_compose_imsg(env->sc_ps, id, -1, IMSG_CFG_DONE, s,
+ &cf, sizeof(cf));
+ }
-void
-merge_config(struct relayd *env, struct relayd *new_env)
-{
- env->sc_opts = new_env->sc_opts;
- env->sc_flags = new_env->sc_flags;
- env->sc_confpath = new_env->sc_confpath;
- env->sc_tablecount = new_env->sc_tablecount;
- env->sc_rdrcount = new_env->sc_rdrcount;
- env->sc_protocount = new_env->sc_protocount;
- env->sc_relaycount = new_env->sc_relaycount;
-
- memcpy(&env->sc_interval, &new_env->sc_interval,
- sizeof(env->sc_interval));
- memcpy(&env->sc_timeout, &new_env->sc_timeout,
- sizeof(env->sc_timeout));
- memcpy(&env->sc_empty_table, &new_env->sc_empty_table,
- sizeof(env->sc_empty_table));
- memcpy(&env->sc_proto_default, &new_env->sc_proto_default,
- sizeof(env->sc_proto_default));
- env->sc_prefork_relay = new_env->sc_prefork_relay;
- (void)strlcpy(env->sc_demote_group, new_env->sc_demote_group,
- sizeof(env->sc_demote_group));
-
- env->sc_tables = new_env->sc_tables;
- env->sc_rdrs = new_env->sc_rdrs;
- env->sc_relays = new_env->sc_relays;
- env->sc_protos = new_env->sc_protos;
-}
+ ret = 0;
+ done:
+ config_purge(env, CONFIG_ALL);
+ return (ret);
+}
void
-reconfigure(void)
+parent_reload(struct relayd *env, u_int reset, const char *filename)
{
- struct relayd *env = relayd_env;
- struct relayd *new_env = NULL;
- struct privsep *ps = env->sc_ps;
- struct rdr *rdr;
- struct address *virt;
- struct table *table;
- struct host *host;
-
- log_info("reloading configuration");
- if ((new_env = parse_config(env->sc_confpath, env->sc_opts)) == NULL) {
- log_warnx("configuration reloading FAILED");
+ if (env->sc_reload) {
+ log_debug("%s: already in progress: %d pending",
+ __func__, env->sc_reload);
return;
}
- if (!(env->sc_flags & F_NEEDPF) && (new_env->sc_flags & F_NEEDPF)) {
- log_warnx("new configuration requires pf while it "
- "was previously disabled."
- "configuration will not be reloaded");
- purge_config(new_env, PURGE_EVERYTHING);
- free(new_env);
- return;
- }
-
- purge_config(env, PURGE_EVERYTHING);
- merge_config(env, new_env);
- free(new_env);
- log_info("configuration merge done");
-
- /*
- * first reconfigure pfe
- */
- proc_compose_imsg(ps, PROC_PFE, -1, IMSG_RECONF, -1, env, sizeof(*env));
- TAILQ_FOREACH(table, env->sc_tables, entry) {
- proc_compose_imsg(ps, PROC_PFE, -1, IMSG_RECONF_TABLE, -1,
- &table->conf, sizeof(table->conf));
- TAILQ_FOREACH(host, &table->hosts, entry) {
- proc_compose_imsg(ps, PROC_PFE, -1, IMSG_RECONF_HOST,
- -1, &host->conf, sizeof(host->conf));
- }
- }
- TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
- proc_compose_imsg(ps, PROC_PFE, -1, IMSG_RECONF_RDR, -1,
- &rdr->conf, sizeof(rdr->conf));
- TAILQ_FOREACH(virt, &rdr->virts, entry)
- proc_compose_imsg(ps, PROC_PFE, -1, IMSG_RECONF_VIRT,
- -1, virt, sizeof(*virt));
- }
- proc_compose_imsg(ps, PROC_PFE, -1, IMSG_RECONF_END, -1, NULL, 0);
-
- /*
- * then reconfigure hce
- */
- proc_compose_imsg(ps, PROC_HCE, -1, IMSG_RECONF, -1, env, sizeof(*env));
- TAILQ_FOREACH(table, env->sc_tables, entry) {
- proc_compose_imsg(ps, PROC_HCE, -1, IMSG_RECONF_TABLE, -1,
- &table->conf, sizeof(table->conf));
- if (table->sendbuf != NULL)
- proc_compose_imsg(ps, PROC_HCE, -1, IMSG_RECONF_SENDBUF,
- -1, table->sendbuf, strlen(table->sendbuf) + 1);
- TAILQ_FOREACH(host, &table->hosts, entry) {
- proc_compose_imsg(ps, PROC_HCE, -1, IMSG_RECONF_HOST,
- -1, &host->conf, sizeof(host->conf));
- }
- }
- proc_compose_imsg(ps, PROC_HCE, -1, IMSG_RECONF_END, -1, NULL, 0);
-}
+ /* Switch back to the default config file */
+ if (filename == NULL || *filename == '\0')
+ filename = env->sc_conffile;
-void
-purge_config(struct relayd *env, u_int8_t what)
-{
- struct table *table;
- struct rdr *rdr;
- struct address *virt;
- struct protocol *proto;
- struct relay *rlay;
- struct rsession *sess;
+ log_debug("%s: level %d config file %s", __func__, reset, filename);
- if (what & PURGE_TABLES && env->sc_tables != NULL) {
- while ((table = TAILQ_FIRST(env->sc_tables)) != NULL)
- purge_table(env->sc_tables, table);
- free(env->sc_tables);
- env->sc_tables = NULL;
- }
+ config_purge(env, CONFIG_ALL);
- if (what & PURGE_RDRS && env->sc_rdrs != NULL) {
- while ((rdr = TAILQ_FIRST(env->sc_rdrs)) != NULL) {
- TAILQ_REMOVE(env->sc_rdrs, rdr, entry);
- while ((virt = TAILQ_FIRST(&rdr->virts)) != NULL) {
- TAILQ_REMOVE(&rdr->virts, virt, entry);
- free(virt);
- }
- free(rdr);
+ if (reset == CONFIG_RELOAD) {
+ if (load_config(filename, env) == -1) {
+ log_debug("%s: failed to load config file %s",
+ __func__, filename);
}
- free(env->sc_rdrs);
- env->sc_rdrs = NULL;
- }
- if (what & PURGE_RELAYS && env->sc_relays != NULL) {
- while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL) {
- TAILQ_REMOVE(env->sc_relays, rlay, rl_entry);
- while ((sess =
- SPLAY_ROOT(&rlay->rl_sessions)) != NULL) {
- SPLAY_REMOVE(session_tree,
- &rlay->rl_sessions, sess);
- free(sess);
- }
- if (rlay->rl_bev != NULL)
- bufferevent_free(rlay->rl_bev);
- if (rlay->rl_dstbev != NULL)
- bufferevent_free(rlay->rl_dstbev);
- if (rlay->rl_ssl_ctx != NULL)
- SSL_CTX_free(rlay->rl_ssl_ctx);
- free(rlay);
- }
- free(env->sc_relays);
- env->sc_relays = NULL;
- }
+ config_setreset(env, CONFIG_ALL);
- if (what & PURGE_PROTOS && env->sc_protos != NULL) {
- while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
- TAILQ_REMOVE(env->sc_protos, proto, entry);
- purge_tree(&proto->request_tree);
- purge_tree(&proto->response_tree);
- if (proto->style != NULL)
- free(proto->style);
- free(proto);
+ if (parent_configure(env) == -1) {
+ log_debug("%s: failed to commit config from %s",
+ __func__, filename);
}
- free(env->sc_protos);
- env->sc_protos = NULL;
- }
+ } else
+ config_setreset(env, reset);
}
void
-purge_tree(struct proto_tree *tree)
+parent_shutdown(struct relayd *env)
{
- struct protonode *proot, *pn;
+ config_purge(env, CONFIG_ALL);
- while ((proot = RB_ROOT(tree)) != NULL) {
- RB_REMOVE(proto_tree, tree, proot);
- if (proot->key != NULL)
- free(proot->key);
- if (proot->value != NULL)
- free(proot->value);
- while ((pn = SIMPLEQ_FIRST(&proot->head)) != NULL) {
- SIMPLEQ_REMOVE_HEAD(&proot->head, entry);
- if (pn->key != NULL)
- free(pn->key);
- if (pn->value != NULL)
- free(pn->value);
- if (pn->label != 0)
- pn_unref(pn->label);
- free(pn);
- }
- free(proot);
- }
-}
+ proc_kill(env->sc_ps);
+ control_cleanup(&env->sc_ps->ps_csock);
+ carp_demote_shutdown();
+ if (env->sc_flags & F_DEMOTE)
+ carp_demote_reset(env->sc_demote_group, 128);
-void
-purge_table(struct tablelist *head, struct table *table)
-{
- struct host *host;
+ free(env->sc_ps);
+ free(env);
- while ((host = TAILQ_FIRST(&table->hosts)) != NULL) {
- TAILQ_REMOVE(&table->hosts, host, entry);
- if (host->cte.ssl != NULL)
- SSL_free(host->cte.ssl);
- free(host);
- }
- if (table->sendbuf != NULL)
- free(table->sendbuf);
- if (table->conf.flags & F_SSL)
- SSL_CTX_free(table->ssl_ctx);
+ log_info("parent terminating, pid %d", getpid());
- if (head != NULL)
- TAILQ_REMOVE(head, table, entry);
- free(table);
+ exit(0);
}
int
@@ -474,6 +377,8 @@ parent_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
struct relayd *env = p->p_env;
struct ctl_demote demote;
struct ctl_netroute crt;
+ u_int v;
+ char *str = NULL;
switch (imsg->hdr.type) {
case IMSG_DEMOTE:
@@ -486,11 +391,24 @@ parent_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
memcpy(&crt, imsg->data, sizeof(crt));
pfe_route(env, &crt);
break;
+ case IMSG_CTL_RESET:
+ IMSG_SIZE_CHECK(imsg, &v);
+ memcpy(&v, imsg->data, sizeof(v));
+ parent_reload(env, v, NULL);
+ break;
case IMSG_CTL_RELOAD:
- /*
- * so far we only get here if no L7 (relay) is done.
- */
- reconfigure();
+ if (IMSG_DATA_SIZE(imsg) > 0)
+ str = get_string(imsg->data, IMSG_DATA_SIZE(imsg));
+ parent_reload(env, CONFIG_RELOAD, str);
+ if (str != NULL)
+ free(str);
+ break;
+ case IMSG_CTL_SHUTDOWN:
+ parent_shutdown(env);
+ break;
+ case IMSG_CFG_DONE:
+ if (env->sc_reload)
+ env->sc_reload--;
break;
default:
return (-1);
@@ -515,7 +433,11 @@ parent_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
-1, &scr, sizeof(scr));
break;
case IMSG_SNMPSOCK:
- (void)snmp_sendsock(env, p->p_id);
+ (void)snmp_setsock(env, p->p_id);
+ break;
+ case IMSG_CFG_DONE:
+ if (env->sc_reload)
+ env->sc_reload--;
break;
default:
return (-1);
@@ -552,6 +474,10 @@ parent_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
proc_compose_imsg(ps, PROC_RELAY, bnd.bnd_proc,
IMSG_BINDANY, s, &bnd.bnd_id, sizeof(bnd.bnd_id));
break;
+ case IMSG_CFG_DONE:
+ if (env->sc_reload)
+ env->sc_reload--;
+ break;
default:
return (-1);
}
@@ -559,6 +485,96 @@ parent_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
return (0);
}
+void
+purge_tree(struct proto_tree *tree)
+{
+ struct protonode *proot, *pn;
+
+ while ((proot = RB_ROOT(tree)) != NULL) {
+ RB_REMOVE(proto_tree, tree, proot);
+ if (proot->key != NULL)
+ free(proot->key);
+ if (proot->value != NULL)
+ free(proot->value);
+ while ((pn = SIMPLEQ_FIRST(&proot->head)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&proot->head, entry);
+ if (pn->key != NULL)
+ free(pn->key);
+ if (pn->value != NULL)
+ free(pn->value);
+ if (pn->label != 0)
+ pn_unref(pn->label);
+ free(pn);
+ }
+ free(proot);
+ }
+}
+
+void
+purge_table(struct tablelist *head, struct table *table)
+{
+ struct host *host;
+
+ while ((host = TAILQ_FIRST(&table->hosts)) != NULL) {
+ TAILQ_REMOVE(&table->hosts, host, entry);
+ if (event_initialized(&host->cte.ev)) {
+ event_del(&host->cte.ev);
+ close(host->cte.s);
+ }
+ if (host->cte.buf != NULL)
+ ibuf_free(host->cte.buf);
+ if (host->cte.ssl != NULL)
+ SSL_free(host->cte.ssl);
+ free(host);
+ }
+ if (table->sendbuf != NULL)
+ free(table->sendbuf);
+ if (table->conf.flags & F_SSL)
+ SSL_CTX_free(table->ssl_ctx);
+
+ if (head != NULL)
+ TAILQ_REMOVE(head, table, entry);
+ free(table);
+}
+
+void
+purge_relay(struct relayd *env, struct relay *rlay)
+{
+ struct rsession *con;
+
+ /* shutdown and remove relay */
+ if (event_initialized(&rlay->rl_ev))
+ event_del(&rlay->rl_ev);
+ close(rlay->rl_s);
+ TAILQ_REMOVE(env->sc_relays, rlay, rl_entry);
+
+ /* cleanup sessions */
+ while ((con =
+ SPLAY_ROOT(&rlay->rl_sessions)) != NULL)
+ relay_close(con, NULL);
+
+ /* cleanup relay */
+ if (rlay->rl_bev != NULL)
+ bufferevent_free(rlay->rl_bev);
+ if (rlay->rl_dstbev != NULL)
+ bufferevent_free(rlay->rl_dstbev);
+
+ if (rlay->rl_ssl_ctx != NULL)
+ SSL_CTX_free(rlay->rl_ssl_ctx);
+ if (rlay->rl_ssl_cert != NULL)
+ free(rlay->rl_ssl_cert);
+ if (rlay->rl_ssl_key != NULL)
+ free(rlay->rl_ssl_key);
+ if (rlay->rl_ssl_ca != NULL)
+ free(rlay->rl_ssl_ca);
+
+ free(rlay);
+}
+
+/*
+ * Utility functions
+ */
+
struct host *
host_find(struct relayd *env, objid_t id)
{
@@ -605,6 +621,17 @@ relay_find(struct relayd *env, objid_t id)
return (NULL);
}
+struct protocol *
+proto_find(struct relayd *env, objid_t id)
+{
+ struct protocol *p;
+
+ TAILQ_FOREACH(p, env->sc_protos, entry)
+ if (p->id == id)
+ return (p);
+ return (NULL);
+}
+
struct rsession *
session_find(struct relayd *env, objid_t id)
{
@@ -629,6 +656,17 @@ route_find(struct relayd *env, objid_t id)
return (NULL);
}
+struct router *
+router_find(struct relayd *env, objid_t id)
+{
+ struct router *rt;
+
+ TAILQ_FOREACH(rt, env->sc_rts, rt_entry)
+ if (rt->rt_conf.id == id)
+ return (rt);
+ return (NULL);
+}
+
struct host *
host_findbyname(struct relayd *env, const char *name)
{
@@ -949,7 +987,6 @@ protonode_add(enum direction dir, struct protocol *proto,
SIMPLEQ_NEXT(proot, entry) = pn;
SIMPLEQ_INSERT_TAIL(&proot->head, pn, entry);
}
-
if (node->type == NODE_TYPE_COOKIE)
pk.key = "Cookie";
else if (node->type == NODE_TYPE_URL)
@@ -1126,3 +1163,32 @@ socket_rlimit(int maxfd)
if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
fatal("socket_rlimit: failed to set resource limit");
}
+
+char *
+get_string(u_int8_t *ptr, size_t len)
+{
+ size_t i;
+ char *str;
+
+ for (i = 0; i < len; i++)
+ if (!(isprint((char)ptr[i]) || isspace((char)ptr[i])))
+ break;
+
+ if ((str = calloc(1, i + 1)) == NULL)
+ return (NULL);
+ memcpy(str, ptr, i);
+
+ return (str);
+}
+
+void *
+get_data(u_int8_t *ptr, size_t len)
+{
+ u_int8_t *data;
+
+ if ((data = calloc(1, len)) == NULL)
+ return (NULL);
+ memcpy(data, ptr, len);
+
+ return (data);
+}
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index 330ad861cd4..8da1a96285d 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.146 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: relayd.h,v 1.147 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -51,15 +51,18 @@
#define RELAY_BACKLOG 10
#define RELAY_MAXLOOKUPLEVELS 5
+#define CONFIG_RELOAD 0x00
+#define CONFIG_TABLES 0x01
+#define CONFIG_RDRS 0x02
+#define CONFIG_RELAYS 0x04
+#define CONFIG_PROTOS 0x08
+#define CONFIG_ROUTES 0x10
+#define CONFIG_RTS 0x20
+#define CONFIG_ALL 0xff
+
#define SMALL_READ_BUF_SIZE 1024
#define ICMP_BUF_SIZE 64
-#define PURGE_TABLES 0x01
-#define PURGE_RDRS 0x02
-#define PURGE_RELAYS 0x04
-#define PURGE_PROTOS 0x08
-#define PURGE_EVERYTHING 0xff
-
#define SNMP_RECONNECT_TIMEOUT { 3, 0 } /* sec, usec */
#if DEBUG > 1
@@ -77,6 +80,11 @@ struct shuffle {
typedef u_int32_t objid_t;
+struct ctl_flags {
+ u_int8_t cf_opts;
+ u_int32_t cf_flags;
+};
+
struct ctl_status {
objid_t id;
int up;
@@ -100,12 +108,6 @@ struct ctl_demote {
int level;
};
-struct ctl_netroute {
- objid_t id;
- objid_t hostid;
- int up;
-};
-
struct ctl_icmp_event {
struct relayd *env;
int s;
@@ -218,6 +220,7 @@ struct portrange {
};
struct address {
+ objid_t rdrid;
struct sockaddr_storage ss;
int ipproto;
struct portrange port;
@@ -370,7 +373,6 @@ struct table {
int skipped;
struct hostlist hosts;
SSL_CTX *ssl_ctx;
- int sendbuf_len;
char *sendbuf;
};
TAILQ_HEAD(tablelist, table);
@@ -465,16 +467,26 @@ enum noderesult {
PN_FAIL = -1
};
+struct protonode_config {
+ objid_t protoid;
+ size_t keylen;
+ size_t valuelen;
+ size_t len;
+ u_int dir;
+};
+
struct protonode {
+ struct protonode_config conf;
objid_t id;
- char *key;
enum nodeaction action;
- char *value;
u_int8_t flags;
enum nodetype type;
u_int16_t mark;
u_int16_t label;
+ char *key;
+ char *value;
+
SIMPLEQ_HEAD(, protonode) head;
SIMPLEQ_ENTRY(protonode) entry;
@@ -526,7 +538,7 @@ struct protocol {
u_int8_t tcpipminttl;
u_int8_t sslflags;
char sslciphers[768];
- char *sslca;
+ char sslca[MAXPATHLEN];
char name[MAX_NAME_SIZE];
int cache;
enum prototype type;
@@ -565,6 +577,9 @@ struct relay_config {
struct sockaddr_storage dstaf;
struct timeval timeout;
enum forwardmode fwdmode;
+ off_t ssl_cert_len;
+ off_t ssl_key_len;
+ off_t ssl_ca_len;
};
struct relay {
@@ -589,11 +604,8 @@ struct relay {
SSL_CTX *rl_ssl_ctx;
char *rl_ssl_cert;
- off_t rl_ssl_cert_len;
char *rl_ssl_key;
- off_t rl_ssl_key_len;
char *rl_ssl_ca;
- off_t rl_ssl_ca_len;
struct ctl_stats rl_stats[RELAY_MAXPROC + 1];
@@ -635,11 +647,11 @@ struct router_config {
objid_t gwtable;
in_port_t gwport;
int rtable;
+ int af;
};
struct router {
struct router_config rt_conf;
- int rt_af;
struct table *rt_gwtable;
struct netroutelist rt_netroutes;
@@ -648,6 +660,12 @@ struct router {
};
TAILQ_HEAD(routerlist, router);
+struct ctl_netroute {
+ int up;
+ struct host_config host;
+ struct netroute_config nr;
+ struct router_config rt;
+};
/* initially control.h */
struct control_sock {
@@ -718,6 +736,7 @@ enum imsg_type {
IMSG_CTL_HOST_DISABLE,
IMSG_CTL_SHUTDOWN,
IMSG_CTL_RELOAD,
+ IMSG_CTL_RESET,
IMSG_CTL_POLL,
IMSG_CTL_NOTIFY,
IMSG_CTL_RDR_STATS,
@@ -733,30 +752,28 @@ enum imsg_type {
IMSG_NATLOOK,
IMSG_DEMOTE,
IMSG_STATISTICS,
- IMSG_RECONF, /* reconfiguration notifies */
- IMSG_RECONF_TABLE,
- IMSG_RECONF_SENDBUF,
- IMSG_RECONF_HOST,
- IMSG_RECONF_RDR,
- IMSG_RECONF_VIRT,
- IMSG_RECONF_PROTO,
- IMSG_RECONF_REQUEST_TREE,
- IMSG_RECONF_RESPONSE_TREE,
- IMSG_RECONF_PNODE_KEY,
- IMSG_RECONF_PNODE_VAL,
- IMSG_RECONF_RELAY,
- IMSG_RECONF_END,
IMSG_SCRIPT,
IMSG_SNMPSOCK,
IMSG_BINDANY,
- IMSG_RTMSG /* from pfe to parent */
+ IMSG_RTMSG, /* from pfe to parent */
+ IMSG_CFG_TABLE, /* configuration from parent */
+ IMSG_CFG_HOST,
+ IMSG_CFG_RDR,
+ IMSG_CFG_VIRT,
+ IMSG_CFG_ROUTER,
+ IMSG_CFG_ROUTE,
+ IMSG_CFG_PROTO,
+ IMSG_CFG_PROTONODE,
+ IMSG_CFG_RELAY,
+ IMSG_CFG_DONE
};
enum privsep_procid {
+ PROC_ALL = -1,
PROC_PARENT = 0,
- PROC_PFE,
PROC_HCE,
PROC_RELAY,
+ PROC_PFE,
PROC_MAX
} privsep_process;
@@ -768,6 +785,7 @@ struct privsep {
struct imsgev *ps_ievs[PROC_MAX];
const char *ps_title[PROC_MAX];
pid_t ps_pid[PROC_MAX];
+ u_int8_t ps_what[PROC_MAX];
u_int ps_instances[PROC_MAX];
u_int ps_instance;
@@ -781,6 +799,7 @@ struct privsep {
struct event ps_evsighup;
struct event ps_evsigpipe;
+ int ps_noaction;
struct passwd *ps_pw;
struct relayd *ps_env;
};
@@ -802,7 +821,7 @@ struct privsep_proc {
struct relayd {
u_int8_t sc_opts;
u_int32_t sc_flags;
- const char *sc_confpath;
+ const char *sc_conffile;
struct pfdata *sc_pf;
int sc_rtsock;
int sc_rtseq;
@@ -842,6 +861,7 @@ struct relayd {
struct ctl_icmp_event sc_icmp6_recv;
struct privsep *sc_ps;
+ int sc_reload;
};
#define RELAYD_OPT_VERBOSE 0x01
@@ -863,8 +883,9 @@ void socket_set_blockmode(int, enum blockmodes);
extern struct ctl_connlist ctl_conns;
/* parse.y */
-struct relayd *parse_config(const char *, int);
-int cmdline_symset(char *);
+int parse_config(const char *, struct relayd *);
+int load_config(const char *, struct relayd *);
+int cmdline_symset(char *);
/* log.c */
const char *host_error(enum host_error);
@@ -889,7 +910,7 @@ int disable_table(struct ctl_conn *, struct ctl_id *);
int disable_host(struct ctl_conn *, struct ctl_id *, struct host *);
/* pfe_filter.c */
-void init_filter(struct relayd *);
+void init_filter(struct relayd *, int);
void init_tables(struct relayd *);
void flush_table(struct relayd *, struct rdr *);
void sync_table(struct relayd *, struct rdr *, struct table *);
@@ -910,6 +931,7 @@ void hce_notify_done(struct host *, enum host_error);
/* relay.c */
pid_t relay(struct privsep *, struct privsep_proc *);
+int relay_privinit(struct relay *);
void relay_notify_done(struct host *, const char *);
int relay_session_cmp(struct rsession *, struct rsession *);
int relay_load_certfiles(struct relay *);
@@ -962,6 +984,7 @@ struct host *host_find(struct relayd *, objid_t);
struct table *table_find(struct relayd *, objid_t);
struct rdr *rdr_find(struct relayd *, objid_t);
struct netroute *route_find(struct relayd *, objid_t);
+struct router *router_find(struct relayd *, objid_t);
struct host *host_findbyname(struct relayd *, const char *);
struct table *table_findbyname(struct relayd *, const char *);
struct table *table_findbyconf(struct relayd *, struct table *);
@@ -970,14 +993,15 @@ void event_again(struct event *, int, short,
void (*)(int, short, void *),
struct timeval *, struct timeval *, void *);
struct relay *relay_find(struct relayd *, objid_t);
+struct protocol *proto_find(struct relayd *, objid_t);
struct rsession *session_find(struct relayd *, objid_t);
struct relay *relay_findbyname(struct relayd *, const char *);
struct relay *relay_findbyaddr(struct relayd *, struct relay_config *);
int expand_string(char *, size_t, const char *, const char *);
void translate_string(char *);
-void purge_config(struct relayd *, u_int8_t);
+void purge_tree(struct proto_tree *);
void purge_table(struct tablelist *, struct table *);
-void merge_config(struct relayd *, struct relayd *);
+void purge_relay(struct relayd *, struct relay *);
char *digeststr(enum digest_type, const u_int8_t *, size_t, char *);
const char *canonicalize_host(const char *, char *, size_t);
struct protonode *protonode_header(enum direction, struct protocol *,
@@ -992,6 +1016,8 @@ void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
pid_t, int, void *, u_int16_t);
void socket_rlimit(int);
+char *get_string(u_int8_t *, size_t);
+void *get_data(u_int8_t *, size_t);
/* carp.c */
int carp_demote_init(char *, int);
@@ -1008,7 +1034,8 @@ void pn_ref(u_int16_t);
/* snmp.c */
void snmp_init(struct relayd *, enum privsep_procid);
-int snmp_sendsock(struct relayd *, enum privsep_procid);
+int snmp_setsock(struct relayd *, enum privsep_procid);
+int snmp_getsock(struct relayd *, struct imsg *);
void snmp_hosttrap(struct relayd *, struct table *, struct host *);
/* shuffle.c */
@@ -1028,11 +1055,13 @@ __dead void fatalx(const char *);
/* proc.c */
void proc_init(struct privsep *, struct privsep_proc *, u_int);
void proc_kill(struct privsep *);
+void proc_clear(struct privsep *, int);
void proc_config(struct privsep *, struct privsep_proc *, u_int);
void proc_dispatch(int, short event, void *);
pid_t proc_run(struct privsep *, struct privsep_proc *,
struct privsep_proc *, u_int,
void (*)(struct privsep *, struct privsep_proc *, void *), void *);
+void proc_range(struct privsep *, enum privsep_procid, int *, int *);
int proc_compose_imsg(struct privsep *, enum privsep_procid, int,
u_int16_t, int, void *, u_int16_t);
int proc_composev_imsg(struct privsep *, enum privsep_procid, int,
@@ -1047,3 +1076,26 @@ int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
pid_t, int, void *, u_int16_t);
int imsg_composev_event(struct imsgev *, u_int16_t, u_int32_t,
pid_t, int, const struct iovec *, int);
+
+/* config.c */
+int config_init(struct relayd *);
+void config_purge(struct relayd *, u_int);
+int config_setreset(struct relayd *, u_int);
+int config_getreset(struct relayd *, struct imsg *);
+int config_getcfg(struct relayd *, struct imsg *);
+int config_settable(struct relayd *, struct table *);
+int config_gettable(struct relayd *, struct imsg *);
+int config_gethost(struct relayd *, struct imsg *);
+int config_setrdr(struct relayd *, struct rdr *);
+int config_getrdr(struct relayd *, struct imsg *);
+int config_getvirt(struct relayd *, struct imsg *);
+int config_setrt(struct relayd *, struct router *);
+int config_getrt(struct relayd *, struct imsg *);
+int config_getroute(struct relayd *, struct imsg *);
+int config_setproto(struct relayd *env, struct protocol *);
+int config_getproto(struct relayd *, struct imsg *);
+int config_setprotonode(struct relayd *, enum privsep_procid,
+ struct protocol *, enum direction);
+int config_getprotonode(struct relayd *, struct imsg *);
+int config_setrelay(struct relayd *env, struct relay *);
+int config_getrelay(struct relayd *, struct imsg *);
diff --git a/usr.sbin/relayd/snmp.c b/usr.sbin/relayd/snmp.c
index f341d74bade..f21f6577455 100644
--- a/usr.sbin/relayd/snmp.c
+++ b/usr.sbin/relayd/snmp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmp.c,v 1.10 2011/05/09 12:08:47 reyk Exp $ */
+/* $OpenBSD: snmp.c,v 1.11 2011/05/19 08:56:49 reyk Exp $ */
/*
* Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
@@ -49,7 +49,6 @@ static struct imsgev *iev_snmp = NULL;
enum privsep_procid snmp_procid;
void snmp_sock(int, short, void *);
-int snmp_getsock(struct relayd *, enum privsep_procid);
int snmp_element(const char *, enum snmp_type, void *, int64_t);
void
@@ -72,80 +71,59 @@ snmp_init(struct relayd *env, enum privsep_procid id)
}
int
-snmp_sendsock(struct relayd *env, enum privsep_procid id)
+snmp_setsock(struct relayd *env, enum privsep_procid id)
{
struct imsgev tmpiev;
struct sockaddr_un sun;
int s = -1;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- goto fail;
+ goto done;
bzero(&sun, sizeof(sun));
sun.sun_family = AF_UNIX;
strlcpy(sun.sun_path, SNMP_SOCKET, sizeof(sun.sun_path));
- if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1)
- goto fail;
+
+ if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+ close(s);
+ s = -1;
+ goto done;
+ }
/* enable restricted snmp socket mode */
bzero(&tmpiev, sizeof(tmpiev));
imsg_init(&tmpiev.ibuf, s);
imsg_compose_event(&tmpiev, IMSG_SNMP_LOCK, 0, 0, -1, NULL, 0);
+ done:
proc_compose_imsg(env->sc_ps, id, -1, IMSG_SNMPSOCK, s, NULL, 0);
- proc_flush_imsg(env->sc_ps, id, -1); /* need to send the socket now */
- close(s);
- return (0);
-
- fail:
- if (s != -1)
- close(s);
- proc_compose_imsg(env->sc_ps, id, -1, IMSG_NONE, -1, NULL, 0);
return (-1);
}
int
-snmp_getsock(struct relayd *env, enum privsep_procid id)
+snmp_getsock(struct relayd *env, struct imsg *imsg)
{
- struct imsg imsg;
- struct imsgbuf *ibuf;
- int n, s = -1, done = 0;
-
- ibuf = proc_ibuf(env->sc_ps, id, -1);
- proc_compose_imsg(env->sc_ps, id, -1, IMSG_SNMPSOCK, -1, NULL, 0);
- proc_flush_imsg(env->sc_ps, id, -1);
-
- while (!done) {
- do {
- if ((n = imsg_read(ibuf)) == -1)
- fatalx("snmp_getsock: imsg_read error");
- } while (n == -2); /* handle non-blocking I/O */
- while (!done) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("snmp_getsock: failed to get imsg");
- if (n == 0)
- break;
- done = 1;
- switch (imsg.hdr.type) {
- case IMSG_SNMPSOCK:
- s = imsg.fd;
- break;
- default:
- break;
- }
- imsg_free(&imsg);
- }
- }
+ struct timeval tv = SNMP_RECONNECT_TIMEOUT;
- if (s != -1) {
- log_debug("%s: got new snmp socket %d", __func__, s);
- if (iev_snmp == NULL && (iev_snmp = (struct imsgev *)
- calloc(1, sizeof(struct imsgev))) == NULL)
- fatal("snmp_getsock: calloc");
- imsg_init(&iev_snmp->ibuf, s);
- }
+ if (imsg->fd == -1)
+ goto retry;
- return (s);
+ env->sc_snmp = imsg->fd;
+
+ log_debug("%s: got new snmp socket %d", __func__, imsg->fd);
+ if (iev_snmp == NULL && (iev_snmp = (struct imsgev *)
+ calloc(1, sizeof(struct imsgev))) == NULL)
+ fatal("snmp_getsock: calloc");
+ imsg_init(&iev_snmp->ibuf, env->sc_snmp);
+
+ event_set(&env->sc_snmpev, env->sc_snmp,
+ EV_READ|EV_TIMEOUT, snmp_sock, env);
+ event_add(&env->sc_snmpev, NULL);
+ return (0);
+ retry:
+ evtimer_set(&env->sc_snmpto, snmp_sock, env);
+ evtimer_add(&env->sc_snmpto, &tv);
+ return (0);
}
void
@@ -164,14 +142,8 @@ snmp_sock(int fd, short event, void *arg)
break;
}
- if ((env->sc_snmp = snmp_getsock(env, snmp_procid)) == -1) {
- DPRINTF("%s: failed to open snmp socket", __func__);
- goto retry;
- }
-
- event_set(&env->sc_snmpev, env->sc_snmp,
- EV_READ|EV_TIMEOUT, snmp_sock, arg);
- event_add(&env->sc_snmpev, NULL);
+ proc_compose_imsg(env->sc_ps, snmp_procid, -1,
+ IMSG_SNMPSOCK, -1, NULL, 0);
return;
retry:
evtimer_set(&env->sc_snmpto, snmp_sock, arg);