diff options
Diffstat (limited to 'libmproxy')
-rw-r--r-- | libmproxy/console/common.py | 14 | ||||
-rw-r--r-- | libmproxy/flow.py | 2 | ||||
-rw-r--r-- | libmproxy/protocol/http.py | 17 | ||||
-rw-r--r-- | libmproxy/proxy/config.py | 52 | ||||
-rw-r--r-- | libmproxy/proxy/server.py | 31 | ||||
-rw-r--r-- | libmproxy/utils.py | 12 |
6 files changed, 81 insertions, 47 deletions
diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index a2cfd57b..fa21c93e 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -162,7 +162,7 @@ def raw_format_flow(f, focus, extended, padding): if f["resp_ctype"]: resp.append(fcol(f["resp_ctype"], rc)) resp.append(fcol(f["resp_clen"], rc)) - resp.append(fcol(f["resp_rate"], rc)) + resp.append(fcol(f["roundtrip"], rc)) elif f["err_msg"]: resp.append(fcol(SYMBOL_RETURN, "error")) @@ -345,19 +345,17 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2): contentdesc = "[content missing]" else: contentdesc = "[no content]" - - if f.response.timestamp_end: - delta = f.response.timestamp_end - f.response.timestamp_start - else: - delta = 0 + duration = 0 + if f.response.timestamp_end and f.request.timestamp_start: + duration = f.response.timestamp_end - f.request.timestamp_start size = f.response.size() - rate = utils.pretty_size(size / ( delta if delta > 0 else 1 ) ) + roundtrip = utils.pretty_duration(duration) d.update(dict( resp_code = f.response.code, resp_is_replay = f.response.is_replay, resp_clen = contentdesc, - resp_rate = "{0}/s".format(rate), + roundtrip = roundtrip, )) t = f.response.headers["content-type"] if t: diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 14497964..43580109 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -165,7 +165,7 @@ class StreamLargeBodies(object): r.headers, is_request, flow.request.method, code ) if not (0 <= expected_size <= self.max_size): - r.stream = True + r.stream = r.stream or True # r.stream may already be a callable, which we want to preserve. class ClientPlaybackState: diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 046d0b42..49310ec3 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -1332,10 +1332,19 @@ class HTTPHandler(ProtocolHandler): # incrementally: h = flow.response._assemble_head(preserve_transfer_encoding=True) self.c.client_conn.send(h) - for chunk in http.read_http_body_chunked(self.c.server_conn.rfile, - flow.response.headers, - self.c.config.body_size_limit, flow.request.method, - flow.response.code, False, 4096): + + chunks = http.read_http_body_chunked( + self.c.server_conn.rfile, + flow.response.headers, + self.c.config.body_size_limit, + flow.request.method, + flow.response.code, + False, + 4096 + ) + if callable(flow.response.stream): + chunks = flow.response.stream(chunks) + for chunk in chunks: for part in chunk: self.c.client_conn.wfile.write(part) self.c.client_conn.wfile.flush() diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index 84893323..dfde2958 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -45,7 +45,8 @@ class ProxyConfig: authenticator=None, ignore_hosts=[], tcp_hosts=[], - ciphers=None, + ciphers_client=None, + ciphers_server=None, certs=[], certforward=False, ssl_version_client="secure", @@ -55,7 +56,8 @@ class ProxyConfig: self.host = host self.port = port self.server_version = server_version - self.ciphers = ciphers + self.ciphers_client = ciphers_client + self.ciphers_server = ciphers_server self.clientcerts = clientcerts self.no_upstream_cert = no_upstream_cert self.body_size_limit = body_size_limit @@ -83,8 +85,8 @@ class ProxyConfig: for spec, cert in certs: self.certstore.add_cert_file(spec, cert) self.certforward = certforward - self.openssl_client_method, self.openssl_client_options = version_to_openssl(ssl_version_client) - self.openssl_server_method, self.openssl_server_options = version_to_openssl(ssl_version_server) + self.openssl_method_client, self.openssl_options_client = version_to_openssl(ssl_version_client) + self.openssl_method_server, self.openssl_options_server = version_to_openssl(ssl_version_server) self.ssl_ports = ssl_ports @@ -188,7 +190,8 @@ def process_proxy_options(parser, options): ignore_hosts=options.ignore_hosts, tcp_hosts=options.tcp_hosts, authenticator=authenticator, - ciphers=options.ciphers, + ciphers_client=options.ciphers_client, + ciphers_server=options.ciphers_server, certs=certs, certforward=options.certforward, ssl_version_client=options.ssl_version_client, @@ -210,19 +213,35 @@ def ssl_option_group(parser): 'Can be passed multiple times.' ) group.add_argument( + "--cert-forward", action="store_true", + dest="certforward", default=False, + help="Simply forward SSL certificates from upstream." + ) + group.add_argument( + "--ciphers-client", action="store", + type=str, dest="ciphers_client", default=None, + help="Set supported ciphers for client connections. (OpenSSL Syntax)" + ) + group.add_argument( + "--ciphers-server", action="store", + type=str, dest="ciphers_server", default=None, + help="Set supported ciphers for server connections. (OpenSSL Syntax)" + ) + group.add_argument( "--client-certs", action="store", type=str, dest="clientcerts", default=None, help="Client certificate directory." ) group.add_argument( - "--ciphers", action="store", - type=str, dest="ciphers", default=None, - help="SSL cipher specification." + "--no-upstream-cert", default=False, + action="store_true", dest="no_upstream_cert", + help="Don't connect to upstream server to look up certificate details." ) group.add_argument( - "--cert-forward", action="store_true", - dest="certforward", default=False, - help="Simply forward SSL certificates from upstream." + "--ssl-port", action="append", type=int, dest="ssl_ports", default=list(TRANSPARENT_SSL_PORTS), + metavar="PORT", + help="Can be passed multiple times. Specify destination ports which are assumed to be SSL. " + "Defaults to %s." % str(TRANSPARENT_SSL_PORTS) ) group.add_argument( "--ssl-version-client", dest="ssl_version_client", @@ -238,14 +257,3 @@ def ssl_option_group(parser): help="Set supported SSL/TLS version for server connections. " "SSLv2, SSLv3 and 'all' are INSECURE. Defaults to secure." ) - group.add_argument( - "--no-upstream-cert", default=False, - action="store_true", dest="no_upstream_cert", - help="Don't connect to upstream server to look up certificate details." - ) - group.add_argument( - "--ssl-port", action="append", type=int, dest="ssl_ports", default=list(TRANSPARENT_SSL_PORTS), - metavar="PORT", - help="Can be passed multiple times. Specify destination ports which are assumed to be SSL. " - "Defaults to %s." % str(TRANSPARENT_SSL_PORTS) - )
\ No newline at end of file diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index ea78d964..896dd024 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -187,8 +187,9 @@ class ConnectionHandler: self.server_conn.establish_ssl( self.config.clientcerts, sni, - method=self.config.openssl_server_method, - options=self.config.openssl_server_options + method=self.config.openssl_method_server, + options=self.config.openssl_options_server, + cipher_list=self.config.ciphers_server, ) except tcp.NetLibError as v: e = ProxyError(502, repr(v)) @@ -207,10 +208,10 @@ class ConnectionHandler: try: self.client_conn.convert_to_ssl( cert, key, - method=self.config.openssl_client_method, - options=self.config.openssl_client_options, + method=self.config.openssl_method_client, + options=self.config.openssl_options_client, handle_sni=self.handle_sni, - cipher_list=self.config.ciphers, + cipher_list=self.config.ciphers_client, dhparams=self.config.certstore.dhparams, chain_file=chain_file ) @@ -260,11 +261,12 @@ class ConnectionHandler: sans = [] if self.server_conn.ssl_established and (not self.config.no_upstream_cert): upstream_cert = self.server_conn.cert + sans.extend(upstream_cert.altnames) if upstream_cert.cn: + sans.append(host) host = upstream_cert.cn.decode("utf8").encode("idna") - sans = upstream_cert.altnames - elif self.server_conn.sni: - sans = [self.server_conn.sni] + if self.server_conn.sni: + sans.append(self.server_conn.sni) ret = self.config.certstore.get_cert(host, sans) if not ret: @@ -285,14 +287,19 @@ class ConnectionHandler: if sni != self.server_conn.sni: self.log("SNI received: %s" % sni, "debug") - self.server_reconnect(sni) # reconnect to upstream server with SNI + # We should only re-establish upstream SSL if one of the following conditions is true: + # - We established SSL with the server previously + # - We initially wanted to establish SSL with the server, + # but the server refused to negotiate without SNI. + if self.server_conn.ssl_established or hasattr(self.server_conn, "may_require_sni"): + self.server_reconnect(sni) # reconnect to upstream server with SNI # Now, change client context to reflect changed certificate: cert, key, chain_file = self.find_cert() new_context = self.client_conn._create_ssl_context( cert, key, - method=self.config.openssl_client_method, - options=self.config.openssl_client_options, - cipher_list=self.config.ciphers, + method=self.config.openssl_method_client, + options=self.config.openssl_options_client, + cipher_list=self.config.ciphers_client, dhparams=self.config.certstore.dhparams, chain_file=chain_file ) diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 33af035f..76e99c34 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -79,6 +79,18 @@ def pretty_size(size): x = int(x) return str(x) + suf +def pretty_duration(secs): + formatters = [ + (100, "{:.0f}s"), + (10, "{:2.1f}s"), + (1, "{:1.2f}s"), + ] + + for limit, formatter in formatters: + if secs >= limit: + return formatter.format(secs) + #less than 1 sec + return "{:.0f}ms".format(secs*1000) class Data: def __init__(self, name): |