summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbenno <benno@openbsd.org>2021-03-24 20:59:53 +0000
committerbenno <benno@openbsd.org>2021-03-24 20:59:53 +0000
commit53e8df0d329f0e7890bb7e3976fd59a63d68e5b4 (patch)
tree21bf854d390d4f6bd1d89aaaf824ad814f9bd6e4
parentUpdate regress for new_cipher rename. (diff)
downloadwireguard-openbsd-53e8df0d329f0e7890bb7e3976fd59a63d68e5b4.tar.xz
wireguard-openbsd-53e8df0d329f0e7890bb7e3976fd59a63d68e5b4.zip
Responses to HEAD requests must not have a message body (even though they have
a Content-Length header). HTTP RFC 7231 section 4.3.2. found by niklas@, claudio@ agrees.
-rw-r--r--usr.sbin/relayd/http.h13
-rw-r--r--usr.sbin/relayd/relay.c4
-rw-r--r--usr.sbin/relayd/relay_http.c96
3 files changed, 99 insertions, 14 deletions
diff --git a/usr.sbin/relayd/http.h b/usr.sbin/relayd/http.h
index e7688165275..b9784ad55ce 100644
--- a/usr.sbin/relayd/http.h
+++ b/usr.sbin/relayd/http.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: http.h,v 1.11 2019/05/08 23:22:19 reyk Exp $ */
+/* $OpenBSD: http.h,v 1.12 2021/03/24 20:59:53 benno Exp $ */
/*
* Copyright (c) 2012 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -19,6 +19,8 @@
#ifndef HTTP_H
#define HTTP_H
+#include <sys/queue.h>
+
#define HTTP_PORT 80
#define HTTPS_PORT 443
@@ -251,4 +253,13 @@ struct http_descriptor {
struct kvtree http_headers;
};
+struct http_method_node {
+ enum httpmethod hmn_method;
+ SIMPLEQ_ENTRY(http_method_node) hmn_entry;
+};
+
+struct http_session {
+ SIMPLEQ_HEAD(, http_method_node) hs_methods;
+};
+
#endif /* HTTP_H */
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index 02324f516c2..da4a1aa0cc1 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.253 2021/01/27 20:33:05 eric Exp $ */
+/* $OpenBSD: relay.c,v 1.254 2021/03/24 20:59:53 benno Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -800,7 +800,7 @@ relay_input(struct rsession *con)
switch (rlay->rl_proto->type) {
case RELAY_PROTO_HTTP:
- if (relay_httpdesc_init(&con->se_in) == -1) {
+ if (relay_http_priv_init(con) == -1) {
relay_close(con,
"failed to allocate http descriptor", 1);
return;
diff --git a/usr.sbin/relayd/relay_http.c b/usr.sbin/relayd/relay_http.c
index 69b48697427..29e401e0935 100644
--- a/usr.sbin/relayd/relay_http.c
+++ b/usr.sbin/relayd/relay_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay_http.c,v 1.80 2021/01/09 08:53:58 denis Exp $ */
+/* $OpenBSD: relay_http.c,v 1.81 2021/03/24 20:59:54 benno Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -113,6 +113,21 @@ relay_http_init(struct relay *rlay)
}
int
+relay_http_priv_init(struct rsession *con)
+{
+
+ struct http_session *hs;
+
+ if ((hs = calloc(1, sizeof(*hs))) == NULL)
+ return (-1);
+ SIMPLEQ_INIT(&hs->hs_methods);
+ DPRINTF("%s: session %d http_session %p", __func__,
+ con->se_id, hs);
+ con->se_priv = hs;
+ return (relay_httpdesc_init(&con->se_in));
+}
+
+int
relay_httpdesc_init(struct ctl_relay_event *cre)
{
struct http_descriptor *desc;
@@ -162,6 +177,9 @@ relay_read_http(struct bufferevent *bev, void *arg)
size_t size, linelen;
struct kv *hdr = NULL;
struct kv *upgrade = NULL, *upgrade_ws = NULL;
+ struct http_method_node *hmn;
+ struct http_session *hs;
+ enum httpmethod request_method;
getmonotime(&con->se_tv_last);
cre->timedout = 0;
@@ -239,11 +257,34 @@ relay_read_http(struct bufferevent *bev, void *arg)
DPRINTF("%s: session %d: header '%s: %s'", __func__,
con->se_id, key, value);
+ hs = con->se_priv;
+ DPRINTF("%s: session %d http_session %p", __func__,
+ con->se_id, hs);
+
/*
* Identify and handle specific HTTP request methods
*/
if (cre->line == 1 && cre->dir == RELAY_DIR_RESPONSE) {
desc->http_method = HTTP_METHOD_RESPONSE;
+ hmn = SIMPLEQ_FIRST(&hs->hs_methods);
+
+ /*
+ * There is nothing preventing the relay to send
+ * an unbalanced response. Be prepared.
+ */
+ if (hmn == NULL) {
+ request_method = HTTP_METHOD_NONE;
+ DPRINTF("%s: session %d unbalanced response",
+ __func__, con->se_id);
+ } else {
+ SIMPLEQ_REMOVE_HEAD(&hs->hs_methods, hmn_entry);
+ request_method = hmn->hmn_method;
+ DPRINTF("%s: session %d dequeing %s", __func__,
+ con->se_id,
+ relay_httpmethod_byid(request_method));
+ free(hmn);
+ }
+
/*
* Decode response path and query
*/
@@ -287,6 +328,15 @@ relay_read_http(struct bufferevent *bev, void *arg)
free(line);
goto fail;
}
+ if ((hmn = calloc(1, sizeof *hmn)) == NULL) {
+ free(line);
+ goto fail;
+ }
+ hmn->hmn_method = desc->http_method;
+ DPRINTF("%s: session %d enqueing %s", __func__,
+ con->se_id,
+ relay_httpmethod_byid(hmn->hmn_method));
+ SIMPLEQ_INSERT_TAIL(&hs->hs_methods, hmn, hmn_entry);
/*
* Decode request path and query
*/
@@ -332,16 +382,26 @@ relay_read_http(struct bufferevent *bev, void *arg)
goto abort;
}
/*
- * Need to read data from the client after the
- * HTTP header.
- * XXX What about non-standard clients not using
- * the carriage return? And some browsers seem to
- * include the line length in the content-length.
+ * HEAD responses may provide a Content-Length header,
+ * but if so it should just be ignored, since there is
+ * no actual payload in the response.
*/
- cre->toread = strtonum(value, 0, LLONG_MAX, &errstr);
- if (errstr) {
- relay_abort_http(con, 500, errstr, 0);
- goto abort;
+ if (desc->http_method != HTTP_METHOD_RESPONSE
+ || request_method != HTTP_METHOD_HEAD) {
+ /*
+ * Need to read data from the client after the
+ * HTTP header.
+ * XXX What about non-standard clients not
+ * using the carriage return? And some browsers
+ * seem to include the line length in the
+ * content-length.
+ */
+ cre->toread = strtonum(value, 0, LLONG_MAX,
+ &errstr);
+ if (errstr) {
+ relay_abort_http(con, 500, errstr, 0);
+ goto abort;
+ }
}
/*
* response with a status code of 1xx
@@ -502,8 +562,9 @@ relay_read_http(struct bufferevent *bev, void *arg)
case HTTP_METHOD_SEARCH:
case HTTP_METHOD_PATCH:
/* HTTP request payload */
- if (cre->toread > 0)
+ if (cre->toread > 0) {
bev->readcb = relay_read_httpcontent;
+ }
/* Single-pass HTTP body */
if (cre->toread < 0) {
@@ -1117,6 +1178,19 @@ relay_abort_http(struct rsession *con, u_int code, const char *msg,
void
relay_close_http(struct rsession *con)
{
+ struct http_session *hs = con->se_priv;
+ struct http_method_node *hmn;
+
+ DPRINTF("%s: session %d http_session %p", __func__,
+ con->se_id, hs);
+ if (hs != NULL)
+ while (!SIMPLEQ_EMPTY(&hs->hs_methods)) {
+ hmn = SIMPLEQ_FIRST(&hs->hs_methods);
+ SIMPLEQ_REMOVE_HEAD(&hs->hs_methods, hmn_entry);
+ DPRINTF("%s: session %d freeing %s", __func__,
+ con->se_id, relay_httpmethod_byid(hmn->hmn_method));
+ free(hmn);
+ }
relay_httpdesc_free(con->se_in.desc);
free(con->se_in.desc);
relay_httpdesc_free(con->se_out.desc);