diff --git a/etc/tinyproxy.conf.in b/etc/tinyproxy.conf.in index 54024cb..7e01865 100644 --- a/etc/tinyproxy.conf.in +++ b/etc/tinyproxy.conf.in @@ -235,6 +235,14 @@ Allow 127.0.0.1 # #AddHeader "X-My-Header" "Powered by Tinyproxy" +# +# AllowUpgrade: 'Upgrade' and 'Connection' headers are stripped in +# non-HTTPS connections per proxy operation in the HTTP RFC. Enabling +# fixes unencrypted WebSocket connections but is RFC 2616 non-compliant. +# May cause issues with in-connection upgrades to unencrypted HTTP/2. +# Don't enable unless you know what you are doing. +# AllowUpgrade Yes + # # ViaProxyName: The "Via" header is required by the HTTP RFC, but using # the real host name is a security concern. If the following directive diff --git a/src/conf.c b/src/conf.c index 5a87c68..f6bb974 100644 --- a/src/conf.c +++ b/src/conf.c @@ -126,6 +126,7 @@ static HANDLE_FUNC (handle_defaulterrorfile); static HANDLE_FUNC (handle_deny); static HANDLE_FUNC (handle_errorfile); static HANDLE_FUNC (handle_addheader); +static HANDLE_FUNC (handle_allowupgrade); #ifdef FILTER_ENABLE static HANDLE_FUNC (handle_filter); static HANDLE_FUNC (handle_filtercasesensitive); @@ -235,6 +236,7 @@ struct { STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), STDCONF ("errorfile", INT WS STR, handle_errorfile), STDCONF ("addheader", STR WS STR, handle_addheader), + STDCONF ("allowupgrade", BOOL, handle_allowupgrade), #ifdef FILTER_ENABLE /* filtering */ @@ -952,6 +954,12 @@ static HANDLE_FUNC (handle_addheader) return 0; } +static HANDLE_FUNC (handle_allowupgrade) +{ + return set_bool_arg (&conf->allowupgrade, line, &match[2]); +} + + /* * Log level's strings. diff --git a/src/conf.h b/src/conf.h index beb2b01..43b3097 100644 --- a/src/conf.h +++ b/src/conf.h @@ -111,6 +111,14 @@ struct config_s { * Extra headers to be added to outgoing HTTP requests. */ vector_t add_headers; + + /* + * Allow Upgrade and Connection headers to pass through proxy. + * Enables unencrypted WebSocket connections violates RFC + * requirements of not passing Connection/Upgrade through a + * proxy. Unexpected behavior may result. + */ + unsigned int allowupgrade; /* boolean */ }; extern int reload_config_file (const char *config_fname, struct config_s *conf, diff --git a/src/reqs.c b/src/reqs.c index bbdcc74..21d626d 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -82,6 +82,30 @@ #define CHECK_LWS(header, len) \ ((len) > 0 && (header[0] == ' ' || header[0] == '\t')) +static const char *skip_headers_allow_upgrade[] = { + "host", + "keep-alive", + "proxy-connection", + "te", + "trailers" +}; +static const char *skip_headers_default[] = { + "host", + "keep-alive", + "proxy-connection", + "te", + "trailers", + "upgrade" +}; + +static const char *connection_headers_allow_upgrade[] = { + "proxy-connection" +}; +static const char *connection_headers_default[] = { + "connection", + "proxy-connection" +}; + /* * Read in the first line from the client (the request line for HTTP * connections. The request line is allocated from the heap, but it must @@ -281,6 +305,13 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request) request->method, request->path, request->host, portbuff, connptr->upstream_proxy->ua.authstr); + } else if (config.allowupgrade) { + /* Allow websockets to not be closed after handshake. */ + return write_message (connptr->server_fd, + "%s %s HTTP/1.0\r\n" + "Host: %s%s\r\n" + request->method, request->path, + request->host, portbuff); } else { return write_message (connptr->server_fd, "%s %s HTTP/1.0\r\n" @@ -721,16 +752,18 @@ static int get_all_headers (int fd, hashmap_t hashofheaders) */ static int remove_connection_headers (hashmap_t hashofheaders) { - static const char *headers[] = { - "connection", - "proxy-connection" - }; - + char **headers; char *data; char *ptr; ssize_t len; int i; + headers = connection_headers_default; + + if (config.allowupgrade) { + headers = connection_headers_allow_upgrade; + } + for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i) { /* Look for the connection header. If it's not found, return. */ len = @@ -850,20 +883,19 @@ done: static int process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders) { - static const char *skipheaders[] = { - "host", - "keep-alive", - "proxy-connection", - "te", - "trailers", - "upgrade" - }; + char **skipheaders; int i; hashmap_iter iter; int ret = 0; char *data, *header; + skipheaders = skip_headers_default; + + if (config.allowupgrade) { + skipheaders = skip_headers_allow_upgrade; + } + /* * Don't send headers if there's already an error, if the request was * a stats request, or if this was a CONNECT method (unless upstream