summaryrefslogtreecommitdiffstats
path: root/usr.sbin/relayd
diff options
context:
space:
mode:
authorrob <rob@openbsd.org>2019-09-15 19:23:29 +0000
committerrob <rob@openbsd.org>2019-09-15 19:23:29 +0000
commit3f229715608395e3b8f08834a8c17738785d87d0 (patch)
tree7db7ef706290ef8acd991e675f5b5dc976f8c2a3 /usr.sbin/relayd
parentMask all MMC interrupts. This prevents an interrupt storm when one of the (diff)
downloadwireguard-openbsd-3f229715608395e3b8f08834a8c17738785d87d0.tar.xz
wireguard-openbsd-3f229715608395e3b8f08834a8c17738785d87d0.zip
Add support for binary protocol health checking. Feedback and guidance from
benno@ and reky@. Man page tweaks from jmc@. ok benno@
Diffstat (limited to 'usr.sbin/relayd')
-rw-r--r--usr.sbin/relayd/check_tcp.c58
-rw-r--r--usr.sbin/relayd/check_tls.c17
-rw-r--r--usr.sbin/relayd/config.c9
-rw-r--r--usr.sbin/relayd/parse.y56
-rw-r--r--usr.sbin/relayd/relayd.c3
-rw-r--r--usr.sbin/relayd/relayd.conf.531
-rw-r--r--usr.sbin/relayd/relayd.h14
-rw-r--r--usr.sbin/relayd/util.c78
8 files changed, 238 insertions, 28 deletions
diff --git a/usr.sbin/relayd/check_tcp.c b/usr.sbin/relayd/check_tcp.c
index 3a3ac92c29e..0a92712c2df 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.56 2018/04/14 20:42:41 benno Exp $ */
+/* $OpenBSD: check_tcp.c,v 1.57 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -171,6 +171,7 @@ tcp_host_up(struct ctl_tcp_event *cte)
cte->validate_read = NULL;
cte->validate_close = check_http_digest;
break;
+ case CHECK_BINSEND_EXPECT:
case CHECK_SEND_EXPECT:
cte->validate_read = check_send_expect;
cte->validate_close = check_send_expect;
@@ -182,8 +183,11 @@ tcp_host_up(struct ctl_tcp_event *cte)
return;
}
- if (cte->table->sendbuf != NULL) {
+ if (cte->table->sendbuf != NULL && cte->table->sendbinbuf == NULL) {
cte->req = cte->table->sendbuf;
+ } else if (cte->table->sendbinbuf != NULL)
+ cte->req = cte->table->sendbinbuf->buf;
+ if (cte->table->sendbuf != NULL || cte->table->sendbinbuf != NULL) {
event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
&cte->tv_start, &cte->table->conf.timeout, cte);
return;
@@ -207,7 +211,15 @@ tcp_send_req(int s, short event, void *arg)
hce_notify_done(cte->host, HCE_TCP_WRITE_TIMEOUT);
return;
}
- len = strlen(cte->req);
+
+ if (cte->table->sendbinbuf != NULL) {
+ len = ibuf_size(cte->table->sendbinbuf);
+ log_debug("%s: table %s sending binary", __func__,
+ cte->table->conf.name);
+ print_hex(cte->table->sendbinbuf->buf, 0, len);
+ } else
+ len = strlen(cte->req);
+
do {
bs = write(s, cte->req, len);
if (bs == -1) {
@@ -289,17 +301,35 @@ check_send_expect(struct ctl_tcp_event *cte)
{
u_char *b;
- /*
- * ensure string is nul-terminated.
- */
- b = ibuf_reserve(cte->buf, 1);
- if (b == NULL)
- fatal("out of memory");
- *b = '\0';
- if (fnmatch(cte->table->conf.exbuf, cte->buf->buf, 0) == 0) {
- cte->host->he = HCE_SEND_EXPECT_OK;
- cte->host->up = HOST_UP;
- return (0);
+ if (cte->table->conf.check == CHECK_BINSEND_EXPECT) {
+ log_debug("%s: table %s expecting binary",
+ __func__, cte->table->conf.name);
+ print_hex(cte->table->conf.exbinbuf, 0,
+ strlen(cte->table->conf.exbuf) / 2);
+
+ if (memcmp(cte->table->conf.exbinbuf, cte->buf->buf,
+ strlen(cte->table->conf.exbuf) / 2) == 0) {
+ cte->host->he = HCE_SEND_EXPECT_OK;
+ cte->host->up = HOST_UP;
+ return (0);
+ } else {
+ log_debug("%s: table %s received mismatching binary",
+ __func__, cte->table->conf.name);
+ print_hex(cte->buf->buf, 0, ibuf_size(cte->buf));
+ }
+ } else if (cte->table->conf.check == CHECK_SEND_EXPECT) {
+ /*
+ * ensure string is nul-terminated.
+ */
+ b = ibuf_reserve(cte->buf, 1);
+ if (b == NULL)
+ fatal("out of memory");
+ *b = '\0';
+ if (fnmatch(cte->table->conf.exbuf, cte->buf->buf, 0) == 0) {
+ cte->host->he = HCE_SEND_EXPECT_OK;
+ cte->host->up = HOST_UP;
+ return (0);
+ }
}
cte->host->he = HCE_SEND_EXPECT_FAIL;
cte->host->up = HOST_UNKNOWN;
diff --git a/usr.sbin/relayd/check_tls.c b/usr.sbin/relayd/check_tls.c
index eb453507c82..3fe829101f7 100644
--- a/usr.sbin/relayd/check_tls.c
+++ b/usr.sbin/relayd/check_tls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: check_tls.c,v 1.1 2017/05/27 08:33:25 claudio Exp $ */
+/* $OpenBSD: check_tls.c,v 1.2 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2017 Claudio Jeker <claudio@openbsd.org>
@@ -93,6 +93,7 @@ check_tls_write(int s, short event, void *arg)
int retry_flag = EV_WRITE;
int len;
int ret;
+ void *buf;
if (event == EV_TIMEOUT) {
cte->host->up = HOST_DOWN;
@@ -101,9 +102,19 @@ check_tls_write(int s, short event, void *arg)
return;
}
- len = strlen(cte->table->sendbuf);
+ if (cte->table->sendbinbuf != NULL) {
+ len = ibuf_size(cte->table->sendbinbuf);
+ buf = cte->table->sendbinbuf->buf;
+ log_debug("%s: table %s sending binary", __func__,
+ cte->table->conf.name);
+ print_hex(cte->table->sendbinbuf->buf, 0, len);
+ } else {
+ len = strlen(cte->table->sendbuf);
+ buf = cte->table->sendbuf;
+ }
+
+ ret = tls_write(cte->tls, buf, len);
- ret = tls_write(cte->tls, cte->table->sendbuf, len);
if (ret > 0) {
if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) ==
NULL)
diff --git a/usr.sbin/relayd/config.c b/usr.sbin/relayd/config.c
index 2b8a308a969..3e60d63ef52 100644
--- a/usr.sbin/relayd/config.c
+++ b/usr.sbin/relayd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.40 2019/06/26 12:13:47 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.41 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -367,6 +367,13 @@ config_gettable(struct relayd *env, struct imsg *imsg)
return (-1);
}
}
+ if (tb->conf.check == CHECK_BINSEND_EXPECT) {
+ tb->sendbinbuf = string2binary(tb->sendbuf);
+ if (tb->sendbinbuf == NULL) {
+ free(tb);
+ return (-1);
+ }
+ }
TAILQ_INIT(&tb->hosts);
TAILQ_INSERT_TAIL(env->sc_tables, tb, entry);
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index c6e2bcacdfb..fc22377b94f 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.241 2019/07/13 06:54:45 chrisz Exp $ */
+/* $OpenBSD: parse.y,v 1.242 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -168,7 +168,7 @@ typedef struct {
%}
-%token ALL APPEND BACKLOG BACKUP BUFFER CA CACHE SET CHECK CIPHERS CODE
+%token ALL APPEND BACKLOG BACKUP BINARY BUFFER CA CACHE SET CHECK CIPHERS CODE
%token COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT PASS BLOCK EXTERNAL FILENAME
%token FORWARD FROM HASH HEADER HEADERLEN HOST HTTP ICMP INCLUDE INET INET6
%token INTERFACE INTERVAL IP KEYPAIR LABEL LISTEN VALUE LOADBALANCE LOG LOOKUP
@@ -389,6 +389,25 @@ sendbuf : NOTHING {
}
;
+sendbinbuf : NOTHING {
+ table->sendbinbuf = NULL;
+ }
+ | STRING {
+ if (strlen($1) == 0) {
+ yyerror("empty binary send data");
+ free($1);
+ YYERROR;
+ }
+ table->sendbuf = strdup($1);
+ if (table->sendbuf == NULL)
+ fatal("out of memory");
+ table->sendbinbuf = string2binary($1);
+ if (table->sendbinbuf == NULL)
+ fatal("failed in binary send data");
+ free($1);
+ }
+ ;
+
main : INTERVAL NUMBER {
if ((conf->sc_conf.interval.tv_sec = $2) < 0) {
yyerror("invalid interval: %lld", $2);
@@ -951,6 +970,36 @@ tablecheck : ICMP { table->conf.check = CHECK_ICMP; }
translate_string(table->conf.exbuf);
free($4);
}
+ | BINARY SEND sendbinbuf EXPECT STRING opttls {
+ table->conf.check = CHECK_BINSEND_EXPECT;
+ if ($6) {
+ conf->sc_conf.flags |= F_TLS;
+ table->conf.flags |= F_TLS;
+ }
+ if (strlen($5) == 0) {
+ yyerror("empty binary expect data");
+ free($5);
+ YYERROR;
+ }
+ if (strlcpy(table->conf.exbuf, $5,
+ sizeof(table->conf.exbuf))
+ >= sizeof(table->conf.exbuf)) {
+ yyerror("expect buffer truncated");
+ free($5);
+ YYERROR;
+ }
+ struct ibuf *ibuf = string2binary($5);
+ if (ibuf == NULL) {
+ yyerror("failed in binary expect data buffer");
+ ibuf_free(ibuf);
+ free($5);
+ YYERROR;
+ }
+ memcpy(table->conf.exbinbuf, ibuf->buf,
+ ibuf_size(ibuf));
+ ibuf_free(ibuf);
+ free($5);
+ }
| SCRIPT STRING {
table->conf.check = CHECK_SCRIPT;
if (strlcpy(table->conf.path, $2,
@@ -2309,6 +2358,7 @@ lookup(char *s)
{ "append", APPEND },
{ "backlog", BACKLOG },
{ "backup", BACKUP },
+ { "binary", BINARY },
{ "block", BLOCK },
{ "buffer", BUFFER },
{ "ca", CA },
@@ -2890,6 +2940,8 @@ load_config(const char *filename, struct relayd *x_conf)
}
if (table->sendbuf != NULL)
free(table->sendbuf);
+ if (table->sendbinbuf != NULL)
+ ibuf_free(table->sendbinbuf);
free(table);
continue;
}
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index eda2064646c..fc10929359f 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.181 2019/08/30 16:54:20 sthen Exp $ */
+/* $OpenBSD: relayd.c,v 1.182 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -530,6 +530,7 @@ purge_table(struct relayd *env, struct tablelist *head, struct table *table)
free(host);
}
free(table->sendbuf);
+ ibuf_free(table->sendbinbuf);
tls_config_free(table->tls_cfg);
if (head != NULL)
diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5
index f45585565ed..5f6b94f12cd 100644
--- a/usr.sbin/relayd/relayd.conf.5
+++ b/usr.sbin/relayd/relayd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: relayd.conf.5,v 1.192 2019/07/05 13:42:06 robert Exp $
+.\" $OpenBSD: relayd.conf.5,v 1.193 2019/09/15 19:23:29 rob Exp $
.\"
.\" Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
.\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -15,7 +15,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: July 5 2019 $
+.Dd $Mdocdate: September 15 2019 $
.Dt RELAYD.CONF 5
.Os
.Sh NAME
@@ -372,6 +372,33 @@ If the
.Ic tls
keyword is present,
the transaction will occur in a TLS tunnel.
+.It Xo
+.Ic check binary send
+.Ar data
+.Ic expect
+.Ar data
+.Op Ic tls
+.Xc
+For each host in the table, a TCP connection is established on the
+port specified, then the
+.Ic send
+.Ar data
+is converted into binary and sent.
+Incoming (binary)
+data is then read and is expected to match against a binary
+conversion of the
+.Ic expect
+.Ar data
+using
+.Xr memcmp 3 .
+.Ar data
+must be populated with a string containing an even number of hexadecimal
+single-byte characters and must not be empty.
+This can be useful with binary protocols such as LDAP and SNMP.
+If the
+.Ic tls
+keyword is present,
+the transaction will occur in a TLS tunnel.
.It Ic check tcp
Use a simple TCP connect to check that hosts are up.
.It Ic check tls
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index ba841ddfcd3..d5ddbc143e2 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.259 2019/06/26 12:13:47 reyk Exp $ */
+/* $OpenBSD: relayd.h,v 1.260 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -504,7 +504,8 @@ struct table_config {
char name[TABLE_NAME_SIZE];
size_t name_len;
char path[PATH_MAX];
- char exbuf[64];
+ unsigned char exbinbuf[128];
+ char exbuf[256];
char digest[41]; /* length of sha1 digest * 2 */
u_int8_t digest_type;
enum forwardmode fwdmode;
@@ -517,6 +518,7 @@ struct table {
int skipped;
struct hostlist hosts;
struct tls_config *tls_cfg;
+ struct ibuf *sendbinbuf;
char *sendbuf;
};
TAILQ_HEAD(tablelist, table);
@@ -527,8 +529,9 @@ enum table_check {
CHECK_TCP = 2,
CHECK_HTTP_CODE = 3,
CHECK_HTTP_DIGEST = 4,
- CHECK_SEND_EXPECT = 5,
- CHECK_SCRIPT = 6
+ CHECK_BINSEND_EXPECT = 5,
+ CHECK_SEND_EXPECT = 6,
+ CHECK_SCRIPT = 7
};
struct rdr_config {
@@ -1169,6 +1172,9 @@ const char *print_host(struct sockaddr_storage *, char *, size_t);
const char *print_time(struct timeval *, struct timeval *, char *, size_t);
const char *printb_flags(const u_int32_t, const char *);
void getmonotime(struct timeval *);
+struct ibuf *string2binary(const char *);
+void print_hex(uint8_t *, off_t, size_t);
+void print_debug(const char *, ...);
/* pfe.c */
void pfe(struct privsep *, struct privsep_proc *);
diff --git a/usr.sbin/relayd/util.c b/usr.sbin/relayd/util.c
index a566a4bc9f6..8a06dc4a419 100644
--- a/usr.sbin/relayd/util.c
+++ b/usr.sbin/relayd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.2 2019/05/13 09:54:07 reyk Exp $ */
+/* $OpenBSD: util.c,v 1.3 2019/09/15 19:23:29 rob Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -168,6 +168,7 @@ table_check(enum table_check check)
return ("http code");
case CHECK_HTTP_DIGEST:
return ("http digest");
+ case CHECK_BINSEND_EXPECT:
case CHECK_SEND_EXPECT:
return ("send expect");
case CHECK_SCRIPT:
@@ -284,3 +285,78 @@ getmonotime(struct timeval *tv)
TIMESPEC_TO_TIMEVAL(tv, &ts);
}
+
+struct ibuf *
+string2binary(const char *string)
+{
+ unsigned long i, j, x;
+ unsigned char *binary = NULL;
+ struct ibuf *ibuf = NULL;
+ char hex[3];
+ int len;
+
+ if (strlen(string) % 2 != 0) {
+ return NULL;
+ }
+
+ binary = calloc(strlen(string), sizeof(unsigned char));
+ if (binary == NULL) {
+ return NULL;
+ }
+
+ hex[2] = '\0';
+ j = 0;
+ for (i = 0; i < strlen(string); i++) {
+ if (isxdigit(string[i]) == 0 || isxdigit(string[i+1]) == 0) {
+ free(binary);
+ return NULL;
+ } else {
+ hex[0] = string[i];
+ hex[1] = string[i+1];
+ x = strtoul(hex, NULL, 16);
+ binary[j++] = (unsigned char)x;
+ i++;
+ }
+ }
+ len = strlen(string) / 2;
+ if ((ibuf = ibuf_open(len)) == NULL ||
+ ibuf_add(ibuf, binary, len) == -1) {
+ ibuf_free(ibuf);
+ free(binary);
+ return NULL;
+ }
+ free(binary);
+ return ibuf;
+}
+
+void
+print_hex(uint8_t *buf, off_t offset, size_t length)
+{
+ unsigned int i;
+
+ if (log_getverbose() < 3 || !length)
+ return;
+
+ for (i = 0; i < length; i++) {
+ if (i && (i % 4) == 0) {
+ if ((i % 32) == 0)
+ print_debug("\n");
+ else
+ print_debug(" ");
+ }
+ print_debug("%02x", buf[offset + i]);
+ }
+ print_debug("\n");
+}
+
+void
+print_debug(const char *emsg, ...)
+{
+ va_list ap;
+
+ if (log_getverbose() > 2) {
+ va_start(ap, emsg);
+ vfprintf(stderr, emsg, ap);
+ va_end(ap);
+ }
+}