diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-09-29 09:58:52 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-09-29 09:58:52 +0000 |
commit | c186faf0b6d68761c8fcad1ecf17cfbdf6230d1f (patch) | |
tree | 8ae88931222b54ddbc69c9d1f2d1e7966191ee24 /usr.sbin | |
parent | 05ec5da5157ac0171176076fee248541995ec393 (diff) |
allow to listen on a port range for redirections. this fixes
stickyness with web applications that cannot do the clustering on
their own and require stickyness with HTTP to HTTPS migration. this
is required in many cases; it is a true fact that we cannot always fix
the backend application in the real world.
Tested and requested by many
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/relayd/parse.y | 108 | ||||
-rw-r--r-- | usr.sbin/relayd/pfe_filter.c | 15 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.conf.5 | 11 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 10 |
4 files changed, 111 insertions, 33 deletions
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y index 1fa08a74550..6843c951044 100644 --- a/usr.sbin/relayd/parse.y +++ b/usr.sbin/relayd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.122 2008/07/22 23:17:37 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.123 2008/09/29 09:58:51 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org> @@ -30,6 +30,7 @@ #include <sys/queue.h> #include <net/if.h> +#include <net/pfvar.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> @@ -100,11 +101,12 @@ static in_port_t tableport = 0; struct address *host_v4(const char *); struct address *host_v6(const char *); int host_dns(const char *, struct addresslist *, - int, in_port_t, const char *); + int, struct portrange *, const char *); int host(const char *, struct addresslist *, - int, in_port_t, const char *); + int, struct portrange *, const char *); struct table *table_inherit(struct table *); +int getservice(char *); typedef struct { union { @@ -113,6 +115,7 @@ typedef struct { struct host *host; struct timeval tv; struct table *table; + struct portrange port; struct { enum digest_type type; char *digest; @@ -134,8 +137,9 @@ typedef struct { %token <v.string> STRING %token <v.number> NUMBER %type <v.string> interface hostname table -%type <v.number> port http_type loglevel sslcache optssl mark parent +%type <v.number> http_type loglevel sslcache optssl mark parent %type <v.number> proto_type dstmode retry log flag direction forwardmode +%type <v.port> port %type <v.host> host %type <v.tv> timeout %type <v.digest> digest @@ -231,15 +235,29 @@ eflags : STYLE STRING ; port : PORT STRING { - struct servent *servent; + char *a, *b; + int p[2]; - servent = getservbyname($2, "tcp"); - if (servent == NULL) { - yyerror("port %s is invalid", $2); + p[0] = p[1] = 0; + + a = $2; + b = strchr($2, ':'); + if (b == NULL) + $$.op = PF_OP_EQ; + else { + *b++ = '\0'; + if ((p[1] = getservice(b)) == -1) { + free($2); + YYERROR; + } + $$.op = PF_OP_RRG; + } + if ((p[0] = getservice(a)) == -1) { free($2); YYERROR; } - $$ = servent->s_port; + $$.val[0] = p[0]; + $$.val[1] = p[1]; free($2); } | PORT NUMBER { @@ -247,7 +265,8 @@ port : PORT STRING { yyerror("invalid port: %d", $2); YYERROR; } - $$ = htons($2); + $$.val[0] = htons($2); + $$.op = PF_OP_EQ; } ; @@ -424,7 +443,7 @@ rdroptsl : forwardmode TO tablespec interface { } | LISTEN ON STRING port interface { if (host($3, &rdr->virts, - SRV_MAX_VIRTS, $4, $5) <= 0) { + SRV_MAX_VIRTS, &$4, $5) <= 0) { yyerror("invalid virtual ip: %s", $3); free($3); free($5); @@ -433,7 +452,7 @@ rdroptsl : forwardmode TO tablespec interface { free($3); free($5); if (rdr->conf.port == 0) - rdr->conf.port = $4; + rdr->conf.port = $4.val[0]; tableport = rdr->conf.port; } | DISABLE { rdr->conf.flags |= F_DISABLE; } @@ -539,6 +558,8 @@ tablespec : table { struct table *tb; if (table->conf.port == 0) table->conf.port = tableport; + else + table->conf.flags |= F_PORT; if ((tb = table_inherit(table)) == NULL) YYERROR; $$ = tb; @@ -550,7 +571,13 @@ tableopts_l : tableopts tableopts_l ; tableopts : CHECK tablecheck - | port { table->conf.port = $1; } + | port { + if ($1.op != PF_OP_EQ) { + yyerror("invalid port"); + YYERROR; + } + table->conf.port = $1.val[0]; + } | TIMEOUT timeout { bcopy(&$2, &table->conf.timeout, sizeof(struct timeval)); @@ -1117,11 +1144,17 @@ relayoptsl : LISTEN ON STRING port optssl { if (rlay->rl_conf.ss.ss_family != AF_UNSPEC) { yyerror("relay %s listener already specified", rlay->rl_conf.name); + free($3); + YYERROR; + } + if ($4.op != PF_OP_EQ) { + yyerror("invalid port"); + free($3); YYERROR; } TAILQ_INIT(&al); - if (host($3, &al, 1, $4, NULL) <= 0) { + if (host($3, &al, 1, &$4, NULL) <= 0) { yyerror("invalid listen ip: %s", $3); free($3); YYERROR; @@ -1129,12 +1162,12 @@ relayoptsl : LISTEN ON STRING port optssl { free($3); h = TAILQ_FIRST(&al); bcopy(&h->ss, &rlay->rl_conf.ss, sizeof(rlay->rl_conf.ss)); - rlay->rl_conf.port = h->port; + rlay->rl_conf.port = h->port.val[0]; if ($5) { rlay->rl_conf.flags |= F_SSL; conf->sc_flags |= F_SSL; } - tableport = h->port; + tableport = h->port.val[0]; } | forwardmode TO forwardspec interface dstaf { rlay->rl_conf.fwdmode = $1; @@ -1207,9 +1240,14 @@ forwardspec : tablespec { free($1); YYERROR; } + if ($2.op != PF_OP_EQ) { + yyerror("invalid port"); + free($1); + YYERROR; + } TAILQ_INIT(&al); - if (host($1, &al, 1, $2, NULL) <= 0) { + if (host($1, &al, 1, &$2, NULL) <= 0) { yyerror("invalid listen ip: %s", $1); free($1); YYERROR; @@ -1218,7 +1256,7 @@ forwardspec : tablespec { h = TAILQ_FIRST(&al); bcopy(&h->ss, &rlay->rl_conf.dstss, sizeof(rlay->rl_conf.dstss)); - rlay->rl_conf.dstport = h->port; + rlay->rl_conf.dstport = h->port.val[0]; rlay->rl_conf.dstretry = $3; } | NAT LOOKUP retry { @@ -1268,7 +1306,7 @@ host : STRING retry parent { fatal("out of memory"); TAILQ_INIT(&al); - if (host($1, &al, 1, 0, NULL) <= 0) { + if (host($1, &al, 1, NULL, NULL) <= 0) { yyerror("invalid host %s", $2); free($1); free($$); @@ -2041,7 +2079,7 @@ host_v6(const char *s) int host_dns(const char *s, struct addresslist *al, int max, - in_port_t port, const char *ifname) + struct portrange *port, const char *ifname) { struct addrinfo hints, *res0, *res; int error, cnt = 0; @@ -2068,7 +2106,8 @@ host_dns(const char *s, struct addresslist *al, int max, if ((h = calloc(1, sizeof(*h))) == NULL) fatal(NULL); - h->port = port; + if (port != NULL) + bcopy(port, &h->port, sizeof(h->port)); if (ifname != NULL) { if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= sizeof(h->ifname)) @@ -2102,7 +2141,7 @@ host_dns(const char *s, struct addresslist *al, int max, int host(const char *s, struct addresslist *al, int max, - in_port_t port, const char *ifname) + struct portrange *port, const char *ifname) { struct address *h; @@ -2113,7 +2152,8 @@ host(const char *s, struct addresslist *al, int max, h = host_v6(s); if (h != NULL) { - h->port = port; + if (port != NULL) + bcopy(port, &h->port, sizeof(h->port)); if (ifname != NULL) { if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= sizeof(h->ifname)) { @@ -2200,3 +2240,25 @@ table_inherit(struct table *tb) return (tb); } + +int +getservice(char *n) +{ + struct servent *s; + const char *errstr; + long long llval; + + llval = strtonum(n, 0, UINT16_MAX, &errstr); + if (errstr) { + s = getservbyname(n, "tcp"); + if (s == NULL) + s = getservbyname(n, "udp"); + if (s == NULL) { + yyerror("unknown port %s", n); + return (-1); + } + return (s->s_port); + } + + return (htons((u_short)llval)); +} diff --git a/usr.sbin/relayd/pfe_filter.c b/usr.sbin/relayd/pfe_filter.c index 8b417fc862c..b74bdc319bc 100644 --- a/usr.sbin/relayd/pfe_filter.c +++ b/usr.sbin/relayd/pfe_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfe_filter.c,v 1.32 2008/07/16 14:38:33 reyk Exp $ */ +/* $OpenBSD: pfe_filter.c,v 1.33 2008/09/29 09:58:51 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -385,8 +385,9 @@ sync_ruleset(struct relayd *env, struct rdr *rdr, int enable) rio.rule.proto = IPPROTO_TCP; rio.rule.src.addr.type = PF_ADDR_ADDRMASK; rio.rule.dst.addr.type = PF_ADDR_ADDRMASK; - rio.rule.dst.port_op = PF_OP_EQ; - rio.rule.dst.port[0] = address->port; + rio.rule.dst.port_op = address->port.op; + rio.rule.dst.port[0] = address->port.val[0]; + rio.rule.dst.port[1] = address->port.val[1]; rio.rule.rtableid = -1; /* stay in the main routing table */ if (strlen(rdr->conf.tag)) @@ -422,8 +423,12 @@ sync_ruleset(struct relayd *env, struct rdr *rdr, int enable) if (ioctl(env->sc_pf->dev, DIOCADDADDR, &pio) == -1) fatal("sync_ruleset: cannot add address to pool"); - rio.rule.rpool.proxy_port[0] = ntohs(rdr->table->conf.port); - rio.rule.rpool.port_op = PF_OP_EQ; + if (address->port.op == PF_OP_EQ || + rdr->table->conf.flags & F_PORT) { + rio.rule.rpool.proxy_port[0] = + ntohs(rdr->table->conf.port); + rio.rule.rpool.port_op = PF_OP_EQ; + } rio.rule.rpool.opts = PF_POOL_ROUNDROBIN; if (rdr->conf.flags & F_STICKY) rio.rule.rpool.opts |= PF_POOL_STICKYADDR; diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5 index 68b243a5609..94448097777 100644 --- a/usr.sbin/relayd/relayd.conf.5 +++ b/usr.sbin/relayd/relayd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: relayd.conf.5,v 1.93 2008/08/08 22:49:33 reyk Exp $ +.\" $OpenBSD: relayd.conf.5,v 1.94 2008/09/29 09:58:51 reyk Exp $ .\" .\" Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 8 2008 $ +.Dd $Mdocdate: September 29 2008 $ .Dt RELAYD.CONF 5 .Os .Sh NAME @@ -414,7 +414,7 @@ Specify the tables of target hosts to be used; see the section above for information about table options. If the .Ic port -option is not specified, the port from the +option is not specified, the first port from the .Ic listen on directive will be used. This directive can be specified twice \(en the second entry will be used @@ -432,6 +432,11 @@ to listen on. .Xr pf 4 will redirect incoming connections for the specified target to the hosts in the main or backup table. +The +.Ar port +argument can optionally specify a port range instead of a single port, +the format is +.Ar min-port Ic : Ar max-port . The rdr rule can be optionally restricted to a given interface name. .It Xo .Ic route to diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index e9a527999d4..ace783581ea 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.110 2008/08/11 08:07:14 reyk Exp $ */ +/* $OpenBSD: relayd.h,v 1.111 2008/09/29 09:58:51 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -309,9 +309,14 @@ struct ctl_stats { u_int32_t last_day; }; +struct portrange { + in_port_t val[2]; + u_int8_t op; +}; + struct address { struct sockaddr_storage ss; - in_port_t port; + struct portrange port; char ifname[IFNAMSIZ]; TAILQ_ENTRY(address) entry; }; @@ -337,6 +342,7 @@ TAILQ_HEAD(addresslist, address); #define F_RETURN 0x00020000 #define F_TRAP 0x00040000 #define F_NEEDPF 0x00080000 +#define F_PORT 0x00100000 enum forwardmode { FWD_NORMAL = 0, |