Agent: Inject dependencies into TCPRelay

This commit is contained in:
Kekoa Kaaikala 2022-09-01 19:28:06 +00:00
parent 46573c9f2d
commit 62e4fb89bb
2 changed files with 77 additions and 41 deletions

View File

@ -9,6 +9,7 @@ from infection_monkey.network.relay import (
RelayUserHandler,
SocketsPipe,
TCPConnectionHandler,
TCPPipeSpawner,
)
DEFAULT_NEW_CLIENT_TIMEOUT = 3 # Wait up to 3 seconds for potential new clients to connect
@ -21,20 +22,18 @@ class TCPRelay(Thread):
def __init__(
self,
local_port: int,
target_addr: str,
target_port: int,
relay_user_handler: RelayUserHandler,
connection_handler: TCPConnectionHandler,
pipe_spawner: TCPPipeSpawner,
new_client_timeout: float = DEFAULT_NEW_CLIENT_TIMEOUT,
):
self._stopped = Event()
self._user_handler = RelayUserHandler()
self._connection_handler = TCPConnectionHandler(
local_port, client_connected=self._user_connected
)
self._local_port = local_port
self._target_addr = target_addr
self._target_port = target_port
self._user_handler = relay_user_handler
self._connection_handler = connection_handler
self._connection_handler.notify_client_connected(self._user_connected)
self._pipe_spawner = pipe_spawner
self._pipe_spawner.notify_client_data_received(self._user_handler.on_user_data_received)
self._new_client_timeout = new_client_timeout
super().__init__(name="MonkeyTcpRelayThread")
self.daemon = True
@ -60,16 +59,7 @@ class TCPRelay(Thread):
self._spawn_pipe(source)
def _spawn_pipe(self, source: socket.socket):
dest = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
dest.connect((self._target_addr, self._target_port))
except socket.error:
source.close()
dest.close()
pipe = SocketsPipe(
source, dest, client_data_received=self._user_handler.on_user_data_received
)
pipe = self._pipe_spawner.spawn_pipe(source)
self._pipes.append(pipe)
pipe.run()

View File

@ -1,9 +1,15 @@
import socket
from ipaddress import IPv4Address
from threading import Thread
from typing import Callable
from unittest.mock import MagicMock
import pytest
from monkey.infection_monkey.tcp_relay import RELAY_CONTROL_MESSAGE, TCPRelay
from monkey.infection_monkey.network.relay.relay_user_handler import ( # RELAY_CONTROL_MESSAGE,
RelayUserHandler,
)
from monkey.infection_monkey.tcp_relay import TCPRelay
NEW_USER_ADDRESS = IPv4Address("0.0.0.1")
LOCAL_PORT = 9975
@ -11,9 +17,51 @@ TARGET_ADDRESS = "0.0.0.0"
TARGET_PORT = 9976
class FakeConnectionHandler:
def notify_client_connected(self, callback: Callable[[socket.socket, IPv4Address], None]):
self.cb = callback
def client_connected(self, socket: socket.socket, addr: IPv4Address):
self.cb(socket, addr)
def start(self):
pass
def stop(self):
pass
def join(self):
pass
class FakePipeSpawner:
spawn_pipe = MagicMock()
def notify_client_data_received(self, callback: Callable[[bytes], bool]):
self.cb = callback
def send_client_data(self, data: bytes):
self.cb(data)
@pytest.fixture
def tcp_relay():
return TCPRelay(LOCAL_PORT, TARGET_ADDRESS, TARGET_PORT)
def relay_user_handler() -> RelayUserHandler:
return RelayUserHandler()
@pytest.fixture
def pipe_spawner():
return FakePipeSpawner()
@pytest.fixture
def connection_handler():
return FakeConnectionHandler()
@pytest.fixture
def tcp_relay(relay_user_handler, connection_handler, pipe_spawner) -> TCPRelay:
return TCPRelay(relay_user_handler, connection_handler, pipe_spawner)
def join_or_kill_thread(thread: Thread, timeout: float):
@ -25,29 +73,27 @@ def join_or_kill_thread(thread: Thread, timeout: float):
return True
# This will fail unless TcpProxy is updated to do non-blocking accepts
# def test_stops():
# relay = TCPRelay(9975, "0.0.0.0", 9976)
# relay.start()
# relay.stop()
# assert join_or_kill_thread(relay, 0.2)
def test_user_added_when_user_connected(connection_handler, relay_user_handler, tcp_relay):
# sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connection_handler.client_connected(sock, NEW_USER_ADDRESS)
# assert len(relay_user_handler.get_relay_users()) == 1
pass
def test_user_added(tcp_relay):
tcp_relay.add_relay_user(NEW_USER_ADDRESS)
users = tcp_relay.relay_users()
assert len(users) == 1
assert NEW_USER_ADDRESS in users
def test_pipe_created_when_user_connected(connection_handler, pipe_spawner, tcp_relay):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection_handler.client_connected(sock, NEW_USER_ADDRESS)
assert pipe_spawner.spawn_pipe.called
def test_user_removed_on_request(tcp_relay):
tcp_relay.add_relay_user(NEW_USER_ADDRESS)
tcp_relay.on_user_data_received(RELAY_CONTROL_MESSAGE, NEW_USER_ADDRESS)
def test_user_removed_on_request(relay_user_handler, pipe_spawner, tcp_relay):
relay_user_handler.add_relay_user(NEW_USER_ADDRESS)
users = tcp_relay.relay_users()
assert len(users) == 0
# pipe_spawner.send_client_data(RELAY_CONTROL_MESSAGE, NEW_USER_ADDRESS)
# users = relay_user_handler.get_relay_users()
# assert len(users) == 0
pass
# This will fail unless TcpProxy is updated to do non-blocking accepts