Agent: Publish PingScanEvent from ping_scanner

This commit is contained in:
Ilija Lazoroski 2022-09-28 11:24:25 +02:00 committed by Shreya Malviya
parent 0357d43d33
commit 228ce9bae1
2 changed files with 50 additions and 19 deletions

View File

@ -4,10 +4,14 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
from ipaddress import IPv4Address
from common import OperatingSystem from common import OperatingSystem
from common.agent_events import PingScanEvent
from common.event_queue import IAgentEventQueue
from common.types import PingScanData from common.types import PingScanData
from infection_monkey.utils.environment import is_windows_os from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.ids import get_agent_id
TTL_REGEX = re.compile(r"TTL=([0-9]+)\b", re.IGNORECASE) TTL_REGEX = re.compile(r"TTL=([0-9]+)\b", re.IGNORECASE)
LINUX_TTL = 64 # Windows TTL is 128 LINUX_TTL = 64 # Windows TTL is 128
@ -17,15 +21,15 @@ EMPTY_PING_SCAN = PingScanData(False, None)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def ping(host: str, timeout: float) -> PingScanData: def ping(host: str, timeout: float, agent_event_queue: IAgentEventQueue) -> PingScanData:
try: try:
return _ping(host, timeout) return _ping(host, timeout, agent_event_queue)
except Exception: except Exception:
logger.exception("Unhandled exception occurred while running ping") logger.exception("Unhandled exception occurred while running ping")
return EMPTY_PING_SCAN return EMPTY_PING_SCAN
def _ping(host: str, timeout: float) -> PingScanData: def _ping(host: str, timeout: float, agent_event_queue: IAgentEventQueue) -> PingScanData:
if is_windows_os(): if is_windows_os():
timeout = math.floor(timeout * 1000) timeout = math.floor(timeout * 1000)
@ -34,6 +38,10 @@ def _ping(host: str, timeout: float) -> PingScanData:
ping_scan_data = _process_ping_command_output(ping_command_output) ping_scan_data = _process_ping_command_output(ping_command_output)
logger.debug(f"{host} - {ping_scan_data}") logger.debug(f"{host} - {ping_scan_data}")
agent_event_queue.publish(
PingScanEvent(source=get_agent_id(), target=IPv4Address(host), scan_data=ping_scan_data)
)
return ping_scan_data return ping_scan_data

View File

@ -5,6 +5,7 @@ from unittest.mock import MagicMock
import pytest import pytest
from common import OperatingSystem from common import OperatingSystem
from common.event_queue import IAgentEventQueue
from infection_monkey.network_scanning import ping from infection_monkey.network_scanning import ping
from infection_monkey.network_scanning.ping_scanner import EMPTY_PING_SCAN from infection_monkey.network_scanning.ping_scanner import EMPTY_PING_SCAN
@ -86,56 +87,75 @@ def set_os_windows(monkeypatch):
monkeypatch.setattr("sys.platform", "win32") monkeypatch.setattr("sys.platform", "win32")
@pytest.fixture
def mock_agent_event_queue():
return MagicMock(spec=IAgentEventQueue)
@pytest.mark.usefixtures("set_os_linux") @pytest.mark.usefixtures("set_os_linux")
def test_linux_ping_success(patch_subprocess_running_ping_with_ping_output): def test_linux_ping_success(patch_subprocess_running_ping_with_ping_output, mock_agent_event_queue):
patch_subprocess_running_ping_with_ping_output(LINUX_SUCCESS_OUTPUT) patch_subprocess_running_ping_with_ping_output(LINUX_SUCCESS_OUTPUT)
result = ping("192.168.1.1", 1.0) result = ping("192.168.1.1", 1.0, mock_agent_event_queue)
assert result.response_received assert result.response_received
assert result.os == OperatingSystem.LINUX assert result.os == OperatingSystem.LINUX
assert mock_agent_event_queue.publish.call_count == 1
@pytest.mark.usefixtures("set_os_linux") @pytest.mark.usefixtures("set_os_linux")
def test_linux_ping_no_response(patch_subprocess_running_ping_with_ping_output): def test_linux_ping_no_response(
patch_subprocess_running_ping_with_ping_output, mock_agent_event_queue
):
patch_subprocess_running_ping_with_ping_output(LINUX_NO_RESPONSE_OUTPUT) patch_subprocess_running_ping_with_ping_output(LINUX_NO_RESPONSE_OUTPUT)
result = ping("192.168.1.1", 1.0) result = ping("192.168.1.1", 1.0, mock_agent_event_queue)
assert not result.response_received assert not result.response_received
assert result.os is None assert result.os is None
assert mock_agent_event_queue.publish.call_count == 1
@pytest.mark.usefixtures("set_os_windows") @pytest.mark.usefixtures("set_os_windows")
def test_windows_ping_success(patch_subprocess_running_ping_with_ping_output): def test_windows_ping_success(
patch_subprocess_running_ping_with_ping_output, mock_agent_event_queue
):
patch_subprocess_running_ping_with_ping_output(WINDOWS_SUCCESS_OUTPUT) patch_subprocess_running_ping_with_ping_output(WINDOWS_SUCCESS_OUTPUT)
result = ping("192.168.1.1", 1.0) result = ping("192.168.1.1", 1.0, mock_agent_event_queue)
assert result.response_received assert result.response_received
assert result.os == OperatingSystem.WINDOWS assert result.os == OperatingSystem.WINDOWS
assert mock_agent_event_queue.publish.call_count == 1
@pytest.mark.usefixtures("set_os_windows") @pytest.mark.usefixtures("set_os_windows")
def test_windows_ping_no_response(patch_subprocess_running_ping_with_ping_output): def test_windows_ping_no_response(
patch_subprocess_running_ping_with_ping_output, mock_agent_event_queue
):
patch_subprocess_running_ping_with_ping_output(WINDOWS_NO_RESPONSE_OUTPUT) patch_subprocess_running_ping_with_ping_output(WINDOWS_NO_RESPONSE_OUTPUT)
result = ping("192.168.1.1", 1.0) result = ping("192.168.1.1", 1.0, mock_agent_event_queue)
assert not result.response_received assert not result.response_received
assert result.os is None assert result.os is None
assert mock_agent_event_queue.publish.call_count == 1
def test_malformed_ping_command_response(patch_subprocess_running_ping_with_ping_output): def test_malformed_ping_command_response(
patch_subprocess_running_ping_with_ping_output, mock_agent_event_queue
):
patch_subprocess_running_ping_with_ping_output(MALFORMED_OUTPUT) patch_subprocess_running_ping_with_ping_output(MALFORMED_OUTPUT)
result = ping("192.168.1.1", 1.0) result = ping("192.168.1.1", 1.0, mock_agent_event_queue)
assert not result.response_received assert not result.response_received
assert result.os is None assert result.os is None
assert mock_agent_event_queue.publish.call_count == 1
@pytest.mark.usefixtures("patch_subprocess_running_ping_to_raise_timeout_expired") @pytest.mark.usefixtures("patch_subprocess_running_ping_to_raise_timeout_expired")
def test_timeout_expired(): def test_timeout_expired(mock_agent_event_queue):
result = ping("192.168.1.1", 1.0) result = ping("192.168.1.1", 1.0, mock_agent_event_queue)
assert not result.response_received assert not result.response_received
assert result.os is None assert result.os is None
assert mock_agent_event_queue.publish.call_count == 1
@pytest.fixture @pytest.fixture
@ -147,9 +167,9 @@ def ping_command_spy(monkeypatch):
@pytest.fixture @pytest.fixture
def assert_expected_timeout(ping_command_spy): def assert_expected_timeout(ping_command_spy, mock_agent_event_queue):
def inner(timeout_flag, timeout_input, expected_timeout): def inner(timeout_flag, timeout_input, expected_timeout):
ping("192.168.1.1", timeout_input) ping("192.168.1.1", timeout_input, mock_agent_event_queue)
assert ping_command_spy.call_args is not None assert ping_command_spy.call_args is not None
@ -159,6 +179,8 @@ def assert_expected_timeout(ping_command_spy):
timeout_flag_index = ping_command.index(timeout_flag) timeout_flag_index = ping_command.index(timeout_flag)
assert ping_command[timeout_flag_index + 1] == expected_timeout assert ping_command[timeout_flag_index + 1] == expected_timeout
assert mock_agent_event_queue.publish.call_count == 1
return inner return inner
@ -178,8 +200,9 @@ def test_linux_timeout(assert_expected_timeout):
assert_expected_timeout(timeout_flag, timeout, str(math.ceil(timeout))) assert_expected_timeout(timeout_flag, timeout, str(math.ceil(timeout)))
def test_exception_handling(monkeypatch): def test_exception_handling(monkeypatch, mock_agent_event_queue):
monkeypatch.setattr( monkeypatch.setattr(
"infection_monkey.network_scanning.ping_scanner._ping", MagicMock(side_effect=Exception) "infection_monkey.network_scanning.ping_scanner._ping", MagicMock(side_effect=Exception)
) )
assert ping("abc", 10) == EMPTY_PING_SCAN assert ping("abc", 10, mock_agent_event_queue) == EMPTY_PING_SCAN
assert mock_agent_event_queue.publish.call_count == 0