aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2014-07-13 01:15:01 +0200
committerReyk Floeter <reyk@esdenera.com>2014-07-13 01:15:01 +0200
commit6d196c9daa83925cc04f8019c1c0065317f6efdf (patch)
tree484726f0f6df8ff02e9cb1943ee35d8711417dd6
parent9edde19e282ba13de068a4dc7e717152aaae77b8 (diff)
downloadhttpd-6d196c9daa83925cc04f8019c1c0065317f6efdf.tar.gz
httpd-6d196c9daa83925cc04f8019c1c0065317f6efdf.zip
Simple file serving
-rw-r--r--Makefile5
-rw-r--r--config.c2
-rw-r--r--http.h17
-rw-r--r--httpd.c209
-rw-r--r--httpd.h68
-rw-r--r--server.c27
-rw-r--r--server_file.c123
-rw-r--r--server_http.c1307
8 files changed, 593 insertions, 1165 deletions
diff --git a/Makefile b/Makefile
index 0aecfb2..539eb5b 100644
--- a/Makefile
+++ b/Makefile
@@ -2,12 +2,13 @@
PROG= httpd
SRCS= parse.y
-SRCS+= config.c control.c httpd.c log.c proc.c server.c
+SRCS+= config.c control.c httpd.c log.c proc.c
+SRCS+= server.c server_http.c server_file.c
MAN= httpd.8 httpd.conf.5
LDADD= -levent -lssl -lcrypto -lutil
DPADD= ${LIBEVENT} ${LIBSSL} ${LIBCRYPTO} ${LIBUTIL}
-DEBUG= -g -DDEBUG=3
+#DEBUG= -g -DDEBUG=3
CFLAGS+= -Wall -I${.CURDIR} -Werror
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
diff --git a/config.c b/config.c
index affe3b2..269d1c4 100644
--- a/config.c
+++ b/config.c
@@ -199,7 +199,9 @@ config_setserver(struct httpd *env, struct server *srv)
int
config_getserver(struct httpd *env, struct imsg *imsg)
{
+#ifdef DEBUG
struct privsep *ps = env->sc_ps;
+#endif
struct server *srv;
u_int8_t *p = imsg->data;
size_t s;
diff --git a/http.h b/http.h
index 625359a..4614e50 100644
--- a/http.h
+++ b/http.h
@@ -119,4 +119,21 @@ struct http_error {
{ 0, NULL } \
}
+/* Used during runtime */
+struct http_descriptor {
+ struct kv http_pathquery;
+#define http_path http_pathquery.kv_key
+#define http_query http_pathquery.kv_value
+#define http_rescode http_pathquery.kv_key
+#define http_resmesg http_pathquery.kv_value
+
+ char *http_version;
+ enum httpmethod http_method;
+ int http_chunked;
+
+ /* A tree of headers and attached lists for repeated headers. */
+ struct kvtree http_headers;
+ struct kv *http_lastheader;
+};
+
#endif /* _HTTPD_HTTP_H */
diff --git a/httpd.c b/httpd.c
index 5f9c17d..32ed5ef 100644
--- a/httpd.c
+++ b/httpd.c
@@ -526,3 +526,212 @@ accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
}
return (ret);
}
+
+struct kv *
+kv_add(struct kvtree *keys, char *key, char *value)
+{
+ struct kv *kv, *oldkv;
+
+ if (key == NULL)
+ return (NULL);
+ if ((kv = calloc(1, sizeof(*kv))) == NULL)
+ return (NULL);
+ if ((kv->kv_key = strdup(key)) == NULL) {
+ free(kv);
+ return (NULL);
+ }
+ if (value != NULL &&
+ (kv->kv_value = strdup(value)) == NULL) {
+ free(kv->kv_key);
+ free(kv);
+ return (NULL);
+ }
+ TAILQ_INIT(&kv->kv_children);
+
+ if ((oldkv = RB_INSERT(kvtree, keys, kv)) != NULL) {
+ TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry);
+ kv->kv_parent = oldkv;
+ }
+
+ return (kv);
+}
+
+int
+kv_set(struct kv *kv, char *fmt, ...)
+{
+ va_list ap;
+ char *value = NULL;
+ struct kv *ckv;
+
+ va_start(ap, fmt);
+ if (vasprintf(&value, fmt, ap) == -1)
+ return (-1);
+ va_end(ap);
+
+ /* Remove all children */
+ while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) {
+ TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry);
+ kv_free(ckv);
+ free(ckv);
+ }
+
+ /* Set the new value */
+ if (kv->kv_value != NULL)
+ free(kv->kv_value);
+ kv->kv_value = value;
+
+ return (0);
+}
+
+int
+kv_setkey(struct kv *kv, char *fmt, ...)
+{
+ va_list ap;
+ char *key = NULL;
+
+ va_start(ap, fmt);
+ if (vasprintf(&key, fmt, ap) == -1)
+ return (-1);
+ va_end(ap);
+
+ if (kv->kv_key != NULL)
+ free(kv->kv_key);
+ kv->kv_key = key;
+
+ return (0);
+}
+
+void
+kv_delete(struct kvtree *keys, struct kv *kv)
+{
+ struct kv *ckv;
+
+ RB_REMOVE(kvtree, keys, kv);
+
+ /* Remove all children */
+ while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) {
+ TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry);
+ kv_free(ckv);
+ free(ckv);
+ }
+
+ kv_free(kv);
+ free(kv);
+}
+
+struct kv *
+kv_extend(struct kvtree *keys, struct kv *kv, char *value)
+{
+ char *newvalue;
+
+ if (kv == NULL) {
+ return (NULL);
+ } else if (kv->kv_value != NULL) {
+ if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1)
+ return (NULL);
+
+ free(kv->kv_value);
+ kv->kv_value = newvalue;
+ } else if ((kv->kv_value = strdup(value)) == NULL)
+ return (NULL);
+
+ return (kv);
+}
+
+void
+kv_purge(struct kvtree *keys)
+{
+ struct kv *kv;
+
+ while ((kv = RB_MIN(kvtree, keys)) != NULL)
+ kv_delete(keys, kv);
+}
+
+void
+kv_free(struct kv *kv)
+{
+ if (kv->kv_type == KEY_TYPE_NONE)
+ return;
+ if (kv->kv_key != NULL) {
+ free(kv->kv_key);
+ }
+ kv->kv_key = NULL;
+ if (kv->kv_value != NULL) {
+ free(kv->kv_value);
+ }
+ kv->kv_value = NULL;
+ memset(kv, 0, sizeof(*kv));
+}
+
+struct kv *
+kv_inherit(struct kv *dst, struct kv *src)
+{
+ memset(dst, 0, sizeof(*dst));
+ memcpy(dst, src, sizeof(*dst));
+ TAILQ_INIT(&dst->kv_children);
+
+ if (src->kv_key != NULL) {
+ if ((dst->kv_key = strdup(src->kv_key)) == NULL) {
+ kv_free(dst);
+ return (NULL);
+ }
+ }
+ if (src->kv_value != NULL) {
+ if ((dst->kv_value = strdup(src->kv_value)) == NULL) {
+ kv_free(dst);
+ return (NULL);
+ }
+ }
+
+ return (dst);
+}
+
+int
+kv_log(struct evbuffer *log, struct kv *kv)
+{
+ char *msg;
+
+ if (log == NULL)
+ return (0);
+ if (asprintf(&msg, " [%s%s%s]",
+ kv->kv_key == NULL ? "(unknown)" : kv->kv_key,
+ kv->kv_value == NULL ? "" : ": ",
+ kv->kv_value == NULL ? "" : kv->kv_value) == -1)
+ return (-1);
+ if (evbuffer_add(log, msg, strlen(msg)) == -1) {
+ free(msg);
+ return (-1);
+ }
+ free(msg);
+
+ return (0);
+}
+
+struct kv *
+kv_find(struct kvtree *keys, struct kv *kv)
+{
+ struct kv *match;
+ const char *key;
+
+ if (kv->kv_flags & KV_FLAG_GLOBBING) {
+ /* Test header key using shell globbing rules */
+ key = kv->kv_key == NULL ? "" : kv->kv_key;
+ RB_FOREACH(match, kvtree, keys) {
+ if (fnmatch(key, match->kv_key, FNM_CASEFOLD) == 0)
+ break;
+ }
+ } else {
+ /* Fast tree-based lookup only works without globbing */
+ match = RB_FIND(kvtree, keys, kv);
+ }
+
+ return (match);
+}
+
+int
+kv_cmp(struct kv *a, struct kv *b)
+{
+ return (strcasecmp(a->kv_key, b->kv_key));
+}
+
+RB_GENERATE(kvtree, kv, kv_node, kv_cmp);
diff --git a/httpd.h b/httpd.h
index 0b9f864..33b9580 100644
--- a/httpd.h
+++ b/httpd.h
@@ -78,6 +78,36 @@ struct ctl_flags {
u_int32_t cf_flags;
};
+enum key_type {
+ KEY_TYPE_NONE = 0,
+ KEY_TYPE_COOKIE,
+ KEY_TYPE_HEADER,
+ KEY_TYPE_PATH,
+ KEY_TYPE_QUERY,
+ KEY_TYPE_URL,
+ KEY_TYPE_MAX
+};
+
+TAILQ_HEAD(kvlist, kv);
+RB_HEAD(kvtree, kv);
+
+struct kv {
+ char *kv_key;
+ char *kv_value;
+
+ enum key_type kv_type;
+
+#define KV_FLAG_INVALID 0x01
+#define KV_FLAG_GLOBBING 0x02
+ u_int8_t kv_flags;
+
+ struct kvlist kv_children;
+ struct kv *kv_parent;
+ TAILQ_ENTRY(kv) kv_entry;
+
+ RB_ENTRY(kv) kv_node;
+};
+
struct portrange {
in_port_t val[2];
u_int8_t op;
@@ -223,6 +253,10 @@ struct client {
struct bufferevent *clt_bev;
struct evbuffer *clt_output;
struct event clt_ev;
+ void *clt_desc;
+
+ int clt_fd;
+ struct bufferevent *clt_file;
off_t clt_toread;
int clt_line;
@@ -329,6 +363,28 @@ int server_bufferevent_write(struct client *, void *, size_t);
SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp);
+/* server_http.c */
+void server_http_init(struct server *);
+void server_http(struct httpd *);
+int server_httpdesc_init(struct client *);
+void server_read_http(struct bufferevent *, void *);
+void server_abort_http(struct client *, u_int, const char *);
+u_int server_httpmethod_byname(const char *);
+const char
+ *server_httpmethod_byid(u_int);
+const char
+ *server_httperror_byid(u_int);
+void server_read_httpcontent(struct bufferevent *, void *);
+void server_read_httpchunks(struct bufferevent *, void *);
+int server_writeheader_kv(struct client *, struct kv *);
+int server_writeheader_http(struct client *);
+int server_writeresponse_http(struct client *);
+void server_reset_http(struct client *);
+void server_close_http(struct client *);
+
+/* server_file.c */
+int server_response(struct client *);
+
/* httpd.c */
void event_again(struct event *, int, short,
void (*)(int, short, void *),
@@ -342,6 +398,18 @@ char *get_string(u_int8_t *, size_t);
void *get_data(u_int8_t *, size_t);
int accept_reserve(int, struct sockaddr *, socklen_t *, int,
volatile int *);
+struct kv *kv_add(struct kvtree *, char *, char *);
+int kv_set(struct kv *, char *, ...);
+int kv_setkey(struct kv *, char *, ...);
+void kv_delete(struct kvtree *, struct kv *);
+struct kv *kv_extend(struct kvtree *, struct kv *, char *);
+void kv_purge(struct kvtree *);
+void kv_free(struct kv *);
+struct kv *kv_inherit(struct kv *, struct kv *);
+int kv_log(struct evbuffer *, struct kv *);
+struct kv *kv_find(struct kvtree *, struct kv *);
+int kv_cmp(struct kv *, struct kv *);
+RB_PROTOTYPE(kvtree, kv, kv_node, kv_cmp);
/* log.c */
void log_init(int);
diff --git a/server.c b/server.c
index b700b2f..aba3952 100644
--- a/server.c
+++ b/server.c
@@ -82,7 +82,7 @@ server(struct privsep *ps, struct privsep_proc *p)
pid_t pid;
env = ps->ps_env;
pid = proc_run(ps, p, procs, nitems(procs), server_init, NULL);
-// server_http(env);
+ server_http(env);
return (pid);
}
@@ -108,6 +108,8 @@ server_privinit(struct server *srv)
void
server_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
+ server_http(ps->ps_env);
+
if (config_init(ps->ps_env) == -1)
fatal("failed to initialize configuration");
@@ -134,7 +136,7 @@ server_launch(void)
struct server *srv;
TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
-// server_http_init(srv);
+ server_http_init(srv);
log_debug("%s: running server %s", __func__,
srv->srv_conf.name);
@@ -296,15 +298,14 @@ server_input(struct client *clt)
evbuffercb inrd = server_read;
evbuffercb inwr = server_write;
-#if 0
- if (server_httpdesc_init(&clt->clt_in) == -1) {
+ if (server_httpdesc_init(clt) == -1) {
server_close(clt,
"failed to allocate http descriptor");
return;
}
-#endif
+
clt->clt_toread = TOREAD_HTTP_HEADER;
-// inrd = server_read_http;
+ inrd = server_read_http;
/*
* Client <-> Server
@@ -370,8 +371,7 @@ server_read(struct bufferevent *bev, void *arg)
goto fail;
if (clt->clt_done)
goto done;
- if (clt->clt_bev)
- bufferevent_enable(clt->clt_bev, EV_READ);
+ bufferevent_enable(bev, EV_READ);
return;
done:
server_close(clt, "done");
@@ -390,7 +390,7 @@ server_error(struct bufferevent *bev, short error, void *arg)
return;
}
if (error & EVBUFFER_ERROR && errno == EFBIG) {
- bufferevent_enable(clt->clt_bev, EV_READ);
+ bufferevent_enable(bev, EV_READ);
return;
}
if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) {
@@ -444,6 +444,7 @@ server_accept(int fd, short event, void *arg)
goto err;
clt->clt_s = s;
+ clt->clt_fd = -1;
clt->clt_toread = TOREAD_UNLIMITED;
clt->clt_server = srv;
clt->clt_id = ++server_cltid;
@@ -511,6 +512,8 @@ server_close(struct client *clt, const char *msg)
event_del(&clt->clt_ev);
if (clt->clt_bev != NULL)
bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE);
+ if (clt->clt_file != NULL)
+ bufferevent_disable(clt->clt_file, EV_READ|EV_WRITE);
if ((env->sc_opts & HTTPD_OPT_LOGUPDATE) && msg != NULL) {
memset(&ibuf, 0, sizeof(ibuf));
@@ -533,6 +536,12 @@ server_close(struct client *clt, const char *msg)
bufferevent_free(clt->clt_bev);
else if (clt->clt_output != NULL)
evbuffer_free(clt->clt_output);
+
+ if (clt->clt_file != NULL)
+ bufferevent_free(clt->clt_file);
+ if (clt->clt_fd != -1)
+ close(clt->clt_fd);
+
if (clt->clt_s != -1) {
close(clt->clt_s);
if (/* XXX */ -1) {
diff --git a/server_file.c b/server_file.c
new file mode 100644
index 0000000..00774c1
--- /dev/null
+++ b/server_file.c
@@ -0,0 +1,123 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/tree.h>
+#include <sys/hash.h>
+
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+#include <event.h>
+
+#include <openssl/ssl.h>
+
+#include "httpd.h"
+#include "http.h"
+
+int
+server_response(struct client *clt)
+{
+ struct http_descriptor *desc = clt->clt_desc;
+ struct server *srv = clt->clt_server;
+ struct kv *kv;
+ const char *errstr = NULL;
+ int fd = -1;
+ char path[MAXPATHLEN];
+ struct stat st;
+
+ if (desc->http_path == NULL)
+ goto fail;
+
+ /*
+ * XXX hardcode XXX
+ */
+ strlcpy(path, "/htdocs", sizeof(path));
+ if (desc->http_path[0] != '/')
+ strlcat(path, "/", sizeof(path));
+ strlcat(path, desc->http_path, sizeof(path));
+ if (desc->http_path[strlen(desc->http_path) - 1] == '/')
+ strlcat(path, "index.html", sizeof(path));
+
+ if (access(path, R_OK) == -1) {
+ switch (errno) {
+ case EACCES:
+ server_abort_http(clt, 403, path);
+ break;
+ case ENOENT:
+ server_abort_http(clt, 404, path);
+ break;
+ default:
+ server_abort_http(clt, 500, path);
+ break;
+ }
+ return (-1);
+ }
+
+ if ((fd = open(path, O_RDONLY)) == -1 || fstat(fd, &st) == -1)
+ goto fail;
+
+ kv_purge(&desc->http_headers);
+ kv_add(&desc->http_headers, "Server", HTTPD_SERVERNAME);
+ kv_add(&desc->http_headers, "Connection", "close");
+ if ((kv = kv_add(&desc->http_headers, "Content-Length", NULL)) != NULL)
+ kv_set(kv, "%ld", st.st_size);
+ kv_setkey(&desc->http_pathquery, "200");
+ kv_set(&desc->http_pathquery, "%s", server_httperror_byid(200));
+
+ if (server_writeresponse_http(clt) == -1 ||
+ server_bufferevent_print(clt, "\r\n") == -1 ||
+ server_writeheader_http(clt) == -1 ||
+ server_bufferevent_print(clt, "\r\n") == -1)
+ goto fail;
+
+ clt->clt_fd = fd;
+ clt->clt_file = bufferevent_new(clt->clt_fd, server_read,
+ server_write, server_error, clt);
+ if (clt->clt_file == NULL) {
+ errstr = "failed to allocate file buffer event";
+ goto fail;
+ }
+
+ bufferevent_settimeout(clt->clt_file,
+ srv->srv_conf.timeout.tv_sec, srv->srv_conf.timeout.tv_sec);
+ bufferevent_enable(clt->clt_file, EV_READ|EV_WRITE);
+
+ return (0);
+ fail:
+ if (errstr == NULL)
+ errstr = strerror(errno);
+ server_abort_http(clt, 500, errstr);
+ return (-1);
+}
diff --git a/server_http.c b/server_http.c
index 75e1521..63d15c7 100644
--- a/server_http.c
+++ b/server_http.c
@@ -45,52 +45,20 @@
#include <openssl/ssl.h>
-#include "relayd.h"
+#include "httpd.h"
#include "http.h"
-static int _relay_lookup_url(struct ctl_relay_event *, char *, char *,
- char *, struct kv *);
-int relay_lookup_url(struct ctl_relay_event *,
- const char *, struct kv *);
-int relay_lookup_query(struct ctl_relay_event *, struct kv *);
-int relay_lookup_cookie(struct ctl_relay_event *, const char *,
- struct kv *);
-void relay_read_httpcontent(struct bufferevent *, void *);
-void relay_read_httpchunks(struct bufferevent *, void *);
-char *relay_expand_http(struct ctl_relay_event *, char *,
- char *, size_t);
-int relay_writeheader_kv(struct ctl_relay_event *, struct kv *);
-int relay_writeheader_http(struct ctl_relay_event *,
- struct ctl_relay_event *);
-int relay_writerequest_http(struct ctl_relay_event *,
- struct ctl_relay_event *);
-int relay_writeresponse_http(struct ctl_relay_event *,
- struct ctl_relay_event *);
-void relay_reset_http(struct ctl_relay_event *);
-static int relay_httpmethod_cmp(const void *, const void *);
-static int relay_httperror_cmp(const void *, const void *);
-int relay_httpquery_test(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *);
-int relay_httpheader_test(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *);
-int relay_httppath_test(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *);
-int relay_httpurl_test(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *);
-int relay_httpcookie_test(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *);
-int relay_apply_actions(struct ctl_relay_event *, struct kvlist *);
-int relay_match_actions(struct ctl_relay_event *,
- struct relay_rule *, struct kvlist *, struct kvlist *);
-void relay_httpdesc_free(struct http_descriptor *);
-
-static struct relayd *env = NULL;
+static int server_httpmethod_cmp(const void *, const void *);
+static int server_httperror_cmp(const void *, const void *);
+void server_httpdesc_free(struct http_descriptor *);
+
+static struct httpd *env = NULL;
static struct http_method http_methods[] = HTTP_METHODS;
static struct http_error http_errors[] = HTTP_ERRORS;
void
-relay_http(struct relayd *x_env)
+server_http(struct httpd *x_env)
{
if (x_env != NULL)
env = x_env;
@@ -100,25 +68,20 @@ relay_http(struct relayd *x_env)
/* Sort the HTTP lookup arrays */
qsort(http_methods, sizeof(http_methods) /
sizeof(http_methods[0]) - 1,
- sizeof(http_methods[0]), relay_httpmethod_cmp);
+ sizeof(http_methods[0]), server_httpmethod_cmp);
qsort(http_errors, sizeof(http_errors) /
sizeof(http_errors[0]) - 1,
- sizeof(http_errors[0]), relay_httperror_cmp);
+ sizeof(http_errors[0]), server_httperror_cmp);
}
void
-relay_http_init(struct relay *rlay)
+server_http_init(struct server *srv)
{
- rlay->rl_proto->close = relay_close_http;
-
- relay_http(NULL);
-
- /* Calculate skip step for the filter rules (may take a while) */
- relay_calc_skip_steps(&rlay->rl_proto->rules);
+ /* nothing */
}
int
-relay_httpdesc_init(struct ctl_relay_event *cre)
+server_httpdesc_init(struct client *clt)
{
struct http_descriptor *desc;
@@ -126,13 +89,13 @@ relay_httpdesc_init(struct ctl_relay_event *cre)
return (-1);
RB_INIT(&desc->http_headers);
- cre->desc = desc;
+ clt->clt_desc = desc;
return (0);
}
void
-relay_httpdesc_free(struct http_descriptor *desc)
+server_httpdesc_free(struct http_descriptor *desc)
{
if (desc->http_path != NULL) {
free(desc->http_path);
@@ -146,45 +109,31 @@ relay_httpdesc_free(struct http_descriptor *desc)
free(desc->http_version);
desc->http_version = NULL;
}
- if (desc->query_key != NULL) {
- free(desc->query_key);
- desc->query_key = NULL;
- }
- if (desc->query_val != NULL) {
- free(desc->query_val);
- desc->query_val = NULL;
- }
kv_purge(&desc->http_headers);
}
void
-relay_read_http(struct bufferevent *bev, void *arg)
+server_read_http(struct bufferevent *bev, void *arg)
{
- struct ctl_relay_event *cre = arg;
- struct http_descriptor *desc = cre->desc;
- struct rsession *con = cre->con;
- struct relay *rlay = con->se_relay;
- struct protocol *proto = rlay->rl_proto;
+ struct client *clt = arg;
+ struct http_descriptor *desc = clt->clt_desc;
struct evbuffer *src = EVBUFFER_INPUT(bev);
char *line = NULL, *key, *value;
- int action;
const char *errstr;
size_t size, linelen;
struct kv *hdr = NULL;
- getmonotime(&con->se_tv_last);
+ getmonotime(&clt->clt_tv_last);
size = EVBUFFER_LENGTH(src);
DPRINTF("%s: session %d: size %lu, to read %lld",
- __func__, con->se_id, size, cre->toread);
+ __func__, clt->clt_id, size, clt->clt_toread);
if (!size) {
- if (cre->dir == RELAY_DIR_RESPONSE)
- return;
- cre->toread = TOREAD_HTTP_HEADER;
+ clt->clt_toread = TOREAD_HTTP_HEADER;
goto done;
}
- while (!cre->done && (line = evbuffer_readline(src)) != NULL) {
+ while (!clt->clt_done && (line = evbuffer_readline(src)) != NULL) {
linelen = strlen(line);
/*
@@ -192,17 +141,17 @@ relay_read_http(struct bufferevent *bev, void *arg)
* libevent already stripped the \r\n for us.
*/
if (!linelen) {
- cre->done = 1;
+ clt->clt_done = 1;
free(line);
break;
}
key = line;
/* Limit the total header length minus \r\n */
- cre->headerlen += linelen;
- if (cre->headerlen > RELAY_MAXHEADERLENGTH) {
+ clt->clt_headerlen += linelen;
+ if (clt->clt_headerlen > SERVER_MAXHEADERLENGTH) {
free(line);
- relay_abort_http(con, 413, "request too large", 0);
+ server_abort_http(clt, 413, "request too large");
return;
}
@@ -210,7 +159,7 @@ relay_read_http(struct bufferevent *bev, void *arg)
* The first line is the GET/POST/PUT/... request,
* subsequent lines are HTTP headers.
*/
- if (++cre->line == 1)
+ if (++clt->clt_line == 1)
value = strchr(key, ' ');
else if (*key == ' ' || *key == '\t')
/* Multiline headers wrap with a space or tab */
@@ -218,9 +167,9 @@ relay_read_http(struct bufferevent *bev, void *arg)
else
value = strchr(key, ':');
if (value == NULL) {
- if (cre->line == 1) {
+ if (clt->clt_line == 1) {
free(line);
- relay_abort_http(con, 400, "malformed", 0);
+ server_abort_http(clt, 400, "malformed");
return;
}
@@ -242,45 +191,16 @@ relay_read_http(struct bufferevent *bev, void *arg)
}
DPRINTF("%s: session %d: header '%s: %s'", __func__,
- con->se_id, key, value);
+ clt->clt_id, key, value);
/*
* Identify and handle specific HTTP request methods
*/
- if (cre->line == 1 && cre->dir == RELAY_DIR_RESPONSE) {
- desc->http_method = HTTP_METHOD_RESPONSE;
- /*
- * Decode response path and query
- */
- desc->http_version = strdup(line);
- if (desc->http_version == NULL) {
- free(line);
- goto fail;
- }
- desc->http_rescode = strdup(value);
- if (desc->http_rescode == NULL) {
- free(line);
- goto fail;
- }
- desc->http_resmesg = strchr(desc->http_rescode, ' ');
- if (desc->http_resmesg == NULL) {
- free(line);
- goto fail;
- }
- *desc->http_resmesg++ = '\0';
- if ((desc->http_resmesg = strdup(desc->http_resmesg))
- == NULL) {
- free(line);
- goto fail;
- }
- DPRINTF("http_version %s http_rescode %s "
- "http_resmesg %s", desc->http_version,
- desc->http_rescode, desc->http_resmesg);
- goto lookup;
- } else if (cre->line == 1 && cre->dir == RELAY_DIR_REQUEST) {
- if ((desc->http_method = relay_httpmethod_byname(key))
+ if (clt->clt_line == 1) {
+ if ((desc->http_method = server_httpmethod_byname(key))
== HTTP_METHOD_NONE)
goto fail;
+
/*
* Decode request path and query
*/
@@ -320,7 +240,7 @@ relay_read_http(struct bufferevent *bev, void *arg)
* These method should not have a body
* and thus no Content-Length header.
*/
- relay_abort_http(con, 400, "malformed", 0);
+ server_abort_http(clt, 400, "malformed");
goto abort;
}
@@ -331,19 +251,19 @@ relay_read_http(struct bufferevent *bev, void *arg)
* the carriage return? And some browsers seem to
* include the line length in the content-length.
*/
- cre->toread = strtonum(value, 0, LLONG_MAX,
+ clt->clt_toread = strtonum(value, 0, LLONG_MAX,
&errstr);
if (errstr) {
- relay_abort_http(con, 500, errstr, 0);
+ server_abort_http(clt, 500, errstr);
goto abort;
}
}
- lookup:
+
if (strcasecmp("Transfer-Encoding", key) == 0 &&
strcasecmp("chunked", value) == 0)
desc->http_chunked = 1;
- if (cre->line != 1) {
+ if (clt->clt_line != 1) {
if ((hdr = kv_add(&desc->http_headers, key,
value)) == NULL) {
free(line);
@@ -354,188 +274,154 @@ relay_read_http(struct bufferevent *bev, void *arg)
free(line);
}
- if (cre->done) {
+ if (clt->clt_done) {
if (desc->http_method == HTTP_METHOD_NONE) {
- relay_abort_http(con, 406, "no method", 0);
- return;
- }
-
- action = relay_test(proto, cre);
- if (action == RES_FAIL) {
- relay_close(con, "filter rule failed");
- return;
- } else if (action != RES_PASS) {
- relay_abort_http(con, 403, "Forbidden", con->se_label);
+ server_abort_http(clt, 406, "no method");
return;
}
switch (desc->http_method) {
case HTTP_METHOD_CONNECT:
/* Data stream */
- cre->toread = TOREAD_UNLIMITED;
- bev->readcb = relay_read;
+ clt->clt_toread = TOREAD_UNLIMITED;
+ bev->readcb = server_read;
break;
case HTTP_METHOD_DELETE:
case HTTP_METHOD_GET:
case HTTP_METHOD_HEAD:
case HTTP_METHOD_OPTIONS:
- cre->toread = 0;
+ clt->clt_toread = 0;
break;
case HTTP_METHOD_POST:
case HTTP_METHOD_PUT:
case HTTP_METHOD_RESPONSE:
/* HTTP request payload */
- if (cre->toread > 0)
- bev->readcb = relay_read_httpcontent;
+ if (clt->clt_toread > 0)
+ bev->readcb = server_read_httpcontent;
/* Single-pass HTTP body */
- if (cre->toread < 0) {
- cre->toread = TOREAD_UNLIMITED;
- bev->readcb = relay_read;
+ if (clt->clt_toread < 0) {
+ clt->clt_toread = TOREAD_UNLIMITED;
+ bev->readcb = server_read;
}
break;
default:
/* HTTP handler */
- cre->toread = TOREAD_HTTP_HEADER;
- bev->readcb = relay_read_http;
+ clt->clt_toread = TOREAD_HTTP_HEADER;
+ bev->readcb = server_read_http;
break;
}
if (desc->http_chunked) {
/* Chunked transfer encoding */
- cre->toread = TOREAD_HTTP_CHUNK_LENGTH;
- bev->readcb = relay_read_httpchunks;
- }
-
- if (cre->dir == RELAY_DIR_REQUEST) {
- if (relay_writerequest_http(cre->dst, cre) == -1)
- goto fail;
- } else {
- if (relay_writeresponse_http(cre->dst, cre) == -1)
- goto fail;
+ clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH;
+ bev->readcb = server_read_httpchunks;
}
- if (relay_bufferevent_print(cre->dst, "\r\n") == -1 ||
- relay_writeheader_http(cre->dst, cre) == -1 ||
- relay_bufferevent_print(cre->dst, "\r\n") == -1)
- goto fail;
- relay_reset_http(cre);
done:
- if (cre->dir == RELAY_DIR_REQUEST && cre->toread <= 0 &&
- cre->dst->bev == NULL) {
- if (rlay->rl_conf.fwdmode == FWD_TRANS) {
- relay_bindanyreq(con, 0, IPPROTO_TCP);
+ if (clt->clt_toread <= 0) {
+ if (server_response(clt) == -1)
return;
- }
- if (relay_connect(con) == -1)
- relay_abort_http(con, 502, "session failed", 0);
- return;
}
+
+ server_reset_http(clt);
}
- if (con->se_done) {
- relay_close(con, "last http read (done)");
+ if (clt->clt_done) {
+ server_close(clt, "done");
return;
}
- if (EVBUFFER_LENGTH(src) && bev->readcb != relay_read_http)
+ if (EVBUFFER_LENGTH(src) && bev->readcb != server_read_http)
bev->readcb(bev, arg);
bufferevent_enable(bev, EV_READ);
- if (relay_splice(cre) == -1)
- relay_close(con, strerror(errno));
return;
fail:
- relay_abort_http(con, 500, strerror(errno), 0);
+ server_abort_http(clt, 500, strerror(errno));
return;
abort:
free(line);
}
void
-relay_read_httpcontent(struct bufferevent *bev, void *arg)
+server_read_httpcontent(struct bufferevent *bev, void *arg)
{
- struct ctl_relay_event *cre = arg;
- struct rsession *con = cre->con;
+ struct client *clt = arg;
struct evbuffer *src = EVBUFFER_INPUT(bev);
size_t size;
- getmonotime(&con->se_tv_last);
+ getmonotime(&clt->clt_tv_last);
size = EVBUFFER_LENGTH(src);
DPRINTF("%s: session %d: size %lu, to read %lld", __func__,
- con->se_id, size, cre->toread);
+ clt->clt_id, size, clt->clt_toread);
if (!size)
return;
- if (relay_spliceadjust(cre) == -1)
- goto fail;
- if (cre->toread > 0) {
+ if (clt->clt_toread > 0) {
/* Read content data */
- if ((off_t)size > cre->toread) {
- size = cre->toread;
- if (relay_bufferevent_write_chunk(cre->dst, src, size)
- == -1)
+ if ((off_t)size > clt->clt_toread) {
+ size = clt->clt_toread;
+ if (server_bufferevent_write_chunk(clt,
+ src, size) == -1)
goto fail;
- cre->toread = 0;
+ clt->clt_toread = 0;
} else {
- if (relay_bufferevent_write_buffer(cre->dst, src) == -1)
+ if (server_bufferevent_write_buffer(clt, src) == -1)
goto fail;
- cre->toread -= size;
+ clt->clt_toread -= size;
}
DPRINTF("%s: done, size %lu, to read %lld", __func__,
- size, cre->toread);
+ size, clt->clt_toread);
}
- if (cre->toread == 0) {
- cre->toread = TOREAD_HTTP_HEADER;
- bev->readcb = relay_read_http;
+ if (clt->clt_toread == 0) {
+ clt->clt_toread = TOREAD_HTTP_HEADER;
+ bev->readcb = server_read_http;
}
- if (con->se_done)
+ if (clt->clt_done)
goto done;
- if (bev->readcb != relay_read_httpcontent)
+ if (bev->readcb != server_read_httpcontent)
bev->readcb(bev, arg);
bufferevent_enable(bev, EV_READ);
return;
done:
- relay_close(con, "last http content read");
+ server_close(clt, "last http content read");
return;
fail:
- relay_close(con, strerror(errno));
+ server_close(clt, strerror(errno));
}
void
-relay_read_httpchunks(struct bufferevent *bev, void *arg)
+server_read_httpchunks(struct bufferevent *bev, void *arg)
{
- struct ctl_relay_event *cre = arg;
- struct rsession *con = cre->con;
+ struct client *clt = arg;
struct evbuffer *src = EVBUFFER_INPUT(bev);
char *line;
long long llval;
size_t size;
- getmonotime(&con->se_tv_last);
+ getmonotime(&clt->clt_tv_last);
size = EVBUFFER_LENGTH(src);
DPRINTF("%s: session %d: size %lu, to read %lld", __func__,
- con->se_id, size, cre->toread);
+ clt->clt_id, size, clt->clt_toread);
if (!size)
return;
- if (relay_spliceadjust(cre) == -1)
- goto fail;
- if (cre->toread > 0) {
+ if (clt->clt_toread > 0) {
/* Read chunk data */
- if ((off_t)size > cre->toread) {
- size = cre->toread;
- if (relay_bufferevent_write_chunk(cre->dst, src, size)
+ if ((off_t)size > clt->clt_toread) {
+ size = clt->clt_toread;
+ if (server_bufferevent_write_chunk(clt, src, size)
== -1)
goto fail;
- cre->toread = 0;
+ clt->clt_toread = 0;
} else {
- if (relay_bufferevent_write_buffer(cre->dst, src) == -1)
+ if (server_bufferevent_write_buffer(clt, src) == -1)
goto fail;
- cre->toread -= size;
+ clt->clt_toread -= size;
}
DPRINTF("%s: done, size %lu, to read %lld", __func__,
- size, cre->toread);
+ size, clt->clt_toread);
}
- switch (cre->toread) {
+ switch (clt->clt_toread) {
case TOREAD_HTTP_CHUNK_LENGTH:
line = evbuffer_readline(src);
if (line == NULL) {
@@ -554,20 +440,20 @@ relay_read_httpchunks(struct bufferevent *bev, void *arg)
*/
if (sscanf(line, "%llx", &llval) != 1 || llval < 0) {
free(line);
- relay_close(con, "invalid chunk size");
+ server_close(clt, "invalid chunk size");
return;
}
- if (relay_bufferevent_print(cre->dst, line) == -1 ||
- relay_bufferevent_print(cre->dst, "\r\n") == -1) {
+ if (server_bufferevent_print(clt, line) == -1 ||
+ server_bufferevent_print(clt, "\r\n") == -1) {
free(line);
goto fail;
}
free(line);
- if ((cre->toread = llval) == 0) {
+ if ((clt->clt_toread = llval) == 0) {
DPRINTF("%s: last chunk", __func__);
- cre->toread = TOREAD_HTTP_CHUNK_TRAILER;
+ clt->clt_toread = TOREAD_HTTP_CHUNK_TRAILER;
}
break;
case TOREAD_HTTP_CHUNK_TRAILER:
@@ -578,15 +464,15 @@ relay_read_httpchunks(struct bufferevent *bev, void *arg)
bufferevent_enable(bev, EV_READ);
return;
}
- if (relay_bufferevent_print(cre->dst, line) == -1 ||
- relay_bufferevent_print(cre->dst, "\r\n") == -1) {
+ if (server_bufferevent_print(clt, line) == -1 ||
+ server_bufferevent_print(clt, "\r\n") == -1) {
free(line);
goto fail;
}
if (strlen(line) == 0) {
/* Switch to HTTP header mode */
- cre->toread = TOREAD_HTTP_HEADER;
- bev->readcb = relay_read_http;
+ clt->clt_toread = TOREAD_HTTP_HEADER;
+ bev->readcb = server_read_http;
}
free(line);
break;
@@ -595,14 +481,14 @@ relay_read_httpchunks(struct bufferevent *bev, void *arg)
line = evbuffer_readline(src);
if (line != NULL)
free(line);
- if (relay_bufferevent_print(cre->dst, "\r\n") == -1)
+ if (server_bufferevent_print(clt, "\r\n") == -1)
goto fail;
- cre->toread = TOREAD_HTTP_CHUNK_LENGTH;
+ clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH;
break;
}
next:
- if (con->se_done)
+ if (clt->clt_done)
goto done;
if (EVBUFFER_LENGTH(src))
bev->readcb(bev, arg);
@@ -610,296 +496,45 @@ relay_read_httpchunks(struct bufferevent *bev, void *arg)
return;
done:
- relay_close(con, "last http chunk read (done)");
+ server_close(clt, "last http chunk read (done)");
return;
fail:
- relay_close(con, strerror(errno));
+ server_close(clt, strerror(errno));
}
void
-relay_reset_http(struct ctl_relay_event *cre)
+server_reset_http(struct client *clt)
{
- struct http_descriptor *desc = cre->desc;
+ struct http_descriptor *desc = clt->clt_desc;
- relay_httpdesc_free(desc);
- if (cre->buf != NULL) {
- free(cre->buf);
- cre->buf = NULL;
- cre->buflen = 0;
- }
+ server_httpdesc_free(desc);
desc->http_method = 0;
desc->http_chunked = 0;
- cre->headerlen = 0;
- cre->line = 0;
- cre->done = 0;
-}
-
-static int
-_relay_lookup_url(struct ctl_relay_event *cre, char *host, char *path,
- char *query, struct kv *kv)
-{
- struct rsession *con = cre->con;
- char *val, *md = NULL;
- int ret = RES_FAIL;
- const char *str = NULL;
-
- if (asprintf(&val, "%s%s%s%s",
- host, path,
- query == NULL ? "" : "?",
- query == NULL ? "" : query) == -1) {
- relay_abort_http(con, 500, "failed to allocate URL", 0);
- return (RES_FAIL);
- }
-
- switch (kv->kv_digest) {
- case DIGEST_SHA1:
- case DIGEST_MD5:
- if ((md = digeststr(kv->kv_digest,
- val, strlen(val), NULL)) == NULL) {
- relay_abort_http(con, 500,
- "failed to allocate digest", 0);
- goto fail;
- }
- str = md;
- break;
- case DIGEST_NONE:
- str = val;
- break;
- }
-
- DPRINTF("%s: session %d: %s, %s: %d", __func__, con->se_id,
- str, kv->kv_key, strcasecmp(kv->kv_key, str));
-
- if (strcasecmp(kv->kv_key, str) == 0) {
- ret = RES_DROP;
- goto fail;
- }
-
- ret = RES_PASS;
- fail:
- if (md != NULL)
- free(md);
- free(val);
- return (ret);
+ clt->clt_headerlen = 0;
+ clt->clt_line = 0;
+ clt->clt_done = 0;
}
-int
-relay_lookup_url(struct ctl_relay_event *cre, const char *host, struct kv *kv)
-{
- struct rsession *con = cre->con;
- struct http_descriptor *desc = (struct http_descriptor *)cre->desc;
- int i, j, dots;
- char *hi[RELAY_MAXLOOKUPLEVELS], *p, *pp, *c, ch;
- char ph[MAXHOSTNAMELEN];
- int ret;
-
- if (desc->http_path == NULL)
- return (RES_PASS);
-
- /*
- * This is an URL lookup algorithm inspired by
- * http://code.google.com/apis/safebrowsing/
- * developers_guide.html#PerformingLookups
- */
-
- DPRINTF("%s: session %d: host '%s', path '%s', query '%s'",
- __func__, con->se_id, host, desc->http_path,
- desc->http_query == NULL ? "" : desc->http_query);
-
- if (canonicalize_host(host, ph, sizeof(ph)) == NULL) {
- relay_abort_http(con, 400, "invalid host name", 0);
- return (RES_FAIL);
- }
-
- bzero(hi, sizeof(hi));
- for (dots = -1, i = strlen(ph) - 1; i > 0; i--) {
- if (ph[i] == '.' && ++dots)
- hi[dots - 1] = &ph[i + 1];
- if (dots > (RELAY_MAXLOOKUPLEVELS - 2))
- break;
- }
- if (dots == -1)
- dots = 0;
- hi[dots] = ph;
-
- if ((pp = strdup(desc->http_path)) == NULL) {
- relay_abort_http(con, 500, "failed to allocate path", 0);
- return (RES_FAIL);
- }
- for (i = (RELAY_MAXLOOKUPLEVELS - 1); i >= 0; i--) {
- if (hi[i] == NULL)
- continue;
-
- /* 1. complete path with query */
- if (desc->http_query != NULL)
- if ((ret = _relay_lookup_url(cre, hi[i],
- pp, desc->http_query, kv)) != RES_PASS)
- goto done;
-
- /* 2. complete path without query */
- if ((ret = _relay_lookup_url(cre, hi[i],
- pp, NULL, kv)) != RES_PASS)
- goto done;
-
- /* 3. traverse path */
- for (j = 0, p = strchr(pp, '/');
- p != NULL; p = strchr(p, '/'), j++) {
- if (j > (RELAY_MAXLOOKUPLEVELS - 2) || *(++p) == '\0')
- break;
- c = &pp[p - pp];
- ch = *c;
- *c = '\0';
- if ((ret = _relay_lookup_url(cre, hi[i],
- pp, NULL, kv)) != RES_PASS)
- goto done;
- *c = ch;
- }
- }
-
- ret = RES_PASS;
- done:
- free(pp);
- return (ret);
-}
-
-int
-relay_lookup_cookie(struct ctl_relay_event *cre, const char *str,
- struct kv *kv)
-{
- struct rsession *con = cre->con;
- char *val, *ptr, *key, *value;
- int ret;
-
- if ((val = strdup(str)) == NULL) {
- relay_abort_http(con, 500, "failed to allocate cookie", 0);
- return (RES_FAIL);
- }
-
- for (ptr = val; ptr != NULL && strlen(ptr);) {
- if (*ptr == ' ')
- *ptr++ = '\0';
- key = ptr;
- if ((ptr = strchr(ptr, ';')) != NULL)
- *ptr++ = '\0';
- /*
- * XXX We do not handle attributes
- * ($Path, $Domain, or $Port)
- */
- if (*key == '$')
- continue;
-
- if ((value =
- strchr(key, '=')) == NULL ||
- strlen(value) < 1)
- continue;
- *value++ = '\0';
- if (*value == '"')
- *value++ = '\0';
- if (value[strlen(value) - 1] == '"')
- value[strlen(value) - 1] = '\0';
-
- DPRINTF("%s: session %d: %s = %s, %s = %s : %d",
- __func__, con->se_id,
- key, value, kv->kv_key, kv->kv_value,
- strcasecmp(kv->kv_key, key));
-
- if (strcasecmp(kv->kv_key, key) == 0 &&
- ((kv->kv_value == NULL) ||
- (fnmatch(kv->kv_value, value,
- FNM_CASEFOLD) != FNM_NOMATCH))) {
- ret = RES_DROP;
- goto done;
- }
- }
-
- ret = RES_PASS;
-
- done:
- free(val);
- return (ret);
-}
-
-int
-relay_lookup_query(struct ctl_relay_event *cre, struct kv *kv)
-{
- struct http_descriptor *desc = cre->desc;
- struct kv *match = &desc->http_matchquery;
- char *val, *ptr, *tmpkey = NULL, *tmpval = NULL;
- int ret = -1;
-
- if (desc->http_query == NULL)
- return (-1);
- if ((val = strdup(desc->http_query)) == NULL) {
- relay_abort_http(cre->con, 500, "failed to allocate query", 0);
- return (-1);
- }
-
- ptr = val;
- while (ptr != NULL && strlen(ptr)) {
- tmpkey = ptr;
- if ((ptr = strchr(ptr, '&')) != NULL)
- *ptr++ = '\0';
- if ((tmpval = strchr(tmpkey, '=')) == NULL || strlen(tmpval)
- < 1)
- continue;
- *tmpval++ = '\0';
-
- if (fnmatch(kv->kv_key, tmpkey, 0) != FNM_NOMATCH &&
- (kv->kv_value == NULL || fnmatch(kv->kv_value, tmpval, 0)
- != FNM_NOMATCH))
- break;
- else
- tmpkey = NULL;
- }
-
- if (tmpkey == NULL || tmpval == NULL)
- goto done;
-
- match->kv_key = strdup(tmpkey);
- if (match->kv_key == NULL)
- goto done;
- match->kv_value = strdup(tmpval);
- if (match->kv_key == NULL)
- goto done;
- ret = 0;
-
- done:
- free(val);
- return (ret);
-}
-
-
void
-relay_abort_http(struct rsession *con, u_int code, const char *msg,
- u_int16_t labelid)
+server_abort_http(struct client *clt, u_int code, const char *msg)
{
- struct relay *rlay = con->se_relay;
- struct bufferevent *bev = con->se_in.bev;
+ struct server *srv = clt->clt_server;
+ struct bufferevent *bev = clt->clt_bev;
const char *httperr = NULL, *text = "";
char *httpmsg;
time_t t;
struct tm *lt;
char tmbuf[32], hbuf[128];
- const char *style, *label = NULL;
+ const char *style;
- if ((httperr = relay_httperror_byid(code)) == NULL)
+ if ((httperr = server_httperror_byid(code)) == NULL)
httperr = "Unknown Error";
- if (labelid != 0)
- label = label_id2name(labelid);
-
- /* In some cases this function may be called from generic places */
- if (rlay->rl_proto->type != RELAY_PROTO_HTTP ||
- (rlay->rl_proto->flags & F_RETURN) == 0) {
- relay_close(con, msg);
- return;
- }
-
if (bev == NULL)
goto done;
/* Some system information */
- if (print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
+ if (print_host(&srv->srv_conf.ss, hbuf, sizeof(hbuf)) == NULL)
goto done;
/* RFC 2616 "tolerates" asctime() */
@@ -914,8 +549,7 @@ relay_abort_http(struct rsession *con, u_int code, const char *msg,
text = msg;
/* A CSS stylesheet allows minimal customization by the user */
- if ((style = rlay->rl_proto->style) == NULL)
- style = "body { background-color: #a00000; color: white; }";
+ style = "body { background-color: white; color: black; }";
/* Generate simple HTTP+HTML error document */
if (asprintf(&httpmsg,
@@ -935,147 +569,58 @@ relay_abort_http(struct rsession *con, u_int code, const char *msg,
"<body>\n"
"<h1>%s</h1>\n"
"<div id='m'>%s</div>\n"
- "<div id='l'>%s</div>\n"
"<hr><address>%s at %s port %d</address>\n"
"</body>\n"
"</html>\n",
- code, httperr, tmbuf, RELAYD_SERVERNAME,
+ code, httperr, tmbuf, HTTPD_SERVERNAME,
code, httperr, style, httperr, text,
- label == NULL ? "" : label,
- RELAYD_SERVERNAME, hbuf, ntohs(rlay->rl_conf.port)) == -1)
+ HTTPD_SERVERNAME, hbuf, ntohs(srv->srv_conf.port)) == -1)
goto done;
/* Dump the message without checking for success */
- relay_dump(&con->se_in, httpmsg, strlen(httpmsg));
+ server_dump(clt, httpmsg, strlen(httpmsg));
free(httpmsg);
done:
if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1)
- relay_close(con, msg);
+ server_close(clt, msg);
else {
- relay_close(con, httpmsg);
+ server_close(clt, httpmsg);
free(httpmsg);
}
}
void
-relay_close_http(struct rsession *con)
-{
- struct http_descriptor *desc[2] = {
- con->se_in.desc, con->se_out.desc
- };
- int i;
-
- for (i = 0; i < 2; i++) {
- if (desc[i] == NULL)
- continue;
- relay_httpdesc_free(desc[i]);
- free(desc[i]);
- }
-}
-
-char *
-relay_expand_http(struct ctl_relay_event *cre, char *val, char *buf,
- size_t len)
-{
- struct rsession *con = cre->con;
- struct relay *rlay = con->se_relay;
- char ibuf[128];
-
- if (strlcpy(buf, val, len) >= len)
- return (NULL);
-
- if (strstr(val, "$REMOTE_") != NULL) {
- if (strstr(val, "$REMOTE_ADDR") != NULL) {
- if (print_host(&cre->ss, ibuf, sizeof(ibuf)) == NULL)
- return (NULL);
- if (expand_string(buf, len,
- "$REMOTE_ADDR", ibuf) != 0)
- return (NULL);
- }
- if (strstr(val, "$REMOTE_PORT") != NULL) {
- snprintf(ibuf, sizeof(ibuf), "%u", ntohs(cre->port));
- if (expand_string(buf, len,
- "$REMOTE_PORT", ibuf) != 0)
- return (NULL);
- }
- }
- if (strstr(val, "$SERVER_") != NULL) {
- if (strstr(val, "$SERVER_ADDR") != NULL) {
- if (print_host(&rlay->rl_conf.ss,
- ibuf, sizeof(ibuf)) == NULL)
- return (NULL);
- if (expand_string(buf, len,
- "$SERVER_ADDR", ibuf) != 0)
- return (NULL);
- }
- if (strstr(val, "$SERVER_PORT") != NULL) {
- snprintf(ibuf, sizeof(ibuf), "%u",
- ntohs(rlay->rl_conf.port));
- if (expand_string(buf, len,
- "$SERVER_PORT", ibuf) != 0)
- return (NULL);
- }
- if (strstr(val, "$SERVER_NAME") != NULL) {
- if (expand_string(buf, len,
- "$SERVER_NAME", RELAYD_SERVERNAME) != 0)
- return (NULL);
- }
- }
- if (strstr(val, "$TIMEOUT") != NULL) {
- snprintf(ibuf, sizeof(ibuf), "%lld",
- (long long)rlay->rl_conf.timeout.tv_sec);
- if (expand_string(buf, len, "$TIMEOUT", ibuf) != 0)
- return (NULL);
- }
-
- return (buf);
-}
-
-int
-relay_writerequest_http(struct ctl_relay_event *dst,
- struct ctl_relay_event *cre)
+server_close_http(struct client *clt)
{
- struct http_descriptor *desc = (struct http_descriptor *)cre->desc;
- const char *name = NULL;
-
- if ((name = relay_httpmethod_byid(desc->http_method)) == NULL)
- return (-1);
+ struct http_descriptor *desc = clt->clt_desc;
- if (relay_bufferevent_print(dst, name) == -1 ||
- relay_bufferevent_print(dst, " ") == -1 ||
- relay_bufferevent_print(dst, desc->http_path) == -1 ||
- (desc->http_query != NULL &&
- (relay_bufferevent_print(dst, "?") == -1 ||
- relay_bufferevent_print(dst, desc->http_query) == -1)) ||
- relay_bufferevent_print(dst, " ") == -1 ||
- relay_bufferevent_print(dst, desc->http_version) == -1)
- return (-1);
-
- return (0);
+ if (desc == NULL)
+ return;
+ server_httpdesc_free(desc);
+ free(desc);
}
int
-relay_writeresponse_http(struct ctl_relay_event *dst,
- struct ctl_relay_event *cre)
+server_writeresponse_http(struct client *clt)
{
- struct http_descriptor *desc = (struct http_descriptor *)cre->desc;
+ struct http_descriptor *desc = (struct http_descriptor *)clt->clt_desc;
DPRINTF("version: %s rescode: %s resmsg: %s", desc->http_version,
desc->http_rescode, desc->http_resmesg);
- if (relay_bufferevent_print(dst, desc->http_version) == -1 ||
- relay_bufferevent_print(dst, " ") == -1 ||
- relay_bufferevent_print(dst, desc->http_rescode) == -1 ||
- relay_bufferevent_print(dst, " ") == -1 ||
- relay_bufferevent_print(dst, desc->http_resmesg) == -1)
+ if (server_bufferevent_print(clt, desc->http_version) == -1 ||
+ server_bufferevent_print(clt, " ") == -1 ||
+ server_bufferevent_print(clt, desc->http_rescode) == -1 ||
+ server_bufferevent_print(clt, " ") == -1 ||
+ server_bufferevent_print(clt, desc->http_resmesg) == -1)
return (-1);
return (0);
}
int
-relay_writeheader_kv(struct ctl_relay_event *dst, struct kv *hdr)
+server_writeheader_kv(struct client *clt, struct kv *hdr)
{
char *ptr;
const char *key;
@@ -1091,11 +636,11 @@ relay_writeheader_kv(struct ctl_relay_event *dst, struct kv *hdr)
ptr = hdr->kv_value;
DPRINTF("%s: ptr %s", __func__, ptr);
- if (relay_bufferevent_print(dst, key) == -1 ||
+ if (server_bufferevent_print(clt, key) == -1 ||
(ptr != NULL &&
- (relay_bufferevent_print(dst, ": ") == -1 ||
- relay_bufferevent_print(dst, ptr) == -1 ||
- relay_bufferevent_print(dst, "\r\n") == -1)))
+ (server_bufferevent_print(clt, ": ") == -1 ||
+ server_bufferevent_print(clt, ptr) == -1 ||
+ server_bufferevent_print(clt, "\r\n") == -1)))
return (-1);
DPRINTF("%s: %s: %s", __func__, key,
hdr->kv_value == NULL ? "" : hdr->kv_value);
@@ -1104,17 +649,16 @@ relay_writeheader_kv(struct ctl_relay_event *dst, struct kv *hdr)
}
int
-relay_writeheader_http(struct ctl_relay_event *dst, struct ctl_relay_event
- *cre)
+server_writeheader_http(struct client *clt)
{
struct kv *hdr, *kv;
- struct http_descriptor *desc = (struct http_descriptor *)cre->desc;
+ struct http_descriptor *desc = (struct http_descriptor *)clt->clt_desc;
RB_FOREACH(hdr, kvtree, &desc->http_headers) {
- if (relay_writeheader_kv(dst, hdr) == -1)
+ if (server_writeheader_kv(clt, hdr) == -1)
return (-1);
TAILQ_FOREACH(kv, &hdr->kv_children, kv_entry) {
- if (relay_writeheader_kv(dst, kv) == -1)
+ if (server_writeheader_kv(clt, kv) == -1)
return (-1);
}
}
@@ -1123,7 +667,7 @@ relay_writeheader_http(struct ctl_relay_event *dst, struct ctl_relay_event
}
enum httpmethod
-relay_httpmethod_byname(const char *name)
+server_httpmethod_byname(const char *name)
{
enum httpmethod id = HTTP_METHOD_NONE;
struct http_method method, *res = NULL;
@@ -1137,14 +681,14 @@ relay_httpmethod_byname(const char *name)
*/
if ((res = bsearch(&method, http_methods,
sizeof(http_methods) / sizeof(http_methods[0]) - 1,
- sizeof(http_methods[0]), relay_httpmethod_cmp)) != NULL)
+ sizeof(http_methods[0]), server_httpmethod_cmp)) != NULL)
id = res->method_id;
return (id);
}
const char *
-relay_httpmethod_byid(u_int id)
+server_httpmethod_byid(u_int id)
{
const char *name = NULL;
int i;
@@ -1160,7 +704,7 @@ relay_httpmethod_byid(u_int id)
}
static int
-relay_httpmethod_cmp(const void *a, const void *b)
+server_httpmethod_cmp(const void *a, const void *b)
{
const struct http_method *ma = a;
const struct http_method *mb = b;
@@ -1168,7 +712,7 @@ relay_httpmethod_cmp(const void *a, const void *b)
}
const char *
-relay_httperror_byid(u_int id)
+server_httperror_byid(u_int id)
{
struct http_error error, *res = NULL;
@@ -1177,560 +721,15 @@ relay_httperror_byid(u_int id)
res = bsearch(&error, http_errors,
sizeof(http_errors) / sizeof(http_errors[0]) - 1,
- sizeof(http_errors[0]), relay_httperror_cmp);
+ sizeof(http_errors[0]), server_httperror_cmp);
return (res->error_name);
}
static int
-relay_httperror_cmp(const void *a, const void *b)
+server_httperror_cmp(const void *a, const void *b)
{
const struct http_error *ea = a;
const struct http_error *eb = b;
return (ea->error_code - eb->error_code);
}
-
-int
-relay_httpquery_test(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *actions)
-{
- struct http_descriptor *desc = cre->desc;
- struct kv *match = &desc->http_matchquery;
- struct kv *kv = &rule->rule_kv[KEY_TYPE_QUERY];
-
- if (cre->dir == RELAY_DIR_RESPONSE || kv->kv_type != KEY_TYPE_QUERY)
- return (0);
- else if (kv->kv_key == NULL)
- return (0);
- else if (relay_lookup_query(cre, kv))
- return (-1);
-
- relay_match(actions, kv, match, NULL);
-
- return (0);
-}
-
-int
-relay_httpheader_test(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *actions)
-{
- struct http_descriptor *desc = cre->desc;
- struct kv *kv = &rule->rule_kv[KEY_TYPE_HEADER];
- struct kv *match;
-
- if (kv->kv_type != KEY_TYPE_HEADER)
- return (0);
-
- match = kv_find(&desc->http_headers, kv);
-
- if (kv->kv_option == KEY_OPTION_APPEND ||
- kv->kv_option == KEY_OPTION_SET) {
- /* header can be NULL and will be added later */
- } else if (match == NULL) {
- /* Fail if header doesn't exist */
- return (-1);
- }
-
- relay_match(actions, kv, match, &desc->http_headers);
-
- return (0);
-}
-
-int
-relay_httppath_test(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *actions)
-{
- struct http_descriptor *desc = cre->desc;
- struct kv *kv = &rule->rule_kv[KEY_TYPE_PATH];
- struct kv *match = &desc->http_pathquery;
- const char *query;
-
- if (cre->dir == RELAY_DIR_RESPONSE || kv->kv_type != KEY_TYPE_PATH)
- return (0);
- else if (kv->kv_key == NULL)
- return (0);
- else if (fnmatch(kv->kv_key, desc->http_path, 0) == FNM_NOMATCH)
- return (-1);
- else if (kv->kv_value != NULL && kv->kv_option == KEY_OPTION_NONE) {
- query = desc->http_query == NULL ? "" : desc->http_query;
- if (fnmatch(kv->kv_value, query, FNM_CASEFOLD) == FNM_NOMATCH)
- return (-1);
- }
-
- relay_match(actions, kv, match, NULL);
-
- return (0);
-}
-
-int
-relay_httpurl_test(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *actions)
-{
- struct http_descriptor *desc = cre->desc;
- struct kv *host, key;
- struct kv *kv = &rule->rule_kv[KEY_TYPE_URL];
- struct kv *match = &desc->http_pathquery;
-
- if (cre->dir == RELAY_DIR_RESPONSE || kv->kv_type != KEY_TYPE_URL ||
- kv->kv_key == NULL)
- return (0);
-
- key.kv_key = "Host";
- host = kv_find(&desc->http_headers, &key);
-
- if (host == NULL || host->kv_value == NULL)
- return (0);
- else if (rule->rule_action != RULE_ACTION_BLOCK &&
- kv->kv_option == KEY_OPTION_LOG &&
- fnmatch(kv->kv_key, match->kv_key, FNM_CASEFOLD) != FNM_NOMATCH) {
- /* fnmatch url only for logging */
- } else if (relay_lookup_url(cre, host->kv_value, kv) != 0)
- return (-1);
-
- relay_match(actions, kv, match, NULL);
-
- return (0);
-}
-
-int
-relay_httpcookie_test(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *actions)
-{
- struct http_descriptor *desc = cre->desc;
- struct kv *kv = &rule->rule_kv[KEY_TYPE_COOKIE], key;
- struct kv *match = NULL;
-
- if (kv->kv_type != KEY_TYPE_COOKIE)
- return (0);
-
- switch (cre->dir) {
- case RELAY_DIR_REQUEST:
- key.kv_key = "Cookie";
- break;
- case RELAY_DIR_RESPONSE:
- key.kv_key = "Set-Cookie";
- break;
- default:
- return (0);
- /* NOTREACHED */
- break;
- }
-
- if (kv->kv_option == KEY_OPTION_APPEND ||
- kv->kv_option == KEY_OPTION_SET) {
- /* no cookie, can be NULL and will be added later */
- } else {
- match = kv_find(&desc->http_headers, &key);
- if (match == NULL)
- return (-1);
- if (kv->kv_key == NULL || match->kv_value == NULL)
- return (0);
- else if (relay_lookup_cookie(cre, match->kv_value, kv) != 0)
- return (-1);
- }
-
- relay_match(actions, kv, match, &desc->http_headers);
-
- return (0);
-}
-
-int
-relay_match_actions(struct ctl_relay_event *cre, struct relay_rule *rule,
- struct kvlist *matches, struct kvlist *actions)
-{
- struct rsession *con = cre->con;
- struct kv *kv;
-
- /*
- * Apply the following options instantly (action per match).
- */
- if (rule->rule_table != NULL)
- con->se_table = rule->rule_table;
-
- if (rule->rule_tag != 0)
- con->se_tag = rule->rule_tag == -1 ? 0 : rule->rule_tag;
-
- if (rule->rule_label != 0)
- con->se_label = rule->rule_label == -1 ? 0 : rule->rule_label;
-
- /*
- * Apply the remaining options once after evaluation.
- */
- if (matches == NULL) {
- /* 'pass' or 'block' rule */
- TAILQ_FOREACH(kv, &rule->rule_kvlist, kv_rule_entry) {
- TAILQ_INSERT_TAIL(actions, kv, kv_action_entry);
- TAILQ_REMOVE(&rule->rule_kvlist, kv, kv_rule_entry);
- }
- } else {
- /* 'match' rule */
- TAILQ_FOREACH(kv, matches, kv_match_entry) {
- TAILQ_INSERT_TAIL(actions, kv, kv_action_entry);
- }
- }
-
- return (0);
-}
-
-int
-relay_apply_actions(struct ctl_relay_event *cre, struct kvlist *actions)
-{
- struct rsession *con = cre->con;
- struct http_descriptor *desc = cre->desc;
- struct kv *host = NULL;
- const char *value;
- struct kv *kv, *match, *kp, *mp, kvcopy, matchcopy, key;
- int addkv, ret;
- char buf[IBUF_READ_SIZE], *ptr;
-
- memset(&kvcopy, 0, sizeof(kvcopy));
- memset(&matchcopy, 0, sizeof(matchcopy));
-
- ret = -1;
- kp = mp = NULL;
- TAILQ_FOREACH(kv, actions, kv_action_entry) {
- kp = NULL;
- match = kv->kv_match;
- addkv = 0;
-
- /*
- * Although marked as deleted, give a chance to non-critical
- * actions, ie. log, to be performed
- */
- if (match != NULL && (match->kv_flags & KV_FLAG_INVALID))
- goto matchdel;
-
- switch (kv->kv_option) {
- case KEY_OPTION_APPEND:
- case KEY_OPTION_SET:
- switch (kv->kv_type) {
- case KEY_TYPE_PATH:
- if (kv->kv_option == KEY_OPTION_APPEND) {
- if (kv_setkey(match, "%s%s",
- match->kv_key, kv->kv_key) == -1)
- goto fail;
- } else {
- if (kv_setkey(match, "%s",
- kv->kv_value) == -1)
- goto fail;
- }
- break;
- case KEY_TYPE_COOKIE:
- kp = &kvcopy;
- if (kv_inherit(kp, kv) == NULL)
- goto fail;
- if (kv_set(kp, "%s=%s;", kp->kv_key,
- kp->kv_value) == -1)
- goto fail;
- if (kv_setkey(kp, "%s", cre->dir ==
- RELAY_DIR_REQUEST ?
- "Cookie" : "Set-Cookie") == -1)
- goto fail;
- /* FALLTHROUGH cookie is a header */
- case KEY_TYPE_HEADER:
- if (match == NULL) {
- addkv = 1;
- break;
- }
- if (match->kv_value == NULL ||
- kv->kv_option == KEY_OPTION_SET) {
- if (kv_set(match, "%s",
- kv->kv_value) == -1)
- goto fail;
- } else {
- if (kv_setkey(match, "%s,%s",
- match->kv_key, kv->kv_key) == -1)
- goto fail;
- }
- break;
- default:
- /* query, url not supported */
- break;
- }
- break;
- case KEY_OPTION_REMOVE:
- switch (kv->kv_type) {
- case KEY_TYPE_PATH:
- if (kv_setkey(match, "/") == -1)
- goto fail;
- break;
- case KEY_TYPE_COOKIE:
- case KEY_TYPE_HEADER:
- if (kv->kv_matchtree != NULL)
- match->kv_flags |= KV_FLAG_INVALID;
- else
- kv_free(match);
- match = kv->kv_match = NULL;
- break;
- default:
- /* query and url not supported */
- break;
- }
- break;
- case KEY_OPTION_HASH:
- switch (kv->kv_type) {
- case KEY_TYPE_PATH:
- value = match->kv_key;
- break;
- default:
- value = match->kv_value;
- break;
- }
- if (!con->se_hashkeyset)
- con->se_hashkey = HASHINIT;
- con->se_hashkey = hash32_str(value, con->se_hashkey);
- con->se_hashkeyset = 1;
- log_debug("%s: hashkey 0x%04x", __func__,
- con->se_hashkey);
- break;
- case KEY_OPTION_LOG:
- /* perform this later */
- break;
- default:
- fatalx("relay_action: invalid action");
- /* NOTREACHED */
- }
-
- /* from now on, reads from kp writes to kv */
- if (kp == NULL)
- kp = kv;
- if (addkv && kv->kv_matchtree != NULL) {
- /* Add new entry to the list (eg. new HTTP header) */
- if ((match = kv_add(kv->kv_matchtree, kp->kv_key,
- kp->kv_value)) == NULL)
- goto fail;
- match->kv_option = kp->kv_option;
- match->kv_type = kp->kv_type;
- kv->kv_match = match;
- }
- if (match != NULL && kp->kv_flags & KV_FLAG_MACRO) {
- bzero(buf, sizeof(buf));
- if ((ptr = relay_expand_http(cre, kp->kv_value, buf,
- sizeof(buf))) == NULL)
- goto fail;
- if (kv_set(match, ptr) == -1)
- goto fail;
- }
-
- matchdel:
- switch(kv->kv_option) {
- case KEY_OPTION_LOG:
- if (match == NULL)
- break;
- mp = &matchcopy;
- if (kv_inherit(mp, match) == NULL)
- goto fail;
- if (mp->kv_flags & KV_FLAG_INVALID) {
- if (kv_set(mp, "%s (removed)",
- mp->kv_value) == -1)
- goto fail;
- }
- switch(kv->kv_type) {
- case KEY_TYPE_URL:
- key.kv_key = "Host";
- host = kv_find(&desc->http_headers, &key);
- switch (kv->kv_digest) {
- case DIGEST_NONE:
- if (host == NULL ||
- host->kv_value == NULL)
- break;
- if (kv_setkey(mp, "%s%s",
- host->kv_value, mp->kv_key) ==
- -1)
- goto fail;
- break;
- default:
- if (kv_setkey(mp, "%s", kv->kv_key)
- == -1)
- goto fail;
- break;
- }
- break;
- default:
- break;
- }
- if (kv_log(con->se_log, mp, con->se_label) == -1)
- goto fail;
- break;
- default:
- break;
- }
-
- /* actions applied, cleanup kv */
- kv->kv_match = NULL;
- kv->kv_matchtree = NULL;
- TAILQ_REMOVE(actions, kv, kv_match_entry);
-
- kv_free(&kvcopy);
- kv_free(&matchcopy);
- }
-
- ret = 0;
- fail:
- kv_free(&kvcopy);
- kv_free(&matchcopy);
-
- return (ret);
-}
-
-#define RELAY_GET_SKIP_STEP(i) \
- do { \
- r = r->rule_skip[i]; \
- DPRINTF("%s:%d: skip %d rules", __func__, __LINE__, i); \
- } while (0)
-
-#define RELAY_GET_NEXT_STEP \
- do { \
- DPRINTF("%s:%d: next rule", __func__, __LINE__); \
- goto nextrule; \
- } while (0)
-
-int
-relay_test(struct protocol *proto, struct ctl_relay_event *cre)
-{
- struct rsession *con;
- struct http_descriptor *desc = cre->desc;
- struct relay_rule *r = NULL, *rule = NULL;
- u_int cnt = 0;
- u_int action = RES_PASS;
- struct kvlist actions, matches;
- struct kv *kv;
-
- con = cre->con;
- TAILQ_INIT(&actions);
-
- r = TAILQ_FIRST(&proto->rules);
- while (r != NULL) {
- cnt++;
- TAILQ_INIT(&matches);
- TAILQ_INIT(&r->rule_kvlist);
- if (r->rule_dir && r->rule_dir != cre->dir)
- RELAY_GET_SKIP_STEP(RULE_SKIP_DIR);
- else if (proto->type != r->rule_proto)
- RELAY_GET_SKIP_STEP(RULE_SKIP_PROTO);
- else if (r->rule_af != AF_UNSPEC &&
- (cre->ss.ss_family != r->rule_af ||
- cre->dst->ss.ss_family != r->rule_af))
- RELAY_GET_SKIP_STEP(RULE_SKIP_AF);
- else if (RELAY_ADDR_CMP(&r->rule_src, &cre->ss) != 0)
- RELAY_GET_SKIP_STEP(RULE_SKIP_SRC);
- else if (RELAY_ADDR_CMP(&r->rule_dst, &cre->dst->ss) != 0)
- RELAY_GET_SKIP_STEP(RULE_SKIP_DST);
- else if (r->rule_method != HTTP_METHOD_NONE &&
- (desc->http_method == HTTP_METHOD_RESPONSE ||
- desc->http_method != r->rule_method))
- RELAY_GET_SKIP_STEP(RULE_SKIP_METHOD);
- else if (r->rule_tagged && con->se_tag != r->rule_tagged)
- RELAY_GET_NEXT_STEP;
- else if (relay_httpheader_test(cre, r, &matches) != 0)
- RELAY_GET_NEXT_STEP;
- else if (relay_httpquery_test(cre, r, &matches) != 0)
- RELAY_GET_NEXT_STEP;
- else if (relay_httppath_test(cre, r, &matches) != 0)
- RELAY_GET_NEXT_STEP;
- else if (relay_httpurl_test(cre, r, &matches) != 0)
- RELAY_GET_NEXT_STEP;
- else if (relay_httpcookie_test(cre, r, &matches) != 0)
- RELAY_GET_NEXT_STEP;
- else {
- DPRINTF("%s: session %d: matched rule %d",
- __func__, con->se_id, r->rule_id);
-
- if (r->rule_action == RULE_ACTION_MATCH) {
- if (relay_match_actions(cre, r, &matches,
- &actions) != 0) {
- /* Something bad happened, drop */
- action = RES_DROP;
- break;
- }
- RELAY_GET_NEXT_STEP;
- } else if (r->rule_action == RULE_ACTION_BLOCK)
- action = RES_DROP;
- else if (r->rule_action == RULE_ACTION_PASS)
- action = RES_PASS;
-
- /* Rule matched */
- rule = r;
-
- /* Temporarily save actions */
- TAILQ_FOREACH(kv, &matches, kv_match_entry) {
- TAILQ_INSERT_TAIL(&rule->rule_kvlist,
- kv, kv_rule_entry);
- }
-
- if (rule->rule_flags & RULE_FLAG_QUICK)
- break;
-
- nextrule:
- /* Continue to find last matching policy */
- r = TAILQ_NEXT(r, rule_entry);
- }
- }
-
- if (rule != NULL &&
- relay_match_actions(cre, rule, NULL, &actions) != 0) {
- /* Something bad happened, drop */
- action = RES_DROP;
- }
-
- if (relay_apply_actions(cre, &actions) != 0) {
- /* Something bad happened, drop */
- action = RES_DROP;
- }
-
- DPRINTF("%s: session %d: action %d", __func__,
- con->se_id, action);
-
- return (action);
-}
-
-#define RELAY_SET_SKIP_STEPS(i) \
- do { \
- while (head[i] != cur) { \
- head[i]->rule_skip[i] = cur; \
- head[i] = TAILQ_NEXT(head[i], rule_entry); \
- } \
- } while (0)
-
-/* This code is derived from pf_calc_skip_steps() from pf.c */
-void
-relay_calc_skip_steps(struct relay_rules *rules)
-{
- struct relay_rule *head[RULE_SKIP_COUNT], *cur, *prev;
- int i;
-
- cur = TAILQ_FIRST(rules);
- prev = cur;
- for (i = 0; i < RULE_SKIP_COUNT; ++i)
- head[i] = cur;
- while (cur != NULL) {
- if (cur->rule_dir != prev->rule_dir)
- RELAY_SET_SKIP_STEPS(RULE_SKIP_DIR);
- else if (cur->rule_proto != prev->rule_proto)
- RELAY_SET_SKIP_STEPS(RULE_SKIP_PROTO);
- else if (cur->rule_af != prev->rule_af)
- RELAY_SET_SKIP_STEPS(RULE_SKIP_AF);
- else if (RELAY_ADDR_NEQ(&cur->rule_src, &prev->rule_src))
- RELAY_SET_SKIP_STEPS(RULE_SKIP_SRC);
- else if (RELAY_ADDR_NEQ(&cur->rule_dst, &prev->rule_dst))
- RELAY_SET_SKIP_STEPS(RULE_SKIP_DST);
- else if (cur->rule_method != prev->rule_method)
- RELAY_SET_SKIP_STEPS(RULE_SKIP_METHOD);
-
- prev = cur;
- cur = TAILQ_NEXT(cur, rule_entry);
- }
- for (i = 0; i < RULE_SKIP_COUNT; ++i)
- RELAY_SET_SKIP_STEPS(i);
-}
-
-void
-relay_match(struct kvlist *actions, struct kv *kv, struct kv *match,
- struct kvtree *matchtree)
-{
- if (kv->kv_option != KEY_OPTION_NONE) {
- kv->kv_match = match;
- kv->kv_matchtree = matchtree;
- TAILQ_INSERT_TAIL(actions, kv, kv_match_entry);
- }
-}