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)
>  {

Reply via email to