WIP: Allow http upgrades w/o using connect method.

This commit is contained in:
Daniel Wilcox 2018-11-08 15:40:40 +00:00
parent f44d0f387b
commit 70da0c0e3b
4 changed files with 69 additions and 13 deletions

View File

@ -235,6 +235,14 @@ Allow 127.0.0.1
# #
#AddHeader "X-My-Header" "Powered by Tinyproxy" #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 # ViaProxyName: The "Via" header is required by the HTTP RFC, but using
# the real host name is a security concern. If the following directive # the real host name is a security concern. If the following directive

View File

@ -126,6 +126,7 @@ static HANDLE_FUNC (handle_defaulterrorfile);
static HANDLE_FUNC (handle_deny); static HANDLE_FUNC (handle_deny);
static HANDLE_FUNC (handle_errorfile); static HANDLE_FUNC (handle_errorfile);
static HANDLE_FUNC (handle_addheader); static HANDLE_FUNC (handle_addheader);
static HANDLE_FUNC (handle_allowupgrade);
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
static HANDLE_FUNC (handle_filter); static HANDLE_FUNC (handle_filter);
static HANDLE_FUNC (handle_filtercasesensitive); static HANDLE_FUNC (handle_filtercasesensitive);
@ -235,6 +236,7 @@ struct {
STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth),
STDCONF ("errorfile", INT WS STR, handle_errorfile), STDCONF ("errorfile", INT WS STR, handle_errorfile),
STDCONF ("addheader", STR WS STR, handle_addheader), STDCONF ("addheader", STR WS STR, handle_addheader),
STDCONF ("allowupgrade", BOOL, handle_allowupgrade),
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
/* filtering */ /* filtering */
@ -952,6 +954,12 @@ static HANDLE_FUNC (handle_addheader)
return 0; return 0;
} }
static HANDLE_FUNC (handle_allowupgrade)
{
return set_bool_arg (&conf->allowupgrade, line, &match[2]);
}
/* /*
* Log level's strings. * Log level's strings.

View File

@ -111,6 +111,14 @@ struct config_s {
* Extra headers to be added to outgoing HTTP requests. * Extra headers to be added to outgoing HTTP requests.
*/ */
vector_t add_headers; 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, extern int reload_config_file (const char *config_fname, struct config_s *conf,

View File

@ -82,6 +82,30 @@
#define CHECK_LWS(header, len) \ #define CHECK_LWS(header, len) \
((len) > 0 && (header[0] == ' ' || header[0] == '\t')) ((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 * 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 * 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->method, request->path,
request->host, portbuff, request->host, portbuff,
connptr->upstream_proxy->ua.authstr); 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 { } else {
return write_message (connptr->server_fd, return write_message (connptr->server_fd,
"%s %s HTTP/1.0\r\n" "%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 int remove_connection_headers (hashmap_t hashofheaders)
{ {
static const char *headers[] = { char **headers;
"connection",
"proxy-connection"
};
char *data; char *data;
char *ptr; char *ptr;
ssize_t len; ssize_t len;
int i; int i;
headers = connection_headers_default;
if (config.allowupgrade) {
headers = connection_headers_allow_upgrade;
}
for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i) { for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i) {
/* Look for the connection header. If it's not found, return. */ /* Look for the connection header. If it's not found, return. */
len = len =
@ -850,20 +883,19 @@ done:
static int static int
process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders) process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders)
{ {
static const char *skipheaders[] = { char **skipheaders;
"host",
"keep-alive",
"proxy-connection",
"te",
"trailers",
"upgrade"
};
int i; int i;
hashmap_iter iter; hashmap_iter iter;
int ret = 0; int ret = 0;
char *data, *header; 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 * 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 * a stats request, or if this was a CONNECT method (unless upstream