diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py index 783a2c947..24cf2270a 100644 --- a/mitmproxy/addons/__init__.py +++ b/mitmproxy/addons/__init__.py @@ -1,3 +1,4 @@ +from mitmproxy.addons import allowremote from mitmproxy.addons import anticache from mitmproxy.addons import anticomp from mitmproxy.addons import check_alpn @@ -25,6 +26,7 @@ def default_addons(): return [ core.Core(), core_option_validation.CoreOptionValidation(), + allowremote.AllowRemote(), anticache.AntiCache(), anticomp.AntiComp(), check_alpn.CheckALPN(), diff --git a/mitmproxy/addons/allowremote.py b/mitmproxy/addons/allowremote.py new file mode 100644 index 000000000..f1d3d8fbd --- /dev/null +++ b/mitmproxy/addons/allowremote.py @@ -0,0 +1,29 @@ +import ipaddress +from mitmproxy import ctx + + +class AllowRemote: + def load(self, loader): + loader.add_option( + "allow_remote", bool, False, + """ + Allow remote clients to connect to proxy. If set to false, + client will not be able to connect to proxy unless it is on the same network + or the proxyauth option is set + """ + ) + + def clientconnect(self, layer): + address = layer.client_conn.address + + accept_connection = ( + ctx.options.allow_remote or + ipaddress.ip_address(address[0]).is_private or + ctx.options.proxyauth is not None + ) + + if not accept_connection: + layer.reply.kill() + ctx.log.warn("Client connection was killed because allow_remote option is set to false, " + "client IP was not a private IP and proxyauth was not set.\n" + "To allow remote connections set allow_remote option to true or set proxyauth option.") diff --git a/test/mitmproxy/addons/test_allowremote.py b/test/mitmproxy/addons/test_allowremote.py new file mode 100644 index 000000000..9fc715251 --- /dev/null +++ b/test/mitmproxy/addons/test_allowremote.py @@ -0,0 +1,38 @@ +from unittest import mock +import pytest + +from mitmproxy.addons import allowremote +from mitmproxy.test import taddons + + +@pytest.mark.parametrize("allow_remote, ip, should_be_killed", [ + (True, "192.168.1.3", False), + (True, "122.176.243.101", False), + (False, "192.168.1.3", False), + (False, "122.176.243.101", True), + (True, "::ffff:1:2", False), + (True, "fe80::", False), + (True, "2001:4860:4860::8888", False), + (False, "::ffff:1:2", False), + (False, "fe80::", False), + (False, "2001:4860:4860::8888", True), +]) +def test_allowremote(allow_remote, ip, should_be_killed): + ar = allowremote.AllowRemote() + with taddons.context() as tctx: + tctx.master.addons.register(ar) + tctx.options.allow_remote = allow_remote + + with mock.patch('mitmproxy.proxy.protocol.base.Layer') as layer: + layer.client_conn.address = (ip, 12345) + + ar.clientconnect(layer) + if should_be_killed: + assert tctx.master.has_log("Client connection was killed", "warn") + else: + assert tctx.master.logs == [] + tctx.master.clear() + + tctx.options.proxyauth = "any" + ar.clientconnect(layer) + assert tctx.master.logs == []