def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ self._tlsConnection = self.factory._createConnection(self) self._appSendBuffer = [] # Add interfaces provided by the transport we are wrapping: for interface in providedBy(transport): directlyProvides(self, interface) # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. try: self._tlsConnection.do_handshake() except WantReadError: # This is the expected case - there's no data in the connection's # input buffer yet, so it won't be able to complete the whole # handshake now. If this is the speak-first side of the # connection, then some bytes will be in the send buffer now; flush # them. self._flushSendBIO()
def parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. """ if self.flavor == HYBI00: parser = parse_hybi00_frames elif self.flavor in (HYBI07, HYBI10, RFC6455): parser = parse_hybi07_frames else: raise WSException("Unknown flavor %r" % self.flavor) try: frames, self.buf = parser(self.buf) except WSException as wse: # Couldn't parse all the frames, something went wrong, let's bail. self.close(wse.args[0]) return for frame in frames: opcode, data = frame if opcode == NORMAL: # Business as usual. Decode the frame, if we have a decoder. if self.codec: data = decoders[self.codec](data) # Pass the frame to the underlying protocol. ProtocolWrapper.dataReceived(self, data) elif opcode == CLOSE: # The other side wants us to close. I wonder why? reason, text = data log.msg("Closing connection: %r (%d)" % (text, reason)) # Close the connection. self.close()
def connectionMade(self): """ Log the new connection and initialize the buffer list. """ ProtocolWrapper.connectionMade(self) log.msg("Opening connection with %s" % self.transport.getPeer()) self._buffer = []
def connectionLost(self, reason): # type: (AnyStr) -> None # reason = [Failure instance: Traceback (failure with no # frames): <class 'twisted.internet.error.ConnectionDone'>: # Connection was closed cleanly. ] (<type 'instance'>) self.clear() ProtocolWrapper.connectionLost(self, reason)
def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ self._tlsConnection = self.factory._createConnection(self) self._appSendBuffer = [] # Add interfaces provided by the transport we are wrapping: for interface in providedBy(transport): directlyProvides(self, interface) # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. self._checkHandshakeStatus()
def __init__(self, factory, wrappedProtocol): ProtocolWrapper.__init__(self, factory, wrappedProtocol) AsyncStateMachine.__init__(self) self.fakeSocket = _FakeSocket(self) self.tlsConnection = TLSConnection(self.fakeSocket) self.tlsStarted = False self.connectionLostCalled = False
def writeSequence(self, data): # type: (List[bytes]) -> None if not self.tlsStarted: ProtocolWrapper.writeSequence(self, b''.join(data)) return self.write(b''.join(data))
def writeSequence(self, seq): if not self.tlsStarted: ProtocolWrapper.writeSequence(self, seq) else: #Because of the FakeSocket, write operations are guaranteed to #terminate immediately. AsyncStateMachine.setWriteOp(self, "".join(seq))
def parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. """ try: frames, self.buf = parse_hybi07_frames(self.buf) except WSException: # Couldn't parse all the frames, something went wrong, let's bail. log.err() self.loseConnection() return for frame in frames: opcode, data = frame if opcode == NORMAL: # Business as usual. Decode the frame, if we have a decoder. if self.codec: data = decoders[self.codec](data) # Pass the frame to the underlying protocol. ProtocolWrapper.dataReceived(self, data) elif opcode == CLOSE: # The other side wants us to close. I wonder why? reason, text = data log.msg("Closing connection: %r (%d)" % (text, reason)) # Close the connection. self.loseConnection() return elif opcode == PING: # 5.5.2 PINGs must be responded to with PONGs. # 5.5.3 PONGs must contain the data that was sent with the # provoking PING. raise AssertionError("this doesn't work") # due to unknown symbol below
def parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. """ try: frames, self.buf = parse_hybi07_frames(self.buf) except WSException: # Couldn't parse all the frames, something went wrong, let's bail. log.err() self.loseConnection() return for frame in frames: opcode, data = frame if opcode == NORMAL: # Business as usual. Decode the frame, if we have a decoder. if self.codec: data = decoders[self.codec](data) # Pass the frame to the underlying protocol. ProtocolWrapper.dataReceived(self, data) elif opcode == CLOSE: # The other side wants us to close. I wonder why? reason, text = data log.msg("Closing connection: %r (%d)" % (text, reason)) # Close the connection. self.loseConnection() return elif opcode == PING: # 5.5.2 PINGs must be responded to with PONGs. # 5.5.3 PONGs must contain the data that was sent with the # provoking PING. raise AssertionError( "this doesn't work") # due to unknown symbol below
def dataReceived(self, data): """ Append the data to the buffer list and parse the whole. """ self._buffer.append(data) if self.challenge: buf = "".join(self._buffer) if len(buf) >= 8: challenge, buf = buf[:8], buf[8:] self._buffer = [buf] nonce = self.challenge(challenge) self.transport.write(nonce) self.challenge = None if self.connected: ProtocolWrapper.connectionMade(self) self.dataReceived("") # Kick it off proper if self.pending_dc: self.pending_dc = False self.loseConnection() else: self._parseFrames() if self._pending_frames: self._sendFrames() self._parseFrames()
def _parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. """ try: frames, rest = _parseFrames("".join(self._buffer)) except _WSException: # Couldn't parse all the frames, something went wrong, let's bail. log.err() self.loseConnection() return self._buffer[:] = [rest] for frame in frames: opcode, data = frame if opcode == _CONTROLS.NORMAL: # Business as usual. Decode the frame, if we have a decoder. # Pass the frame to the underlying protocol. ProtocolWrapper.dataReceived(self, data) elif opcode == _CONTROLS.CLOSE: # The other side wants us to close. I wonder why? reason, text = data log.msg("Closing connection: %r (%d)" % (text, reason)) # Close the connection. self.loseConnection() return elif opcode == _CONTROLS.PING: # 5.5.2 PINGs must be responded to with PONGs. # 5.5.3 PONGs must contain the data that was sent with the # provoking PING. self.transport.write(_makeFrame(data, _opcode=_CONTROLS.PONG))
def makeConnection(self, transport): """ Fire the Deferred at C{self.factory.connectionNotification} with the real protocol. """ ProtocolWrapper.makeConnection(self, transport) self.factory.connectionNotification.callback(self.wrappedProtocol)
def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ tlsContext = self.factory._contextFactory.getContext() self._tlsConnection = Connection(tlsContext, None) if self.factory._isClient: self._tlsConnection.set_connect_state() else: self._tlsConnection.set_accept_state() self._appSendBuffer = [] # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. try: self._tlsConnection.do_handshake() except WantReadError: # This is the expected case - there's no data in the connection's # input buffer yet, so it won't be able to complete the whole # handshake now. If this is the speak-first side of the # connection, then some bytes will be in the send buffer now; flush # them. self._flushSendBIO()
def __init__(self, factory, wrappedProtocol, connectedDeferred, host, port): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectedDeferred = connectedDeferred self._host = host self._port = port self._buf = b'' self.state = 0
def writeSequence(self, data): if debug: print 'TwistedProtocolWrapper.writeSequence' if not self.tlsStarted: ProtocolWrapper.writeSequence(self, ''.join(data)) return self.write(''.join(data))
def __init__(self, factory, wrappedProtocol, connectedDeferred, host, port, optimistic = False): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectedDeferred = connectedDeferred self._host = host self._port = port self._optimistic = optimistic self._buf = '' self.state = 0
def dataReceived(self, data): if not data: return try: dat = json.loads(data) except ValueError: self.transport.loseConnection() else: for d in dat: ProtocolWrapper.dataReceived(self, d)
def dataReceived(self, data): if not data: return try: dat = json.loads(data) except ValueError: self.transport.loseConnection() else: for d in dat: d = normalize(d, self.parent._options['encoding']) ProtocolWrapper.dataReceived(self, d)
def dataReceived(self, data): try: if not self.tlsStarted: ProtocolWrapper.dataReceived(self, data) else: self.fakeSocket.data += data while self.fakeSocket.data: AsyncStateMachine.inReadEvent(self) except TLSError, e: self.connectionLost(Failure(e)) ProtocolWrapper.loseConnection(self)
def _clientHello(self): try: # We rely on OpenSSL implicitly starting with client hello # when we haven't yet established an SSL connection encryptedData = self._encrypt(clientHello=1) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 except M2Crypto.BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e
def __init__(self, *args, **kwargs): ProtocolWrapper.__init__(self, *args, **kwargs) self.buf = '' self.codec = None self.location = '/' self.host = '' self.origin = '' self.version = None self.state = HANDSHAKE self.pending_frames = [] self.protocols = [] self.headers = {}
def _clientHello(self): try: # We rely on OpenSSL implicitly starting with client hello # when we haven't yet established an SSL connection encryptedData = self._encrypt(clientHello=1) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e
def _flushReceiveBIO(self): """ Try to receive any application-level bytes which are now available because of a previous write into the receive BIO. This will take care of delivering any application-level bytes which are received to the protocol, as well as handling of the various exceptions which can come from trying to get such bytes. """ # Keep trying this until an error indicates we should stop or we # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2 ** 15) except WantReadError: # The newly received bytes might not have been enough to produce # any application data. break except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. self._shutdownTLS() # Passing in None means the user protocol's connnectionLost # will get called with reason from underlying transport: self._tlsShutdownFinished(None) except Error as e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # Squash EOF in violation of protocol into ConnectionLost; we # create Failure before calling _flushSendBio so that no new # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() self._flushSendBIO() self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshakeDone = True if not self._aborted: ProtocolWrapper.dataReceived(self, bytes) # The received bytes might have generated a response which needs to be # sent now. For example, the handshake involves several round-trip # exchanges without ever producing application-bytes. self._flushSendBIO()
def _flushReceiveBIO(self): """ Try to receive any application-level bytes which are now available because of a previous write into the receive BIO. This will take care of delivering any application-level bytes which are received to the protocol, as well as handling of the various exceptions which can come from trying to get such bytes. """ # Keep trying this until an error indicates we should stop or we # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2**15) except WantReadError: # The newly received bytes might not have been enough to produce # any application data. break except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. self._shutdownTLS() # Passing in None means the user protocol's connnectionLost # will get called with reason from underlying transport: self._tlsShutdownFinished(None) except Error as e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # Squash EOF in violation of protocol into ConnectionLost; we # create Failure before calling _flushSendBio so that no new # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() self._flushSendBIO() self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshakeDone = True if not self._aborted: ProtocolWrapper.dataReceived(self, bytes) # The received bytes might have generated a response which needs to be # sent now. For example, the handshake involves several round-trip # exchanges without ever producing application-bytes. self._flushSendBIO()
def write(self, data): if not self.tlsStarted: ProtocolWrapper.write(self, data) return try: encryptedData = self._encrypt(data) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 except M2Crypto.BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e
def __init__(self, factory, wrappedProtocol, connectedDeferred, host, port, optimistic=False): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectedDeferred = connectedDeferred self._host = host self._port = port self._optimistic = optimistic self._buf = '' self.state = 0
def parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. """ try: frames, self.buf = parse_hybi07_frames(self.buf) except WSException: # Couldn't parse all the frames, something went wrong, let's bail. log.err() self.loseConnection() return for frame in frames: opcode, data, fin = frame if opcode == NORMAL: # Business as usual. Decode the frame, if we have a decoder. if self.codec: self.complete_data += decoders[self.codec](data) # If no decoder, just tack it on as is to any previous frame data. else: self.complete_data += data # If FIN bit is set this is the last data frame in this context. if fin: # Pass the data compiled from the frames to the underlying protocol. ProtocolWrapper.dataReceived(self, self.complete_data) self.complete_data = "" elif opcode == CLOSE: # The other side wants us to close. I wonder why? reason, text = data log.msg("Closing connection: %r (%d)" % (text, reason)) # Close the connection. self.loseConnection() return elif opcode == PING: # 5.5.2 PINGs must be responded to with PONGs. # 5.5.3 PONGs must contain the data that was sent with the # provoking PING. pong_data = data # DJM/JW - Chrome v39+ Websockets code breaks when you follow 5.5.3! if self.dumb_pong: pong_data = "" self.transport.write( make_hybi07_frame(pong_data, opcode=PONG) ) # DJM - this used to say make_hybi07_packet() but there is no definition for that!
def connectionLost(self, reason): """ Handle the possible repetition of calls to this method (due to either the underlying transport going away or due to an error at the TLS layer) and make sure the base implementation only gets invoked once. """ if not self._lostTLSConnection: # Tell the TLS connection that it's not going to get any more data # and give it a chance to finish reading. self._tlsConnection.bio_shutdown() self._flushReceiveBIO() self._lostTLSConnection = True reason = self._reason or reason self._reason = None ProtocolWrapper.connectionLost(self, reason)
def actuallyWrite(self): if self.writeLimit is None: data = self.buf self.buf = '' else: data = self.buf[:self.writeLimit] self.buf = self.buf[self.writeLimit:] ProtocolWrapper.write(self, data) if data != '': self.writesOutstanding = True reactor.callLater(1, self.actuallyWrite) else: self.writesOutstanding = False if self.loseConnectionWhenReady: self.actuallyLoseConnection()
def getPeer(self): if self.parent._options["proxy_header"] and self.request.requestHeaders.hasHeader(self.parent._options["proxy_header"]): ip = self.request.requestHeaders.getRawHeaders(self.parent._options["proxy_header"])[0].decode().split(",")[-1].strip() if re.match("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", ip): return address.IPv4Address("TCP", ip, None) else: return address.IPv6Address("TCP", ip, None) return ProtocolWrapper.getPeer(self)
def getPeer(self): if self.parent._options["proxy_header"] and self.request.requestHeaders.hasHeader(self.parent._options["proxy_header"]): ip = self.request.requestHeaders.getRawHeaders(self.parent._options["proxy_header"])[0].split(",")[-1].strip() if re.match("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", ip): return address.IPv4Address("TCP", ip, None) else: return address.IPv6Address("TCP", ip, None) return ProtocolWrapper.getPeer(self)
def loseConnection(self): """ Close the connection. This includes telling the other side we're closing the connection. If the other side didn't signal that the connection is being closed, then we might not see their last message, but since their last message should, according to the spec, be a simple acknowledgement, it shouldn't be a problem. """ # Send a closing frame. It's only polite. (And might keep the browser # from hanging.) if not self.disconnecting: frame = _makeFrame("", _opcode=_CONTROLS.CLOSE) self.transport.write(frame) ProtocolWrapper.loseConnection(self)
def dataReceived(self, data): self.buf += data if self.challenge: if len(self.buf) >= 8: challenge, self.buf = self.buf[:8], self.buf[8:] nonce = self.challenge(challenge) self.transport.write(nonce) self.challenge = None if self.connected: ProtocolWrapper.connectionMade(self) self.dataReceived("") # Kick it off proper if self.pending_dc: self.pending_dc = False self.loseConnection() else: self.parseFrames() if self._pending_frames: self.sendFrames()
def parseFrames(self): """ Find frames in incoming data and pass them to the underlying protocol. """ start = self.buf.find("\x00") while start != -1: end = self.buf.find("\xff") if end == -1: # Incomplete frame, try again later. return else: frame, self.buf = self.buf[start + 1:end], self.buf[end + 1:] # Decode the frame, if we have a decoder. if self.codec: frame = decoders[self.codec](frame) # Pass the frame to the underlying protocol. ProtocolWrapper.dataReceived(self, frame) start = self.buf.find("\x00")
def handle_frames(self): """ Use the correct frame parser and send parsed data to the underlying protocol """ if self.version == HYBI00: frame_parser = HyBi00Frame(self.buf) elif self.version in (HYBI07, HYBI10, RFC6455): frame_parser = HyBi07Frame(self.buf) else: raise InvalidProtocolVersion( 'Unknown version {!r}'.format(self.version) ) try: frames, self.buf = frame_parser.parse() except WebSocketError as error: log.err(error) self.close(error) return for frame in frames: opcode, data = frame if opcode == DATA: # pass the frame to the underlying protocol ProtocolWrapper.dataReceived(self, data) elif opcode == CLOSE: # the other side want's to close reason, text = data log.msg('Closing connection: {!r} ({:d})'.format( text, reason )) # close the connection self.close() elif opcode == PING: # send pong self.transport.write( HyBi07Frame(data).generate(0xa) )
def parseFrames(self): try: frames, self.buf = _parseFrames(self.buf, self.old) except _WSException: log.err() self.loseConnection() return for frame in frames: opcode, data = frame if opcode == _CONTROLS.NORMAL: if self.codec: data = _decoders[self.codec](data) ProtocolWrapper.dataReceived(self, data) elif opcode == _CONTROLS.CLOSE: reason, text = data log.msg("Closing connection: %r (%d)" % (text, reason)) self.transport.loseConnection() return elif opcode == _CONTROLS.PING: self.transport.write(_makeFrame(data, self.old, _opcode=_CONTROLS.PONG))
def dataReceived(self, data): if not self.tlsStarted: ProtocolWrapper.dataReceived(self, data) return self.encrypted += data try: while 1: decryptedData = self._decrypt() self._check() encryptedData = self._encrypt() ProtocolWrapper.write(self, encryptedData) ProtocolWrapper.dataReceived(self, decryptedData) if decryptedData == '' and encryptedData == '': break except M2Crypto.BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e
def buildProtocol(self, addr): if (self.connectionLimit is None or self.connectionCount < self.connectionLimit): # Build the normal protocol wrappedProtocol = self.protocol() elif self.overflowProtocol is None: # Just drop the connection log.limit_reached(Config.modbus.name, str(addr)) return None else: # Too many connections, so build the overflow protocol wrappedProtocol = self.overflowProtocol() wrappedProtocol.factory = self protocol = ProtocolWrapper(self, wrappedProtocol) self.connectionCount += 1 return protocol
def __init__(self, *args, **kwargs): ProtocolWrapper.__init__(self, *args, **kwargs) self.pending_frames = []