def bm_command_version(self): self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \ self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv") self.nonce = struct.pack('>Q', self.nonce) self.timeOffset = self.timestamp - int(time.time()) logger.debug("remoteProtocolVersion: %i", self.remoteProtocolVersion) logger.debug("services: 0x%08X", self.services) logger.debug("time offset: %i", self.timestamp - int(time.time())) logger.debug("my external IP: %s", self.sockNode.host) logger.debug("remote node incoming address: %s:%i", self.destination.host, self.peerNode.port) logger.debug("user agent: %s", self.userAgent) logger.debug("streams: [%s]", ",".join(map(str,self.streams))) if not self.peerValidityChecks(): # TODO ABORT return True #shared.connectedHostsList[self.destination] = self.streams[0] self.append_write_buf(protocol.CreatePacket('verack')) self.verackSent = True if not self.isOutbound: self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ network.connectionpool.BMConnectionPool().streams, True, nodeid=self.nodeid)) #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.isOutbound)): self.isSSL = True if self.verackReceived: if self.isSSL: self.set_state("tls_init", length=self.payloadLength, expectBytes=0) return False self.set_state("connection_fully_established", length=self.payloadLength, expectBytes=0) return False return True
def bm_command_version(self): self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \ self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv") self.nonce = struct.pack('>Q', self.nonce) self.timeOffset = self.timestamp - int(time.time()) logger.debug("remoteProtocolVersion: %i", self.remoteProtocolVersion) logger.debug("services: 0x%08X", self.services) logger.debug("time offset: %i", self.timestamp - int(time.time())) logger.debug("my external IP: %s", self.sockNode.host) logger.debug("remote node incoming address: %s:%i", self.destination.host, self.peerNode.port) logger.debug("user agent: %s", self.userAgent) logger.debug("streams: [%s]", ",".join(map(str,self.streams))) if not self.peerValidityChecks(): # TODO ABORT return True #shared.connectedHostsList[self.destination] = self.streams[0] self.append_write_buf(protocol.CreatePacket('verack')) self.verackSent = True if not self.isOutbound: self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ network.connectionpool.BMConnectionPool().streams, True, nodeid=self.nodeid)) #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.isOutbound)): self.isSSL = True if self.verackReceived: if self.isSSL: self.set_state("tls_init", length=self.payloadLength, expectBytes=0) return False self.set_state("connection_fully_established", length=self.payloadLength, expectBytes=0) return False return True
def sslHandshake(self): self.sslSock = self.sock if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") if sys.version_info >= (2,7,9): context = ssl.SSLContext(protocol.sslProtocolVersion) context.set_ciphers(protocol.sslProtocolCiphers) context.set_ecdh_curve("secp256k1") context.check_hostname = False context.verify_mode = ssl.CERT_NONE # also exclude TLSv1 and TLSv1.1 in the future context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE self.sslSock = context.wrap_socket(self.sock, server_side = not self.initiatedConnection, do_handshake_on_connect=False) else: self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=protocol.sslProtocolVersion, do_handshake_on_connect=False, ciphers=protocol.sslProtocolCiphers) self.sendDataThreadQueue.join() while True: try: self.sslSock.do_handshake() logger.debug("TLS handshake success") if sys.version_info >= (2, 7, 9): logger.debug("TLS protocol version: %s", self.sslSock.version()) break except ssl.SSLError as e: if sys.hexversion >= 0x02070900: if isinstance (e, ssl.SSLWantReadError): logger.debug("Waiting for SSL socket handhake read") select.select([self.sslSock], [], [], 10) continue elif isinstance (e, ssl.SSLWantWriteError): logger.debug("Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) continue else: if e.args[0] == ssl.SSL_ERROR_WANT_READ: logger.debug("Waiting for SSL socket handhake read") select.select([self.sslSock], [], [], 10) continue elif e.args[0] == ssl.SSL_ERROR_WANT_WRITE: logger.debug("Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) continue logger.error("SSL socket handhake failed: shutting down connection, %s", str(e)) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail %s' % (str(e)))) return False except socket.error as err: logger.debug('SSL socket handshake failed, shutting down connection, %s', str(err)) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) return False except Exception: logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) return False # SSL in the background should be blocking, otherwise the error handling is difficult self.sslSock.settimeout(None) return True # no SSL return True
def connectionFullyEstablished(self): if self.connectionIsOrWasFullyEstablished: # there is no reason to run this function a second time return if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): try: self.sslHandshake() except socket.error as ex: logger.error("SSL socket handshake failed, shutting down connection", exc_info=(type(ex), ex, None)) self.sendDataThreadQueue.put((0, 'shutdown', None)) return self.connectionIsOrWasFullyEstablished = True shared.timeOffsetWrongCount = 0 # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sock))) if not self.initiatedConnection: shared.clientHasReceivedIncomingConnections = True queues.UISignalQueue.put(('setStatusIcon', 'green')) self.sock.settimeout( 600) # We'll send out a ping every 5 minutes to make sure the connection stays alive if there has been no other traffic to send lately. queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) logger.debug('Connection fully established with ' + str(self.peer) + "\n" + \ 'The size of the connectedHostsList is now ' + str(len(shared.connectedHostsList)) + "\n" + \ 'The length of sendDataQueues is now: ' + str(len(state.sendDataQueues)) + "\n" + \ 'broadcasting addr from within connectionFullyEstablished function.') if self.initiatedConnection: state.networkProtocolAvailability[protocol.networkType(self.peer.host)] = True # we need to send our own objects to this node PendingUpload().add() self.sendaddr() # This is one large addr message to this one peer. if len(shared.connectedHostsList) > \ BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200): logger.info ('We are connected to too many people. Closing connection.') if self.initiatedConnection: self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Thank you for providing a listening node."))) else: self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Server full, please try again later."))) self.sendDataThreadQueue.put((0, 'shutdown','no data')) return self.sendBigInv()
def sendBytes(self, data=""): self.buffer += data if len(self.buffer) < throttle.SendThrottle( ).chunkSize and self.sendDataThreadQueue.qsize() > 1: return True while self.buffer and state.shutdown == 0: isSSL = False try: if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): isSSL = True amountSent = self.sslSock.send( self.buffer[:throttle.SendThrottle().chunkSize]) else: amountSent = self.sock.send( self.buffer[:throttle.SendThrottle().chunkSize]) except socket.timeout: continue except SSLError as e: if e.errno == SSL_ERROR_WANT_WRITE: select.select([], [self.sslSock], [], 10) logger.debug('sock.recv retriable SSL error') continue logger.debug('Connection error (SSL)') return False except socket.error as e: if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ e.errno == errno.WSAEWOULDBLOCK): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue if e.errno in (errno.EPIPE, errno.ECONNRESET, errno.EHOSTUNREACH, errno.ETIMEDOUT): logger.debug( 'Connection error (EPIPE/ECONNRESET/EHOSTUNREACH/ETIMEDOUT)' ) return False raise throttle.SendThrottle().wait(amountSent) self.lastTimeISentData = int(time.time()) self.buffer = self.buffer[amountSent:] return True
def bm_command_version(self): """ Incoming version. Parse and log, remember important things, like streams, bitfields, etc. """ decoded = self.decode_payload_content("IQQiiQlslv") (self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, self.userAgent) = decoded[:7] self.streams = decoded[7:] self.nonce = struct.pack('>Q', self.nonce) self.timeOffset = self.timestamp - int(time.time()) logger.debug('remoteProtocolVersion: %i', self.remoteProtocolVersion) logger.debug('services: 0x%08X', self.services) logger.debug('time offset: %i', self.timeOffset) logger.debug('my external IP: %s', self.sockNode.host) logger.debug('remote node incoming address: %s:%i', self.destination.host, self.peerNode.port) logger.debug('user agent: %s', self.userAgent) logger.debug('streams: [%s]', ','.join(map(str, self.streams))) if not self.peerValidityChecks(): # ABORT afterwards return True self.append_write_buf(protocol.CreatePacket('verack')) self.verackSent = True if not self.isOutbound: self.append_write_buf( protocol.assembleVersionMessage( self.destination.host, self.destination.port, connectionpool.BMConnectionPool().streams, True, nodeid=self.nodeid)) logger.debug('%(host)s:%(port)i sending version', self.destination._asdict()) if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.isOutbound)): self.isSSL = True if not self.verackReceived: return True self.set_state( "tls_init" if self.isSSL else "connection_fully_established", length=self.payloadLength, expectBytes=0) return False
def sendBytes(self, data = ""): self.buffer += data if len(self.buffer) < throttle.SendThrottle().chunkSize and self.sendDataThreadQueue.qsize() > 1: return True while self.buffer and state.shutdown == 0: isSSL = False try: if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): isSSL = True amountSent = self.sslSock.send(self.buffer[:throttle.SendThrottle().chunkSize]) else: amountSent = self.sock.send(self.buffer[:throttle.SendThrottle().chunkSize]) except socket.timeout: continue except SSLError as e: if e.errno == SSL_ERROR_WANT_WRITE: select.select([], [self.sslSock], [], 10) logger.debug('sock.recv retriable SSL error') continue logger.debug('Connection error (SSL)') return False except socket.error as e: if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ e.errno == errno.WSAEWOULDBLOCK): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue if e.errno in (errno.EPIPE, errno.ECONNRESET, errno.EHOSTUNREACH, errno.ETIMEDOUT, errno.ECONNREFUSED): logger.debug('Connection error: %s', str(e)) return False raise throttle.SendThrottle().wait(amountSent) self.lastTimeISentData = int(time.time()) self.buffer = self.buffer[amountSent:] return True
def run(self): logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) while state.shutdown == 0: dataLen = len(self.data) try: isSSL = False if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): isSSL = True dataRecv = self.sslSock.recv( throttle.ReceiveThrottle().chunkSize) else: dataRecv = self.sock.recv( throttle.ReceiveThrottle().chunkSize) self.data += dataRecv throttle.ReceiveThrottle().wait(len(dataRecv)) except socket.timeout: if self.connectionIsOrWasFullyEstablished: self.sendping("Still around!") continue logger.error("Timeout during protocol initialisation") break except ssl.SSLError as err: if err.errno == ssl.SSL_ERROR_WANT_READ: select.select([self.sslSock], [], [], 10) logger.debug('sock.recv retriable SSL error') continue if err.errno is None and 'timed out' in str(err): if self.connectionIsOrWasFullyEstablished: self.sendping("Still around!") continue logger.error('SSL error: %i/%s', err.errno if err.errno else 0, str(err)) break except socket.error as err: if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ err.errno == errno.WSAEWOULDBLOCK): select.select([self.sslSock if isSSL else self.sock], [], [], 10) logger.debug('sock.recv retriable error') continue logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) break # print 'Received', repr(self.data) if len(self.data ) == dataLen: # If self.sock.recv returned no data: logger.debug('Connection to ' + str(self.peer) + ' closed. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break else: self.processData() try: for stream in self.streamNumber: try: del self.selfInitiatedConnections[stream][self] except KeyError: pass logger.debug( 'removed self (a receiveDataThread) from selfInitiatedConnections' ) except: pass self.sendDataThreadQueue.put( (0, 'shutdown', 'no data') ) # commands the corresponding sendDataThread to shut itself down. try: del shared.connectedHostsList[self.hostIdent] except Exception as err: logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) PendingDownload().threadEnd() queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.checkTimeOffsetNotification() logger.debug('receiveDataThread ending. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList)))
def sslHandshake(self): self.sslSock = self.sock if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") if sys.version_info >= (2, 7, 9): context = ssl.SSLContext(protocol.sslProtocolVersion) context.set_ciphers(protocol.sslProtocolCiphers) context.set_ecdh_curve("secp256k1") context.check_hostname = False context.verify_mode = ssl.CERT_NONE # also exclude TLSv1 and TLSv1.1 in the future context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE self.sslSock = context.wrap_socket( self.sock, server_side=not self.initiatedConnection, do_handshake_on_connect=False) else: self.sslSock = ssl.wrap_socket( self.sock, keyfile=os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile=os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side=not self.initiatedConnection, ssl_version=protocol.sslProtocolVersion, do_handshake_on_connect=False, ciphers=protocol.sslProtocolCiphers) self.sendDataThreadQueue.join() while True: try: self.sslSock.do_handshake() logger.debug("TLS handshake success") break except ssl.SSLError as e: if sys.hexversion >= 0x02070900: if isinstance(e, ssl.SSLWantReadError): logger.debug( "Waiting for SSL socket handhake read") select.select([self.sslSock], [], [], 10) continue elif isinstance(e, ssl.SSLWantWriteError): logger.debug( "Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) continue else: if e.args[0] == ssl.SSL_ERROR_WANT_READ: logger.debug( "Waiting for SSL socket handhake read") select.select([self.sslSock], [], [], 10) continue elif e.args[0] == ssl.SSL_ERROR_WANT_WRITE: logger.debug( "Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) continue logger.error( "SSL socket handhake failed: %s, shutting down connection", str(e)) self.sendDataThreadQueue.put( (0, 'shutdown', 'tls handshake fail %s' % (str(e)))) return False except Exception: logger.error( "SSL socket handhake failed, shutting down connection", exc_info=True) self.sendDataThreadQueue.put( (0, 'shutdown', 'tls handshake fail')) return False # SSL in the background should be blocking, otherwise the error handling is difficult self.sslSock.settimeout(None) return True # no SSL return True
def run(self): logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) while state.shutdown == 0: dataLen = len(self.data) try: isSSL = False if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): isSSL = True dataRecv = self.sslSock.recv(throttle.ReceiveThrottle().chunkSize) else: dataRecv = self.sock.recv(throttle.ReceiveThrottle().chunkSize) self.data += dataRecv throttle.ReceiveThrottle().wait(len(dataRecv)) except socket.timeout: if self.connectionIsOrWasFullyEstablished: self.sendping("Still around!") continue logger.error("Timeout during protocol initialisation") break except ssl.SSLError as err: if err.errno == ssl.SSL_ERROR_WANT_READ: select.select([self.sslSock], [], [], 10) logger.debug('sock.recv retriable SSL error') continue if err.errno is None and 'timed out' in str(err): if self.connectionIsOrWasFullyEstablished: self.sendping("Still around!") continue logger.error ('SSL error: %i/%s', err.errno if err.errno else 0, str(err)) break except socket.error as err: if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ err.errno == errno.WSAEWOULDBLOCK): select.select([self.sslSock if isSSL else self.sock], [], [], 10) logger.debug('sock.recv retriable error') continue logger.error('sock.recv error. Closing receiveData thread, %s', str(err)) break # print 'Received', repr(self.data) if len(self.data) == dataLen: # If self.sock.recv returned no data: logger.debug('Connection to ' + str(self.peer) + ' closed. Closing receiveData thread') break else: self.processData() try: for stream in self.streamNumber: try: del self.selfInitiatedConnections[stream][self] except KeyError: pass logger.debug('removed self (a receiveDataThread) from selfInitiatedConnections') except: pass self.sendDataThreadQueue.put((0, 'shutdown','no data')) # commands the corresponding sendDataThread to shut itself down. try: del shared.connectedHostsList[self.hostIdent] except Exception as err: logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.checkTimeOffsetNotification() logger.debug('receiveDataThread ending. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList)))