2023-08-03 21:30:13 +01:00
|
|
|
from abc import abstractmethod
|
2023-08-03 14:37:55 +01:00
|
|
|
from enum import Enum
|
2023-08-03 21:30:13 +01:00
|
|
|
from typing import Any, Dict, List, Set
|
2023-08-03 14:37:55 +01:00
|
|
|
|
|
|
|
|
from primaite.simulator.core import SimComponent
|
2023-08-03 21:30:13 +01:00
|
|
|
from primaite.simulator.network.transmission.transport_layer import Port
|
2023-08-03 14:37:55 +01:00
|
|
|
|
|
|
|
|
|
2023-08-07 19:33:52 +01:00
|
|
|
class SoftwareType(Enum):
|
|
|
|
|
"""
|
|
|
|
|
An enumeration representing the different types of software within a simulated environment.
|
|
|
|
|
|
|
|
|
|
Members:
|
|
|
|
|
- APPLICATION: User-facing programs that may perform input/output operations.
|
|
|
|
|
- SERVICE: Represents programs that run in the background and may perform input/output operations.
|
|
|
|
|
- PROCESS: Software executed by a Node that does not have the ability to performing input/output operations.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
APPLICATION = 1
|
|
|
|
|
"User-facing software that may perform input/output operations."
|
|
|
|
|
SERVICE = 2
|
|
|
|
|
"Software that runs in the background and may perform input/output operations."
|
|
|
|
|
PROCESS = 3
|
|
|
|
|
"Software executed by a Node that does not have the ability to performing input/output operations."
|
|
|
|
|
|
|
|
|
|
|
2023-08-03 14:37:55 +01:00
|
|
|
class SoftwareHealthState(Enum):
|
|
|
|
|
"""Enumeration of the Software Health States."""
|
|
|
|
|
|
|
|
|
|
GOOD = 1
|
|
|
|
|
"The software is in a good and healthy condition."
|
|
|
|
|
COMPROMISED = 2
|
|
|
|
|
"The software's security has been compromised."
|
|
|
|
|
OVERWHELMED = 3
|
|
|
|
|
"he software is overwhelmed and not functioning properly."
|
|
|
|
|
PATCHING = 4
|
|
|
|
|
"The software is undergoing patching or updates."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SoftwareCriticality(Enum):
|
|
|
|
|
"""Enumeration of Software Criticality Levels."""
|
|
|
|
|
|
|
|
|
|
LOWEST = 1
|
|
|
|
|
"The lowest level of criticality."
|
|
|
|
|
LOW = 2
|
|
|
|
|
"A low level of criticality."
|
|
|
|
|
MEDIUM = 3
|
|
|
|
|
"A medium level of criticality."
|
|
|
|
|
HIGH = 4
|
|
|
|
|
"A high level of criticality."
|
|
|
|
|
HIGHEST = 5
|
|
|
|
|
"The highest level of criticality."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Software(SimComponent):
|
|
|
|
|
"""
|
2023-08-03 21:30:13 +01:00
|
|
|
A base class representing software in a simulator environment.
|
2023-08-03 14:37:55 +01:00
|
|
|
|
2023-08-03 21:30:13 +01:00
|
|
|
This class is intended to be subclassed by specific types of software entities.
|
|
|
|
|
It outlines the fundamental attributes and behaviors expected of any software in the simulation.
|
|
|
|
|
"""
|
2023-08-07 19:33:52 +01:00
|
|
|
|
2023-08-03 14:37:55 +01:00
|
|
|
name: str
|
2023-08-03 21:30:13 +01:00
|
|
|
"The name of the software."
|
2023-08-03 14:37:55 +01:00
|
|
|
health_state_actual: SoftwareHealthState
|
2023-08-03 21:30:13 +01:00
|
|
|
"The actual health state of the software."
|
2023-08-03 14:37:55 +01:00
|
|
|
health_state_visible: SoftwareHealthState
|
2023-08-03 21:30:13 +01:00
|
|
|
"The health state of the software visible to the red agent."
|
2023-08-03 14:37:55 +01:00
|
|
|
criticality: SoftwareCriticality
|
2023-08-03 21:30:13 +01:00
|
|
|
"The criticality level of the software."
|
2023-08-03 14:37:55 +01:00
|
|
|
patching_count: int = 0
|
2023-08-03 21:30:13 +01:00
|
|
|
"The count of patches applied to the software, defaults to 0."
|
2023-08-03 14:37:55 +01:00
|
|
|
scanning_count: int = 0
|
2023-08-03 21:30:13 +01:00
|
|
|
"The count of times the software has been scanned, defaults to 0."
|
2023-08-03 14:37:55 +01:00
|
|
|
revealed_to_red: bool = False
|
2023-08-03 21:30:13 +01:00
|
|
|
"Indicates if the software has been revealed to red agent, defaults is False."
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def describe_state(self) -> Dict:
|
|
|
|
|
"""
|
2023-08-17 15:32:12 +01:00
|
|
|
Produce a dictionary describing the current state of this object.
|
2023-08-03 21:30:13 +01:00
|
|
|
|
2023-08-17 15:32:12 +01:00
|
|
|
Please see :py:meth:`primaite.simulator.core.SimComponent.describe_state` for a more detailed explanation.
|
2023-08-03 21:30:13 +01:00
|
|
|
|
2023-08-17 15:32:12 +01:00
|
|
|
:return: Current state of this object and child objects.
|
2023-08-03 21:30:13 +01:00
|
|
|
:rtype: Dict
|
|
|
|
|
"""
|
2023-08-17 15:32:12 +01:00
|
|
|
state = super().describe_state()
|
|
|
|
|
state.update(
|
|
|
|
|
{
|
|
|
|
|
"health_state": self.health_state_actual.name,
|
|
|
|
|
"health_state_red_view": self.health_state_visible.name,
|
|
|
|
|
"criticality": self.criticality.name,
|
|
|
|
|
"patching_count": self.patching_count,
|
|
|
|
|
"scanning_count": self.scanning_count,
|
|
|
|
|
"revealed_to_red": self.revealed_to_red,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
return state
|
2023-08-03 21:30:13 +01:00
|
|
|
|
|
|
|
|
def apply_action(self, action: List[str]) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Applies a list of actions to the software.
|
|
|
|
|
|
|
|
|
|
The specifics of how these actions are applied should be implemented in subclasses.
|
|
|
|
|
|
|
|
|
|
:param action: A list of actions to apply.
|
|
|
|
|
:type action: List[str]
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def reset_component_for_episode(self, episode: int):
|
|
|
|
|
"""
|
|
|
|
|
Resets the software component for a new episode.
|
|
|
|
|
|
|
|
|
|
This method should ensure the software is ready for a new episode, including resetting any
|
|
|
|
|
stateful properties or statistics, and clearing any message queues. The specifics of what constitutes a
|
|
|
|
|
"reset" should be implemented in subclasses.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class IOSoftware(Software):
|
|
|
|
|
"""
|
|
|
|
|
Represents software in a simulator environment that is capable of input/output operations.
|
|
|
|
|
|
|
|
|
|
This base class is meant to be sub-classed by Application and Service classes. It provides the blueprint for
|
|
|
|
|
Applications and Services that can receive payloads from a Node's SessionManager (corresponding to layer 5 in the
|
|
|
|
|
OSI Model), process them according to their internals, and send a response payload back to the SessionManager if
|
|
|
|
|
required.
|
|
|
|
|
"""
|
2023-08-07 19:33:52 +01:00
|
|
|
|
2023-08-03 21:30:13 +01:00
|
|
|
installing_count: int = 0
|
|
|
|
|
"The number of times the software has been installed. Default is 0."
|
|
|
|
|
max_sessions: int = 1
|
|
|
|
|
"The maximum number of sessions that the software can handle simultaneously. Default is 0."
|
|
|
|
|
tcp: bool = True
|
|
|
|
|
"Indicates if the software uses TCP protocol for communication. Default is True."
|
|
|
|
|
udp: bool = True
|
|
|
|
|
"Indicates if the software uses UDP protocol for communication. Default is True."
|
|
|
|
|
ports: Set[Port]
|
|
|
|
|
"The set of ports to which the software is connected."
|
|
|
|
|
|
2023-08-07 19:33:52 +01:00
|
|
|
@abstractmethod
|
|
|
|
|
def describe_state(self) -> Dict:
|
|
|
|
|
"""
|
2023-08-17 15:32:12 +01:00
|
|
|
Produce a dictionary describing the current state of this object.
|
2023-08-07 19:33:52 +01:00
|
|
|
|
2023-08-17 15:32:12 +01:00
|
|
|
Please see :py:meth:`primaite.simulator.core.SimComponent.describe_state` for a more detailed explanation.
|
2023-08-07 19:33:52 +01:00
|
|
|
|
2023-08-17 15:32:12 +01:00
|
|
|
:return: Current state of this object and child objects.
|
2023-08-07 19:33:52 +01:00
|
|
|
:rtype: Dict
|
2023-08-03 21:30:13 +01:00
|
|
|
"""
|
2023-08-07 19:33:52 +01:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def send(self, payload: Any, session_id: str, **kwargs) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Sends a payload to the SessionManager.
|
2023-08-03 21:30:13 +01:00
|
|
|
|
|
|
|
|
The specifics of how the payload is processed and whether a response payload
|
|
|
|
|
is generated should be implemented in subclasses.
|
|
|
|
|
|
|
|
|
|
:param payload: The payload to send.
|
2023-08-07 19:33:52 +01:00
|
|
|
:param session_id: The identifier of the session that the payload is associated with.
|
|
|
|
|
:param kwargs: Additional keyword arguments specific to the implementation.
|
|
|
|
|
:return: True if the payload was successfully sent, False otherwise.
|
2023-08-03 21:30:13 +01:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2023-08-07 19:33:52 +01:00
|
|
|
def receive(self, payload: Any, session_id: str, **kwargs) -> bool:
|
2023-08-03 21:30:13 +01:00
|
|
|
"""
|
|
|
|
|
Receives a payload from the SessionManager.
|
|
|
|
|
|
|
|
|
|
The specifics of how the payload is processed and whether a response payload
|
|
|
|
|
is generated should be implemented in subclasses.
|
|
|
|
|
|
2023-08-07 19:33:52 +01:00
|
|
|
|
2023-08-03 21:30:13 +01:00
|
|
|
:param payload: The payload to receive.
|
2023-08-07 19:33:52 +01:00
|
|
|
:param session_id: The identifier of the session that the payload is associated with.
|
|
|
|
|
:param kwargs: Additional keyword arguments specific to the implementation.
|
|
|
|
|
:return: True if the payload was successfully received and processed, False otherwise.
|
2023-08-03 21:30:13 +01:00
|
|
|
"""
|
|
|
|
|
pass
|