diff options
-rw-r--r-- | usr.sbin/relayd/relay.c | 68 | ||||
-rw-r--r-- | usr.sbin/relayd/relay_http.c | 36 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 9 | ||||
-rw-r--r-- | usr.sbin/relayd/util.c | 25 |
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) { |