From f20bb366e3e93c1e3034d596aebe7317fcbca4f2 Mon Sep 17 00:00:00 2001 From: claudio Date: Mon, 8 Jun 2015 15:47:51 +0000 Subject: [PATCH] Introduce a state on the ctl_relay_event struct. This makes it possible to better track the connection state of a session and stops doing double opens in certain situations using http relays. Using a state field to simplify the logic since relay_connect() is called multiple times. OK benno@, bluhm@ and running in production for more than a week --- usr.sbin/relayd/relay.c | 39 +++++++++++++++++++++++++++++------- usr.sbin/relayd/relay_http.c | 4 ++-- usr.sbin/relayd/relayd.h | 3 ++- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c index 33146226d22..d854ce85210 100644 --- a/usr.sbin/relayd/relay.c +++ b/usr.sbin/relayd/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.194 2015/05/18 16:57:20 bluhm Exp $ */ +/* $OpenBSD: relay.c,v 1.195 2015/06/08 15:47:51 claudio Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -1408,8 +1408,10 @@ relay_connect_retry(int fd, short sig, void *arg) struct relay *rlay = con->se_relay; int bnds = -1; - if (relay_inflight < 1) - fatalx("relay_connect_retry: no connection in flight"); + if (relay_inflight < 1) { + log_warnx("relay_connect_retry: no connection in flight"); + relay_inflight = 1; + } DPRINTF("%s: retry %d of %d, inflight: %d",__func__, con->se_retrycount, con->se_retry, relay_inflight); @@ -1466,6 +1468,10 @@ relay_connect_retry(int fd, short sig, void *arg) return; } + if (rlay->rl_conf.flags & F_TLSINSPECT) + con->se_out.state = PRECONNECT; + else + con->se_out.state = CONNECTED; relay_inflight--; DPRINTF("%s: inflight decremented, now %d",__func__, relay_inflight); @@ -1484,9 +1490,14 @@ relay_connect_retry(int fd, short sig, void *arg) int relay_preconnect(struct rsession *con) { + int rv; + log_debug("%s: session %d: process %d", __func__, con->se_id, privsep_process); - return (relay_connect(con)); + rv = relay_connect(con); + if (con->se_out.state == CONNECTED) + con->se_out.state = PRECONNECT; + return (rv); } int @@ -1496,18 +1507,28 @@ relay_connect(struct rsession *con) struct timeval evtpause = { 1, 0 }; int bnds = -1, ret; + /* relay_connect should only be called once per relay */ + if (con->se_out.state == CONNECTED) { + log_debug("%s: connect already called once", __func__); + return (0); + } + /* Connection is already established but session not active */ - if ((rlay->rl_conf.flags & F_TLSINSPECT) && con->se_out.s != -1) { + if ((rlay->rl_conf.flags & F_TLSINSPECT) && + con->se_out.state == PRECONNECT) { if (con->se_out.ssl == NULL) { log_debug("%s: tls connect failed", __func__); return (-1); } relay_connected(con->se_out.s, EV_WRITE, con); + con->se_out.state = CONNECTED; return (0); } - if (relay_inflight < 1) - fatalx("relay_connect: no connection in flight"); + if (relay_inflight < 1) { + log_warnx("relay_connect: no connection in flight"); + relay_inflight = 1; + } getmonotime(&con->se_tv_start); @@ -1555,6 +1576,8 @@ relay_connect(struct rsession *con) event_del(&rlay->rl_ev); evtimer_add(&con->se_inflightevt, &evtpause); evtimer_add(&rlay->rl_evt, &evtpause); + /* this connect is pending */ + con->se_out.state = PENDING; return (0); } else { if (con->se_retry) { @@ -1572,6 +1595,7 @@ relay_connect(struct rsession *con) } } + con->se_out.state = CONNECTED; relay_inflight--; DPRINTF("%s: inflight decremented, now %d",__func__, relay_inflight); @@ -1673,6 +1697,7 @@ relay_close(struct rsession *con, const char *msg) event_add(&rlay->rl_ev, NULL); } } + con->se_out.state = INIT; if (con->se_out.buf != NULL) free(con->se_out.buf); diff --git a/usr.sbin/relayd/relay_http.c b/usr.sbin/relayd/relay_http.c index e40014da9ef..7fc0cd9e633 100644 --- a/usr.sbin/relayd/relay_http.c +++ b/usr.sbin/relayd/relay_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay_http.c,v 1.48 2015/06/01 09:54:16 claudio Exp $ */ +/* $OpenBSD: relay_http.c,v 1.49 2015/06/08 15:47:51 claudio Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -421,7 +421,7 @@ relay_read_http(struct bufferevent *bev, void *arg) relay_reset_http(cre); done: if (cre->dir == RELAY_DIR_REQUEST && cre->toread <= 0 && - cre->dst->bev == NULL) { + cre->dst->state != CONNECTED) { if (rlay->rl_conf.fwdmode == FWD_TRANS) { relay_bindanyreq(con, 0, IPPROTO_TCP); return; diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index f9f2a0fb5da..f35eca57336 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.209 2015/05/02 13:15:24 claudio Exp $ */ +/* $OpenBSD: relayd.h,v 1.210 2015/06/08 15:47:51 claudio Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -200,6 +200,7 @@ struct ctl_relay_event { int line; int done; int timedout; + enum { INIT, PENDING, PRECONNECT, CONNECTED } state; enum direction dir; u_int8_t *buf; -- 2.20.1