relayd: add from/to filter options

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

relayd: add from/to filter options

Reyk Floeter-2
Hi,

the relayd code already had a few bits for from/to specifiers in
filter rules, but it wasn't finished.  I did get occasional requests
if it would be possible to filter based on IPs (much like Allow/Deny
rules elsewhere).  Simple blocking should better be done in pf but the
purpose of this is to match URLs/headers related to IPs (see below).

```relayd.conf
http protocol foo {
        block from 10.1.1.1
        block from 10.1.1.2 to 192.168.0.0/24
        pass from 10.1.0.0/16 path "/hello/*" forward to <a>
        pass from 10.2.0.0/16 path "/hello/*" forward to <b>
}
```

Ok?

Reyk

Index: usr.sbin/relayd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.233
diff -u -p -u -p -r1.233 parse.y
--- usr.sbin/relayd/parse.y 13 Mar 2019 23:29:32 -0000 1.233
+++ usr.sbin/relayd/parse.y 9 May 2019 17:12:09 -0000
@@ -153,6 +153,7 @@ typedef struct {
  enum direction dir;
  struct {
  struct sockaddr_storage ss;
+ int prefixlen;
  char name[HOST_NAME_MAX+1];
  } addr;
  struct {
@@ -187,7 +188,7 @@ typedef struct {
 %type <v.number> action ruleaf key_option
 %type <v.port> port
 %type <v.host> host
-%type <v.addr> address
+%type <v.addr> address rulesrc ruledst addrprefix
 %type <v.tv> timeout
 %type <v.digest> digest optdigest
 %type <v.table> tablespec
@@ -1293,6 +1294,20 @@ filterrule : action dir quick ruleaf rul
  rule->rule_dir = $2;
  rule->rule_flags |= $3;
  rule->rule_af = $4;
+ rule->rule_src.addr = $5.ss;
+ rule->rule_src.addr_mask = $5.prefixlen;
+ rule->rule_dst.addr = $6.ss;
+ rule->rule_dst.addr_mask = $6.prefixlen;
+
+ if (RELAY_AF_NEQ(rule->rule_af,
+    rule->rule_src.addr.ss_family) ||
+    RELAY_AF_NEQ(rule->rule_af,
+    rule->rule_dst.addr.ss_family) ||
+    RELAY_AF_NEQ(rule->rule_src.addr.ss_family,
+    rule->rule_dst.addr.ss_family)) {
+ yyerror("address family mismatch");
+ YYERROR;
+ }
 
  rulefile = NULL;
  } ruleopts_l {
@@ -1341,10 +1356,20 @@ ruleaf : /* empty */ { $$ = AF_UNSPEC
  | INET { $$ = AF_INET; }
  ;
 
-rulesrc : /* XXX */
+rulesrc : /* empty */ {
+ memset(&$$, 0, sizeof($$));
+ }
+ | FROM addrprefix {
+ $$ = $2;
+ }
  ;
 
-ruledst : /* XXX */
+ruledst : /* empty */ {
+ memset(&$$, 0, sizeof($$));
+ }
+ | TO addrprefix {
+ $$ = $2;
+ }
  ;
 
 ruleopts_l : /* empty */
@@ -1967,7 +1992,7 @@ routeopts_l : routeopts_l routeoptsl nl
  | routeoptsl optnl
  ;
 
-routeoptsl : ROUTE address '/' NUMBER {
+routeoptsl : ROUTE addrprefix {
  struct netroute *nr;
 
  if (router->rt_conf.af == AF_UNSPEC)
@@ -1978,14 +2003,6 @@ routeoptsl : ROUTE address '/' NUMBER {
  YYERROR;
  }
 
- if ((router->rt_conf.af == AF_INET &&
-    ($4 > 32 || $4 < 0)) ||
-    (router->rt_conf.af == AF_INET6 &&
-    ($4 > 128 || $4 < 0))) {
- yyerror("invalid prefixlen %d", $4);
- YYERROR;
- }
-
  if ((nr = calloc(1, sizeof(*nr))) == NULL)
  fatal("out of memory");
 
@@ -1995,7 +2012,7 @@ routeoptsl : ROUTE address '/' NUMBER {
  free(nr);
  YYERROR;
  }
- nr->nr_conf.prefixlen = $4;
+ nr->nr_conf.prefixlen = $2.prefixlen;
  nr->nr_conf.routerid = router->rt_conf.id;
  nr->nr_router = router;
  bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss));
@@ -2166,6 +2183,26 @@ address : STRING {
  h = TAILQ_FIRST(&al);
  memcpy(&$$.ss, &h->ss, sizeof($$.ss));
  host_free(&al);
+ }
+ ;
+
+addrprefix : address '/' NUMBER {
+ $$ = $1;
+ if (($$.ss.ss_family == AF_INET &&
+    ($3 > 32 || $3 < 0)) ||
+    ($$.ss.ss_family == AF_INET6 &&
+    ($3 > 128 || $3 < 0))) {
+ yyerror("invalid prefixlen %d", $3);
+ YYERROR;
+ }
+ $$.prefixlen = $3;
+ }
+ | address {
+ $$ = $1;
+ if ($$.ss.ss_family == AF_INET)
+ $$.prefixlen = 32;
+ else if ($$.ss.ss_family == AF_INET6)
+ $$.prefixlen = 128;
  }
  ;
 
Index: usr.sbin/relayd/relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.243
diff -u -p -u -p -r1.243 relay.c
--- usr.sbin/relayd/relay.c 8 May 2019 23:22:19 -0000 1.243
+++ usr.sbin/relayd/relay.c 9 May 2019 17:12:09 -0000
@@ -28,6 +28,7 @@
 #include <arpa/inet.h>
 
 #include <limits.h>
+#include <netdb.h>
 #include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -117,6 +118,7 @@ relay_ruledebug(struct relay_rule *rule)
 {
  struct kv *kv = NULL;
  u_int i;
+ char buf[NI_MAXHOST];
 
  fprintf(stderr, "\t\t");
 
@@ -150,6 +152,25 @@ relay_ruledebug(struct relay_rule *rule)
  if (rule->rule_flags & RULE_FLAG_QUICK)
  fprintf(stderr, "quick ");
 
+ switch (rule->rule_af) {
+ case AF_INET:
+ fprintf(stderr, "inet ");
+ break;
+ case AF_INET6:
+ fprintf(stderr, "inet6 ");
+ break;
+ }
+
+ if (rule->rule_src.addr.ss_family != AF_UNSPEC)
+ fprintf(stderr, "from %s/%d ",
+    print_host(&rule->rule_src.addr, buf, sizeof(buf)),
+    rule->rule_src.addr_mask);
+
+ if (rule->rule_dst.addr.ss_family != AF_UNSPEC)
+ fprintf(stderr, "to %s/%d ",
+    print_host(&rule->rule_dst.addr, buf, sizeof(buf)),
+    rule->rule_dst.addr_mask);
+
  for (i = 1; i < KEY_TYPE_MAX; i++) {
  kv = &rule->rule_kv[i];
  if (kv->kv_type != i)
@@ -1118,7 +1139,13 @@ relay_accept(int fd, short event, void *
  con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port;
  break;
  }
- bcopy(&ss, &con->se_in.ss, sizeof(con->se_in.ss));
+ memcpy(&con->se_in.ss, &ss, sizeof(con->se_in.ss));
+
+ slen = sizeof(con->se_sockname);
+ if (getsockname(s, (struct sockaddr *)&con->se_sockname, &slen) == -1) {
+ relay_close(con, "sockname lookup failed", 1);
+ return;
+ }
 
  getmonotime(&con->se_tv_start);
  bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last));
@@ -1143,12 +1170,8 @@ relay_accept(int fd, short event, void *
  }
 
  if (rlay->rl_conf.flags & F_DIVERT) {
- slen = sizeof(con->se_out.ss);
- if (getsockname(s, (struct sockaddr *)&con->se_out.ss,
-    &slen) == -1) {
- relay_close(con, "peer lookup failed", 1);
- return;
- }
+ memcpy(&con->se_out.ss, &con->se_sockname,
+    sizeof(con->se_out.ss));
  con->se_out.port = relay_socket_getport(&con->se_out.ss);
 
  /* Detect loop and fall back to the alternate forward target */
@@ -1169,13 +1192,8 @@ relay_accept(int fd, short event, void *
  cnl->proc = ps->ps_instance;
  cnl->proto = IPPROTO_TCP;
 
- bcopy(&con->se_in.ss, &cnl->src, sizeof(cnl->src));
- slen = sizeof(cnl->dst);
- if (getsockname(s,
-    (struct sockaddr *)&cnl->dst, &slen) == -1) {
- relay_close(con, "failed to get local address", 1);
- return;
- }
+ memcpy(&cnl->src, &con->se_in.ss, sizeof(cnl->src));
+ memcpy(&cnl->dst, &con->se_sockname, sizeof(cnl->dst));
 
  proc_compose(env->sc_ps, PROC_PFE, IMSG_NATLOOK,
     cnl, sizeof(*cnl));
Index: usr.sbin/relayd/relay_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v
retrieving revision 1.73
diff -u -p -u -p -r1.73 relay_http.c
--- usr.sbin/relayd/relay_http.c 8 May 2019 23:22:19 -0000 1.73
+++ usr.sbin/relayd/relay_http.c 9 May 2019 17:12:09 -0000
@@ -1765,13 +1765,12 @@ relay_test(struct protocol *proto, struc
  RELAY_GET_SKIP_STEP(RULE_SKIP_DIR);
  else if (proto->type != r->rule_proto)
  RELAY_GET_SKIP_STEP(RULE_SKIP_PROTO);
- else if (r->rule_af != AF_UNSPEC &&
-    (cre->ss.ss_family != r->rule_af ||
-     cre->dst->ss.ss_family != r->rule_af))
+ else if (RELAY_AF_NEQ(r->rule_af, cre->ss.ss_family) ||
+     RELAY_AF_NEQ(r->rule_af, cre->dst->ss.ss_family))
  RELAY_GET_SKIP_STEP(RULE_SKIP_AF);
  else if (RELAY_ADDR_CMP(&r->rule_src, &cre->ss) != 0)
  RELAY_GET_SKIP_STEP(RULE_SKIP_SRC);
- else if (RELAY_ADDR_CMP(&r->rule_dst, &cre->dst->ss) != 0)
+ else if (RELAY_ADDR_CMP(&r->rule_dst, &con->se_sockname) != 0)
  RELAY_GET_SKIP_STEP(RULE_SKIP_DST);
  else if (r->rule_method != HTTP_METHOD_NONE &&
     (desc->http_method == HTTP_METHOD_RESPONSE ||
@@ -1870,7 +1869,7 @@ relay_calc_skip_steps(struct relay_rules
  RELAY_SET_SKIP_STEPS(RULE_SKIP_DIR);
  else if (cur->rule_proto != prev->rule_proto)
  RELAY_SET_SKIP_STEPS(RULE_SKIP_PROTO);
- else if (cur->rule_af != prev->rule_af)
+ else if (RELAY_AF_NEQ(cur->rule_af, prev->rule_af))
  RELAY_SET_SKIP_STEPS(RULE_SKIP_AF);
  else if (RELAY_ADDR_NEQ(&cur->rule_src, &prev->rule_src))
  RELAY_SET_SKIP_STEPS(RULE_SKIP_SRC);
Index: usr.sbin/relayd/relayd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
retrieving revision 1.188
diff -u -p -u -p -r1.188 relayd.conf.5
--- usr.sbin/relayd/relayd.conf.5 4 Mar 2019 21:25:03 -0000 1.188
+++ usr.sbin/relayd/relayd.conf.5 9 May 2019 17:12:09 -0000
@@ -1080,6 +1080,13 @@ evaluation is skipped.
 .It Ic inet No or Ic inet6
 Only match connections with the specified address family,
 either of type IPv4 or IPv6.
+.It Ic from Ar address Ns Oo Li / Ns Ar prefix Oc
+This rule only matches for connections from the specified source.
+.It Ic to Ar address Ns Oo Li / Ns Ar prefix Oc
+This rule only matches for connections to the specified destination.
+The destination is the address the client was connecting to,
+typically the relay's listen address in non-transparent mode,
+not the address of the forwarded backend connection.
 .It Ic forward to Pf < Ar table Ns >
 Forward the request to a server in the specified table.
 With this option, requests can be passed to specific backend servers.
Index: usr.sbin/relayd/relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.253
diff -u -p -u -p -r1.253 relayd.h
--- usr.sbin/relayd/relayd.h 8 May 2019 23:22:19 -0000 1.253
+++ usr.sbin/relayd/relayd.h 9 May 2019 17:12:09 -0000
@@ -550,6 +550,7 @@ TAILQ_HEAD(rdrlist, rdr);
 struct rsession {
  objid_t se_id;
  objid_t se_relayid;
+ struct sockaddr_storage se_sockname;
  struct ctl_relay_event se_in;
  struct ctl_relay_event se_out;
  void *se_priv;
@@ -601,11 +602,9 @@ enum rule_action {
 };
 
 struct rule_addr {
- int addr_af;
  struct sockaddr_storage addr;
  u_int8_t addr_mask;
- int addr_net;
- in_port_t addr_port;
+ int addr_port;
 };
 
 #define RELAY_ADDR_EQ(_a, _b) \
@@ -621,6 +620,10 @@ struct rule_addr {
  ((_a)->addr_mask != (_b)->addr_mask || \
  sockaddr_cmp((struct sockaddr *)&(_a)->addr, \
  (struct sockaddr *)&(_b)->addr, (_a)->addr_mask) != 0)
+
+#define RELAY_AF_NEQ(_a, _b) \
+ (((_a) != AF_UNSPEC) && ((_b) != AF_UNSPEC) && \
+ ((_a) != (_b)))
 
 struct relay_rule {
  objid_t rule_id;

Reply | Threaded
Open this post in threaded view
|

Re: relayd: add from/to filter options

Sebastian Benoit-3
ok


Reyk Floeter([hidden email]) on 2019.05.09 19:27:31 +0200:

> Hi,
>
> the relayd code already had a few bits for from/to specifiers in
> filter rules, but it wasn't finished.  I did get occasional requests
> if it would be possible to filter based on IPs (much like Allow/Deny
> rules elsewhere).  Simple blocking should better be done in pf but the
> purpose of this is to match URLs/headers related to IPs (see below).
>
> ```relayd.conf
> http protocol foo {
> block from 10.1.1.1
> block from 10.1.1.2 to 192.168.0.0/24
> pass from 10.1.0.0/16 path "/hello/*" forward to <a>
> pass from 10.2.0.0/16 path "/hello/*" forward to <b>
> }
> ```
>
> Ok?
>
> Reyk
>
> Index: usr.sbin/relayd/parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
> retrieving revision 1.233
> diff -u -p -u -p -r1.233 parse.y
> --- usr.sbin/relayd/parse.y 13 Mar 2019 23:29:32 -0000 1.233
> +++ usr.sbin/relayd/parse.y 9 May 2019 17:12:09 -0000
> @@ -153,6 +153,7 @@ typedef struct {
>   enum direction dir;
>   struct {
>   struct sockaddr_storage ss;
> + int prefixlen;
>   char name[HOST_NAME_MAX+1];
>   } addr;
>   struct {
> @@ -187,7 +188,7 @@ typedef struct {
>  %type <v.number> action ruleaf key_option
>  %type <v.port> port
>  %type <v.host> host
> -%type <v.addr> address
> +%type <v.addr> address rulesrc ruledst addrprefix
>  %type <v.tv> timeout
>  %type <v.digest> digest optdigest
>  %type <v.table> tablespec
> @@ -1293,6 +1294,20 @@ filterrule : action dir quick ruleaf rul
>   rule->rule_dir = $2;
>   rule->rule_flags |= $3;
>   rule->rule_af = $4;
> + rule->rule_src.addr = $5.ss;
> + rule->rule_src.addr_mask = $5.prefixlen;
> + rule->rule_dst.addr = $6.ss;
> + rule->rule_dst.addr_mask = $6.prefixlen;
> +
> + if (RELAY_AF_NEQ(rule->rule_af,
> +    rule->rule_src.addr.ss_family) ||
> +    RELAY_AF_NEQ(rule->rule_af,
> +    rule->rule_dst.addr.ss_family) ||
> +    RELAY_AF_NEQ(rule->rule_src.addr.ss_family,
> +    rule->rule_dst.addr.ss_family)) {
> + yyerror("address family mismatch");
> + YYERROR;
> + }
>  
>   rulefile = NULL;
>   } ruleopts_l {
> @@ -1341,10 +1356,20 @@ ruleaf : /* empty */ { $$ = AF_UNSPEC
>   | INET { $$ = AF_INET; }
>   ;
>  
> -rulesrc : /* XXX */
> +rulesrc : /* empty */ {
> + memset(&$$, 0, sizeof($$));
> + }
> + | FROM addrprefix {
> + $$ = $2;
> + }
>   ;
>  
> -ruledst : /* XXX */
> +ruledst : /* empty */ {
> + memset(&$$, 0, sizeof($$));
> + }
> + | TO addrprefix {
> + $$ = $2;
> + }
>   ;
>  
>  ruleopts_l : /* empty */
> @@ -1967,7 +1992,7 @@ routeopts_l : routeopts_l routeoptsl nl
>   | routeoptsl optnl
>   ;
>  
> -routeoptsl : ROUTE address '/' NUMBER {
> +routeoptsl : ROUTE addrprefix {
>   struct netroute *nr;
>  
>   if (router->rt_conf.af == AF_UNSPEC)
> @@ -1978,14 +2003,6 @@ routeoptsl : ROUTE address '/' NUMBER {
>   YYERROR;
>   }
>  
> - if ((router->rt_conf.af == AF_INET &&
> -    ($4 > 32 || $4 < 0)) ||
> -    (router->rt_conf.af == AF_INET6 &&
> -    ($4 > 128 || $4 < 0))) {
> - yyerror("invalid prefixlen %d", $4);
> - YYERROR;
> - }
> -
>   if ((nr = calloc(1, sizeof(*nr))) == NULL)
>   fatal("out of memory");
>  
> @@ -1995,7 +2012,7 @@ routeoptsl : ROUTE address '/' NUMBER {
>   free(nr);
>   YYERROR;
>   }
> - nr->nr_conf.prefixlen = $4;
> + nr->nr_conf.prefixlen = $2.prefixlen;
>   nr->nr_conf.routerid = router->rt_conf.id;
>   nr->nr_router = router;
>   bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss));
> @@ -2166,6 +2183,26 @@ address : STRING {
>   h = TAILQ_FIRST(&al);
>   memcpy(&$$.ss, &h->ss, sizeof($$.ss));
>   host_free(&al);
> + }
> + ;
> +
> +addrprefix : address '/' NUMBER {
> + $$ = $1;
> + if (($$.ss.ss_family == AF_INET &&
> +    ($3 > 32 || $3 < 0)) ||
> +    ($$.ss.ss_family == AF_INET6 &&
> +    ($3 > 128 || $3 < 0))) {
> + yyerror("invalid prefixlen %d", $3);
> + YYERROR;
> + }
> + $$.prefixlen = $3;
> + }
> + | address {
> + $$ = $1;
> + if ($$.ss.ss_family == AF_INET)
> + $$.prefixlen = 32;
> + else if ($$.ss.ss_family == AF_INET6)
> + $$.prefixlen = 128;
>   }
>   ;
>  
> Index: usr.sbin/relayd/relay.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
> retrieving revision 1.243
> diff -u -p -u -p -r1.243 relay.c
> --- usr.sbin/relayd/relay.c 8 May 2019 23:22:19 -0000 1.243
> +++ usr.sbin/relayd/relay.c 9 May 2019 17:12:09 -0000
> @@ -28,6 +28,7 @@
>  #include <arpa/inet.h>
>  
>  #include <limits.h>
> +#include <netdb.h>
>  #include <poll.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -117,6 +118,7 @@ relay_ruledebug(struct relay_rule *rule)
>  {
>   struct kv *kv = NULL;
>   u_int i;
> + char buf[NI_MAXHOST];
>  
>   fprintf(stderr, "\t\t");
>  
> @@ -150,6 +152,25 @@ relay_ruledebug(struct relay_rule *rule)
>   if (rule->rule_flags & RULE_FLAG_QUICK)
>   fprintf(stderr, "quick ");
>  
> + switch (rule->rule_af) {
> + case AF_INET:
> + fprintf(stderr, "inet ");
> + break;
> + case AF_INET6:
> + fprintf(stderr, "inet6 ");
> + break;
> + }
> +
> + if (rule->rule_src.addr.ss_family != AF_UNSPEC)
> + fprintf(stderr, "from %s/%d ",
> +    print_host(&rule->rule_src.addr, buf, sizeof(buf)),
> +    rule->rule_src.addr_mask);
> +
> + if (rule->rule_dst.addr.ss_family != AF_UNSPEC)
> + fprintf(stderr, "to %s/%d ",
> +    print_host(&rule->rule_dst.addr, buf, sizeof(buf)),
> +    rule->rule_dst.addr_mask);
> +
>   for (i = 1; i < KEY_TYPE_MAX; i++) {
>   kv = &rule->rule_kv[i];
>   if (kv->kv_type != i)
> @@ -1118,7 +1139,13 @@ relay_accept(int fd, short event, void *
>   con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port;
>   break;
>   }
> - bcopy(&ss, &con->se_in.ss, sizeof(con->se_in.ss));
> + memcpy(&con->se_in.ss, &ss, sizeof(con->se_in.ss));
> +
> + slen = sizeof(con->se_sockname);
> + if (getsockname(s, (struct sockaddr *)&con->se_sockname, &slen) == -1) {
> + relay_close(con, "sockname lookup failed", 1);
> + return;
> + }
>  
>   getmonotime(&con->se_tv_start);
>   bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last));
> @@ -1143,12 +1170,8 @@ relay_accept(int fd, short event, void *
>   }
>  
>   if (rlay->rl_conf.flags & F_DIVERT) {
> - slen = sizeof(con->se_out.ss);
> - if (getsockname(s, (struct sockaddr *)&con->se_out.ss,
> -    &slen) == -1) {
> - relay_close(con, "peer lookup failed", 1);
> - return;
> - }
> + memcpy(&con->se_out.ss, &con->se_sockname,
> +    sizeof(con->se_out.ss));
>   con->se_out.port = relay_socket_getport(&con->se_out.ss);
>  
>   /* Detect loop and fall back to the alternate forward target */
> @@ -1169,13 +1192,8 @@ relay_accept(int fd, short event, void *
>   cnl->proc = ps->ps_instance;
>   cnl->proto = IPPROTO_TCP;
>  
> - bcopy(&con->se_in.ss, &cnl->src, sizeof(cnl->src));
> - slen = sizeof(cnl->dst);
> - if (getsockname(s,
> -    (struct sockaddr *)&cnl->dst, &slen) == -1) {
> - relay_close(con, "failed to get local address", 1);
> - return;
> - }
> + memcpy(&cnl->src, &con->se_in.ss, sizeof(cnl->src));
> + memcpy(&cnl->dst, &con->se_sockname, sizeof(cnl->dst));
>  
>   proc_compose(env->sc_ps, PROC_PFE, IMSG_NATLOOK,
>      cnl, sizeof(*cnl));
> Index: usr.sbin/relayd/relay_http.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v
> retrieving revision 1.73
> diff -u -p -u -p -r1.73 relay_http.c
> --- usr.sbin/relayd/relay_http.c 8 May 2019 23:22:19 -0000 1.73
> +++ usr.sbin/relayd/relay_http.c 9 May 2019 17:12:09 -0000
> @@ -1765,13 +1765,12 @@ relay_test(struct protocol *proto, struc
>   RELAY_GET_SKIP_STEP(RULE_SKIP_DIR);
>   else if (proto->type != r->rule_proto)
>   RELAY_GET_SKIP_STEP(RULE_SKIP_PROTO);
> - else if (r->rule_af != AF_UNSPEC &&
> -    (cre->ss.ss_family != r->rule_af ||
> -     cre->dst->ss.ss_family != r->rule_af))
> + else if (RELAY_AF_NEQ(r->rule_af, cre->ss.ss_family) ||
> +     RELAY_AF_NEQ(r->rule_af, cre->dst->ss.ss_family))
>   RELAY_GET_SKIP_STEP(RULE_SKIP_AF);
>   else if (RELAY_ADDR_CMP(&r->rule_src, &cre->ss) != 0)
>   RELAY_GET_SKIP_STEP(RULE_SKIP_SRC);
> - else if (RELAY_ADDR_CMP(&r->rule_dst, &cre->dst->ss) != 0)
> + else if (RELAY_ADDR_CMP(&r->rule_dst, &con->se_sockname) != 0)
>   RELAY_GET_SKIP_STEP(RULE_SKIP_DST);
>   else if (r->rule_method != HTTP_METHOD_NONE &&
>      (desc->http_method == HTTP_METHOD_RESPONSE ||
> @@ -1870,7 +1869,7 @@ relay_calc_skip_steps(struct relay_rules
>   RELAY_SET_SKIP_STEPS(RULE_SKIP_DIR);
>   else if (cur->rule_proto != prev->rule_proto)
>   RELAY_SET_SKIP_STEPS(RULE_SKIP_PROTO);
> - else if (cur->rule_af != prev->rule_af)
> + else if (RELAY_AF_NEQ(cur->rule_af, prev->rule_af))
>   RELAY_SET_SKIP_STEPS(RULE_SKIP_AF);
>   else if (RELAY_ADDR_NEQ(&cur->rule_src, &prev->rule_src))
>   RELAY_SET_SKIP_STEPS(RULE_SKIP_SRC);
> Index: usr.sbin/relayd/relayd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
> retrieving revision 1.188
> diff -u -p -u -p -r1.188 relayd.conf.5
> --- usr.sbin/relayd/relayd.conf.5 4 Mar 2019 21:25:03 -0000 1.188
> +++ usr.sbin/relayd/relayd.conf.5 9 May 2019 17:12:09 -0000
> @@ -1080,6 +1080,13 @@ evaluation is skipped.
>  .It Ic inet No or Ic inet6
>  Only match connections with the specified address family,
>  either of type IPv4 or IPv6.
> +.It Ic from Ar address Ns Oo Li / Ns Ar prefix Oc
> +This rule only matches for connections from the specified source.
> +.It Ic to Ar address Ns Oo Li / Ns Ar prefix Oc
> +This rule only matches for connections to the specified destination.
> +The destination is the address the client was connecting to,
> +typically the relay's listen address in non-transparent mode,
> +not the address of the forwarded backend connection.
>  .It Ic forward to Pf < Ar table Ns >
>  Forward the request to a server in the specified table.
>  With this option, requests can be passed to specific backend servers.
> Index: usr.sbin/relayd/relayd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
> retrieving revision 1.253
> diff -u -p -u -p -r1.253 relayd.h
> --- usr.sbin/relayd/relayd.h 8 May 2019 23:22:19 -0000 1.253
> +++ usr.sbin/relayd/relayd.h 9 May 2019 17:12:09 -0000
> @@ -550,6 +550,7 @@ TAILQ_HEAD(rdrlist, rdr);
>  struct rsession {
>   objid_t se_id;
>   objid_t se_relayid;
> + struct sockaddr_storage se_sockname;
>   struct ctl_relay_event se_in;
>   struct ctl_relay_event se_out;
>   void *se_priv;
> @@ -601,11 +602,9 @@ enum rule_action {
>  };
>  
>  struct rule_addr {
> - int addr_af;
>   struct sockaddr_storage addr;
>   u_int8_t addr_mask;
> - int addr_net;
> - in_port_t addr_port;
> + int addr_port;
>  };
>  
>  #define RELAY_ADDR_EQ(_a, _b) \
> @@ -621,6 +620,10 @@ struct rule_addr {
>   ((_a)->addr_mask != (_b)->addr_mask || \
>   sockaddr_cmp((struct sockaddr *)&(_a)->addr, \
>   (struct sockaddr *)&(_b)->addr, (_a)->addr_mask) != 0)
> +
> +#define RELAY_AF_NEQ(_a, _b) \
> + (((_a) != AF_UNSPEC) && ((_b) != AF_UNSPEC) && \
> + ((_a) != (_b)))
>  
>  struct relay_rule {
>   objid_t rule_id;
>