def test_upstream_https(tctx): """ Test mitmproxy in HTTPS upstream mode with another mitmproxy instance upstream. In other words: mitmdump --mode upstream:https://localhost:8081 --ssl-insecure mitmdump -p 8081 curl -x localhost:8080 -k http://example.com """ tctx1 = Context(Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), copy.deepcopy(tctx.options)) tctx1.options.mode = "upstream:https://example.mitmproxy.org:8081" tctx2 = Context(Client(("client", 4321), ("127.0.0.1", 8080), 1605699329), copy.deepcopy(tctx.options)) assert tctx2.options.mode == "regular" del tctx proxy1 = Playbook(modes.HttpProxy(tctx1), hooks=False) proxy2 = Playbook(modes.HttpProxy(tctx2), hooks=False) upstream = Placeholder(Server) server = Placeholder(Server) clienthello = Placeholder(bytes) serverhello = Placeholder(bytes) request = Placeholder(bytes) tls_finished = Placeholder(bytes) response = Placeholder(bytes) assert ( proxy1 >> DataReceived( tctx1.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n") << NextLayerHook(Placeholder(NextLayer)) >> reply_next_layer(lambda ctx: http.HttpLayer(ctx, HTTPMode.upstream)) << OpenConnection(upstream) >> reply(None) << TlsStartServerHook( Placeholder()) >> reply_tls_start_server(alpn=b"http/1.1") << SendData(upstream, clienthello)) assert upstream().address == ("example.mitmproxy.org", 8081) assert upstream().sni == "example.mitmproxy.org" assert (proxy2 >> DataReceived( tctx2.client, clienthello()) << NextLayerHook(Placeholder(NextLayer)) >> reply_next_layer(ClientTLSLayer) << TlsStartClientHook( Placeholder()) >> reply_tls_start_client(alpn=b"http/1.1") << SendData(tctx2.client, serverhello)) assert (proxy1 >> DataReceived(upstream, serverhello()) << SendData( upstream, request)) assert (proxy2 >> DataReceived(tctx2.client, request()) << SendData( tctx2.client, tls_finished) << NextLayerHook(Placeholder(NextLayer)) >> reply_next_layer(lambda ctx: http.HttpLayer(ctx, HTTPMode.regular)) << OpenConnection(server) >> reply(None) << SendData( server, b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n') >> DataReceived(server, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << SendData(tctx2.client, response)) assert server().address == ("example.com", 80) assert (proxy1 >> DataReceived( upstream, tls_finished() + response()) << SendData( tctx1.client, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"))
def test_reverse_proxy(tctx, keep_host_header): """Test mitmproxy in reverse proxy mode. - make sure that we connect to the right host - make sure that we respect keep_host_header - make sure that we include non-standard ports in the host header (#4280) """ server = Placeholder(Server) tctx.options.mode = "reverse:http://localhost:8000" tctx.options.connection_strategy = "lazy" tctx.options.keep_host_header = keep_host_header assert ( Playbook(modes.ReverseProxy(tctx), hooks=False) >> DataReceived( tctx.client, b"GET /foo HTTP/1.1\r\n" b"Host: 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\n" b"Host: " + (b"example.com" if keep_host_header else b"localhost:8000") + b"\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 == ("localhost", 8000)
def test_transparent_tcp(tctx: Context, monkeypatch, connection_strategy): monkeypatch.setattr(platform, "original_addr", lambda sock: ("address", 22)) flow = Placeholder(TCPFlow) tctx.options.connection_strategy = connection_strategy sock = object() playbook = Playbook(modes.TransparentProxy(tctx)) ( playbook << GetSocket(tctx.client) >> reply(sock) ) if connection_strategy == "lazy": assert playbook else: assert ( playbook << OpenConnection(tctx.server) >> reply(None) >> DataReceived(tctx.server, b"hello") << NextLayerHook(Placeholder(NextLayer)) >> reply_next_layer(tcp.TCPLayer) << TcpStartHook(flow) >> reply() << TcpMessageHook(flow) >> reply() << SendData(tctx.client, b"hello") ) assert flow().messages[0].content == b"hello" assert not flow().messages[0].from_client assert tctx.server.address == ("address", 22)
def test_socks5_success(address: str, packed: bytes, tctx: Context): tctx.options.connection_strategy = "eager" playbook = Playbook(modes.Socks5Proxy(tctx)) server = Placeholder(Server) nextlayer = Placeholder(NextLayer) assert (playbook >> DataReceived(tctx.client, CLIENT_HELLO) << SendData( tctx.client, SERVER_HELLO) >> DataReceived( tctx.client, b"\x05\x01\x00" + packed + b"\x12\x34applicationdata") << OpenConnection(server) >> reply(None) << SendData( tctx.client, b"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00") << NextLayerHook(nextlayer)) assert server().address == (address, 0x1234) assert nextlayer().data_client() == b"applicationdata"
def test_reverse_proxy_tcp_over_tls(tctx: Context, monkeypatch, patch, connection_strategy): """ Test client --TCP-- mitmproxy --TCP over TLS-- server reverse proxying. """ if patch: monkeypatch.setattr(tls, "ServerTLSLayer", tls.MockTLSLayer) flow = Placeholder(TCPFlow) data = Placeholder(bytes) tctx.options.mode = "reverse:https://localhost:8000" tctx.options.connection_strategy = connection_strategy playbook = Playbook(modes.ReverseProxy(tctx)) if connection_strategy == "eager": (playbook << OpenConnection(tctx.server) >> DataReceived( tctx.client, b"\x01\x02\x03") >> reply( None, to=OpenConnection(tctx.server))) else: (playbook >> DataReceived(tctx.client, b"\x01\x02\x03")) if patch: (playbook << NextLayerHook(Placeholder(NextLayer)) >> reply_next_layer( tcp.TCPLayer) << TcpStartHook(flow) >> reply()) if connection_strategy == "lazy": (playbook << OpenConnection(tctx.server) >> reply(None)) assert (playbook << TcpMessageHook(flow) >> reply() << SendData( tctx.server, data)) assert data() == b"\x01\x02\x03" else: if connection_strategy == "lazy": (playbook << NextLayerHook(Placeholder(NextLayer)) >> reply_next_layer(tcp.TCPLayer) << TcpStartHook(flow) >> reply() << OpenConnection(tctx.server) >> reply(None)) assert (playbook << TlsStartHook(Placeholder()) >> reply_tls_start() << SendData(tctx.server, data)) assert tls.parse_client_hello(data()).sni == "localhost"
def test_socks5_auth_success(client_greeting: bytes, server_choice: bytes, client_auth: bytes, server_resp: bytes, address: bytes, packed: bytes, tctx: Context): ProxyAuth().load(tctx.options) tctx.options.proxyauth = "user:password" server = Placeholder(Server) nextlayer = Placeholder(NextLayer) playbook = (Playbook(modes.Socks5Proxy(tctx), logs=True) >> DataReceived( tctx.client, client_greeting) << SendData(tctx.client, server_choice) >> DataReceived(tctx.client, client_auth) << modes.Socks5AuthHook(Placeholder(modes.Socks5AuthData)) >> reply(side_effect=_valid_socks_auth) << SendData( tctx.client, server_resp) >> DataReceived( tctx.client, b"\x05\x01\x00" + packed + b"\x12\x34applicationdata") << OpenConnection(server) >> reply(None) << SendData( tctx.client, b"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00") << NextLayerHook(nextlayer)) assert playbook assert server().address == (address, 0x1234) assert nextlayer().data_client() == b"applicationdata"