diff options
Diffstat (limited to 'usr.sbin/relayd/relay.c')
-rw-r--r-- | usr.sbin/relayd/relay.c | 319 |
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); |