Skip to content
Open
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
14 changes: 14 additions & 0 deletions docs/man5/tinyproxy.conf.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,20 @@ put the outermost URL here (the address which the end user
types into his/her browser). If this option is not set then
no rewriting of redirects occurs.

=item B<ClientUsesProxyProtocol>

Set this option to `Yes` when the tinyproxy's client is a proxy that
uses the PROXY protocol, which inserts a line before the HTTP request
line to indicate the IP address of the real client. Only version 1
(human-readable header format) is supported.

For instance, when using stunnel in front of tinyproxy and the
BasicAuth option is used, if the PROXY protocol is used, tinyproxy
will report the actual client IP address in the log instead of the IP
address of the stunnel server, so that the log can be parsed by
tools like fail2ban to ban clients that try to brute force the
authentication.

=back

=head1 BUGS
Expand Down
15 changes: 15 additions & 0 deletions etc/tinyproxy.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,18 @@ ViaProxyName "tinyproxy"
# If not set then no rewriting occurs.
#
#ReverseBaseURL "http://localhost:8888/"

#
# The tinyproxy's client is a proxy that uses the PROXY protocol, which
# inserts a line before the HTTP request line to indicate the IP
# address of the real client. Only version 1 (human-readable header
# format) is supported.
#
# For instance, when using stunnel in front of tinyproxy and the
# BasicAuth option is used, if the PROXY protocol is used, tinyproxy
# will report the actual client IP address in the log instead of the IP
# address of the stunnel server, so that the log can be parsed by
# tools like fail2ban to ban clients that try to brute force the
# authentication.
#
#ClientUsesProxyProtocol Yes
3 changes: 2 additions & 1 deletion src/conf-tokens.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ config_directive_find (register const char *str, register size_t len)
{"basicauth", CD_basicauth},
{"basicauthrealm", CD_basicauthrealm},
{"addheader", CD_addheader},
{"maxrequestsperchild", CD_maxrequestsperchild}
{"maxrequestsperchild", CD_maxrequestsperchild},
{"clientusesproxyprotocol", CD_clientusesproxyprotocol}
};

for(i=0;i<sizeof(wordlist)/sizeof(wordlist[0]);++i) {
Expand Down
1 change: 1 addition & 0 deletions src/conf-tokens.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ reversemagic, CD_reversemagic
reversepath, CD_reversepath
upstream, CD_upstream
loglevel, CD_loglevel
clientusesproxyprotocol, CD_clientusesproxyprotocol
%%

1 change: 1 addition & 0 deletions src/conf-tokens.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ CD_xtinyproxy,
CD_syslog,
CD_bindsame,
CD_disableviaheader,
CD_clientusesproxyprotocol,
CD_port,
CD_maxclients,
CD_maxspareservers,
Expand Down
15 changes: 15 additions & 0 deletions src/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ static HANDLE_FUNC (handle_user);
static HANDLE_FUNC (handle_viaproxyname);
static HANDLE_FUNC (handle_disableviaheader);
static HANDLE_FUNC (handle_xtinyproxy);
static HANDLE_FUNC (handle_clientusesproxyprotocol);

#ifdef UPSTREAM_SUPPORT
static HANDLE_FUNC (handle_upstream);
Expand Down Expand Up @@ -207,6 +208,7 @@ struct {
STDCONF (syslog, BOOL, handle_syslog),
STDCONF (bindsame, BOOL, handle_bindsame),
STDCONF (disableviaheader, BOOL, handle_disableviaheader),
STDCONF (clientusesproxyprotocol, BOOL, handle_clientusesproxyprotocol),
/* integer arguments */
STDCONF (port, INT, handle_port),
STDCONF (maxclients, INT, handle_maxclients),
Expand Down Expand Up @@ -694,6 +696,19 @@ static HANDLE_FUNC (handle_disableviaheader)
return 0;
}

static HANDLE_FUNC (handle_clientusesproxyprotocol)
{
int r = set_bool_arg (&conf->client_uses_proxyproto, line, &match[2]);

if (r) {
return r;
}

if (conf->client_uses_proxyproto)
log_message (LOG_INFO, "Expecting PROXY protocol header.");
return 0;
}

static HANDLE_FUNC (handle_defaulterrorfile)
{
return set_string_arg (&conf->errorpage_undef, line, &match[2]);
Expand Down
2 changes: 2 additions & 0 deletions src/conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ struct config_s {

unsigned int disable_viaheader; /* boolean */

unsigned int client_uses_proxyproto; /* boolean */

/*
* Error page support. Map error numbers to file paths.
*/
Expand Down
73 changes: 73 additions & 0 deletions src/reqs.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,74 @@
#define CHECK_LWS(header, len) \
((len) > 0 && (header[0] == ' ' || header[0] == '\t'))

/*
* Read and parse the PROXY protocol v1 line, and update the client address.
*/
static int read_proxy_line (struct conn_s *connptr, union sockaddr_union* addr)
{
int result = -1;
char *line = NULL;
ssize_t len;
char *src_addr, *end;
sa_family_t af;

len = readline (connptr->client_fd, &line);
if (len <= 0) {
log_message (LOG_ERR,
"read_proxy_line: Client (file descriptor: %d) "
"closed socket before read.", connptr->client_fd);

goto cleanup;
}

/*
* The PROXY line looks like that:
* PROXY <proto> <src_addr> <dst_addr> <src_port> <dst_port>\r\n
* <proto> can be "TCP4" for IPv4/TCP or "TCP6" for IPv6/TCP
* <src_addr> and <dst_addr> are IPv4 or IPv6 addresses
* <src_port> and <dst_port> are TCP port numbers*
*/

/* Expect "PROXY TCP4 " or "PROXY TCP6 " */
if (!(!strncmp (line, "PROXY TCP", 9)
&& (line[9] == '4' || line[9] == '6')
&& line[10] == ' ')) {
bad_syntax:
log_message (LOG_ERR, "Bad PROXY line: %s", line);

goto cleanup;
}

af = line[9] == '6' ? AF_INET6 : AF_INET;

/* Only extract the source address string */
src_addr = line + 11;
end = strchr (src_addr, ' ');
if (end == NULL)
goto bad_syntax;

*end = '\0';

/* Update "addr" with the given address */
memset (addr, 0, sizeof(*addr));
addr->v4.sin_family = af;
if (inet_pton (af, src_addr, SOCKADDR_UNION_ADDRESS(addr)) != 1) {
log_message (LOG_ERR,
"Cannot convert address from PROXY line: %s",
src_addr);

goto cleanup;
}

result = 0;

cleanup:

safefree (line);

return result;
}

/*
* 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 @@ -1598,6 +1666,11 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
char sock_ipaddr[IP_LENGTH];
char peer_ipaddr[IP_LENGTH];

if (config->client_uses_proxyproto && read_proxy_line (connptr, addr)) {
close (fd);
return;
}

getpeer_information (addr, peer_ipaddr, sizeof(peer_ipaddr));

if (config->bindsame)
Expand Down