diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-02-27 13:38:59 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-02-27 13:38:59 +0000 |
commit | c9264b75c20efb4a4120a89f107e9771dd42b1bf (patch) | |
tree | a37c32994cb34289a2dc16d2ec5eb31ec258545c /usr.sbin/hoststated | |
parent | e7c46625ff26167cee75d713d172dc7d865df298 (diff) |
in addition to actions on request headers, allow to define relay
actions on response headers (the reply sent by backend HTTP servers).
the default and slightly faster relay streaming mode will be used if
no actions are defined.
for example:
response change "Server" to "OpenBSD-hoststated/4.1"
ok pyr@
Diffstat (limited to 'usr.sbin/hoststated')
-rw-r--r-- | usr.sbin/hoststated/hoststated.conf.5 | 16 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.h | 18 | ||||
-rw-r--r-- | usr.sbin/hoststated/parse.y | 54 | ||||
-rw-r--r-- | usr.sbin/hoststated/relay.c | 75 |
4 files changed, 126 insertions, 37 deletions
diff --git a/usr.sbin/hoststated/hoststated.conf.5 b/usr.sbin/hoststated/hoststated.conf.5 index 82b399e01be..872dc3ed097 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.34 2007/02/27 08:39:00 reyk Exp $ +.\" $OpenBSD: hoststated.conf.5,v 1.35 2007/02/27 13:38:58 reyk Exp $ .\" .\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> .\" @@ -415,6 +415,7 @@ Handle the Hypertext Transfer Protocol Generic handler for TCP-based protocols. .El .It Xo +.Op Ar direction .Op Ar type .Ar action .Op Ic log @@ -426,6 +427,17 @@ keyword will log the entity name and the value. The actions are depending on the underlying application .Ic protocol . .Pp +The following directions are allowed for the specified action: +.Bl -tag -width Ds +.It Ic request +Handle the data stream from the client to the relay, like HTTP +requests. +This is the default if the direction directive is omitted. +.It Ic response +Handle the data stream from the target host to the relay, like +HTTP server replys. +.El +.Pp The following entity types for the actions are available: .Bl -tag -width Ds .It Ic header @@ -437,6 +449,8 @@ mode. Look up the entity as a GET variable in the URL when using the .Ic http protocol. +This type is only available with the direction +.Ic request . .El .Pp The following actions are available: diff --git a/usr.sbin/hoststated/hoststated.h b/usr.sbin/hoststated/hoststated.h index f0337aafa50..eac62bae1bd 100644 --- a/usr.sbin/hoststated/hoststated.h +++ b/usr.sbin/hoststated/hoststated.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hoststated.h,v 1.34 2007/02/26 12:35:43 reyk Exp $ */ +/* $OpenBSD: hoststated.h,v 1.35 2007/02/27 13:38:58 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -182,7 +182,13 @@ enum httpmethod { HTTP_METHOD_DELETE = 4, HTTP_METHOD_OPTIONS = 5, HTTP_METHOD_TRACE = 6, - HTTP_METHOD_CONNECT = 7 + HTTP_METHOD_CONNECT = 7, + HTTP_METHOD_RESPONSE = 8 /* Server response */ +}; + +enum direction { + RELAY_DIR_REQUEST = 0, + RELAY_DIR_RESPONSE = 1 }; struct ctl_relay_event { @@ -195,6 +201,7 @@ struct ctl_relay_event { void *con; SSL *ssl; u_int8_t *nodes; + struct proto_tree *tree; int marked; int line; @@ -202,6 +209,7 @@ struct ctl_relay_event { int chunked; int done; enum httpmethod method; + enum direction dir; u_int8_t *buf; int buflen; @@ -415,8 +423,10 @@ struct protocol { enum prototype type; int lateconnect; - int nodecount; - struct proto_tree tree; + int request_nodes; + struct proto_tree request_tree; + int response_nodes; + struct proto_tree response_tree; TAILQ_ENTRY(protocol) entry; }; TAILQ_HEAD(protolist, protocol); diff --git a/usr.sbin/hoststated/parse.y b/usr.sbin/hoststated/parse.y index f978c48f3e3..8fa77d94e08 100644 --- a/usr.sbin/hoststated/parse.y +++ b/usr.sbin/hoststated/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.32 2007/02/26 20:48:48 pyr Exp $ */ +/* $OpenBSD: parse.y,v 1.33 2007/02/27 13:38:58 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -104,7 +104,7 @@ typedef struct { %} %token SERVICE TABLE BACKUP HOST REAL -%token CHECK TCP ICMP EXTERNAL +%token CHECK TCP ICMP EXTERNAL REQUEST RESPONSE %token TIMEOUT CODE DIGEST PORT TAG INTERFACE %token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG %token SEND EXPECT NOTHING SSL LOADBALANCE ROUNDROBIN CIPHERS @@ -115,7 +115,7 @@ typedef struct { %token <v.string> STRING %type <v.string> interface %type <v.number> number port http_type loglevel sslcache optssl -%type <v.number> proto_type dstmode docheck retry log flag +%type <v.number> proto_type dstmode docheck retry log flag direction %type <v.host> host %type <v.tv> timeout @@ -549,7 +549,8 @@ proto : PROTO STRING { yyerror("too many protocols defined"); YYERROR; } - RB_INIT(&p->tree); + RB_INIT(&p->request_tree); + RB_INIT(&p->response_tree); proto = p; } '{' optnl protopts_l '}' { conf->protocount++; @@ -572,10 +573,15 @@ protoptsl : SSL sslflags | TCP tcpflags | TCP '{' tcpflags_l '}' | PROTO proto_type { proto->type = $2; } - | protonode log { - struct protonode *pn, pk; - - pn = RB_FIND(proto_tree, &proto->tree, &node); + | direction protonode log { + struct protonode *pn, pk; + struct proto_tree *tree; + + if ($1 == RELAY_DIR_RESPONSE) + tree = &proto->response_tree; + else + tree = &proto->request_tree; + pn = RB_FIND(proto_tree, tree, &node); if (pn != NULL) { yyerror("protocol node %s defined twice", node.key); @@ -588,21 +594,22 @@ protoptsl : SSL sslflags pn->key = node.key; pn->value = node.value; pn->type = node.type; - pn->id = proto->nodecount++; - if ($2) { - proto->lateconnect++; + if ($1 == RELAY_DIR_RESPONSE) + pn->id = proto->response_nodes++; + else + pn->id = proto->request_nodes++; + if ($3) pn->flags |= PNFLAG_LOG; - } if (pn->id == INT_MAX) { yyerror("too many protocol nodes defined"); YYERROR; } - RB_INSERT(proto_tree, &proto->tree, pn); + RB_INSERT(proto_tree, tree, pn); if (node.type != NODE_TYPE_HEADER) { pk.key = "GET"; pk.type = NODE_TYPE_HEADER; - pn = RB_FIND(proto_tree, &proto->tree, &pk); + pn = RB_FIND(proto_tree, tree, &pk); if (pn == NULL) { if ((pn = (struct protonode *) calloc(1, sizeof(*pn))) == NULL) @@ -613,13 +620,17 @@ protoptsl : SSL sslflags pn->value = NULL; pn->action = NODE_ACTION_NONE; pn->type = pk.type; - pn->id = proto->nodecount++; + if ($1 == RELAY_DIR_RESPONSE) + pn->id = + proto->response_nodes++; + else + pn->id = proto->request_nodes++; if (pn->id == INT_MAX) { yyerror("too many protocol " "nodes defined"); YYERROR; } - RB_INSERT(proto_tree, &proto->tree, pn); + RB_INSERT(proto_tree, tree, pn); } switch (node.type) { case NODE_TYPE_URL: @@ -637,6 +648,11 @@ protoptsl : SSL sslflags } ; +direction : /* empty */ { $$ = RELAY_DIR_REQUEST; } + | REQUEST { $$ = RELAY_DIR_REQUEST; } + | RESPONSE { $$ = RELAY_DIR_RESPONSE; } + ; + tcpflags_l : tcpflags comma tcpflags_l | tcpflags ; @@ -754,7 +770,6 @@ protonode : nodetype APPEND STRING TO STRING marked { if (node.key == NULL) fatal("out of memory"); free($3); - proto->lateconnect++; } ; @@ -1081,6 +1096,8 @@ lookup(char *s) { "real", REAL }, { "relay", RELAY }, { "remove", REMOVE }, + { "request", REQUEST }, + { "response", RESPONSE }, { "retry", RETRY }, { "roundrobin", ROUNDROBIN }, { "sack", SACK }, @@ -1333,7 +1350,8 @@ parse_config(struct hoststated *x_conf, const char *filename, int opts) conf->proto_default.type = RELAY_PROTO_TCP; (void)strlcpy(conf->proto_default.name, "default", sizeof(conf->proto_default.name)); - RB_INIT(&conf->proto_default.tree); + RB_INIT(&conf->proto_default.request_tree); + RB_INIT(&conf->proto_default.response_tree); TAILQ_INSERT_TAIL(&conf->protos, &conf->proto_default, entry); conf->timeout.tv_sec = CHECK_TIMEOUT / 1000; diff --git a/usr.sbin/hoststated/relay.c b/usr.sbin/hoststated/relay.c index ee7926ba114..d407e8d1047 100644 --- a/usr.sbin/hoststated/relay.c +++ b/usr.sbin/hoststated/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.13 2007/02/26 16:10:24 reyk Exp $ */ +/* $OpenBSD: relay.c,v 1.14 2007/02/27 13:38:58 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> @@ -273,6 +273,8 @@ relay_protodebug(struct relay *rlay) { struct protocol *proto = rlay->proto; struct protonode *pn; + struct proto_tree *tree; + const char *name; fprintf(stderr, "protocol %d: name %s\n", proto->id, proto->name); fprintf(stderr, "\tflags: 0x%04x\n", proto->flags); @@ -287,9 +289,15 @@ relay_protodebug(struct relay *rlay) fprintf(stderr, "http\n"); break; } - RB_FOREACH(pn, proto_tree, &proto->tree) { + + name = "request"; + tree = &proto->request_tree; + show: + RB_FOREACH(pn, proto_tree, tree) { fprintf(stderr, "\t\t"); + fprintf(stderr, "%s ", name); + switch (pn->type) { case NODE_TYPE_HEADER: break; @@ -334,6 +342,11 @@ relay_protodebug(struct relay *rlay) } fprintf(stderr, "\n"); } + if (tree == &proto->request_tree) { + name = "response"; + tree = &proto->response_tree; + goto show; + } } void @@ -597,6 +610,7 @@ relay_connected(int fd, short sig, void *arg) { struct session *con = (struct session *)arg; struct relay *rlay = (struct relay *)con->relay; + struct protocol *proto = rlay->proto; evbuffercb outrd = relay_read; evbuffercb outwr = relay_write; struct bufferevent *bev; @@ -609,6 +623,25 @@ relay_connected(int fd, short sig, void *arg) DPRINTF("relay_connected: session %d: %ssuccessful", con->id, rlay->proto->lateconnect ? "late connect " : ""); + switch (rlay->proto->type) { + case RELAY_PROTO_HTTP: + /* Check the servers's HTTP response */ + if (!RB_EMPTY(&rlay->proto->response_tree)) { + outrd = relay_read_http; + if ((con->out.nodes = calloc(proto->response_nodes, + sizeof(u_int8_t))) == NULL) { + relay_close(con, "failed to allocate nodes"); + return; + } + } + break; + case RELAY_PROTO_TCP: + /* Use defaults */ + break; + default: + fatalx("relay_input: unknown protocol"); + } + /* * Relay <-> Server */ @@ -639,11 +672,14 @@ relay_input(struct session *con) switch (rlay->proto->type) { case RELAY_PROTO_HTTP: /* Check the client's HTTP request */ - inrd = relay_read_http; - if ((con->in.nodes = calloc(proto->nodecount, - sizeof(u_int8_t))) == NULL) { - relay_close(con, "failed to allocate node buffer"); - return; + if (!RB_EMPTY(&rlay->proto->request_tree) || + proto->lateconnect) { + inrd = relay_read_http; + if ((con->in.nodes = calloc(proto->request_nodes, + sizeof(u_int8_t))) == NULL) { + relay_close(con, "failed to allocate nodes"); + return; + } } break; case RELAY_PROTO_TCP: @@ -1038,7 +1074,9 @@ relay_read_http(struct bufferevent *bev, void *arg) * Identify and handle specific HTTP request methods */ if (cre->line == 1) { - if (strcmp("GET", pk.key) == 0) + if (cre->dir == RELAY_DIR_RESPONSE) + cre->method = HTTP_METHOD_RESPONSE; + else if (strcmp("GET", pk.key) == 0) cre->method = HTTP_METHOD_GET; else if (strcmp("HEAD", pk.key) == 0) cre->method = HTTP_METHOD_HEAD; @@ -1055,7 +1093,8 @@ relay_read_http(struct bufferevent *bev, void *arg) else if (strcmp("CONNECT", pk.key) == 0) cre->method = HTTP_METHOD_CONNECT; } else if ((cre->method == HTTP_METHOD_POST || - cre->method == HTTP_METHOD_PUT) && + cre->method == HTTP_METHOD_PUT || + cre->method == HTTP_METHOD_RESPONSE) && strcasecmp("Content-Length", pk.key) == 0) { /* * Need to read data from the client after the @@ -1077,11 +1116,12 @@ relay_read_http(struct bufferevent *bev, void *arg) cre->chunked = 1; /* Match the HTTP header */ - if ((pn = RB_FIND(proto_tree, &proto->tree, &pk)) == NULL) + if ((pn = RB_FIND(proto_tree, cre->tree, &pk)) == NULL) goto next; /* Decode the URL */ - if (pn->flags & PNFLAG_LOOKUP_URL) { + if (pn->flags & PNFLAG_LOOKUP_URL && + cre->dir == RELAY_DIR_REQUEST) { url = strdup(pk.value); if (url == NULL) goto next; @@ -1105,7 +1145,7 @@ relay_read_http(struct bufferevent *bev, void *arg) continue; *pkv.value++ = '\0'; if ((pnv = RB_FIND(proto_tree, - &proto->tree, &pkv)) == NULL) + cre->tree, &pkv)) == NULL) continue; ret = relay_handle_http(cre, pnv, &pkv, 0); if (ret == 1) @@ -1140,7 +1180,7 @@ next: continue; } if (cre->done) { - RB_FOREACH(pn, proto_tree, &proto->tree) { + RB_FOREACH(pn, proto_tree, cre->tree) { if (cre->nodes[pn->id]) { cre->nodes[pn->id] = 0; continue; @@ -1194,6 +1234,7 @@ next: break; case HTTP_METHOD_POST: case HTTP_METHOD_PUT: + case HTTP_METHOD_RESPONSE: /* HTTP request payload */ if (cre->toread) { bev->readcb = relay_read_httpcontent; @@ -1220,7 +1261,8 @@ next: cre->done = 0; cre->chunked = 0; - if (proto->lateconnect && cre->dst->bev == NULL && + if (cre->dir == RELAY_DIR_REQUEST && + proto->lateconnect && cre->dst->bev == NULL && relay_connect(con) == -1) { relay_close(con, "session failed"); return; @@ -1284,6 +1326,7 @@ void relay_accept(int fd, short sig, void *arg) { struct relay *rlay = (struct relay *)arg; + struct protocol *proto = rlay->proto; struct session *con = NULL; struct ctl_natlook *cnl = NULL; socklen_t slen; @@ -1313,6 +1356,10 @@ relay_accept(int fd, short sig, void *arg) con->relay = rlay; con->id = ++relay_conid; con->outkey = rlay->dstkey; + con->in.tree = &proto->request_tree; + con->out.tree = &proto->response_tree; + con->in.dir = RELAY_DIR_REQUEST; + con->out.dir = RELAY_DIR_RESPONSE; if (gettimeofday(&con->tv_start, NULL)) goto err; bcopy(&con->tv_start, &con->tv_last, sizeof(con->tv_last)); |