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; >