I would like to control mitmproxy’s behavior by passing it instructions in the proxy URL’s path.
For example, if mitmproxy is running at http://0.0.0.0:8080, a client might toggle debug-level logging by proxying requests through either http://0.0.0.0:8080/debug-mode-on or http://0.0.0.0:8080/debug-mode-off.
Is there a way to detect the proxy server’s URL/path from a mitmproxy script? Or is there a better way for me to go about doing this type of thing?
The most flexible way to do this is to use mitmproxy’s inline scripting ability to host a custom web app from within mitmproxy. Mitmproxy then routes all requests to a magic domain you specify straight to your app, just as if it was served from a server out on the internet. This sounds like deep magic, but is actually very easy, and very, very flexible.
Here’s an example of how to do that using Flask. This exposes 3 URLS on the magic http://settings domain - /debug (to get the debug status), /debug/on (to turn it on), /debug/off (to turn it off). In practice, you’d probably make the URLS that change state use POST not GET, but you get the idea from the example. To see this in action, point your browser at mitmproxy, and visit http://settings/debug.
@cortesi, thank you very much for the response! I believe I’m aiming for something slightly different, but this is awesome.
What approach would you recommend I take to support the following:
# Turn debug mode on for this request to mitmproxy.org
curl --proxy http://0.0.0.0:8080/debug/on https://mitmproxy.org
# Turn debug mode off for this request to mitmproxy.org
curl --proxy http://0.0.0.0:8080/debug/off https://mitmproxy.org
Ah, interesting. I would use a custom header to signal this - say X-Debug, which you can then read inside a script in mitmproxy and delete before forwarding so it’s not externally visible. Would something like this work for you?
curl -H "X-Debug: on" https://mitmproxy.org
To answer your question more directly, proxy URLs don’t have paths - they just define a protocol, address and port (and optionally a user/password). I haven’t tried to pass a path in the proxy URL to curl, but if you did, it should strictly reject it. To put it differently, there’s no “extra” HTTP request during a proxied request where a path on the proxy specification could fit in.
One last idea. Any way subdomains in the proxy URL could be used? For example:
# Turn debug mode on for this request to mitmproxy.org
curl --proxy http://debug-on.example.com:8080 https://mitmproxy.org
# Turn debug mode off for this request to mitmproxy.org
curl --proxy http://debug-off.example.com:8080 https://mitmproxy.org
This would be possible, but we’d have to make some changes to mitmproxy’s core to expose the subdomain and to allow wildcards to be specified for interception. Let me know if you’d like to get your hands dirty and give it a go.
Actually, considering this a bit more closely, a subdomain is probably not the way to go - the proxy domain isn’t passed to mitmproxy by the browser, so doing this would involve complicated futzing with local interfaces to distinguish between the various domains.
Could you maybe describe your use case a bit more, so that I can understand what you’re trying to do? There might be a better way than trying to pass parameters in the proxy specification.
Hi @cortesi, I apologize for the late reply. I went back to your suggestion to pass a custom header, and it’s working very well.
I’m using a mitmproxy script to detect the client from information passed in the headers (thanks to your suggestion), load corresponding authentication details from a vault, and add them to the request headers. I’ll post back if/when I have a usable demo
I am a newbie on python web programming, still don’t know how to integrate mitmproxy with web framework such as flask. I mean is it possible to send a request to start mitmproxy service, another request to stop it, as example below:
app = Flask(__name__)
class MyMaster(flow.FlowMaster):
def run(self):
try:
flow.FlowMaster.run(self)
except KeyboardInterrupt:
self.shutdown()
@controller.handler
def request(self, f):
print("request", f)
@controller.handler
def response(self, f):
print("response", f)
@controller.handler
def error(self, f):
print("error", f)
@controller.handler
def log(self, l):
print("log", l.msg)
opts = options.Options(cadir="~/.mitmproxy/", listen_port=9000)
config = ProxyConfig(opts)
state = flow.State()
server = ProxyServer(config)
m = MyMaster(opts, server, state)
@app.route("/")
def index():
return "hello"
@app.route("/start")
def start():
global m
m.run()
return 'Start!'
def stop():
global m
m.shutdown()
app.run(debug=True)
now I have to divide my application into two parts, the mitmproxy as service be controlled by supervisor, store the data into database, another flask app to display the data from database. actually I want to control the service from the client side.