summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2009-04-01 14:56:39 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2009-04-01 14:56:39 +0000
commit32e2b02a8722eff69b6df3287982cd6803e9add8 (patch)
tree2380fcda7707d6cd54beb5eff3b17f5e1723c503
parent4bd0a5bb0865c3233a6bfae144c72921458f4594 (diff)
Add support for client-side SSL connections from relays. relayd can
now sit between two SSL connections (Oitm - OpenBSD-in-the-middle), accept SSL connections and forward to TCP, accept TCP connections and forward to SSL, and do TCP to TCP of course. This was tested by some people a while ago.
-rw-r--r--usr.sbin/relayd/parse.y55
-rw-r--r--usr.sbin/relayd/relay.c117
-rw-r--r--usr.sbin/relayd/relayd.conf.519
-rw-r--r--usr.sbin/relayd/relayd.h3
4 files changed, 154 insertions, 40 deletions
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index 8746e066c6d..6e2387f1771 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.128 2009/03/31 21:03:49 tobias Exp $ */
+/* $OpenBSD: parse.y,v 1.129 2009/04/01 14:56:38 reyk Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -140,8 +140,9 @@ typedef struct {
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> hostname interface table
-%type <v.number> http_type loglevel mark optssl parent sslcache
+%type <v.number> http_type loglevel mark parent
%type <v.number> direction dstmode flag forwardmode proto_type retry
+%type <v.number> optssl optsslclient sslcache
%type <v.port> port
%type <v.host> host
%type <v.tv> timeout
@@ -180,6 +181,10 @@ optssl : /*empty*/ { $$ = 0; }
| SSL { $$ = 1; }
;
+optsslclient : /*empty*/ { $$ = 0; }
+ | WITH SSL { $$ = 1; }
+ ;
+
http_type : STRING {
if (strcmp("https", $1) == 0) {
$$ = 1;
@@ -573,7 +578,7 @@ tableopts_l : tableopts tableopts_l
| tableopts
;
-tableopts : CHECK tablecheck
+tableopts : CHECK tablecheck
| port {
if ($1.op != PF_OP_EQ) {
yyerror("invalid port");
@@ -1217,11 +1222,11 @@ relayoptsl : LISTEN ON STRING port optssl {
}
tableport = h->port.val[0];
}
- | forwardmode TO forwardspec interface dstaf {
+ | forwardmode optsslclient TO forwardspec interface dstaf {
rlay->rl_conf.fwdmode = $1;
switch ($1) {
case FWD_NORMAL:
- if ($4 == NULL)
+ if ($5 == NULL)
break;
yyerror("superfluous interface");
YYERROR;
@@ -1229,15 +1234,19 @@ relayoptsl : LISTEN ON STRING port optssl {
yyerror("no route for redirections");
YYERROR;
case FWD_TRANS:
- if ($4 != NULL)
+ if ($5 != NULL)
break;
yyerror("missing interface");
YYERROR;
}
- if ($4 != NULL) {
- strlcpy(rlay->rl_conf.ifname, $4,
+ if ($5 != NULL) {
+ strlcpy(rlay->rl_conf.ifname, $5,
sizeof(rlay->rl_conf.ifname));
- free($4);
+ free($5);
+ }
+ if ($2) {
+ rlay->rl_conf.flags |= F_SSLCLIENT;
+ conf->sc_flags |= F_SSLCLIENT;
}
}
| SESSION TIMEOUT NUMBER {
@@ -1266,19 +1275,7 @@ relayoptsl : LISTEN ON STRING port optssl {
| include
;
-forwardspec : tablespec {
- if (rlay->rl_dsttable) {
- yyerror("table already specified");
- purge_table(conf->sc_tables, $1);
- YYERROR;
- }
-
- rlay->rl_dsttable = $1;
- rlay->rl_dsttable->conf.flags |= F_USED;
- rlay->rl_conf.dsttable = $1->conf.id;
- rlay->rl_conf.dstport = $1->conf.port;
- }
- | STRING port retry {
+forwardspec : STRING port retry {
struct addresslist al;
struct address *h;
@@ -1307,11 +1304,23 @@ forwardspec : tablespec {
rlay->rl_conf.dstport = h->port.val[0];
rlay->rl_conf.dstretry = $3;
}
- | NAT LOOKUP retry {
+ | NAT LOOKUP retry {
conf->sc_flags |= F_NEEDPF;
rlay->rl_conf.flags |= F_NATLOOK;
rlay->rl_conf.dstretry = $3;
}
+ | tablespec {
+ if (rlay->rl_dsttable) {
+ yyerror("table already specified");
+ purge_table(conf->sc_tables, $1);
+ YYERROR;
+ }
+
+ rlay->rl_dsttable = $1;
+ rlay->rl_dsttable->conf.flags |= F_USED;
+ rlay->rl_conf.dsttable = $1->conf.id;
+ rlay->rl_conf.dstport = $1->conf.port;
+ }
;
dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; }
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index 77451fc9352..a0b45fa4803 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.107 2008/09/29 15:50:56 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.108 2009/04/01 14:56:38 reyk Exp $ */
/*
* Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -103,8 +103,10 @@ void relay_close_http(struct session *, u_int, const char *,
u_int16_t);
SSL_CTX *relay_ssl_ctx_create(struct relay *);
-void relay_ssl_transaction(struct session *);
+void relay_ssl_transaction(struct session *,
+ struct ctl_relay_event *);
void relay_ssl_accept(int, short, void *);
+void relay_ssl_connect(int, short, void *);
void relay_ssl_connected(struct ctl_relay_event *);
void relay_ssl_readcb(int, short, void *);
void relay_ssl_writecb(int, short, void *);
@@ -408,7 +410,7 @@ relay_privinit(void)
struct relay *rlay;
extern int debug;
- if (env->sc_flags & F_SSL)
+ if (env->sc_flags & (F_SSL|F_SSLCLIENT))
ssl_init(env);
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
@@ -460,7 +462,7 @@ relay_init(void)
fatal("relay_init: failed to set resource limit");
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
- if ((rlay->rl_conf.flags & F_SSL) &&
+ 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");
@@ -749,12 +751,18 @@ relay_connected(int fd, short sig, void *arg)
evbuffercb outrd = relay_read;
evbuffercb outwr = relay_write;
struct bufferevent *bev;
+ struct ctl_relay_event *out = &con->se_out;
if (sig == EV_TIMEOUT) {
relay_close_http(con, 504, "connect timeout", 0);
return;
}
+ if ((rlay->rl_conf.flags & F_SSLCLIENT) && (out->ssl == NULL)) {
+ relay_ssl_transaction(con, out);
+ return;
+ }
+
DPRINTF("relay_connected: session %d: %ssuccessful",
con->se_id, rlay->rl_proto->lateconnect ? "late connect " : "");
@@ -791,8 +799,12 @@ relay_connected(int fd, short sig, void *arg)
bev->output = con->se_out.output;
if (bev->output == NULL)
fatal("relay_connected: invalid output buffer");
-
con->se_out.bev = bev;
+
+ /* Initialize the SSL wrapper */
+ if ((rlay->rl_conf.flags & F_SSLCLIENT) && (out->ssl != NULL))
+ relay_ssl_connected(out);
+
bufferevent_settimeout(bev,
rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
bufferevent_enable(bev, EV_READ|EV_WRITE);
@@ -2179,7 +2191,7 @@ relay_session(struct session *con)
}
if ((rlay->rl_conf.flags & F_SSL) && (in->ssl == NULL)) {
- relay_ssl_transaction(con);
+ relay_ssl_transaction(con, in);
return;
}
@@ -2603,6 +2615,9 @@ relay_ssl_ctx_create(struct relay *rlay)
if (!SSL_CTX_set_cipher_list(ctx, proto->sslciphers))
goto err;
+ if ((rlay->rl_conf.flags & F_SSL) == 0)
+ return (ctx);
+
log_debug("relay_ssl_ctx_create: loading certificate");
if (!ssl_ctx_use_certificate_chain(ctx,
rlay->rl_ssl_cert, rlay->rl_ssl_cert_len))
@@ -2630,31 +2645,49 @@ relay_ssl_ctx_create(struct relay *rlay)
}
void
-relay_ssl_transaction(struct session *con)
+relay_ssl_transaction(struct session *con, struct ctl_relay_event *cre)
{
struct relay *rlay = (struct relay *)con->se_relay;
SSL *ssl;
+ SSL_METHOD *method;
+ void (*cb)(int, short, void *);
+ u_int flags = EV_TIMEOUT;
ssl = SSL_new(rlay->rl_ssl_ctx);
if (ssl == NULL)
goto err;
- if (!SSL_set_ssl_method(ssl, SSLv23_server_method()))
+ if (cre->dir == RELAY_DIR_REQUEST) {
+ cb = relay_ssl_accept;
+ method = SSLv23_server_method();
+ flags |= EV_READ;
+ } else {
+ cb = relay_ssl_connect;
+ method = SSLv23_client_method();
+ flags |= EV_WRITE;
+ }
+
+ if (!SSL_set_ssl_method(ssl, method))
goto err;
- if (!SSL_set_fd(ssl, con->se_in.s))
+ if (!SSL_set_fd(ssl, cre->s))
goto err;
- SSL_set_accept_state(ssl);
- con->se_in.ssl = ssl;
+ if (cre->dir == RELAY_DIR_REQUEST)
+ SSL_set_accept_state(ssl);
+ else
+ SSL_set_connect_state(ssl);
+
+ cre->ssl = ssl;
- event_again(&con->se_ev, con->se_in.s, EV_TIMEOUT|EV_READ,
- relay_ssl_accept, &con->se_tv_start, &env->sc_timeout, con);
+ event_again(&con->se_ev, cre->s, EV_TIMEOUT|flags,
+ cb, &con->se_tv_start, &env->sc_timeout, con);
return;
err:
if (ssl != NULL)
SSL_free(ssl);
ssl_error(rlay->rl_conf.name, "relay_ssl_transaction");
+ relay_close(con, "session ssl failed");
}
void
@@ -2717,6 +2750,64 @@ retry:
}
void
+relay_ssl_connect(int fd, short event, void *arg)
+{
+ struct session *con = (struct session *)arg;
+ struct relay *rlay = (struct relay *)con->se_relay;
+ int ret;
+ int ssl_err;
+ int retry_flag;
+
+ if (event == EV_TIMEOUT) {
+ relay_close(con, "SSL connect timeout");
+ return;
+ }
+
+ retry_flag = ssl_err = 0;
+
+ ret = SSL_connect(con->se_out.ssl);
+ if (ret <= 0) {
+ ssl_err = SSL_get_error(con->se_out.ssl, ret);
+
+ switch (ssl_err) {
+ case SSL_ERROR_WANT_READ:
+ retry_flag = EV_READ;
+ goto retry;
+ case SSL_ERROR_WANT_WRITE:
+ retry_flag = EV_WRITE;
+ goto retry;
+ case SSL_ERROR_ZERO_RETURN:
+ case SSL_ERROR_SYSCALL:
+ if (ret == 0) {
+ relay_close(con, "closed");
+ return;
+ }
+ /* FALLTHROUGH */
+ default:
+ ssl_error(rlay->rl_conf.name, "relay_ssl_connect");
+ relay_close(con, "SSL connect error");
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ log_info("relay %s, session %d connected (%d active)",
+ rlay->rl_conf.name, con->se_id, relay_sessions);
+#else
+ log_debug("relay %s, session %d connected (%d active)",
+ rlay->rl_conf.name, con->se_id, relay_sessions);
+#endif
+ relay_connected(fd, EV_WRITE, con);
+ return;
+
+retry:
+ DPRINTF("relay_ssl_connect: session %d: scheduling on %s", con->se_id,
+ (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
+ event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_ssl_connect,
+ &con->se_tv_start, &env->sc_timeout, con);
+}
+
+void
relay_ssl_connected(struct ctl_relay_event *cre)
{
/*
diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5
index ae8daac65fb..3a08596fd07 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.100 2009/02/16 19:46:12 jmc Exp $
+.\" $OpenBSD: relayd.conf.5,v 1.101 2009/04/01 14:56:38 reyk Exp $
.\"
.\" Copyright (c) 2006, 2007 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: February 16 2009 $
+.Dd $Mdocdate: April 1 2009 $
.Dt RELAYD.CONF 5
.Os
.Sh NAME
@@ -500,7 +500,9 @@ configuration directives are described below:
Start the relay but immediately close any accepted connections.
.It Xo
.Op Ic transparent
-.Ic forward to
+.Ic forward
+.Op Ic with ssl
+.Ic to
.Ar address
.Op Ic port Ar port
.Ar options ...
@@ -516,6 +518,13 @@ Use the
keyword to enable fully-transparent mode; the source address of the
client will be retained in this case.
.Pp
+The
+.Ic with ssl
+directive enables client-side SSL mode to connect to the remote host.
+Note that
+.Xr relayd 8
+will not verify the remote SSL certificate.
+.Pp
The following options may be specified for forward directives:
.Pp
.Bl -tag -width Ds
@@ -1131,3 +1140,7 @@ program was written by
.An Pierre-Yves Ritschard Aq pyr@openbsd.org
and
.An Reyk Floeter Aq reyk@openbsd.org .
+.Sh CAVEATS
+.Xr relayd 8
+does not support verification of server certificates when connecting
+to a remote host using the SSL protocol.
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index 2eb76fc4e75..5a0813250da 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.113 2008/12/05 16:37:56 reyk Exp $ */
+/* $OpenBSD: relayd.h,v 1.114 2009/04/01 14:56:38 reyk Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -344,6 +344,7 @@ TAILQ_HEAD(addresslist, address);
#define F_TRAP 0x00040000
#define F_NEEDPF 0x00080000
#define F_PORT 0x00100000
+#define F_SSLCLIENT 0x00200000
enum forwardmode {
FWD_NORMAL = 0,