Reyk Floeter writes:
> Hi, > > the attached diff fixes filter rules with "forward to" statement in > persistent (keep-alive) connections. See the XXX comment below. > > ```relayd.conf > log connection > table <a> { > 127.0.0.1 > } > table <b> { > 127.0.0.1 > } > table <c> { > 127.0.0.1 > } > http protocol pathfwd { > return error > > # XXX The following workaround is not needed anymore: > #match header set "Connection" value "close" > > pass path "/a/*" forward to <a> > pass path "/b/*" forward to <b> > #match request path log "*" > } > relay pathfwd { > listen on 0.0.0.0 port 80 > protocol pathfwd > forward to <c> port 8082 > forward to <a> port 8080 > forward to <b> port 8081 > } > ``` > > OK? > Works great for us. FWIW, OK mikeb > reyk > > Index: usr.sbin/relayd/relay.c > =================================================================== > RCS file: /cvs/src/usr.sbin/relayd/relay.c,v > retrieving revision 1.242 > diff -u -p -u -p -r1.242 relay.c > --- usr.sbin/relayd/relay.c 4 Mar 2019 21:25:03 -0000 1.242 > +++ usr.sbin/relayd/relay.c 8 May 2019 14:26:40 -0000 > @@ -76,11 +76,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 *); > > @@ -654,6 +657,7 @@ relay_socket_listen(struct sockaddr_stor > 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; > @@ -696,6 +700,22 @@ relay_connected(int fd, short sig, void > > 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) { > @@ -1465,6 +1485,17 @@ relay_bindany(int fd, short event, void > } > > 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 }; > @@ -1533,9 +1564,9 @@ relay_connect_retry(int fd, short sig, v > } > > 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); > > @@ -1560,7 +1591,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); > } > > @@ -1585,7 +1616,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); > } > > @@ -1642,7 +1673,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) { > @@ -1660,7 +1691,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); > @@ -1686,10 +1717,6 @@ relay_close(struct rsession *con, const > 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) { > @@ -1726,7 +1753,8 @@ relay_close(struct rsession *con, const > > 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, > @@ -1740,7 +1768,8 @@ relay_close(struct rsession *con, const > 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); > @@ -1766,14 +1795,16 @@ relay_close(struct rsession *con, const > } > > 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); > @@ -1784,7 +1815,6 @@ relay_reset_event(struct ctl_relay_event > close(cre->s); > rv = 1; > } > - cre->state = STATE_DONE; > cre->bev = NULL; > cre->tls = NULL; > cre->tls_cfg = NULL; > Index: usr.sbin/relayd/relay_http.c > =================================================================== > RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v > retrieving revision 1.72 > diff -u -p -u -p -r1.72 relay_http.c > --- usr.sbin/relayd/relay_http.c 4 Mar 2019 21:25:03 -0000 1.72 > +++ usr.sbin/relayd/relay_http.c 8 May 2019 14:26:40 -0000 > @@ -71,9 +71,11 @@ int relay_httpurl_test(struct ctl_rela > 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; > @@ -1509,7 +1511,7 @@ relay_httpcookie_test(struct ctl_relay_e > > 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; > @@ -1518,11 +1520,9 @@ relay_match_actions(struct ctl_relay_eve > * 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; > > @@ -1546,7 +1546,8 @@ relay_match_actions(struct ctl_relay_eve > } > > 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; > @@ -1735,12 +1736,22 @@ relay_apply_actions(struct ctl_relay_eve > } > > /* > + * 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 ? "" : ";"); > @@ -1770,6 +1781,7 @@ relay_test(struct protocol *proto, struc > 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; > @@ -1820,7 +1832,7 @@ relay_test(struct protocol *proto, struc > > 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; > @@ -1854,13 +1866,13 @@ relay_test(struct protocol *proto, struc > } > } > > - 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; > } > Index: usr.sbin/relayd/relayd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v > retrieving revision 1.252 > diff -u -p -u -p -r1.252 relayd.h > --- usr.sbin/relayd/relayd.h 4 Mar 2019 21:25:03 -0000 1.252 > +++ usr.sbin/relayd/relayd.h 8 May 2019 14:26:40 -0000 > @@ -193,6 +193,7 @@ enum relay_state { > STATE_PENDING, > STATE_PRECONNECT, > STATE_CONNECTED, > + STATE_CLOSED, > STATE_DONE > }; > > @@ -555,6 +556,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; > @@ -1134,6 +1136,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); > @@ -1178,7 +1183,7 @@ int relay_session_cmp(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 *); > Index: usr.sbin/relayd/util.c > =================================================================== > RCS file: /cvs/src/usr.sbin/relayd/util.c,v > retrieving revision 1.1 > diff -u -p -u -p -r1.1 util.c > --- usr.sbin/relayd/util.c 21 Nov 2015 12:37:42 -0000 1.1 > +++ usr.sbin/relayd/util.c 8 May 2019 14:26:41 -0000 > @@ -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) > {