Merge pull request #2053 from krsoninikhil/on-issues

Adds --keep-host-header option (#2039)
This commit is contained in:
Maximilian Hils 2017-03-04 11:42:44 +01:00 committed by GitHub
commit 78fd5a9dad
7 changed files with 35 additions and 13 deletions

View File

@ -31,7 +31,8 @@ Host Header
In reverse proxy mode, mitmproxy automatically rewrites the Host header to match the In reverse proxy mode, mitmproxy automatically rewrites the Host header to match the
upstream server. This allows mitmproxy to easily connect to existing endpoints on the upstream server. This allows mitmproxy to easily connect to existing endpoints on the
open web (e.g. ``mitmproxy -R https://example.com``). open web (e.g. ``mitmproxy -R https://example.com``). You can disable this behaviour
by passing ``--keep-host-header`` on the console.
However, keep in mind that absolute URLs within the returned document or HTTP redirects will However, keep in mind that absolute URLs within the returned document or HTTP redirects will
NOT be rewritten by mitmproxy. This means that if you click on a link for "http://example.com" NOT be rewritten by mitmproxy. This means that if you click on a link for "http://example.com"

View File

@ -13,6 +13,8 @@ Usage:
-s dns_spoofing.py -s dns_spoofing.py
# Used as the target location if neither SNI nor host header are present. # Used as the target location if neither SNI nor host header are present.
-R http://example.com/ -R http://example.com/
# To avoid auto rewriting of host header by the reverse proxy target.
--keep-host-header
mitmdump mitmdump
-p 80 -p 80
-R http://localhost:443/ -R http://localhost:443/
@ -29,13 +31,6 @@ parse_host_header = re.compile(r"^(?P<host>[^:]+|\[.+\])(?::(?P<port>\d+))?$")
class Rerouter: class Rerouter:
def requestheaders(self, flow):
"""
The original host header is retrieved early
before flow.request is replaced by mitmproxy new outgoing request
"""
flow.metadata["original_host"] = flow.request.host_header
def request(self, flow): def request(self, flow):
if flow.client_conn.ssl_established: if flow.client_conn.ssl_established:
flow.request.scheme = "https" flow.request.scheme = "https"
@ -46,7 +41,7 @@ class Rerouter:
sni = None sni = None
port = 80 port = 80
host_header = flow.metadata["original_host"] host_header = flow.request.host_header
m = parse_host_header.match(host_header) m = parse_host_header.match(host_header)
if m: if m:
host_header = m.group("host").strip("[]") host_header = m.group("host").strip("[]")

View File

@ -72,6 +72,7 @@ class Options(optmanager.OptManager):
upstream_bind_address: str = "", upstream_bind_address: str = "",
mode: str = "regular", mode: str = "regular",
no_upstream_cert: bool = False, no_upstream_cert: bool = False,
keep_host_header: bool = False,
http2: bool = True, http2: bool = True,
http2_priority: bool = False, http2_priority: bool = False,
@ -162,6 +163,7 @@ class Options(optmanager.OptManager):
self.upstream_bind_address = upstream_bind_address self.upstream_bind_address = upstream_bind_address
self.mode = mode self.mode = mode
self.no_upstream_cert = no_upstream_cert self.no_upstream_cert = no_upstream_cert
self.keep_host_header = keep_host_header
self.http2 = http2 self.http2 = http2
self.http2_priority = http2_priority self.http2_priority = http2_priority

View File

@ -288,7 +288,7 @@ class HttpLayer(base.Layer):
request.first_line_format = "relative" request.first_line_format = "relative"
# update host header in reverse proxy mode # update host header in reverse proxy mode
if self.config.options.mode == "reverse": if self.config.options.mode == "reverse" and not self.config.options.keep_host_header:
f.request.host_header = self.config.upstream_server.address[0] f.request.host_header = self.config.upstream_server.address[0]
# Determine .scheme, .host and .port attributes for inline scripts. For # Determine .scheme, .host and .port attributes for inline scripts. For

View File

@ -112,6 +112,7 @@ def get_common_options(args):
replacements=args.replacements, replacements=args.replacements,
replacement_files=args.replacement_files, replacement_files=args.replacement_files,
setheaders=args.setheaders, setheaders=args.setheaders,
keep_host_header=args.keep_host_header,
server_replay=args.server_replay, server_replay=args.server_replay,
scripts=args.scripts, scripts=args.scripts,
stickycookie=stickycookie, stickycookie=stickycookie,
@ -387,6 +388,11 @@ def proxy_options(parser):
action="store", type=str, dest="upstream_bind_address", action="store", type=str, dest="upstream_bind_address",
help="Address to bind upstream requests to (defaults to none)" help="Address to bind upstream requests to (defaults to none)"
) )
group.add_argument(
"--keep-host-header",
action="store_true", dest="keep_host_header",
help="Reverse Proxy: Keep the original host header instead of rewriting it to the reverse proxy target."
)
def proxy_ssl_options(parser): def proxy_ssl_options(parser):

View File

@ -481,6 +481,26 @@ class TestHTTPSNoCommonName(tservers.HTTPProxyTest):
class TestReverse(tservers.ReverseProxyTest, CommonMixin, TcpMixin): class TestReverse(tservers.ReverseProxyTest, CommonMixin, TcpMixin):
reverse = True reverse = True
def test_host_header(self):
self.config.options.keep_host_header = True
p = self.pathoc()
with p.connect():
resp = p.request("get:/p/200:h'Host'='example.com'")
assert resp.status_code == 200
req = self.master.state.flows[0].request
assert req.host_header == "example.com"
def test_overridden_host_header(self):
self.config.options.keep_host_header = False # default value
p = self.pathoc()
with p.connect():
resp = p.request("get:/p/200:h'Host'='example.com'")
assert resp.status_code == 200
req = self.master.state.flows[0].request
assert req.host_header == "127.0.0.1"
class TestReverseSSL(tservers.ReverseProxyTest, CommonMixin, TcpMixin): class TestReverseSSL(tservers.ReverseProxyTest, CommonMixin, TcpMixin):
reverse = True reverse = True

View File

@ -114,13 +114,11 @@ class TestScripts(tservers.MasterTest):
# Rewrite by reverse proxy mode # Rewrite by reverse proxy mode
f.request.scheme = "https" f.request.scheme = "https"
f.request.host = "mitmproxy.org"
f.request.port = 443 f.request.port = 443
m.request(f) m.request(f)
assert f.request.scheme == "http" assert f.request.scheme == "http"
assert f.request.host == original_host
assert f.request.port == 80 assert f.request.port == 80
assert f.request.headers["Host"] == original_host assert f.request.headers["Host"] == original_host