From 7562c073291a4c542e2be82cc5aa332031ee4b29 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Tue, 20 Nov 2018 16:07:52 +0000 Subject: use CONNECT method if request contains upgrade header this should allow using websockets or other upgraded connections on a standard (non-encrypted) proxified HTTP connection. testcase: $ telnet localhost 8888 GET / HTTP/1.1 Host: echo.websocket.org:80 Upgrade: websocket Connection: Upgrade Origin: http://echo.websocket.org Sec-WebSocket-Key: 5KNqfsPZ9m/BbeRlVpf7MQ== Sec-WebSocket-Version: 13 --- src/reqs.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/reqs.c b/src/reqs.c index bbdcc74..f356e02 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -87,7 +87,7 @@ * connections. The request line is allocated from the heap, but it must * be freed in another function. */ -static int read_request_line (struct conn_s *connptr) +static int read_request_line (struct conn_s *connptr, char** lines, size_t* lines_len) { ssize_t len; @@ -101,6 +101,12 @@ retry: return -1; } + *lines = saferealloc(*lines, *lines_len + len + 1); + if(*lines) { + strcpy(*lines + *lines_len, connptr->request_line); + *lines_len += len; + } + /* * Strip the new line and carriage return from the string. */ @@ -626,7 +632,7 @@ add_header_to_connection (hashmap_t hashofheaders, char *header, size_t len) /* * Read all the headers from the stream */ -static int get_all_headers (int fd, hashmap_t hashofheaders) +static int get_all_headers (int fd, hashmap_t hashofheaders, char** lines, size_t* lines_len) { char *line = NULL; char *header = NULL; @@ -646,6 +652,14 @@ static int get_all_headers (int fd, hashmap_t hashofheaders) return -1; } + if(lines) { + *lines = saferealloc(*lines, *lines_len + linelen + 1); + if(*lines) { + strcpy(*lines + *lines_len, line); + *lines_len += linelen; + } + } + /* * If we received a CR LF or a non-continuation line, then add * the accumulated header field, if any, to the hashmap, and @@ -1011,7 +1025,7 @@ retry: /* * Get all the headers from the remote server in a big hash */ - if (get_all_headers (connptr->server_fd, hashofheaders) < 0) { + if (get_all_headers (connptr->server_fd, hashofheaders, NULL, NULL) < 0) { log_message (LOG_WARNING, "Could not retrieve all the headers from the remote server."); hashmap_delete (hashofheaders); @@ -1543,6 +1557,8 @@ void handle_connection (int fd) char sock_ipaddr[IP_LENGTH]; char peer_ipaddr[IP_LENGTH]; char peer_string[HOSTNAME_LENGTH]; + char *lines = NULL; + size_t lines_len = 0; getpeer_information (fd, peer_ipaddr, peer_string); @@ -1571,7 +1587,7 @@ void handle_connection (int fd) goto fail; } - if (read_request_line (connptr) < 0) { + if (read_request_line (connptr, &lines, &lines_len) < 0) { update_stats (STAT_BADCONN); indicate_http_error (connptr, 408, "Timeout", "detail", @@ -1597,7 +1613,7 @@ void handle_connection (int fd) /* * Get all the headers from the client in a big hash. */ - if (get_all_headers (connptr->client_fd, hashofheaders) < 0) { + if (get_all_headers (connptr->client_fd, hashofheaders, &lines, &lines_len) < 0) { log_message (LOG_WARNING, "Could not retrieve all the headers from the client"); indicate_http_error (connptr, 400, "Bad Request", @@ -1683,6 +1699,11 @@ void handle_connection (int fd) "file descriptor %d.", request->host, connptr->server_fd); + if(hashmap_search(hashofheaders, "upgrade") > 0) { + connptr->connect_method = TRUE; + safe_write (connptr->server_fd, lines, lines_len); + } + if (!connptr->connect_method) establish_http_connection (connptr, request); } @@ -1740,6 +1761,7 @@ fail: } done: + safefree(lines); free_request_struct (request); hashmap_delete (hashofheaders); destroy_conn (connptr); -- cgit v1.2.3 From 679b683331771d2ed196abf46ee7c2278f0f687f Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sat, 29 Dec 2018 16:39:04 +0000 Subject: connection upgrade: do not emit 200 header when establishing conn a tri-state connect_method enum was introduced for this purpose. if connect_method is set to CM_UPGRADE, the "HTTP/1.0 200 Connection established" response won't be emitted. --- src/conns.c | 2 +- src/conns.h | 9 ++++++++- src/reqs.c | 6 ++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/conns.c b/src/conns.c index 94faeea..3859d69 100644 --- a/src/conns.c +++ b/src/conns.c @@ -68,7 +68,7 @@ struct conn_s *initialize_conn (int client_fd, const char *ipaddr, connptr->error_string = NULL; connptr->error_number = -1; - connptr->connect_method = FALSE; + connptr->connect_method = CM_FALSE; connptr->show_stats = FALSE; connptr->protocol.major = connptr->protocol.minor = 0; diff --git a/src/conns.h b/src/conns.h index b63d026..322ead1 100644 --- a/src/conns.h +++ b/src/conns.h @@ -24,6 +24,12 @@ #include "main.h" #include "hashmap.h" +enum connect_method_e { + CM_FALSE = 0, + CM_TRUE = 1, + CM_UPGRADE = 2, +}; + /* * Connection Definition */ @@ -37,8 +43,9 @@ struct conn_s { /* The request line (first line) from the client */ char *request_line; + enum connect_method_e connect_method; + /* Booleans */ - unsigned int connect_method; unsigned int show_stats; /* diff --git a/src/reqs.c b/src/reqs.c index f356e02..9675980 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -438,7 +438,7 @@ BAD_REQUEST_ERROR: goto fail; } - connptr->connect_method = TRUE; + connptr->connect_method = CM_TRUE; } else { #ifdef TRANSPARENT_PROXY if (!do_transparent_proxy @@ -1700,7 +1700,7 @@ void handle_connection (int fd) connptr->server_fd); if(hashmap_search(hashofheaders, "upgrade") > 0) { - connptr->connect_method = TRUE; + connptr->connect_method = CM_UPGRADE; safe_write (connptr->server_fd, lines, lines_len); } @@ -1718,6 +1718,8 @@ void handle_connection (int fd) update_stats (STAT_BADCONN); goto fail; } + } else if (connptr->connect_method == CM_UPGRADE) { + /* NOP */ ; } else { if (send_ssl_response (connptr) < 0) { log_message (LOG_ERR, -- cgit v1.2.3