aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/change_upstream_proxy.py47
-rw-r--r--examples/dns_spoofing.py47
-rw-r--r--examples/ignore_websocket.py37
-rw-r--r--examples/stub.py13
4 files changed, 66 insertions, 78 deletions
diff --git a/examples/change_upstream_proxy.py b/examples/change_upstream_proxy.py
index 7782dd84..8f58e1f2 100644
--- a/examples/change_upstream_proxy.py
+++ b/examples/change_upstream_proxy.py
@@ -1,29 +1,34 @@
# This scripts demonstrates how mitmproxy can switch to a second/different upstream proxy
# in upstream proxy mode.
#
-# Usage: mitmdump -U http://default-upstream-proxy.local:8080/ -s
-# "change_upstream_proxy.py host"
-from libmproxy.protocol.http import send_connect_request
-
-alternative_upstream_proxy = ("localhost", 8082)
+# Usage: mitmdump -U http://default-upstream-proxy.local:8080/ -s change_upstream_proxy.py
+#
+# If you want to change the target server, you should modify flow.request.host and flow.request.port
+# flow.live.set_server should only be used by inline scripts to change the upstream proxy.
-def should_redirect(flow):
- return flow.request.host == "example.com"
+def proxy_address(flow):
+ # Poor man's loadbalancing: route every second domain through the alternative proxy.
+ if hash(flow.request.host) % 2 == 1:
+ return ("localhost", 8082)
+ else:
+ return ("localhost", 8081)
def request(context, flow):
- if flow.live and should_redirect(flow):
-
- # If you want to change the target server, you should modify flow.request.host and flow.request.port
- # flow.live.change_server should only be used by inline scripts to change the upstream proxy,
- # unless you are sure that you know what you are doing.
- server_changed = flow.live.change_server(
- alternative_upstream_proxy,
- persistent_change=True)
- if flow.request.scheme == "https" and server_changed:
- send_connect_request(
- flow.live.c.server_conn,
- flow.request.host,
- flow.request.port)
- flow.live.c.establish_ssl(server=True)
+ if flow.request.method == "CONNECT":
+ # If the decision is done by domain, one could also modify the server address here.
+ # We do it after CONNECT here to have the request data available as well.
+ return
+ address = proxy_address(flow)
+ if flow.live:
+ if flow.request.scheme == "http":
+ # For a normal HTTP request, we just change the proxy server and we're done!
+ if address != flow.live.server_conn.address:
+ flow.live.set_server(address, depth=1)
+ else:
+ # If we have CONNECTed (and thereby established "destination state"), the story is
+ # a bit more complex. Now we don't want to change the top level address (which is
+ # the connect destination) but the address below that. (Notice the `.via` and depth=2).
+ if address != flow.live.server_conn.via.address:
+ flow.live.set_server(address, depth=2)
diff --git a/examples/dns_spoofing.py b/examples/dns_spoofing.py
index dddf172c..98495d45 100644
--- a/examples/dns_spoofing.py
+++ b/examples/dns_spoofing.py
@@ -9,29 +9,42 @@ Using transparent mode is the better option most of the time.
Usage:
mitmproxy
- -p 80
- -R http://example.com/ // Used as the target location if no Host header is present
- mitmproxy
-p 443
- -R https://example.com/ // Used as the target locaction if neither SNI nor host header are present.
+ -s dns_spoofing.py
+ # Used as the target location if neither SNI nor host header are present.
+ -R http://example.com/
+ mitmdump
+ -p 80
+ -R http://localhost:443/
-mitmproxy will always connect to the default location first, so it must be reachable.
-As a workaround, you can spawn an arbitrary HTTP server and use that for both endpoints, e.g.
-mitmproxy -p 80 -R http://localhost:8000
-mitmproxy -p 443 -R https2http://localhost:8000
+ (Setting up a single proxy instance and using iptables to redirect to it
+ works as well)
"""
+import re
+
+
+# This regex extracts splits the host header into host and port.
+# Handles the edge case of IPv6 addresses containing colons.
+# https://bugzilla.mozilla.org/show_bug.cgi?id=45891
+parse_host_header = re.compile(r"^(?P<host>[^:]+|\[.+\])(?::(?P<port>\d+))?$")
def request(context, flow):
if flow.client_conn.ssl_established:
- # TLS SNI or Host header
- flow.request.host = flow.client_conn.connection.get_servername(
- ) or flow.request.pretty_host(hostheader=True)
-
- # If you use a https2http location as default destination, these
- # attributes need to be corrected as well:
- flow.request.port = 443
flow.request.scheme = "https"
+ sni = flow.client_conn.connection.get_servername()
+ port = 443
else:
- # Host header
- flow.request.host = flow.request.pretty_host(hostheader=True)
+ flow.request.scheme = "http"
+ sni = None
+ port = 80
+
+ host_header = flow.request.pretty_host(hostheader=True)
+ m = parse_host_header.match(host_header)
+ if m:
+ host_header = m.group("host").strip("[]")
+ if m.group("port"):
+ port = int(m.group("port"))
+
+ flow.request.host = sni or host_header
+ flow.request.port = port \ No newline at end of file
diff --git a/examples/ignore_websocket.py b/examples/ignore_websocket.py
deleted file mode 100644
index 57e11d5b..00000000
--- a/examples/ignore_websocket.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This script makes mitmproxy switch to passthrough mode for all HTTP
-# responses with "Connection: Upgrade" header. This is useful to make
-# WebSockets work in untrusted environments.
-#
-# Note: Chrome (and possibly other browsers), when explicitly configured
-# to use a proxy (i.e. mitmproxy's regular mode), send a CONNECT request
-# to the proxy before they initiate the websocket connection.
-# To make WebSockets work in these cases, supply
-# `--ignore :80$` as an additional parameter.
-# (see http://mitmproxy.org/doc/features/passthrough.html)
-
-import netlib.http.semantics
-
-from libmproxy.protocol.tcp import TCPHandler
-from libmproxy.protocol import KILL
-from libmproxy.script import concurrent
-
-
-def start(context, argv):
- netlib.http.semantics.Request._headers_to_strip_off.remove("Connection")
- netlib.http.semantics.Request._headers_to_strip_off.remove("Upgrade")
-
-
-def done(context):
- netlib.http.semantics.Request._headers_to_strip_off.append("Connection")
- netlib.http.semantics.Request._headers_to_strip_off.append("Upgrade")
-
-
-@concurrent
-def response(context, flow):
- value = flow.response.headers.get_first("Connection", None)
- if value and value.upper() == "UPGRADE":
- # We need to send the response manually now...
- flow.client_conn.send(flow.client_conn.protocol.assemble(flow.response))
- # ...and then delegate to tcp passthrough.
- TCPHandler(flow.live.c, log=False).handle_messages()
- flow.reply(KILL)
diff --git a/examples/stub.py b/examples/stub.py
index d5502a47..bd3e7cd0 100644
--- a/examples/stub.py
+++ b/examples/stub.py
@@ -10,7 +10,7 @@ def start(context, argv):
context.log("start")
-def clientconnect(context, conn_handler):
+def clientconnect(context, root_layer):
"""
Called when a client initiates a connection to the proxy. Note that a
connection can correspond to multiple HTTP requests
@@ -18,7 +18,7 @@ def clientconnect(context, conn_handler):
context.log("clientconnect")
-def serverconnect(context, conn_handler):
+def serverconnect(context, server_connection):
"""
Called when the proxy initiates a connection to the target server. Note that a
connection can correspond to multiple HTTP requests
@@ -58,7 +58,14 @@ def error(context, flow):
context.log("error")
-def clientdisconnect(context, conn_handler):
+def serverdisconnect(context, server_connection):
+ """
+ Called when the proxy closes the connection to the target server.
+ """
+ context.log("serverdisconnect")
+
+
+def clientdisconnect(context, root_layer):
"""
Called when a client disconnects from the proxy.
"""