def __call__(self): client = self.client_conn.connection server = self.server_conn.connection conns = [client, server] try: while not self.channel.should_exit.is_set(): r = tcp.ssl_read_select(conns, 1) for conn in r: source_conn = self.client_conn if conn == client else self.server_conn other_conn = self.server_conn if conn == client else self.client_conn is_server = (conn == self.server_conn.connection) frame = websockets.Frame.from_file(source_conn.rfile) if not self._handle_frame(frame, source_conn, other_conn, is_server): return except (socket.error, netlib.exceptions.TcpException, SSL.Error) as e: self.log( "WebSockets connection closed unexpectedly by {}: {}".format( "server" if is_server else "client", repr(e)), "info") except Exception as e: # pragma: no cover raise exceptions.ProtocolException( "Error in WebSockets connection: {}".format(repr(e)))
def connect(self): """ Establishes a server connection. Must not be called if there is an existing connection. Raises: ~mitmproxy.exceptions.ProtocolException: if the connection could not be established. """ if not self.server_conn.address: raise exceptions.ProtocolException("Cannot connect to server, no server address given.") self.log("serverconnect", "debug", [repr(self.server_conn.address)]) self.channel.ask("serverconnect", self.server_conn) try: self.server_conn.connect() except netlib.exceptions.TcpException as e: raise exceptions.ProtocolException( "Server connection to {} failed: {}".format( repr(self.server_conn.address), str(e) ) )
def __check_self_connect(self): """ We try to protect the proxy from _accidentally_ connecting to itself, e.g. because of a failed transparent lookup or an invalid configuration. """ address = self.server_conn.address if address: self_connect = (address.port == self.config.port and address.host in ("localhost", "127.0.0.1", "::1")) if self_connect: raise exceptions.ProtocolException( "Invalid server address: {}\r\n" "The proxy shall not connect to itself.".format( repr(address)))
def _next_layer(self, top_layer): try: d = top_layer.client_conn.rfile.peek(3) except netlib.exceptions.TcpException as e: six.reraise(exceptions.ProtocolException, exceptions.ProtocolException(str(e)), sys.exc_info()[2]) client_tls = protocol.is_tls_record_magic(d) # 1. check for --ignore if self.config.check_ignore: ignore = self.config.check_ignore(top_layer.server_conn.address) if not ignore and client_tls: try: client_hello = protocol.TlsClientHello.from_client_conn( self.client_conn) except exceptions.TlsProtocolException as e: self.log("Cannot parse Client Hello: %s" % repr(e), "error") else: ignore = self.config.check_ignore((client_hello.sni, 443)) if ignore: return protocol.RawTCPLayer(top_layer, ignore=True) # 2. Always insert a TLS layer, even if there's neither client nor server tls. # An inline script may upgrade from http to https, # in which case we need some form of TLS layer. if isinstance(top_layer, modes.ReverseProxy): return protocol.TlsLayer(top_layer, client_tls, top_layer.server_tls, top_layer.server_conn.address.host) if isinstance(top_layer, protocol.ServerConnectionMixin) or isinstance( top_layer, protocol.UpstreamConnectLayer): return protocol.TlsLayer(top_layer, client_tls, client_tls) # 3. In Http Proxy mode and Upstream Proxy mode, the next layer is fixed. if isinstance(top_layer, protocol.TlsLayer): if isinstance(top_layer.ctx, modes.HttpProxy): return protocol.Http1Layer(top_layer, "regular") if isinstance(top_layer.ctx, modes.HttpUpstreamProxy): return protocol.Http1Layer(top_layer, "upstream") # 4. Check for other TLS cases (e.g. after CONNECT). if client_tls: return protocol.TlsLayer(top_layer, True, True) # 4. Check for --tcp if self.config.check_tcp(top_layer.server_conn.address): return protocol.RawTCPLayer(top_layer) # 5. Check for TLS ALPN (HTTP1/HTTP2) if isinstance(top_layer, protocol.TlsLayer): alpn = top_layer.client_conn.get_alpn_proto_negotiated() if alpn == b'h2': return protocol.Http2Layer(top_layer, 'transparent') if alpn == b'http/1.1': return protocol.Http1Layer(top_layer, 'transparent') # 6. Check for raw tcp mode is_ascii = ( len(d) == 3 and # expect A-Za-z all(65 <= x <= 90 or 97 <= x <= 122 for x in six.iterbytes(d))) if self.config.options.rawtcp and not is_ascii: return protocol.RawTCPLayer(top_layer) # 7. Assume HTTP1 by default return protocol.Http1Layer(top_layer, 'transparent')