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.c319
1 files changed, 154 insertions, 165 deletions
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index 4375cca391c..09642f5b9cd 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.171 2014/06/27 07:49:08 andre Exp $ */
+/* $OpenBSD: relay.c,v 1.172 2014/07/09 16:42:05 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -56,8 +56,8 @@ int relay_dispatch_ca(int, struct privsep_proc *,
struct imsg *);
void relay_shutdown(void);
-void relay_nodedebug(const char *, struct protonode *);
void relay_protodebug(struct relay *);
+void relay_ruledebug(struct relay_rule *);
void relay_init(struct privsep *, struct privsep_proc *p, void *);
void relay_launch(void);
int relay_socket(struct sockaddr_storage *, in_port_t,
@@ -83,8 +83,6 @@ void relay_ssl_readcb(int, short, void *);
void relay_ssl_writecb(int, short, void *);
char *relay_load_file(const char *, off_t *);
-static __inline int
- relay_proto_cmp(struct protonode *, struct protonode *);
extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t,
size_t, void *);
@@ -104,8 +102,11 @@ static struct privsep_proc procs[] = {
pid_t
relay(struct privsep *ps, struct privsep_proc *p)
{
+ pid_t pid;
env = ps->ps_env;
- return (proc_run(ps, p, procs, nitems(procs), relay_init, NULL));
+ pid = proc_run(ps, p, procs, nitems(procs), relay_init, NULL);
+ relay_http(env);
+ return (pid);
}
void
@@ -116,74 +117,125 @@ relay_shutdown(void)
}
void
-relay_nodedebug(const char *name, struct protonode *pn)
+relay_ruledebug(struct relay_rule *rule)
{
- const char *s;
- int digest;
-
- if (pn->action == NODE_ACTION_NONE)
- return;
+ struct kv *kv = NULL;
+ u_int i;
fprintf(stderr, "\t\t");
- fprintf(stderr, "%s ", name);
- switch (pn->type) {
- case NODE_TYPE_HEADER:
- break;
- case NODE_TYPE_QUERY:
- fprintf(stderr, "query ");
+ switch (rule->rule_action) {
+ case RULE_ACTION_MATCH:
+ fprintf(stderr, "match ");
break;
- case NODE_TYPE_COOKIE:
- fprintf(stderr, "cookie ");
+ case RULE_ACTION_BLOCK:
+ fprintf(stderr, "block ");
break;
- case NODE_TYPE_PATH:
- fprintf(stderr, "path ");
- break;
- case NODE_TYPE_URL:
- fprintf(stderr, "url ");
+ case RULE_ACTION_PASS:
+ fprintf(stderr, "pass ");
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);
+ switch (rule->rule_dir) {
+ case RELAY_DIR_ANY:
break;
- case NODE_ACTION_REMOVE:
- fprintf(stderr, "remove \"%s\"",
- pn->key);
+ case RELAY_DIR_REQUEST:
+ fprintf(stderr, "request ");
break;
- case NODE_ACTION_EXPECT:
- case NODE_ACTION_FILTER:
- s = pn->action == NODE_ACTION_EXPECT ? "expect" : "filter";
- digest = pn->flags & PNFLAG_LOOKUP_URL_DIGEST;
- if (strcmp(pn->value, "*") == 0)
- fprintf(stderr, "%s %s\"%s\"", s,
- digest ? "digest " : "", pn->key);
- else
- fprintf(stderr, "%s \"%s\" from \"%s\"", 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_MARK:
- if (strcmp(pn->value, "*") == 0)
- fprintf(stderr, "mark \"%s\"", pn->key);
- else
- fprintf(stderr, "mark \"%s\" from \"%s\"",
- pn->value, pn->key);
+ case RELAY_DIR_RESPONSE:
+ fprintf(stderr, "response ");
break;
- case NODE_ACTION_NONE:
+ default:
+ return;
+ /* NOTREACHED */
break;
}
+
+ if (rule->rule_flags & RULE_FLAG_QUICK)
+ fprintf(stderr, "quick ");
+
+ for (i = 1; i < KEY_TYPE_MAX; i++) {
+ kv = &rule->rule_kv[i];
+ if (kv->kv_type != i)
+ continue;
+
+ switch (kv->kv_type) {
+ case KEY_TYPE_COOKIE:
+ fprintf(stderr, "cookie ");
+ break;
+ case KEY_TYPE_HEADER:
+ fprintf(stderr, "header ");
+ break;
+ case KEY_TYPE_PATH:
+ fprintf(stderr, "path ");
+ break;
+ case KEY_TYPE_QUERY:
+ fprintf(stderr, "query ");
+ break;
+ case KEY_TYPE_URL:
+ fprintf(stderr, "url ");
+ break;
+ default:
+ continue;
+ }
+
+ switch (kv->kv_option) {
+ case KEY_OPTION_APPEND:
+ fprintf(stderr, "append ");
+ break;
+ case KEY_OPTION_SET:
+ fprintf(stderr, "set ");
+ break;
+ case KEY_OPTION_REMOVE:
+ fprintf(stderr, "remove ");
+ break;
+ case KEY_OPTION_HASH:
+ fprintf(stderr, "hash ");
+ break;
+ case KEY_OPTION_LOG:
+ fprintf(stderr, "log ");
+ break;
+ case KEY_OPTION_NONE:
+ break;
+ }
+
+ switch (kv->kv_digest) {
+ case DIGEST_SHA1:
+ case DIGEST_MD5:
+ fprintf(stderr, "digest ");
+ break;
+ default:
+ break;
+ }
+
+ fprintf(stderr, "%s%s%s%s%s%s ",
+ kv->kv_key == NULL ? "" : "\"",
+ kv->kv_key == NULL ? "" : kv->kv_key,
+ kv->kv_key == NULL ? "" : "\"",
+ kv->kv_value == NULL ? "" : " value \"",
+ kv->kv_value == NULL ? "" : kv->kv_value,
+ kv->kv_value == NULL ? "" : "\"");
+ }
+
+ if (rule->rule_tablename[0])
+ fprintf(stderr, "forward to <%s> ", rule->rule_tablename);
+
+ if (rule->rule_tag == -1)
+ fprintf(stderr, "no tag ");
+ else if (rule->rule_tag && rule->rule_tagname[0])
+ fprintf(stderr, "tag \"%s\" ",
+ rule->rule_tagname);
+
+ if (rule->rule_tagged && rule->rule_taggedname[0])
+ fprintf(stderr, "tagged \"%s\" ",
+ rule->rule_taggedname);
+
+ if (rule->rule_label == -1)
+ fprintf(stderr, "no label ");
+ else if (rule->rule_label && rule->rule_labelname[0])
+ fprintf(stderr, "label \"%s\" ",
+ rule->rule_labelname);
+
fprintf(stderr, "\n");
}
@@ -191,10 +243,7 @@ void
relay_protodebug(struct relay *rlay)
{
struct protocol *proto = rlay->rl_proto;
- struct protonode *proot, *pn;
- struct proto_tree *tree;
- const char *name;
- int i;
+ struct relay_rule *rule = NULL;
fprintf(stderr, "protocol %d: name %s\n",
proto->id, proto->name);
@@ -222,32 +271,10 @@ relay_protodebug(struct relay *rlay)
break;
}
- name = "request";
- tree = &proto->request_tree;
- show:
- i = 0;
- RB_FOREACH(proot, proto_tree, tree) {
-#if DEBUG > 1
- i = 0;
-#endif
- PROTONODE_FOREACH(pn, proot, entry) {
-#if DEBUG > 1
- i = 0;
-#endif
- if (++i > 100)
- break;
- relay_nodedebug(name, pn);
- }
- /* Limit the number of displayed lines */
- if (++i > 100) {
- fprintf(stderr, "\t\t...\n");
- break;
- }
- }
- if (tree == &proto->request_tree) {
- name = "response";
- tree = &proto->response_tree;
- goto show;
+ rule = TAILQ_FIRST(&proto->rules);
+ while (rule != NULL) {
+ relay_ruledebug(rule);
+ rule = TAILQ_NEXT(rule, rule_entry);
}
}
@@ -266,8 +293,8 @@ relay_privinit(struct relay *rlay)
relay_udp_privinit(env, rlay);
break;
case RELAY_PROTO_TCP:
+ break;
case RELAY_PROTO_HTTP:
- /* Use defaults */
break;
}
@@ -384,6 +411,13 @@ relay_launch(void)
fatal("relay_init: failed to create SSL context");
TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
+ /*
+ * set rule->rule_table in advance and save time
+ * looking up for this later on rule/connection
+ * evalution
+ */
+ rule_settable(&rlay->rl_proto->rules, rlt);
+
switch (rlt->rlt_mode) {
case RELAY_DSTMODE_ROUNDROBIN:
case RELAY_DSTMODE_RANDOM:
@@ -418,6 +452,7 @@ relay_launch(void)
break;
case RELAY_PROTO_TCP:
case RELAY_PROTO_HTTP:
+ relay_http_init(rlay);
/* Use defaults */
break;
}
@@ -608,7 +643,6 @@ relay_connected(int fd, short sig, void *arg)
{
struct rsession *con = arg;
struct relay *rlay = con->se_relay;
- struct protocol *proto = rlay->rl_proto;
evbuffercb outrd = relay_read;
evbuffercb outwr = relay_write;
struct bufferevent *bev;
@@ -635,22 +669,17 @@ relay_connected(int fd, short sig, void *arg)
return;
}
- DPRINTF("%s: session %d: %ssuccessful", __func__,
- con->se_id, rlay->rl_proto->lateconnect ? "late connect " : "");
+ DPRINTF("%s: session %d: successful", __func__, con->se_id);
switch (rlay->rl_proto->type) {
case RELAY_PROTO_HTTP:
- /* Check the servers's HTTP response */
- if (!RB_EMPTY(&rlay->rl_proto->response_tree)) {
- con->se_out.toread = TOREAD_HTTP_HEADER;
- outrd = relay_read_http;
- if ((con->se_out.nodes = calloc(proto->response_nodes,
- sizeof(u_int8_t))) == NULL) {
- relay_abort_http(con, 500,
- "failed to allocate nodes", 0);
- return;
- }
+ if (relay_httpdesc_init(out) == -1) {
+ relay_close(con,
+ "failed to allocate http descriptor");
+ return;
}
+ con->se_out.toread = TOREAD_HTTP_HEADER;
+ outrd = relay_read_http;
break;
case RELAY_PROTO_TCP:
/* Use defaults */
@@ -690,23 +719,18 @@ void
relay_input(struct rsession *con)
{
struct relay *rlay = con->se_relay;
- struct protocol *proto = rlay->rl_proto;
evbuffercb inrd = relay_read;
evbuffercb inwr = relay_write;
switch (rlay->rl_proto->type) {
case RELAY_PROTO_HTTP:
- /* Check the client's HTTP request */
- if (!RB_EMPTY(&rlay->rl_proto->request_tree) ||
- proto->lateconnect) {
- con->se_in.toread = TOREAD_HTTP_HEADER;
- inrd = relay_read_http;
- if ((con->se_in.nodes = calloc(proto->request_nodes,
- sizeof(u_int8_t))) == NULL) {
- relay_close(con, "failed to allocate nodes");
- return;
- }
+ if (relay_httpdesc_init(&con->se_in) == -1) {
+ relay_close(con,
+ "failed to allocate http descriptor");
+ return;
}
+ con->se_in.toread = TOREAD_HTTP_HEADER;
+ inrd = relay_read_http;
break;
case RELAY_PROTO_TCP:
/* Use defaults */
@@ -801,26 +825,6 @@ relay_read(struct bufferevent *bev, void *arg)
}
int
-relay_lognode(struct rsession *con, struct protonode *pn, struct protonode *pk,
- char *buf, size_t len)
-{
- const char *label = NULL;
-
- if ((pn->flags & PNFLAG_LOG) == 0)
- return (0);
- bzero(buf, len);
- if (pn->label != 0)
- label = pn_id2name(pn->label);
- if (snprintf(buf, len, " [%s%s%s: %s]",
- label == NULL ? "" : label,
- label == NULL ? "" : ", ",
- pk->key, pk->value) == -1 ||
- evbuffer_add(con->se_log, buf, strlen(buf)) == -1)
- return (-1);
- return (0);
-}
-
-int
relay_splice(struct ctl_relay_event *cre)
{
struct rsession *con = cre->con;
@@ -857,7 +861,7 @@ relay_splice(struct ctl_relay_event *cre)
bzero(&sp, sizeof(sp));
sp.sp_fd = cre->dst->s;
sp.sp_max = cre->toread > 0 ? cre->toread : 0;
- sp.sp_idle = rlay->rl_conf.timeout;
+ bcopy(&rlay->rl_conf.timeout, &sp.sp_idle, sizeof(sp.sp_idle));
if (setsockopt(cre->s, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp)) == -1) {
log_debug("%s: session %d: splice dir %d failed: %s",
__func__, con->se_id, cre->dir, strerror(errno));
@@ -991,7 +995,6 @@ void
relay_accept(int fd, short event, void *arg)
{
struct relay *rlay = arg;
- struct protocol *proto = rlay->rl_proto;
struct rsession *con = NULL;
struct ctl_natlook *cnl = NULL;
socklen_t slen;
@@ -1045,8 +1048,6 @@ relay_accept(int fd, short event, void *arg)
con->se_id = ++relay_conid;
con->se_relayid = rlay->rl_conf.id;
con->se_pid = getpid();
- con->se_in.tree = &proto->request_tree;
- con->se_out.tree = &proto->response_tree;
con->se_in.dir = RELAY_DIR_REQUEST;
con->se_out.dir = RELAY_DIR_RESPONSE;
con->se_retry = rlay->rl_conf.dstretry;
@@ -1250,7 +1251,8 @@ relay_from_table(struct rsession *con)
host = TAILQ_NEXT(host, entry);
}
TAILQ_FOREACH(host, &table->hosts, entry) {
- DPRINTF("%s: next host %s", __func__, host->conf.name);
+ DPRINTF("%s: session %d: next host %s",
+ __func__, con->se_id, host->conf.name);
if (!table->conf.check || host->up == HOST_UP)
goto found;
}
@@ -1323,7 +1325,7 @@ relay_session(struct rsession *con)
return;
}
- if (!rlay->rl_proto->lateconnect) {
+ if (rlay->rl_proto->type != RELAY_PROTO_HTTP) {
if (rlay->rl_conf.fwdmode == FWD_TRANS)
relay_bindanyreq(con, 0, IPPROTO_TCP);
else if (relay_connect(con) == -1) {
@@ -1561,6 +1563,7 @@ relay_close(struct rsession *con, const char *msg)
{
char ibuf[128], obuf[128], *ptr = NULL;
struct relay *rlay = con->se_relay;
+ struct protocol *proto = rlay->rl_proto;
SPLAY_REMOVE(session_tree, &rlay->rl_sessions, con);
@@ -1579,14 +1582,18 @@ relay_close(struct rsession *con, const char *msg)
evbuffer_add_printf(con->se_log, "\r\n") != -1)
ptr = evbuffer_readline(con->se_log);
log_info("relay %s, "
- "session %d (%d active), %d, %s -> %s:%d, "
+ "session %d (%d active), %s, %s -> %s:%d, "
"%s%s%s", rlay->rl_conf.name, con->se_id, relay_sessions,
- con->se_mark, ibuf, obuf, ntohs(con->se_out.port), msg,
- ptr == NULL ? "" : ",", ptr == NULL ? "" : ptr);
+ con->se_tag != 0 ? tag_id2name(con->se_tag) : "0", ibuf,
+ obuf, ntohs(con->se_out.port), msg, ptr == NULL ? "" : ",",
+ ptr == NULL ? "" : ptr);
if (ptr != NULL)
free(ptr);
}
+ if (proto->close != NULL)
+ (*proto->close)(con);
+
if (con->se_priv != NULL)
free(con->se_priv);
if (con->se_in.bev != NULL)
@@ -1613,12 +1620,8 @@ relay_close(struct rsession *con, const char *msg)
__func__, relay_inflight);
}
}
- if (con->se_in.path != NULL)
- free(con->se_in.path);
if (con->se_in.buf != NULL)
free(con->se_in.buf);
- if (con->se_in.nodes != NULL)
- free(con->se_in.nodes);
if (con->se_out.bev != NULL)
bufferevent_free(con->se_out.bev);
@@ -1642,12 +1645,8 @@ relay_close(struct rsession *con, const char *msg)
}
}
- if (con->se_out.path != NULL)
- free(con->se_out.path);
if (con->se_out.buf != NULL)
free(con->se_out.buf);
- if (con->se_out.nodes != NULL)
- free(con->se_out.nodes);
if (con->se_log != NULL)
evbuffer_free(con->se_log);
@@ -1823,8 +1822,9 @@ relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
case IMSG_CFG_PROTO:
config_getproto(env, imsg);
break;
- case IMSG_CFG_PROTONODE:
- return (config_getprotonode(env, imsg));
+ case IMSG_CFG_RULE:
+ config_getrule(env, imsg);
+ break;
case IMSG_CFG_RELAY:
config_getrelay(env, imsg);
break;
@@ -2338,7 +2338,7 @@ relay_bufferevent_printf(struct ctl_relay_event *cre, const char *fmt, ...)
#endif
int
-relay_bufferevent_print(struct ctl_relay_event *cre, char *str)
+relay_bufferevent_print(struct ctl_relay_event *cre, const char *str)
{
if (cre->bev == NULL)
return (evbuffer_add(cre->output, str, strlen(str)));
@@ -2511,16 +2511,6 @@ relay_load_certfiles(struct relay *rlay)
return (0);
}
-static __inline int
-relay_proto_cmp(struct protonode *a, struct protonode *b)
-{
- int ret;
- ret = strcasecmp(a->key, b->key);
- if (ret == 0)
- ret = (int)a->type - b->type;
- return (ret);
-}
-
int
relay_session_cmp(struct rsession *a, struct rsession *b)
{
@@ -2533,5 +2523,4 @@ relay_session_cmp(struct rsession *a, struct rsession *b)
return ((int)a->se_id - b->se_id);
}
-RB_GENERATE(proto_tree, protonode, nodes, relay_proto_cmp);
SPLAY_GENERATE(session_tree, rsession, se_nodes, relay_session_cmp);