summaryrefslogtreecommitdiff
path: root/usr.sbin/relayd/relay.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/relayd/relay.c')
-rw-r--r--usr.sbin/relayd/relay.c361
1 files changed, 209 insertions, 152 deletions
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) {