-/* $OpenBSD: parse.y,v 1.196 2014/12/12 10:05:09 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.197 2014/12/18 20:55:01 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/stat.h>
#include <sys/queue.h>
#include <sys/ioctl.h>
-#include <sys/hash.h>
#include <net/if.h>
#include <net/pfvar.h>
#include <string.h>
#include <ifaddrs.h>
#include <syslog.h>
+#include <md5.h>
#include <openssl/ssl.h>
static enum key_type keytype = KEY_TYPE_NONE;
static enum direction dir = RELAY_DIR_ANY;
static char *rulefile = NULL;
+static union hashkey *hashkey = NULL;
struct address *host_v4(const char *);
struct address *host_v6(const char *);
struct timeval tv;
struct table *table;
struct portrange port;
+ struct {
+ union hashkey key;
+ int keyset;
+ } key;
enum direction dir;
struct {
struct sockaddr_storage ss;
%type <v.digest> digest optdigest
%type <v.table> tablespec
%type <v.dir> dir
+%type <v.key> hashkey
%%
;
rdroptsl : forwardmode TO tablespec interface {
+ if (hashkey != NULL) {
+ free(hashkey);
+ hashkey = NULL;
+ }
+
switch ($1) {
case FWD_NORMAL:
if ($4 == NULL)
free($1);
table = tb;
dstmode = RELAY_DSTMODE_DEFAULT;
+ hashkey = NULL;
} tableopts_l {
struct table *tb;
if (table->conf.port == 0)
table->conf.skip_cnt =
($2 / conf->sc_interval.tv_sec) - 1;
}
- | MODE dstmode {
+ | MODE dstmode hashkey {
switch ($2) {
case RELAY_DSTMODE_LOADBALANCE:
case RELAY_DSTMODE_HASH:
case RELAY_DSTMODE_SRCHASH:
+ if (hashkey != NULL) {
+ yyerror("key already specified");
+ free(hashkey);
+ YYERROR;
+ }
+ if ((hashkey = calloc(1,
+ sizeof(*hashkey))) == NULL)
+ fatal("out of memory");
+ memcpy(hashkey, &$3.key, sizeof(*hashkey));
+ break;
+ default:
+ if ($3.keyset) {
+ yyerror("key not supported by mode");
+ YYERROR;
+ }
+ hashkey = NULL;
+ break;
+ }
+
+ switch ($2) {
+ case RELAY_DSTMODE_LOADBALANCE:
+ case RELAY_DSTMODE_HASH:
case RELAY_DSTMODE_RANDOM:
+ case RELAY_DSTMODE_SRCHASH:
if (rdr != NULL) {
yyerror("mode not supported "
"for redirections");
}
;
+/* should be in sync with sbin/pfctl/parse.y's hashkey */
+hashkey : /* empty */ {
+ $$.keyset = 0;
+ $$.key.data[0] = arc4random();
+ $$.key.data[1] = arc4random();
+ $$.key.data[2] = arc4random();
+ $$.key.data[3] = arc4random();
+ }
+ | STRING {
+ /* manual key configuration */
+ $$.keyset = 1;
+
+ if (!strncmp($1, "0x", 2)) {
+ if (strlen($1) != 34) {
+ free($1);
+ yyerror("hex key must be 128 bits "
+ "(32 hex digits) long");
+ YYERROR;
+ }
+
+ if (sscanf($1, "0x%8x%8x%8x%8x",
+ &$$.key.data[0], &$$.key.data[1],
+ &$$.key.data[2], &$$.key.data[3]) != 4) {
+ free($1);
+ yyerror("invalid hex key");
+ YYERROR;
+ }
+ } else {
+ MD5_CTX context;
+
+ MD5Init(&context);
+ MD5Update(&context, (unsigned char *)$1,
+ strlen($1));
+ MD5Final((unsigned char *)$$.key.data,
+ &context);
+ HTONL($$.key.data[0]);
+ HTONL($$.key.data[1]);
+ HTONL($$.key.data[2]);
+ HTONL($$.key.data[3]);
+ }
+ free($1);
+ }
+ ;
+
tablecheck : ICMP { table->conf.check = CHECK_ICMP; }
| TCP { table->conf.check = CHECK_TCP; }
| ssltls {
if (!TAILQ_EMPTY(&rlay->rl_tables))
rlt->rlt_flags |= F_BACKUP;
+ if (hashkey != NULL &&
+ (rlay->rl_conf.flags & F_HASHKEY) == 0) {
+ memcpy(&rlay->rl_conf.hashkey,
+ hashkey, sizeof(rlay->rl_conf.hashkey));
+ rlay->rl_conf.flags |= F_HASHKEY;
+ }
+ free(hashkey);
+ hashkey = NULL;
+
TAILQ_INSERT_TAIL(&rlay->rl_tables, rlt, rlt_entry);
}
;
TAILQ_INSERT_TAIL(conf->sc_routes, nr, nr_route);
}
| FORWARD TO tablespec {
+ free(hashkey);
+ hashkey = NULL;
+
if (router->rt_gwtable) {
yyerror("router %s table already specified",
router->rt_conf.name);
-/* $OpenBSD: relay.c,v 1.182 2014/12/12 10:05:09 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.183 2014/12/18 20:55:01 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/tree.h>
-#include <sys/hash.h>
#include <net/if.h>
#include <netinet/in.h>
void relay_accept(int, short, void *);
void relay_input(struct rsession *);
-u_int32_t relay_hash_addr(struct sockaddr_storage *, u_int32_t);
+void relay_hash_addr(SIPHASH_CTX *, struct sockaddr_storage *, int);
DH * relay_tls_get_dhparams(int);
void relay_tls_callback_info(const SSL *, int, int);
*/
rule_settable(&rlay->rl_proto->rules, rlt);
- switch (rlt->rlt_mode) {
- case RELAY_DSTMODE_ROUNDROBIN:
- case RELAY_DSTMODE_RANDOM:
- rlt->rlt_key = 0;
- break;
- case RELAY_DSTMODE_LOADBALANCE:
- case RELAY_DSTMODE_HASH:
- case RELAY_DSTMODE_SRCHASH:
- rlt->rlt_key =
- hash32_str(rlay->rl_conf.name, HASHINIT);
- rlt->rlt_key =
- hash32_str(rlt->rlt_table->conf.name,
- rlt->rlt_key);
- break;
- }
+ rlt->rlt_index = 0;
rlt->rlt_nhosts = 0;
TAILQ_FOREACH(host, &rlt->rlt_table->hosts, entry) {
if (rlt->rlt_nhosts >= RELAY_MAXHOSTS)
getmonotime(&con->se_tv_start);
bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last));
+ if (rlay->rl_conf.flags & F_HASHKEY) {
+ SipHash24_Init(&con->se_siphashctx,
+ &rlay->rl_conf.hashkey.siphashkey);
+ }
+
relay_sessions++;
SPLAY_INSERT(session_tree, &rlay->rl_sessions, con);
relay_session_publish(con);
}
}
-u_int32_t
-relay_hash_addr(struct sockaddr_storage *ss, u_int32_t p)
+void
+relay_hash_addr(SIPHASH_CTX *ctx, struct sockaddr_storage *ss, int portset)
{
struct sockaddr_in *sin4;
struct sockaddr_in6 *sin6;
+ in_port_t port;
if (ss->ss_family == AF_INET) {
sin4 = (struct sockaddr_in *)ss;
- p = hash32_buf(&sin4->sin_addr,
- sizeof(struct in_addr), p);
+ SipHash24_Update(ctx, &sin4->sin_addr,
+ sizeof(struct in_addr));
} else {
sin6 = (struct sockaddr_in6 *)ss;
- p = hash32_buf(&sin6->sin6_addr,
- sizeof(struct in6_addr), p);
+ SipHash24_Update(ctx, &sin6->sin6_addr,
+ sizeof(struct in6_addr));
}
- return (p);
+ if (portset != -1) {
+ port = (in_port_t)portset;
+ SipHash24_Update(ctx, &port, sizeof(port));
+ }
}
int
struct host *host;
struct relay_table *rlt = NULL;
struct table *table = NULL;
- u_int32_t p = con->se_hashkey;
int idx = -1;
+ u_int64_t p = 0;
/* the table is already selected */
if (con->se_table != NULL) {
__func__, con->se_id);
return (-1);
}
- if (!con->se_hashkeyset) {
- p = con->se_hashkey = rlt->rlt_key;
- con->se_hashkeyset = 1;
- }
switch (rlt->rlt_mode) {
case RELAY_DSTMODE_ROUNDROBIN:
- if ((int)rlt->rlt_key >= rlt->rlt_nhosts)
- rlt->rlt_key = 0;
- idx = (int)rlt->rlt_key;
+ if ((int)rlt->rlt_index >= rlt->rlt_nhosts)
+ rlt->rlt_index = 0;
+ idx = (int)rlt->rlt_index;
break;
case RELAY_DSTMODE_RANDOM:
idx = (int)arc4random_uniform(rlt->rlt_nhosts);
break;
case RELAY_DSTMODE_SRCHASH:
+ /* Source IP address without port */
+ relay_hash_addr(&con->se_siphashctx, &con->se_in.ss, -1);
+ break;
case RELAY_DSTMODE_LOADBALANCE:
/* Source IP address without port */
- p = relay_hash_addr(&con->se_in.ss, p);
- if (rlt->rlt_mode == RELAY_DSTMODE_SRCHASH)
- break;
+ relay_hash_addr(&con->se_siphashctx, &con->se_in.ss, -1);
/* FALLTHROUGH */
case RELAY_DSTMODE_HASH:
/* Local "destination" IP address and port */
- p = relay_hash_addr(&rlay->rl_conf.ss, p);
- p = hash32_buf(&rlay->rl_conf.port,
- sizeof(rlay->rl_conf.port), p);
+ relay_hash_addr(&con->se_siphashctx, &rlay->rl_conf.ss,
+ rlay->rl_conf.port);
break;
default:
fatalx("relay_from_table: unsupported mode");
/* NOTREACHED */
}
- if (idx == -1 && (idx = p % rlt->rlt_nhosts) >= RELAY_MAXHOSTS)
- return (-1);
+ if (idx == -1) {
+ p = SipHash24_End(&con->se_siphashctx);
+
+ /* Reset hash context */
+ SipHash24_Init(&con->se_siphashctx,
+ &rlay->rl_conf.hashkey.siphashkey);
+
+ if ((idx = p % rlt->rlt_nhosts) >= RELAY_MAXHOSTS)
+ return (-1);
+ }
host = rlt->rlt_host[idx];
DPRINTF("%s: session %d: table %s host %s, p 0x%08x, idx %d",
__func__, con->se_id, table->conf.name, host->conf.name, p, idx);
found:
if (rlt->rlt_mode == RELAY_DSTMODE_ROUNDROBIN)
- rlt->rlt_key = host->idx + 1;
+ rlt->rlt_index = host->idx + 1;
con->se_retry = host->conf.retry;
con->se_out.port = table->conf.port;
bcopy(&host->conf.ss, &con->se_out.ss, sizeof(con->se_out.ss));
-/* $OpenBSD: relay_http.c,v 1.35 2014/10/25 03:23:49 lteo Exp $ */
+/* $OpenBSD: relay_http.c,v 1.36 2014/12/18 20:55:01 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/tree.h>
-#include <sys/hash.h>
#include <net/if.h>
#include <netinet/in.h>
value = match->kv_value;
break;
}
- if (!con->se_hashkeyset)
- con->se_hashkey = HASHINIT;
- con->se_hashkey = hash32_str(value, con->se_hashkey);
- con->se_hashkeyset = 1;
- log_debug("%s: hashkey 0x%04x", __func__,
- con->se_hashkey);
+ SipHash24_Update(&con->se_siphashctx,
+ value, strlen(value));
break;
case KEY_OPTION_LOG:
/* perform this later */
-/* $OpenBSD: relay_udp.c,v 1.35 2014/12/12 10:05:09 reyk Exp $ */
+/* $OpenBSD: relay_udp.c,v 1.36 2014/12/18 20:55:01 reyk Exp $ */
/*
* Copyright (c) 2007 - 2013 Reyk Floeter <reyk@openbsd.org>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/tree.h>
-#include <sys/hash.h>
#include <net/if.h>
#include <netinet/in.h>
-/* $OpenBSD: relayd.c,v 1.134 2014/12/12 10:05:09 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.135 2014/12/18 20:55:01 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/resource.h>
-#include <sys/hash.h>
#include <net/if.h>
#include <netinet/in.h>
-.\" $OpenBSD: relayd.conf.5,v 1.153 2014/12/12 10:05:09 reyk Exp $
+.\" $OpenBSD: relayd.conf.5,v 1.154 2014/12/18 20:55:01 reyk Exp $
.\"
.\" Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
.\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: December 12 2014 $
+.Dd $Mdocdate: December 18 2014 $
.Dt RELAYD.CONF 5
.Os
.Sh NAME
The following options will set the scheduling algorithm to select a
host from the specified table:
.Bl -tag -width Ds
-.It Ic mode hash
+.It Ic mode hash Op Ar key
Balances the outgoing connections across the active hosts based on the
-hashed name of the relay, the hashed name of the table, and the IP
-address and port of the relay.
+.Ar key ,
+IP address and port of the relay.
Additional input can be fed into the
hash by looking at HTTP headers and GET variables;
see the
.Xr pf 4
states.
This mode is only supported by redirections.
-.It Ic mode loadbalance
+.It Ic mode loadbalance Op Ar key
Balances the outgoing connections across the active hosts based on the
-hashed name of the relay, the hashed name of the table, the source IP
-address of the client, and the IP address and port of the relay.
+.Ar key ,
+the source IP address of the client, and the IP address and port of the relay.
This mode is only supported by relays.
.It Ic mode random
Distributes the outgoing connections randomly through all active hosts.
through all active hosts.
This is the default mode and will be used if no option has been specified.
This mode is supported by redirections and relays.
-.It Ic mode source-hash
+.It Ic mode source-hash Op Ar key
Balances the outgoing connections across the active hosts based on the
-hashed name of the redirection or relay, the hashed name of the table,
+.Ar key
and the source IP address of the client.
This mode is only supported by relays.
.El
+.Pp
+The optional
+.Ar key
+argument can be specified for the
+.Ic hash ,
+.Ic loadbalance ,
+and
+.Ic source-hash
+modes as either an hex value with a leading
+.Ar 0x
+or as a string.
+If omitted,
+.Xr relayd 8
+generates a random key when the configuration is loaded.
.Sh REDIRECTIONS
Redirections represent a
.Xr pf 4
-/* $OpenBSD: relayd.h,v 1.199 2014/12/17 13:54:27 reyk Exp $ */
+/* $OpenBSD: relayd.h,v 1.200 2014/12/18 20:55:01 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <sys/param.h> /* MAXHOSTNAMELEN */
#include <limits.h>
#include <imsg.h>
+#include <siphash.h>
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
};
TAILQ_HEAD(addresslist, address);
+union hashkey {
+ /* Simplified version of pf_poolhashkey */
+ u_int32_t data[4];
+ SIPHASH_KEY siphashkey;
+};
+
#define F_DISABLE 0x00000001
#define F_BACKUP 0x00000002
#define F_USED 0x00000004
#define F_DIVERT 0x01000000
#define F_SCRIPT 0x02000000
#define F_TLSINSPECT 0x04000000
+#define F_HASHKEY 0x08000000
#define F_BITS \
"\10\01DISABLE\02BACKUP\03USED\04DOWN\05ADD\06DEL\07CHANGED" \
"\10STICKY-ADDRESS\11CHECK_DONE\12ACTIVE_RULESET\13CHECK_SENT" \
"\14TLS\15NAT_LOOKUP\16DEMOTE\17LOOKUP_PATH\20DEMOTED\21UDP" \
"\22RETURN\23TRAP\24NEEDPF\25PORT\26TLS_CLIENT\27NEEDRT" \
- "\30MATCH\31DIVERT\32SCRIPT\33TLS_INSPECT"
+ "\30MATCH\31DIVERT\32SCRIPT\33TLS_INSPECT\34HASHKEY"
enum forwardmode {
FWD_NORMAL = 0,
objid_t table_id;
objid_t backup_id;
int mode;
+ union hashkey key;
char name[SRV_NAME_SIZE];
char tag[RD_TAG_NAME_SIZE];
struct timeval timeout;
struct ctl_relay_event se_in;
struct ctl_relay_event se_out;
void *se_priv;
- u_int32_t se_hashkey;
- int se_hashkeyset;
+ SIPHASH_CTX se_siphashctx;
struct relay_table *se_table;
struct event se_ev;
struct timeval se_timeout;
struct table *rlt_table;
u_int32_t rlt_flags;
int rlt_mode;
- u_int32_t rlt_key;
+ u_int32_t rlt_index;
struct host *rlt_host[RELAY_MAXHOSTS];
int rlt_nhosts;
TAILQ_ENTRY(relay_table) rlt_entry;
struct sockaddr_storage dstaf;
struct timeval timeout;
enum forwardmode fwdmode;
+ union hashkey hashkey;
off_t tls_cert_len;
off_t tls_key_len;
objid_t tls_keyid;