#2768 - Added listen_on_ports attribute to IOSoftware. updated software manager so that it sends copies of payloads to listening ports too. Added integration test that installs a listening service to snoop on DB traffic.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
from copy import deepcopy
|
||||
from ipaddress import IPv4Address, IPv4Network
|
||||
from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING, Union
|
||||
|
||||
@@ -76,6 +77,8 @@ class SoftwareManager:
|
||||
for software in self.port_protocol_mapping.values():
|
||||
if software.operating_state in {ApplicationOperatingState.RUNNING, ServiceOperatingState.RUNNING}:
|
||||
open_ports.append(software.port)
|
||||
if software.listen_on_ports:
|
||||
open_ports += list(software.listen_on_ports)
|
||||
return open_ports
|
||||
|
||||
def check_port_is_open(self, port: Port, protocol: IPProtocol) -> bool:
|
||||
@@ -223,7 +226,9 @@ class SoftwareManager:
|
||||
frame: Frame,
|
||||
):
|
||||
"""
|
||||
Receive a payload from the SessionManager and forward it to the corresponding service or application.
|
||||
Receive a payload from the SessionManager and forward it to the corresponding service or applications.
|
||||
|
||||
This function handles both software assigned a specific port, and software listening in on other ports.
|
||||
|
||||
:param payload: The payload being received.
|
||||
:param session: The transport session the payload originates from.
|
||||
@@ -231,11 +236,17 @@ class SoftwareManager:
|
||||
if payload.__class__.__name__ == "PortScanPayload":
|
||||
self.software.get("NMAP").receive(payload=payload, session_id=session_id)
|
||||
return
|
||||
receiver: Optional[Union[Service, Application]] = self.port_protocol_mapping.get((port, protocol), None)
|
||||
if receiver:
|
||||
receiver.receive(
|
||||
payload=payload, session_id=session_id, from_network_interface=from_network_interface, frame=frame
|
||||
)
|
||||
main_receiver = self.port_protocol_mapping.get((port, protocol), None)
|
||||
listening_receivers = [software for software in self.software.values() if port in software.listen_on_ports]
|
||||
receivers = [main_receiver] + listening_receivers if main_receiver else listening_receivers
|
||||
if receivers:
|
||||
for receiver in receivers:
|
||||
receiver.receive(
|
||||
payload=deepcopy(payload),
|
||||
session_id=session_id,
|
||||
from_network_interface=from_network_interface,
|
||||
frame=frame,
|
||||
)
|
||||
else:
|
||||
self.sys_log.warning(f"No service or application found for port {port} and protocol {protocol}")
|
||||
pass
|
||||
|
||||
@@ -377,6 +377,8 @@ class DatabaseService(Service):
|
||||
)
|
||||
else:
|
||||
result = {"status_code": 401, "type": "sql"}
|
||||
else:
|
||||
self.sys_log.info(f"{self.name}: Ignoring payload as it is not a Database payload")
|
||||
self.send(payload=result, session_id=session_id)
|
||||
return True
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ from abc import abstractmethod
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from ipaddress import IPv4Address, IPv4Network
|
||||
from typing import Any, Dict, Optional, TYPE_CHECKING, Union
|
||||
from typing import Any, Dict, Optional, Set, TYPE_CHECKING, Union
|
||||
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
from pydantic import Field
|
||||
|
||||
from primaite.interface.request import RequestResponse
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
@@ -252,6 +253,8 @@ class IOSoftware(Software):
|
||||
"Indicates if the software uses UDP protocol for communication. Default is True."
|
||||
port: Port
|
||||
"The port to which the software is connected."
|
||||
listen_on_ports: Set[Port] = Field(default_factory=set)
|
||||
"The set of ports to listen on."
|
||||
protocol: IPProtocol
|
||||
"The IP Protocol the Software operates on."
|
||||
_connections: Dict[str, Dict] = {}
|
||||
|
||||
Reference in New Issue
Block a user