diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-02-24 00:22:33 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-02-24 00:22:33 +0000 |
commit | 734f81ce16f22bbc092039fbc6ca93152151152e (patch) | |
tree | c06a29f4faf11e92f1750423d1d29a0308292144 /usr.sbin/hoststated | |
parent | dec39bb469d328708653d813db30983b2457c18d (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.5 | 73 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.h | 41 | ||||
-rw-r--r-- | usr.sbin/hoststated/parse.y | 113 | ||||
-rw-r--r-- | usr.sbin/hoststated/relay.c | 187 |
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); |