summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/relayd/relay.c68
-rw-r--r--usr.sbin/relayd/relay_http.c36
-rw-r--r--usr.sbin/relayd/relayd.h9
-rw-r--r--usr.sbin/relayd/util.c25
4 files changed, 104 insertions, 34 deletions
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index 997a5f7a02b..8661f1c4964 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.244 2019/05/10 09:15:00 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.245 2019/05/13 09:54:07 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -77,11 +77,14 @@ int relay_tls_ctx_create(struct relay *);
void relay_tls_transaction(struct rsession *,
struct ctl_relay_event *);
void relay_tls_handshake(int, short, void *);
-void relay_connect_retry(int, short, void *);
void relay_tls_connected(struct ctl_relay_event *);
void relay_tls_readcb(int, short, void *);
void relay_tls_writecb(int, short, void *);
+void relay_connect_retry(int, short, void *);
+void relay_connect_state(struct rsession *,
+ struct ctl_relay_event *, enum relay_state);
+
extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t,
size_t, void *);
@@ -675,6 +678,7 @@ relay_socket_listen(struct sockaddr_storage *ss, in_port_t port,
void
relay_connected(int fd, short sig, void *arg)
{
+ char obuf[128];
struct rsession *con = arg;
struct relay *rlay = con->se_relay;
struct protocol *proto = rlay->rl_proto;
@@ -717,6 +721,22 @@ relay_connected(int fd, short sig, void *arg)
DPRINTF("%s: session %d: successful", __func__, con->se_id);
+ /* Log destination if it was changed in a keep-alive connection */
+ if ((con->se_table != con->se_table0) &&
+ (env->sc_conf.opts & (RELAYD_OPT_LOGCON|RELAYD_OPT_LOGCONERR))) {
+ con->se_table0 = con->se_table;
+ memset(&obuf, 0, sizeof(obuf));
+ (void)print_host(&con->se_out.ss, obuf, sizeof(obuf));
+ if (asprintf(&msg, " -> %s:%d",
+ obuf, ntohs(con->se_out.port)) == -1) {
+ relay_abort_http(con, 500,
+ "connection changed and asprintf failed", 0);
+ return;
+ }
+ relay_log(con, msg);
+ free(msg);
+ }
+
switch (rlay->rl_proto->type) {
case RELAY_PROTO_HTTP:
if (relay_httpdesc_init(out) == -1) {
@@ -1477,6 +1497,17 @@ relay_bindany(int fd, short event, void *arg)
}
void
+relay_connect_state(struct rsession *con, struct ctl_relay_event *cre,
+ enum relay_state new)
+{
+ DPRINTF("%s: session %d: %s state %s -> %s",
+ __func__, con->se_id,
+ cre->dir == RELAY_DIR_REQUEST ? "accept" : "connect",
+ relay_state(cre->state), relay_state(new));
+ cre->state = new;
+}
+
+void
relay_connect_retry(int fd, short sig, void *arg)
{
struct timeval evtpause = { 1, 0 };
@@ -1545,9 +1576,9 @@ relay_connect_retry(int fd, short sig, void *arg)
}
if (rlay->rl_conf.flags & F_TLSINSPECT)
- con->se_out.state = STATE_PRECONNECT;
+ relay_connect_state(con, &con->se_out, STATE_PRECONNECT);
else
- con->se_out.state = STATE_CONNECTED;
+ relay_connect_state(con, &con->se_out, STATE_CONNECTED);
relay_inflight--;
DPRINTF("%s: inflight decremented, now %d",__func__, relay_inflight);
@@ -1572,7 +1603,7 @@ relay_preconnect(struct rsession *con)
con->se_id, privsep_process);
rv = relay_connect(con);
if (con->se_out.state == STATE_CONNECTED)
- con->se_out.state = STATE_PRECONNECT;
+ relay_connect_state(con, &con->se_out, STATE_PRECONNECT);
return (rv);
}
@@ -1597,7 +1628,7 @@ relay_connect(struct rsession *con)
return (-1);
}
relay_connected(con->se_out.s, EV_WRITE, con);
- con->se_out.state = STATE_CONNECTED;
+ relay_connect_state(con, &con->se_out, STATE_CONNECTED);
return (0);
}
@@ -1654,7 +1685,7 @@ relay_connect(struct rsession *con)
evtimer_add(&rlay->rl_evt, &evtpause);
/* this connect is pending */
- con->se_out.state = STATE_PENDING;
+ relay_connect_state(con, &con->se_out, STATE_PENDING);
return (0);
} else {
if (con->se_retry) {
@@ -1672,7 +1703,7 @@ relay_connect(struct rsession *con)
}
}
- con->se_out.state = STATE_CONNECTED;
+ relay_connect_state(con, &con->se_out, STATE_CONNECTED);
relay_inflight--;
DPRINTF("%s: inflight decremented, now %d",__func__,
relay_inflight);
@@ -1698,10 +1729,6 @@ relay_close(struct rsession *con, const char *msg, int err)
relay_session_unpublish(con);
event_del(&con->se_ev);
- if (con->se_in.bev != NULL)
- bufferevent_disable(con->se_in.bev, EV_READ|EV_WRITE);
- if (con->se_out.bev != NULL)
- bufferevent_disable(con->se_out.bev, EV_READ|EV_WRITE);
if ((env->sc_conf.opts & (RELAYD_OPT_LOGCON|RELAYD_OPT_LOGCONERR)) &&
msg != NULL) {
@@ -1738,7 +1765,8 @@ relay_close(struct rsession *con, const char *msg, int err)
free(con->se_priv);
- if (relay_reset_event(&con->se_in)) {
+ relay_connect_state(con, &con->se_in, STATE_DONE);
+ if (relay_reset_event(con, &con->se_in)) {
if (con->se_out.s == -1) {
/*
* the output was never connected,
@@ -1752,7 +1780,8 @@ relay_close(struct rsession *con, const char *msg, int err)
if (con->se_in.output != NULL)
evbuffer_free(con->se_in.output);
- if (relay_reset_event(&con->se_out)) {
+ relay_connect_state(con, &con->se_out, STATE_DONE);
+ if (relay_reset_event(con, &con->se_out)) {
/* Some file descriptors are available again. */
if (evtimer_pending(&rlay->rl_evt, NULL)) {
evtimer_del(&rlay->rl_evt);
@@ -1778,14 +1807,16 @@ relay_close(struct rsession *con, const char *msg, int err)
}
int
-relay_reset_event(struct ctl_relay_event *cre)
+relay_reset_event(struct rsession *con, struct ctl_relay_event *cre)
{
int rv = 0;
- DPRINTF("%s: state %d dir %d", __func__, cre->state, cre->dir);
-
- if (cre->bev != NULL)
+ if (cre->state != STATE_DONE)
+ relay_connect_state(con, cre, STATE_CLOSED);
+ if (cre->bev != NULL) {
+ bufferevent_disable(cre->bev, EV_READ|EV_WRITE);
bufferevent_free(cre->bev);
+ }
if (cre->tls != NULL)
tls_close(cre->tls);
tls_free(cre->tls);
@@ -1796,7 +1827,6 @@ relay_reset_event(struct ctl_relay_event *cre)
close(cre->s);
rv = 1;
}
- cre->state = STATE_DONE;
cre->bev = NULL;
cre->tls = NULL;
cre->tls_cfg = NULL;
diff --git a/usr.sbin/relayd/relay_http.c b/usr.sbin/relayd/relay_http.c
index fb51ccb87a6..82ed343e48d 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.74 2019/05/10 09:15:00 reyk Exp $ */
+/* $OpenBSD: relay_http.c,v 1.75 2019/05/13 09:54:07 reyk Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -71,9 +71,11 @@ int relay_httpurl_test(struct ctl_relay_event *,
struct relay_rule *, struct kvlist *);
int relay_httpcookie_test(struct ctl_relay_event *,
struct relay_rule *, struct kvlist *);
-int relay_apply_actions(struct ctl_relay_event *, struct kvlist *);
+int relay_apply_actions(struct ctl_relay_event *, struct kvlist *,
+ struct relay_table *);
int relay_match_actions(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *, struct kvlist *);
+ struct relay_rule *, struct kvlist *, struct kvlist *,
+ struct relay_table **);
void relay_httpdesc_free(struct http_descriptor *);
static struct relayd *env = NULL;
@@ -1484,7 +1486,7 @@ relay_httpcookie_test(struct ctl_relay_event *cre, struct relay_rule *rule,
int
relay_match_actions(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *matches, struct kvlist *actions)
+ struct kvlist *matches, struct kvlist *actions, struct relay_table **tbl)
{
struct rsession *con = cre->con;
struct kv *kv, *tmp;
@@ -1493,11 +1495,9 @@ relay_match_actions(struct ctl_relay_event *cre, struct relay_rule *rule,
* Apply the following options instantly (action per match).
*/
if (rule->rule_table != NULL)
- con->se_table = rule->rule_table;
-
+ *tbl = rule->rule_table;
if (rule->rule_tag != 0)
con->se_tag = rule->rule_tag == -1 ? 0 : rule->rule_tag;
-
if (rule->rule_label != 0)
con->se_label = rule->rule_label == -1 ? 0 : rule->rule_label;
@@ -1521,7 +1521,8 @@ relay_match_actions(struct ctl_relay_event *cre, struct relay_rule *rule,
}
int
-relay_apply_actions(struct ctl_relay_event *cre, struct kvlist *actions)
+relay_apply_actions(struct ctl_relay_event *cre, struct kvlist *actions,
+ struct relay_table *tbl)
{
struct rsession *con = cre->con;
struct http_descriptor *desc = cre->desc;
@@ -1710,12 +1711,22 @@ relay_apply_actions(struct ctl_relay_event *cre, struct kvlist *actions)
}
/*
+ * Change the backend if the forward table has been changed.
+ * This only works in the request direction.
+ */
+ if (cre->dir == RELAY_DIR_REQUEST && con->se_table != tbl) {
+ relay_reset_event(con, &con->se_out);
+ con->se_table = tbl;
+ con->se_haslog = 1;
+ }
+
+ /*
* log tag for request and response, request method
* and end of request marker ","
*/
if ((con->se_log != NULL) &&
((meth = relay_httpmethod_byid(desc->http_method)) != NULL) &&
- (asprintf(&msg, " %s",meth) >= 0))
+ (asprintf(&msg, " %s", meth) != -1))
evbuffer_add(con->se_log, msg, strlen(msg));
free(msg);
relay_log(con, cre->dir == RELAY_DIR_REQUEST ? "" : ";");
@@ -1745,6 +1756,7 @@ relay_test(struct protocol *proto, struct ctl_relay_event *cre)
struct rsession *con;
struct http_descriptor *desc = cre->desc;
struct relay_rule *r = NULL, *rule = NULL;
+ struct relay_table *tbl = NULL;
u_int cnt = 0;
u_int action = RES_PASS;
struct kvlist actions, matches;
@@ -1794,7 +1806,7 @@ relay_test(struct protocol *proto, struct ctl_relay_event *cre)
if (r->rule_action == RULE_ACTION_MATCH) {
if (relay_match_actions(cre, r, &matches,
- &actions) != 0) {
+ &actions, &tbl) != 0) {
/* Something bad happened, drop */
action = RES_DROP;
break;
@@ -1828,13 +1840,13 @@ relay_test(struct protocol *proto, struct ctl_relay_event *cre)
}
}
- if (rule != NULL && relay_match_actions(cre, rule, NULL, &actions)
+ if (rule != NULL && relay_match_actions(cre, rule, NULL, &actions, &tbl)
!= 0) {
/* Something bad happened, drop */
action = RES_DROP;
}
- if (relay_apply_actions(cre, &actions) != 0) {
+ if (relay_apply_actions(cre, &actions, tbl) != 0) {
/* Something bad happened, drop */
action = RES_DROP;
}
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index 4f07ae1c9fe..552332b9056 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.254 2019/05/10 09:15:00 reyk Exp $ */
+/* $OpenBSD: relayd.h,v 1.255 2019/05/13 09:54:07 reyk Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -193,6 +193,7 @@ enum relay_state {
STATE_PENDING,
STATE_PRECONNECT,
STATE_CONNECTED,
+ STATE_CLOSED,
STATE_DONE
};
@@ -556,6 +557,7 @@ struct rsession {
void *se_priv;
SIPHASH_CTX se_siphashctx;
struct relay_table *se_table;
+ struct relay_table *se_table0;
struct event se_ev;
struct timeval se_timeout;
struct timeval se_tv_start;
@@ -1137,6 +1139,9 @@ int cmdline_symset(char *);
const char *host_error(enum host_error);
const char *host_status(enum host_status);
const char *table_check(enum table_check);
+#ifdef DEBUG
+const char *relay_state(enum relay_state);
+#endif
const char *print_availability(u_long, u_long);
const char *print_host(struct sockaddr_storage *, char *, size_t);
const char *print_time(struct timeval *, struct timeval *, char *, size_t);
@@ -1181,7 +1186,7 @@ int relay_session_cmp(struct rsession *, struct rsession *);
char *relay_load_fd(int, off_t *);
int relay_load_certfiles(struct relay *);
void relay_close(struct rsession *, const char *, int);
-int relay_reset_event(struct ctl_relay_event *);
+int relay_reset_event(struct rsession *, struct ctl_relay_event *);
void relay_natlook(int, short, void *);
void relay_session(struct rsession *);
int relay_from_table(struct rsession *);
diff --git a/usr.sbin/relayd/util.c b/usr.sbin/relayd/util.c
index a06b6b2e731..a566a4bc9f6 100644
--- a/usr.sbin/relayd/util.c
+++ b/usr.sbin/relayd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.1 2015/11/21 12:37:42 reyk Exp $ */
+/* $OpenBSD: util.c,v 1.2 2019/05/13 09:54:07 reyk Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -177,6 +177,29 @@ table_check(enum table_check check)
return ("invalid");
}
+#ifdef DEBUG
+const char *
+relay_state(enum relay_state state)
+{
+ switch (state) {
+ case STATE_INIT:
+ return ("init");
+ case STATE_PENDING:
+ return ("pending");
+ case STATE_PRECONNECT:
+ return ("preconnect");
+ case STATE_CONNECTED:
+ return ("connected");
+ case STATE_CLOSED:
+ return ("closed");
+ case STATE_DONE:
+ return ("done");
+ };
+ /* NOTREACHED */
+ return ("invalid");
+}
+#endif
+
const char *
print_availability(u_long cnt, u_long up)
{