reverse proxy: do not assume TLS for non-standard ports

This commit is contained in:
Maximilian Hils 2021-01-01 16:51:37 +01:00
parent c32c0322a1
commit 0bbb5ca345
3 changed files with 28 additions and 18 deletions

View File

@ -41,6 +41,8 @@ If you depend on these features, please raise your voice in
* Use pyca/cryptography to generate certificates, not pyOpenSSL (@mhils)
* Remove the legacy protocol stack (@Kriechi)
* Remove all deprecated pathod and pathoc tools and modules (@Kriechi)
* In reverse proxy mode, mitmproxy now does not assume TLS if no scheme
is given but a custom port is provided (@mhils)
* --- TODO: add new PRs above this line ---
* ... and various other fixes, documentation improvements, dependency version bumps, etc.

View File

@ -1,16 +1,16 @@
"""
Parse scheme, host and port from a string.
"""
import functools
import re
import typing
from typing import Tuple
from typing import Tuple, Literal, NamedTuple
from mitmproxy.net import check
class ServerSpec(typing.NamedTuple):
scheme: str
address: typing.Tuple[str, int]
class ServerSpec(NamedTuple):
scheme: Literal["http", "https"]
address: Tuple[str, int]
server_spec_re = re.compile(
@ -26,6 +26,7 @@ server_spec_re = re.compile(
)
@functools.lru_cache
def parse(server_spec: str) -> ServerSpec:
"""
Parses a server mode specification, e.g.:
@ -41,8 +42,10 @@ def parse(server_spec: str) -> ServerSpec:
if not m:
raise ValueError(f"Invalid server specification: {server_spec}")
# defaulting to https/port 443 may annoy some folks, but it's secure-by-default.
scheme = m.group("scheme") or "https"
if m.group("scheme"):
scheme = m.group("scheme")
else:
scheme = "https" if m.group("port") in ("443", None) else "http"
if scheme not in ("http", "https"):
raise ValueError(f"Invalid server scheme: {scheme}")
@ -50,7 +53,7 @@ def parse(server_spec: str) -> ServerSpec:
# IPv6 brackets
if host.startswith("[") and host.endswith("]"):
host = host[1:-1]
if not check.is_valid_host(host.encode("idna")):
if not check.is_valid_host(host):
raise ValueError(f"Invalid hostname: {host}")
if m.group("port"):
@ -63,7 +66,7 @@ def parse(server_spec: str) -> ServerSpec:
if not check.is_valid_port(port):
raise ValueError(f"Invalid port: {port}")
return ServerSpec(scheme, (host, port))
return ServerSpec(scheme, (host, port)) # type: ignore
def parse_with_mode(mode: str) -> Tuple[str, ServerSpec]:

View File

@ -3,16 +3,21 @@ import pytest
from mitmproxy.net import server_spec
def test_parse():
assert server_spec.parse("example.com") == ("https", ("example.com", 443))
assert server_spec.parse("example.com") == ("https", ("example.com", 443))
assert server_spec.parse("http://example.com") == ("http", ("example.com", 80))
assert server_spec.parse("http://127.0.0.1") == ("http", ("127.0.0.1", 80))
assert server_spec.parse("http://[::1]") == ("http", ("::1", 80))
assert server_spec.parse("http://[::1]/") == ("http", ("::1", 80))
assert server_spec.parse("https://[::1]/") == ("https", ("::1", 443))
assert server_spec.parse("http://[::1]:8080") == ("http", ("::1", 8080))
@pytest.mark.parametrize("spec,out", [
("example.com", ("https", ("example.com", 443))),
("http://example.com", ("http", ("example.com", 80))),
("smtp.example.com:25", ("http", ("smtp.example.com", 25))),
("http://127.0.0.1", ("http", ("127.0.0.1", 80))),
("http://[::1]", ("http", ("::1", 80))),
("http://[::1]/", ("http", ("::1", 80))),
("https://[::1]/", ("https", ("::1", 443))),
("http://[::1]:8080", ("http", ("::1", 8080))),
])
def test_parse(spec, out):
assert server_spec.parse(spec) == out
def test_parse_err():
with pytest.raises(ValueError, match="Invalid server specification"):
server_spec.parse(":")