summaryrefslogtreecommitdiff
path: root/usr.sbin/relayd
diff options
context:
space:
mode:
authorPierre-Yves Ritschard <pyr@cvs.openbsd.org>2007-01-29 14:23:32 +0000
committerPierre-Yves Ritschard <pyr@cvs.openbsd.org>2007-01-29 14:23:32 +0000
commit06d15a1620bd5274567e1bad0e2be7623e5e5fc9 (patch)
treed52dd07d1c89b6a17880e57fb2cf113fd1b9d3d2 /usr.sbin/relayd
parent6306aef59f4a6f6202699665489bfeb95ff5c51c (diff)
Add SSL support to hoststated.
with help and OK reyk@ with help and advice by claudio@ and Srebrenko Sehic
Diffstat (limited to 'usr.sbin/relayd')
-rw-r--r--usr.sbin/relayd/Makefile8
-rw-r--r--usr.sbin/relayd/buffer.c4
-rw-r--r--usr.sbin/relayd/check_icmp.c4
-rw-r--r--usr.sbin/relayd/check_tcp.c14
-rw-r--r--usr.sbin/relayd/control.c4
-rw-r--r--usr.sbin/relayd/hce.c14
-rw-r--r--usr.sbin/relayd/imsg.c4
-rw-r--r--usr.sbin/relayd/parse.y54
-rw-r--r--usr.sbin/relayd/pfe.c4
-rw-r--r--usr.sbin/relayd/pfe_filter.c4
-rw-r--r--usr.sbin/relayd/relayd.c4
-rw-r--r--usr.sbin/relayd/relayd.conf.525
-rw-r--r--usr.sbin/relayd/relayd.h12
-rw-r--r--usr.sbin/relayd/ssl.c309
14 files changed, 439 insertions, 25 deletions
diff --git a/usr.sbin/relayd/Makefile b/usr.sbin/relayd/Makefile
index 2cf8d3a13c1..b619932c623 100644
--- a/usr.sbin/relayd/Makefile
+++ b/usr.sbin/relayd/Makefile
@@ -1,13 +1,13 @@
-# $OpenBSD: Makefile,v 1.4 2007/01/09 02:32:58 reyk Exp $
+# $OpenBSD: Makefile,v 1.5 2007/01/29 14:23:31 pyr Exp $
PROG= hoststated
SRCS= parse.y log.c control.c buffer.c imsg.c hoststated.c \
- pfe.c pfe_filter.c hce.c \
+ ssl.c pfe.c pfe_filter.c hce.c \
check_icmp.c check_tcp.c check_http.c check_send_expect.c
MAN= hoststated.8 hoststated.conf.5
-LDADD= -levent
-DPADD= ${LIBEVENT}
+LDADD= -levent -lcrypto -lssl
+DPADD= ${LIBEVENT} ${LIBCRYPTO} ${LIBSSL}
CFLAGS+= -Wall -Werror -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
diff --git a/usr.sbin/relayd/buffer.c b/usr.sbin/relayd/buffer.c
index 7133094ddfc..4d85f78ea57 100644
--- a/usr.sbin/relayd/buffer.c
+++ b/usr.sbin/relayd/buffer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.c,v 1.4 2007/01/09 00:45:32 deraadt Exp $ */
+/* $OpenBSD: buffer.c,v 1.5 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -30,6 +30,8 @@
#include <string.h>
#include <unistd.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
int buf_realloc(struct buf *, size_t);
diff --git a/usr.sbin/relayd/check_icmp.c b/usr.sbin/relayd/check_icmp.c
index f4167359a0e..ce83f7de214 100644
--- a/usr.sbin/relayd/check_icmp.c
+++ b/usr.sbin/relayd/check_icmp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: check_icmp.c,v 1.11 2007/01/12 17:12:58 pyr Exp $ */
+/* $OpenBSD: check_icmp.c,v 1.12 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -35,6 +35,8 @@
#include <stdlib.h>
#include <err.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
void icmp_setup(struct hoststated *, struct ctl_icmp_event *, int);
diff --git a/usr.sbin/relayd/check_tcp.c b/usr.sbin/relayd/check_tcp.c
index 7195a216710..a3ebc23c563 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.11 2007/01/20 16:32:10 pyr Exp $ */
+/* $OpenBSD: check_tcp.c,v 1.12 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <errno.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
void tcp_write(int, short, void *);
@@ -108,6 +110,7 @@ tcp_write(int s, short event, void *arg)
else
cte->host->up = HOST_UP;
}
+
if (cte->host->up == HOST_UP)
tcp_host_up(s, cte);
else {
@@ -123,8 +126,10 @@ tcp_host_up(int s, struct ctl_tcp_event *cte)
switch (cte->table->check) {
case CHECK_TCP:
+ if (cte->table->flags & F_SSL)
+ break;
close(s);
- hce_notify_done(cte->host, "tcp_host_up: success");
+ hce_notify_done(cte->host, "tcp_host_up: connect successfull");
return;
case CHECK_HTTP_CODE:
cte->validate_read = NULL;
@@ -140,6 +145,11 @@ tcp_host_up(int s, struct ctl_tcp_event *cte)
break;
}
+ if (cte->table->flags & F_SSL) {
+ ssl_transaction(cte);
+ return;
+ }
+
if (cte->table->sendbuf != NULL) {
cte->req = cte->table->sendbuf;
event_again(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
diff --git a/usr.sbin/relayd/control.c b/usr.sbin/relayd/control.c
index 46ac0e87ec8..b7f78b2434e 100644
--- a/usr.sbin/relayd/control.c
+++ b/usr.sbin/relayd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.9 2007/01/23 17:43:36 claudio Exp $ */
+/* $OpenBSD: control.c,v 1.10 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -31,6 +31,8 @@
#include <unistd.h>
#include <signal.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
#define CONTROL_BACKLOG 5
diff --git a/usr.sbin/relayd/hce.c b/usr.sbin/relayd/hce.c
index aceef6f8e88..ac887311164 100644
--- a/usr.sbin/relayd/hce.c
+++ b/usr.sbin/relayd/hce.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hce.c,v 1.11 2007/01/24 10:26:00 claudio Exp $ */
+/* $OpenBSD: hce.c,v 1.12 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -36,6 +36,8 @@
#include <err.h>
#include <pwd.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
void hce_sig_handler(int sig, short, void *);
@@ -70,6 +72,7 @@ hce(struct hoststated *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2],
struct timeval tv;
struct event ev_sigint;
struct event ev_sigterm;
+ struct table *table;
switch (pid = fork()) {
case -1:
@@ -135,6 +138,15 @@ hce(struct hoststated *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2],
bzero(&tv, sizeof(tv));
evtimer_add(&env->ev, &tv);
+ if (env->flags & F_SSL) {
+ ssl_init(env);
+ TAILQ_FOREACH(table, &env->tables, entry) {
+ if (!(table->flags & F_SSL))
+ continue;
+ table->ssl_ctx = ssl_ctx_create(env);
+ }
+ }
+
event_dispatch();
hce_shutdown();
diff --git a/usr.sbin/relayd/imsg.c b/usr.sbin/relayd/imsg.c
index fb110a45fb8..83d633e2dc1 100644
--- a/usr.sbin/relayd/imsg.c
+++ b/usr.sbin/relayd/imsg.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: imsg.c,v 1.4 2007/01/09 00:45:32 deraadt Exp $ */
+/* $OpenBSD: imsg.c,v 1.5 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -28,6 +28,8 @@
#include <string.h>
#include <unistd.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
void
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index 7dc5648ea6f..195823f2aa3 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.18 2007/01/25 19:40:08 niallo Exp $ */
+/* $OpenBSD: parse.y,v 1.19 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -41,6 +41,8 @@
#include <netdb.h>
#include <string.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
struct hoststated *conf = NULL;
@@ -98,14 +100,14 @@ typedef struct {
%}
%token SERVICE TABLE BACKUP HOST REAL
-%token CHECK HTTP TCP ICMP EXTERNAL
+%token CHECK HTTP HTTPS TCP ICMP EXTERNAL
%token TIMEOUT CODE DIGEST PORT TAG INTERFACE
%token VIRTUAL IP INTERVAL DISABLE STICKYADDR
-%token SEND EXPECT NOTHING
+%token SEND EXPECT NOTHING USE SSL
%token ERROR
%token <v.string> STRING
%type <v.string> interface
-%type <v.number> number port
+%type <v.number> number port http_type
%type <v.host> host
%type <v.tv> timeout
@@ -134,6 +136,10 @@ number : STRING {
}
;
+http_type : HTTP { $$ = 0; }
+ | HTTPS { $$ = 1; }
+ ;
+
port : PORT STRING {
const char *estr;
struct servent *servent;
@@ -156,12 +162,22 @@ port : PORT STRING {
$$ = htons($$);
free($2);
}
- | PORT HTTP {
+ | PORT http_type {
struct servent *servent;
+ int port;
+ const char *sport;
+
+ if ($2) {
+ port = 443;
+ sport = "https";
+ } else {
+ port = 80;
+ sport = "http";
+ }
- servent = getservbyname("http", "tcp");
+ servent = getservbyname(sport, "tcp");
if (servent == NULL)
- $$ = htons(80);
+ $$ = htons(port);
else
$$ = servent->s_port;
}
@@ -380,7 +396,16 @@ tableoptsl : host {
| CHECK TCP {
table->check = CHECK_TCP;
}
- | CHECK HTTP STRING CODE number {
+ | CHECK SSL {
+ table->check = CHECK_TCP;
+ conf->flags |= F_SSL;
+ table->flags |= F_SSL;
+ }
+ | CHECK http_type STRING CODE number {
+ if ($2) {
+ conf->flags |= F_SSL;
+ table->flags |= F_SSL;
+ }
table->check = CHECK_HTTP_CODE;
table->retcode = $5;
asprintf(&table->sendbuf, "HEAD %s HTTP/1.0\r\n\r\n",
@@ -389,7 +414,11 @@ tableoptsl : host {
if (table->sendbuf == NULL)
fatal("out of memory");
}
- | CHECK HTTP STRING DIGEST STRING {
+ | CHECK http_type STRING DIGEST STRING {
+ if ($2) {
+ conf->flags |= F_SSL;
+ table->flags |= F_SSL;
+ }
table->check = CHECK_HTTP_DIGEST;
asprintf(&table->sendbuf, "GET %s HTTP/1.0\r\n\r\n",
$3);
@@ -418,6 +447,10 @@ tableoptsl : host {
table->port = $2;
}
| DISABLE { table->flags |= F_DISABLE; }
+ | USE SSL {
+ table->flags |= F_SSL;
+ conf->flags |= F_SSL;
+ }
;
interface : /*empty*/ { $$ = NULL; }
@@ -515,6 +548,7 @@ lookup(char *s)
{ "external", EXTERNAL },
{ "host", HOST },
{ "http", HTTP },
+ { "https", HTTPS },
{ "icmp", ICMP },
{ "interface", INTERFACE },
{ "interval", INTERVAL },
@@ -524,11 +558,13 @@ lookup(char *s)
{ "real", REAL },
{ "send", SEND },
{ "service", SERVICE },
+ { "ssl", SSL },
{ "sticky-address", STICKYADDR },
{ "table", TABLE },
{ "tag", TAG },
{ "tcp", TCP },
{ "timeout", TIMEOUT },
+ { "use", USE },
{ "virtual", VIRTUAL }
};
const struct keywords *p;
diff --git a/usr.sbin/relayd/pfe.c b/usr.sbin/relayd/pfe.c
index 1077928d1ef..43c6f358c37 100644
--- a/usr.sbin/relayd/pfe.c
+++ b/usr.sbin/relayd/pfe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfe.c,v 1.8 2007/01/24 10:26:00 claudio Exp $ */
+/* $OpenBSD: pfe.c,v 1.9 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -31,6 +31,8 @@
#include <unistd.h>
#include <pwd.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
void pfe_sig_handler(int sig, short, void *);
diff --git a/usr.sbin/relayd/pfe_filter.c b/usr.sbin/relayd/pfe_filter.c
index 18e0af927e3..22c95844271 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.9 2007/01/09 13:50:11 pyr Exp $ */
+/* $OpenBSD: pfe_filter.c,v 1.10 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -35,6 +35,8 @@
#include <stdlib.h>
#include <errno.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
struct pfdata {
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index 2a0b1233620..ae31748ae37 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.12 2007/01/24 10:26:00 claudio Exp $ */
+/* $OpenBSD: relayd.c,v 1.13 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -33,6 +33,8 @@
#include <unistd.h>
#include <pwd.h>
+#include <openssl/ssl.h>
+
#include "hoststated.h"
__dead void usage(void);
diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5
index ae3f6ec209f..ce0d6b760e8 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.14 2007/01/10 13:42:19 jmc Exp $
+.\" $OpenBSD: relayd.conf.5,v 1.15 2007/01/29 14:23:31 pyr Exp $
.\"
.\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
.\"
@@ -109,6 +109,12 @@ For each host in the table, verify that retrieving the URL
.Ar path
gives the HTTP return code
.Ar number .
+If
+.Ic use ssl
+is specified, HTTPS will be used to contact the host.
+.It Ic check https Ar path Ic code Ar number
+This has the same effect than above but also implies
+.Ic use ssl .
.It Ic check http Ar path Ic digest Ar string
For each host in the table, verify that retrieving the URL
.Ar path
@@ -125,6 +131,12 @@ that can be used as is in a digest statement:
.Bd -literal -offset indent
a9993e36476816aba3e25717850c26c9cd0d89d
.Ed
+If
+.Ic use ssl
+is specified, HTTPS will be used to contact the host.
+.It Ic check https Ar path Ic digest Ar string
+This has the same effect than above but also implies
+.Ic use ssl .
.It Ic check icmp
Ping hosts in this table to determine whether they are up or not.
This method will automatically use ICMP or ICMPV6 depending on the
@@ -145,8 +157,17 @@ then nothing is sent on the connection and data is immediately
read.
This can be useful with protocols that output a banner like
SMTP, NNTP and FTP.
+If
+.Ic use ssl
+is specified, the data will be sent and/or received inside a SSL tunnel.
.It Ic check tcp
Use a simple TCP connect to check that hosts are up.
+If
+.Ic use ssl
+is specified, a complete SSL handshake will also be performed.
+.It Ic check ssl
+This has the same effect than above but also implies
+.Ic use ssl .
.It Ic disable
Start the table disabled \(en no hosts will be checked in this table.
The table can be later enabled through
@@ -166,6 +187,8 @@ Main and backup tables need to have the same real port.
Set the timeout in milliseconds for each host that is checked using
TCP as the transport.
This will override the global timeout, which is 200 milliseconds by default.
+.It Ic use ssl
+When the table uses a TCP check, wrap it into SSL.
.El
.Sh SERVICES
Services represent a
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index b76c4e68e9b..f375d5724c6 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.16 2007/01/12 17:05:18 pyr Exp $ */
+/* $OpenBSD: relayd.h,v 1.17 2007/01/29 14:23:31 pyr Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -143,6 +143,8 @@ struct ctl_tcp_event {
struct event ev;
int (*validate_read)(struct ctl_tcp_event *);
int (*validate_close)(struct ctl_tcp_event *);
+ SSL *ssl;
+ char rbuf[SMALL_READ_BUF_SIZE];
};
struct address {
@@ -164,6 +166,7 @@ TAILQ_HEAD(addresslist, address);
#define F_CHECK_DONE 0x0100
#define F_ACTIVE_RULESET 0x0200
#define F_CHECK_SENT 0x0400
+#define F_SSL 0x0800
struct host {
u_int16_t flags;
@@ -197,6 +200,7 @@ struct table {
char *sendbuf;
char exbuf[64];
char digest[41]; /* length of sha1 digest * 2 */
+ SSL_CTX *ssl_ctx;
struct hostlist hosts;
TAILQ_ENTRY(table) entry;
};
@@ -230,6 +234,7 @@ enum {
struct hoststated {
u_int8_t opts;
+ u_int16_t flags;
struct pfdata *pf;
int tablecount;
int servicecount;
@@ -356,6 +361,11 @@ int check_http_digest(struct ctl_tcp_event *);
/* check_send_expect.c */
int check_send_expect(struct ctl_tcp_event *);
+/* ssl.c */
+void ssl_init(struct hoststated *);
+void ssl_transaction(struct ctl_tcp_event *);
+SSL_CTX *ssl_ctx_create(struct hoststated *);
+
/* hoststated.c */
struct host *host_find(struct hoststated *, objid_t);
struct table *table_find(struct hoststated *, objid_t);
diff --git a/usr.sbin/relayd/ssl.c b/usr.sbin/relayd/ssl.c
new file mode 100644
index 00000000000..9cedfb9b37d
--- /dev/null
+++ b/usr.sbin/relayd/ssl.c
@@ -0,0 +1,309 @@
+/* $OpenBSD: ssl.c,v 1.1 2007/01/29 14:23:31 pyr Exp $ */
+
+/*
+ * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.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/queue.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <limits.h>
+#include <event.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "hoststated.h"
+
+void ssl_read(int, short, void *);
+void ssl_write(int, short, void *);
+void ssl_connect(int, short, void *);
+void ssl_cleanup(struct ctl_tcp_event *);
+void ssl_error(const char *);
+
+void
+ssl_read(int s, short event, void *arg)
+{
+ struct ctl_tcp_event *cte = arg;
+ int ret;
+ int ssl_err;
+ int retry_flag;
+ char rbuf[SMALL_READ_BUF_SIZE];
+
+ if (event == EV_TIMEOUT) {
+ cte->host->up = HOST_DOWN;
+ ssl_cleanup(cte);
+ hce_notify_done(cte->host, "ssl_read: timeout");
+ return;
+ }
+ log_debug("ssl_read: event occurred");
+
+ bzero(rbuf, sizeof(rbuf));
+ ssl_err = 0;
+ retry_flag = EV_READ;
+
+ ret = SSL_read(cte->ssl, rbuf, sizeof(rbuf));
+
+ if (ret <= 0) {
+ ssl_err = SSL_get_error(cte->ssl, ret);
+ switch (ssl_err) {
+ case SSL_ERROR_WANT_READ:
+ log_debug("ssl_read: want read");
+ retry_flag = EV_READ;
+ goto retry;
+ case SSL_ERROR_WANT_WRITE:
+ log_debug("ssl_read: want read");
+ retry_flag = EV_WRITE;
+ goto retry;
+ case SSL_ERROR_ZERO_RETURN: /* FALLTHROUGH */
+ case SSL_ERROR_SYSCALL:
+ if (ret == 0) {
+ cte->host->up = HOST_DOWN;
+ (void)cte->validate_close(cte);
+ ssl_cleanup(cte);
+ if (cte->host->up == HOST_UP)
+ hce_notify_done(cte->host,
+ "ssl_read: check succeeded");
+ else
+ hce_notify_done(cte->host,
+ "ssl_read: check failed");
+ return;
+ }
+ /* FALLTHROUGH */
+ default:
+ cte->host->up = HOST_DOWN;
+ ssl_error("cannot read");
+ ssl_cleanup(cte);
+ hce_notify_done(cte->host, "ssl_read: SSL error");
+ break;
+ }
+ return;
+ }
+ buf_add(cte->buf, rbuf, ret);
+
+ if (cte->validate_read != NULL) {
+ if (cte->validate_read(cte) != 0)
+ goto retry;
+
+ ssl_cleanup(cte);
+ if (cte->host->up == HOST_UP)
+ hce_notify_done(cte->host, "ssl_read: check succeeded");
+ else
+ hce_notify_done(cte->host, "ssl_read: check failed");
+ return;
+ }
+
+retry:
+ log_debug("ssl_read: scheduling ssl_read on %s",
+ (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
+ event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_read,
+ &cte->tv_start, &cte->table->timeout, cte);
+ return;
+}
+
+void
+ssl_write(int s, short event, void *arg)
+{
+ struct ctl_tcp_event *cte = arg;
+ int len;
+ int ret;
+ int ssl_err;
+ int retry_flag;
+
+ if (event == EV_TIMEOUT) {
+ cte->host->up = HOST_DOWN;
+ ssl_cleanup(cte);
+ hce_notify_done(cte->host, "ssl_write: timeout");
+ return;
+ }
+
+ log_debug("ssl_write: event occurred");
+ len = strlen(cte->table->sendbuf);
+ retry_flag = EV_WRITE;
+
+ ret = SSL_write(cte->ssl, cte->table->sendbuf, len);
+
+ if (ret <= 0) {
+ ssl_err = SSL_get_error(cte->ssl, ret);
+ switch (ssl_err) {
+ case SSL_ERROR_WANT_READ:
+ log_debug("ssl_write: want read");
+ retry_flag = EV_READ;
+ goto retry;
+ case SSL_ERROR_WANT_WRITE:
+ log_debug("ssl_write: want write");
+ retry_flag = EV_WRITE;
+ goto retry;
+ default:
+ cte->host->up = HOST_DOWN;
+ ssl_error("cannot write");
+ ssl_cleanup(cte);
+ hce_notify_done(cte->host, "ssl_write: SSL error");
+ return;
+ }
+ }
+ if ((cte->buf = buf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
+ fatalx("ssl_write: cannot create dynamic buffer");
+
+ log_debug("ssl_write: scheduling ssl_read on EV_READ");
+ event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, ssl_read,
+ &cte->tv_start, &cte->table->timeout, cte);
+ return;
+retry:
+ log_debug("ssl_write: scheduling ssl_write on %s",
+ (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
+ event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_write,
+ &cte->tv_start, &cte->table->timeout, cte);
+}
+
+void
+ssl_connect(int s, short event, void *arg)
+{
+ struct ctl_tcp_event *cte = arg;
+ int ret;
+ int ssl_err;
+ int retry_flag;
+
+ if (event == EV_TIMEOUT) {
+ cte->host->up = HOST_DOWN;
+ hce_notify_done(cte->host, "ssl_connect: timeout");
+ return;
+ }
+
+ retry_flag = ssl_err = 0;
+
+ ret = SSL_connect(cte->ssl);
+
+ if (ret <= 0) {
+ ssl_err = SSL_get_error(cte->ssl, ret);
+ switch (ssl_err) {
+ case SSL_ERROR_WANT_READ:
+ log_debug("ssl_connect: want read");
+ retry_flag = EV_READ;
+ goto retry;
+ case SSL_ERROR_WANT_WRITE:
+ log_debug("ssl_connect: want write");
+ retry_flag = EV_WRITE;
+ goto retry;
+ default:
+ cte->host->up = HOST_DOWN;
+ ssl_error("ssl_connect: cannot connect");
+ hce_notify_done(cte->host, "ssl_connect: SSL error");
+ ssl_cleanup(cte);
+ return;
+ }
+ }
+
+ if (cte->table->check == CHECK_TCP) {
+ cte->host->up = HOST_UP;
+ hce_notify_done(cte->host, "ssl_connect: connect successful");
+ ssl_cleanup(cte);
+ return;
+ }
+ log_debug("ssl_connect: connect succeeded");
+ if (cte->table->sendbuf != NULL) {
+ log_debug("ssl_connect: scheduling ssl_write on EV_WRITE");
+ event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_write,
+ &cte->tv_start, &cte->table->timeout, cte);
+ return;
+ }
+
+ if ((cte->buf = buf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
+ fatalx("ssl_connect: cannot create dynamic buffer");
+ log_debug("ssl_connect: scheduling ssl_read on EV_READ");
+ event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, ssl_read,
+ &cte->tv_start, &cte->table->timeout, cte);
+ return;
+
+retry:
+ log_debug("ssl_write: scheduling ssl_write on %s",
+ (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
+ event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_connect,
+ &cte->tv_start, &cte->table->timeout, cte);
+}
+
+void
+ssl_cleanup(struct ctl_tcp_event *cte)
+{
+ log_debug("ssl_cleanup: cleaning for %s", cte->host->name);
+ close(cte->s);
+ if (cte->ssl != NULL)
+ SSL_free(cte->ssl);
+ if (cte->buf != NULL)
+ buf_free(cte->buf);
+}
+
+void
+ssl_error(const char *msg)
+{
+ unsigned long code;
+ char errbuf[128];
+
+
+ for (; (code = ERR_get_error()) != 0 ;) {
+ ERR_error_string_n(code, errbuf, sizeof(errbuf));
+ log_debug("ssl_error: %s: %s", msg, errbuf);
+ }
+}
+
+void
+ssl_init(struct hoststated *env)
+{
+ SSL_library_init();
+ SSL_load_error_strings();
+}
+
+void
+ssl_transaction(struct ctl_tcp_event *cte)
+{
+ cte->ssl = SSL_new(cte->table->ssl_ctx);
+ if (cte->ssl == NULL) {
+ ssl_error("ssl_transaction: cannot create object");
+ fatal("cannot create SSL object");
+ }
+
+ if (SSL_set_fd(cte->ssl, cte->s) == 0) {
+ cte->host->up = HOST_UNKNOWN;
+ ssl_error("ssl_transaction: cannot set fd");
+ ssl_cleanup(cte);
+ hce_notify_done(cte->host, "cannot set SSL fd");
+ return;
+ }
+ SSL_set_connect_state(cte->ssl);
+
+ event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_connect,
+ &cte->tv_start, &cte->table->timeout, cte);
+}
+
+SSL_CTX *
+ssl_ctx_create(struct hoststated *env)
+{
+ SSL_CTX *ctx;
+
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ if (ctx == NULL) {
+ ssl_error("ssl_ctx_create: cannot create context");
+ fatal("could not create SSL context");
+ }
+ return (ctx);
+}