How to view the proxy server's URL

Hello,

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?

Thanks very much for any help you can give!

Eugene

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.

from flask import Flask

app = Flask("settings")

debug = False

@app.route('/debug/on')
def debug_on():
    global debug
    debug = True
    return str(debug)


@app.route('/debug/off')
def debug_off():
    global debug
    debug = False
    return str(debug)


@app.route('/debug')
def debug():
    return str(debug)


def start(context, argv):
    context.app_registry.add(app, "settings", 80)
1 Like

@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.

Got it, thank you for the education on mitmproxy and proxying in general. I have enough to get running for now, but I’m sure I’ll be back :slight_smile:

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. :slight_smile:

I will give it a shot! Can you point me to the best place to pdb.set_trace() and start exploring?

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 :slight_smile:

For other newbies like myself…adding correction for ver 0.18 and above:

The ‘start’ callback is changed and no longer includes the listed parameters:
> def start():
> mitmproxy.ctx.master.apps.add(app, “settings”, 80)

Hi, cortesi,

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.