-/* $OpenBSD: ca.c,v 1.28 2017/08/09 21:31:16 claudio Exp $ */
+/* $OpenBSD: ca.c,v 1.29 2017/11/27 21:06:25 claudio Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
ca_launch(void)
{
char hash[TLS_CERT_HASH_SIZE];
+ char *buf;
BIO *in = NULL;
EVP_PKEY *pkey = NULL;
struct relay *rlay;
X509 *cert = NULL;
+ off_t len;
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
continue;
- if (rlay->rl_conf.tls_cert_len) {
- if ((in = BIO_new_mem_buf(rlay->rl_tls_cert,
- rlay->rl_conf.tls_cert_len)) == NULL)
+ if (rlay->rl_tls_cert_fd != -1) {
+ if ((buf = relay_load_fd(rlay->rl_tls_cert_fd,
+ &len)) == NULL)
+ fatalx("ca_launch: cert");
+
+ if ((in = BIO_new_mem_buf(buf, len)) == NULL)
fatalx("ca_launch: cert");
if ((cert = PEM_read_bio_X509(in, NULL,
BIO_free(in);
X509_free(cert);
- purge_key(&rlay->rl_tls_cert,
- rlay->rl_conf.tls_cert_len);
+ purge_key(&buf, len);
}
if (rlay->rl_conf.tls_key_len) {
if ((in = BIO_new_mem_buf(rlay->rl_tls_key,
rlay->rl_conf.tls_key_len);
}
- if (rlay->rl_conf.tls_cacert_len) {
- if ((in = BIO_new_mem_buf(rlay->rl_tls_cacert,
- rlay->rl_conf.tls_cacert_len)) == NULL)
+ if (rlay->rl_tls_cacert_fd != -1) {
+ if ((buf = relay_load_fd(rlay->rl_tls_cacert_fd,
+ &len)) == NULL)
+ fatalx("ca_launch: cacert");
+
+ if ((in = BIO_new_mem_buf(buf, len)) == NULL)
fatalx("ca_launch: cacert");
if ((cert = PEM_read_bio_X509(in, NULL,
BIO_free(in);
X509_free(cert);
- purge_key(&rlay->rl_tls_cacert,
- rlay->rl_conf.tls_cacert_len);
+ purge_key(&buf, len);
}
if (rlay->rl_conf.tls_cakey_len) {
if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey,
purge_key(&rlay->rl_tls_cakey,
rlay->rl_conf.tls_cakey_len);
}
+ close(rlay->rl_tls_ca_fd);
}
}
case IMSG_CFG_RELAY:
config_getrelay(env, imsg);
break;
+ case IMSG_CFG_RELAY_FD:
+ config_getrelayfd(env, imsg);
+ break;
case IMSG_CFG_DONE:
config_getcfg(env, imsg);
break;
-/* $OpenBSD: config.c,v 1.33 2017/09/14 08:59:54 jsg Exp $ */
+/* $OpenBSD: config.c,v 1.34 2017/11/27 21:06:26 claudio Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
}
ps->ps_what[PROC_PARENT] = CONFIG_ALL;
- ps->ps_what[PROC_PFE] = CONFIG_ALL & ~CONFIG_PROTOS;
+ ps->ps_what[PROC_PFE] = CONFIG_ALL & ~(CONFIG_PROTOS|CONFIG_CERTS);
ps->ps_what[PROC_HCE] = CONFIG_TABLES;
- ps->ps_what[PROC_CA] = CONFIG_RELAYS;
- ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|
+ ps->ps_what[PROC_CA] = CONFIG_RELAYS|CONFIG_CERTS;
+ ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|CONFIG_CERTS|
CONFIG_TABLES|CONFIG_PROTOS|CONFIG_CA_ENGINE;
/* Other configuration */
return (0);
}
+static int
+config_setrelayfd(struct privsep *ps, int id, int n, int rlay_id, int type,
+ int ofd)
+{
+ struct ctl_relayfd rfd;
+ int fd;
+
+ rfd.relayid = rlay_id;
+ rfd.type = type;
+
+ if ((fd = dup(ofd)) == -1)
+ return (-1);
+ if (proc_compose_imsg(ps, id, n, IMSG_CFG_RELAY_FD, -1, fd,
+ &rfd, sizeof(rfd)) != 0)
+ return (-1);
+
+ return (0);
+}
+
int
config_setrelay(struct relayd *env, struct relay *rlay)
{
c = 0;
iov[c].iov_base = &rl;
iov[c++].iov_len = sizeof(rl);
- if (rl.tls_cert_len) {
- iov[c].iov_base = rlay->rl_tls_cert;
- iov[c++].iov_len = rl.tls_cert_len;
- }
+
if ((what & CONFIG_CA_ENGINE) == 0 &&
rl.tls_key_len) {
iov[c].iov_base = rlay->rl_tls_key;
iov[c++].iov_len = rl.tls_key_len;
} else
rl.tls_key_len = 0;
- if (rl.tls_ca_len) {
- iov[c].iov_base = rlay->rl_tls_ca;
- iov[c++].iov_len = rl.tls_ca_len;
- }
- if (rl.tls_cacert_len) {
- iov[c].iov_base = rlay->rl_tls_cacert;
- iov[c++].iov_len = rl.tls_cacert_len;
- }
if ((what & CONFIG_CA_ENGINE) == 0 &&
rl.tls_cakey_len) {
iov[c].iov_base = rlay->rl_tls_cakey;
__func__, rlay->rl_conf.name);
return (-1);
}
-
/* Prevent fd exhaustion in the parent. */
if (proc_flush_imsg(ps, id, n) == -1) {
log_warn("%s: failed to flush "
}
}
+
+ if (what & CONFIG_CERTS) {
+ n = -1;
+ proc_range(ps, id, &n, &m);
+ for (n = 0; n < m; n++) {
+ if (rlay->rl_tls_cert_fd != -1 &&
+ config_setrelayfd(ps, id, n,
+ rlay->rl_conf.id, RELAY_FD_CERT,
+ rlay->rl_tls_cert_fd) == -1) {
+ log_warn("%s: fd passing failed for "
+ "`%s'", __func__,
+ rlay->rl_conf.name);
+ return (-1);
+ }
+ if (rlay->rl_tls_ca_fd != -1 &&
+ config_setrelayfd(ps, id, n,
+ rlay->rl_conf.id, RELAY_FD_CACERT,
+ rlay->rl_tls_ca_fd) == -1) {
+ log_warn("%s: fd passing failed for "
+ "`%s'", __func__,
+ rlay->rl_conf.name);
+ return (-1);
+ }
+ if (rlay->rl_tls_cacert_fd != -1 &&
+ config_setrelayfd(ps, id, n,
+ rlay->rl_conf.id, RELAY_FD_CAFILE,
+ rlay->rl_tls_cacert_fd) == -1) {
+ log_warn("%s: fd passing failed for "
+ "`%s'", __func__,
+ rlay->rl_conf.name);
+ return (-1);
+ }
+ /* Prevent fd exhaustion in the parent. */
+ if (proc_flush_imsg(ps, id, n) == -1) {
+ log_warn("%s: failed to flush "
+ "IMSG_CFG_RELAY imsg for `%s'",
+ __func__, rlay->rl_conf.name);
+ return (-1);
+ }
+ }
+ }
+
if ((what & CONFIG_TABLES) == 0)
continue;
close(rlay->rl_s);
rlay->rl_s = -1;
}
+ if (rlay->rl_tls_cert_fd != -1) {
+ close(rlay->rl_tls_cert_fd);
+ rlay->rl_tls_cert_fd = -1;
+ }
+ if (rlay->rl_tls_cacert_fd != -1) {
+ close(rlay->rl_tls_cacert_fd);
+ rlay->rl_tls_cacert_fd = -1;
+ }
+ if (rlay->rl_tls_ca_fd != -1) {
+ close(rlay->rl_tls_ca_fd);
+ rlay->rl_tls_ca_fd = -1;
+ }
return (0);
}
s = sizeof(rlay->rl_conf);
rlay->rl_s = imsg->fd;
+ rlay->rl_tls_cert_fd = -1;
+ rlay->rl_tls_ca_fd = -1;
+ rlay->rl_tls_cacert_fd = -1;
if (ps->ps_what[privsep_process] & CONFIG_PROTOS) {
if (rlay->rl_conf.proto == EMPTY_ID)
}
if ((off_t)(IMSG_DATA_SIZE(imsg) - s) <
- (rlay->rl_conf.tls_cert_len +
- rlay->rl_conf.tls_key_len +
- rlay->rl_conf.tls_ca_len +
- rlay->rl_conf.tls_cacert_len +
- rlay->rl_conf.tls_cakey_len)) {
+ (rlay->rl_conf.tls_key_len + rlay->rl_conf.tls_cakey_len)) {
log_debug("%s: invalid message length", __func__);
goto fail;
}
- if (rlay->rl_conf.tls_cert_len) {
- if ((rlay->rl_tls_cert = get_data(p + s,
- rlay->rl_conf.tls_cert_len)) == NULL)
- goto fail;
- s += rlay->rl_conf.tls_cert_len;
- }
if (rlay->rl_conf.tls_key_len) {
if ((rlay->rl_tls_key = get_data(p + s,
rlay->rl_conf.tls_key_len)) == NULL)
goto fail;
s += rlay->rl_conf.tls_key_len;
}
- if (rlay->rl_conf.tls_ca_len) {
- if ((rlay->rl_tls_ca = get_data(p + s,
- rlay->rl_conf.tls_ca_len)) == NULL)
- goto fail;
- s += rlay->rl_conf.tls_ca_len;
- }
- if (rlay->rl_conf.tls_cacert_len) {
- if ((rlay->rl_tls_cacert = get_data(p + s,
- rlay->rl_conf.tls_cacert_len)) == NULL)
- goto fail;
- s += rlay->rl_conf.tls_cacert_len;
- }
if (rlay->rl_conf.tls_cakey_len) {
if ((rlay->rl_tls_cakey = get_data(p + s,
rlay->rl_conf.tls_cakey_len)) == NULL)
return (0);
fail:
- free(rlay->rl_tls_cert);
free(rlay->rl_tls_key);
- free(rlay->rl_tls_ca);
+ free(rlay->rl_tls_cakey);
close(rlay->rl_s);
free(rlay);
return (-1);
free(rlt);
return (-1);
}
+
+int
+config_getrelayfd(struct relayd *env, struct imsg *imsg)
+{
+ struct relay_table *rlt = NULL;
+ struct ctl_relayfd crfd;
+ struct relay *rlay;
+ u_int8_t *p = imsg->data;
+
+ IMSG_SIZE_CHECK(imsg, &crfd);
+ memcpy(&crfd, p, sizeof(crfd));
+
+ if ((rlay = relay_find(env, crfd.relayid)) == NULL) {
+ log_debug("%s: unknown relay", __func__);
+ goto fail;
+ }
+
+ switch (crfd.type) {
+ case RELAY_FD_CERT:
+ rlay->rl_tls_cert_fd = imsg->fd;
+ break;
+ case RELAY_FD_CACERT:
+ rlay->rl_tls_ca_fd = imsg->fd;
+ break;
+ case RELAY_FD_CAFILE:
+ rlay->rl_tls_cacert_fd = imsg->fd;
+ break;
+ }
+
+ DPRINTF("%s: %s %d received relay fd %d type %d for relay %s", __func__,
+ env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
+ imsg->fd, crfd.type, rlay->rl_conf.name);
+
+ return (0);
+
+ fail:
+ free(rlt);
+ return (-1);
+}
-/* $OpenBSD: parse.y,v 1.218 2017/11/16 14:24:34 bluhm Exp $ */
+/* $OpenBSD: parse.y,v 1.219 2017/11/27 21:06:26 claudio Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
objid_t last_proto_id = 0;
objid_t last_rt_id = 0;
objid_t last_nr_id = 0;
-objid_t last_key_id = 0;
static struct rdr *rdr = NULL;
static struct table *table = NULL;
r->rl_proto = NULL;
r->rl_conf.proto = EMPTY_ID;
r->rl_conf.dstretry = 0;
+ r->rl_tls_cert_fd = -1;
+ r->rl_tls_ca_fd = -1;
+ r->rl_tls_cacert_fd = -1;
TAILQ_INIT(&r->rl_tables);
if (last_relay_id == INT_MAX) {
yyerror("too many relays defined");
relay_id(struct relay *rl)
{
rl->rl_conf.id = ++last_relay_id;
- rl->rl_conf.tls_keyid = ++last_key_id;
- rl->rl_conf.tls_cakeyid = ++last_key_id;
- if (last_relay_id == INT_MAX || last_key_id == INT_MAX)
+ if (last_relay_id == INT_MAX)
return (-1);
return (0);
rb->rl_conf.flags =
(ra->rl_conf.flags & ~F_TLS) | (rc.flags & F_TLS);
if (!(rb->rl_conf.flags & F_TLS)) {
- rb->rl_tls_cert = NULL;
- rb->rl_conf.tls_cert_len = 0;
+ rb->rl_tls_cert_fd = -1;
+ rb->rl_tls_cacert_fd = -1;
+ rb->rl_tls_ca_fd = -1;
rb->rl_tls_key = NULL;
rb->rl_conf.tls_key_len = 0;
}
-/* $OpenBSD: relay.c,v 1.229 2017/11/27 17:35:49 claudio Exp $ */
+/* $OpenBSD: relay.c,v 1.230 2017/11/27 21:06:26 claudio Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
void relay_tls_readcb(int, short, void *);
void relay_tls_writecb(int, short, void *);
-char *relay_load_file(const char *, off_t *);
extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t,
size_t, void *);
case IMSG_CFG_RELAY_TABLE:
config_getrelaytable(env, imsg);
break;
+ case IMSG_CFG_RELAY_FD:
+ config_getrelayfd(env, imsg);
+ break;
case IMSG_CFG_DONE:
config_getcfg(env, imsg);
break;
struct tls *tls = NULL;
const char *fake_key;
int fake_keylen;
+ char *buf = NULL, *cabuf = NULL;
+ off_t len = 0, calen = 0;
if ((tls_cfg = tls_config_new()) == NULL) {
log_warnx("unable to allocate TLS config");
*/
tls_config_insecure_noverifyname(tls_client_cfg);
- if (rlay->rl_tls_ca != NULL) {
- if (tls_config_set_ca_mem(tls_client_cfg,
- rlay->rl_tls_ca, rlay->rl_conf.tls_ca_len) != 0) {
+ if (rlay->rl_tls_ca_fd != -1) {
+ if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) ==
+ NULL) {
+ log_warn("failed to read root certificates");
+ goto err;
+ }
+
+ if (tls_config_set_ca_mem(tls_client_cfg, buf, len) !=
+ 0) {
log_warnx("failed to set root certificates: %s",
tls_config_error(tls_client_cfg));
goto err;
}
+ purge_key(&buf, len);
} else {
/* No root cert available so disable the checking */
tls_config_insecure_noverifycert(tls_client_cfg);
*/
tls_config_skip_private_key_check(tls_cfg);
- if ((fake_keylen = ssl_ctx_fake_private_key(rlay->rl_tls_cert,
- rlay->rl_conf.tls_cert_len, &fake_key)) == -1) {
+ if ((buf = relay_load_fd(rlay->rl_tls_cert_fd, &len)) == NULL) {
+ log_warn("failed to load tls certificate");
+ goto err;
+ }
+
+ if ((fake_keylen = ssl_ctx_fake_private_key(buf, len,
+ &fake_key)) == -1) {
/* error already printed */
goto err;
}
- if (tls_config_set_keypair_ocsp_mem(tls_cfg,
- rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len,
+ if (tls_config_set_keypair_ocsp_mem(tls_cfg, buf, len,
fake_key, fake_keylen, NULL, 0) != 0) {
log_warnx("failed to set tls certificate: %s",
tls_config_error(tls_cfg));
goto err;
}
- if (rlay->rl_conf.tls_cacert_len) {
+
+ if (rlay->rl_tls_cacert_fd != -1) {
+ if ((cabuf = relay_load_fd(rlay->rl_tls_cacert_fd,
+ &calen)) == NULL) {
+ log_warn("failed to load tls CA certificate");
+ goto err;
+ }
log_debug("%s: loading CA certificate", __func__);
- if (!ssl_load_pkey(
- rlay->rl_tls_cacert, rlay->rl_conf.tls_cacert_len,
+ if (!ssl_load_pkey(cabuf, calen,
&rlay->rl_tls_cacertx509, &rlay->rl_tls_capkey))
goto err;
/* loading certificate public key */
log_debug("%s: loading certificate", __func__);
- if (!ssl_load_pkey(
- rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len,
- NULL, &rlay->rl_tls_pkey))
+ if (!ssl_load_pkey(buf, len, NULL, &rlay->rl_tls_pkey))
goto err;
}
}
rlay->rl_tls_cfg = tls_cfg;
rlay->rl_tls_ctx = tls;
+
+ purge_key(&cabuf, calen);
+ purge_key(&buf, len);
}
- /* The text versions of the keys/certs are not needed anymore */
- purge_key(&rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len);
- purge_key(&rlay->rl_tls_cacert, rlay->rl_conf.tls_cacert_len);
+ /* The fd for the keys/certs are not needed anymore */
+ close(rlay->rl_tls_cert_fd);
+ close(rlay->rl_tls_cacert_fd);
+ close(rlay->rl_tls_ca_fd);
if (rlay->rl_tls_client_cfg == NULL)
tls_config_free(tls_client_cfg);
return (0);
err:
+ purge_key(&cabuf, calen);
+ purge_key(&buf, len);
+
tls_config_free(tls_client_cfg);
tls_config_free(tls_cfg);
return (-1);
}
char *
-relay_load_file(const char *name, off_t *len)
+relay_load_fd(int fd, off_t *len)
{
+ char *buf = NULL;
struct stat st;
off_t size;
- u_int8_t *buf = NULL;
- int fd;
+ ssize_t rv;
- if ((fd = open(name, O_RDONLY)) == -1)
- return (NULL);
if (fstat(fd, &st) != 0)
goto fail;
size = st.st_size;
if ((buf = calloc(1, size + 1)) == NULL)
goto fail;
- if (read(fd, buf, size) != size)
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ goto fail;
+ if ((rv = read(fd, buf, size)) != size)
goto fail;
close(fd);
if (rlay->rl_conf.flags & F_TLSCLIENT) {
if (strlen(proto->tlsca)) {
- if ((rlay->rl_tls_ca =
- relay_load_file(proto->tlsca,
- &rlay->rl_conf.tls_ca_len)) == NULL)
+ if ((rlay->rl_tls_ca_fd =
+ open(proto->tlsca, O_RDONLY)) == -1)
return (-1);
log_debug("%s: using ca %s", __func__, proto->tlsca);
}
if (strlen(proto->tlscacert)) {
- if ((rlay->rl_tls_cacert =
- relay_load_file(proto->tlscacert,
- &rlay->rl_conf.tls_cacert_len)) == NULL)
+ if ((rlay->rl_tls_cacert_fd =
+ open(proto->tlscacert, O_RDONLY)) == -1)
return (-1);
log_debug("%s: using ca certificate %s", __func__,
proto->tlscacert);
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s:%u.crt", hbuf, useport) == -1)
return (-1);
- if ((rlay->rl_tls_cert = relay_load_file(certfile,
- &rlay->rl_conf.tls_cert_len)) == NULL) {
+ if ((rlay->rl_tls_cert_fd = open(certfile, O_RDONLY)) == -1) {
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s.crt", hbuf) == -1)
return (-1);
- if ((rlay->rl_tls_cert = relay_load_file(certfile,
- &rlay->rl_conf.tls_cert_len)) == NULL)
+ if ((rlay->rl_tls_cert_fd = open(certfile, O_RDONLY)) == -1)
return (-1);
useport = 0;
}
-/* $OpenBSD: relayd.c,v 1.169 2017/05/31 04:14:34 jsg Exp $ */
+/* $OpenBSD: relayd.c,v 1.170 2017/11/27 21:06:26 claudio Exp $ */
/*
* Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org>
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
/* Check for TLS Inspection */
if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) ==
- (F_TLS|F_TLSCLIENT) &&
- rlay->rl_conf.tls_cacert_len &&
- rlay->rl_conf.tls_cakey_len)
+ (F_TLS|F_TLSCLIENT) && rlay->rl_tls_cacert_fd != -1)
rlay->rl_conf.flags |= F_TLSINSPECT;
config_setrelay(env, rlay);
if (rlay->rl_dstbev != NULL)
bufferevent_free(rlay->rl_dstbev);
- purge_key(&rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len);
purge_key(&rlay->rl_tls_key, rlay->rl_conf.tls_key_len);
- purge_key(&rlay->rl_tls_ca, rlay->rl_conf.tls_ca_len);
purge_key(&rlay->rl_tls_cakey, rlay->rl_conf.tls_cakey_len);
if (rlay->rl_tls_pkey != NULL) {
-/* $OpenBSD: relayd.h,v 1.243 2017/11/15 19:03:26 benno Exp $ */
+/* $OpenBSD: relayd.h,v 1.244 2017/11/27 21:06:26 claudio Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
#define CONFIG_ROUTES 0x10
#define CONFIG_RTS 0x20
#define CONFIG_CA_ENGINE 0x40
+#define CONFIG_CERTS 0x80
#define CONFIG_ALL 0xff
#define SMALL_READ_BUF_SIZE 1024
u_int32_t flags;
};
+struct ctl_relayfd {
+ objid_t relayid;
+ int type;
+};
+#define RELAY_FD_CERT 1
+#define RELAY_FD_CACERT 2
+#define RELAY_FD_CAFILE 3
+
struct ctl_script {
objid_t host;
int retval;
struct timeval timeout;
enum forwardmode fwdmode;
union hashkey hashkey;
- off_t tls_cert_len;
off_t tls_key_len;
- objid_t tls_keyid;
- off_t tls_ca_len;
- off_t tls_cacert_len;
off_t tls_cakey_len;
- objid_t tls_cakeyid;
};
struct relay {
struct tls_config *rl_tls_client_cfg;
struct tls *rl_tls_ctx;
- char *rl_tls_cert;
+ int rl_tls_cert_fd;
+ int rl_tls_ca_fd;
+ int rl_tls_cacert_fd;
char *rl_tls_key;
EVP_PKEY *rl_tls_pkey;
- char *rl_tls_ca;
- char *rl_tls_cacert;
X509 *rl_tls_cacertx509;
char *rl_tls_cakey;
EVP_PKEY *rl_tls_capkey;
IMSG_CFG_RULE,
IMSG_CFG_RELAY,
IMSG_CFG_RELAY_TABLE,
+ IMSG_CFG_RELAY_CERT,
+ IMSG_CFG_RELAY_FD,
IMSG_CFG_DONE,
IMSG_CA_PRIVENC,
IMSG_CA_PRIVDEC,
int relay_privinit(struct relay *);
void relay_notify_done(struct host *, const char *);
int relay_session_cmp(struct rsession *, struct rsession *);
+char *relay_load_fd(int, off_t *);
int relay_load_certfiles(struct relay *);
void relay_close(struct rsession *, const char *);
void relay_natlook(int, short, void *);
int config_setrelay(struct relayd *, struct relay *);
int config_getrelay(struct relayd *, struct imsg *);
int config_getrelaytable(struct relayd *, struct imsg *);
+int config_getrelayfd(struct relayd *, struct imsg *);
#endif /* RELAYD_H */