diff --git a/src/Connection/Connection.py b/src/Connection/Connection.py index 27ae3734..4a7c6ab9 100644 --- a/src/Connection/Connection.py +++ b/src/Connection/Connection.py @@ -118,6 +118,9 @@ class Connection(object): # Open connection to peer and wait for handshake def connect(self): + if not self.event_connected or self.event_connected.ready(): + self.event_connected = gevent.event.AsyncResult() + self.type = "out" if self.ip_type == "onion": if not self.server.tor_manager or not self.server.tor_manager.enabled: @@ -148,37 +151,56 @@ class Connection(object): self.sock.connect(sock_address) - # Implicit SSL - should_encrypt = not self.ip_type == "onion" and self.ip not in self.server.broken_ssl_ips and self.ip not in config.ip_local - if self.cert_pin: - self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa", cert_pin=self.cert_pin) - self.sock.do_handshake() - self.crypt = "tls-rsa" - self.sock_wrapped = True - elif should_encrypt and "tls-rsa" in CryptConnection.manager.crypt_supported: + if self.shouldEncrypt(): try: - self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa") - self.sock.do_handshake() - self.crypt = "tls-rsa" - self.sock_wrapped = True + self.wrapSocket() except Exception as err: - if not config.force_encryption: - self.log("Crypt connection error, adding %s:%s as broken ssl. %s" % (self.ip, self.port, Debug.formatException(err))) - self.server.broken_ssl_ips[self.ip] = True - self.sock.close() - self.crypt = None - self.sock = self.createSocket() - self.sock.settimeout(30) - self.sock.connect(sock_address) + if self.sock: + self.sock.close() + self.sock = None + if self.mustEncrypt(): + raise + self.log("Crypt connection error, adding %s:%s as broken ssl. %s" % (self.ip, self.port, Debug.formatException(err))) + self.server.broken_ssl_ips[self.ip] = True + return self.connect() # Detect protocol - self.send({"cmd": "handshake", "req_id": 0, "params": self.getHandshakeInfo()}) event_connected = self.event_connected + self.send({"cmd": "handshake", "req_id": 0, "params": self.getHandshakeInfo()}) gevent.spawn(self.messageLoop) connect_res = event_connected.get() # Wait for handshake - self.sock.settimeout(timeout_before) + if self.sock: + self.sock.settimeout(timeout_before) return connect_res + def mustEncrypt(self): + if self.cert_pin: + return True + if (not self.ip_type == "onion") and config.force_encryption: + return True + return False + + def shouldEncrypt(self): + if self.mustEncrypt(): + return True + return ( + (not self.ip_type == "onion") + and + (self.ip not in self.server.broken_ssl_ips) + and + (self.ip not in config.ip_local) + and + ("tls-rsa" in CryptConnection.manager.crypt_supported) + ) + + def wrapSocket(self, crypt="tls-rsa", do_handshake=True): + server = (self.type == "in") + sock = CryptConnection.manager.wrapSocket(self.sock, crypt, server=server, cert_pin=self.cert_pin) + sock.do_handshake() + self.crypt = crypt + self.sock_wrapped = True + self.sock = sock + # Handle incoming connection def handleIncomingConnection(self, sock): self.log("Incoming connection...") @@ -192,9 +214,7 @@ class Connection(object): first_byte = sock.recv(1, gevent.socket.MSG_PEEK) if first_byte == b"\x16": self.log("Crypt in connection using implicit SSL") - self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa", True) - self.sock_wrapped = True - self.crypt = "tls-rsa" + self.wrapSocket(do_handshake=False) except Exception as err: self.log("Socket peek error: %s" % Debug.formatException(err)) self.messageLoop() @@ -435,7 +455,6 @@ class Connection(object): self.updateName() self.event_connected.set(True) # Mark handshake as done - self.event_connected = None self.handshake_time = time.time() # Handle incoming message @@ -459,12 +478,10 @@ class Connection(object): self.last_ping_delay = ping # Server switched to crypt, lets do it also if not crypted already if message.get("crypt") and not self.sock_wrapped: - self.crypt = message["crypt"] + crypt = message["crypt"] server = (self.type == "in") - self.log("Crypt out connection using: %s (server side: %s, ping: %.3fs)..." % (self.crypt, server, ping)) - self.sock = CryptConnection.manager.wrapSocket(self.sock, self.crypt, server, cert_pin=self.cert_pin) - self.sock.do_handshake() - self.sock_wrapped = True + self.log("Crypt out connection using: %s (server side: %s, ping: %.3fs)..." % (crypt, server, ping)) + self.wrapSocket(crypt) if not self.sock_wrapped and self.cert_pin: self.close("Crypt connection error: Socket not encrypted, but certificate pin present") @@ -492,8 +509,7 @@ class Connection(object): server = (self.type == "in") self.log("Crypt in connection using: %s (server side: %s)..." % (self.crypt, server)) try: - self.sock = CryptConnection.manager.wrapSocket(self.sock, self.crypt, server, cert_pin=self.cert_pin) - self.sock_wrapped = True + self.wrapSocket(self.crypt) except Exception as err: if not config.force_encryption: self.log("Crypt connection error, adding %s:%s as broken ssl. %s" % (self.ip, self.port, Debug.formatException(err))) @@ -640,6 +656,10 @@ class Connection(object): self.sock = None self.unpacker = None self.event_connected = None + self.crypt = None + self.sock_wrapped = False + + return True def updateOnlineStatus(self, outgoing_activity=False, successful_activity=False): self.server.updateOnlineStatus(self, diff --git a/src/Peer/Peer.py b/src/Peer/Peer.py index 0a518fdc..2e809b26 100644 --- a/src/Peer/Peer.py +++ b/src/Peer/Peer.py @@ -33,6 +33,7 @@ class Peer(object): self.key = "%s:%s" % (ip, port) self.log_level = logging.DEBUG + self.connection_error_log_level = logging.DEBUG self.connection = None self.connection_server = connection_server @@ -61,8 +62,10 @@ class Peer(object): else: return getattr(self, key) - def log(self, text): - if self.log_level <= logging.DEBUG: + def log(self, text, log_level = None): + if log_level is None: + log_level = self.log_level + if log_level <= logging.DEBUG: if not config.verbose: return # Only log if we are in debug mode @@ -73,7 +76,7 @@ class Peer(object): else: logger = logging.getLogger() - logger.log(self.log_level, "%s:%s %s" % (self.ip, self.port, text)) + logger.log(log_level, "%s:%s %s" % (self.ip, self.port, text)) # Site marks its Peers protected, if it has not enough peers connected. # This is to be used to prevent disconnecting from peers when doing @@ -124,12 +127,14 @@ class Peer(object): import main connection_server = main.file_server self.connection = connection_server.getConnection(self.ip, self.port, site=self.site, is_tracker_connection=self.is_tracker_connection) - self.reputation += 1 - self.connection.sites += 1 + if self.connection and self.connection.connected: + self.reputation += 1 + self.connection.sites += 1 except Exception as err: self.onConnectionError("Getting connection error") self.log("Getting connection error: %s (connection_error: %s, hash_failed: %s)" % - (Debug.formatException(err), self.connection_error, self.hash_failed)) + (Debug.formatException(err), self.connection_error, self.hash_failed), + log_level=self.connection_error_log_level) self.connection = None return self.connection