ok

Reyk Floeter(r...@openbsd.org) 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;
> 

Reply via email to