mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-27 02:24:18 +00:00
improve https handling
This commit is contained in:
parent
607d79b63f
commit
efdb25ef68
@ -120,6 +120,9 @@ class HTTPRequest(object):
|
|||||||
request_line = None
|
request_line = None
|
||||||
if self.form_out == "asterisk" or self.form_out == "origin":
|
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])
|
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:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
return '%s\r\n%s\r\n%s' % (request_line, str(self.headers), self.content)
|
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":
|
if self.c.mode == "regular":
|
||||||
self.authenticate(request)
|
self.authenticate(request)
|
||||||
if request.form_in == "authority":
|
if request.form_in == "authority" and self.c.client_conn.ssl_established:
|
||||||
if not self.c.config.forward_proxy:
|
raise ProtocolError(502, "Must not CONNECT on SSL connection")
|
||||||
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 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.mode = "transparent"
|
||||||
self.c.determine_conntype()
|
self.c.determine_conntype()
|
||||||
# FIXME: We need to persist the CONNECT request
|
|
||||||
raise ConnectionTypeChange
|
raise ConnectionTypeChange
|
||||||
|
|
||||||
|
if self.c.mode == "regular":
|
||||||
|
if request.form_in == "authority":
|
||||||
|
pass
|
||||||
elif request.form_in == "absolute":
|
elif request.form_in == "absolute":
|
||||||
if not self.c.config.forward_proxy:
|
if not self.c.config.forward_proxy:
|
||||||
request.form_out = "origin"
|
request.form_out = "origin"
|
||||||
if ((not self.c.server_conn) or
|
if ((not self.c.server_conn) or
|
||||||
(self.c.server_conn.address != (request.host, request.port))):
|
(self.c.server_conn.address != (request.host, request.port))):
|
||||||
self.c.establish_server_connection(request.host, request.port)
|
self.c.establish_server_connection(request.host, request.port)
|
||||||
|
elif request.form_in == "asterisk":
|
||||||
|
raise ProtocolError(501, "Not Implemented")
|
||||||
else:
|
else:
|
||||||
raise ProtocolError(400, "Invalid Request")
|
raise ProtocolError(400, "Invalid Request")
|
||||||
|
|
||||||
return request
|
return request
|
||||||
|
|
||||||
def read_response(self, flow):
|
def read_response(self, flow):
|
||||||
|
@ -148,6 +148,7 @@ class ConnectionHandler:
|
|||||||
def del_server_connection(self):
|
def del_server_connection(self):
|
||||||
if self.server_conn:
|
if self.server_conn:
|
||||||
self.server_conn.finish()
|
self.server_conn.finish()
|
||||||
|
self.log("serverdisconnect", ["%s:%s"%(self.server_conn.host, self.server_conn.port)])
|
||||||
self.channel.tell("serverdisconnect", self)
|
self.channel.tell("serverdisconnect", self)
|
||||||
self.server_conn = None
|
self.server_conn = None
|
||||||
self.sni = None
|
self.sni = None
|
||||||
@ -170,11 +171,11 @@ class ConnectionHandler:
|
|||||||
raise ProxyError(502, "Transparent mode failure: could not resolve original destination.")
|
raise ProxyError(502, "Transparent mode failure: could not resolve original destination.")
|
||||||
self.log("transparent to %s:%s"%server_address)
|
self.log("transparent to %s:%s"%server_address)
|
||||||
|
|
||||||
|
self.determine_conntype()
|
||||||
|
|
||||||
if server_address:
|
if server_address:
|
||||||
self.establish_server_connection(*server_address)
|
self.establish_server_connection(*server_address)
|
||||||
self.handle_ssl()
|
self._handle_ssl()
|
||||||
|
|
||||||
self.determine_conntype()
|
|
||||||
|
|
||||||
while not self.close:
|
while not self.close:
|
||||||
try:
|
try:
|
||||||
@ -191,6 +192,18 @@ class ConnectionHandler:
|
|||||||
self.log("disconnect")
|
self.log("disconnect")
|
||||||
self.channel.tell("clientdisconnect", self)
|
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):
|
def finish(self):
|
||||||
self.client_conn.finish()
|
self.client_conn.finish()
|
||||||
|
|
||||||
@ -209,21 +222,19 @@ class ConnectionHandler:
|
|||||||
self.log("serverconnect", ["%s:%s"%(host, port)])
|
self.log("serverconnect", ["%s:%s"%(host, port)])
|
||||||
self.channel.tell("serverconnect", self)
|
self.channel.tell("serverconnect", self)
|
||||||
|
|
||||||
def handle_ssl(self):
|
def establish_ssl(self, client, server):
|
||||||
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
|
|
||||||
|
|
||||||
# TODO: Implement SSL pass-through handling and change conntype
|
# 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)
|
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()
|
dummycert = self.find_cert()
|
||||||
self.client_conn.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert,
|
self.client_conn.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert,
|
||||||
handle_sni=self.handle_sni)
|
handle_sni=self.handle_sni)
|
||||||
@ -266,7 +277,7 @@ class ConnectionHandler:
|
|||||||
if sn and sn != self.sni:
|
if sn and sn != self.sni:
|
||||||
self.sni = sn.decode("utf8").encode("idna")
|
self.sni = sn.decode("utf8").encode("idna")
|
||||||
self.establish_server_connection() # reconnect to upstream server with SNI
|
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:
|
# Now, change client context to reflect changed certificate:
|
||||||
new_context = SSL.Context(SSL.TLSv1_METHOD)
|
new_context = SSL.Context(SSL.TLSv1_METHOD)
|
||||||
new_context.use_privatekey_file(self.config.certfile or self.config.cacert)
|
new_context.use_privatekey_file(self.config.certfile or self.config.cacert)
|
||||||
|
Loading…
Reference in New Issue
Block a user