aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmproxy/proxy.py94
-rw-r--r--libmproxy/utils.py58
-rwxr-xr-xmitmdump8
-rwxr-xr-xmitmplayback8
-rwxr-xr-xmitmproxy8
-rwxr-xr-xmitmrecord8
-rw-r--r--test/test_proxy.py3
-rw-r--r--test/test_utils.py6
8 files changed, 102 insertions, 91 deletions
diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py
index e3c692b9..f70fad25 100644
--- a/libmproxy/proxy.py
+++ b/libmproxy/proxy.py
@@ -6,11 +6,10 @@
Development started from Neil Schemenauer's munchy.py
"""
import sys, os, time, string, socket, urlparse, re, select, copy, base64
-import SocketServer, ssl
+import optparse, SocketServer, ssl
import utils, controller
NAME = "mitmproxy"
-config = None
class ProxyError(Exception):
@@ -495,7 +494,8 @@ class ServerConnection:
class ProxyHandler(SocketServer.StreamRequestHandler):
- def __init__(self, request, client_address, server, q):
+ def __init__(self, config, request, client_address, server, q):
+ self.config = config
self.mqueue = q
SocketServer.StreamRequestHandler.__init__(self, request, client_address, server)
@@ -545,22 +545,14 @@ class ProxyHandler(SocketServer.StreamRequestHandler):
if server:
server.terminate()
- def find_cert(self, host, port=443):
- #return config.certpath + "/" + host + ":" + port + ".pem"
- if config.certpath is not None:
- cert = config.certpath + "/" + host + ".pem"
- if not os.path.exists(cert) and config.cacert is not None:
- utils.dummy_cert(config.certpath, config.cacert, host)
- if os.path.exists(cert):
- return cert
- print >> sys.stderr, "WARNING: Certificate missing for %s:%d! (%s)\n" % (host, port, cert)
- return config.certfile
-
- def find_key(self, host, port=443):
- if config.cacert is not None:
- return config.cacert
+ def find_cert(self, host):
+ if self.config.certfile:
+ return self.config.certfile
else:
- return config.certfile
+ ret = utils.dummy_cert(self.config.certpath, self.config.cacert, host)
+ if not ret:
+ raise ProxyError(400, "mitmproxy: Unable to generate dummy cert.")
+ return ret
def read_request(self, client_conn):
line = self.rfile.readline()
@@ -583,14 +575,14 @@ class ProxyHandler(SocketServer.StreamRequestHandler):
)
self.wfile.flush()
kwargs = dict(
- certfile = self.find_cert(host,port),
- keyfile = self.find_key(host,port),
+ certfile = self.find_cert(host),
+ keyfile = self.config.certfile or self.config.cacert,
server_side = True,
ssl_version = ssl.PROTOCOL_SSLv23,
do_handshake_on_connect = False
)
if sys.version_info[1] > 6:
- kwargs["ciphers"] = config.ciphers
+ kwargs["ciphers"] = self.config.ciphers
self.connection = ssl.wrap_socket(self.connection, **kwargs)
self.rfile = FileLike(self.connection)
self.wfile = FileLike(self.connection)
@@ -671,8 +663,8 @@ ServerBase.daemon_threads = True # Terminate workers when main thread ter
class ProxyServer(ServerBase):
request_queue_size = 20
allow_reuse_address = True
- def __init__(self, port, address=''):
- self.port, self.address = port, address
+ def __init__(self, config, port, address=''):
+ self.config, self.port, self.address = config, port, address
ServerBase.__init__(self, (address, port), ProxyHandler)
self.masterq = None
@@ -680,8 +672,62 @@ class ProxyServer(ServerBase):
self.masterq = q
def finish_request(self, request, client_address):
- self.RequestHandlerClass(request, client_address, self, self.masterq)
+ self.RequestHandlerClass(self.config, request, client_address, self, self.masterq)
def shutdown(self):
ServerBase.shutdown(self)
+
+# Command-line utils
+def certificate_option_group(parser):
+ group = optparse.OptionGroup(parser, "SSL")
+ group.add_option(
+ "--cert", action="store",
+ type = "str", dest="cert", default=None,
+ help = "User-created SSL certificate file."
+ )
+ group.add_option(
+ "--cacert", action="store",
+ type = "str", dest="cacert", default="~/.mitmproxy/ca.pem",
+ help = "SSL CA certificate file. Generated if it doesn't exist."
+ )
+ group.add_option(
+ "--certpath", action="store",
+ type = "str", dest="certpath", default="~/.mitmproxy/",
+ help = "SSL certificate store path."
+ )
+ group.add_option(
+ "--ciphers", action="store",
+ type = "str", dest="ciphers", default=None,
+ help = "SSL ciphers."
+ )
+ parser.add_option_group(group)
+
+
+def process_certificate_option_group(parser, options):
+ conf = {}
+ if options.cert:
+ options.cert = os.path.expanduser(options.cert)
+ if not os.path.exists(options.cert):
+ parser.error("Manually created certificate does not exist: %s"%options.cert)
+ if options.cacert:
+ options.cacert = os.path.expanduser(options.cacert)
+ if not os.path.exists(options.cacert):
+ dummy_ca(options.cacert)
+ if options.certpath:
+ options.certpath = os.path.expanduser(options.certpath)
+ elif options.cacert:
+ options.certpath = os.path.dirname(options.cacert)
+
+ if getattr(options, "cache", None) is not None:
+ options.cache = os.path.expanduser(options.cache)
+
+ return Config(
+ certfile = options.cert,
+ certpath = options.certpath,
+ cacert = options.cacert,
+ ciphers = options.ciphers
+ )
+
+
+
diff --git a/libmproxy/utils.py b/libmproxy/utils.py
index 51a8e871..ab861c55 100644
--- a/libmproxy/utils.py
+++ b/libmproxy/utils.py
@@ -13,7 +13,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re, os, subprocess, datetime, textwrap, errno, sys
-import optparse
def format_timestamp(s):
d = datetime.datetime.fromtimestamp(s)
@@ -355,11 +354,14 @@ def dummy_cert(certdir, ca, commonname):
ca: Path to the certificate authority file, or None.
commonname: Common name for the generated certificate.
- Returns True if operation succeeded, False if not.
+ Returns cert path if operation succeeded, None if not.
"""
+ certpath = os.path.join(certdir, commonname + ".pem")
+ if os.path.exists(certpath):
+ return certpath
+
confpath = os.path.join(certdir, commonname + ".cnf")
reqpath = os.path.join(certdir, commonname + ".req")
- certpath = os.path.join(certdir, commonname + ".pem")
template = open(data.path("resources/cert.cnf")).read()
f = open(confpath, "w").write(template%(dict(commonname=commonname)))
@@ -381,7 +383,7 @@ def dummy_cert(certdir, ca, commonname):
stdin=subprocess.PIPE
)
if ret:
- return False
+ return None
cmd = [
"openssl",
"x509",
@@ -401,7 +403,7 @@ def dummy_cert(certdir, ca, commonname):
stdin=subprocess.PIPE
)
if ret:
- return False
+ return None
else:
# Create a new selfsigned certificate + key
cmd = [
@@ -423,8 +425,8 @@ def dummy_cert(certdir, ca, commonname):
stdin=subprocess.PIPE
)
if ret:
- return False
- return True
+ return None
+ return certpath
def mkdir_p(path):
@@ -437,45 +439,3 @@ def mkdir_p(path):
raise
-def certificate_option_group(parser):
- group = optparse.OptionGroup(parser, "SSL")
- group.add_option(
- "--cert", action="store",
- type = "str", dest="cert", default=None,
- help = "SSL certificate file."
- )
- group.add_option(
- "--cacert", action="store",
- type = "str", dest="cacert", default="~/.mitmproxy/ca.pem",
- help = "SSL CA certificate file."
- )
- group.add_option(
- "--certpath", action="store",
- type = "str", dest="certpath", default="~/.mitmproxy/",
- help = "SSL certificate store path."
- )
- group.add_option(
- "--ciphers", action="store",
- type = "str", dest="ciphers", default=None,
- help = "SSL ciphers."
- )
- parser.add_option_group(group)
-
-
-def process_certificate_option_group(parser, options):
- if options.cert is not None:
- options.cert = os.path.expanduser(options.cert)
- if not os.path.exists(options.cert):
- parser.error("Manually created certificate does not exist: %s"%options.cert)
- if options.cacert is not None:
- options.cacert = os.path.expanduser(options.cacert)
- if not os.path.exists(options.cacert):
- print >> sys.stderr, "Creating dummy CA certificate at %s"%options.cacert
- dummy_ca(options.cacert)
- if options.certpath is not None:
- options.certpath = os.path.expanduser(options.certpath)
- elif options.cacert is not None:
- options.certpath = os.path.dirname(options.cacert)
- if getattr(options, "cache", None) is not None:
- options.cache = os.path.expanduser(options.cache)
-
diff --git a/mitmdump b/mitmdump
index 58254038..56210f39 100755
--- a/mitmdump
+++ b/mitmdump
@@ -26,7 +26,7 @@ if __name__ == '__main__':
usage = "%prog [options] [filter]",
version="%%prog %s"%VERSION,
)
- utils.certificate_option_group(parser)
+ proxy.certificate_option_group(parser)
parser.add_option(
"-p", "--port", action="store",
type = "int", dest="port", default=8080,
@@ -54,15 +54,15 @@ if __name__ == '__main__':
if options.quiet:
options.verbose = 0
- utils.process_certificate_option_group(parser, options)
+ proxy.process_certificate_option_group(parser, options)
- proxy.config = proxy.Config(
+ config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
- server = proxy.ProxyServer(options.port)
+ server = proxy.ProxyServer(config, options.port)
dumpopts = dump.Options(
verbosity = options.verbose,
diff --git a/mitmplayback b/mitmplayback
index ddfe233b..428d9a04 100755
--- a/mitmplayback
+++ b/mitmplayback
@@ -30,7 +30,7 @@ if __name__ == '__main__':
version="%%prog %s"%VERSION,
)
- utils.certificate_option_group(parser)
+ proxy.certificate_option_group(parser)
parser.add_option(
"-p", "--port", action="store",
@@ -56,17 +56,17 @@ if __name__ == '__main__':
if options.quiet:
options.verbose = 0
- utils.process_certificate_option_group(parser, options)
+ proxy.process_certificate_option_group(parser, options)
if options.cache is not None:
options.cache = os.path.expanduser(options.cache)
- proxy.config = proxy.Config(
+ config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
- server = proxy.ProxyServer(options.port)
+ server = proxy.ProxyServer(config, options.port)
m = playback.PlaybackMaster(server, options)
m.run()
diff --git a/mitmproxy b/mitmproxy
index 934b2ec7..0a9e81c0 100755
--- a/mitmproxy
+++ b/mitmproxy
@@ -26,7 +26,7 @@ if __name__ == '__main__':
usage = "%prog [options] [flowdump path]",
version="%%prog %s"%VERSION,
)
- utils.certificate_option_group(parser)
+ proxy.certificate_option_group(parser)
parser.add_option(
"-a", "--addr", action="store",
type = "str", dest="addr", default='',
@@ -85,12 +85,12 @@ if __name__ == '__main__':
options, args = parser.parse_args()
- utils.process_certificate_option_group(parser, options)
+ proxy.process_certificate_option_group(parser, options)
if options.cache is not None:
options.cache = os.path.expanduser(options.cache)
- proxy.config = proxy.Config(
+ config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
@@ -101,7 +101,7 @@ if __name__ == '__main__':
if os.path.exists(options.cache + "/index.txt"):
print >> sys.stderr, "ERROR: data already recorded in %s"%options.cache
sys.exit(1)
- server = proxy.ProxyServer(options.port, options.addr)
+ server = proxy.ProxyServer(config, options.port, options.addr)
m = console.ConsoleMaster(server, options)
for i in args:
diff --git a/mitmrecord b/mitmrecord
index 73376154..ec35bc85 100755
--- a/mitmrecord
+++ b/mitmrecord
@@ -29,7 +29,7 @@ if __name__ == '__main__':
version="%%prog %s"%VERSION,
)
- utils.certificate_option_group(parser)
+ proxy.certificate_option_group(parser)
parser.add_option(
"-p", "--port", action="store",
@@ -61,15 +61,15 @@ if __name__ == '__main__':
if options.quiet:
options.verbose = 0
- utils.process_certificate_option_group(parser, options)
+ proxy.process_certificate_option_group(parser, options)
- proxy.config = proxy.Config(
+ config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
- server = proxy.ProxyServer(options.port)
+ server = proxy.ProxyServer(config, options.port)
utils.mkdir_p(options.cache)
if os.path.exists(options.cache + "/index.txt"):
print >> sys.stderr, "ERROR: data already recorded in %s"%options.cache
diff --git a/test/test_proxy.py b/test/test_proxy.py
index 0b40164e..0c05aeb2 100644
--- a/test/test_proxy.py
+++ b/test/test_proxy.py
@@ -15,7 +15,7 @@ HTTPS_PORT = random.randint(30000, 40000)
class TestMaster(controller.Master):
def __init__(self, port, testq):
- serv = proxy.ProxyServer(port)
+ serv = proxy.ProxyServer(proxy.Config("data/testkey.pem"), port)
controller.Master.__init__(self, serv)
self.testq = testq
self.log = []
@@ -54,7 +54,6 @@ class ServerThread(threading.Thread):
class _TestServers(libpry.TestContainer):
def setUpAll(self):
- proxy.config = proxy.Config("data/testkey.pem")
self.tqueue = Queue.Queue()
# We don't make any concurrent requests, so we can access
# the attributes on this object safely.
diff --git a/test/test_utils.py b/test/test_utils.py
index a52c8e3b..f65c1ea7 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -293,6 +293,12 @@ class udummy_cert(libpry.AutoTree):
"foo.com"
)
assert os.path.exists(os.path.join(d, "foo", "foo.com.pem"))
+ # Short-circuit
+ assert utils.dummy_cert(
+ os.path.join(d, "foo"),
+ cacert,
+ "foo.com"
+ )
def test_no_ca(self):
d = self.tmpdir()