Permalink
Browse files

fix the correct remote address

The remote address should return the direct client addr not a forwarded
header.

This is a breaking change. The main problem with such changes is the way
the application or framework will handle the URL completion. Indeed most
of them are only expecting a TCP socket.

fix #633
  • Loading branch information...
benoitc committed Dec 27, 2013
1 parent 776f315 commit c4873681299212d6082cd9902740eef18c2f14f1
Showing with 14 additions and 52 deletions.
  1. +1 −14 gunicorn/config.py
  2. +13 −38 gunicorn/http/wsgi.py
View
@@ -914,19 +914,6 @@ class SecureSchemeHeader(Setting):
"""
class XForwardedFor(Setting):
name = "x_forwarded_for_header"
section = "Server Mechanics"
cli = ["--x-forwarded-for-hdr"]
meta = "STRING"
validator = validate_string
default = 'X-FORWARDED-FOR'
desc = """\
Set the X-Forwarded-For header that identify the originating IP
address of the client connection to gunicorn via a proxy.
"""
class ForwardedAllowIPS(Setting):
name = "forwarded_allow_ips"
section = "Server Mechanics"
@@ -935,7 +922,7 @@ class ForwardedAllowIPS(Setting):
validator = validate_string_to_list
default = "127.0.0.1"
desc = """\
Front-end's IPs from which allowed to handle X-Forwarded-* headers.
Front-end's IPs from which allowed to handle set secure headers.
(comma separate).
Set to "*" to disable checking of Front-end IPs (useful for setups
View
@@ -80,29 +80,22 @@ def create(req, sock, client, server, cfg):
environ = default_environ(req, sock, cfg)
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
# may not qualify the remote addr:
# http://www.ietf.org/rfc/rfc3875
forward = client or "127.0.0.1"
url_scheme = "https" if cfg.is_ssl else "http"
script_name = os.environ.get("SCRIPT_NAME", "")
secure_headers = cfg.secure_scheme_headers
x_forwarded_for_header = cfg.x_forwarded_for_header
if '*' not in cfg.forwarded_allow_ips and client\
and client[0] not in cfg.forwarded_allow_ips:
x_forwarded_for_header = None
secure_headers = {}
if client and not isinstance(client, string_types):
if ('*' not in cfg.forwarded_allow_ips
and client[0] not in cfg.forwarded_allow_ips):
secure_headers = {}
for hdr_name, hdr_value in req.headers:
if hdr_name == "EXPECT":
# handle expect
if hdr_value.lower() == "100-continue":
sock.send(b"HTTP/1.1 100 Continue\r\n\r\n")
elif x_forwarded_for_header and hdr_name == x_forwarded_for_header:
forward = hdr_value
elif secure_headers and (hdr_name.upper() in secure_headers and
hdr_value == secure_headers[hdr_name.upper()]):
elif secure_headers and (hdr_name in secure_headers and
hdr_value == secure_headers[hdr_name]):
url_scheme = "https"
elif hdr_name == "HOST":
server = hdr_value
@@ -122,32 +115,14 @@ def create(req, sock, client, server, cfg):
environ['wsgi.url_scheme'] = url_scheme
if isinstance(forward, string_types):
# we only took the last one
# http://en.wikipedia.org/wiki/X-Forwarded-For
if forward.find(",") >= 0:
forward = forward.rsplit(",", 1)[1].strip()
# find host and port on ipv6 address
if '[' in forward and ']' in forward:
host = forward.split(']')[0][1:].lower()
elif ":" in forward and forward.count(":") == 1:
host = forward.split(":")[0].lower()
else:
host = forward
forward = forward.split(']')[-1]
if ":" in forward and forward.count(":") == 1:
port = forward.split(':', 1)[1]
else:
port = 80
remote = (host, port)
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
# may not qualify the remote addr:
# http://www.ietf.org/rfc/rfc3875
if isinstance(client, string_types):
environ['REMOTE_ADDR'] = client
else:
remote = forward
environ['REMOTE_ADDR'] = remote[0]
environ['REMOTE_PORT'] = str(remote[1])
environ['REMOTE_ADDR'] = client[0]
environ['REMOTE_PORT'] = str(client[1])
if isinstance(server, string_types):
server = server.split(":")

0 comments on commit c487368

Please sign in to comment.