Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions etc/tinyproxy.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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.

Expand Down
8 changes: 8 additions & 0 deletions src/conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
58 changes: 45 additions & 13 deletions src/reqs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -850,20 +883,19 @@ write_via_header (int fd, hashmap_t hashofheaders,
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
Expand Down