def test_copy(self): f = tflow.ttcpflow() f.get_state() f2 = f.copy() a = f.get_state() b = f2.get_state() del a["id"] del b["id"] assert a == b assert not f == f2 assert f is not f2 assert f.messages is not f2.messages for m in f.messages: assert m.get_state() m2 = m.copy() assert not m == m2 assert m is not m2 a = m.get_state() b = m2.get_state() assert a == b m = tcp.TCPMessage(False, 'foo') m.set_state(f.messages[0].get_state()) assert m.timestamp == f.messages[0].timestamp f = tflow.ttcpflow(err=True) f2 = f.copy() assert f is not f2 assert f.error.get_state() == f2.error.get_state() assert f.error is not f2.error
def relay_messages( self, event: events.ConnectionEvent) -> layer.CommandGenerator[None]: from_client = event.connection == self.context.client send_to: Connection if from_client: send_to = self.context.server else: send_to = self.context.client if isinstance(event, events.DataReceived): if self.flow: tcp_message = tcp.TCPMessage(from_client, event.data) self.flow.messages.append(tcp_message) yield TcpMessageHook(self.flow) yield commands.SendData(send_to, tcp_message.content) else: yield commands.SendData(send_to, event.data) elif isinstance(event, events.ConnectionClosed): all_done = not ( (self.context.client.state & ConnectionState.CAN_READ) or (self.context.server.state & ConnectionState.CAN_READ)) if all_done: if self.context.server.state is not ConnectionState.CLOSED: yield commands.CloseConnection(self.context.server) if self.context.client.state is not ConnectionState.CLOSED: yield commands.CloseConnection(self.context.client) self._handle_event = self.done if self.flow: yield TcpEndHook(self.flow) else: yield commands.CloseConnection(send_to, half_close=True)
def ttcpflow(client_conn=True, server_conn=True, messages=True, err=None): if client_conn is True: client_conn = tclient_conn() if server_conn is True: server_conn = tserver_conn() if messages is True: messages = [ tcp.TCPMessage(True, b"hello"), tcp.TCPMessage(False, b"it's me"), ] if err is True: err = terr() f = tcp.TCPFlow(client_conn, server_conn) f.messages = messages f.error = err f.reply = controller.DummyReply() return f
def inject_tcp(self, flow: Flow, to_client: bool, message: bytes): if not isinstance(flow, tcp.TCPFlow): ctx.log.warn("Cannot inject TCP messages into non-TCP flows.") event = TcpMessageInjected(flow, tcp.TCPMessage(not to_client, message)) try: self.inject_event(event) except ValueError as e: ctx.log.warn(str(e))
def __call__(self): self.connect() client = self.client_conn.connection server = self.server_conn.connection buf = memoryview(bytearray(self.chunk_size)) # send CONNECT, expect 200 OK connect_req = make_connect_request((self.host, self.port)) server.send(assemble_request(connect_req)) resp = server.recv(1024).decode() if not resp.startswith('HTTP/1.1 200 OK'): raise BubbleFlexPassthruException('CONNECT request error: ' + resp) conns = [client, server] # https://github.com/openssl/openssl/issues/6234 for conn in conns: if isinstance(conn, SSL.Connection) and hasattr( SSL._lib, "SSL_clear_mode"): SSL._lib.SSL_clear_mode(conn._ssl, SSL._lib.SSL_MODE_AUTO_RETRY) try: while not self.channel.should_exit.is_set(): r = ssl_read_select(conns, 10) for conn in r: dst = server if conn == client else client try: size = conn.recv_into(buf, self.chunk_size) except (SSL.WantReadError, SSL.WantWriteError): continue if not size: conns.remove(conn) # Shutdown connection to the other peer if isinstance(conn, SSL.Connection): # We can't half-close a connection, so we just close everything here. # Sockets will be cleaned up on a higher level. return else: dst.shutdown(socket.SHUT_WR) if len(conns) == 0: return continue tcp_message = tcp.TCPMessage(dst == server, buf[:size].tobytes()) dst.sendall(tcp_message.content) except (socket.error, exceptions.TcpException, SSL.Error) as e: bubble_log.error('exception: ' + repr(e))
def ttcpflow(client_conn=True, server_conn=True, messages=True, err=None) -> tcp.TCPFlow: if client_conn is True: client_conn = tclient_conn() if server_conn is True: server_conn = tserver_conn() if messages is True: messages = [ tcp.TCPMessage(True, b"hello", 946681204.2), tcp.TCPMessage(False, b"it's me", 946681204.5), ] if err is True: err = terr() f = tcp.TCPFlow(client_conn, server_conn) f.timestamp_created = client_conn.timestamp_start f.messages = messages f.error = err f.live = True return f
def relay_messages(self, event: events.Event) -> layer.CommandGenerator[None]: if isinstance(event, TcpMessageInjected): # we just spoof that we received data here and then process that regularly. event = events.DataReceived( self.context.client if event.message.from_client else self.context.server, event.message.content, ) assert isinstance(event, events.ConnectionEvent) from_client = event.connection == self.context.client send_to: Connection if from_client: send_to = self.context.server else: send_to = self.context.client if isinstance(event, events.DataReceived): if self.flow: tcp_message = tcp.TCPMessage(from_client, event.data) self.flow.messages.append(tcp_message) yield TcpMessageHook(self.flow) yield commands.SendData(send_to, tcp_message.content) else: yield commands.SendData(send_to, event.data) elif isinstance(event, events.ConnectionClosed): all_done = not ( (self.context.client.state & ConnectionState.CAN_READ) or (self.context.server.state & ConnectionState.CAN_READ)) if all_done: if self.context.server.state is not ConnectionState.CLOSED: yield commands.CloseConnection(self.context.server) if self.context.client.state is not ConnectionState.CLOSED: yield commands.CloseConnection(self.context.client) self._handle_event = self.done if self.flow: yield TcpEndHook(self.flow) self.flow.live = False else: yield commands.CloseConnection(send_to, half_close=True) else: raise AssertionError(f"Unexpected event: {event}")