Bracket IPv6 literals in Host headers and URLs by RitiGrover · Pull Request #8484 · mitmproxy/mitmproxy · GitHub
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
6 changes: 6 additions & 0 deletions mitmproxy/net/http/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ def hostport(scheme: AnyStr, host: AnyStr, port: int) -> AnyStr:
"""
Returns the host component, with a port specification if needed.
"""
# IPv6 literals need brackets to tell their colons apart from the port.
if isinstance(host, bytes) and b":" in host and not host.startswith(b"["):
host = b"[%s]" % host
elif isinstance(host, str) and ":" in host and not host.startswith("["):
host = f"[{host}]"

if default_port(scheme) == port:
return host
else:
Expand Down
16 changes: 16 additions & 0 deletions test/mitmproxy/net/http/test_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,22 @@ def test_hostport():
assert url.hostport(b"https", b"foo.com", 8080) == b"foo.com:8080"


def test_hostport_ipv6():
assert url.hostport("http", "::1", 8080) == "[::1]:8080"
assert url.hostport("http", "::1", 80) == "[::1]"
assert url.hostport(b"https", b"2001:db8::1", 8443) == b"[2001:db8::1]:8443"
assert url.hostport(b"https", b"2001:db8::1", 443) == b"[2001:db8::1]"
assert url.hostport("http", "[::1]", 8080) == "[::1]:8080"


def test_unparse_ipv6():
assert url.unparse("http", "::1", 8080, "/a") == "http://[::1]:8080/a"
assert (
url.unparse(b"https", b"2001:db8::1", 443, b"/a") == b"https://[2001:db8::1]/a"
)
assert url.unparse(*url.parse("http://[::1]:8080/a")) == b"http://[::1]:8080/a"


def test_default_port():
assert url.default_port("http") == 80
assert url.default_port(b"https") == 443
Expand Down
19 changes: 19 additions & 0 deletions test/mitmproxy/proxy/layers/test_modes.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ def test_reverse_proxy(tctx, keep_host_header):
assert server().address == ("localhost", 8000)


def test_reverse_proxy_ipv6(tctx):
"""Test that the host header of an IPv6 backend is bracketed."""
server = Placeholder(Server)
tctx.client.proxy_mode = ProxyMode.parse("reverse:http://[::1]:8000")
tctx.options.connection_strategy = "lazy"
assert (
Playbook(modes.ReverseProxy(tctx), hooks=False)
>> DataReceived(tctx.client, b"GET /foo HTTP/1.1\r\nHost: example.com\r\n\r\n")
<< NextLayerHook(Placeholder(NextLayer))
>> reply_next_layer(lambda ctx: http.HttpLayer(ctx, HTTPMode.transparent))
<< OpenConnection(server)
>> reply(None)
<< SendData(server, b"GET /foo HTTP/1.1\r\nHost: [::1]:8000\r\n\r\n")
>> DataReceived(server, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")
<< SendData(tctx.client, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")
)
assert server().address == ("::1", 8000)


def test_reverse_dns(tctx):
tctx.client.transport_protocol = "udp"
tctx.server.transport_protocol = "udp"
Expand Down
18 changes: 18 additions & 0 deletions test/mitmproxy/test_http.py
Loading