From 7b6057fa64af6cd6becd1ce6b55a2c10f6bb3c85 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 12 Dec 2013 07:54:13 +0100 Subject: [PATCH 1/3] serverconnect hook: Set sc.request The serverconnect hook script might need to examine the incoming request in order to set up the server connection. Example use: bind to a distinct source IPv6 address for each client. --- libmproxy/proxy.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 73b7f0a32..1d2386974 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -133,7 +133,7 @@ class ProxyHandler(tcp.BaseHandler): self.server_conn = None tcp.BaseHandler.__init__(self, connection, client_address, server) - def get_server_connection(self, cc, scheme, host, port, sni): + def get_server_connection(self, cc, scheme, host, port, sni, request=None): """ When SNI is in play, this means we have an SSL-encrypted connection, which means that the entire handler is dedicated to a @@ -159,6 +159,7 @@ class ProxyHandler(tcp.BaseHandler): if not self.server_conn: try: self.server_conn = ServerConnection(self.config, scheme, host, port, sni) + self.server_conn.request = request # the hook might need it self.channel.ask(self.server_conn) self.server_conn.connect() except tcp.NetLibError, v: @@ -223,7 +224,7 @@ class ProxyHandler(tcp.BaseHandler): # the case, we want to reconnect without sending an error # to the client. while 1: - sc = self.get_server_connection(cc, scheme, host, port, self.sni) + sc = self.get_server_connection(cc, scheme, host, port, self.sni, request=request) sc.send(request) if sc.requestcount == 1: # add timestamps only for first request (others are not directly affected) request.tcp_setup_timestamp = sc.tcp_setup_timestamp From 517e5e66885c79879938d618bfc9da23eba85c0d Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 12 Dec 2013 09:22:55 +0100 Subject: [PATCH 2/3] handle a hook changing connection parameters --- libmproxy/proxy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 1d2386974..38356a93f 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -140,11 +140,15 @@ class ProxyHandler(tcp.BaseHandler): single server connection - no multiplexing. If this assumption ever breaks, we'll have to do something different with the SNI host variable on the handler object. + + `conn_info` holds the initial connection's parameters. + The hook might change them. """ sc = self.server_conn if not sni: sni = host - if sc and (scheme, host, port, sni) != (sc.scheme, sc.host, sc.port, sc.sni): + conn_info = (scheme, host, port, sni) + if sc and conn_info != sc.conn_info: sc.terminate() self.server_conn = None self.log( @@ -160,6 +164,7 @@ class ProxyHandler(tcp.BaseHandler): try: self.server_conn = ServerConnection(self.config, scheme, host, port, sni) self.server_conn.request = request # the hook might need it + self.server_conn.conn_info = conn_info self.channel.ask(self.server_conn) self.server_conn.connect() except tcp.NetLibError, v: From afff1f17340b2a62de168ec42655ed7e5779c3c4 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 12 Dec 2013 10:00:23 +0100 Subject: [PATCH 3/3] Reconnect if the server-connect hook needs the request to decide what to do --- libmproxy/proxy.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 38356a93f..77c8828a5 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -141,14 +141,17 @@ class ProxyHandler(tcp.BaseHandler): breaks, we'll have to do something different with the SNI host variable on the handler object. - `conn_info` holds the initial connection's parameters. - The hook might change them. + `conn_info` holds the initial connection's parameters, as the + hook might change them. Also, the hook might require an initial + request to figure out connection settings; in this case it can + set require_request, which will cause the connection to be + re-opened after the client's request arrives. """ sc = self.server_conn if not sni: sni = host conn_info = (scheme, host, port, sni) - if sc and conn_info != sc.conn_info: + if sc and (conn_info != sc.conn_info or request and sc.require_request): sc.terminate() self.server_conn = None self.log( @@ -163,7 +166,12 @@ class ProxyHandler(tcp.BaseHandler): if not self.server_conn: try: self.server_conn = ServerConnection(self.config, scheme, host, port, sni) - self.server_conn.request = request # the hook might need it + + # Additional attributes, used if the server_connect hook + # needs to change parameters + self.server_conn.request = request + self.server_conn.require_request = False + self.server_conn.conn_info = conn_info self.channel.ask(self.server_conn) self.server_conn.connect()