diff options
-rw-r--r-- | usr.sbin/relayctl/parser.c | 22 | ||||
-rw-r--r-- | usr.sbin/relayctl/parser.h | 4 | ||||
-rw-r--r-- | usr.sbin/relayctl/relayctl.8 | 6 | ||||
-rw-r--r-- | usr.sbin/relayctl/relayctl.c | 11 | ||||
-rw-r--r-- | usr.sbin/relayd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/relayd/check_tcp.c | 59 | ||||
-rw-r--r-- | usr.sbin/relayd/config.c | 898 | ||||
-rw-r--r-- | usr.sbin/relayd/control.c | 29 | ||||
-rw-r--r-- | usr.sbin/relayd/hce.c | 78 | ||||
-rw-r--r-- | usr.sbin/relayd/parse.y | 237 | ||||
-rw-r--r-- | usr.sbin/relayd/pfe.c | 124 | ||||
-rw-r--r-- | usr.sbin/relayd/pfe_filter.c | 19 | ||||
-rw-r--r-- | usr.sbin/relayd/pfe_route.c | 51 | ||||
-rw-r--r-- | usr.sbin/relayd/proc.c | 46 | ||||
-rw-r--r-- | usr.sbin/relayd/relay.c | 206 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.c | 522 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 138 | ||||
-rw-r--r-- | usr.sbin/relayd/snmp.c | 92 |
18 files changed, 1777 insertions, 769 deletions
diff --git a/usr.sbin/relayctl/parser.c b/usr.sbin/relayctl/parser.c index a9fa3a25814..a8a80c73f2c 100644 --- a/usr.sbin/relayctl/parser.c +++ b/usr.sbin/relayctl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.24 2010/09/04 21:31:04 tedu Exp $ */ +/* $OpenBSD: parser.c,v 1.25 2011/05/19 08:56:49 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -46,7 +46,8 @@ enum token_type { HOSTID, TABLEID, RDRID, - KEYWORD + KEYWORD, + PATH }; struct token { @@ -65,10 +66,12 @@ static const struct token t_rdr_id[]; static const struct token t_table_id[]; static const struct token t_host_id[]; static const struct token t_log[]; +static const struct token t_load[]; static const struct token t_main[] = { {KEYWORD, "monitor", MONITOR, NULL}, {KEYWORD, "show", NONE, t_show}, + {KEYWORD, "load", LOAD, t_load}, {KEYWORD, "poll", POLL, NULL}, {KEYWORD, "reload", RELOAD, NULL}, {KEYWORD, "stop", SHUTDOWN, NULL}, @@ -131,6 +134,11 @@ static const struct token t_log[] = { {ENDTOKEN, "", NONE, NULL} }; +static const struct token t_load[] = { + {PATH, "", NONE, NULL}, + {ENDTOKEN, "", NONE, NULL} +}; + static const struct token *match_token(const char *, const struct token *, struct parse_result *); static void show_valid_args(const struct token *); @@ -228,6 +236,13 @@ match_token(const char *word, const struct token *table, t = &table[i]; match++; break; + case PATH: + if (!match && word != NULL && strlen(word) > 0) { + res->path = strdup(word); + match++; + t = &table[i]; + } + break; case ENDTOKEN: break; } @@ -268,6 +283,9 @@ show_valid_args(const struct token *table) case HOSTID: fprintf(stderr, " <hostid>\n"); break; + case PATH: + fprintf(stderr, " <path>\n"); + break; case ENDTOKEN: break; } diff --git a/usr.sbin/relayctl/parser.h b/usr.sbin/relayctl/parser.h index 8682b433c1f..5e19f9befde 100644 --- a/usr.sbin/relayctl/parser.h +++ b/usr.sbin/relayctl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.13 2010/09/04 21:31:04 tedu Exp $ */ +/* $OpenBSD: parser.h,v 1.14 2011/05/19 08:56:49 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -32,6 +32,7 @@ enum actions { HOST_ENABLE, SHUTDOWN, POLL, + LOAD, RELOAD, MONITOR, LOG_VERBOSE, @@ -41,6 +42,7 @@ enum actions { struct parse_result { struct ctl_id id; enum actions action; + char *path; }; struct parse_result *parse(int, char *[]); diff --git a/usr.sbin/relayctl/relayctl.8 b/usr.sbin/relayctl/relayctl.8 index 7de530474de..75aec549914 100644 --- a/usr.sbin/relayctl/relayctl.8 +++ b/usr.sbin/relayctl/relayctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: relayctl.8,v 1.26 2009/10/22 15:02:12 sobrado Exp $ +.\" $OpenBSD: relayctl.8,v 1.27 2011/05/19 08:56:49 reyk Exp $ .\" .\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 22 2009 $ +.Dd $Mdocdate: May 19 2011 $ .Dt RELAYCTL 8 .Os .Sh NAME @@ -39,6 +39,8 @@ Treat it as though it were always down. .It Cm host enable Op Ar name | id Enable the host. Start checking its health again. +.It Cm load Ar filename +Reload the configuration from the specified file. .It Cm monitor Continuously report any changes in the host checking engine and the .Xr pf 4 diff --git a/usr.sbin/relayctl/relayctl.c b/usr.sbin/relayctl/relayctl.c index f09dccd9709..1f83e8109ad 100644 --- a/usr.sbin/relayctl/relayctl.c +++ b/usr.sbin/relayctl/relayctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relayctl.c,v 1.43 2011/05/09 12:08:46 reyk Exp $ */ +/* $OpenBSD: relayctl.c,v 1.44 2011/05/19 08:56:49 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -179,8 +179,14 @@ main(int argc, char *argv[]) case POLL: imsg_compose(ibuf, IMSG_CTL_POLL, 0, 0, -1, NULL, 0); break; + case LOAD: + imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, + res->path, strlen(res->path)); + done = 1; + break; case RELOAD: imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); + done = 1; break; case MONITOR: imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0); @@ -229,13 +235,14 @@ main(int argc, char *argv[]) case HOST_DISABLE: case HOST_ENABLE: case POLL: - case RELOAD: case SHUTDOWN: done = show_command_output(&imsg); break; case NONE: case LOG_VERBOSE: case LOG_BRIEF: + case RELOAD: + case LOAD: break; case MONITOR: done = monitor(&imsg); 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); |