aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2014-01-09 17:56:42 +0100
committerMaximilian Hils <git@maximilianhils.com>2014-01-09 17:56:42 +0100
commitefdb25ef686f82f5c3a1cd83cd10f302cf6346a0 (patch)
tree17f0e10753f75e5c5840493b810f98a483b1532c /libmproxy
parent607d79b63feb49f67426aaaf1b3f55ccf3f7be2a (diff)
downloadmitmproxy-efdb25ef686f82f5c3a1cd83cd10f302cf6346a0.tar.gz
mitmproxy-efdb25ef686f82f5c3a1cd83cd10f302cf6346a0.tar.bz2
mitmproxy-efdb25ef686f82f5c3a1cd83cd10f302cf6346a0.zip
improve https handling
Diffstat (limited to 'libmproxy')
-rw-r--r--libmproxy/protocol.py46
-rw-r--r--libmproxy/proxy.py43
2 files changed, 56 insertions, 33 deletions
diff --git a/libmproxy/protocol.py b/libmproxy/protocol.py
index 866ac419..402caef5 100644
--- a/libmproxy/protocol.py
+++ b/libmproxy/protocol.py
@@ -120,6 +120,9 @@ class HTTPRequest(object):
request_line = None
if self.form_out == "asterisk" or self.form_out == "origin":
request_line = '%s %s HTTP/%s.%s' % (self.method, self.path, self.http_version[0], self.http_version[1])
+ elif self.form_out == "authority":
+ request_line = '%s %s:%s HTTP/%s.%s' % (self.method, self.host, self.port,
+ self.http_version[0], self.http_version[1])
else:
raise NotImplementedError
return '%s\r\n%s\r\n%s' % (request_line, str(self.headers), self.content)
@@ -219,30 +222,39 @@ class HTTPHandler(ProtocolHandler):
if self.c.mode == "regular":
self.authenticate(request)
- if request.form_in == "authority":
- if not self.c.config.forward_proxy:
- self.c.establish_server_connection(request.host, request.port)
- self.c.client_conn.wfile.write(
- 'HTTP/1.1 200 Connection established\r\n' +
- ('Proxy-agent: %s\r\n'%self.c.server_version) +
- '\r\n'
- )
- self.c.client_conn.wfile.flush()
-
- self.c.handle_ssl()
+ if request.form_in == "authority" and self.c.client_conn.ssl_established:
+ raise ProtocolError(502, "Must not CONNECT on SSL connection")
+
+ # If we have a CONNECT request, we might need to intercept
+ if request.form_in == "authority":
+ directly_addressed_at_mitmproxy = (self.c.mode == "regular") and not self.c.config.forward_proxy
+ if directly_addressed_at_mitmproxy:
+ self.c.establish_server_connection(request.host, request.port)
+ self.c.client_conn.wfile.write(
+ 'HTTP/1.1 200 Connection established\r\n' +
+ ('Proxy-agent: %s\r\n'%self.c.server_version) +
+ '\r\n'
+ )
+ self.c.client_conn.wfile.flush()
+
+ self.c.establish_ssl(server=True, client=True)
self.c.mode = "transparent"
self.c.determine_conntype()
- # FIXME: We need to persist the CONNECT request
raise ConnectionTypeChange
+
+ if self.c.mode == "regular":
+ if request.form_in == "authority":
+ pass
elif request.form_in == "absolute":
if not self.c.config.forward_proxy:
- request.form_out = "origin"
- if ((not self.c.server_conn) or
- (self.c.server_conn.address != (request.host, request.port))):
- self.c.establish_server_connection(request.host, request.port)
+ request.form_out = "origin"
+ if ((not self.c.server_conn) or
+ (self.c.server_conn.address != (request.host, request.port))):
+ self.c.establish_server_connection(request.host, request.port)
+ elif request.form_in == "asterisk":
+ raise ProtocolError(501, "Not Implemented")
else:
raise ProtocolError(400, "Invalid Request")
-
return request
def read_response(self, flow):
diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py
index 3297ab90..4ce14491 100644
--- a/libmproxy/proxy.py
+++ b/libmproxy/proxy.py
@@ -148,6 +148,7 @@ class ConnectionHandler:
def del_server_connection(self):
if self.server_conn:
self.server_conn.finish()
+ self.log("serverdisconnect", ["%s:%s"%(self.server_conn.host, self.server_conn.port)])
self.channel.tell("serverdisconnect", self)
self.server_conn = None
self.sni = None
@@ -170,11 +171,11 @@ class ConnectionHandler:
raise ProxyError(502, "Transparent mode failure: could not resolve original destination.")
self.log("transparent to %s:%s"%server_address)
+ self.determine_conntype()
+
if server_address:
self.establish_server_connection(*server_address)
- self.handle_ssl()
-
- self.determine_conntype()
+ self._handle_ssl()
while not self.close:
try:
@@ -191,6 +192,18 @@ class ConnectionHandler:
self.log("disconnect")
self.channel.tell("clientdisconnect", self)
+ def _handle_ssl(self):
+ """
+ Check if we can already identify SSL connections.
+ """
+ if self.config.transparent_proxy:
+ client_ssl = server_ssl = (self.server_conn.port in self.config.transparent_proxy["sslports"])
+ elif self.config.reverse_proxy:
+ client_ssl = server_ssl = (self.config.reverse_proxy[0] == "https")
+ # TODO: Make protocol generic (as with transparent proxies)
+ # TODO: Add SSL-terminating capatbility (SSL -> mitmproxy -> plain and vice versa)
+ self.establish_ssl(client=client_ssl, server=server_ssl)
+
def finish(self):
self.client_conn.finish()
@@ -209,21 +222,19 @@ class ConnectionHandler:
self.log("serverconnect", ["%s:%s"%(host, port)])
self.channel.tell("serverconnect", self)
- def handle_ssl(self):
- if self.config.transparent_proxy:
- client_ssl = server_ssl = (self.server_conn.port in self.config.transparent_proxy["sslports"])
- elif self.config.reverse_proxy:
- client_ssl = server_ssl = (self.config.reverse_proxy[0] == "https")
- # TODO: Make protocol generic (as with transparent proxies)
- # TODO: Add SSL-terminating capatbility (SSL -> mitmproxy -> plain and vice versa)
- else:
- client_ssl = server_ssl = True # In regular mode, this function will only be called on HTTP CONNECT
-
+ def establish_ssl(self, client, server):
# TODO: Implement SSL pass-through handling and change conntype
- if server_ssl and not self.server_conn.ssl_established:
+ if self.server_conn.host == "ycombinator.com":
+ self.conntype = "tcp"
+
+ if server:
+ if self.server_conn.ssl_established:
+ raise ProxyError(502, "SSL to Server already established.")
self.server_conn.establish_ssl(self.config.clientcerts, self.sni)
- if client_ssl and not self.client_conn.ssl_established:
+ if client:
+ if self.client_conn.ssl_established:
+ raise ProxyError(502, "SSL to Client already established.")
dummycert = self.find_cert()
self.client_conn.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert,
handle_sni=self.handle_sni)
@@ -266,7 +277,7 @@ class ConnectionHandler:
if sn and sn != self.sni:
self.sni = sn.decode("utf8").encode("idna")
self.establish_server_connection() # reconnect to upstream server with SNI
- self.handle_ssl() # establish SSL with upstream
+ self.establish_ssl(server=True) # establish SSL with upstream
# Now, change client context to reflect changed certificate:
new_context = SSL.Context(SSL.TLSv1_METHOD)
new_context.use_privatekey_file(self.config.certfile or self.config.cacert)