diff options
-rw-r--r-- | usr.sbin/relayd/check_tcp.c | 58 | ||||
-rw-r--r-- | usr.sbin/relayd/check_tls.c | 17 | ||||
-rw-r--r-- | usr.sbin/relayd/config.c | 9 | ||||
-rw-r--r-- | usr.sbin/relayd/parse.y | 56 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.c | 3 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.conf.5 | 31 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 14 | ||||
-rw-r--r-- | usr.sbin/relayd/util.c | 78 |
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); + } +} |