aboutsummaryrefslogtreecommitdiffstats
path: root/examples/mitmproxywrapper.py
blob: 48963896b8eeee18a2a6040ab37dc1137798c18b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python
#
# Helper tool to enable/disable OS X proxy and wrap mitmproxy
#
# Get usage information with:
#
# mitmproxywrapper.py -h
#

import subprocess
import re
import argparse

class Wrapper(object):
    
    def __init__(self, port):
        self.port = port
        self.primary_service_name = self.find_primary_service_name()

    def run_networksetup_command(self, *arguments):
        return subprocess.check_output(['sudo', 'networksetup'] + list(arguments))

    def proxy_state_for_service(self, service):
        state = self.run_networksetup_command('-getwebproxy', service).splitlines()
        return dict([re.findall(r'([^:]+): (.*)', line)[0] for line in state])

    def enable_proxy_for_service(self, service):
        print 'Enabling proxy on {}...'.format(service)
        for subcommand in ['-setwebproxy', '-setsecurewebproxy']:
            self.run_networksetup_command(subcommand, service, '127.0.0.1', str(self.port))

    def disable_proxy_for_service(self, service):
        print 'Disabling proxy on {}...'.format(service)
        for subcommand in ['-setwebproxystate', '-setsecurewebproxystate']:
            self.run_networksetup_command(subcommand, service, 'Off')

    def interface_name_to_service_name_map(self):
        order = self.run_networksetup_command('-listnetworkserviceorder')
        mapping = re.findall(r'\(\d+\)\s(.*)$\n\(.*Device: (.+)\)$', order, re.MULTILINE)
        return dict([(b, a) for (a, b) in mapping])

    def run_command_with_input(self, command, input):
        popen = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        (stdout, stderr) = popen.communicate(input)
        return stdout
    
    def primary_interace_name(self):
        scutil_script = 'get State:/Network/Global/IPv4\nd.show\n'
        stdout = self.run_command_with_input('/usr/sbin/scutil', scutil_script)
        interface, = re.findall(r'PrimaryInterface\s*:\s*(.+)', stdout)
        return interface

    def find_primary_service_name(self):
        return self.interface_name_to_service_name_map()[self.primary_interace_name()]

    def proxy_enabled_for_service(self, service):
        return self.proxy_state_for_service(service)['Enabled'] == 'Yes'

    def toggle_proxy(self):
        if self.proxy_enabled_for_service(self.primary_service_name):
            self.disable_proxy_for_service(self.primary_service_name)
        else:
            self.enable_proxy_for_service(self.primary_service_name)

    def wrap_mitmproxy(self):
        if not self.proxy_enabled_for_service(self.primary_service_name):
            self.enable_proxy_for_service(self.primary_service_name)

        subprocess.check_call(['mitmproxy', '-p', str(self.port), '--palette', 'light'])

        if self.proxy_enabled_for_service(self.primary_service_name):
            self.disable_proxy_for_service(self.primary_service_name)

    @classmethod
    def main(cls):
        parser = argparse.ArgumentParser(description='Helper tool for OS X proxy configuration and mitmproxy')
        parser.add_argument('-t', '--toggle', action='store_true', help='just toggle the proxy configuration')
        parser.add_argument('-p', '--port', type=int, help='override the default port of 8080', default=8080)
        args = parser.parse_args()

        wrapper = cls(port=args.port)
        if args.toggle:
            wrapper.toggle_proxy()
        else:
            wrapper.wrap_mitmproxy()

if __name__ == '__main__':
    Wrapper.main()