summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2007-11-19 14:48:20 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2007-11-19 14:48:20 +0000
commit4c531e2a02bcf90b8cc73c8795d1a1039207821d (patch)
tree620120625ab3b1b1e0fd3549faf91b479570eb6e /usr.sbin
parentc42b469a54c61a3d1eefce70aa16636281d6d6d7 (diff)
rework the internal handling of protocol actions a little bit:
- allow to use a key for multiple times by appending a queue of additional matches to the tree node. for example, this allows to specify multiple "expect" or "filter" actions to white-/black-list a list of HTTP-headers, URLs, .. - prevent specifing an HTTP header for multiple times when using the expect action. - minor code shuffling
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/hoststated/hoststated.c12
-rw-r--r--usr.sbin/hoststated/hoststated.h22
-rw-r--r--usr.sbin/hoststated/parse.y23
-rw-r--r--usr.sbin/hoststated/relay.c361
-rw-r--r--usr.sbin/relayd/parse.y23
-rw-r--r--usr.sbin/relayd/relay.c361
-rw-r--r--usr.sbin/relayd/relayd.c12
-rw-r--r--usr.sbin/relayd/relayd.h22
8 files changed, 494 insertions, 342 deletions
diff --git a/usr.sbin/hoststated/hoststated.c b/usr.sbin/hoststated/hoststated.c
index 9444c0c710e..9879309d7c6 100644
--- a/usr.sbin/hoststated/hoststated.c
+++ b/usr.sbin/hoststated/hoststated.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hoststated.c,v 1.52 2007/11/19 11:39:49 reyk Exp $ */
+/* $OpenBSD: hoststated.c,v 1.53 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -510,7 +510,7 @@ purge_config(struct hoststated *env, u_int8_t what)
void
purge_tree(struct proto_tree *tree)
{
- struct protonode *proot;
+ struct protonode *proot, *pn;
while ((proot = RB_ROOT(tree)) != NULL) {
RB_REMOVE(proto_tree, tree, proot);
@@ -518,6 +518,14 @@ purge_tree(struct proto_tree *tree)
free(proot->key);
if (proot->value != NULL)
free(proot->value);
+ while ((pn = SIMPLEQ_FIRST(&proot->head)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&proot->head, entry);
+ if (pn->key != NULL)
+ free(pn->key);
+ if (pn->value != NULL)
+ free(pn->value);
+ free(pn);
+ }
free(proot);
}
}
diff --git a/usr.sbin/hoststated/hoststated.h b/usr.sbin/hoststated/hoststated.h
index b16f662b4e3..8dcaa306973 100644
--- a/usr.sbin/hoststated/hoststated.h
+++ b/usr.sbin/hoststated/hoststated.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hoststated.h,v 1.72 2007/11/14 10:59:01 pyr Exp $ */
+/* $OpenBSD: hoststated.h,v 1.73 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -442,17 +442,23 @@ enum noderesult {
};
struct protonode {
- objid_t id;
- char *key;
- enum nodeaction action;
- char *value;
- u_int8_t flags;
- enum nodetype type;
+ objid_t id;
+ char *key;
+ enum nodeaction action;
+ char *value;
+ u_int8_t flags;
+ enum nodetype type;
- RB_ENTRY(protonode) nodes;
+ SIMPLEQ_HEAD(, protonode) head;
+ SIMPLEQ_ENTRY(protonode) entry;
+
+ RB_ENTRY(protonode) nodes;
};
RB_HEAD(proto_tree, protonode);
+#define PROTONODE_FOREACH(elm, root, field) \
+ for (elm = root; elm != NULL; elm = SIMPLEQ_NEXT(elm, entry)) \
+
enum prototype {
RELAY_PROTO_TCP = 0,
RELAY_PROTO_HTTP = 1,
diff --git a/usr.sbin/hoststated/parse.y b/usr.sbin/hoststated/parse.y
index 01495ccc16d..4bb3bd2a9b3 100644
--- a/usr.sbin/hoststated/parse.y
+++ b/usr.sbin/hoststated/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.81 2007/11/19 14:41:05 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.82 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -641,19 +641,13 @@ protoptsl : SSL sslflags
| TCP '{' tcpflags_l '}'
| PROTO proto_type { proto->type = $2; }
| direction protonode log {
- struct protonode *pn, pk;
+ struct protonode *pn, *proot, 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);
- YYERROR;
- }
if ((pn = calloc(1, sizeof (*pn))) == NULL)
fatal("out of memory");
@@ -661,6 +655,7 @@ protoptsl : SSL sslflags
pn->key = node.key;
pn->value = node.value;
pn->type = node.type;
+ SIMPLEQ_INIT(&pn->head);
if ($1 == RELAY_DIR_RESPONSE)
pn->id = proto->response_nodes++;
else
@@ -671,7 +666,17 @@ protoptsl : SSL sslflags
yyerror("too many protocol nodes defined");
YYERROR;
}
- RB_INSERT(proto_tree, tree, pn);
+ if ((proot =
+ RB_INSERT(proto_tree, tree, pn)) != NULL) {
+ /*
+ * A protocol node with the same key already
+ * exists, append it to a queue behind the
+ * existing node.
+ */
+ if (SIMPLEQ_EMPTY(&proot->head))
+ SIMPLEQ_NEXT(proot, entry) = pn;
+ SIMPLEQ_INSERT_TAIL(&proot->head, pn, entry);
+ }
if (node.type == NODE_TYPE_COOKIE)
pk.key = "Cookie";
diff --git a/usr.sbin/hoststated/relay.c b/usr.sbin/hoststated/relay.c
index f42f9efed69..06f1e64619f 100644
--- a/usr.sbin/hoststated/relay.c
+++ b/usr.sbin/hoststated/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.53 2007/10/22 17:14:10 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.54 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org>
@@ -56,6 +56,7 @@ void relay_dispatch_parent(int, short, void *);
void relay_shutdown(void);
void relay_privinit(void);
+void relay_nodedebug(const char *, struct protonode *);
void relay_protodebug(struct relay *);
void relay_init(void);
void relay_launch(void);
@@ -83,8 +84,12 @@ void relay_write(struct bufferevent *, void *);
void relay_read(struct bufferevent *, void *);
void relay_error(struct bufferevent *, short, void *);
+
+int relay_resolve(struct ctl_relay_event *,
+ struct protonode *, struct protonode *);
int relay_handle_http(struct ctl_relay_event *,
- struct protonode *, struct protonode *, int);
+ struct protonode *, struct protonode *,
+ struct protonode *, int);
void relay_read_http(struct bufferevent *, void *);
void relay_read_httpcontent(struct bufferevent *, void *);
void relay_read_httpchunks(struct bufferevent *, void *);
@@ -273,12 +278,66 @@ relay_shutdown(void)
}
void
+relay_nodedebug(const char *name, struct protonode *pn)
+{
+ fprintf(stderr, "\t\t");
+ fprintf(stderr, "%s ", name);
+
+ switch (pn->type) {
+ case NODE_TYPE_HEADER:
+ break;
+ case NODE_TYPE_URL:
+ fprintf(stderr, "url ");
+ break;
+ case NODE_TYPE_COOKIE:
+ fprintf(stderr, "cookie ");
+ break;
+ case NODE_TYPE_PATH:
+ fprintf(stderr, "path ");
+ break;
+ }
+
+ switch (pn->action) {
+ case NODE_ACTION_APPEND:
+ fprintf(stderr, "append \"%s\" to \"%s\"",
+ pn->value, pn->key);
+ break;
+ case NODE_ACTION_CHANGE:
+ fprintf(stderr, "change \"%s\" to \"%s\"",
+ pn->key, pn->value);
+ break;
+ case NODE_ACTION_REMOVE:
+ fprintf(stderr, "remove \"%s\"",
+ pn->key);
+ break;
+ case NODE_ACTION_EXPECT:
+ fprintf(stderr, "expect \"%s\" from \"%s\"",
+ pn->value, pn->key);
+ break;
+ case NODE_ACTION_FILTER:
+ fprintf(stderr, "filter \"%s\" from \"%s\"",
+ pn->value, pn->key);
+ break;
+ case NODE_ACTION_HASH:
+ fprintf(stderr, "hash \"%s\"", pn->key);
+ break;
+ case NODE_ACTION_LOG:
+ fprintf(stderr, "log \"%s\"", pn->key);
+ break;
+ case NODE_ACTION_NONE:
+ fprintf(stderr, "none \"%s\"", pn->key);
+ break;
+ }
+ fprintf(stderr, "\n");
+}
+
+void
relay_protodebug(struct relay *rlay)
{
- struct protocol *proto = rlay->proto;
- struct protonode *pn;
- struct proto_tree *tree;
- const char *name;
+ struct protocol *proto = rlay->proto;
+ struct protonode *proot, *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);
@@ -300,57 +359,9 @@ relay_protodebug(struct relay *rlay)
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;
- case NODE_TYPE_URL:
- fprintf(stderr, "url ");
- break;
- case NODE_TYPE_COOKIE:
- fprintf(stderr, "cookie ");
- break;
- case NODE_TYPE_PATH:
- fprintf(stderr, "path ");
- break;
- }
-
- switch (pn->action) {
- case NODE_ACTION_APPEND:
- fprintf(stderr, "append \"%s\" to \"%s\"",
- pn->value, pn->key);
- break;
- case NODE_ACTION_CHANGE:
- fprintf(stderr, "change \"%s\" to \"%s\"",
- pn->key, pn->value);
- break;
- case NODE_ACTION_REMOVE:
- fprintf(stderr, "remove \"%s\"",
- pn->key);
- break;
- case NODE_ACTION_EXPECT:
- fprintf(stderr, "expect \"%s\" from \"%s\"",
- pn->value, pn->key);
- break;
- case NODE_ACTION_FILTER:
- fprintf(stderr, "filter \"%s\" from \"%s\"",
- pn->value, pn->key);
- break;
- case NODE_ACTION_HASH:
- fprintf(stderr, "hash \"%s\"", pn->key);
- break;
- case NODE_ACTION_LOG:
- fprintf(stderr, "log \"%s\"", pn->key);
- break;
- case NODE_ACTION_NONE:
- fprintf(stderr, "none \"%s\"", pn->key);
- break;
- }
- fprintf(stderr, "\n");
+ RB_FOREACH(proot, proto_tree, tree) {
+ PROTONODE_FOREACH(pn, proot, entry)
+ relay_nodedebug(name, pn);
}
if (tree == &proto->request_tree) {
name = "response";
@@ -809,6 +820,76 @@ relay_read(struct bufferevent *bev, void *arg)
relay_close(con, strerror(errno));
}
+int
+relay_resolve(struct ctl_relay_event *cre,
+ struct protonode *proot, struct protonode *pn)
+{
+ struct session *con = (struct session *)cre->con;
+ char buf[READ_BUF_SIZE], *ptr;
+
+ switch (pn->action) {
+ case NODE_ACTION_FILTER:
+ if (!cre->nodes[pn->id])
+ return (0);
+ cre->nodes[pn->id] = 0;
+ break;
+ case NODE_ACTION_EXPECT:
+ if (proot == pn)
+ cre->nodes[proot->id]--;
+ if (cre->nodes[proot->id]) {
+ if (SIMPLEQ_NEXT(pn, entry) == NULL)
+ cre->nodes[proot->id] = 0;
+ return (0);
+ }
+ break;
+ default:
+ if (cre->nodes[pn->id]) {
+ cre->nodes[pn->id] = 0;
+ return (0);
+ }
+ break;
+ }
+ switch (pn->action) {
+ case NODE_ACTION_APPEND:
+ case NODE_ACTION_CHANGE:
+ ptr = pn->value;
+ if ((pn->flags & PNFLAG_MARK) &&
+ cre->marked == 0)
+ break;
+ if ((pn->flags & PNFLAG_MACRO) &&
+ (ptr = relay_expand_http(cre, pn->value,
+ buf, sizeof(buf))) == NULL)
+ break;
+ if (relay_bufferevent_print(cre->dst, pn->key) == -1 ||
+ relay_bufferevent_print(cre->dst, ": ") == -1 ||
+ relay_bufferevent_print(cre->dst, ptr) == -1 ||
+ relay_bufferevent_print(cre->dst, "\r\n") == -1) {
+ relay_close(con, "failed to modify header (done)");
+ return (-1);
+ }
+ DPRINTF("relay_resolve: add '%s: %s'",
+ pn->key, ptr);
+ break;
+ case NODE_ACTION_EXPECT:
+ if (pn->flags & PNFLAG_MARK)
+ break;
+ DPRINTF("relay_resolve: missing '%s: %s'",
+ pn->key, pn->value);
+ relay_close(con, "incomplete header (done)");
+ return (-1);
+ case NODE_ACTION_FILTER:
+ if (pn->flags & PNFLAG_MARK)
+ break;
+ DPRINTF("relay_resolve: filtered '%s: %s'",
+ pn->key, pn->value);
+ relay_close(con, "rejecting header (done)");
+ return (-1);
+ default:
+ break;
+ }
+ return (0);
+}
+
char *
relay_expand_http(struct ctl_relay_event *cre, char *val, char *buf, size_t len)
{
@@ -861,8 +942,8 @@ relay_expand_http(struct ctl_relay_event *cre, char *val, char *buf, size_t len)
int
-relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
- struct protonode *pk, int header)
+relay_handle_http(struct ctl_relay_event *cre, struct protonode *proot,
+ struct protonode *pn, struct protonode *pk, int header)
{
struct session *con = (struct session *)cre->con;
char buf[READ_BUF_SIZE], *ptr;
@@ -896,6 +977,14 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
pk->key, pk->value);
break;
case NODE_ACTION_EXPECT:
+ /*
+ * A client may specify the header line for multiple times
+ * trying to circumvent the filter.
+ */
+ if (cre->nodes[proot->id]) {
+ relay_close(con, "repeated header line (done)");
+ return (PN_FAIL);
+ }
ret = PN_PASS;
/* FALLTHROUGH */
case NODE_ACTION_FILTER:
@@ -905,8 +994,10 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
if (fnmatch(pn->value, pk->value, FNM_CASEFOLD) == 0) {
if (pn->flags & PNFLAG_MARK)
cre->marked++;
- cre->nodes[pn->id] = 1;
+ cre->nodes[proot->id] = 1;
}
+ if (SIMPLEQ_NEXT(pn, entry) == NULL)
+ cre->nodes[proot->id]++;
break;
case NODE_ACTION_HASH:
if ((pn->flags & PNFLAG_MARK) && cre->marked == 0)
@@ -1080,9 +1171,9 @@ relay_read_http(struct bufferevent *bev, void *arg)
struct relay *rlay = (struct relay *)con->relay;
struct protocol *proto = rlay->proto;
struct evbuffer *src = EVBUFFER_INPUT(bev);
- struct protonode *pn, pk, *pnv, pkv;
- char *line, buf[READ_BUF_SIZE], *ptr, *val;
- int header = 0, ret;
+ struct protonode *pn, pk, *proot, *pnv = NULL, pkv;
+ char *line, *ptr, *val;
+ int header = 0, ret, pass = 0;
const char *errstr;
size_t size;
@@ -1116,6 +1207,11 @@ relay_read_http(struct bufferevent *bev, void *arg)
} else
pk.value = strchr(pk.key, ':');
if (pk.value == NULL || strlen(pk.value) < 3) {
+ if (cre->line == 1) {
+ free(line);
+ goto fail;
+ }
+
DPRINTF("relay_read_http: request '%s'", line);
/* Append line to the output buffer */
if (relay_bufferevent_print(cre->dst, line) == -1 ||
@@ -1176,6 +1272,7 @@ relay_read_http(struct bufferevent *bev, void *arg)
if (cre->args != NULL)
*cre->args++ = '\0';
#ifdef DEBUG
+ char buf[BUFSIZ];
if (snprintf(buf, sizeof(buf), " \"%s\"",
cre->path) == -1 ||
evbuffer_add(con->log, buf, strlen(buf)) == -1) {
@@ -1197,14 +1294,17 @@ relay_read_http(struct bufferevent *bev, void *arg)
DPRINTF("relay_read_http: "
"lookup path '%s: %s'", pkv.key, pkv.value);
- if ((pnv = RB_FIND(proto_tree,
+ if ((proot = RB_FIND(proto_tree,
cre->tree, &pkv)) == NULL)
goto lookup;
- ret = relay_handle_http(cre, pnv, &pkv, 0);
- if (ret == PN_FAIL) {
- free(line);
- goto fail;
+ PROTONODE_FOREACH(pnv, proot, entry) {
+ ret = relay_handle_http(cre, proot,
+ pnv, &pkv, 0);
+ if (ret == PN_FAIL) {
+ free(line);
+ return;
+ }
}
} else if ((cre->method == HTTP_METHOD_POST ||
cre->method == HTTP_METHOD_PUT ||
@@ -1254,16 +1354,17 @@ relay_read_http(struct bufferevent *bev, void *arg)
continue;
*pkv.value++ = '\0';
- if ((pnv = RB_FIND(proto_tree,
+ if ((proot = RB_FIND(proto_tree,
cre->tree, &pkv)) == NULL)
continue;
- ret = relay_handle_http(cre, pnv, &pkv, 0);
- if (ret == PN_PASS)
- continue;
- else if (ret == PN_FAIL) {
- free(val);
- free(line);
- return;
+ PROTONODE_FOREACH(pnv, proot, entry) {
+ ret = relay_handle_http(cre, proot,
+ pnv, &pkv, 0);
+ if (ret == PN_FAIL) {
+ free(val);
+ free(line);
+ return;
+ }
}
}
free(val);
@@ -1299,97 +1400,53 @@ relay_read_http(struct bufferevent *bev, void *arg)
if (pkv.value[strlen(pkv.value) - 1] == '"')
pkv.value[strlen(pkv.value) - 1] = '\0';
- if ((pnv = RB_FIND(proto_tree,
+ if ((proot = RB_FIND(proto_tree,
cre->tree, &pkv)) == NULL)
continue;
- ret = relay_handle_http(cre, pnv, &pkv, 0);
- if (ret == PN_PASS)
- continue;
- else if (ret == PN_FAIL) {
- free(val);
- free(line);
- return;
+ PROTONODE_FOREACH(pnv, proot, entry) {
+ ret = relay_handle_http(cre, proot,
+ pnv, &pkv, 0);
+ if (ret == PN_FAIL) {
+ free(val);
+ free(line);
+ return;
+ }
}
}
free(val);
}
handle:
- ret = relay_handle_http(cre, pn, &pk, header);
- if (ret == PN_PASS)
- goto next;
- free(line);
- if (ret == PN_FAIL)
- return;
- continue;
+ pass = 0;
+ PROTONODE_FOREACH(pnv, pn, entry) {
+ ret = relay_handle_http(cre, pn, pnv, &pk, header);
+ if (ret == PN_PASS)
+ pass = 1;
+ else if (ret == PN_FAIL) {
+ free(line);
+ return;
+ }
+ }
+ if (pass) {
next:
- if (relay_bufferevent_print(cre->dst, pk.key) == -1 ||
- relay_bufferevent_print(cre->dst,
- header ? ": " : " ") == -1 ||
- relay_bufferevent_print(cre->dst, pk.value) == -1 ||
- relay_bufferevent_print(cre->dst, "\r\n") == -1) {
- free(line);
- goto fail;
+ if (relay_bufferevent_print(cre->dst, pk.key) == -1 ||
+ relay_bufferevent_print(cre->dst,
+ header ? ": " : " ") == -1 ||
+ relay_bufferevent_print(cre->dst, pk.value) == -1 ||
+ relay_bufferevent_print(cre->dst, "\r\n") == -1) {
+ free(line);
+ goto fail;
+ }
}
free(line);
continue;
}
if (cre->done) {
- RB_FOREACH(pn, proto_tree, cre->tree) {
- switch (pn->action) {
- case NODE_ACTION_FILTER:
- if (!cre->nodes[pn->id])
- continue;
- cre->nodes[pn->id] = 0;
- break;
- default:
- if (cre->nodes[pn->id]) {
- cre->nodes[pn->id] = 0;
- continue;
- }
- break;
- }
- switch (pn->action) {
- case NODE_ACTION_APPEND:
- case NODE_ACTION_CHANGE:
- ptr = pn->value;
- if ((pn->flags & PNFLAG_MARK) &&
- cre->marked == 0)
- break;
- if ((pn->flags & PNFLAG_MACRO) &&
- (ptr = relay_expand_http(cre, pn->value,
- buf, sizeof(buf))) == NULL)
- break;
- if (relay_bufferevent_print(cre->dst,
- pn->key) == -1 ||
- relay_bufferevent_print(cre->dst,
- ": ") == -1 ||
- relay_bufferevent_print(cre->dst,
- ptr) == -1 ||
- relay_bufferevent_print(cre->dst,
- "\r\n") == -1)
- goto fail;
- DPRINTF("relay_read_http: add '%s: %s'",
- pn->key, ptr);
- break;
- case NODE_ACTION_EXPECT:
- if (pn->flags & PNFLAG_MARK)
- break;
- DPRINTF("relay_read_http: missing '%s: %s'",
- pn->key, pn->value);
- relay_close(con, "incomplete header (done)");
- return;
- case NODE_ACTION_FILTER:
- if (pn->flags & PNFLAG_MARK)
- break;
- DPRINTF("relay_read_http: filtered '%s: %s'",
- pn->key, pn->value);
- relay_close(con, "rejecting header (done)");
- return;
- default:
- break;
- }
+ RB_FOREACH(proot, proto_tree, cre->tree) {
+ PROTONODE_FOREACH(pn, proot, entry)
+ if (relay_resolve(cre, proot, pn) != 0)
+ return;
}
switch (cre->method) {
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index 01495ccc16d..4bb3bd2a9b3 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.81 2007/11/19 14:41:05 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.82 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -641,19 +641,13 @@ protoptsl : SSL sslflags
| TCP '{' tcpflags_l '}'
| PROTO proto_type { proto->type = $2; }
| direction protonode log {
- struct protonode *pn, pk;
+ struct protonode *pn, *proot, 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);
- YYERROR;
- }
if ((pn = calloc(1, sizeof (*pn))) == NULL)
fatal("out of memory");
@@ -661,6 +655,7 @@ protoptsl : SSL sslflags
pn->key = node.key;
pn->value = node.value;
pn->type = node.type;
+ SIMPLEQ_INIT(&pn->head);
if ($1 == RELAY_DIR_RESPONSE)
pn->id = proto->response_nodes++;
else
@@ -671,7 +666,17 @@ protoptsl : SSL sslflags
yyerror("too many protocol nodes defined");
YYERROR;
}
- RB_INSERT(proto_tree, tree, pn);
+ if ((proot =
+ RB_INSERT(proto_tree, tree, pn)) != NULL) {
+ /*
+ * A protocol node with the same key already
+ * exists, append it to a queue behind the
+ * existing node.
+ */
+ if (SIMPLEQ_EMPTY(&proot->head))
+ SIMPLEQ_NEXT(proot, entry) = pn;
+ SIMPLEQ_INSERT_TAIL(&proot->head, pn, entry);
+ }
if (node.type == NODE_TYPE_COOKIE)
pk.key = "Cookie";
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index f42f9efed69..06f1e64619f 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.53 2007/10/22 17:14:10 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.54 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org>
@@ -56,6 +56,7 @@ void relay_dispatch_parent(int, short, void *);
void relay_shutdown(void);
void relay_privinit(void);
+void relay_nodedebug(const char *, struct protonode *);
void relay_protodebug(struct relay *);
void relay_init(void);
void relay_launch(void);
@@ -83,8 +84,12 @@ void relay_write(struct bufferevent *, void *);
void relay_read(struct bufferevent *, void *);
void relay_error(struct bufferevent *, short, void *);
+
+int relay_resolve(struct ctl_relay_event *,
+ struct protonode *, struct protonode *);
int relay_handle_http(struct ctl_relay_event *,
- struct protonode *, struct protonode *, int);
+ struct protonode *, struct protonode *,
+ struct protonode *, int);
void relay_read_http(struct bufferevent *, void *);
void relay_read_httpcontent(struct bufferevent *, void *);
void relay_read_httpchunks(struct bufferevent *, void *);
@@ -273,12 +278,66 @@ relay_shutdown(void)
}
void
+relay_nodedebug(const char *name, struct protonode *pn)
+{
+ fprintf(stderr, "\t\t");
+ fprintf(stderr, "%s ", name);
+
+ switch (pn->type) {
+ case NODE_TYPE_HEADER:
+ break;
+ case NODE_TYPE_URL:
+ fprintf(stderr, "url ");
+ break;
+ case NODE_TYPE_COOKIE:
+ fprintf(stderr, "cookie ");
+ break;
+ case NODE_TYPE_PATH:
+ fprintf(stderr, "path ");
+ break;
+ }
+
+ switch (pn->action) {
+ case NODE_ACTION_APPEND:
+ fprintf(stderr, "append \"%s\" to \"%s\"",
+ pn->value, pn->key);
+ break;
+ case NODE_ACTION_CHANGE:
+ fprintf(stderr, "change \"%s\" to \"%s\"",
+ pn->key, pn->value);
+ break;
+ case NODE_ACTION_REMOVE:
+ fprintf(stderr, "remove \"%s\"",
+ pn->key);
+ break;
+ case NODE_ACTION_EXPECT:
+ fprintf(stderr, "expect \"%s\" from \"%s\"",
+ pn->value, pn->key);
+ break;
+ case NODE_ACTION_FILTER:
+ fprintf(stderr, "filter \"%s\" from \"%s\"",
+ pn->value, pn->key);
+ break;
+ case NODE_ACTION_HASH:
+ fprintf(stderr, "hash \"%s\"", pn->key);
+ break;
+ case NODE_ACTION_LOG:
+ fprintf(stderr, "log \"%s\"", pn->key);
+ break;
+ case NODE_ACTION_NONE:
+ fprintf(stderr, "none \"%s\"", pn->key);
+ break;
+ }
+ fprintf(stderr, "\n");
+}
+
+void
relay_protodebug(struct relay *rlay)
{
- struct protocol *proto = rlay->proto;
- struct protonode *pn;
- struct proto_tree *tree;
- const char *name;
+ struct protocol *proto = rlay->proto;
+ struct protonode *proot, *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);
@@ -300,57 +359,9 @@ relay_protodebug(struct relay *rlay)
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;
- case NODE_TYPE_URL:
- fprintf(stderr, "url ");
- break;
- case NODE_TYPE_COOKIE:
- fprintf(stderr, "cookie ");
- break;
- case NODE_TYPE_PATH:
- fprintf(stderr, "path ");
- break;
- }
-
- switch (pn->action) {
- case NODE_ACTION_APPEND:
- fprintf(stderr, "append \"%s\" to \"%s\"",
- pn->value, pn->key);
- break;
- case NODE_ACTION_CHANGE:
- fprintf(stderr, "change \"%s\" to \"%s\"",
- pn->key, pn->value);
- break;
- case NODE_ACTION_REMOVE:
- fprintf(stderr, "remove \"%s\"",
- pn->key);
- break;
- case NODE_ACTION_EXPECT:
- fprintf(stderr, "expect \"%s\" from \"%s\"",
- pn->value, pn->key);
- break;
- case NODE_ACTION_FILTER:
- fprintf(stderr, "filter \"%s\" from \"%s\"",
- pn->value, pn->key);
- break;
- case NODE_ACTION_HASH:
- fprintf(stderr, "hash \"%s\"", pn->key);
- break;
- case NODE_ACTION_LOG:
- fprintf(stderr, "log \"%s\"", pn->key);
- break;
- case NODE_ACTION_NONE:
- fprintf(stderr, "none \"%s\"", pn->key);
- break;
- }
- fprintf(stderr, "\n");
+ RB_FOREACH(proot, proto_tree, tree) {
+ PROTONODE_FOREACH(pn, proot, entry)
+ relay_nodedebug(name, pn);
}
if (tree == &proto->request_tree) {
name = "response";
@@ -809,6 +820,76 @@ relay_read(struct bufferevent *bev, void *arg)
relay_close(con, strerror(errno));
}
+int
+relay_resolve(struct ctl_relay_event *cre,
+ struct protonode *proot, struct protonode *pn)
+{
+ struct session *con = (struct session *)cre->con;
+ char buf[READ_BUF_SIZE], *ptr;
+
+ switch (pn->action) {
+ case NODE_ACTION_FILTER:
+ if (!cre->nodes[pn->id])
+ return (0);
+ cre->nodes[pn->id] = 0;
+ break;
+ case NODE_ACTION_EXPECT:
+ if (proot == pn)
+ cre->nodes[proot->id]--;
+ if (cre->nodes[proot->id]) {
+ if (SIMPLEQ_NEXT(pn, entry) == NULL)
+ cre->nodes[proot->id] = 0;
+ return (0);
+ }
+ break;
+ default:
+ if (cre->nodes[pn->id]) {
+ cre->nodes[pn->id] = 0;
+ return (0);
+ }
+ break;
+ }
+ switch (pn->action) {
+ case NODE_ACTION_APPEND:
+ case NODE_ACTION_CHANGE:
+ ptr = pn->value;
+ if ((pn->flags & PNFLAG_MARK) &&
+ cre->marked == 0)
+ break;
+ if ((pn->flags & PNFLAG_MACRO) &&
+ (ptr = relay_expand_http(cre, pn->value,
+ buf, sizeof(buf))) == NULL)
+ break;
+ if (relay_bufferevent_print(cre->dst, pn->key) == -1 ||
+ relay_bufferevent_print(cre->dst, ": ") == -1 ||
+ relay_bufferevent_print(cre->dst, ptr) == -1 ||
+ relay_bufferevent_print(cre->dst, "\r\n") == -1) {
+ relay_close(con, "failed to modify header (done)");
+ return (-1);
+ }
+ DPRINTF("relay_resolve: add '%s: %s'",
+ pn->key, ptr);
+ break;
+ case NODE_ACTION_EXPECT:
+ if (pn->flags & PNFLAG_MARK)
+ break;
+ DPRINTF("relay_resolve: missing '%s: %s'",
+ pn->key, pn->value);
+ relay_close(con, "incomplete header (done)");
+ return (-1);
+ case NODE_ACTION_FILTER:
+ if (pn->flags & PNFLAG_MARK)
+ break;
+ DPRINTF("relay_resolve: filtered '%s: %s'",
+ pn->key, pn->value);
+ relay_close(con, "rejecting header (done)");
+ return (-1);
+ default:
+ break;
+ }
+ return (0);
+}
+
char *
relay_expand_http(struct ctl_relay_event *cre, char *val, char *buf, size_t len)
{
@@ -861,8 +942,8 @@ relay_expand_http(struct ctl_relay_event *cre, char *val, char *buf, size_t len)
int
-relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
- struct protonode *pk, int header)
+relay_handle_http(struct ctl_relay_event *cre, struct protonode *proot,
+ struct protonode *pn, struct protonode *pk, int header)
{
struct session *con = (struct session *)cre->con;
char buf[READ_BUF_SIZE], *ptr;
@@ -896,6 +977,14 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
pk->key, pk->value);
break;
case NODE_ACTION_EXPECT:
+ /*
+ * A client may specify the header line for multiple times
+ * trying to circumvent the filter.
+ */
+ if (cre->nodes[proot->id]) {
+ relay_close(con, "repeated header line (done)");
+ return (PN_FAIL);
+ }
ret = PN_PASS;
/* FALLTHROUGH */
case NODE_ACTION_FILTER:
@@ -905,8 +994,10 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *pn,
if (fnmatch(pn->value, pk->value, FNM_CASEFOLD) == 0) {
if (pn->flags & PNFLAG_MARK)
cre->marked++;
- cre->nodes[pn->id] = 1;
+ cre->nodes[proot->id] = 1;
}
+ if (SIMPLEQ_NEXT(pn, entry) == NULL)
+ cre->nodes[proot->id]++;
break;
case NODE_ACTION_HASH:
if ((pn->flags & PNFLAG_MARK) && cre->marked == 0)
@@ -1080,9 +1171,9 @@ relay_read_http(struct bufferevent *bev, void *arg)
struct relay *rlay = (struct relay *)con->relay;
struct protocol *proto = rlay->proto;
struct evbuffer *src = EVBUFFER_INPUT(bev);
- struct protonode *pn, pk, *pnv, pkv;
- char *line, buf[READ_BUF_SIZE], *ptr, *val;
- int header = 0, ret;
+ struct protonode *pn, pk, *proot, *pnv = NULL, pkv;
+ char *line, *ptr, *val;
+ int header = 0, ret, pass = 0;
const char *errstr;
size_t size;
@@ -1116,6 +1207,11 @@ relay_read_http(struct bufferevent *bev, void *arg)
} else
pk.value = strchr(pk.key, ':');
if (pk.value == NULL || strlen(pk.value) < 3) {
+ if (cre->line == 1) {
+ free(line);
+ goto fail;
+ }
+
DPRINTF("relay_read_http: request '%s'", line);
/* Append line to the output buffer */
if (relay_bufferevent_print(cre->dst, line) == -1 ||
@@ -1176,6 +1272,7 @@ relay_read_http(struct bufferevent *bev, void *arg)
if (cre->args != NULL)
*cre->args++ = '\0';
#ifdef DEBUG
+ char buf[BUFSIZ];
if (snprintf(buf, sizeof(buf), " \"%s\"",
cre->path) == -1 ||
evbuffer_add(con->log, buf, strlen(buf)) == -1) {
@@ -1197,14 +1294,17 @@ relay_read_http(struct bufferevent *bev, void *arg)
DPRINTF("relay_read_http: "
"lookup path '%s: %s'", pkv.key, pkv.value);
- if ((pnv = RB_FIND(proto_tree,
+ if ((proot = RB_FIND(proto_tree,
cre->tree, &pkv)) == NULL)
goto lookup;
- ret = relay_handle_http(cre, pnv, &pkv, 0);
- if (ret == PN_FAIL) {
- free(line);
- goto fail;
+ PROTONODE_FOREACH(pnv, proot, entry) {
+ ret = relay_handle_http(cre, proot,
+ pnv, &pkv, 0);
+ if (ret == PN_FAIL) {
+ free(line);
+ return;
+ }
}
} else if ((cre->method == HTTP_METHOD_POST ||
cre->method == HTTP_METHOD_PUT ||
@@ -1254,16 +1354,17 @@ relay_read_http(struct bufferevent *bev, void *arg)
continue;
*pkv.value++ = '\0';
- if ((pnv = RB_FIND(proto_tree,
+ if ((proot = RB_FIND(proto_tree,
cre->tree, &pkv)) == NULL)
continue;
- ret = relay_handle_http(cre, pnv, &pkv, 0);
- if (ret == PN_PASS)
- continue;
- else if (ret == PN_FAIL) {
- free(val);
- free(line);
- return;
+ PROTONODE_FOREACH(pnv, proot, entry) {
+ ret = relay_handle_http(cre, proot,
+ pnv, &pkv, 0);
+ if (ret == PN_FAIL) {
+ free(val);
+ free(line);
+ return;
+ }
}
}
free(val);
@@ -1299,97 +1400,53 @@ relay_read_http(struct bufferevent *bev, void *arg)
if (pkv.value[strlen(pkv.value) - 1] == '"')
pkv.value[strlen(pkv.value) - 1] = '\0';
- if ((pnv = RB_FIND(proto_tree,
+ if ((proot = RB_FIND(proto_tree,
cre->tree, &pkv)) == NULL)
continue;
- ret = relay_handle_http(cre, pnv, &pkv, 0);
- if (ret == PN_PASS)
- continue;
- else if (ret == PN_FAIL) {
- free(val);
- free(line);
- return;
+ PROTONODE_FOREACH(pnv, proot, entry) {
+ ret = relay_handle_http(cre, proot,
+ pnv, &pkv, 0);
+ if (ret == PN_FAIL) {
+ free(val);
+ free(line);
+ return;
+ }
}
}
free(val);
}
handle:
- ret = relay_handle_http(cre, pn, &pk, header);
- if (ret == PN_PASS)
- goto next;
- free(line);
- if (ret == PN_FAIL)
- return;
- continue;
+ pass = 0;
+ PROTONODE_FOREACH(pnv, pn, entry) {
+ ret = relay_handle_http(cre, pn, pnv, &pk, header);
+ if (ret == PN_PASS)
+ pass = 1;
+ else if (ret == PN_FAIL) {
+ free(line);
+ return;
+ }
+ }
+ if (pass) {
next:
- if (relay_bufferevent_print(cre->dst, pk.key) == -1 ||
- relay_bufferevent_print(cre->dst,
- header ? ": " : " ") == -1 ||
- relay_bufferevent_print(cre->dst, pk.value) == -1 ||
- relay_bufferevent_print(cre->dst, "\r\n") == -1) {
- free(line);
- goto fail;
+ if (relay_bufferevent_print(cre->dst, pk.key) == -1 ||
+ relay_bufferevent_print(cre->dst,
+ header ? ": " : " ") == -1 ||
+ relay_bufferevent_print(cre->dst, pk.value) == -1 ||
+ relay_bufferevent_print(cre->dst, "\r\n") == -1) {
+ free(line);
+ goto fail;
+ }
}
free(line);
continue;
}
if (cre->done) {
- RB_FOREACH(pn, proto_tree, cre->tree) {
- switch (pn->action) {
- case NODE_ACTION_FILTER:
- if (!cre->nodes[pn->id])
- continue;
- cre->nodes[pn->id] = 0;
- break;
- default:
- if (cre->nodes[pn->id]) {
- cre->nodes[pn->id] = 0;
- continue;
- }
- break;
- }
- switch (pn->action) {
- case NODE_ACTION_APPEND:
- case NODE_ACTION_CHANGE:
- ptr = pn->value;
- if ((pn->flags & PNFLAG_MARK) &&
- cre->marked == 0)
- break;
- if ((pn->flags & PNFLAG_MACRO) &&
- (ptr = relay_expand_http(cre, pn->value,
- buf, sizeof(buf))) == NULL)
- break;
- if (relay_bufferevent_print(cre->dst,
- pn->key) == -1 ||
- relay_bufferevent_print(cre->dst,
- ": ") == -1 ||
- relay_bufferevent_print(cre->dst,
- ptr) == -1 ||
- relay_bufferevent_print(cre->dst,
- "\r\n") == -1)
- goto fail;
- DPRINTF("relay_read_http: add '%s: %s'",
- pn->key, ptr);
- break;
- case NODE_ACTION_EXPECT:
- if (pn->flags & PNFLAG_MARK)
- break;
- DPRINTF("relay_read_http: missing '%s: %s'",
- pn->key, pn->value);
- relay_close(con, "incomplete header (done)");
- return;
- case NODE_ACTION_FILTER:
- if (pn->flags & PNFLAG_MARK)
- break;
- DPRINTF("relay_read_http: filtered '%s: %s'",
- pn->key, pn->value);
- relay_close(con, "rejecting header (done)");
- return;
- default:
- break;
- }
+ RB_FOREACH(proot, proto_tree, cre->tree) {
+ PROTONODE_FOREACH(pn, proot, entry)
+ if (relay_resolve(cre, proot, pn) != 0)
+ return;
}
switch (cre->method) {
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index 82b31811c15..8c1dc61e355 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.52 2007/11/19 11:39:49 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.53 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -510,7 +510,7 @@ purge_config(struct hoststated *env, u_int8_t what)
void
purge_tree(struct proto_tree *tree)
{
- struct protonode *proot;
+ struct protonode *proot, *pn;
while ((proot = RB_ROOT(tree)) != NULL) {
RB_REMOVE(proto_tree, tree, proot);
@@ -518,6 +518,14 @@ purge_tree(struct proto_tree *tree)
free(proot->key);
if (proot->value != NULL)
free(proot->value);
+ while ((pn = SIMPLEQ_FIRST(&proot->head)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&proot->head, entry);
+ if (pn->key != NULL)
+ free(pn->key);
+ if (pn->value != NULL)
+ free(pn->value);
+ free(pn);
+ }
free(proot);
}
}
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index f4fba6829de..1a4ec09e124 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.72 2007/11/14 10:59:01 pyr Exp $ */
+/* $OpenBSD: relayd.h,v 1.73 2007/11/19 14:48:19 reyk Exp $ */
/*
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -442,17 +442,23 @@ enum noderesult {
};
struct protonode {
- objid_t id;
- char *key;
- enum nodeaction action;
- char *value;
- u_int8_t flags;
- enum nodetype type;
+ objid_t id;
+ char *key;
+ enum nodeaction action;
+ char *value;
+ u_int8_t flags;
+ enum nodetype type;
- RB_ENTRY(protonode) nodes;
+ SIMPLEQ_HEAD(, protonode) head;
+ SIMPLEQ_ENTRY(protonode) entry;
+
+ RB_ENTRY(protonode) nodes;
};
RB_HEAD(proto_tree, protonode);
+#define PROTONODE_FOREACH(elm, root, field) \
+ for (elm = root; elm != NULL; elm = SIMPLEQ_NEXT(elm, entry)) \
+
enum prototype {
RELAY_PROTO_TCP = 0,
RELAY_PROTO_HTTP = 1,