summaryrefslogtreecommitdiff
path: root/usr.sbin/hoststated
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2007-02-24 00:22:33 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2007-02-24 00:22:33 +0000
commit734f81ce16f22bbc092039fbc6ca93152151152e (patch)
treec06a29f4faf11e92f1750423d1d29a0308292144 /usr.sbin/hoststated
parentdec39bb469d328708653d813db30983b2457c18d (diff)
- allow to specify the SSL cipher suite and the SSL protocols
(as required by the PCI DSS) - increase the default listen backlog to 10, allow to modify the backlog as a per-protocol tcp option to improve the performance on busy systems (to get less connection failures on heavy load) - close the connection if SSL_accept returned an error - instead of logging _new_ relay sessions to syslog, log the sessions in relay_close() after they have been _finished_. this will allow to collect some additional information - add a new log keyword to log specified header/url entities (useful to track "bad guys" using many session ids or multiple user agents) - some minor fixes, manpage bits, and bump the copyright (by some reason, i didn't realize that we already have 2007...).
Diffstat (limited to 'usr.sbin/hoststated')
-rw-r--r--usr.sbin/hoststated/hoststated.conf.573
-rw-r--r--usr.sbin/hoststated/hoststated.h41
-rw-r--r--usr.sbin/hoststated/parse.y113
-rw-r--r--usr.sbin/hoststated/relay.c187
4 files changed, 316 insertions, 98 deletions
diff --git a/usr.sbin/hoststated/hoststated.conf.5 b/usr.sbin/hoststated/hoststated.conf.5
index 2a2b5cd54b9..71afb2f1d9a 100644
--- a/usr.sbin/hoststated/hoststated.conf.5
+++ b/usr.sbin/hoststated/hoststated.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: hoststated.conf.5,v 1.23 2007/02/23 14:54:44 jmc Exp $
+.\" $OpenBSD: hoststated.conf.5,v 1.24 2007/02/24 00:22:32 reyk Exp $
.\"
.\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
.\"
@@ -414,6 +414,22 @@ Handle the Hypertext Transfer Protocol
.It Ic tcp
Generic handler for TCP-based protocols.
.El
+.It Xo
+.Ar action
+.Op Ic log
+.Xc
+Define an action for the selected entity.
+The
+.Ic log
+keyword will log the entity name and the value.
+The optional
+.Ic url
+keyword will look up the entity as a GET variable in the URL instead
+of an HTTP header value when using the
+.Ic http
+protocol.
+.Pp
+.Bl -tag -width Ds
.It Ic append Ar value Ic to Ar key
Append the specified value to a protocol entity with the selected name.
When using the
@@ -459,18 +475,24 @@ See the
keyword in the
.Sx RELAYS
section above.
-The
-.Ic url
-keyword will look up the entity as a GET variable in the URL instead
-of an HTTP header value when using the
-.Ic http
-protocol.
+.It Xo
+.Op Ic url
+.Ic log Ar key
+.Xc
+Log the name and the value of the entity.
+.El
.It Ic tcp Ar option
Enable or disable the specified TCP option; see
.Xr tcp 4
for details about TCP options.
Valid options are:
.Bl -tag -width Ds
+.It Ic backlog Ar number
+Set the maximum length the queue of pending connections may grow to.
+The backlog option is 10 by default and is limited by the
+.Ic kern.somaxconn
+.Xr sysctl 8
+variable.
.It Xo
.Op Ic no
.Ic nodelay
@@ -488,7 +510,21 @@ Set the socket-level buffer size for input and output for this
connection.
This will affect the TCP window size.
.El
-.It Ic ssl session cache Ar value
+.It Ic ssl Ar option
+Set the SSL options and session settings.
+This is only used if SSL is enabled in the relay.
+Valid options are:
+.Bl -tag -width Ds
+.It Ic ciphers Ar string
+Set the string defining the SSL cipher suite.
+If not specified, the default suite defined by the SSL library will be
+used.
+See the
+.Sx CIPHERS
+section of
+.Xr openssl 1
+for information about SSL cipher suites and preference lists.
+.It Ic session cache Ar value
Set the maximum size of the SSL session cache.
If the
.Ar value
@@ -496,6 +532,22 @@ is zero, the default size defined by the SSL library will be used.
A positive number will set the maximum size in bytes and the keyword
.Ic disable
will disable the SSL session cache.
+.It Xo
+.Op Ic no
+.Ic sslv2
+.Xc
+Enable the SSLv2 protocol.
+.It Xo
+.Op Ic no
+.Ic sslv3
+.Xc
+Enable the SSLv3 protocol.
+.It Xo
+.Op Ic no
+.Ic tlsv1
+.Xc
+Enable the TLSv1/SSLv3.1 protocol.
+.El
.El
.Pp
The
@@ -594,6 +646,8 @@ protocol http_ssl {
append "$SERVER_ADDR:$SERVER_PORT" to "X-Forwarded-By"
change "Keep-Alive" to "$TIMEOUT"
url hash "sessid"
+
+ ssl { no sslv2, ciphers "HIGH" }
}
relay sslaccel {
@@ -612,11 +666,12 @@ option will allow a
SSH session without delays between keystrokes or displayed output on
the terminal:
.Bd -literal -offset indent
-protocol http_ssl {
+protocol myssh {
tcp { nodelay, socket buffer 65536 }
}
relay sshforward {
+ protocol myssh
listen on www.example.com port 2222
forward to shell.example.com port 22
}
diff --git a/usr.sbin/hoststated/hoststated.h b/usr.sbin/hoststated/hoststated.h
index 90f9010707a..a6fc7127336 100644
--- a/usr.sbin/hoststated/hoststated.h
+++ b/usr.sbin/hoststated/hoststated.h
@@ -1,8 +1,8 @@
-/* $OpenBSD: hoststated.h,v 1.27 2007/02/23 00:28:06 deraadt Exp $ */
+/* $OpenBSD: hoststated.h,v 1.28 2007/02/24 00:22:32 reyk Exp $ */
/*
- * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
- * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@spootnik.org>
+ * Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -42,6 +42,7 @@
#define RELAY_MAXPROC 32
#define RELAY_MAXHOSTS 32
#define RELAY_STATINTERVAL 60
+#define RELAY_BACKLOG 10
#define SMALL_READ_BUF_SIZE 1024
#define READ_BUF_SIZE 65535
@@ -337,6 +338,7 @@ struct session {
struct timeval tv_start;
struct timeval tv_last;
int done;
+ struct evbuffer *log;
void *relay;
struct ctl_natlook *cnl;
TAILQ_ENTRY(session) entry;
@@ -350,18 +352,29 @@ enum nodeaction {
NODE_ACTION_REMOVE = 3,
NODE_ACTION_EXPECT = 4,
NODE_ACTION_FILTER = 5,
- NODE_ACTION_HASH = 6
+ NODE_ACTION_HASH = 6,
+ NODE_ACTION_LOG = 7
};
+enum nodetype {
+ NODE_TYPE_HEADER = 0,
+ NODE_TYPE_URL = 1,
+ NODE_TYPE_COOKIE = 2
+};
+
+#define PNFLAG_MACRO 0x01
+#define PNFLAG_MARK 0x02
+#define PNFLAG_LOG 0x04
+#define PNFLAG_LOOKUP_URL 0x08
+#define PNFLAG_LOOKUP_COOKIE 0x10
+
struct protonode {
objid_t id;
char *key;
enum nodeaction action;
char *value;
- int macro;
- int getvars;
- int header;
- int mark;
+ u_int8_t flags;
+ enum nodetype type;
RB_ENTRY(protonode) nodes;
};
@@ -377,12 +390,22 @@ enum prototype {
#define TCPFLAG_SACK 0x04
#define TCPFLAG_NSACK 0x08
#define TCPFLAG_BUFSIZ 0x10
+#define TCPFLAG_DEFAULT 0x00
+
+#define SSLFLAG_SSLV2 0x01
+#define SSLFLAG_SSLV3 0x02
+#define SSLFLAG_TLSV1 0x04
+#define SSLFLAG_VERSION 0x07
+#define SSLFLAG_DEFAULT (SSLFLAG_SSLV2|SSLFLAG_SSLV3|SSLFLAG_TLSV1)
struct protocol {
objid_t id;
u_int16_t flags;
- u_int16_t tcpflags;
+ u_int8_t tcpflags;
int tcpbufsiz;
+ int tcpbacklog;
+ u_int8_t sslflags;
+ char *sslciphers;
char name[MAX_NAME_SIZE];
int cache;
enum prototype type;
diff --git a/usr.sbin/hoststated/parse.y b/usr.sbin/hoststated/parse.y
index efbb11882b8..a14e6bb9a5a 100644
--- a/usr.sbin/hoststated/parse.y
+++ b/usr.sbin/hoststated/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.26 2007/02/22 03:32:39 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.27 2007/02/24 00:22:32 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -106,8 +106,8 @@ typedef struct {
%token SERVICE TABLE BACKUP HOST REAL
%token CHECK HTTP HTTPS TCP ICMP EXTERNAL
%token TIMEOUT CODE DIGEST PORT TAG INTERFACE
-%token VIRTUAL IP INTERVAL DISABLE STICKYADDR
-%token SEND EXPECT NOTHING USE SSL LOADBALANCE ROUNDROBIN
+%token VIRTUAL IP INTERVAL DISABLE STICKYADDR BACKLOG
+%token SEND EXPECT NOTHING USE SSL LOADBALANCE ROUNDROBIN CIPHERS
%token RELAY LISTEN ON FORWARD TO NAT LOOKUP PREFORK NO MARK MARKED
%token PROTO SESSION CACHE APPEND CHANGE REMOVE FROM FILTER HASH
%token LOG UPDATES ALL DEMOTE NODELAY SACK SOCKET BUFFER URL RETRY
@@ -115,7 +115,7 @@ typedef struct {
%token <v.string> STRING
%type <v.string> interface
%type <v.number> number port http_type loglevel sslcache
-%type <v.number> prototype dstmode docheck retry
+%type <v.number> prototype dstmode docheck retry no log
%type <v.host> host
%type <v.tv> timeout
@@ -533,6 +533,10 @@ proto : PROTO STRING {
p->id = last_proto_id++;
p->cache = RELAY_CACHESIZE;
p->type = RELAY_PROTO_TCP;
+ p->tcpflags = TCPFLAG_DEFAULT;
+ p->sslflags = SSLFLAG_DEFAULT;
+ p->sslciphers = NULL;
+ p->tcpbacklog = RELAY_BACKLOG;
if (last_proto_id == INT_MAX) {
yyerror("too many protocols defined");
YYERROR;
@@ -541,6 +545,12 @@ proto : PROTO STRING {
proto = p;
} '{' optnl protopts_l '}' {
conf->protocount++;
+
+ if ((proto->sslflags & SSLFLAG_VERSION) == 0) {
+ yyerror("invalid SSL protocol");
+ YYERROR;
+ }
+
TAILQ_INSERT_HEAD(&conf->protos, proto, entry);
}
;
@@ -549,11 +559,12 @@ protopts_l : protopts_l protoptsl nl
| protoptsl optnl
;
-protoptsl : SSL SESSION CACHE sslcache { proto->cache = $4; }
- | PROTO prototype { proto->type = $2; }
+protoptsl : SSL sslflags
+ | SSL '{' sslflags_l '}'
| TCP tcpflags
| TCP '{' tcpflags_l '}'
- | protonode {
+ | PROTO prototype { proto->type = $2; }
+ | protonode log {
struct protonode *pn, pk;
pn = RB_FIND(proto_tree, &proto->tree, &node);
@@ -568,20 +579,23 @@ protoptsl : SSL SESSION CACHE sslcache { proto->cache = $4; }
bcopy(&node, pn, sizeof(*pn));
pn->key = node.key;
pn->value = node.value;
- pn->header = node.getvars ? 0 : 1;
+ pn->type = node.type;
pn->id = proto->nodecount++;
+ if ($2) {
+ proto->lateconnect++;
+ pn->flags |= PNFLAG_LOG;
+ }
if (pn->id == INT_MAX) {
yyerror("too many protocol nodes defined");
YYERROR;
}
RB_INSERT(proto_tree, &proto->tree, pn);
- if (node.getvars) {
+ if (node.type != NODE_TYPE_HEADER) {
pk.key = "GET";
+ pk.type = NODE_TYPE_HEADER;
pn = RB_FIND(proto_tree, &proto->tree, &pk);
- if (pn != NULL) {
- pn->getvars++;
- } else if (pn == NULL) {
+ if (pn == NULL) {
if ((pn = (struct protonode *)
calloc(1, sizeof(*pn))) == NULL)
fatal("out of memory");
@@ -590,7 +604,7 @@ protoptsl : SSL SESSION CACHE sslcache { proto->cache = $4; }
fatal("out of memory");
pn->value = NULL;
pn->action = NODE_ACTION_NONE;
- pn->getvars = 1;
+ pn->type = pk.type;
pn->id = proto->nodecount++;
if (pn->id == INT_MAX) {
yyerror("too many protocol "
@@ -599,6 +613,16 @@ protoptsl : SSL SESSION CACHE sslcache { proto->cache = $4; }
}
RB_INSERT(proto_tree, &proto->tree, pn);
}
+ switch (node.type) {
+ case NODE_TYPE_URL:
+ pn->flags |= PNFLAG_LOOKUP_URL;
+ break;
+ case NODE_TYPE_COOKIE:
+ pn->flags |= PNFLAG_LOOKUP_COOKIE;
+ break;
+ default:
+ break;
+ }
}
bzero(&node, sizeof(node));
@@ -613,12 +637,45 @@ tcpflags : SACK { proto->tcpflags |= TCPFLAG_SACK; }
| NO SACK { proto->tcpflags |= TCPFLAG_NSACK; }
| NODELAY { proto->tcpflags |= TCPFLAG_NODELAY; }
| NO NODELAY { proto->tcpflags |= TCPFLAG_NNODELAY; }
+ | BACKLOG number {
+ if ($2 > RELAY_MAX_SESSIONS) {
+ yyerror("invalid backlog: %d", $2);
+ YYERROR;
+ }
+ proto->tcpbacklog = $2;
+ }
| SOCKET BUFFER number {
proto->tcpflags |= TCPFLAG_BUFSIZ;
proto->tcpbufsiz = $3;
}
;
+sslflags_l : sslflags comma sslflags_l
+ | sslflags
+ ;
+
+sslflags : SESSION CACHE sslcache { proto->cache = $3; }
+ | CIPHERS STRING {
+ proto->sslciphers = strdup($2);
+ if (proto->sslciphers == NULL)
+ fatal("out of memory");
+ free($2);
+ }
+ | no STRING {
+ u_int flags = 0;
+ if (strcmp("sslv2", $2) == 0)
+ flags = SSLFLAG_SSLV2;
+ else if (strcmp("sslv3", $2) == 0)
+ flags = SSLFLAG_SSLV3;
+ else if (strcmp("tlsv1", $2) == 0)
+ flags = SSLFLAG_TLSV1;
+ if ($1)
+ proto->sslflags &= ~flags;
+ else
+ proto->sslflags |= flags;
+ free($2);
+ }
+ ;
protonode : APPEND STRING TO STRING marked {
node.action = NODE_ACTION_APPEND;
@@ -627,7 +684,7 @@ protonode : APPEND STRING TO STRING marked {
if (node.key == NULL || node.value == NULL)
fatal("out of memory");
if (strchr(node.value, '$') != NULL)
- node.macro = 1;
+ node.flags |= PNFLAG_MACRO;
free($4);
free($2);
}
@@ -638,7 +695,7 @@ protonode : APPEND STRING TO STRING marked {
if (node.key == NULL || node.value == NULL)
fatal("out of memory");
if (strchr(node.value, '$') != NULL)
- node.macro = 1;
+ node.flags |= PNFLAG_MACRO;
free($4);
free($2);
}
@@ -677,18 +734,28 @@ protonode : APPEND STRING TO STRING marked {
free($3);
proto->lateconnect++;
}
+ | getvars LOG STRING marked {
+ node.action = NODE_ACTION_LOG;
+ node.key = strdup($3);
+ node.value = NULL;
+ node.flags |= PNFLAG_LOG;
+ if (node.key == NULL)
+ fatal("out of memory");
+ free($3);
+ proto->lateconnect++;
+ }
;
mark : /* nothing */
- | MARK { node.mark++; }
+ | MARK { node.flags |= PNFLAG_MARK; }
;
marked : /* nothing */
- | MARKED { node.mark++; }
+ | MARKED { node.flags |= PNFLAG_MARK; }
;
getvars : /* nothing */
- | URL { node.getvars++; }
+ | URL { node.type = NODE_TYPE_URL; }
;
sslcache : /* empty */ { $$ = RELAY_CACHESIZE; }
@@ -921,6 +988,14 @@ timeout : number
}
;
+no : /* empty */ { $$ = 0; }
+ | NO { $$ = 1; }
+ ;
+
+log : /* empty */ { $$ = 0; }
+ | LOG { $$ = 1; }
+ ;
+
comma : ','
| /* empty */
;
@@ -967,11 +1042,13 @@ lookup(char *s)
static const struct keywords keywords[] = {
{ "all", ALL },
{ "append", APPEND },
+ { "backlog", BACKLOG },
{ "backup", BACKUP },
{ "buffer", BUFFER },
{ "cache", CACHE },
{ "change", CHANGE },
{ "check", CHECK },
+ { "ciphers", CIPHERS },
{ "code", CODE },
{ "demote", DEMOTE },
{ "digest", DIGEST },
diff --git a/usr.sbin/hoststated/relay.c b/usr.sbin/hoststated/relay.c
index d18aa07caa7..6078d36d891 100644
--- a/usr.sbin/hoststated/relay.c
+++ b/usr.sbin/hoststated/relay.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: relay.c,v 1.2 2007/02/22 23:07:38 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.3 2007/02/24 00:22:32 reyk Exp $ */
/*
- * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -286,6 +286,18 @@ relay_protodebug(struct relay *rlay)
}
RB_FOREACH(pn, proto_tree, &proto->tree) {
fprintf(stderr, "\t\t");
+
+ switch (pn->type) {
+ case NODE_TYPE_HEADER:
+ break;
+ case NODE_TYPE_URL:
+ fprintf(stderr, "url ");
+ break;
+ case NODE_TYPE_COOKIE:
+ fprintf(stderr, "cookie ");
+ break;
+ }
+
switch (pn->action) {
case NODE_ACTION_APPEND:
fprintf(stderr, "append \"%s\" to \"%s\"",
@@ -300,24 +312,21 @@ relay_protodebug(struct relay *rlay)
pn->key);
break;
case NODE_ACTION_EXPECT:
- fprintf(stderr, "%sexpect \"%s\" from \"%s\"",
- pn->header ? "" : "url ",
+ fprintf(stderr, "expect \"%s\" from \"%s\"",
pn->value, pn->key);
break;
case NODE_ACTION_FILTER:
- fprintf(stderr, "%sfilter \"%s\" from \"%s\"",
- pn->header ? "" : "url ",
+ fprintf(stderr, "filter \"%s\" from \"%s\"",
pn->value, pn->key);
break;
case NODE_ACTION_HASH:
- fprintf(stderr, "%shash \"%s\"",
- pn->header ? "" : "url ",
- pn->key);
+ fprintf(stderr, "hash \"%s\"", pn->key);
+ break;
+ case NODE_ACTION_LOG:
+ fprintf(stderr, "log \"%s\"", pn->key);
break;
case NODE_ACTION_NONE:
- fprintf(stderr, "%snone \"%s\"",
- pn->header ? "" : "url ",
- pn->key);
+ fprintf(stderr, "none \"%s\"", pn->key);
break;
}
fprintf(stderr, "\n");
@@ -570,7 +579,7 @@ relay_socket_listen(struct sockaddr_storage *ss, in_port_t port,
if (bind(s, (struct sockaddr *)ss, ss->ss_len) == -1)
goto bad;
- if (listen(s, 5) == -1)
+ if (listen(s, proto->tcpbacklog) == -1)
goto bad;
return (s);
@@ -588,7 +597,6 @@ relay_connected(int fd, short sig, void *arg)
evbuffercb outrd = relay_read;
evbuffercb outwr = relay_write;
struct bufferevent *bev;
- char ibuf[128], obuf[128];
if (sig == EV_TIMEOUT) {
relay_close(con, "connect timeout");
@@ -598,14 +606,6 @@ relay_connected(int fd, short sig, void *arg)
DPRINTF("relay_connected: session %d: %ssuccessful",
con->id, rlay->proto->lateconnect ? "late connect " : "");
- if (env->opts & HOSTSTATED_OPT_LOGUPDATE) {
- relay_host(&con->in.ss, ibuf, sizeof(ibuf));
- relay_host(&con->out.ss, obuf, sizeof(obuf));
- log_info("relay %s, session %d (%d active), %s -> %s:%d",
- rlay->name, con->id, relay_sessions,
- ibuf, obuf, ntohs(con->out.port));
- }
-
/*
* Relay <-> Server
*/
@@ -677,7 +677,7 @@ relay_write(struct bufferevent *bev, void *arg)
if (gettimeofday(&con->tv_last, NULL))
con->done = 1;
if (con->done)
- relay_close(con, "last write, done");
+ relay_close(con, "last write (done)");
}
void
@@ -697,7 +697,7 @@ relay_read(struct bufferevent *bev, void *arg)
bufferevent_enable(con->in.bev, EV_READ);
return;
done:
- relay_close(con, "last read, done");
+ relay_close(con, "last read (done)");
}
char *
@@ -754,16 +754,14 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
struct session *con = (struct session *)cre->con;
char buf[READ_BUF_SIZE], *ptr;
- if (pn->header != header)
- return (0);
-
switch (pn->action) {
case NODE_ACTION_APPEND:
- if (!header || (pn->mark && cre->marked == 0))
+ if (!header || ((pn->flags & PNFLAG_MARK) && cre->marked == 0))
return (-1);
ptr = pn->value;
- if (pn->macro && (ptr = relay_expand_http(cre,
- pn->value, buf, sizeof(buf))) == NULL)
+ if ((pn->flags & PNFLAG_MACRO) &&
+ (ptr = relay_expand_http(cre, pn->value,
+ buf, sizeof(buf))) == NULL)
break;
relay_bufferevent_print(cre->dst, pn->key);
relay_bufferevent_print(cre->dst, ": ");
@@ -777,7 +775,7 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
break;
case NODE_ACTION_CHANGE:
case NODE_ACTION_REMOVE:
- if (!header || (pn->mark && cre->marked == 0))
+ if (!header || ((pn->flags & PNFLAG_MARK) && cre->marked == 0))
return (-1);
DPRINTF("relay_handle_http: change/remove '%s: %s'",
pk->key, pk->value);
@@ -786,7 +784,7 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
DPRINTF("relay_handle_http: expect '%s: %s'",
pn->key, pn->value);
if (fnmatch(pn->value, pk->value, FNM_CASEFOLD) == 0) {
- if (pn->mark)
+ if (pn->flags & PNFLAG_MARK)
cre->marked++;
cre->nodes[pn->id] = 1;
}
@@ -796,22 +794,30 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
pn->key, pn->value);
if (fnmatch(pn->value, pk->value, FNM_CASEFOLD) ==
FNM_NOMATCH) {
- if (pn->mark)
+ if (pn->flags & PNFLAG_MARK)
cre->marked++;
cre->nodes[pn->id] = 1;
}
break;
case NODE_ACTION_HASH:
- if (pn->mark && !cre->marked)
+ if ((pn->flags & PNFLAG_MARK) && cre->marked == 0)
return (-1);
DPRINTF("relay_handle_http: hash '%s: %s'",
pn->key, pk->value);
con->outkey = hash32_str(pk->value, con->outkey);
break;
+ case NODE_ACTION_LOG:
+ if ((pn->flags & PNFLAG_MARK) && cre->marked == 0)
+ return (-1);
+ DPRINTF("relay_handle_http: log '%s: %s'",
+ pn->key, pk->value);
+ break;
case NODE_ACTION_NONE:
return (-1);
}
-
+ if (pn->flags & PNFLAG_LOG)
+ evbuffer_add_printf(con->log, " [%s: %s]",
+ pn->key, pk->value);
return (0);
}
@@ -841,7 +847,7 @@ relay_read_httpcontent(struct bufferevent *bev, void *arg)
bufferevent_enable(bev, EV_READ);
return;
done:
- relay_close(con, "last http content read, done");
+ relay_close(con, "last http content read (done)");
}
void
@@ -865,6 +871,8 @@ relay_read_http(struct bufferevent *bev, void *arg)
if (!size)
return;
+ pk.type = NODE_TYPE_HEADER;
+
while (!done && (line = evbuffer_readline(src)) != NULL) {
/*
* An empty line indicates the end of the request.
@@ -947,7 +955,7 @@ relay_read_http(struct bufferevent *bev, void *arg)
goto next;
/* Decode the URL */
- if (pn->getvars) {
+ if (pn->flags & PNFLAG_LOOKUP_URL) {
url = strdup(pk.value);
if (url == NULL)
goto next;
@@ -962,13 +970,13 @@ relay_read_http(struct bufferevent *bev, void *arg)
*method++ = '\0';
while (ptr != NULL && strlen(ptr)) {
pkv.key = ptr;
+ pkv.type = NODE_TYPE_URL;
if ((ptr = strchr(ptr, '&')) != NULL)
*ptr++ = '\0';
if ((pkv.value =
strchr(pkv.key, '=')) == NULL ||
- strlen(pkv.value) < 1) {
+ strlen(pkv.value) < 1)
continue;
- }
*pkv.value++ = '\0';
if ((pnv = RB_FIND(proto_tree,
&proto->tree, &pkv)) == NULL)
@@ -1006,10 +1014,12 @@ next:
case NODE_ACTION_APPEND:
case NODE_ACTION_CHANGE:
ptr = pn->value;
- if (pn->mark && cre->marked == 0)
+ if ((pn->flags & PNFLAG_MARK) &&
+ cre->marked == 0)
break;
- if (pn->macro && (ptr = relay_expand_http(cre,
- pn->value, buf, sizeof(buf))) == NULL)
+ if ((pn->flags & PNFLAG_MACRO) &&
+ (ptr = relay_expand_http(cre, pn->value,
+ buf, sizeof(buf))) == NULL)
break;
relay_bufferevent_print(cre->dst, pn->key);
relay_bufferevent_print(cre->dst, ": ");
@@ -1019,18 +1029,18 @@ next:
pn->key, ptr);
break;
case NODE_ACTION_EXPECT:
- if (pn->mark)
+ if (pn->flags & PNFLAG_MARK)
break;
DPRINTF("relay_read_http: missing '%s: %s'",
pn->key, pn->value);
- relay_close(con, "incomplete header, done");
+ relay_close(con, "incomplete header (done)");
return;
case NODE_ACTION_FILTER:
- if (pn->mark)
+ if (pn->flags & PNFLAG_MARK)
break;
DPRINTF("relay_read_http: filtered '%s: %s'",
pn->key, pn->value);
- relay_close(con, "rejecting header, done");
+ relay_close(con, "rejecting header (done)");
return;
default:
break;
@@ -1062,7 +1072,7 @@ next:
cre->method = 0;
cre->marked = 0;
- if (proto->lateconnect && cre->bev == NULL &&
+ if (proto->lateconnect && cre->dst->bev == NULL &&
relay_connect(con) == -1) {
relay_close(con, "session failed");
return;
@@ -1075,7 +1085,7 @@ next:
bufferevent_enable(bev, EV_READ);
return;
done:
- relay_close(con, "last http read, done");
+ relay_close(con, "last http read (done)");
}
void
@@ -1174,6 +1184,13 @@ relay_accept(int fd, short sig, void *arg)
return;
}
+ /* Pre-allocate log buffer */
+ con->log = evbuffer_new();
+ if (con->log == NULL) {
+ relay_close(con, "failed to allocate log buffer");
+ return;
+ }
+
if (rlay->flags & F_NATLOOK) {
if ((cnl = (struct ctl_natlook *)
calloc(1, sizeof(struct ctl_natlook))) == NULL)
@@ -1356,6 +1373,7 @@ relay_connect(struct session *con)
con->id, strerror(errno));
return (-1);
}
+
if (errno == EINPROGRESS)
event_again(&con->ev, con->out.s, EV_WRITE|EV_TIMEOUT,
relay_connected, &con->tv_start, &env->timeout, con);
@@ -1369,6 +1387,7 @@ void
relay_close(struct session *con, const char *msg)
{
struct relay *rlay = (struct relay *)con->relay;
+ char ibuf[128], obuf[128], *ptr = NULL;
TAILQ_REMOVE(&rlay->sessions, con, entry);
@@ -1378,6 +1397,19 @@ relay_close(struct session *con, const char *msg)
if (con->out.bev != NULL)
bufferevent_disable(con->out.bev, EV_READ|EV_WRITE);
+ if (env->opts & HOSTSTATED_OPT_LOGUPDATE) {
+ relay_host(&con->in.ss, ibuf, sizeof(ibuf));
+ relay_host(&con->out.ss, obuf, sizeof(obuf));
+ if (EVBUFFER_LENGTH(con->log)) {
+ evbuffer_add_printf(con->log, "\r\n");
+ ptr = evbuffer_readline(con->log);
+ }
+ log_info("relay %s, session %d (%d active), %s -> %s:%d, "
+ "%s%s%s", rlay->name, con->id, relay_sessions,
+ ibuf, obuf, ntohs(con->out.port), msg,
+ ptr == NULL ? "" : ",", ptr == NULL ? "" : ptr);
+ }
+
if (con->in.bev != NULL)
bufferevent_free(con->in.bev);
else if (con->in.output != NULL)
@@ -1406,6 +1438,9 @@ relay_close(struct session *con, const char *msg)
if (con->out.nodes != NULL)
free(con->out.nodes);
+ if (con->log != NULL)
+ evbuffer_free(con->log);
+
if (con->cnl != NULL) {
#if 0
imsg_compose(ibuf_pfe, IMSG_KILLSTATES, 0, 0,
@@ -1414,12 +1449,6 @@ relay_close(struct session *con, const char *msg)
free(con->cnl);
}
-#ifdef DEBUG
- log_info("relay %s, session %d closed: %s", rlay->name, con->id, msg);
-#else
- log_debug("relay %s, session %d closed: %s", rlay->name, con->id, msg);
-#endif
-
free(con);
relay_sessions--;
}
@@ -1558,6 +1587,7 @@ relay_dispatch_parent(int fd, short event, void * ptr)
SSL_CTX *
relay_ssl_ctx_create(struct relay *rlay)
{
+ struct protocol *proto = rlay->proto;
SSL_CTX *ctx;
char certfile[PATH_MAX], hbuf[128];
@@ -1567,16 +1597,34 @@ relay_ssl_ctx_create(struct relay *rlay)
/* Modify session timeout and cache size*/
SSL_CTX_set_timeout(ctx, rlay->timeout.tv_sec);
- if (rlay->proto->cache < -1) {
+ if (proto->cache < -1) {
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
- } else if (rlay->proto->cache >= -1) {
+ } else if (proto->cache >= -1) {
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
- if (rlay->proto->cache >= 0)
- SSL_CTX_sess_set_cache_size(ctx, rlay->proto->cache);
+ if (proto->cache >= 0)
+ SSL_CTX_sess_set_cache_size(ctx, proto->cache);
}
- /* Enable all workarounds */
+ /* Enable all workarounds and set SSL options */
SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ SSL_CTX_set_options(ctx,
+ SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+
+ /* Set the allowed SSL protocols */
+ if ((proto->sslflags & SSLFLAG_SSLV2) == 0)
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ if ((proto->sslflags & SSLFLAG_SSLV3) == 0)
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+ if ((proto->sslflags & SSLFLAG_TLSV1) == 0)
+ SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
+
+ /* Change the default SSL cipher suite, if specified */
+ if (proto->sslciphers != NULL) {
+ log_debug("relay_ssl_ctx_create: ciphers '%s'",
+ proto->sslciphers);
+ if (!SSL_CTX_set_cipher_list(ctx, proto->sslciphers))
+ goto err;
+ }
if (relay_host(&rlay->ss, hbuf, sizeof(hbuf)) == NULL)
goto err;
@@ -1669,14 +1717,28 @@ relay_ssl_accept(int fd, short event, void *arg)
case SSL_ERROR_WANT_WRITE:
retry_flag = EV_WRITE;
goto retry;
+ case SSL_ERROR_ZERO_RETURN:
+ case SSL_ERROR_SYSCALL:
+ if (ret == 0) {
+ relay_close(con, "closed");
+ return;
+ }
+ /* FALLTHROUGH */
default:
ssl_error(rlay->name, "relay_ssl_accept");
+ relay_close(con, "SSL accept error");
return;
}
}
- DPRINTF("relay_ssl_accept: session %d: connection established",
- con->id);
+
+#ifdef DEBUG
+ log_info("relay %s, session %d established (%d active)",
+ rlay->name, con->id, relay_sessions);
+#else
+ log_debug("relay %s, session %d established (%d active)",
+ rlay->name, con->id, relay_sessions);
+#endif
relay_session(con);
return;
@@ -1916,7 +1978,8 @@ relay_bufferevent_write(struct ctl_relay_event *cre, void *data, size_t size)
static __inline int
relay_proto_cmp(struct protonode *a, struct protonode *b)
{
- return (strcasecmp(a->key, b->key));
+ return (strcasecmp(a->key, b->key) +
+ a->type == b->type ? 0 : (a->type > b->type ? 1 : -1));
}
RB_GENERATE(proto_tree, protonode, nodes, relay_proto_cmp);