2013-05-15 22:24:18 +00:00
|
|
|
#!/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
|
2013-05-16 05:40:08 +00:00
|
|
|
import contextlib
|
2013-06-02 19:43:49 +00:00
|
|
|
import os
|
|
|
|
import sys
|
2013-05-15 22:24:18 +00:00
|
|
|
|
|
|
|
class Wrapper(object):
|
|
|
|
|
2013-07-07 22:58:21 +00:00
|
|
|
def __init__(self, port, extra_arguments=None):
|
2013-05-15 22:24:18 +00:00
|
|
|
self.port = port
|
2013-07-07 22:58:21 +00:00
|
|
|
self.extra_arguments = extra_arguments
|
2013-05-15 22:24:18 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2013-05-16 05:40:08 +00:00
|
|
|
def primary_service_name(self):
|
2013-05-15 22:24:18 +00:00
|
|
|
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):
|
2013-05-16 05:40:08 +00:00
|
|
|
new_state = not self.proxy_enabled_for_service(self.primary_service_name())
|
|
|
|
for service_name in self.connected_service_names():
|
|
|
|
if self.proxy_enabled_for_service(service_name) and not new_state:
|
|
|
|
self.disable_proxy_for_service(service_name)
|
|
|
|
elif not self.proxy_enabled_for_service(service_name) and new_state:
|
|
|
|
self.enable_proxy_for_service(service_name)
|
|
|
|
|
|
|
|
def connected_service_names(self):
|
|
|
|
scutil_script = 'list\n'
|
|
|
|
stdout = self.run_command_with_input('/usr/sbin/scutil', scutil_script)
|
|
|
|
service_ids = re.findall(r'State:/Network/Service/(.+)/IPv4', stdout)
|
2013-05-15 22:24:18 +00:00
|
|
|
|
2013-05-16 05:40:08 +00:00
|
|
|
service_names = []
|
|
|
|
for service_id in service_ids:
|
|
|
|
scutil_script = 'show Setup:/Network/Service/{}\n'.format(service_id)
|
|
|
|
stdout = self.run_command_with_input('/usr/sbin/scutil', scutil_script)
|
|
|
|
service_name, = re.findall(r'UserDefinedName\s*:\s*(.+)', stdout)
|
|
|
|
service_names.append(service_name)
|
2013-05-15 22:24:18 +00:00
|
|
|
|
2013-05-16 05:40:08 +00:00
|
|
|
return service_names
|
2013-05-15 22:24:18 +00:00
|
|
|
|
2013-05-16 05:40:08 +00:00
|
|
|
def wrap_mitmproxy(self):
|
|
|
|
with self.wrap_proxy():
|
2013-07-07 22:58:21 +00:00
|
|
|
cmd = ['mitmproxy', '-p', str(self.port)]
|
|
|
|
if self.extra_arguments:
|
|
|
|
cmd.extend(self.extra_arguments)
|
|
|
|
cmd.extend(['--palette', 'light'])
|
|
|
|
subprocess.check_call(cmd)
|
2013-05-16 05:40:08 +00:00
|
|
|
|
|
|
|
def wrap_honeyproxy(self):
|
|
|
|
with self.wrap_proxy():
|
|
|
|
popen = subprocess.Popen('honeyproxy.sh')
|
|
|
|
try:
|
|
|
|
popen.wait()
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
popen.terminate()
|
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
def wrap_proxy(self):
|
|
|
|
connected_service_names = self.connected_service_names()
|
|
|
|
for service_name in connected_service_names:
|
|
|
|
if not self.proxy_enabled_for_service(service_name):
|
|
|
|
self.enable_proxy_for_service(service_name)
|
|
|
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
for service_name in connected_service_names:
|
|
|
|
if self.proxy_enabled_for_service(service_name):
|
|
|
|
self.disable_proxy_for_service(service_name)
|
2013-05-15 22:24:18 +00:00
|
|
|
|
2013-06-02 19:43:49 +00:00
|
|
|
@classmethod
|
|
|
|
def ensure_superuser(cls):
|
|
|
|
if os.getuid() != 0:
|
|
|
|
print 'Relaunching with sudo...'
|
|
|
|
os.execv('/usr/bin/sudo', ['/usr/bin/sudo'] + sys.argv)
|
|
|
|
|
2013-05-15 22:24:18 +00:00
|
|
|
@classmethod
|
|
|
|
def main(cls):
|
2013-07-07 22:58:21 +00:00
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description='Helper tool for OS X proxy configuration and mitmproxy.',
|
|
|
|
epilog='Any additional arguments will be passed on unchanged to mitmproxy.'
|
|
|
|
)
|
2013-05-15 22:24:18 +00:00
|
|
|
parser.add_argument('-t', '--toggle', action='store_true', help='just toggle the proxy configuration')
|
2013-05-16 05:40:08 +00:00
|
|
|
# parser.add_argument('--honeyproxy', action='store_true', help='run honeyproxy instead of mitmproxy')
|
2013-05-15 22:24:18 +00:00
|
|
|
parser.add_argument('-p', '--port', type=int, help='override the default port of 8080', default=8080)
|
2013-07-07 22:58:21 +00:00
|
|
|
args, extra_arguments = parser.parse_known_args()
|
2013-05-15 22:24:18 +00:00
|
|
|
|
2013-07-07 22:58:21 +00:00
|
|
|
wrapper = cls(port=args.port, extra_arguments=extra_arguments)
|
2013-05-16 05:40:08 +00:00
|
|
|
|
2013-05-15 22:24:18 +00:00
|
|
|
if args.toggle:
|
|
|
|
wrapper.toggle_proxy()
|
2013-05-16 05:40:08 +00:00
|
|
|
# elif args.honeyproxy:
|
|
|
|
# wrapper.wrap_honeyproxy()
|
2013-05-15 22:24:18 +00:00
|
|
|
else:
|
|
|
|
wrapper.wrap_mitmproxy()
|
|
|
|
|
2013-05-16 05:40:08 +00:00
|
|
|
|
2013-05-15 22:24:18 +00:00
|
|
|
if __name__ == '__main__':
|
2013-06-02 19:43:49 +00:00
|
|
|
Wrapper.ensure_superuser()
|
2013-05-15 22:24:18 +00:00
|
|
|
Wrapper.main()
|
|
|
|
|