From 2c743005cd4800f68a90462259393128483fc21c Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 12 Feb 2024 18:58:10 +0000 Subject: [PATCH 01/18] #2257: moved config tests into its own directory + added dmz_network.yaml to use in tests --- .../configs/basic_switched_network.yaml | 7 + tests/assets/configs/dmz_network.yaml | 230 ++++++++++++++++++ .../configuration_file_parsing/__init__.py | 0 .../router_game_configuration.py | 58 +++++ ...oftware_installation_and_configuration.py} | 0 5 files changed, 295 insertions(+) create mode 100644 tests/assets/configs/dmz_network.yaml create mode 100644 tests/integration_tests/configuration_file_parsing/__init__.py create mode 100644 tests/integration_tests/configuration_file_parsing/router_game_configuration.py rename tests/integration_tests/{game_configuration.py => configuration_file_parsing/software_installation_and_configuration.py} (100%) diff --git a/tests/assets/configs/basic_switched_network.yaml b/tests/assets/configs/basic_switched_network.yaml index d1cec079..a248065c 100644 --- a/tests/assets/configs/basic_switched_network.yaml +++ b/tests/assets/configs/basic_switched_network.yaml @@ -1,3 +1,10 @@ +# Basic Switched network +# +# -------------- -------------- -------------- +# | client_1 |------| switch_1 |------| client_2 | +# -------------- -------------- -------------- +# + training_config: rl_framework: SB3 rl_algorithm: PPO diff --git a/tests/assets/configs/dmz_network.yaml b/tests/assets/configs/dmz_network.yaml new file mode 100644 index 00000000..ddf8fb36 --- /dev/null +++ b/tests/assets/configs/dmz_network.yaml @@ -0,0 +1,230 @@ +# Network with DMZ +# +# An example network configuration with an internal network, a DMZ network and a couple of external networks. +# +# ............................................................................ +# . . +# . Internal Network . +# . . +# . -------------- -------------- -------------- . +# . | client_1 |------| switch_1 |------| router_1 | . +# . -------------- -------------- -------------- . +# . (Computer) | . +# ......................................................|..................... +# | +# | +# ......................................................|..................... +# . | . +# . DMZ Network | . +# . | . +# . -------------- -------------- -------------- . +# . | client_2 |------| switch_2 |------| router_2 | . +# . -------------- -------------- -------------- . +# . (Computer) | . +# ......................................................|..................... +# | +# External Network | +# | +# | +# ----------------------- -------------- --------------------- +# | external_computer |------| switch_3 |------| external_server | +# ----------------------- -------------- --------------------- +# +training_config: + rl_framework: SB3 + rl_algorithm: PPO + seed: 333 + n_learn_episodes: 1 + n_eval_episodes: 5 + max_steps_per_episode: 128 + deterministic_eval: false + n_agents: 1 + agent_references: + - defender + +io_settings: + save_checkpoints: true + checkpoint_interval: 5 + save_step_metadata: false + save_pcap_logs: true + save_sys_logs: true + + +game: + max_episode_length: 256 + ports: + - ARP + - DNS + - HTTP + - POSTGRES_SERVER + protocols: + - ICMP + - TCP + - UDP + +agents: + - ref: client_2_green_user + team: GREEN + type: GreenWebBrowsingAgent + observation_space: + type: UC2GreenObservation + action_space: + action_list: + - type: DONOTHING + - type: NODE_APPLICATION_EXECUTE + options: + nodes: + - node_name: client_2 + applications: + - application_name: WebBrowser + max_folders_per_node: 1 + max_files_per_folder: 1 + max_services_per_node: 1 + max_applications_per_node: 1 + + reward_function: + reward_components: + - type: DUMMY + + agent_settings: + start_settings: + start_step: 5 + frequency: 4 + variance: 3 + + +simulation: + network: + nodes: + - ref: client_1 + type: computer + hostname: client_1 + ip_address: 192.168.0.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.0.1 + dns_server: 192.168.20.10 + + - ref: switch_1 + type: switch + hostname: switch_1 + num_ports: 8 + + - ref: router_1 + type: router + hostname: router_1 + num_ports: 5 + ports: + 1: + ip_address: 192.168.0.1 + subnet_mask: 255.255.255.0 + 2: + ip_address: 192.168.1.1 + subnet_mask: 255.255.255.0 + acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + + - ref: client_2 + type: computer + hostname: client_2 + ip_address: 192.168.10.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.10.1 + dns_server: 192.168.20.10 + + - ref: switch_2 + type: switch + hostname: switch_2 + num_ports: 8 + + - ref: router_2 + type: router + hostname: router_2 + num_ports: 5 + ports: + 1: + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 + 2: + ip_address: 192.168.11.1 + subnet_mask: 255.255.255.0 + 3: + ip_address: 192.168.20.1 + subnet_mask: 255.255.255.0 + acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + + - ref: switch_3 + type: switch + hostname: switch_3 + num_ports: 8 + + - ref: external_computer + type: computer + hostname: external_computer + ip_address: 192.168.20.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.20.1 + dns_server: 192.168.20.10 + + - ref: external_server + type: server + hostname: external_server + ip_address: 192.168.20.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.20.1 + services: + - ref: domain_controller_dns_server + type: DNSServer + links: + - ref: client_1___switch_1 + endpoint_a_ref: client_1 + endpoint_a_port: 1 + endpoint_b_ref: switch_1 + endpoint_b_port: 1 + - ref: router_1___switch_1 + endpoint_a_ref: router_1 + endpoint_a_port: 1 + endpoint_b_ref: switch_1 + endpoint_b_port: 8 + - ref: router_1___router_2 + endpoint_a_ref: router_1 + endpoint_a_port: 2 + endpoint_b_ref: router_2 + endpoint_b_port: 2 + - ref: router_2___switch_2 + endpoint_a_ref: router_2 + endpoint_a_port: 1 + endpoint_b_ref: switch_2 + endpoint_b_port: 8 + - ref: client_2___switch_2 + endpoint_a_ref: client_2 + endpoint_a_port: 1 + endpoint_b_ref: switch_2 + endpoint_b_port: 1 + - ref: router_2___switch_3 + endpoint_a_ref: router_2 + endpoint_a_port: 3 + endpoint_b_ref: switch_3 + endpoint_b_port: 8 + - ref: external_computer___switch_3 + endpoint_a_ref: external_computer + endpoint_a_port: 1 + endpoint_b_ref: switch_3 + endpoint_b_port: 1 + - ref: external_server___switch_3 + endpoint_a_ref: external_server + endpoint_a_port: 1 + endpoint_b_ref: switch_3 + endpoint_b_port: 2 diff --git a/tests/integration_tests/configuration_file_parsing/__init__.py b/tests/integration_tests/configuration_file_parsing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration_tests/configuration_file_parsing/router_game_configuration.py b/tests/integration_tests/configuration_file_parsing/router_game_configuration.py new file mode 100644 index 00000000..49b889d7 --- /dev/null +++ b/tests/integration_tests/configuration_file_parsing/router_game_configuration.py @@ -0,0 +1,58 @@ +from pathlib import Path +from typing import Union + +import yaml + +from primaite.game.game import PrimaiteGame +from primaite.simulator.network.container import Network +from tests import TEST_ASSETS_ROOT + +DMZ_NETWORK = TEST_ASSETS_ROOT / "configs/dmz_network.yaml" + + +def load_config(config_path: Union[str, Path]) -> PrimaiteGame: + """Returns a PrimaiteGame object which loads the contents of a given yaml path.""" + with open(config_path, "r") as f: + cfg = yaml.safe_load(f) + + return PrimaiteGame.from_config(cfg) + + +def test_dmz_config(): + """Test that the DMZ network config can be parsed properly.""" + game = load_config(DMZ_NETWORK) + + network: Network = game.simulation.network + + assert len(network.nodes) == 9 # 9 nodes in network + assert len(network.routers) == 2 # 2 routers in network + assert len(network.switches) == 3 # 3 switches in network + assert len(network.servers) == 1 # 1 server in network + + +def test_router_routes_are_correctly_added(): + """Test that makes sure that router routes have been added from the configuration file.""" + pass + + +def test_firewall_node_added_to_network(): + """Test that the firewall has been correctly added to and configured in the network.""" + pass + + +def test_router_acl_rules_correctly_added(): + """Test that makes sure that the router ACLs have been configured onto the router node via configuration file.""" + pass + + +def test_firewall_routes_are_correctly_added(): + """Test that the firewall routes have been correctly added to and configured in the network.""" + pass + + +def test_firewall_acl_rules_correctly_added(): + """ + Test that makes sure that the firewall ACLs have been configured onto the firewall + node via configuration file. + """ + pass diff --git a/tests/integration_tests/game_configuration.py b/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py similarity index 100% rename from tests/integration_tests/game_configuration.py rename to tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py From b277034e8b8d48afef97eccda9ccc213d9cdf0f8 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Tue, 13 Feb 2024 13:02:24 +0000 Subject: [PATCH 02/18] #2257: temporarily commit changes - added startup and shut down durations to node config + adding routes --- src/primaite/game/game.py | 14 ++- .../network/hardware/nodes/network/router.py | 8 ++ tests/assets/configs/dmz_network.yaml | 98 +++++++++++++------ .../router_game_configuration.py | 22 ++++- 4 files changed, 105 insertions(+), 37 deletions(-) diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index c03bca36..3bc3789a 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -266,6 +266,10 @@ class PrimaiteGame: game.ref_map_services[service_ref] = new_service.uuid else: _LOGGER.warning(f"service type not found {service_type}") + + # start the service + new_service.start() + # service-dependent options if service_type == "DNSClient": if "options" in service_cfg: @@ -282,17 +286,14 @@ class PrimaiteGame: if "options" in service_cfg: opt = service_cfg["options"] new_service.configure_backup(backup_server=IPv4Address(opt.get("backup_server_ip"))) - new_service.start() if service_type == "FTPServer": if "options" in service_cfg: opt = service_cfg["options"] new_service.server_password = opt.get("server_password") - new_service.start() if service_type == "NTPClient": if "options" in service_cfg: opt = service_cfg["options"] new_service.ntp_server = IPv4Address(opt.get("ntp_server_ip")) - new_service.start() if "applications" in node_cfg: for application_cfg in node_cfg["applications"]: new_application = None @@ -306,6 +307,9 @@ class PrimaiteGame: else: _LOGGER.warning(f"application type not found {application_type}") + # run the application + new_application.run() + if application_type == "DataManipulationBot": if "options" in application_cfg: opt = application_cfg["options"] @@ -327,7 +331,6 @@ class PrimaiteGame: if "options" in application_cfg: opt = application_cfg["options"] new_application.target_url = opt.get("target_url") - elif application_type == "DoSBot": if "options" in application_cfg: opt = application_cfg["options"] @@ -344,6 +347,9 @@ class PrimaiteGame: for nic_num, nic_cfg in node_cfg["network_interfaces"].items(): new_node.connect_nic(NIC(ip_address=nic_cfg["ip_address"], subnet_mask=nic_cfg["subnet_mask"])) + new_node.start_up_duration = int(node_cfg.get("start_up_duration", 3)) + new_node.shut_down_duration = int(node_cfg.get("shut_down_duration", 3)) + net.add_node(new_node) new_node.power_on() game.ref_map_nodes[node_ref] = new_node.uuid diff --git a/src/primaite/simulator/network/hardware/nodes/network/router.py b/src/primaite/simulator/network/hardware/nodes/network/router.py index 40cbc16d..f034fcbd 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/router.py +++ b/src/primaite/simulator/network/hardware/nodes/network/router.py @@ -1276,4 +1276,12 @@ class Router(NetworkNode): if "acl" in cfg: new.acl._default_config = cfg["acl"] # save the config to allow resetting new.acl._reset_rules_to_default() # read the config and apply rules + if "routes" in cfg: + for route in cfg.get("routes"): + new.route_table.add_route( + address=IPv4Address(route.get("address")), + subnet_mask=IPv4Address(route.get("subnet_mask")), + next_hop_ip_address=IPv4Address(route.get("subnet_mask")), + metric=float(route.get("metric")), + ) return new diff --git a/tests/assets/configs/dmz_network.yaml b/tests/assets/configs/dmz_network.yaml index ddf8fb36..0c67ba7c 100644 --- a/tests/assets/configs/dmz_network.yaml +++ b/tests/assets/configs/dmz_network.yaml @@ -9,26 +9,26 @@ # . -------------- -------------- -------------- . # . | client_1 |------| switch_1 |------| router_1 | . # . -------------- -------------- -------------- . -# . (Computer) | . -# ......................................................|..................... -# | -# | -# ......................................................|..................... -# . | . -# . DMZ Network | . -# . | . -# . -------------- -------------- -------------- . -# . | client_2 |------| switch_2 |------| router_2 | . -# . -------------- -------------- -------------- . -# . (Computer) | . -# ......................................................|..................... -# | -# External Network | -# | -# | -# ----------------------- -------------- --------------------- -# | external_computer |------| switch_3 |------| external_server | -# ----------------------- -------------- --------------------- +# . (Computer) | . +# ........................................................|..................... +# | +# | +# ........................................................|..................... +# . | . +# . DMZ Network | . +# . | . +# . ---------------- -------------- -------------- . +# . | dmz_server |------| switch_2 |------| router_2 | . +# . ---------------- -------------- -------------- . +# . (Computer) | . +# ........................................................|................... +# | +# External Network | +# | +# | +# ----------------------- -------------- --------------------- +# | external_computer |------| switch_3 |------| external_server | +# ----------------------- -------------- --------------------- # training_config: rl_framework: SB3 @@ -63,7 +63,7 @@ game: - UDP agents: - - ref: client_2_green_user + - ref: client_1_green_user team: GREEN type: GreenWebBrowsingAgent observation_space: @@ -74,7 +74,7 @@ agents: - type: NODE_APPLICATION_EXECUTE options: nodes: - - node_name: client_2 + - node_name: client_1 applications: - application_name: WebBrowser max_folders_per_node: 1 @@ -102,17 +102,23 @@ simulation: ip_address: 192.168.0.10 subnet_mask: 255.255.255.0 default_gateway: 192.168.0.1 - dns_server: 192.168.20.10 + dns_server: 192.168.20.11 + start_up_duration: 0 + shut_down_duration: 0 - ref: switch_1 type: switch hostname: switch_1 num_ports: 8 + start_up_duration: 0 + shut_down_duration: 0 - ref: router_1 type: router hostname: router_1 num_ports: 5 + start_up_duration: 0 + shut_down_duration: 0 ports: 1: ip_address: 192.168.0.1 @@ -128,24 +134,43 @@ simulation: 23: action: PERMIT protocol: ICMP + routes: + - address: 192.168.10.10 + subnet_mask: 255.255.255.0 + next_hop_ip_address: 192.168.11.1 + metric: 0 + - address: 192.168.20.10 + subnet_mask: 255.255.255.0 + next_hop_ip_address: 192.168.11.1 + metric: 0 + - address: 192.168.20.11 + subnet_mask: 255.255.255.0 + next_hop_ip_address: 192.168.11.1 + metric: 0 - - ref: client_2 - type: computer - hostname: client_2 + - ref: dmz_server + type: server + hostname: dmz_server ip_address: 192.168.10.10 subnet_mask: 255.255.255.0 default_gateway: 192.168.10.1 - dns_server: 192.168.20.10 + dns_server: 192.168.20.11 + start_up_duration: 0 + shut_down_duration: 0 - ref: switch_2 type: switch hostname: switch_2 num_ports: 8 + start_up_duration: 0 + shut_down_duration: 0 - ref: router_2 type: router hostname: router_2 num_ports: 5 + start_up_duration: 0 + shut_down_duration: 0 ports: 1: ip_address: 192.168.10.1 @@ -164,11 +189,18 @@ simulation: 23: action: PERMIT protocol: ICMP + routes: + - address: 192.168.0.10 + subnet_mask: 255.255.255.0 + next_hop_ip_address: 192.168.1.1 + metric: 0 - ref: switch_3 type: switch hostname: switch_3 num_ports: 8 + start_up_duration: 0 + shut_down_duration: 0 - ref: external_computer type: computer @@ -176,14 +208,18 @@ simulation: ip_address: 192.168.20.10 subnet_mask: 255.255.255.0 default_gateway: 192.168.20.1 - dns_server: 192.168.20.10 + dns_server: 192.168.20.11 + start_up_duration: 0 + shut_down_duration: 0 - ref: external_server type: server hostname: external_server - ip_address: 192.168.20.10 + ip_address: 192.168.20.11 subnet_mask: 255.255.255.0 default_gateway: 192.168.20.1 + start_up_duration: 0 + shut_down_duration: 0 services: - ref: domain_controller_dns_server type: DNSServer @@ -208,8 +244,8 @@ simulation: endpoint_a_port: 1 endpoint_b_ref: switch_2 endpoint_b_port: 8 - - ref: client_2___switch_2 - endpoint_a_ref: client_2 + - ref: dmz_server___switch_2 + endpoint_a_ref: dmz_server endpoint_a_port: 1 endpoint_b_ref: switch_2 endpoint_b_port: 1 diff --git a/tests/integration_tests/configuration_file_parsing/router_game_configuration.py b/tests/integration_tests/configuration_file_parsing/router_game_configuration.py index 49b889d7..9d682dcc 100644 --- a/tests/integration_tests/configuration_file_parsing/router_game_configuration.py +++ b/tests/integration_tests/configuration_file_parsing/router_game_configuration.py @@ -5,6 +5,9 @@ import yaml from primaite.game.game import PrimaiteGame from primaite.simulator.network.container import Network +from primaite.simulator.network.hardware.nodes.host.computer import Computer +from primaite.simulator.network.hardware.nodes.host.server import Server +from primaite.simulator.network.hardware.nodes.network.router import Router from tests import TEST_ASSETS_ROOT DMZ_NETWORK = TEST_ASSETS_ROOT / "configs/dmz_network.yaml" @@ -27,12 +30,27 @@ def test_dmz_config(): assert len(network.nodes) == 9 # 9 nodes in network assert len(network.routers) == 2 # 2 routers in network assert len(network.switches) == 3 # 3 switches in network - assert len(network.servers) == 1 # 1 server in network + assert len(network.servers) == 2 # 2 servers in network def test_router_routes_are_correctly_added(): """Test that makes sure that router routes have been added from the configuration file.""" - pass + game = load_config(DMZ_NETWORK) + + network: Network = game.simulation.network + + router_1: Router = network.get_node_by_hostname("router_1") + client_1: Computer = network.get_node_by_hostname("client_1") + dmz_server: Server = network.get_node_by_hostname("dmz_server") + external_computer: Computer = network.get_node_by_hostname("external_computer") + external_server: Server = network.get_node_by_hostname("external_server") + + # test that client_1 has a route to the DMZ and external nodes - they are on a second router + + # there should be a route to the dmz server + assert router_1.route_table.find_best_route(dmz_server.network_interface[1].ip_address) + # ping DMZ server + # assert client_1.ping(dmz_server.network_interface[1].ip_address) def test_firewall_node_added_to_network(): From b7398233188ec12dcc11ed4a57c07f347e45d94f Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Thu, 15 Feb 2024 15:45:18 +0000 Subject: [PATCH 03/18] #2257: add firewall via config + fix router hop ip address + shuffling around tests --- src/primaite/game/game.py | 9 +- src/primaite/simulator/__init__.py | 4 +- .../hardware/nodes/network/firewall.py | 67 ++++++++++ .../network/hardware/nodes/network/router.py | 2 +- tests/assets/configs/dmz_network.yaml | 122 ++++++++++++------ tests/conftest.py | 19 +++ .../configuration_file_parsing/__init__.py | 19 +++ .../nodes/__init__.py | 0 .../nodes/network/__init__.py | 0 .../nodes/network/test_firewall_config.py | 45 +++++++ .../nodes/network/test_router_config.py | 54 ++++++++ .../nodes/test_node_config.py | 26 ++++ .../router_game_configuration.py | 76 ----------- ...software_installation_and_configuration.py | 52 +------- 14 files changed, 322 insertions(+), 173 deletions(-) create mode 100644 tests/integration_tests/configuration_file_parsing/nodes/__init__.py create mode 100644 tests/integration_tests/configuration_file_parsing/nodes/network/__init__.py create mode 100644 tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py create mode 100644 tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py create mode 100644 tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py delete mode 100644 tests/integration_tests/configuration_file_parsing/router_game_configuration.py diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index 3bc3789a..b860fb2a 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -15,6 +15,7 @@ from primaite.simulator.network.hardware.base import NodeOperatingState from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.host_node import NIC from primaite.simulator.network.hardware.nodes.host.server import Server +from primaite.simulator.network.hardware.nodes.network.firewall import Firewall from primaite.simulator.network.hardware.nodes.network.router import Router from primaite.simulator.network.hardware.nodes.network.switch import Switch from primaite.simulator.network.transmission.transport_layer import Port @@ -252,6 +253,8 @@ class PrimaiteGame: ) elif n_type == "router": new_node = Router.from_config(node_cfg) + elif n_type == "firewall": + new_node = Firewall.from_config(node_cfg) else: _LOGGER.warning(f"invalid node type {n_type} in config") if "services" in node_cfg: @@ -264,12 +267,12 @@ class PrimaiteGame: new_node.software_manager.install(SERVICE_TYPES_MAPPING[service_type]) new_service = new_node.software_manager.software[service_type] game.ref_map_services[service_ref] = new_service.uuid + + # start the service + new_service.start() else: _LOGGER.warning(f"service type not found {service_type}") - # start the service - new_service.start() - # service-dependent options if service_type == "DNSClient": if "options" in service_cfg: diff --git a/src/primaite/simulator/__init__.py b/src/primaite/simulator/__init__.py index 97bcd57b..aebd77cf 100644 --- a/src/primaite/simulator/__init__.py +++ b/src/primaite/simulator/__init__.py @@ -12,8 +12,8 @@ class _SimOutput: self._path: Path = ( _PRIMAITE_ROOT.parent.parent / "simulation_output" / datetime.now().strftime("%Y-%m-%d_%H-%M-%S") ) - self.save_pcap_logs: bool = True - self.save_sys_logs: bool = True + self.save_pcap_logs: bool = False + self.save_sys_logs: bool = False @property def path(self) -> Path: diff --git a/src/primaite/simulator/network/hardware/nodes/network/firewall.py b/src/primaite/simulator/network/hardware/nodes/network/firewall.py index 22effa2a..f48d0561 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/firewall.py +++ b/src/primaite/simulator/network/hardware/nodes/network/firewall.py @@ -1,8 +1,10 @@ +from ipaddress import IPv4Address from typing import Dict, Final, Optional, Union from prettytable import MARKDOWN, PrettyTable from pydantic import validate_call +from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.hardware.nodes.network.router import ( AccessControlList, ACLAction, @@ -491,3 +493,68 @@ class Firewall(Router): """ self.configure_port(DMZ_PORT_ID, ip_address, subnet_mask) self.dmz_port.enable() + + @classmethod + def from_config(cls, cfg: dict) -> "Firewall": + """Create a firewall based on a config dict.""" + new = Firewall(hostname=cfg["hostname"], operating_state=NodeOperatingState.ON) + if "ports" in cfg: + internal_port = cfg["ports"]["internal_port"] + external_port = cfg["ports"]["external_port"] + dmz_port = cfg["ports"]["dmz_port"] + + # configure internal port + new.configure_internal_port( + ip_address=IPV4Address(internal_port.get("ip_address")), + subnet_mask=IPV4Address(internal_port.get("subnet_mask")), + ) + + # configure external port + new.configure_external_port( + ip_address=IPV4Address(external_port.get("ip_address")), + subnet_mask=IPV4Address(external_port.get("subnet_mask")), + ) + + # configure dmz port + new.configure_dmz_port( + ip_address=IPV4Address(dmz_port.get("ip_address")), subnet_mask=IPV4Address(dmz_port.get("subnet_mask")) + ) + if "acl" in cfg: + # acl rules for internal_inbound_acl + if cfg["acl"]["internal_inbound_acl"]: + new.internal_inbound_acl._default_config = cfg["acl"]["internal_inbound_acl"] + new.internal_inbound_acl._reset_rules_to_default() + + # acl rules for internal_outbound_acl + if cfg["acl"]["internal_outbound_acl"]: + new.internal_outbound_acl._default_config = cfg["acl"]["internal_outbound_acl"] + new.internal_outbound_acl._reset_rules_to_default() + + # acl rules for dmz_inbound_acl + if cfg["acl"]["dmz_inbound_acl"]: + new.dmz_inbound_acl._default_config = cfg["acl"]["dmz_inbound_acl"] + new.dmz_inbound_acl._reset_rules_to_default() + + # acl rules for dmz_outbound_acl + if cfg["acl"]["dmz_outbound_acl"]: + new.dmz_outbound_acl._default_config = cfg["acl"]["dmz_outbound_acl"] + new.dmz_outbound_acl._reset_rules_to_default() + + # acl rules for external_inbound_acl + if cfg["acl"]["external_inbound_acl"]: + new.external_inbound_acl._default_config = cfg["acl"]["external_inbound_acl"] + new.external_inbound_acl._reset_rules_to_default() + + # acl rules for external_outbound_acl + if cfg["acl"]["external_outbound_acl"]: + new.external_outbound_acl._default_config = cfg["acl"]["external_outbound_acl"] + new.external_outbound_acl._reset_rules_to_default() + if "routes" in cfg: + for route in cfg.get("routes"): + new.route_table.add_route( + address=IPv4Address(route.get("address")), + subnet_mask=IPv4Address(route.get("subnet_mask")), + next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")), + metric=float(route.get("metric")), + ) + return new diff --git a/src/primaite/simulator/network/hardware/nodes/network/router.py b/src/primaite/simulator/network/hardware/nodes/network/router.py index fd18ce70..d52028a8 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/router.py +++ b/src/primaite/simulator/network/hardware/nodes/network/router.py @@ -1500,7 +1500,7 @@ class Router(NetworkNode): new.route_table.add_route( address=IPv4Address(route.get("address")), subnet_mask=IPv4Address(route.get("subnet_mask")), - next_hop_ip_address=IPv4Address(route.get("subnet_mask")), + next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")), metric=float(route.get("metric")), ) return new diff --git a/tests/assets/configs/dmz_network.yaml b/tests/assets/configs/dmz_network.yaml index 0c67ba7c..1a099e41 100644 --- a/tests/assets/configs/dmz_network.yaml +++ b/tests/assets/configs/dmz_network.yaml @@ -6,19 +6,19 @@ # . . # . Internal Network . # . . -# . -------------- -------------- -------------- . -# . | client_1 |------| switch_1 |------| router_1 | . -# . -------------- -------------- -------------- . +# . -------------- -------------- -------------- . +# . | client_1 |------| switch_1 |--------| router_1 | . +# . -------------- -------------- -------------- . # . (Computer) | . -# ........................................................|..................... +# ........................................................|................... # | # | -# ........................................................|..................... +# ........................................................|................... # . | . # . DMZ Network | . # . | . # . ---------------- -------------- -------------- . -# . | dmz_server |------| switch_2 |------| router_2 | . +# . | dmz_server |------| switch_2 |------| firewall | . # . ---------------- -------------- -------------- . # . (Computer) | . # ........................................................|................... @@ -135,17 +135,17 @@ simulation: action: PERMIT protocol: ICMP routes: - - address: 192.168.10.10 + - address: 192.168.10.10 # route to dmz_server subnet_mask: 255.255.255.0 - next_hop_ip_address: 192.168.11.1 + next_hop_ip_address: 192.168.1.2 metric: 0 - - address: 192.168.20.10 + - address: 192.168.20.10 # route to external_computer subnet_mask: 255.255.255.0 - next_hop_ip_address: 192.168.11.1 + next_hop_ip_address: 192.168.1.2 metric: 0 - - address: 192.168.20.11 + - address: 192.168.20.11 # route to external_server subnet_mask: 255.255.255.0 - next_hop_ip_address: 192.168.11.1 + next_hop_ip_address: 192.168.1.2 metric: 0 - ref: dmz_server @@ -165,32 +165,72 @@ simulation: start_up_duration: 0 shut_down_duration: 0 - - ref: router_2 - type: router - hostname: router_2 - num_ports: 5 + - ref: firewall + type: firewall + hostname: firewall start_up_duration: 0 shut_down_duration: 0 ports: - 1: - ip_address: 192.168.10.1 - subnet_mask: 255.255.255.0 - 2: - ip_address: 192.168.11.1 - subnet_mask: 255.255.255.0 - 3: + external_port: # port 1 ip_address: 192.168.20.1 subnet_mask: 255.255.255.0 + internal_port: # port 2 + ip_address: 192.168.1.2 + subnet_mask: 255.255.255.0 + dmz_port: # port 3 + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 acl: - 22: - action: PERMIT - src_port: ARP - dst_port: ARP - 23: - action: PERMIT - protocol: ICMP + internal_inbound_acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + internal_outbound_acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + dmz_inbound_acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + dmz_outbound_acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + external_inbound_acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP + external_outbound_acl: + 22: + action: PERMIT + src_port: ARP + dst_port: ARP + 23: + action: PERMIT + protocol: ICMP routes: - - address: 192.168.0.10 + - address: 192.168.0.10 # route to client_1 subnet_mask: 255.255.255.0 next_hop_ip_address: 192.168.1.1 metric: 0 @@ -234,14 +274,14 @@ simulation: endpoint_a_port: 1 endpoint_b_ref: switch_1 endpoint_b_port: 8 - - ref: router_1___router_2 - endpoint_a_ref: router_1 - endpoint_a_port: 2 - endpoint_b_ref: router_2 + - ref: router_1___firewall + endpoint_a_ref: firewall + endpoint_a_port: 2 # internal firewall port + endpoint_b_ref: router_1 endpoint_b_port: 2 - - ref: router_2___switch_2 - endpoint_a_ref: router_2 - endpoint_a_port: 1 + - ref: firewall___switch_2 + endpoint_a_ref: firewall + endpoint_a_port: 3 # dmz firewall port endpoint_b_ref: switch_2 endpoint_b_port: 8 - ref: dmz_server___switch_2 @@ -249,9 +289,9 @@ simulation: endpoint_a_port: 1 endpoint_b_ref: switch_2 endpoint_b_port: 1 - - ref: router_2___switch_3 - endpoint_a_ref: router_2 - endpoint_a_port: 3 + - ref: firewall___switch_3 + endpoint_a_ref: firewall + endpoint_a_port: 1 # external firewall port endpoint_b_ref: switch_3 endpoint_b_port: 8 - ref: external_computer___switch_3 diff --git a/tests/conftest.py b/tests/conftest.py index 5084c339..ada89026 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,9 +1,11 @@ # © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +from datetime import datetime from pathlib import Path from typing import Any, Dict, Tuple, Union import pytest import yaml +from _pytest.monkeypatch import MonkeyPatch from primaite import getLogger, PRIMAITE_PATHS from primaite.game.agent.actions import ActionManager @@ -12,6 +14,7 @@ from primaite.game.agent.observations import ICSObservation, ObservationManager from primaite.game.agent.rewards import RewardFunction from primaite.game.game import PrimaiteGame from primaite.session.session import PrimaiteSession +from primaite.simulator import SIM_OUTPUT from primaite.simulator.file_system.file_system import FileSystem from primaite.simulator.network.container import Network from primaite.simulator.network.hardware.nodes.host.computer import Computer @@ -29,6 +32,7 @@ from primaite.simulator.system.services.dns.dns_client import DNSClient from primaite.simulator.system.services.dns.dns_server import DNSServer from primaite.simulator.system.services.service import Service from primaite.simulator.system.services.web_server.web_server import WebServer +from tests import TEST_ASSETS_ROOT from tests.mock_and_patch.get_session_path_mock import temp_user_sessions_path ACTION_SPACE_NODE_VALUES = 1 @@ -37,6 +41,21 @@ ACTION_SPACE_NODE_ACTION_VALUES = 1 _LOGGER = getLogger(__name__) +@pytest.fixture(scope="function", autouse=True) +def set_syslog_output_to_true(): + """Will be run before each test.""" + monkeypatch = MonkeyPatch() + monkeypatch.setattr( + SIM_OUTPUT, + "path", + Path(TEST_ASSETS_ROOT.parent.parent / "simulation_output" / datetime.now().strftime("%Y-%m-%d_%H-%M-%S")), + ) + monkeypatch.setattr(SIM_OUTPUT, "save_pcap_logs", True) + monkeypatch.setattr(SIM_OUTPUT, "save_sys_logs", True) + + yield + + class TestService(Service): """Test Service class""" diff --git a/tests/integration_tests/configuration_file_parsing/__init__.py b/tests/integration_tests/configuration_file_parsing/__init__.py index e69de29b..1c8481d6 100644 --- a/tests/integration_tests/configuration_file_parsing/__init__.py +++ b/tests/integration_tests/configuration_file_parsing/__init__.py @@ -0,0 +1,19 @@ +from pathlib import Path +from typing import Union + +import yaml + +from primaite.game.game import PrimaiteGame +from tests import TEST_ASSETS_ROOT + +BASIC_CONFIG = TEST_ASSETS_ROOT / "configs/basic_switched_network.yaml" + +DMZ_NETWORK = TEST_ASSETS_ROOT / "configs/dmz_network.yaml" + + +def load_config(config_path: Union[str, Path]) -> PrimaiteGame: + """Returns a PrimaiteGame object which loads the contents of a given yaml path.""" + with open(config_path, "r") as f: + cfg = yaml.safe_load(f) + + return PrimaiteGame.from_config(cfg) diff --git a/tests/integration_tests/configuration_file_parsing/nodes/__init__.py b/tests/integration_tests/configuration_file_parsing/nodes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/__init__.py b/tests/integration_tests/configuration_file_parsing/nodes/network/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py b/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py new file mode 100644 index 00000000..65fe8c6d --- /dev/null +++ b/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py @@ -0,0 +1,45 @@ +import pytest + +from primaite.simulator.network.container import Network +from primaite.simulator.network.hardware.nodes.host.computer import Computer +from primaite.simulator.network.hardware.nodes.host.server import Server +from primaite.simulator.network.hardware.nodes.network.firewall import Firewall +from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config + + +@pytest.fixture(scope="function") +def dmz_config() -> Network: + game = load_config(DMZ_NETWORK) + return game.simulation.network + + +def test_firewall_is_in_configuration(dmz_config): + """Test that the firewall exists in the configuration file.""" + network: Network = dmz_config + + assert network.get_node_by_hostname("firewall") + + +def test_firewall_routes_are_correctly_added(dmz_config): + """Test that the firewall routes have been correctly added to and configured in the network.""" + network: Network = dmz_config + + firewall: Firewall = network.get_node_by_hostname("firewall") + client_1: Computer = network.get_node_by_hostname("client_1") + dmz_server: Server = network.get_node_by_hostname("dmz_server") + external_computer: Computer = network.get_node_by_hostname("external_computer") + external_server: Server = network.get_node_by_hostname("external_server") + + # there should be a route to client_1 + assert firewall.route_table.find_best_route(client_1.network_interface[1].ip_address) + assert dmz_server.ping(client_1.network_interface[1].ip_address) + assert external_computer.ping(client_1.network_interface[1].ip_address) + assert external_server.ping(client_1.network_interface[1].ip_address) + + +def test_firewall_acl_rules_correctly_added(): + """ + Test that makes sure that the firewall ACLs have been configured onto the firewall + node via configuration file. + """ + pass diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py b/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py new file mode 100644 index 00000000..d09d2e94 --- /dev/null +++ b/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py @@ -0,0 +1,54 @@ +import pytest + +from primaite.simulator.network.container import Network +from primaite.simulator.network.hardware.nodes.host.computer import Computer +from primaite.simulator.network.hardware.nodes.host.server import Server +from primaite.simulator.network.hardware.nodes.network.router import Router +from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config + + +@pytest.fixture(scope="function") +def dmz_config() -> Network: + game = load_config(DMZ_NETWORK) + return game.simulation.network + + +def test_router_is_in_configuration(dmz_config): + """Test that the router exists in the configuration file.""" + network: Network = dmz_config + + assert network.get_node_by_hostname("router_1") + + +def test_router_routes_are_correctly_added(dmz_config): + """Test that makes sure that router routes have been added from the configuration file.""" + network: Network = dmz_config + + router_1: Router = network.get_node_by_hostname("router_1") + client_1: Computer = network.get_node_by_hostname("client_1") + dmz_server: Server = network.get_node_by_hostname("dmz_server") + external_computer: Computer = network.get_node_by_hostname("external_computer") + external_server: Server = network.get_node_by_hostname("external_server") + + # there should be a route to dmz_server + assert router_1.route_table.find_best_route(dmz_server.network_interface[1].ip_address) + assert client_1.ping(dmz_server.network_interface[1].ip_address) + assert external_computer.ping(dmz_server.network_interface[1].ip_address) + assert external_server.ping(dmz_server.network_interface[1].ip_address) + + # there should be a route to external_computer + assert router_1.route_table.find_best_route(external_computer.network_interface[1].ip_address) + assert client_1.ping(external_computer.network_interface[1].ip_address) + assert dmz_server.ping(external_computer.network_interface[1].ip_address) + assert external_server.ping(external_computer.network_interface[1].ip_address) + + # there should be a route to external_server + assert router_1.route_table.find_best_route(external_server.network_interface[1].ip_address) + assert client_1.ping(external_server.network_interface[1].ip_address) + assert dmz_server.ping(external_server.network_interface[1].ip_address) + assert external_computer.ping(external_server.network_interface[1].ip_address) + + +def test_router_acl_rules_correctly_added(): + """Test that makes sure that the router ACLs have been configured onto the router node via configuration file.""" + pass diff --git a/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py b/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py new file mode 100644 index 00000000..e222bfaf --- /dev/null +++ b/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py @@ -0,0 +1,26 @@ +from primaite.config.load import example_config_path +from primaite.simulator.network.container import Network +from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config + + +def test_example_config(): + """Test that the example config can be parsed properly.""" + game = load_config(example_config_path()) + network: Network = game.simulation.network + + assert len(network.nodes) == 10 # 10 nodes in example network + assert len(network.routers) == 1 # 1 router in network + assert len(network.switches) == 2 # 2 switches in network + assert len(network.servers) == 5 # 5 servers in network + + +def test_dmz_config(): + """Test that the DMZ network config can be parsed properly.""" + game = load_config(DMZ_NETWORK) + + network: Network = game.simulation.network + + assert len(network.nodes) == 9 # 9 nodes in network + assert len(network.routers) == 2 # 2 routers in network + assert len(network.switches) == 3 # 3 switches in network + assert len(network.servers) == 2 # 2 servers in network diff --git a/tests/integration_tests/configuration_file_parsing/router_game_configuration.py b/tests/integration_tests/configuration_file_parsing/router_game_configuration.py deleted file mode 100644 index 9d682dcc..00000000 --- a/tests/integration_tests/configuration_file_parsing/router_game_configuration.py +++ /dev/null @@ -1,76 +0,0 @@ -from pathlib import Path -from typing import Union - -import yaml - -from primaite.game.game import PrimaiteGame -from primaite.simulator.network.container import Network -from primaite.simulator.network.hardware.nodes.host.computer import Computer -from primaite.simulator.network.hardware.nodes.host.server import Server -from primaite.simulator.network.hardware.nodes.network.router import Router -from tests import TEST_ASSETS_ROOT - -DMZ_NETWORK = TEST_ASSETS_ROOT / "configs/dmz_network.yaml" - - -def load_config(config_path: Union[str, Path]) -> PrimaiteGame: - """Returns a PrimaiteGame object which loads the contents of a given yaml path.""" - with open(config_path, "r") as f: - cfg = yaml.safe_load(f) - - return PrimaiteGame.from_config(cfg) - - -def test_dmz_config(): - """Test that the DMZ network config can be parsed properly.""" - game = load_config(DMZ_NETWORK) - - network: Network = game.simulation.network - - assert len(network.nodes) == 9 # 9 nodes in network - assert len(network.routers) == 2 # 2 routers in network - assert len(network.switches) == 3 # 3 switches in network - assert len(network.servers) == 2 # 2 servers in network - - -def test_router_routes_are_correctly_added(): - """Test that makes sure that router routes have been added from the configuration file.""" - game = load_config(DMZ_NETWORK) - - network: Network = game.simulation.network - - router_1: Router = network.get_node_by_hostname("router_1") - client_1: Computer = network.get_node_by_hostname("client_1") - dmz_server: Server = network.get_node_by_hostname("dmz_server") - external_computer: Computer = network.get_node_by_hostname("external_computer") - external_server: Server = network.get_node_by_hostname("external_server") - - # test that client_1 has a route to the DMZ and external nodes - they are on a second router - - # there should be a route to the dmz server - assert router_1.route_table.find_best_route(dmz_server.network_interface[1].ip_address) - # ping DMZ server - # assert client_1.ping(dmz_server.network_interface[1].ip_address) - - -def test_firewall_node_added_to_network(): - """Test that the firewall has been correctly added to and configured in the network.""" - pass - - -def test_router_acl_rules_correctly_added(): - """Test that makes sure that the router ACLs have been configured onto the router node via configuration file.""" - pass - - -def test_firewall_routes_are_correctly_added(): - """Test that the firewall routes have been correctly added to and configured in the network.""" - pass - - -def test_firewall_acl_rules_correctly_added(): - """ - Test that makes sure that the firewall ACLs have been configured onto the firewall - node via configuration file. - """ - pass diff --git a/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py b/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py index 3bd870e3..54dca371 100644 --- a/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py +++ b/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py @@ -1,14 +1,6 @@ from ipaddress import IPv4Address -from pathlib import Path -from typing import Union -import yaml - -from primaite.config.load import example_config_path -from primaite.game.agent.data_manipulation_bot import DataManipulationAgent -from primaite.game.agent.interface import ProxyAgent, RandomAgent -from primaite.game.game import APPLICATION_TYPES_MAPPING, PrimaiteGame, SERVICE_TYPES_MAPPING -from primaite.simulator.network.container import Network +from primaite.game.game import APPLICATION_TYPES_MAPPING, SERVICE_TYPES_MAPPING from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.system.applications.database_client import DatabaseClient from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot @@ -22,47 +14,7 @@ from primaite.simulator.system.services.ftp.ftp_server import FTPServer from primaite.simulator.system.services.ntp.ntp_client import NTPClient from primaite.simulator.system.services.ntp.ntp_server import NTPServer from primaite.simulator.system.services.web_server.web_server import WebServer -from tests import TEST_ASSETS_ROOT - -BASIC_CONFIG = TEST_ASSETS_ROOT / "configs/basic_switched_network.yaml" - - -def load_config(config_path: Union[str, Path]) -> PrimaiteGame: - """Returns a PrimaiteGame object which loads the contents of a given yaml path.""" - with open(config_path, "r") as f: - cfg = yaml.safe_load(f) - - return PrimaiteGame.from_config(cfg) - - -def test_example_config(): - """Test that the example config can be parsed properly.""" - game = load_config(example_config_path()) - - assert len(game.agents) == 4 # red, blue and 2 green agents - - # green agent 1 - assert game.agents[0].agent_name == "client_2_green_user" - assert isinstance(game.agents[0], RandomAgent) - - # green agent 2 - assert game.agents[1].agent_name == "client_1_green_user" - assert isinstance(game.agents[1], RandomAgent) - - # red agent - assert game.agents[2].agent_name == "client_1_data_manipulation_red_bot" - assert isinstance(game.agents[2], DataManipulationAgent) - - # blue agent - assert game.agents[3].agent_name == "defender" - assert isinstance(game.agents[3], ProxyAgent) - - network: Network = game.simulation.network - - assert len(network.nodes) == 10 # 10 nodes in example network - assert len(network.routers) == 1 # 1 router in network - assert len(network.switches) == 2 # 2 switches in network - assert len(network.servers) == 5 # 5 servers in network +from tests.integration_tests.configuration_file_parsing import BASIC_CONFIG, load_config def test_node_software_install(): From e390d8385c9f5e54dd3c6a929c1557c4b6c38e44 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Thu, 15 Feb 2024 16:29:36 +0000 Subject: [PATCH 04/18] #2257: acl tests --- tests/assets/configs/dmz_network.yaml | 6 -- .../nodes/network/test_firewall_config.py | 61 ++++++++++++++++++- .../nodes/network/test_router_config.py | 17 +++++- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/tests/assets/configs/dmz_network.yaml b/tests/assets/configs/dmz_network.yaml index 1a099e41..971ed8cd 100644 --- a/tests/assets/configs/dmz_network.yaml +++ b/tests/assets/configs/dmz_network.yaml @@ -218,17 +218,11 @@ simulation: action: PERMIT src_port: ARP dst_port: ARP - 23: - action: PERMIT - protocol: ICMP external_outbound_acl: 22: action: PERMIT src_port: ARP dst_port: ARP - 23: - action: PERMIT - protocol: ICMP routes: - address: 192.168.0.10 # route to client_1 subnet_mask: 255.255.255.0 diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py b/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py index 65fe8c6d..ae71809b 100644 --- a/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py +++ b/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py @@ -4,6 +4,9 @@ from primaite.simulator.network.container import Network from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.network.firewall import Firewall +from primaite.simulator.network.hardware.nodes.network.router import ACLAction +from primaite.simulator.network.transmission.network_layer import IPProtocol +from primaite.simulator.network.transmission.transport_layer import Port from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config @@ -37,9 +40,63 @@ def test_firewall_routes_are_correctly_added(dmz_config): assert external_server.ping(client_1.network_interface[1].ip_address) -def test_firewall_acl_rules_correctly_added(): +def test_firewall_acl_rules_correctly_added(dmz_config): """ Test that makes sure that the firewall ACLs have been configured onto the firewall node via configuration file. """ - pass + firewall: Firewall = dmz_config.get_node_by_hostname("firewall") + + # ICMP and ARP should be allowed internal_inbound + assert firewall.internal_inbound_acl.num_rules == 2 + assert firewall.internal_inbound_acl.acl[22].action == ACLAction.PERMIT + assert firewall.internal_inbound_acl.acl[22].src_port == Port.ARP + assert firewall.internal_inbound_acl.acl[22].dst_port == Port.ARP + assert firewall.internal_inbound_acl.acl[23].action == ACLAction.PERMIT + assert firewall.internal_inbound_acl.acl[23].protocol == IPProtocol.ICMP + assert firewall.internal_inbound_acl.implicit_action == ACLAction.DENY + + # ICMP and ARP should be allowed internal_outbound + assert firewall.internal_outbound_acl.num_rules == 2 + assert firewall.internal_outbound_acl.acl[22].action == ACLAction.PERMIT + assert firewall.internal_outbound_acl.acl[22].src_port == Port.ARP + assert firewall.internal_outbound_acl.acl[22].dst_port == Port.ARP + assert firewall.internal_outbound_acl.acl[23].action == ACLAction.PERMIT + assert firewall.internal_outbound_acl.acl[23].protocol == IPProtocol.ICMP + assert firewall.internal_outbound_acl.implicit_action == ACLAction.DENY + + # ICMP and ARP should be allowed dmz_inbound + assert firewall.dmz_inbound_acl.num_rules == 2 + assert firewall.dmz_inbound_acl.acl[22].action == ACLAction.PERMIT + assert firewall.dmz_inbound_acl.acl[22].src_port == Port.ARP + assert firewall.dmz_inbound_acl.acl[22].dst_port == Port.ARP + assert firewall.dmz_inbound_acl.acl[23].action == ACLAction.PERMIT + assert firewall.dmz_inbound_acl.acl[23].protocol == IPProtocol.ICMP + assert firewall.dmz_inbound_acl.implicit_action == ACLAction.DENY + + # ICMP and ARP should be allowed dmz_outbound + assert firewall.dmz_outbound_acl.num_rules == 2 + assert firewall.dmz_outbound_acl.acl[22].action == ACLAction.PERMIT + assert firewall.dmz_outbound_acl.acl[22].src_port == Port.ARP + assert firewall.dmz_outbound_acl.acl[22].dst_port == Port.ARP + assert firewall.dmz_outbound_acl.acl[23].action == ACLAction.PERMIT + assert firewall.dmz_outbound_acl.acl[23].protocol == IPProtocol.ICMP + assert firewall.dmz_outbound_acl.implicit_action == ACLAction.DENY + + # ICMP and ARP should be allowed external_inbound + assert firewall.external_inbound_acl.num_rules == 1 + assert firewall.external_inbound_acl.acl[22].action == ACLAction.PERMIT + assert firewall.external_inbound_acl.acl[22].src_port == Port.ARP + assert firewall.external_inbound_acl.acl[22].dst_port == Port.ARP + # external_inbound should have implicit action PERMIT + # ICMP does not have a provided ACL Rule but implicit action should allow anything + assert firewall.external_inbound_acl.implicit_action == ACLAction.PERMIT + + # ICMP and ARP should be allowed external_outbound + assert firewall.external_outbound_acl.num_rules == 1 + assert firewall.external_outbound_acl.acl[22].action == ACLAction.PERMIT + assert firewall.external_outbound_acl.acl[22].src_port == Port.ARP + assert firewall.external_outbound_acl.acl[22].dst_port == Port.ARP + # external_outbound should have implicit action PERMIT + # ICMP does not have a provided ACL Rule but implicit action should allow anything + assert firewall.external_outbound_acl.implicit_action == ACLAction.PERMIT diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py b/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py index d09d2e94..fbaca12d 100644 --- a/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py +++ b/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py @@ -3,7 +3,9 @@ import pytest from primaite.simulator.network.container import Network from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.server import Server -from primaite.simulator.network.hardware.nodes.network.router import Router +from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router +from primaite.simulator.network.transmission.network_layer import IPProtocol +from primaite.simulator.network.transmission.transport_layer import Port from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config @@ -49,6 +51,15 @@ def test_router_routes_are_correctly_added(dmz_config): assert external_computer.ping(external_server.network_interface[1].ip_address) -def test_router_acl_rules_correctly_added(): +def test_router_acl_rules_correctly_added(dmz_config): """Test that makes sure that the router ACLs have been configured onto the router node via configuration file.""" - pass + router_1: Router = dmz_config.get_node_by_hostname("router_1") + + # ICMP and ARP should be allowed + assert router_1.acl.num_rules == 2 + assert router_1.acl.acl[22].action == ACLAction.PERMIT + assert router_1.acl.acl[22].src_port == Port.ARP + assert router_1.acl.acl[22].dst_port == Port.ARP + assert router_1.acl.acl[23].action == ACLAction.PERMIT + assert router_1.acl.acl[23].protocol == IPProtocol.ICMP + assert router_1.acl.implicit_action == ACLAction.DENY From 2e2d83c3e9775d1ba87f717abd0cba4937c37534 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Fri, 16 Feb 2024 16:14:36 +0000 Subject: [PATCH 05/18] #2257: update sphinx version + cleaning up some errors + splitting configuration page into multiple pages --- docs/api.rst | 2 + docs/conf.py | 11 +- docs/source/config.rst | 105 ++---------------- docs/source/configuration/agents.rst | 45 ++++++++ docs/source/configuration/game.rst | 8 ++ docs/source/configuration/io_settings.rst | 26 +++++ docs/source/configuration/simulation.rst | 27 +++++ docs/source/configuration/training_config.rst | 25 +++++ docs/source/dependencies.rst | 2 + docs/source/request_system.rst | 4 +- docs/source/simulation.rst | 2 +- .../network/base_hardware.rst | 59 ++++++++++ .../simulation_components/system/software.rst | 1 + docs/source/state_system.rst | 2 +- pyproject.toml | 4 +- 15 files changed, 220 insertions(+), 103 deletions(-) create mode 100644 docs/source/configuration/agents.rst create mode 100644 docs/source/configuration/game.rst create mode 100644 docs/source/configuration/io_settings.rst create mode 100644 docs/source/configuration/simulation.rst create mode 100644 docs/source/configuration/training_config.rst diff --git a/docs/api.rst b/docs/api.rst index aeaef4e2..13f3a1ec 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,3 +1,5 @@ +:orphan: + .. only:: comment © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK diff --git a/docs/conf.py b/docs/conf.py index efd60b49..6cdc0ac4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,6 @@ import furo # noqa sys.path.insert(0, os.path.abspath("../")) - # -- Project information ----------------------------------------------------- year = datetime.datetime.now().year project = "PrimAITE" @@ -45,13 +44,17 @@ extensions = [ "sphinx_copybutton", # Adds a copy button to code blocks ] - templates_path = ["_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", +] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "furo" html_static_path = ["_static"] +html_theme_options = {"globaltoc_collapse": True, "globaltoc_maxdepth": 2} +html_copy_source = False diff --git a/docs/source/config.rst b/docs/source/config.rst index 575a3139..46631ab9 100644 --- a/docs/source/config.rst +++ b/docs/source/config.rst @@ -1,3 +1,7 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + Primaite v3 config ****************** @@ -5,98 +9,13 @@ PrimAITE uses a single configuration file to define everything needed to train a The entire config is used by the ``PrimaiteSession`` object for users who wish to let PrimAITE handle the agent definition and training. If you wish to define custom agents and control the training loop yourself, you can use the config with the ``PrimaiteGame``, and ``PrimaiteGymEnv`` objects instead. That way, only the network configuration and agent setup parts of the config are used, and the training section is ignored. Configurable items -================== +################## -``training_config`` -------------------- -This section allows selecting which training framework and algorithm to use, and set some training hyperparameters. +.. toctree:: + :maxdepth: 1 -``io_settings`` ---------------- -This section configures how PrimAITE saves data during simulation and training. - -**save_final_model**: Only used if training with PrimaiteSession, if true, the policy will be saved after the final training iteration. - -**save_checkpoints**: Only used if training with PrimaiteSession, if true, the policy will be saved periodically during training. - -**checkpoint_interval**: Only used if training with PrimaiteSession and if ``save_checkpoints`` is true. Defines how often to save the policy during training. - -**save_logs**: *currently unused*. - -**save_transactions**: *currently unused*. - -**save_tensorboard_logs**: *currently unused*. - -**save_step_metadata**: Whether to save the RL agents' action, environment state, and other data at every single step. - -**save_pcap_logs**: Whether to save pcap files of all network traffic during the simulation. - -**save_sys_logs**: Whether to save system logs from all nodes during the simulation. - -``game`` --------- -This section defines high-level settings that apply across the game, currently it's used to help shape the action and observation spaces by restricting which ports and internet protocols should be considered. Here, users can also set the maximum number of steps in an episode. - -``agents`` ----------- -Agents can be scripted (deterministic and stochastic), or controlled by a reinforcement learning algorithm. Not to be confused with an RL agent, the term agent here is used to refer to an entity that sends requests to the simulated network. In this part of the config, each agent's action space, observation space, and reward function can be defined. All three are defined in a modular way. - -**type**: Specifies which class should be used for the agent. ``ProxyAgent`` is used for agents that receive instructions from an RL algorithm. Scripted agents like ``RedDatabaseCorruptingAgent`` and ``GreenWebBrowsingAgent`` generate their own behaviour. - -**team**: Specifies if the agent is malicious (RED), benign (GREEN), or defensive (BLUE). Currently this value is not used for anything. - -**observation space:** - * ``type``: selects which python class from the ``primaite.game.agent.observation`` module is used for the overall observation structure. - * ``options``: allows configuring the chosen observation type. The ``UC2BlueObservation`` should be used for RL Agents. - * ``num_services_per_node``, ``num_folders_per_node``, ``num_files_per_folder``, ``num_nics_per_node`` all define the shape of the observation space. The size and shape of the obs space must remain constant, but the number of files, folders, ACL rules, and other components can change within an episode. Therefore padding is performed and these options set the size of the obs space. - * ``nodes``: list of nodes that will be present in this agent's observation space. The ``node_ref`` relates to the human-readable unique reference defined later in the ``simulation`` part of the config. Each node can also be configured with services, and files that should be monitored. - * ``links``: list of links that will be present in this agent's observation space. The ``link_ref`` relates to the human-readable unique reference defined later in the ``simulation`` part of the config. - * ``acl``: configure how the agent reads the access control list on the router in the simulation. ``router_node_ref`` is for selecting which router's ACL table should be used. ``ip_address_order`` sets the encoding of ip addresses as integers within the observation space. - -**action space:** -The action space is configured to be made up of individual action types. Once configured, the agent can select an action type and some optional action parameters at every step. For example: The ``NODE_SERVICE_SCAN`` action takes the parameters ``node_id`` and ``service_id``. - -Description of configurable items: - * ``action_list``: a list of action modules. The options are listed in the ``primaite.game.agent.actions`` module. - * ``action_map``: (optional). Restricts the possible combinations of action type / action parameter values to reduce the overall size of the action space. By default, every possible combination of actions and parameters will be assigned an integer for the agent's ``MultiDiscrete`` action space. Instead, the ``action_map`` allows you to list the actions corresponding to each integer in the ``MultiDiscrete`` space. - * ``options``: Options that apply too all action components. - * ``nodes``: list the nodes that the agent can act on, the order of this list defines the mapping between nodes and ``node_id`` integers. - * ``max_folders_per_node``, ``max_files_per_folder``, ``max_services_per_node``, ``max_nics_per_node``, ``max_acl_rules`` all are used to define the size of the action space. - -**reward function:** -Similar to action space, this is defined as a list of components. - -Description of configurable items: - * ``reward_components`` a list of reward components from the ``primaite.game.agent.reward`` module. - * ``weight``: relative importance of this reward component. The total reward for a step is a weighted sum of all reward components. - * ``options``: list of options passed to the reward component during initialisation, the exact options required depend on the reward component. - -**agent_settings**: -Settings passed to the agent during initialisation. These depend on the agent class. - -Reinforcement learning agents use the ``ProxyAgent`` class, they accept these agent settings: - -**flatten_obs**: If true, gymnasium flattening will be performed on the observation space before sending to the agent. Set this to true if your agent does not support nested observation spaces. - -``simulation`` --------------- -In this section the network layout is defined. This part of the config follows a hierarchical structure. Almost every component defines a ``ref`` field which acts as a human-readable unique identifier, used by other parts of the config, such as agents. - -At the top level of the network are ``nodes`` and ``links``. - -**nodes:** - * ``type``: one of ``router``, ``switch``, ``computer``, or ``server``, this affects what other sub-options should be defined. - * ``hostname`` - a non-unique name used for logging and outputs. - * ``num_ports`` (optional, routers and switches only): number of network interfaces present on the device. - * ``ports`` (optional, routers and switches only): configuration for each network interface, including IP address and subnet mask. - * ``acl`` (Router only): Define the ACL rules at each index of the ACL on the router. the possible options are: ``action`` (PERMIT or DENY), ``src_port``, ``dst_port``, ``protocol``, ``src_ip``, ``dst_ip``. Any options left blank default to none which usually means that it will apply across all options. For example leaving ``src_ip`` blank will apply the rule to all IP addresses. - * ``services`` (computers and servers only): a list of services to install on the node. They must define a ``ref``, ``type``, and ``options`` that depend on which ``type`` was selected. - * ``applications`` (computer and servers only): Similar to services. A list of application to install on the node. - * ``network_interfaces`` (computers and servers only): If the node has multiple networking devices, the second, third, fourth, etc... must be defined here with an ``ip_address`` and ``subnet_mask``. - -**links:** - * ``ref``: unique identifier for this link - * ``endpoint_a_ref``: Reference to the node at the first end of the link - * ``endpoint_a_port``: The ethernet port or switch port index of the second node - * ``endpoint_b_ref``: Reference to the node at the second end of the link - * ``endpoint_b_port``: The ethernet port or switch port index on the second node + configuration/training_config.rst + configuration/io_settings.rst + configuration/game.rst + configuration/agents.rst + configuration/simulation.rst diff --git a/docs/source/configuration/agents.rst b/docs/source/configuration/agents.rst new file mode 100644 index 00000000..4d81c89d --- /dev/null +++ b/docs/source/configuration/agents.rst @@ -0,0 +1,45 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + + +``agents`` +========== +Agents can be scripted (deterministic and stochastic), or controlled by a reinforcement learning algorithm. Not to be confused with an RL agent, the term agent here is used to refer to an entity that sends requests to the simulated network. In this part of the config, each agent's action space, observation space, and reward function can be defined. All three are defined in a modular way. + +**type**: Specifies which class should be used for the agent. ``ProxyAgent`` is used for agents that receive instructions from an RL algorithm. Scripted agents like ``RedDatabaseCorruptingAgent`` and ``GreenWebBrowsingAgent`` generate their own behaviour. + +**team**: Specifies if the agent is malicious (RED), benign (GREEN), or defensive (BLUE). Currently this value is not used for anything. + +**observation space:** + * ``type``: selects which python class from the ``primaite.game.agent.observation`` module is used for the overall observation structure. + * ``options``: allows configuring the chosen observation type. The ``UC2BlueObservation`` should be used for RL Agents. + * ``num_services_per_node``, ``num_folders_per_node``, ``num_files_per_folder``, ``num_nics_per_node`` all define the shape of the observation space. The size and shape of the obs space must remain constant, but the number of files, folders, ACL rules, and other components can change within an episode. Therefore padding is performed and these options set the size of the obs space. + * ``nodes``: list of nodes that will be present in this agent's observation space. The ``node_ref`` relates to the human-readable unique reference defined later in the ``simulation`` part of the config. Each node can also be configured with services, and files that should be monitored. + * ``links``: list of links that will be present in this agent's observation space. The ``link_ref`` relates to the human-readable unique reference defined later in the ``simulation`` part of the config. + * ``acl``: configure how the agent reads the access control list on the router in the simulation. ``router_node_ref`` is for selecting which router's ACL table should be used. ``ip_address_order`` sets the encoding of ip addresses as integers within the observation space. + +**action space:** +The action space is configured to be made up of individual action types. Once configured, the agent can select an action type and some optional action parameters at every step. For example: The ``NODE_SERVICE_SCAN`` action takes the parameters ``node_id`` and ``service_id``. + +Description of configurable items: + * ``action_list``: a list of action modules. The options are listed in the ``primaite.game.agent.actions`` module. + * ``action_map``: (optional). Restricts the possible combinations of action type / action parameter values to reduce the overall size of the action space. By default, every possible combination of actions and parameters will be assigned an integer for the agent's ``MultiDiscrete`` action space. Instead, the ``action_map`` allows you to list the actions corresponding to each integer in the ``MultiDiscrete`` space. + * ``options``: Options that apply too all action components. + * ``nodes``: list the nodes that the agent can act on, the order of this list defines the mapping between nodes and ``node_id`` integers. + * ``max_folders_per_node``, ``max_files_per_folder``, ``max_services_per_node``, ``max_nics_per_node``, ``max_acl_rules`` all are used to define the size of the action space. + +**reward function:** +Similar to action space, this is defined as a list of components. + +Description of configurable items: + * ``reward_components`` a list of reward components from the ``primaite.game.agent.reward`` module. + * ``weight``: relative importance of this reward component. The total reward for a step is a weighted sum of all reward components. + * ``options``: list of options passed to the reward component during initialisation, the exact options required depend on the reward component. + +**agent_settings**: +Settings passed to the agent during initialisation. These depend on the agent class. + +Reinforcement learning agents use the ``ProxyAgent`` class, they accept these agent settings: + +**flatten_obs**: If true, gymnasium flattening will be performed on the observation space before sending to the agent. Set this to true if your agent does not support nested observation spaces. diff --git a/docs/source/configuration/game.rst b/docs/source/configuration/game.rst new file mode 100644 index 00000000..797c3813 --- /dev/null +++ b/docs/source/configuration/game.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + + +``game`` +======== +This section defines high-level settings that apply across the game, currently it's used to help shape the action and observation spaces by restricting which ports and internet protocols should be considered. Here, users can also set the maximum number of steps in an episode. diff --git a/docs/source/configuration/io_settings.rst b/docs/source/configuration/io_settings.rst new file mode 100644 index 00000000..11d044bb --- /dev/null +++ b/docs/source/configuration/io_settings.rst @@ -0,0 +1,26 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + + +``io_settings`` +=============== +This section configures how PrimAITE saves data during simulation and training. + +**save_final_model**: Only used if training with PrimaiteSession, if true, the policy will be saved after the final training iteration. + +**save_checkpoints**: Only used if training with PrimaiteSession, if true, the policy will be saved periodically during training. + +**checkpoint_interval**: Only used if training with PrimaiteSession and if ``save_checkpoints`` is true. Defines how often to save the policy during training. + +**save_logs**: *currently unused*. + +**save_transactions**: *currently unused*. + +**save_tensorboard_logs**: *currently unused*. + +**save_step_metadata**: Whether to save the RL agents' action, environment state, and other data at every single step. + +**save_pcap_logs**: Whether to save pcap files of all network traffic during the simulation. + +**save_sys_logs**: Whether to save system logs from all nodes during the simulation. diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst new file mode 100644 index 00000000..eb13e2be --- /dev/null +++ b/docs/source/configuration/simulation.rst @@ -0,0 +1,27 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + + +``simulation`` +============== +In this section the network layout is defined. This part of the config follows a hierarchical structure. Almost every component defines a ``ref`` field which acts as a human-readable unique identifier, used by other parts of the config, such as agents. + +At the top level of the network are ``nodes`` and ``links``. + +**nodes:** + * ``type``: one of ``router``, ``switch``, ``computer``, or ``server``, this affects what other sub-options should be defined. + * ``hostname`` - a non-unique name used for logging and outputs. + * ``num_ports`` (optional, routers and switches only): number of network interfaces present on the device. + * ``ports`` (optional, routers and switches only): configuration for each network interface, including IP address and subnet mask. + * ``acl`` (Router only): Define the ACL rules at each index of the ACL on the router. the possible options are: ``action`` (PERMIT or DENY), ``src_port``, ``dst_port``, ``protocol``, ``src_ip``, ``dst_ip``. Any options left blank default to none which usually means that it will apply across all options. For example leaving ``src_ip`` blank will apply the rule to all IP addresses. + * ``services`` (computers and servers only): a list of services to install on the node. They must define a ``ref``, ``type``, and ``options`` that depend on which ``type`` was selected. + * ``applications`` (computer and servers only): Similar to services. A list of application to install on the node. + * ``network_interfaces`` (computers and servers only): If the node has multiple networking devices, the second, third, fourth, etc... must be defined here with an ``ip_address`` and ``subnet_mask``. + +**links:** + * ``ref``: unique identifier for this link + * ``endpoint_a_ref``: Reference to the node at the first end of the link + * ``endpoint_a_port``: The ethernet port or switch port index of the second node + * ``endpoint_b_ref``: Reference to the node at the second end of the link + * ``endpoint_b_port``: The ethernet port or switch port index on the second node diff --git a/docs/source/configuration/training_config.rst b/docs/source/configuration/training_config.rst new file mode 100644 index 00000000..cde6cf52 --- /dev/null +++ b/docs/source/configuration/training_config.rst @@ -0,0 +1,25 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``training_config`` +=================== + +``rl_framework`` +---------------- +The RL (Reinforcement Learning) Framework to use in the training session + +Options available are: + +- ``SB3`` (Stable Baselines 3) +- ``RLLIB_single_agent`` (Single Agent Ray RLLib) +- ``RLLIB_multi_agent`` (Multi Agent Ray RLLib) + +``rl_algorithm`` +---------------- +The Reinforcement Learning Algorithm to use in the training session + +Options available are: + +- ``PPO`` (Proximal Policy Optimisation) +- ``A2C`` (Advantage Actor Critic) diff --git a/docs/source/dependencies.rst b/docs/source/dependencies.rst index 942ccfd8..ddea27fa 100644 --- a/docs/source/dependencies.rst +++ b/docs/source/dependencies.rst @@ -5,6 +5,8 @@ .. role:: raw-html(raw) :format: html +.. _Dependencies: + Dependencies ============ diff --git a/docs/source/request_system.rst b/docs/source/request_system.rst index 392bc792..e4c5584e 100644 --- a/docs/source/request_system.rst +++ b/docs/source/request_system.rst @@ -36,7 +36,7 @@ Technical Detail This system was achieved by implementing two classes, :py:class:`primaite.simulator.core.RequestType`, and :py:class:`primaite.simulator.core.RequestManager`. ``RequestType`` ------- +--------------- The ``RequestType`` object stores a reference to a method that executes the request, for example a node could have a request type that stores a reference to ``self.turn_on()``. Technically, this can be any callable that accepts `request, context` as it's parameters. In practice, this is often defined using ``lambda`` functions within a component's ``self._init_request_manager()`` method. Optionally, the ``RequestType`` object can also hold a validator that will permit/deny the request depending on context. @@ -60,7 +60,7 @@ A simple example without chaining can be seen in the :py:class:`primaite.simulat *ellipses (``...``) used to omit code impertinent to this explanation* Chaining RequestManagers ------------------------ +------------------------ A request function needs to be a callable that accepts ``request, context`` as parameters. Since the request manager resolves requests by invoking it with ``request, context`` as parameter, it is possible to use a ``RequestManager`` as a ``RequestType``. diff --git a/docs/source/simulation.rst b/docs/source/simulation.rst index c703b299..c4bf1bf0 100644 --- a/docs/source/simulation.rst +++ b/docs/source/simulation.rst @@ -22,9 +22,9 @@ Contents simulation_components/network/nodes/host_node simulation_components/network/nodes/network_node simulation_components/network/nodes/router + simulation_components/network/nodes/switch simulation_components/network/nodes/wireless_router simulation_components/network/nodes/firewall - simulation_components/network/switch simulation_components/network/network simulation_components/system/internal_frame_processing simulation_components/system/sys_log diff --git a/docs/source/simulation_components/network/base_hardware.rst b/docs/source/simulation_components/network/base_hardware.rst index c7545810..3aa6b073 100644 --- a/docs/source/simulation_components/network/base_hardware.rst +++ b/docs/source/simulation_components/network/base_hardware.rst @@ -41,6 +41,65 @@ Node Attributes - **session_manager**: Manages user sessions within the node. - **software_manager**: Controls the installation and management of software and services on the node. +.. _Node Start up and Shut down: + +Node Start up and Shut down +--------------------------- +Nodes are powered on and off over multiple timesteps. By default, the node ``start_up_duration`` and ``shut_down_duration`` is 3 timesteps. + +Example code where a node is turned on: + +.. code-block:: python + + from primaite.simulator.network.hardware.base import Node + from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState + + node = Node(hostname="pc_a") + + assert node.operating_state is NodeOperatingState.OFF # By default, node is instantiated in an OFF state + + node.power_on() # power on the node + + assert node.operating_state is NodeOperatingState.BOOTING # node is booting up + + for i in range(node.start_up_duration + 1): + # apply timestep until the node start up duration + node.apply_timestep(timestep=i) + + assert node.operating_state is NodeOperatingState.ON # node is in ON state + + +If the node needs to be instantiated in an on state: + + +.. code-block:: python + + from primaite.simulator.network.hardware.base import Node + from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState + + node = Node(hostname="pc_a", operating_state=NodeOperatingState.ON) + + assert node.operating_state is NodeOperatingState.ON # node is in ON state + +Setting ``start_up_duration`` and/or ``shut_down_duration`` to ``0`` will allow for the ``power_on`` and ``power_off`` methods to be completed instantly without applying timesteps: + +.. code-block:: python + + from primaite.simulator.network.hardware.base import Node + from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState + + node = Node(hostname="pc_a", start_up_duration=0, shut_down_duration=0) + + assert node.operating_state is NodeOperatingState.OFF # node is in OFF state + + node.power_on() + + assert node.operating_state is NodeOperatingState.ON # node is in ON state + + node.power_off() + + assert node.operating_state is NodeOperatingState.OFF # node is in OFF state + Node Behaviours/Functions ------------------------- diff --git a/docs/source/simulation_components/system/software.rst b/docs/source/simulation_components/system/software.rst index cd6b0aa3..7a1359f4 100644 --- a/docs/source/simulation_components/system/software.rst +++ b/docs/source/simulation_components/system/software.rst @@ -50,4 +50,5 @@ Services, Processes and Applications: data_manipulation_bot dns_client_server ftp_client_server + ntp_client_server web_browser_and_web_server_service diff --git a/docs/source/state_system.rst b/docs/source/state_system.rst index 860c9827..0bbbdd34 100644 --- a/docs/source/state_system.rst +++ b/docs/source/state_system.rst @@ -3,7 +3,7 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK Simulation State -============== +================ ``SimComponent`` objects in the simulation have a method called ``describe_state`` which return a dictionary of the state of the component. This is used to report pertinent data that could impact an agent's actions or rewards. For instance, the name and health status of a node is reported, which can be used by a reward function to punish corrupted or compromised nodes and reward healthy nodes. Each ``SimComponent`` object reports not only its own attributes in the state but also those of its child components. I.e. a computer node will report the state of its ``FileSystem`` and the ``FileSystem`` will report the state of its files and folders. This happens by recursively calling the childrens' own ``describe_state`` methods. diff --git a/pyproject.toml b/pyproject.toml index 3e5b959a..44ce75c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ dev = [ "build==0.10.0", "flake8==6.0.0", "flake8-annotations", - "furo==2023.3.27", + "furo==2024.01.29", "gputil==1.4.0", "pip-licenses==4.3.0", "pre-commit==2.20.0", @@ -67,7 +67,7 @@ dev = [ "pytest-cov==4.0.0", "pytest-flake8==1.1.1", "setuptools==66", - "Sphinx==6.1.3", + "Sphinx==7.2.6", "sphinx-copybutton==0.5.2", "wheel==0.38.4" ] From deb7a3aa9d066ae4b25aa995628a9ac7d33e3c34 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Wed, 21 Feb 2024 14:49:59 +0000 Subject: [PATCH 06/18] #2257: massive docs addition for config file --- docs/_static/firewall_acl.png | Bin 0 -> 36036 bytes docs/_static/switched_p2p_network.png | Bin 0 -> 9178 bytes docs/source/config.rst | 19 ++ docs/source/configuration/agents.rst | 181 ++++++++++-- docs/source/configuration/game.rst | 38 +++ docs/source/configuration/io_settings.rst | 81 +++++- docs/source/configuration/simulation.rst | 89 +++++- .../common/common_host_node_attributes.rst | 41 +++ .../common/common_network_node_attributes.rst | 49 ++++ .../nodes/common/common_node_attributes.rst | 13 + .../nodes/common/node_type_list.rst | 18 ++ .../simulation/nodes/computer.rst | 39 +++ .../simulation/nodes/firewall.rst | 258 ++++++++++++++++++ .../configuration/simulation/nodes/router.rst | 125 +++++++++ .../configuration/simulation/nodes/server.rst | 39 +++ .../configuration/simulation/nodes/switch.rst | 37 +++ .../simulation/software/applications.rst | 10 + .../simulation/software/services.rst | 10 + docs/source/configuration/training_config.rst | 50 ++++ .../config/_package_data/example_config.yaml | 20 +- src/primaite/game/agent/actions.py | 4 +- src/primaite/game/agent/rewards.py | 5 +- src/primaite/game/game.py | 10 +- .../hardware/nodes/network/firewall.py | 12 +- .../network/hardware/nodes/network/router.py | 8 +- .../network/transmission/network_layer.py | 9 +- .../network/transmission/transport_layer.py | 6 +- tests/assets/configs/dmz_network.yaml | 2 +- 28 files changed, 1101 insertions(+), 72 deletions(-) create mode 100644 docs/_static/firewall_acl.png create mode 100644 docs/_static/switched_p2p_network.png create mode 100644 docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst create mode 100644 docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst create mode 100644 docs/source/configuration/simulation/nodes/common/common_node_attributes.rst create mode 100644 docs/source/configuration/simulation/nodes/common/node_type_list.rst create mode 100644 docs/source/configuration/simulation/nodes/computer.rst create mode 100644 docs/source/configuration/simulation/nodes/firewall.rst create mode 100644 docs/source/configuration/simulation/nodes/router.rst create mode 100644 docs/source/configuration/simulation/nodes/server.rst create mode 100644 docs/source/configuration/simulation/nodes/switch.rst create mode 100644 docs/source/configuration/simulation/software/applications.rst create mode 100644 docs/source/configuration/simulation/software/services.rst diff --git a/docs/_static/firewall_acl.png b/docs/_static/firewall_acl.png new file mode 100644 index 0000000000000000000000000000000000000000..1cdd25263cf0817dde59ae02124ab17879197237 GIT binary patch literal 36036 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 for a list of ports. + +``protocols`` +------------- + +A list of protocols that the Reinforcement Learning agent(s) are able to see in the observation space. + +See :ref:`List of IPProtocols ` for a list of protocols. diff --git a/docs/source/configuration/io_settings.rst b/docs/source/configuration/io_settings.rst index 11d044bb..96cc28fe 100644 --- a/docs/source/configuration/io_settings.rst +++ b/docs/source/configuration/io_settings.rst @@ -7,20 +7,83 @@ =============== This section configures how PrimAITE saves data during simulation and training. -**save_final_model**: Only used if training with PrimaiteSession, if true, the policy will be saved after the final training iteration. +``io_settings`` hierarchy +------------------------- -**save_checkpoints**: Only used if training with PrimaiteSession, if true, the policy will be saved periodically during training. +.. code-block:: yaml -**checkpoint_interval**: Only used if training with PrimaiteSession and if ``save_checkpoints`` is true. Defines how often to save the policy during training. + io_settings: + save_final_model: True + save_checkpoints: False + checkpoint_interval: 10 + # save_logs: True + # save_transactions: False + # save_tensorboard_logs: False + save_step_metadata: False + save_pcap_logs: False + save_sys_logs: False -**save_logs**: *currently unused*. +``save_final_model`` +-------------------- -**save_transactions**: *currently unused*. +Optional. Default value is ``True``. -**save_tensorboard_logs**: *currently unused*. +Only used if training with PrimaiteSession. +If ``True``, the policy will be saved after the final training iteration. -**save_step_metadata**: Whether to save the RL agents' action, environment state, and other data at every single step. -**save_pcap_logs**: Whether to save pcap files of all network traffic during the simulation. +``save_checkpoints`` +-------------------- -**save_sys_logs**: Whether to save system logs from all nodes during the simulation. +Optional. Default value is ``False``. + +Only used if training with PrimaiteSession. +If ``True``, the policy will be saved periodically during training. + + +``checkpoint_interval`` +----------------------- + +Optional. Default value is ``10``. + +Only used if training with PrimaiteSession and if ``save_checkpoints`` is ``True``. +Defines how often to save the policy during training. + + +``save_logs`` +------------- + +*currently unused*. + +``save_transactions`` +--------------------- + +*currently unused*. + +``save_tensorboard_logs`` +------------------------- + +*currently unused*. + +``save_step_metadata`` +---------------------- + +Optional. Default value is ``False``. + +If ``True``, The RL agent(s) actions, environment states and other data will be saved at every single step. + + +``save_pcap_logs`` +------------------ + +Optional. Default value is ``False``. + +If ``True``, then the pcap files which contain all network traffic during the simulation will be saved. + + +``save_sys_logs`` +----------------- + +Optional. Default value is ``False``. + +If ``True``, then the log files which contain all node actions during the simulation will be saved. diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst index eb13e2be..d8497212 100644 --- a/docs/source/configuration/simulation.rst +++ b/docs/source/configuration/simulation.rst @@ -9,6 +9,17 @@ In this section the network layout is defined. This part of the config follows a At the top level of the network are ``nodes`` and ``links``. +e.g. + +.. code-block:: yaml + + simulation: + network: + nodes: + ... + links: + ... + **nodes:** * ``type``: one of ``router``, ``switch``, ``computer``, or ``server``, this affects what other sub-options should be defined. * ``hostname`` - a non-unique name used for logging and outputs. @@ -19,9 +30,75 @@ At the top level of the network are ``nodes`` and ``links``. * ``applications`` (computer and servers only): Similar to services. A list of application to install on the node. * ``network_interfaces`` (computers and servers only): If the node has multiple networking devices, the second, third, fourth, etc... must be defined here with an ``ip_address`` and ``subnet_mask``. -**links:** - * ``ref``: unique identifier for this link - * ``endpoint_a_ref``: Reference to the node at the first end of the link - * ``endpoint_a_port``: The ethernet port or switch port index of the second node - * ``endpoint_b_ref``: Reference to the node at the second end of the link - * ``endpoint_b_port``: The ethernet port or switch port index on the second node +``nodes`` +--------- + +This is where the list of nodes are defined. Some items will differ according to the node type, however, there will be common items such as a node's reference (which is used by the agent), the node's ``type`` and ``hostname`` + +To see the configuration for these nodes, refer to the following: + +.. toctree:: + :maxdepth: 1 + + simulation/nodes/computer.rst + simulation/nodes/firewall.rst + simulation/nodes/router.rst + simulation/nodes/server.rst + simulation/nodes/switch.rst + +``links`` +--------- + +This is where the links between the nodes are formed. + +e.g. + +In order to recreate the network below, we will need to create 2 links: + +- a link from computer_1 to the switch +- a link from computer_2 to the switch + +.. image:: ../../_static/switched_p2p_network.png + +this results in: + +.. code-block:: yaml + + links: + - ref: computer_1___switch + endpoint_a_ref: computer_1 + endpoint_a_port: 1 # port 1 on computer_1 + endpoint_b_ref: switch + endpoint_b_port: 1 # port 1 on switch + - ref: computer_2___switch + endpoint_a_ref: computer_2 + endpoint_a_port: 1 # port 1 on computer_2 + endpoint_b_ref: switch + endpoint_b_port: 2 # port 2 on switch + +``ref`` +^^^^^^^ + +The human readable name for the link. Not used in code, however is useful for a human to understand what the link is for. + +``endpoint_a_ref`` +^^^^^^^^^^^^^^^^^^ + +The name of the node which must be connected. + +``endpoint_a_port`` +^^^^^^^^^^^^^^^^^^^ + +The port on ``endpoint_a_ref`` which is to be connected to ``endpoint_b_port``. +This accepts an integer value e.g. if port 1 is to be connected, the configuration should be ``endpoint_a_port: 1`` + +``endpoint_b_ref`` +^^^^^^^^^^^^^^^^^^ + +The name of the node which must be connected. + +``endpoint_b_port`` +^^^^^^^^^^^^^^^^^^^ + +The port on ``endpoint_b_ref`` which is to be connected to ``endpoint_a_port``. +This accepts an integer value e.g. if port 1 is to be connected, the configuration should be ``endpoint_b_port: 1`` diff --git a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst new file mode 100644 index 00000000..265c7106 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst @@ -0,0 +1,41 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``ip_address`` +^^^^^^^^^^^^^^ + +The IP address of the |NODE| in the network. + +``subnet_mask`` +^^^^^^^^^^^^^^^ + +Optional. Default value is ``255.255.255.0``. + +The subnet mask for the |NODE| to use. + +``default_gateway`` +^^^^^^^^^^^^^^^^^^^ + +The IP address that the |NODE| will use as the default gateway. Typically, this is the IP address of the closest router that the |NODE| is connected to. + +``dns_server`` +^^^^^^^^^^^^^^ + +Optional. Default value is ``None`` + +The IP address of the node which holds an instance of the DNS server. Some applications may use a domain name e.g. the WebBrowser (TODO: WebBrowser page) + +``applications`` +^^^^^^^^^^^^^^^^ + +A list of applications which are not considered system software that need to be installed on the |NODE|. + +See :ref:`Applications ` + +``services`` +^^^^^^^^^^^^ + +A list of services which are not considered system software that need to be installed on the |NODE|. + +See :ref:`Services ` diff --git a/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst new file mode 100644 index 00000000..83007145 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst @@ -0,0 +1,49 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``routes`` +---------- + +A list of routes which tells the |NODE| where to forward the packet to depending on the target IP address. + +e.g. + +.. code-block:: yaml + + nodes: + - ref: node + ... + routes: + - address: 192.168.0.10 + subnet_mask: 255.255.255.0 + next_hop_ip_address: 192.168.1.1 + metric: 0 + +``address`` +""""""""""" + +The target IP address for the route. If the packet destination IP address matches this, the router will route the packet according to the ``next_hop_ip_address``. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``subnet_mask`` +""""""""""""""" + +Optional. Default value is ``255.255.255.0``. + +The subnet mask setting for the route. + +``next_hop_ip_address`` +""""""""""""""""""""""" + +The IP address of the next hop IP address that the packet will follow if the address matches the packet's destination IP address. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``metric`` +"""""""""" + +Optional. Default value is ``0``. This value accepts floats. + +The cost or distance of a route. The higher the value, the more cost or distance is attributed to the route. diff --git a/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst new file mode 100644 index 00000000..c1523518 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst @@ -0,0 +1,13 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``ref`` +------- + +Human readable name used as reference for the |NODE|. Not used in code. + +``hostname`` +------------ + +The hostname of the |NODE|. This will be used to reference the |NODE|. diff --git a/docs/source/configuration/simulation/nodes/common/node_type_list.rst b/docs/source/configuration/simulation/nodes/common/node_type_list.rst new file mode 100644 index 00000000..ceee8207 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/common/node_type_list.rst @@ -0,0 +1,18 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``type`` +-------- + +The type of node to add. + +Available options are: + +- ``computer`` +- ``firewall`` +- ``router`` +- ``server`` +- ``switch`` + +To create a |NODE|, type must be |NODE_TYPE|. diff --git a/docs/source/configuration/simulation/nodes/computer.rst b/docs/source/configuration/simulation/nodes/computer.rst new file mode 100644 index 00000000..bbdf087d --- /dev/null +++ b/docs/source/configuration/simulation/nodes/computer.rst @@ -0,0 +1,39 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _computer_configuration: + +``computer`` +============ + +A basic representation of a computer within the simulation. + +See :py:mod:`primaite.simulator.network.hardware.nodes.host.computer.Computer` + +example computer +---------------- + +.. code-block:: yaml + + nodes: + - ref: client_1 + hostname: client_1 + type: computer + ip_address: 192.168.0.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.0.1 + dns_server: 192.168.1.10 + applications: + ... + services: + ... + +.. include:: common/common_node_attributes.rst + +.. include:: common/node_type_list.rst + +.. include:: common/common_host_node_attributes.rst + +.. |NODE| replace:: computer +.. |NODE_TYPE| replace:: ``computer`` diff --git a/docs/source/configuration/simulation/nodes/firewall.rst b/docs/source/configuration/simulation/nodes/firewall.rst new file mode 100644 index 00000000..b1e4e5e1 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/firewall.rst @@ -0,0 +1,258 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _firewall_configuration: + +``firewall`` +============ + +A basic representation of a network router within the simulation. + +The firewall is similar to how :ref:`Router ` works, with the difference being how firewall has specific ACL rules for inbound and outbound traffic as well as firewall being limited to 3 ports. + +See :py:mod:`primaite.simulator.network.hardware.nodes.network.firewall.Firewall` + +example firewall +---------------- + +.. code-block:: yaml + + nodes: + - ref: firewall + hostname: firewall + type: firewall + start_up_duration: 0 + shut_down_duration: 0 + ports: + external_port: # port 1 + ip_address: 192.168.20.1 + subnet_mask: 255.255.255.0 + internal_port: # port 2 + ip_address: 192.168.1.2 + subnet_mask: 255.255.255.0 + dmz_port: # port 3 + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 + acl: + internal_inbound_acl: + ... + internal_outbound_acl: + ... + dmz_inbound_acl: + ... + dmz_outbound_acl: + ... + external_inbound_acl: + ... + external_outbound_acl: + ... + routes: + ... + +.. include:: common/common_node_attributes.rst + +.. include:: common/node_type_list.rst + +``ports`` +--------- + +The firewall node only has 3 ports. These specifically are: + +- ``external_port`` (port 1) +- ``internal_port`` (port 2) +- ``dmz_port`` (port 3) (can be optional) + +The ports should be defined with an ip address and subnet mask e.g. + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + ports: + external_port: # port 1 + ip_address: 192.168.20.1 + subnet_mask: 255.255.255.0 + internal_port: # port 2 + ip_address: 192.168.1.2 + subnet_mask: 255.255.255.0 + dmz_port: # port 3 + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 + +``ip_address`` +"""""""""""""" + +The IP address for the given port. This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``subnet_mask`` +""""""""""""""" + +Optional. Default value is ``255.255.255.0``. + +The subnet mask setting for the port. + +``acl`` +------- + +There are 6 ACLs that can be defined for a firewall + +- ``internal_inbound_acl`` for traffic going towards the internal network +- ``internal_outbound_acl`` for traffic coming from the internal network +- ``dmz_inbound_acl`` for traffic going towards the dmz network +- ``dmz_outbound_acl`` for traffic coming from the dmz network +- ``external_inbound_acl`` for traffic coming from the external network +- ``external_outbound_acl`` for traffic going towards the external network + +.. image:: ../../../../_static/firewall_acl.png + +By default, ``external_inbound_acl`` and ``external_outbound_acl`` will permit any traffic through. + +See :py:mod:`primaite.simulator.network.hardware.nodes.network.router.AccessControlList` + +See :ref:`List of Ports ` for a list of ports. + +``internal_inbound_acl`` +"""""""""""""""""""""""" + +ACL rules for packets that have a destination IP address in what is considered the internal network. + +example: + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + acl: + internal_inbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP + +``internal_outbound_acl`` +""""""""""""""""""""""""" + +ACL rules for packets that have a source IP address in what is considered the internal network and is going towards the DMZ network or the external network. + +example: + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + acl: + internal_outbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP + + +``dmz_inbound_acl`` +""""""""""""""""""" + +ACL rules for packets that have a destination IP address in what is considered the DMZ network. + +example: + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + acl: + dmz_inbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP + +``dmz_outbound_acl`` +"""""""""""""""""""" + +ACL rules for packets that have a source IP address in what is considered the DMZ network and is going towards the internal network or the external network. + +example: + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + acl: + dmz_outbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP + + + +``external_inbound_acl`` +"""""""""""""""""""""""" + +Optional. By default, this will allow any traffic through. + +ACL rules for packets that have a destination IP address in what is considered the external network. + +example: + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + acl: + external_inbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP + +``external_outbound_acl`` +""""""""""""""""""""""""" + +Optional. By default, this will allow any traffic through. + +ACL rules for packets that have a source IP address in what is considered the external network and is going towards the DMZ network or the internal network. + +example: + +.. code-block:: yaml + + nodes: + - ref: firewall + ... + acl: + external_outbound_acl: + 22: # position 22 on ACL list + action: PERMIT # allow packets that + src_port: ARP # are emitted from the ARP port + dst_port: ARP # are going towards an ARP port + 23: # position 23 on ACL list + action: PERMIT # allow packets that + protocol: ICMP # are ICMP + +.. include:: common/common_network_node_attributes.rst + +.. |NODE| replace:: firewall +.. |NODE_TYPE| replace:: ``firewall`` diff --git a/docs/source/configuration/simulation/nodes/router.rst b/docs/source/configuration/simulation/nodes/router.rst new file mode 100644 index 00000000..8a8efc06 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/router.rst @@ -0,0 +1,125 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _router_configuration: + +``router`` +========== + +A basic representation of a network router within the simulation. + +See :py:mod:`primaite.simulator.network.hardware.nodes.network.router.Router` + +example router +-------------- + +.. code-block:: yaml + + nodes: + - ref: router_1 + hostname: router_1 + type: router + num_ports: 5 + ports: + ... + acl: + ... + +.. include:: common/common_node_attributes.rst + +.. include:: common/node_type_list.rst + +``num_ports`` +------------- + +Optional. Default value is ``5``. + +The number of ports the router will have. + +``ports`` +--------- + +Sets up the router's ports with an IP address and a subnet mask. + +Example of setting ports for a router with 2 ports: + +.. code-block:: yaml + + nodes: + - ref: router_1 + ... + ports: + 1: + ip_address: 192.168.1.1 + subnet_mask: 255.255.255.0 + 2: + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 + +``ip_address`` +"""""""""""""" + +The IP address for the given port. This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``subnet_mask`` +""""""""""""""" + +Optional. Default value is ``255.255.255.0``. + +The subnet mask setting for the port. + +``acl`` +------- + +Sets up the ACL rules for the router. + +e.g. + +.. code-block:: yaml + + nodes: + - ref: router_1 + ... + acl: + 1: + action: PERMIT + src_port: ARP + dst_port: ARP + 2: + action: PERMIT + protocol: ICMP + +See :py:mod:`primaite.simulator.network.hardware.nodes.network.router.AccessControlList` + +See :ref:`List of Ports ` for a list of ports. + +``action`` +"""""""""" + +Available options are + +- ``PERMIT`` : Allows the specified ``protocol`` or ``src_port`` and ``dst_port`` pairs +- ``DENY`` : Blocks the specified ``protocol`` or ``src_port`` and ``dst_port`` pairs + +``src_port`` +"""""""""""" + +Is used alongside ``dst_port``. Specifies the port where a packet originates. Used by the ACL Rule to determine if a packet with a specific source port is allowed to pass through the network node. + +``dst_port`` +"""""""""""" + +Is used alongside ``src_port``. Specifies the port where a packet is destined to arrive. Used by the ACL Rule to determine if a packet with a specific destination port is allowed to pass through the network node. + +``protocol`` +"""""""""""" + +Specifies which protocols are allowed by the ACL Rule to pass through the network node. + +See :ref:`List of IPProtocols ` for a list of protocols. + +.. include:: common/common_network_node_attributes.rst + +.. |NODE| replace:: router +.. |NODE_TYPE| replace:: ``router`` diff --git a/docs/source/configuration/simulation/nodes/server.rst b/docs/source/configuration/simulation/nodes/server.rst new file mode 100644 index 00000000..7f51eaf2 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/server.rst @@ -0,0 +1,39 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _server_configuration: + +``server`` +========== + +A basic representation of a server within the simulation. + +See :py:mod:`primaite.simulator.network.hardware.nodes.host.server.Server` + +example server +-------------- + +.. code-block:: yaml + + nodes: + - ref: server_1 + hostname: server_1 + type: server + ip_address: 192.168.10.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.10.1 + dns_server: 192.168.1.10 + applications: + ... + services: + ... + +.. include:: common/common_node_attributes.rst + +.. include:: common/node_type_list.rst + +.. include:: common/common_host_node_attributes.rst + +.. |NODE| replace:: server +.. |NODE_TYPE| replace:: ``server`` diff --git a/docs/source/configuration/simulation/nodes/switch.rst b/docs/source/configuration/simulation/nodes/switch.rst new file mode 100644 index 00000000..4d57f76e --- /dev/null +++ b/docs/source/configuration/simulation/nodes/switch.rst @@ -0,0 +1,37 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _switch_configuration: + +``switch`` +========== + +A basic representation of a network switch within the simulation. + +See :py:mod:`primaite.simulator.network.hardware.nodes.network.switch.Switch` + +example switch +-------------- + +.. code-block:: yaml + + nodes: + - ref: switch_1 + hostname: switch_1 + type: switch + num_ports: 8 + +.. include:: common/common_node_attributes.rst + +.. include:: common/node_type_list.rst + +``num_ports`` +------------- + +Optional. Default value is ``8``. + +The number of ports the switch will have. + +.. |NODE| replace:: switch +.. |NODE_TYPE| replace:: ``switch`` diff --git a/docs/source/configuration/simulation/software/applications.rst b/docs/source/configuration/simulation/software/applications.rst new file mode 100644 index 00000000..75e0c64c --- /dev/null +++ b/docs/source/configuration/simulation/software/applications.rst @@ -0,0 +1,10 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _applications_config: + +``applications`` +================ + +apps diff --git a/docs/source/configuration/simulation/software/services.rst b/docs/source/configuration/simulation/software/services.rst new file mode 100644 index 00000000..5f1783af --- /dev/null +++ b/docs/source/configuration/simulation/software/services.rst @@ -0,0 +1,10 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _services_config: + +``services`` +============ + +services diff --git a/docs/source/configuration/training_config.rst b/docs/source/configuration/training_config.rst index cde6cf52..3e63f69b 100644 --- a/docs/source/configuration/training_config.rst +++ b/docs/source/configuration/training_config.rst @@ -4,6 +4,22 @@ ``training_config`` =================== +Configuration items relevant to how the Reinforcement Learning agent(s) will be trained. + +``training_config`` hierarchy +----------------------------- + +.. code-block:: yaml + + training_config: + rl_framework: SB3 # or RLLIB_single_agent or RLLIB_multi_agent + rl_algorithm: PPO # or A2C + n_learn_episodes: 5 + max_steps_per_episode: 200 + n_eval_episodes: 1 + deterministic_eval: True + seed: 123 + ``rl_framework`` ---------------- @@ -23,3 +39,37 @@ Options available are: - ``PPO`` (Proximal Policy Optimisation) - ``A2C`` (Advantage Actor Critic) + +``n_learn_episodes`` +-------------------- +The number of episodes to train the agent(s). +This should be an integer value above ``0`` + +``max_steps_per_episode`` +------------------------- +The number of steps each episode will last for. +This should be an integer value above ``0``. + + +``n_eval_episodes`` +------------------- +Optional. Default value is ``0``. + +The number of evaluation episodes to run the trained agent for. +This should be an integer value above ``0``. + +``deterministic_eval`` +---------------------- +Optional. By default this value is ``False``. + +If this is set to ``True``, the agents will act deterministically instead of stochastically. + + + +``seed`` +-------- +Optional. + +The seed is used (alongside ``deterministic_eval``) to reproduce a previous instance of training and evaluation of an RL agent. +The seed should be an integer value. +Useful for debugging. diff --git a/src/primaite/config/_package_data/example_config.yaml b/src/primaite/config/_package_data/example_config.yaml index 6eab6c54..ae248f23 100644 --- a/src/primaite/config/_package_data/example_config.yaml +++ b/src/primaite/config/_package_data/example_config.yaml @@ -583,8 +583,8 @@ simulation: nodes: - ref: router_1 - type: router hostname: router_1 + type: router num_ports: 5 ports: 1: @@ -619,18 +619,18 @@ simulation: protocol: ICMP - ref: switch_1 - type: switch hostname: switch_1 + type: switch num_ports: 8 - ref: switch_2 - type: switch hostname: switch_2 + type: switch num_ports: 8 - ref: domain_controller - type: server hostname: domain_controller + type: server ip_address: 192.168.1.10 subnet_mask: 255.255.255.0 default_gateway: 192.168.1.1 @@ -642,8 +642,8 @@ simulation: arcd.com: 192.168.1.12 # web server - ref: web_server - type: server hostname: web_server + type: server ip_address: 192.168.1.12 subnet_mask: 255.255.255.0 default_gateway: 192.168.1.1 @@ -658,8 +658,8 @@ simulation: - ref: database_server - type: server hostname: database_server + type: server ip_address: 192.168.1.14 subnet_mask: 255.255.255.0 default_gateway: 192.168.1.1 @@ -673,8 +673,8 @@ simulation: type: FTPClient - ref: backup_server - type: server hostname: backup_server + type: server ip_address: 192.168.1.16 subnet_mask: 255.255.255.0 default_gateway: 192.168.1.1 @@ -684,8 +684,8 @@ simulation: type: FTPServer - ref: security_suite - type: server hostname: security_suite + type: server ip_address: 192.168.1.110 subnet_mask: 255.255.255.0 default_gateway: 192.168.1.1 @@ -696,8 +696,8 @@ simulation: subnet_mask: 255.255.255.0 - ref: client_1 - type: computer hostname: client_1 + type: computer ip_address: 192.168.10.21 subnet_mask: 255.255.255.0 default_gateway: 192.168.10.1 @@ -719,8 +719,8 @@ simulation: type: DNSClient - ref: client_2 - type: computer hostname: client_2 + type: computer ip_address: 192.168.10.22 subnet_mask: 255.255.255.0 default_gateway: 192.168.10.1 diff --git a/src/primaite/game/agent/actions.py b/src/primaite/game/agent/actions.py index 1793d420..b85cf86c 100644 --- a/src/primaite/game/agent/actions.py +++ b/src/primaite/game/agent/actions.py @@ -572,7 +572,7 @@ class NetworkNICDisableAction(NetworkNICAbstractAction): class ActionManager: """Class which manages the action space for an agent.""" - _act_class_identifiers: Dict[str, type] = { + act_class_identifiers: Dict[str, type] = { "DONOTHING": DoNothingAction, "NODE_SERVICE_SCAN": NodeServiceScanAction, "NODE_SERVICE_STOP": NodeServiceStopAction, @@ -753,7 +753,7 @@ class ActionManager: # and `options` is an optional dict of options to pass to the init method of the action class act_type = act_spec.get("type") act_options = act_spec.get("options", {}) - self.actions[act_type] = self._act_class_identifiers[act_type](self, **global_action_args, **act_options) + self.actions[act_type] = self.act_class_identifiers[act_type](self, **global_action_args, **act_options) self.action_map: Dict[int, Tuple[str, Dict]] = {} """ diff --git a/src/primaite/game/agent/rewards.py b/src/primaite/game/agent/rewards.py index b5d5f998..27c39b65 100644 --- a/src/primaite/game/agent/rewards.py +++ b/src/primaite/game/agent/rewards.py @@ -245,12 +245,13 @@ class WebpageUnavailablePenalty(AbstractReward): class RewardFunction: """Manages the reward function for the agent.""" - __rew_class_identifiers: Dict[str, Type[AbstractReward]] = { + rew_class_identifiers: Dict[str, Type[AbstractReward]] = { "DUMMY": DummyReward, "DATABASE_FILE_INTEGRITY": DatabaseFileIntegrity, "WEB_SERVER_404_PENALTY": WebServer404Penalty, "WEBPAGE_UNAVAILABLE_PENALTY": WebpageUnavailablePenalty, } + """List of reward class identifiers.""" def __init__(self): """Initialise the reward function object.""" @@ -297,7 +298,7 @@ class RewardFunction: for rew_component_cfg in config["reward_components"]: rew_type = rew_component_cfg["type"] weight = rew_component_cfg.get("weight", 1.0) - rew_class = cls.__rew_class_identifiers[rew_type] + rew_class = cls.rew_class_identifiers[rew_type] rew_instance = rew_class.from_config(config=rew_component_cfg.get("options", {})) new.register_component(component=rew_instance, weight=weight) return new diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index b860fb2a..909b27a4 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -231,24 +231,24 @@ class PrimaiteGame: new_node = Computer( hostname=node_cfg["hostname"], ip_address=node_cfg["ip_address"], - subnet_mask=node_cfg["subnet_mask"], + subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")), default_gateway=node_cfg["default_gateway"], - dns_server=node_cfg["dns_server"], + dns_server=node_cfg.get("dns_server", None), operating_state=NodeOperatingState.ON, ) elif n_type == "server": new_node = Server( hostname=node_cfg["hostname"], ip_address=node_cfg["ip_address"], - subnet_mask=node_cfg["subnet_mask"], + subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")), default_gateway=node_cfg["default_gateway"], - dns_server=node_cfg.get("dns_server"), + dns_server=node_cfg.get("dns_server", None), operating_state=NodeOperatingState.ON, ) elif n_type == "switch": new_node = Switch( hostname=node_cfg["hostname"], - num_ports=node_cfg.get("num_ports"), + num_ports=int(node_cfg.get("num_ports", "8")), operating_state=NodeOperatingState.ON, ) elif n_type == "router": diff --git a/src/primaite/simulator/network/hardware/nodes/network/firewall.py b/src/primaite/simulator/network/hardware/nodes/network/firewall.py index f48d0561..903ce3f3 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/firewall.py +++ b/src/primaite/simulator/network/hardware/nodes/network/firewall.py @@ -506,22 +506,24 @@ class Firewall(Router): # configure internal port new.configure_internal_port( ip_address=IPV4Address(internal_port.get("ip_address")), - subnet_mask=IPV4Address(internal_port.get("subnet_mask")), + subnet_mask=IPV4Address(internal_port.get("subnet_mask", "255.255.255.0")), ) # configure external port new.configure_external_port( ip_address=IPV4Address(external_port.get("ip_address")), - subnet_mask=IPV4Address(external_port.get("subnet_mask")), + subnet_mask=IPV4Address(external_port.get("subnet_mask", "255.255.255.0")), ) # configure dmz port new.configure_dmz_port( - ip_address=IPV4Address(dmz_port.get("ip_address")), subnet_mask=IPV4Address(dmz_port.get("subnet_mask")) + ip_address=IPV4Address(dmz_port.get("ip_address")), + subnet_mask=IPV4Address(dmz_port.get("subnet_mask", "255.255.255.0")), ) if "acl" in cfg: # acl rules for internal_inbound_acl if cfg["acl"]["internal_inbound_acl"]: + new.internal_inbound_acl.max_acl_rules new.internal_inbound_acl._default_config = cfg["acl"]["internal_inbound_acl"] new.internal_inbound_acl._reset_rules_to_default() @@ -553,8 +555,8 @@ class Firewall(Router): for route in cfg.get("routes"): new.route_table.add_route( address=IPv4Address(route.get("address")), - subnet_mask=IPv4Address(route.get("subnet_mask")), + subnet_mask=IPv4Address(route.get("subnet_mask", "255.255.255.0")), next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")), - metric=float(route.get("metric")), + metric=float(route.get("metric", 0)), ) return new diff --git a/src/primaite/simulator/network/hardware/nodes/network/router.py b/src/primaite/simulator/network/hardware/nodes/network/router.py index d52028a8..b3d7f7bf 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/router.py +++ b/src/primaite/simulator/network/hardware/nodes/network/router.py @@ -1482,7 +1482,7 @@ class Router(NetworkNode): """ new = Router( hostname=cfg["hostname"], - num_ports=cfg.get("num_ports"), + num_ports=int(cfg.get("num_ports", "5")), operating_state=NodeOperatingState.ON, ) if "ports" in cfg: @@ -1490,7 +1490,7 @@ class Router(NetworkNode): new.configure_port( port=port_num, ip_address=port_cfg["ip_address"], - subnet_mask=port_cfg["subnet_mask"], + subnet_mask=IPv4Address(port_cfg.get("subnet_mask", "255.255.255.0")), ) if "acl" in cfg: new.acl._default_config = cfg["acl"] # save the config to allow resetting @@ -1499,8 +1499,8 @@ class Router(NetworkNode): for route in cfg.get("routes"): new.route_table.add_route( address=IPv4Address(route.get("address")), - subnet_mask=IPv4Address(route.get("subnet_mask")), + subnet_mask=IPv4Address(route.get("subnet_mask", "255.255.255.0")), next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")), - metric=float(route.get("metric")), + metric=float(route.get("metric", 0)), ) return new diff --git a/src/primaite/simulator/network/transmission/network_layer.py b/src/primaite/simulator/network/transmission/network_layer.py index bdf4babc..dc848ade 100644 --- a/src/primaite/simulator/network/transmission/network_layer.py +++ b/src/primaite/simulator/network/transmission/network_layer.py @@ -9,11 +9,18 @@ _LOGGER = getLogger(__name__) class IPProtocol(Enum): - """Enum representing transport layer protocols in IP header.""" + """ + Enum representing transport layer protocols in IP header. + + .. _List of IPProtocols: + """ TCP = "tcp" + """Transmission Control Protocol.""" UDP = "udp" + """User Datagram Protocol.""" ICMP = "icmp" + """Internet Control Message Protocol.""" class Precedence(Enum): diff --git a/src/primaite/simulator/network/transmission/transport_layer.py b/src/primaite/simulator/network/transmission/transport_layer.py index 7c7509ab..c73e451a 100644 --- a/src/primaite/simulator/network/transmission/transport_layer.py +++ b/src/primaite/simulator/network/transmission/transport_layer.py @@ -5,7 +5,11 @@ from pydantic import BaseModel class Port(Enum): - """Enumeration of common known TCP/UDP ports used by protocols for operation of network applications.""" + """ + Enumeration of common known TCP/UDP ports used by protocols for operation of network applications. + + .. _List of Ports: + """ NONE = 0 "Place holder for a non-port." diff --git a/tests/assets/configs/dmz_network.yaml b/tests/assets/configs/dmz_network.yaml index 971ed8cd..880735d9 100644 --- a/tests/assets/configs/dmz_network.yaml +++ b/tests/assets/configs/dmz_network.yaml @@ -20,7 +20,7 @@ # . ---------------- -------------- -------------- . # . | dmz_server |------| switch_2 |------| firewall | . # . ---------------- -------------- -------------- . -# . (Computer) | . +# . (Server) | . # ........................................................|................... # | # External Network | From 98fb28cbbc97cb164378507dd2bac120ea67f391 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Wed, 21 Feb 2024 18:19:16 +0000 Subject: [PATCH 07/18] #2257: setting up application and service docs --- docs/source/configuration/simulation.rst | 10 ------ .../common/common_host_node_attributes.rst | 22 ++++-------- .../simulation/software/applications.rst | 29 ++++++++++++--- .../applications/data_manipulation_bot.rst | 8 +++++ .../software/applications/database_client.rst | 8 +++++ .../software/applications/dos_bot.rst | 8 +++++ .../software/applications/web_browser.rst | 8 +++++ .../software/common/system_software.rst | 12 +++++++ .../simulation/software/services.rst | 35 ++++++++++++++++--- .../software/services/database_service.rst | 8 +++++ .../software/services/dns_client.rst | 8 +++++ .../software/services/dns_server.rst | 8 +++++ .../software/services/ftp_client.rst | 8 +++++ .../software/services/ftp_server.rst | 8 +++++ .../software/services/ntp_client.rst | 8 +++++ .../software/services/ntp_server.rst | 8 +++++ .../software/services/web_server.rst | 8 +++++ src/primaite/game/game.py | 2 ++ .../network/hardware/nodes/host/host_node.py | 30 +++++++--------- 19 files changed, 185 insertions(+), 51 deletions(-) create mode 100644 docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst create mode 100644 docs/source/configuration/simulation/software/applications/database_client.rst create mode 100644 docs/source/configuration/simulation/software/applications/dos_bot.rst create mode 100644 docs/source/configuration/simulation/software/applications/web_browser.rst create mode 100644 docs/source/configuration/simulation/software/common/system_software.rst create mode 100644 docs/source/configuration/simulation/software/services/database_service.rst create mode 100644 docs/source/configuration/simulation/software/services/dns_client.rst create mode 100644 docs/source/configuration/simulation/software/services/dns_server.rst create mode 100644 docs/source/configuration/simulation/software/services/ftp_client.rst create mode 100644 docs/source/configuration/simulation/software/services/ftp_server.rst create mode 100644 docs/source/configuration/simulation/software/services/ntp_client.rst create mode 100644 docs/source/configuration/simulation/software/services/ntp_server.rst create mode 100644 docs/source/configuration/simulation/software/services/web_server.rst diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst index d8497212..7bb079e9 100644 --- a/docs/source/configuration/simulation.rst +++ b/docs/source/configuration/simulation.rst @@ -20,16 +20,6 @@ e.g. links: ... -**nodes:** - * ``type``: one of ``router``, ``switch``, ``computer``, or ``server``, this affects what other sub-options should be defined. - * ``hostname`` - a non-unique name used for logging and outputs. - * ``num_ports`` (optional, routers and switches only): number of network interfaces present on the device. - * ``ports`` (optional, routers and switches only): configuration for each network interface, including IP address and subnet mask. - * ``acl`` (Router only): Define the ACL rules at each index of the ACL on the router. the possible options are: ``action`` (PERMIT or DENY), ``src_port``, ``dst_port``, ``protocol``, ``src_ip``, ``dst_ip``. Any options left blank default to none which usually means that it will apply across all options. For example leaving ``src_ip`` blank will apply the rule to all IP addresses. - * ``services`` (computers and servers only): a list of services to install on the node. They must define a ``ref``, ``type``, and ``options`` that depend on which ``type`` was selected. - * ``applications`` (computer and servers only): Similar to services. A list of application to install on the node. - * ``network_interfaces`` (computers and servers only): If the node has multiple networking devices, the second, third, fourth, etc... must be defined here with an ``ip_address`` and ``subnet_mask``. - ``nodes`` --------- diff --git a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst index 265c7106..a95f98d4 100644 --- a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst +++ b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst @@ -3,39 +3,29 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK ``ip_address`` -^^^^^^^^^^^^^^ +-------------- The IP address of the |NODE| in the network. ``subnet_mask`` -^^^^^^^^^^^^^^^ +--------------- Optional. Default value is ``255.255.255.0``. The subnet mask for the |NODE| to use. ``default_gateway`` -^^^^^^^^^^^^^^^^^^^ +------------------- The IP address that the |NODE| will use as the default gateway. Typically, this is the IP address of the closest router that the |NODE| is connected to. ``dns_server`` -^^^^^^^^^^^^^^ +-------------- Optional. Default value is ``None`` The IP address of the node which holds an instance of the DNS server. Some applications may use a domain name e.g. the WebBrowser (TODO: WebBrowser page) -``applications`` -^^^^^^^^^^^^^^^^ +.. include:: ../software/applications.rst -A list of applications which are not considered system software that need to be installed on the |NODE|. - -See :ref:`Applications ` - -``services`` -^^^^^^^^^^^^ - -A list of services which are not considered system software that need to be installed on the |NODE|. - -See :ref:`Services ` +.. include:: ../software/services.rst diff --git a/docs/source/configuration/simulation/software/applications.rst b/docs/source/configuration/simulation/software/applications.rst index 75e0c64c..7acde817 100644 --- a/docs/source/configuration/simulation/software/applications.rst +++ b/docs/source/configuration/simulation/software/applications.rst @@ -2,9 +2,30 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -.. _applications_config: - ``applications`` -================ +---------------- -apps +List of available applications that can be installed on a |NODE|: + +.. toctree:: + :maxdepth: 1 + + ../software/applications/data_manipulation_bot.rst + ../software/applications/database_client.rst + ../software/applications/dos_bot.rst + ../software/applications/web_browser.rst + +More info :py:mod:`primaite.game.game.APPLICATION_TYPES_MAPPING` + +.. include:: ../software/common/system_software.rst + + +.. toctree:: + :maxdepth: 1 + + ../software/applications/web_browser.rst + +More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` + +.. |SOFTWARE_TYPE| replace:: application +.. |SOFTWARE_TYPES| replace:: applications diff --git a/docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst b/docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst new file mode 100644 index 00000000..6b650cf7 --- /dev/null +++ b/docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``DataManipulationBot`` +----------------------- + +test diff --git a/docs/source/configuration/simulation/software/applications/database_client.rst b/docs/source/configuration/simulation/software/applications/database_client.rst new file mode 100644 index 00000000..81e827bc --- /dev/null +++ b/docs/source/configuration/simulation/software/applications/database_client.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``DatabaseClient`` +------------------ + +test diff --git a/docs/source/configuration/simulation/software/applications/dos_bot.rst b/docs/source/configuration/simulation/software/applications/dos_bot.rst new file mode 100644 index 00000000..98939e5b --- /dev/null +++ b/docs/source/configuration/simulation/software/applications/dos_bot.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``DoSBot`` +---------- + +test diff --git a/docs/source/configuration/simulation/software/applications/web_browser.rst b/docs/source/configuration/simulation/software/applications/web_browser.rst new file mode 100644 index 00000000..4af0d7b7 --- /dev/null +++ b/docs/source/configuration/simulation/software/applications/web_browser.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``WebBrowser`` +-------------- + +test diff --git a/docs/source/configuration/simulation/software/common/system_software.rst b/docs/source/configuration/simulation/software/common/system_software.rst new file mode 100644 index 00000000..64248272 --- /dev/null +++ b/docs/source/configuration/simulation/software/common/system_software.rst @@ -0,0 +1,12 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``system software`` +""""""""""""""""""" + +Some |SOFTWARE_TYPES| are pre installed on nodes - this is similar to how some |SOFTWARE_TYPES| are included with the Operating System. + +The |SOFTWARE_TYPE| may not be configured as needed, in which case, follow the steps above to configure them. + +The list of |SOFTWARE_TYPES| that are considered system software are: diff --git a/docs/source/configuration/simulation/software/services.rst b/docs/source/configuration/simulation/software/services.rst index 5f1783af..383f9de4 100644 --- a/docs/source/configuration/simulation/software/services.rst +++ b/docs/source/configuration/simulation/software/services.rst @@ -2,9 +2,36 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -.. _services_config: - ``services`` -============ +------------ -services +List of available services that can be installed on a |NODE|: + +.. toctree:: + :maxdepth: 1 + + ../software/services/database_service.rst + ../software/services/dns_client.rst + ../software/services/dns_server.rst + ../software/services/ftp_client.rst + ../software/services/ftp_server.rst + ../software/services/ntp_client.rst + ../software/services/ntp_server.rst + ../software/services/web_server.rst + +More info :py:mod:`primaite.game.game.SERVICE_TYPES_MAPPING` + +.. include:: ../software/common/system_software.rst + + +.. toctree:: + :maxdepth: 1 + + ../software/services/dns_client.rst + ../software/services/ftp_client.rst + ../software/services/ntp_client.rst + +More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` + +.. |SOFTWARE_TYPE| replace:: service +.. |SOFTWARE_TYPES| replace:: services diff --git a/docs/source/configuration/simulation/software/services/database_service.rst b/docs/source/configuration/simulation/software/services/database_service.rst new file mode 100644 index 00000000..f03fde70 --- /dev/null +++ b/docs/source/configuration/simulation/software/services/database_service.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``DatabaseService`` +------------------- + +test diff --git a/docs/source/configuration/simulation/software/services/dns_client.rst b/docs/source/configuration/simulation/software/services/dns_client.rst new file mode 100644 index 00000000..d9b8008d --- /dev/null +++ b/docs/source/configuration/simulation/software/services/dns_client.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``DNSClient`` +------------- + +test diff --git a/docs/source/configuration/simulation/software/services/dns_server.rst b/docs/source/configuration/simulation/software/services/dns_server.rst new file mode 100644 index 00000000..a342967f --- /dev/null +++ b/docs/source/configuration/simulation/software/services/dns_server.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``DNSServer`` +------------- + +test diff --git a/docs/source/configuration/simulation/software/services/ftp_client.rst b/docs/source/configuration/simulation/software/services/ftp_client.rst new file mode 100644 index 00000000..d51a3dc1 --- /dev/null +++ b/docs/source/configuration/simulation/software/services/ftp_client.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``FTPClient`` +------------- + +test diff --git a/docs/source/configuration/simulation/software/services/ftp_server.rst b/docs/source/configuration/simulation/software/services/ftp_server.rst new file mode 100644 index 00000000..c7f92340 --- /dev/null +++ b/docs/source/configuration/simulation/software/services/ftp_server.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``FTPServer`` +------------- + +test diff --git a/docs/source/configuration/simulation/software/services/ntp_client.rst b/docs/source/configuration/simulation/software/services/ntp_client.rst new file mode 100644 index 00000000..51b2e061 --- /dev/null +++ b/docs/source/configuration/simulation/software/services/ntp_client.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``NTPClient`` +------------- + +test diff --git a/docs/source/configuration/simulation/software/services/ntp_server.rst b/docs/source/configuration/simulation/software/services/ntp_server.rst new file mode 100644 index 00000000..2efbdf1a --- /dev/null +++ b/docs/source/configuration/simulation/software/services/ntp_server.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``NTPServer`` +------------- + +test diff --git a/docs/source/configuration/simulation/software/services/web_server.rst b/docs/source/configuration/simulation/software/services/web_server.rst new file mode 100644 index 00000000..4fab660d --- /dev/null +++ b/docs/source/configuration/simulation/software/services/web_server.rst @@ -0,0 +1,8 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``WebServer`` +------------- + +test diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index 909b27a4..7a17a03d 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -41,6 +41,7 @@ APPLICATION_TYPES_MAPPING = { "DataManipulationBot": DataManipulationBot, "DoSBot": DoSBot, } +"""List of available applications that can be installed on nodes in the PrimAITE Simulation.""" SERVICE_TYPES_MAPPING = { "DNSClient": DNSClient, @@ -52,6 +53,7 @@ SERVICE_TYPES_MAPPING = { "NTPClient": NTPClient, "NTPServer": NTPServer, } +"""List of available services that can be installed on nodes in the PrimAITE Simulation.""" class PrimaiteGameOptions(BaseModel): diff --git a/src/primaite/simulator/network/hardware/nodes/host/host_node.py b/src/primaite/simulator/network/hardware/nodes/host/host_node.py index 3f34f736..6db1e036 100644 --- a/src/primaite/simulator/network/hardware/nodes/host/host_node.py +++ b/src/primaite/simulator/network/hardware/nodes/host/host_node.py @@ -261,6 +261,17 @@ class NIC(IPWiredNetworkInterface): return f"Port {self.port_num}: {self.mac_address}/{self.ip_address}" +SYSTEM_SOFTWARE = { + "HostARP": HostARP, + "ICMP": ICMP, + "DNSClient": DNSClient, + "FTPClient": FTPClient, + "NTPClient": NTPClient, + "WebBrowser": WebBrowser, +} +"""List of system software that is automatically installed on nodes.""" + + class HostNode(Node): """ Represents a host node in the network. @@ -321,23 +332,8 @@ class HostNode(Node): This method equips the host with essential network services and applications, preparing it for various network-related tasks and operations. """ - # ARP Service - self.software_manager.install(HostARP) - - # ICMP Service - self.software_manager.install(ICMP) - - # DNS Client - self.software_manager.install(DNSClient) - - # FTP Client - self.software_manager.install(FTPClient) - - # NTP Client - self.software_manager.install(NTPClient) - - # Web Browser - self.software_manager.install(WebBrowser) + for _, software_class in SYSTEM_SOFTWARE.items(): + self.software_manager.install(software_class) super()._install_system_software() From 5836ea68e339d59ffc9c6f56f472bb8dea2477cf Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Fri, 23 Feb 2024 08:55:32 +0000 Subject: [PATCH 08/18] #2257: rearrange software pages + creating a list of applications and services which is hopefully a single point that should be referred to --- docs/conf.py | 5 ++ docs/source/config.rst | 4 +- docs/source/configuration/simulation.rst | 2 + .../simulation/nodes/firewall.rst | 4 ++ .../simulation/software/applications.rst | 34 ++++----- .../applications/data_manipulation_bot.rst | 8 --- .../software/applications/database_client.rst | 8 --- .../software/applications/web_browser.rst | 8 --- .../software/common/system_software.rst | 12 ---- .../simulation/software/services.rst | 40 ++++------- .../software/services/database_service.rst | 8 --- .../software/services/dns_client.rst | 8 --- .../software/services/dns_server.rst | 8 --- .../software/services/ftp_client.rst | 8 --- .../software/services/ftp_server.rst | 8 --- .../software/services/ntp_client.rst | 8 --- .../software/services/ntp_server.rst | 8 --- .../software/services/web_server.rst | 8 --- docs/source/game_layer.rst | 2 +- .../network/network_interfaces.rst | 2 + .../network/nodes/firewall.rst | 2 +- .../network/nodes/network_node.rst | 2 +- .../data_manipulation_bot.rst | 1 + .../system/applications/database_client.rst | 38 ++++++++++ .../system}/applications/dos_bot.rst | 4 +- .../web_browser.rst} | 30 +------- .../system/database_client_server.rst | 71 ------------------- .../system/list_of_applications.rst | 11 +++ .../system/list_of_services.rst | 15 ++++ .../system/list_of_system_applications.rst | 19 +++++ .../system/list_of_system_services.rst | 21 ++++++ .../system/services/database_service.rst | 33 +++++++++ .../dns_client.rst} | 30 +------- .../system/services/dns_server.rst | 26 +++++++ .../ftp_client.rst} | 30 +------- .../system/services/ftp_server.rst | 27 +++++++ .../system/services/ntp_client.rst | 26 +++++++ .../ntp_server.rst} | 30 +------- .../system/services/web_server.rst | 27 +++++++ .../system/session_and_software_manager.rst | 2 + .../simulation_components/system/software.rst | 31 +++++--- docs/source/simulation_structure.rst | 11 +-- 42 files changed, 329 insertions(+), 351 deletions(-) delete mode 100644 docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst delete mode 100644 docs/source/configuration/simulation/software/applications/database_client.rst delete mode 100644 docs/source/configuration/simulation/software/applications/web_browser.rst delete mode 100644 docs/source/configuration/simulation/software/common/system_software.rst delete mode 100644 docs/source/configuration/simulation/software/services/database_service.rst delete mode 100644 docs/source/configuration/simulation/software/services/dns_client.rst delete mode 100644 docs/source/configuration/simulation/software/services/dns_server.rst delete mode 100644 docs/source/configuration/simulation/software/services/ftp_client.rst delete mode 100644 docs/source/configuration/simulation/software/services/ftp_server.rst delete mode 100644 docs/source/configuration/simulation/software/services/ntp_client.rst delete mode 100644 docs/source/configuration/simulation/software/services/ntp_server.rst delete mode 100644 docs/source/configuration/simulation/software/services/web_server.rst rename docs/source/simulation_components/system/{ => applications}/data_manipulation_bot.rst (99%) create mode 100644 docs/source/simulation_components/system/applications/database_client.rst rename docs/source/{configuration/simulation/software => simulation_components/system}/applications/dos_bot.rst (82%) rename docs/source/simulation_components/system/{web_browser_and_web_server_service.rst => applications/web_browser.rst} (72%) delete mode 100644 docs/source/simulation_components/system/database_client_server.rst create mode 100644 docs/source/simulation_components/system/list_of_applications.rst create mode 100644 docs/source/simulation_components/system/list_of_services.rst create mode 100644 docs/source/simulation_components/system/list_of_system_applications.rst create mode 100644 docs/source/simulation_components/system/list_of_system_services.rst create mode 100644 docs/source/simulation_components/system/services/database_service.rst rename docs/source/simulation_components/system/{dns_client_server.rst => services/dns_client.rst} (52%) create mode 100644 docs/source/simulation_components/system/services/dns_server.rst rename docs/source/simulation_components/system/{ftp_client_server.rst => services/ftp_client.rst} (78%) create mode 100644 docs/source/simulation_components/system/services/ftp_server.rst create mode 100644 docs/source/simulation_components/system/services/ntp_client.rst rename docs/source/simulation_components/system/{ntp_client_server.rst => services/ntp_server.rst} (56%) create mode 100644 docs/source/simulation_components/system/services/web_server.rst diff --git a/docs/conf.py b/docs/conf.py index 6cdc0ac4..d246afe5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,6 +27,11 @@ with open("../src/primaite/VERSION", "r") as file: # The full version, including alpha/beta/rc tags release = version +# set global variables +rst_prolog = f""" +.. |VERSION| replace:: {release} +""" + html_title = f"{project} v{release} docs" # -- General configuration --------------------------------------------------- diff --git a/docs/source/config.rst b/docs/source/config.rst index b7bce731..89181a24 100644 --- a/docs/source/config.rst +++ b/docs/source/config.rst @@ -2,8 +2,8 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -Primaite v3 config -****************** +PrimAITE |VERSION| Configuration +******************************** PrimAITE uses a single configuration file to define everything needed to train and evaluate an RL policy in a custom cybersecurity scenario. This includes the configuration of the network, the scripted or trained agents that interact with the network, as well as settings that define how to perform training in Stable Baselines 3 or Ray RLLib. The entire config is used by the ``PrimaiteSession`` object for users who wish to let PrimAITE handle the agent definition and training. If you wish to define custom agents and control the training loop yourself, you can use the config with the ``PrimaiteGame``, and ``PrimaiteGymEnv`` objects instead. That way, only the network configuration and agent setup parts of the config are used, and the training section is ignored. diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst index 7bb079e9..f24cc41d 100644 --- a/docs/source/configuration/simulation.rst +++ b/docs/source/configuration/simulation.rst @@ -49,6 +49,8 @@ In order to recreate the network below, we will need to create 2 links: - a link from computer_2 to the switch .. image:: ../../_static/switched_p2p_network.png + :width: 500 + :align: center this results in: diff --git a/docs/source/configuration/simulation/nodes/firewall.rst b/docs/source/configuration/simulation/nodes/firewall.rst index b1e4e5e1..c8a21a02 100644 --- a/docs/source/configuration/simulation/nodes/firewall.rst +++ b/docs/source/configuration/simulation/nodes/firewall.rst @@ -106,9 +106,13 @@ There are 6 ACLs that can be defined for a firewall - ``external_outbound_acl`` for traffic going towards the external network .. image:: ../../../../_static/firewall_acl.png + :width: 500 + :align: center By default, ``external_inbound_acl`` and ``external_outbound_acl`` will permit any traffic through. +``internal_inbound_acl``, ``internal_outbound_acl``, ``dmz_inbound_acl`` and ``dmz_outbound_acl`` will deny any traffic by default, so must be configured to allow defined ``src_port`` and ``dst_port`` or ``protocol``. + See :py:mod:`primaite.simulator.network.hardware.nodes.network.router.AccessControlList` See :ref:`List of Ports ` for a list of ports. diff --git a/docs/source/configuration/simulation/software/applications.rst b/docs/source/configuration/simulation/software/applications.rst index 7acde817..90ae3ec1 100644 --- a/docs/source/configuration/simulation/software/applications.rst +++ b/docs/source/configuration/simulation/software/applications.rst @@ -5,27 +5,21 @@ ``applications`` ---------------- -List of available applications that can be installed on a |NODE|: +List of available applications that can be installed on a |NODE| can be found in :ref:`List of Applications ` -.. toctree:: - :maxdepth: 1 +application in configuration +"""""""""""""""""""""""""""" - ../software/applications/data_manipulation_bot.rst - ../software/applications/database_client.rst - ../software/applications/dos_bot.rst - ../software/applications/web_browser.rst +Applications takes a list of applications as shown in the example below. -More info :py:mod:`primaite.game.game.APPLICATION_TYPES_MAPPING` +.. code-block:: yaml -.. include:: ../software/common/system_software.rst - - -.. toctree:: - :maxdepth: 1 - - ../software/applications/web_browser.rst - -More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` - -.. |SOFTWARE_TYPE| replace:: application -.. |SOFTWARE_TYPES| replace:: applications + - ref: client_1 + hostname: client_1 + type: computer + ... + applications: + - ref: example_application + type: example_application_type + options: + # this section is different for each application diff --git a/docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst b/docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst deleted file mode 100644 index 6b650cf7..00000000 --- a/docs/source/configuration/simulation/software/applications/data_manipulation_bot.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``DataManipulationBot`` ------------------------ - -test diff --git a/docs/source/configuration/simulation/software/applications/database_client.rst b/docs/source/configuration/simulation/software/applications/database_client.rst deleted file mode 100644 index 81e827bc..00000000 --- a/docs/source/configuration/simulation/software/applications/database_client.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``DatabaseClient`` ------------------- - -test diff --git a/docs/source/configuration/simulation/software/applications/web_browser.rst b/docs/source/configuration/simulation/software/applications/web_browser.rst deleted file mode 100644 index 4af0d7b7..00000000 --- a/docs/source/configuration/simulation/software/applications/web_browser.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``WebBrowser`` --------------- - -test diff --git a/docs/source/configuration/simulation/software/common/system_software.rst b/docs/source/configuration/simulation/software/common/system_software.rst deleted file mode 100644 index 64248272..00000000 --- a/docs/source/configuration/simulation/software/common/system_software.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``system software`` -""""""""""""""""""" - -Some |SOFTWARE_TYPES| are pre installed on nodes - this is similar to how some |SOFTWARE_TYPES| are included with the Operating System. - -The |SOFTWARE_TYPE| may not be configured as needed, in which case, follow the steps above to configure them. - -The list of |SOFTWARE_TYPES| that are considered system software are: diff --git a/docs/source/configuration/simulation/software/services.rst b/docs/source/configuration/simulation/software/services.rst index 383f9de4..88957001 100644 --- a/docs/source/configuration/simulation/software/services.rst +++ b/docs/source/configuration/simulation/software/services.rst @@ -5,33 +5,21 @@ ``services`` ------------ -List of available services that can be installed on a |NODE|: +List of available services that can be installed on a |NODE| can be found in :ref:`List of Services ` -.. toctree:: - :maxdepth: 1 +services in configuration +""""""""""""""""""""""""" - ../software/services/database_service.rst - ../software/services/dns_client.rst - ../software/services/dns_server.rst - ../software/services/ftp_client.rst - ../software/services/ftp_server.rst - ../software/services/ntp_client.rst - ../software/services/ntp_server.rst - ../software/services/web_server.rst +Services takes a list of services as shown in the example below. -More info :py:mod:`primaite.game.game.SERVICE_TYPES_MAPPING` +.. code-block:: yaml -.. include:: ../software/common/system_software.rst - - -.. toctree:: - :maxdepth: 1 - - ../software/services/dns_client.rst - ../software/services/ftp_client.rst - ../software/services/ntp_client.rst - -More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` - -.. |SOFTWARE_TYPE| replace:: service -.. |SOFTWARE_TYPES| replace:: services + - ref: client_1 + hostname: client_1 + type: computer + ... + applications: + - ref: example_service + type: example_service_type + options: + # this section is different for each service diff --git a/docs/source/configuration/simulation/software/services/database_service.rst b/docs/source/configuration/simulation/software/services/database_service.rst deleted file mode 100644 index f03fde70..00000000 --- a/docs/source/configuration/simulation/software/services/database_service.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``DatabaseService`` -------------------- - -test diff --git a/docs/source/configuration/simulation/software/services/dns_client.rst b/docs/source/configuration/simulation/software/services/dns_client.rst deleted file mode 100644 index d9b8008d..00000000 --- a/docs/source/configuration/simulation/software/services/dns_client.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``DNSClient`` -------------- - -test diff --git a/docs/source/configuration/simulation/software/services/dns_server.rst b/docs/source/configuration/simulation/software/services/dns_server.rst deleted file mode 100644 index a342967f..00000000 --- a/docs/source/configuration/simulation/software/services/dns_server.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``DNSServer`` -------------- - -test diff --git a/docs/source/configuration/simulation/software/services/ftp_client.rst b/docs/source/configuration/simulation/software/services/ftp_client.rst deleted file mode 100644 index d51a3dc1..00000000 --- a/docs/source/configuration/simulation/software/services/ftp_client.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``FTPClient`` -------------- - -test diff --git a/docs/source/configuration/simulation/software/services/ftp_server.rst b/docs/source/configuration/simulation/software/services/ftp_server.rst deleted file mode 100644 index c7f92340..00000000 --- a/docs/source/configuration/simulation/software/services/ftp_server.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``FTPServer`` -------------- - -test diff --git a/docs/source/configuration/simulation/software/services/ntp_client.rst b/docs/source/configuration/simulation/software/services/ntp_client.rst deleted file mode 100644 index 51b2e061..00000000 --- a/docs/source/configuration/simulation/software/services/ntp_client.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``NTPClient`` -------------- - -test diff --git a/docs/source/configuration/simulation/software/services/ntp_server.rst b/docs/source/configuration/simulation/software/services/ntp_server.rst deleted file mode 100644 index 2efbdf1a..00000000 --- a/docs/source/configuration/simulation/software/services/ntp_server.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``NTPServer`` -------------- - -test diff --git a/docs/source/configuration/simulation/software/services/web_server.rst b/docs/source/configuration/simulation/software/services/web_server.rst deleted file mode 100644 index 4fab660d..00000000 --- a/docs/source/configuration/simulation/software/services/web_server.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - -``WebServer`` -------------- - -test diff --git a/docs/source/game_layer.rst b/docs/source/game_layer.rst index cdae17dd..eb9b17c3 100644 --- a/docs/source/game_layer.rst +++ b/docs/source/game_layer.rst @@ -18,7 +18,7 @@ Game layer The game layer is responsible for managing agents and getting them to interface with the simulator correctly. It consists of several components: PrimAITE Session -^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ ``PrimaiteSession`` is the main entry point into Primaite and it allows the simultaneous coordination of a simulation and agents that interact with it. ``PrimaiteSession`` keeps track of multiple agents of different types. diff --git a/docs/source/simulation_components/network/network_interfaces.rst b/docs/source/simulation_components/network/network_interfaces.rst index 9e1ad80a..f3d4d373 100644 --- a/docs/source/simulation_components/network/network_interfaces.rst +++ b/docs/source/simulation_components/network/network_interfaces.rst @@ -13,6 +13,8 @@ facilitates modular development, enhances maintainability, and supports scalabil allowing for focused enhancements within each layer. .. image:: primaite_network_interface_model.png + :width: 500 + :align: center Layer Descriptions ================== diff --git a/docs/source/simulation_components/network/nodes/firewall.rst b/docs/source/simulation_components/network/nodes/firewall.rst index 73168517..2f948081 100644 --- a/docs/source/simulation_components/network/nodes/firewall.rst +++ b/docs/source/simulation_components/network/nodes/firewall.rst @@ -229,7 +229,7 @@ To limit database server access to selected external IP addresses: position=7 ) -**Permitting DMZ Web Server Access while Blocking Specific Threats* +**Permitting DMZ Web Server Access while Blocking Specific Threats** To authorize HTTP/HTTPS access to a DMZ-hosted web server, excluding known malicious IPs: diff --git a/docs/source/simulation_components/network/nodes/network_node.rst b/docs/source/simulation_components/network/nodes/network_node.rst index eb9997ba..33bcea5b 100644 --- a/docs/source/simulation_components/network/nodes/network_node.rst +++ b/docs/source/simulation_components/network/nodes/network_node.rst @@ -27,7 +27,7 @@ in the transmission and routing of data within the simulated environment. **Key Features:** - **Frame Processing:** Central to the class is the ability to receive and process network frames, facilitating the -simulation of data flow through network devices. + simulation of data flow through network devices. - **Abstract Methods:** Includes abstract methods such as ``receive_frame``, which subclasses must implement to specify how devices handle incoming traffic. diff --git a/docs/source/simulation_components/system/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst similarity index 99% rename from docs/source/simulation_components/system/data_manipulation_bot.rst rename to docs/source/simulation_components/system/applications/data_manipulation_bot.rst index 1fd5e5c8..8c326b56 100644 --- a/docs/source/simulation_components/system/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -16,6 +16,7 @@ The bot is intended to simulate a malicious actor carrying out attacks like: - Dropping tables - Deleting records - Modifying data + on a database server by abusing an application's trusted database connectivity. The bot performs attacks in the following stages to simulate the real pattern of an attack: diff --git a/docs/source/simulation_components/system/applications/database_client.rst b/docs/source/simulation_components/system/applications/database_client.rst new file mode 100644 index 00000000..47690cb6 --- /dev/null +++ b/docs/source/simulation_components/system/applications/database_client.rst @@ -0,0 +1,38 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + + +DatabaseClient +=============== + +The DatabaseClient provides a client interface for connecting to the ``DatabaseService``. + +Key features +^^^^^^^^^^^^ + +- Connects to the ``DatabaseService`` via the ``SoftwareManager``. +- Handles connecting and disconnecting. +- Executes SQL queries and retrieves result sets. + +Usage +^^^^^ + +- Initialise with server IP address and optional password. +- Connect to the ``DatabaseService`` with ``connect``. +- Retrieve results in a dictionary. +- Disconnect when finished. + +To create database backups: + +- Configure the backup server on the ``DatabaseService`` by providing the Backup server ``IPv4Address`` with ``configure_backup`` +- Create a backup using ``backup_database``. This fails if the backup server is not configured. +- Restore a backup using ``restore_backup``. By default, this uses the database created via ``backup_database``. + +Implementation +^^^^^^^^^^^^^^ + +- Leverages ``SoftwareManager`` for sending payloads over the network. +- Connect and disconnect methods manage sessions. +- Payloads serialised as dictionaries for transmission. +- Extends base Application class. diff --git a/docs/source/configuration/simulation/software/applications/dos_bot.rst b/docs/source/simulation_components/system/applications/dos_bot.rst similarity index 82% rename from docs/source/configuration/simulation/software/applications/dos_bot.rst rename to docs/source/simulation_components/system/applications/dos_bot.rst index 98939e5b..6aa849a7 100644 --- a/docs/source/configuration/simulation/software/applications/dos_bot.rst +++ b/docs/source/simulation_components/system/applications/dos_bot.rst @@ -2,7 +2,7 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -``DoSBot`` ----------- +DoSBot +------ test diff --git a/docs/source/simulation_components/system/web_browser_and_web_server_service.rst b/docs/source/simulation_components/system/applications/web_browser.rst similarity index 72% rename from docs/source/simulation_components/system/web_browser_and_web_server_service.rst rename to docs/source/simulation_components/system/applications/web_browser.rst index 538baa58..ee4e8b94 100644 --- a/docs/source/simulation_components/system/web_browser_and_web_server_service.rst +++ b/docs/source/simulation_components/system/applications/web_browser.rst @@ -2,35 +2,9 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -Web Browser and Web Server Service -================================== -Web Server Service ------------------- -Provides a Web Server simulation by extending the base Service class. - -Key capabilities -^^^^^^^^^^^^^^^^ - -- Simulates a web server with the capability to also request data from a database -- Allows the emulation of HTTP requests between client (e.g. a web browser) and server - - GET request sends a get all users request to the database server and returns an HTTP 200 status if the database is responsive -- Leverages the Service base class for install/uninstall, status tracking, etc. - -Usage -^^^^^ -- Install on a Node via the ``SoftwareManager`` to start the `WebServer`. -- Service runs on HTTP port 80 by default. (TODO: HTTPS) - -Implementation -^^^^^^^^^^^^^^ - -- HTTP request uses a ``HttpRequestPacket`` object -- HTTP response uses a ``HttpResponsePacket`` object -- Extends Service class for integration with ``SoftwareManager``. - -Web Browser (Web Client) ------------------------- +WebBrowser +========== The ``WebBrowser`` provides a client interface for connecting to the ``WebServer``. diff --git a/docs/source/simulation_components/system/database_client_server.rst b/docs/source/simulation_components/system/database_client_server.rst deleted file mode 100644 index 07912f3e..00000000 --- a/docs/source/simulation_components/system/database_client_server.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. only:: comment - - © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK - - -Database Client Server -====================== - -Database Service ----------------- - -The ``DatabaseService`` provides a SQL database server simulation by extending the base Service class. - -Key capabilities -^^^^^^^^^^^^^^^^ - -- Creates a database file in the ``Node`` 's ``FileSystem`` upon creation. -- Handles connecting clients by maintaining a dictionary of connections mapped to session IDs. -- Authenticates connections using a configurable password. -- Simulates ``SELECT``, ``DELETE`` and ``INSERT`` SQL queries. -- Returns query results and status codes back to clients. -- Leverages the Service base class for install/uninstall, status tracking, etc. - -Usage -^^^^^ -- Install on a Node via the ``SoftwareManager`` to start the database service. -- Clients connect, execute queries, and disconnect. -- Service runs on TCP port 5432 by default. - -Implementation -^^^^^^^^^^^^^^ - -- Creates the database file within the node's file system. -- Manages client connections in a dictionary by session ID. -- Processes SQL queries. -- Returns results and status codes in a standard dictionary format. -- Extends Service class for integration with ``SoftwareManager``. - -Database Client ---------------- - -The DatabaseClient provides a client interface for connecting to the ``DatabaseService``. - -Key features -^^^^^^^^^^^^ - -- Connects to the ``DatabaseService`` via the ``SoftwareManager``. -- Handles connecting and disconnecting. -- Executes SQL queries and retrieves result sets. - -Usage -^^^^^ - -- Initialise with server IP address and optional password. -- Connect to the ``DatabaseService`` with ``connect``. -- Retrieve results in a dictionary. -- Disconnect when finished. - -To create database backups: - -- Configure the backup server on the ``DatabaseService`` by providing the Backup server ``IPv4Address`` with ``configure_backup`` -- Create a backup using ``backup_database``. This fails if the backup server is not configured. -- Restore a backup using ``restore_backup``. By default, this uses the database created via ``backup_database``. - -Implementation -^^^^^^^^^^^^^^ - -- Leverages ``SoftwareManager`` for sending payloads over the network. -- Connect and disconnect methods manage sessions. -- Payloads serialised as dictionaries for transmission. -- Extends base Application class. diff --git a/docs/source/simulation_components/system/list_of_applications.rst b/docs/source/simulation_components/system/list_of_applications.rst new file mode 100644 index 00000000..9aac23de --- /dev/null +++ b/docs/source/simulation_components/system/list_of_applications.rst @@ -0,0 +1,11 @@ +.. toctree:: + :maxdepth: 1 + + applications/data_manipulation_bot.rst + applications/database_client.rst + applications/dos_bot.rst + applications/web_browser.rst + +More info :py:mod:`primaite.game.game.APPLICATION_TYPES_MAPPING` + +.. include:: list_of_system_applications.rst diff --git a/docs/source/simulation_components/system/list_of_services.rst b/docs/source/simulation_components/system/list_of_services.rst new file mode 100644 index 00000000..07bc25ee --- /dev/null +++ b/docs/source/simulation_components/system/list_of_services.rst @@ -0,0 +1,15 @@ +.. toctree:: + :maxdepth: 1 + + services/database_service.rst + services/dns_client.rst + services/dns_server.rst + services/ftp_client.rst + services/ftp_server.rst + services/ntp_client.rst + services/ntp_server.rst + services/web_server.rst + +More info :py:mod:`primaite.game.game.SERVICE_TYPES_MAPPING` + +.. include:: list_of_system_services.rst diff --git a/docs/source/simulation_components/system/list_of_system_applications.rst b/docs/source/simulation_components/system/list_of_system_applications.rst new file mode 100644 index 00000000..ca5a7457 --- /dev/null +++ b/docs/source/simulation_components/system/list_of_system_applications.rst @@ -0,0 +1,19 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``system applications`` +""""""""""""""""""""""" + +Some applications are pre installed on nodes - this is similar to how some applications are included with the Operating System. + +The application may not be configured as needed, in which case, see the relevant application page. + +The list of applications that are considered system software are: + +.. toctree:: + :maxdepth: 1 + + applications/web_browser.rst + +More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` diff --git a/docs/source/simulation_components/system/list_of_system_services.rst b/docs/source/simulation_components/system/list_of_system_services.rst new file mode 100644 index 00000000..657faa52 --- /dev/null +++ b/docs/source/simulation_components/system/list_of_system_services.rst @@ -0,0 +1,21 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +``system services`` +""""""""""""""""""" + +Some services are pre installed on nodes - this is similar to how some services are included with the Operating System. + +The service may not be configured as needed, in which case, see the relevant service page. + +The list of services that are considered system software are: + +.. toctree:: + :maxdepth: 1 + + services/dns_client.rst + services/ftp_client.rst + services/ntp_client.rst + +More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` diff --git a/docs/source/simulation_components/system/services/database_service.rst b/docs/source/simulation_components/system/services/database_service.rst new file mode 100644 index 00000000..a4591d15 --- /dev/null +++ b/docs/source/simulation_components/system/services/database_service.rst @@ -0,0 +1,33 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +DatabaseService +=============== + +The ``DatabaseService`` provides a SQL database server simulation by extending the base Service class. + +Key capabilities +^^^^^^^^^^^^^^^^ + +- Creates a database file in the ``Node`` 's ``FileSystem`` upon creation. +- Handles connecting clients by maintaining a dictionary of connections mapped to session IDs. +- Authenticates connections using a configurable password. +- Simulates ``SELECT``, ``DELETE`` and ``INSERT`` SQL queries. +- Returns query results and status codes back to clients. +- Leverages the Service base class for install/uninstall, status tracking, etc. + +Usage +^^^^^ +- Install on a Node via the ``SoftwareManager`` to start the database service. +- Clients connect, execute queries, and disconnect. +- Service runs on TCP port 5432 by default. + +Implementation +^^^^^^^^^^^^^^ + +- Creates the database file within the node's file system. +- Manages client connections in a dictionary by session ID. +- Processes SQL queries. +- Returns results and status codes in a standard dictionary format. +- Extends Service class for integration with ``SoftwareManager``. diff --git a/docs/source/simulation_components/system/dns_client_server.rst b/docs/source/simulation_components/system/services/dns_client.rst similarity index 52% rename from docs/source/simulation_components/system/dns_client_server.rst rename to docs/source/simulation_components/system/services/dns_client.rst index f57f903b..f961ece3 100644 --- a/docs/source/simulation_components/system/dns_client_server.rst +++ b/docs/source/simulation_components/system/services/dns_client.rst @@ -2,34 +2,8 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -DNS Client Server -================= - -DNS Server ----------- -Also known as a DNS Resolver, the ``DNSServer`` provides a DNS Server simulation by extending the base Service class. - -Key capabilities -^^^^^^^^^^^^^^^^ - -- Simulates DNS requests and DNSPacket transfer across a network -- Registers domain names and the IP Address linked to the domain name -- Returns the IP address for a given domain name within a DNS Packet that a DNS Client can read -- Leverages the Service base class for install/uninstall, status tracking, etc. - -Usage -^^^^^ -- Install on a Node via the ``SoftwareManager`` to start the database service. -- Service runs on TCP port 53 by default. (TODO: TCP for now, should be UDP in future) - -Implementation -^^^^^^^^^^^^^^ - -- DNS request and responses use a ``DNSPacket`` object -- Extends Service class for integration with ``SoftwareManager``. - -DNS Client ----------- +DNSClient +========= The DNSClient provides a client interface for connecting to the ``DNSServer``. diff --git a/docs/source/simulation_components/system/services/dns_server.rst b/docs/source/simulation_components/system/services/dns_server.rst new file mode 100644 index 00000000..ef463d9a --- /dev/null +++ b/docs/source/simulation_components/system/services/dns_server.rst @@ -0,0 +1,26 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +DNSServer +========= +Also known as a DNS Resolver, the ``DNSServer`` provides a DNS Server simulation by extending the base Service class. + +Key capabilities +^^^^^^^^^^^^^^^^ + +- Simulates DNS requests and DNSPacket transfer across a network +- Registers domain names and the IP Address linked to the domain name +- Returns the IP address for a given domain name within a DNS Packet that a DNS Client can read +- Leverages the Service base class for install/uninstall, status tracking, etc. + +Usage +^^^^^ +- Install on a Node via the ``SoftwareManager`` to start the database service. +- Service runs on TCP port 53 by default. (TODO: TCP for now, should be UDP in future) + +Implementation +^^^^^^^^^^^^^^ + +- DNS request and responses use a ``DNSPacket`` object +- Extends Service class for integration with ``SoftwareManager``. diff --git a/docs/source/simulation_components/system/ftp_client_server.rst b/docs/source/simulation_components/system/services/ftp_client.rst similarity index 78% rename from docs/source/simulation_components/system/ftp_client_server.rst rename to docs/source/simulation_components/system/services/ftp_client.rst index a544b4c8..77111938 100644 --- a/docs/source/simulation_components/system/ftp_client_server.rst +++ b/docs/source/simulation_components/system/services/ftp_client.rst @@ -2,35 +2,9 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -FTP Client Server -================= -FTP Server ----------- -Provides a FTP Client-Server simulation by extending the base Service class. - -Key capabilities -^^^^^^^^^^^^^^^^ - -- Simulates FTP requests and FTPPacket transfer across a network -- Allows the emulation of FTP commands between an FTP client and server: - - STOR: stores a file from client to server - - RETR: retrieves a file from the FTP server -- Leverages the Service base class for install/uninstall, status tracking, etc. - -Usage -^^^^^ -- Install on a Node via the ``SoftwareManager`` to start the FTP server service. -- Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command) - -Implementation -^^^^^^^^^^^^^^ - -- FTP request and responses use a ``FTPPacket`` object -- Extends Service class for integration with ``SoftwareManager``. - -FTP Client ----------- +FTPClient +========= The ``FTPClient`` provides a client interface for connecting to the ``FTPServer``. diff --git a/docs/source/simulation_components/system/services/ftp_server.rst b/docs/source/simulation_components/system/services/ftp_server.rst new file mode 100644 index 00000000..81f51e6b --- /dev/null +++ b/docs/source/simulation_components/system/services/ftp_server.rst @@ -0,0 +1,27 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +FTPServer +========= +Provides a FTP Client-Server simulation by extending the base Service class. + +Key capabilities +^^^^^^^^^^^^^^^^ + +- Simulates FTP requests and FTPPacket transfer across a network +- Allows the emulation of FTP commands between an FTP client and server: + - STOR: stores a file from client to server + - RETR: retrieves a file from the FTP server +- Leverages the Service base class for install/uninstall, status tracking, etc. + +Usage +^^^^^ +- Install on a Node via the ``SoftwareManager`` to start the FTP server service. +- Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command) + +Implementation +^^^^^^^^^^^^^^ + +- FTP request and responses use a ``FTPPacket`` object +- Extends Service class for integration with ``SoftwareManager``. diff --git a/docs/source/simulation_components/system/services/ntp_client.rst b/docs/source/simulation_components/system/services/ntp_client.rst new file mode 100644 index 00000000..27cd27e4 --- /dev/null +++ b/docs/source/simulation_components/system/services/ntp_client.rst @@ -0,0 +1,26 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +NTPClient +========= + +The NTPClient provides a client interface for connecting to the ``NTPServer``. + +Key features +^^^^^^^^^^^^ + +- Connects to the ``NTPServer`` via the ``SoftwareManager``. + +Usage +^^^^^ + +- Install on a Node via the ``SoftwareManager`` to start the database service. +- Service runs on UDP port 123 by default. + +Implementation +^^^^^^^^^^^^^^ + +- Leverages ``SoftwareManager`` for sending payloads over the network. +- Provides easy interface for Nodes to find IP addresses via domain names. +- Extends base Service class. diff --git a/docs/source/simulation_components/system/ntp_client_server.rst b/docs/source/simulation_components/system/services/ntp_server.rst similarity index 56% rename from docs/source/simulation_components/system/ntp_client_server.rst rename to docs/source/simulation_components/system/services/ntp_server.rst index b6d57c13..066ad5ac 100644 --- a/docs/source/simulation_components/system/ntp_client_server.rst +++ b/docs/source/simulation_components/system/services/ntp_server.rst @@ -2,11 +2,8 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -NTP Client Server -================= - -NTP Server ----------- +NTPServer +========= The ``NTPServer`` provides a NTP Server simulation by extending the base Service class. NTP Client @@ -29,26 +26,3 @@ Implementation - NTP request and responses use a ``NTPPacket`` object - Extends Service class for integration with ``SoftwareManager``. - -NTP Client ----------- - -The NTPClient provides a client interface for connecting to the ``NTPServer``. - -Key features -^^^^^^^^^^^^ - -- Connects to the ``NTPServer`` via the ``SoftwareManager``. - -Usage -^^^^^ - -- Install on a Node via the ``SoftwareManager`` to start the database service. -- Service runs on UDP port 123 by default. - -Implementation -^^^^^^^^^^^^^^ - -- Leverages ``SoftwareManager`` for sending payloads over the network. -- Provides easy interface for Nodes to find IP addresses via domain names. -- Extends base Service class. diff --git a/docs/source/simulation_components/system/services/web_server.rst b/docs/source/simulation_components/system/services/web_server.rst new file mode 100644 index 00000000..ae3f32e6 --- /dev/null +++ b/docs/source/simulation_components/system/services/web_server.rst @@ -0,0 +1,27 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +WebServer +========= +Provides a Web Server simulation by extending the base Service class. + +Key capabilities +^^^^^^^^^^^^^^^^ + +- Simulates a web server with the capability to also request data from a database +- Allows the emulation of HTTP requests between client (e.g. a web browser) and server + - GET request sends a get all users request to the database server and returns an HTTP 200 status if the database is responsive +- Leverages the Service base class for install/uninstall, status tracking, etc. + +Usage +^^^^^ +- Install on a Node via the ``SoftwareManager`` to start the `WebServer`. +- Service runs on HTTP port 80 by default. (TODO: HTTPS) + +Implementation +^^^^^^^^^^^^^^ + +- HTTP request uses a ``HttpRequestPacket`` object +- HTTP response uses a ``HttpResponsePacket`` object +- Extends Service class for integration with ``SoftwareManager``. diff --git a/docs/source/simulation_components/system/session_and_software_manager.rst b/docs/source/simulation_components/system/session_and_software_manager.rst index a550faf1..8af96e87 100644 --- a/docs/source/simulation_components/system/session_and_software_manager.rst +++ b/docs/source/simulation_components/system/session_and_software_manager.rst @@ -16,6 +16,8 @@ ARP, ICMP, or the Web Client. This pathway exemplifies the structured processing each frame reaches its intended target within the simulated environment. .. image:: node_session_software_model_example.png + :width: 500 + :align: center Session Manager --------------- diff --git a/docs/source/simulation_components/system/software.rst b/docs/source/simulation_components/system/software.rst index 7a1359f4..459064f0 100644 --- a/docs/source/simulation_components/system/software.rst +++ b/docs/source/simulation_components/system/software.rst @@ -39,16 +39,27 @@ See :ref:`Node Start up and Shut down` assert node.operating_state is NodeOperatingState.ON assert web_server.operating_state is ServiceOperatingState.RUNNING # service turned back on when node is powered on +.. _List of Applications: -Services, Processes and Applications: -##################################### +Applications +############ -.. toctree:: - :maxdepth: 2 +These are a list of applications that are currently available in PrimAITE: - database_client_server - data_manipulation_bot - dns_client_server - ftp_client_server - ntp_client_server - web_browser_and_web_server_service +.. include:: list_of_applications.rst + +.. _List of Services: + +Services +######## + +These are a list of services that are currently available in PrimAITE: + +.. include:: list_of_services.rst + +.. _List of Processes: + +Processes +######### + +`To be implemented` diff --git a/docs/source/simulation_structure.rst b/docs/source/simulation_structure.rst index 6e0ab5ce..f9a69b26 100644 --- a/docs/source/simulation_structure.rst +++ b/docs/source/simulation_structure.rst @@ -12,14 +12,15 @@ and a domain controller for managing software and users. Each node of the simulation 'tree' has responsibility for creating, deleting, and updating its direct descendants. Also, when a component's ``describe_state()`` method is called, it will include the state of its descendants. The -``apply_request()`` method can be used to act on a component or one of its descendatnts. The diagram below shows the +``apply_request()`` method can be used to act on a component or one of its descendants. The diagram below shows the relationship between components. -.. image:: _static/component_relationship.png +.. image:: ../../_static/component_relationship.png :width: 500 - :alt: The top level simulation object owns a NetworkContainer and a DomainController. The DomainController has a - list of accounts. The network container has links and nodes. Nodes can own switchports, NICs, FileSystem, - Application, Service, and Process. + :align: center + :alt: :: The top level simulation object owns a NetworkContainer and a DomainController. The DomainController has a + list of accounts. The network container has links and nodes. Nodes can own switchports, NICs, FileSystem, + Application, Service, and Process. Actions From fb148dc4fb100ae50545913094537bc5b7dfa3b2 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Fri, 23 Feb 2024 16:49:01 +0000 Subject: [PATCH 09/18] #2257: applications and services docs --- docs/source/configuration/simulation.rst | 7 +- .../simulation_components/network/network.rst | 10 +- .../applications/data_manipulation_bot.rst | 92 +++++++++-- .../system/applications/database_client.rst | 90 +++++++++- .../system/applications/dos_bot.rst | 156 +++++++++++++++++- .../system/applications/web_browser.rst | 103 +++++++----- .../system/common/common_configuration.rst | 14 ++ .../system/list_of_applications.rst | 8 +- .../system/list_of_services.rst | 12 +- .../system/list_of_system_applications.rst | 5 +- .../system/list_of_system_services.rst | 9 +- .../system/services/database_service.rst | 84 +++++++++- .../system/services/dns_client.rst | 83 +++++++++- .../system/services/dns_server.rst | 80 ++++++++- .../system/services/ftp_client.rst | 103 +++++------- .../system/services/ftp_server.rst | 74 ++++++++- .../system/services/ntp_client.rst | 77 ++++++++- .../system/services/ntp_server.rst | 68 +++++++- .../system/services/web_server.rst | 67 +++++++- src/primaite/game/game.py | 3 +- .../services/database/database_service.py | 3 + 21 files changed, 956 insertions(+), 192 deletions(-) create mode 100644 docs/source/simulation_components/system/common/common_configuration.rst diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst index f24cc41d..89c1669b 100644 --- a/docs/source/configuration/simulation.rst +++ b/docs/source/configuration/simulation.rst @@ -29,12 +29,9 @@ To see the configuration for these nodes, refer to the following: .. toctree:: :maxdepth: 1 + :glob: - simulation/nodes/computer.rst - simulation/nodes/firewall.rst - simulation/nodes/router.rst - simulation/nodes/server.rst - simulation/nodes/switch.rst + simulation/nodes/* ``links`` --------- diff --git a/docs/source/simulation_components/network/network.rst b/docs/source/simulation_components/network/network.rst index 533a15f2..36e8ee48 100644 --- a/docs/source/simulation_components/network/network.rst +++ b/docs/source/simulation_components/network/network.rst @@ -30,11 +30,11 @@ we'll use the following Network that has a client, server, two switches, and a r .. code-block:: python from primaite.simulator.network.container import Network - from primaite.simulator.network.hardware.base import NIC - from primaite.simulator.network.hardware.nodes.computer import Computer - from primaite.simulator.network.hardware.nodes.router import Router, ACLAction - from primaite.simulator.network.hardware.nodes.server import Server - from primaite.simulator.network.hardware.nodes.switch import Switch + from primaite.simulator.network.hardware.base import NetworkInterface + from primaite.simulator.network.hardware.nodes.host.computer import Computer + from primaite.simulator.network.hardware.nodes.network.router import Router, ACLAction + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.network.hardware.nodes.network.switch import Switch from primaite.simulator.network.transmission.network_layer import IPProtocol from primaite.simulator.network.transmission.transport_layer import Port diff --git a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst index 8c326b56..209cdcbd 100644 --- a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -2,14 +2,15 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _DataManipulationBot: DataManipulationBot -=================== +################### -The ``DataManipulationBot`` class provides functionality to connect to a ``DatabaseService`` and execute malicious SQL statements. +The ``DataManipulationBot`` class provides functionality to connect to a :ref:`DatabaseService` and execute malicious SQL statements. Overview --------- +======== The bot is intended to simulate a malicious actor carrying out attacks like: @@ -28,7 +29,7 @@ The bot performs attacks in the following stages to simulate the real pattern of Each of these stages has a random, configurable probability of succeeding (by default 10%). The bot can also be configured to repeat the attack once complete. Usage ------ +===== - Create an instance and call ``configure`` to set: - Target database server IP @@ -41,16 +42,35 @@ The bot handles connecting, executing the statement, and disconnecting. In a simulation, the bot can be controlled by using ``DataManipulationAgent`` which calls ``run`` on the bot at configured timesteps. -Example -------- +Implementation +============== + +The bot extends :ref:`DatabaseClient` and leverages its connectivity. + +- Uses the Application base class for lifecycle management. +- Credentials, target IP and other options set via ``configure``. +- ``run`` handles connecting, executing statement, and disconnecting. +- SQL payload executed via ``query`` method. +- Results in malicious SQL being executed on remote database server. + + +Examples +======== + +Python +"""""" .. code-block:: python + from primaite.simulator.network.hardware.nodes.host.computer import Computer + from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState + from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot + client_1 = Computer( hostname="client_1", ip_address="192.168.10.21", subnet_mask="255.255.255.0", - default_gateway="192.168.10.1" + default_gateway="192.168.10.1", operating_state=NodeOperatingState.ON # initialise the computer in an ON state ) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1]) @@ -62,13 +82,13 @@ Example This would connect to the database service at 192.168.1.14, authenticate, and execute the SQL statement to drop the 'users' table. Example with ``DataManipulationAgent`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +"""""""""""""""""""""""""""""""""""""" If not using the data manipulation bot manually, it needs to be used with a data manipulation agent. Below is an example section of configuration file for setting up a simulation with data manipulation bot and agent. .. code-block:: yaml - game_config: + game: # ... agents: - ref: data_manipulation_red_bot @@ -129,13 +149,51 @@ If not using the data manipulation bot manually, it needs to be used with a data payload: "DELETE" server_ip: 192.168.1.14 -Implementation --------------- +Configuration +============= -The bot extends ``DatabaseClient`` and leverages its connectivity. +.. include:: ../common/common_configuration.rst -- Uses the Application base class for lifecycle management. -- Credentials, target IP and other options set via ``configure``. -- ``run`` handles connecting, executing statement, and disconnecting. -- SQL payload executed via ``query`` method. -- Results in malicious SQL being executed on remote database server. +.. |SOFTWARE_NAME| replace:: DataManipulationBot +.. |SOFTWARE_NAME_BACKTICK| replace:: ``DataManipulationBot`` + +``server_ip`` +""""""""""""" + +IP address of the :ref:`DatabaseService` which the ``DataManipulationBot`` will try to attack. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``server_password`` +""""""""""""""""""" + +Optional. Default value is ``None``. + +The password that the ``DataManipulationBot`` will use to access the :ref:`DatabaseService`. + +``payload`` +""""""""""" + +Optional. Default value is ``DELETE``. + +The payload that the ``DataManipulationBot`` will send to the :ref:`DatabaseService`. + +See :ref:`Database Payload List` + +``port_scan_p_of_success`` +"""""""""""""""""""""""""" + +Optional. Default value is ``0.1``. + +The chance of the ``DataManipulationBot`` to succeed with a port scan (and therefore continue the attack). + +This must be a float value between ``0`` and ``1``. + +``data_manipulation_p_of_success`` +"""""""""""""""""""""""""""""""""" + +Optional. Default value is ``0.1``. + +The chance of the ``DataManipulationBot`` to succeed with a data manipulation attack. + +This must be a float value between ``0`` and ``1``. diff --git a/docs/source/simulation_components/system/applications/database_client.rst b/docs/source/simulation_components/system/applications/database_client.rst index 47690cb6..61d955f2 100644 --- a/docs/source/simulation_components/system/applications/database_client.rst +++ b/docs/source/simulation_components/system/applications/database_client.rst @@ -2,37 +2,111 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _DatabaseClient: DatabaseClient -=============== +############## -The DatabaseClient provides a client interface for connecting to the ``DatabaseService``. +The ``DatabaseClient`` provides a client interface for connecting to the :ref:`DatabaseService`. Key features -^^^^^^^^^^^^ +============ -- Connects to the ``DatabaseService`` via the ``SoftwareManager``. +- Connects to the :ref:`DatabaseService` via the ``SoftwareManager``. - Handles connecting and disconnecting. - Executes SQL queries and retrieves result sets. Usage -^^^^^ +===== - Initialise with server IP address and optional password. -- Connect to the ``DatabaseService`` with ``connect``. +- Connect to the :ref:`DatabaseService` with ``connect``. - Retrieve results in a dictionary. - Disconnect when finished. To create database backups: -- Configure the backup server on the ``DatabaseService`` by providing the Backup server ``IPv4Address`` with ``configure_backup`` +- Configure the backup server on the :ref:`DatabaseService` by providing the Backup server ``IPv4Address`` with ``configure_backup`` - Create a backup using ``backup_database``. This fails if the backup server is not configured. - Restore a backup using ``restore_backup``. By default, this uses the database created via ``backup_database``. Implementation -^^^^^^^^^^^^^^ +============== - Leverages ``SoftwareManager`` for sending payloads over the network. - Connect and disconnect methods manage sessions. - Payloads serialised as dictionaries for transmission. - Extends base Application class. + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from ipaddress import IPv4Address + + from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState + from primaite.simulator.network.hardware.nodes.host.computer import Computer + from primaite.simulator.system.applications.database_client import DatabaseClient + + client = Computer( + hostname="client", + ip_address="192.168.10.21", + subnet_mask="255.255.255.0", + default_gateway="192.168.10.1", + operating_state=NodeOperatingState.ON # initialise the computer in an ON state + ) + + # install DatabaseClient + client.software_manager.install(DatabaseClient) + + database_client: DatabaseClient = client.software_manager.software.get("DatabaseClient") + + # Configure the DatabaseClient + database_client.configure(server_ip_address=IPv4Address("192.168.0.1")) # address of the DatabaseService + database_client.run() + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_computer + hostname: example_computer + type: computer + ... + applications: + - ref: database_client + type: DatabaseClient + options: + db_server_ip: 192.168.0.1 + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: DatabaseClient +.. |SOFTWARE_NAME_BACKTICK| replace:: ``DatabaseClient`` + + +``db_server_ip`` +"""""""""""""""" + +IP address of the :ref:`DatabaseService` that the ``DatabaseClient`` will connect to + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``server_password`` +""""""""""""""""""" + +Optional. Default value is ``None``. + +The password that the ``DatabaseClient`` will use to access the :ref:`DatabaseService`. diff --git a/docs/source/simulation_components/system/applications/dos_bot.rst b/docs/source/simulation_components/system/applications/dos_bot.rst index 6aa849a7..fcf3f207 100644 --- a/docs/source/simulation_components/system/applications/dos_bot.rst +++ b/docs/source/simulation_components/system/applications/dos_bot.rst @@ -2,7 +2,157 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -DoSBot ------- +.. _DoSBot: -test +DoSBot +###### + +The ``DoSBot`` is an implementation of a Denial of Service attack within the PrimAITE simulation. This specifically simulates a `Slow Loris attack `. + +Key features +============ + +- Connects to the :ref:`DatabaseService` via the ``SoftwareManager``. +- Makes many connections to the :ref:`DatabaseService` which ends up using up the available connections. + +Usage +===== + +- Configure with target IP address and optional password. +- use ``run`` to run the application_loop of DoSBot to begin attacks +- DoSBot runs through different actions at each timestep + +Implementation +============== + +- Leverages :ref:`DatabaseClient` to create connections with :ref`DatabaseServer`. +- Extends base Application class. + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from ipaddress import IPv4Address + + from primaite.simulator.network.hardware.nodes.host.computer import Computer + from primaite.simulator.system.applications.red_applications.dos_bot import DoSBot + + # Create Computer + computer = Computer( + hostname="computer", + ip_address="192.168.1.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + computer.power_on() + + # Install DoSBot on computer + computer.software_manager.install(DoSBot) + dos_bot: DoSBot = computer.software_manager.software.get("DoSBot") + + # Configure the DoSBot + dos_bot.configure( + target_ip_address=IPv4Address("192.168.0.10"), + payload="SPOOF DATA", + repeat=False, + port_scan_p_of_success=0.8, + dos_intensity=1.0, + max_sessions=1000 + ) + + # run DoSBot + dos_bot.run() + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_computer + hostname: example_computer + type: computer + ... + applications: + - ref: dos_bot + type: DoSBot + options: + target_ip_address: 192.168.0.10 + payload: SPOOF DATA + repeat: False + port_scan_p_of_success: 0.8 + dos_intensity: 1.0 + max_sessions: 1000 + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: DoSBot +.. |SOFTWARE_NAME_BACKTICK| replace:: ``DoSBot`` + +``target_ip_address`` +""""""""""""""""""""" + +IP address of the :ref:`DatabaseService` which the ``DataManipulationBot`` will try to attack. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``target_port`` +""""""""""""""" + +Optional. Default value is ``5432``. + +Port of the target service. + +See :ref:`List of IPProtocols ` for a list of protocols. + +``payload`` +""""""""""" + +Optional. Default value is ``None``. + +The payload that the ``DoSBot`` sends as part of its attack. + +``repeat`` +"""""""""" + +Optional. Default value is ``False``. + +If ``True`` the ``DoSBot`` will maintain its attack. + +``port_scan_p_of_success`` +"""""""""""""""""""""""""" + +Optional. Default value is ``0.1``. + +The chance of the ``DoSBot`` to succeed with a port scan (and therefore continue the attack). + +This must be a float value between ``0`` and ``1``. + +``dos_intensity`` +""""""""""""""""" + +Optional. Default value is ``1.0``. + +The intensity of the Denial of Service attack. This is multiplied by the number of ``max_sessions``. + +This must be a float value between ``0`` and ``1``. + +``max_sessions`` +"""""""""""""""" + +Optional. Default value is ``1000``. + +The maximum number of sessions the ``DoSBot`` is able to make. + +This must be an integer value above equal to or greater than ``0``. diff --git a/docs/source/simulation_components/system/applications/web_browser.rst b/docs/source/simulation_components/system/applications/web_browser.rst index ee4e8b94..c46089ba 100644 --- a/docs/source/simulation_components/system/applications/web_browser.rst +++ b/docs/source/simulation_components/system/applications/web_browser.rst @@ -2,16 +2,17 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _WebBrowser: WebBrowser -========== +########## -The ``WebBrowser`` provides a client interface for connecting to the ``WebServer``. +The ``WebBrowser`` provides a client interface for connecting to the :ref:`WebServer`. Key features -^^^^^^^^^^^^ +============ -- Connects to the ``WebServer`` via the ``SoftwareManager``. +- Connects to the :ref:`WebServer` via the ``SoftwareManager``. - Simulates HTTP requests and HTTP packet transfer across a network - Allows the emulation of HTTP requests between client and server: - Automatically uses ``DNSClient`` to resolve domain names @@ -19,66 +20,92 @@ Key features - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the ``WebBrowser``. - Service runs on HTTP port 80 by default. (TODO: HTTPS) - Execute sending an HTTP GET request with ``get_webpage`` Implementation -^^^^^^^^^^^^^^ +============== - Leverages ``SoftwareManager`` for sending payloads over the network. - Provides easy interface for making HTTP requests between an HTTP client and server. - Extends base Service class. -Example Usage -------------- +Examples +======== -Dependencies -^^^^^^^^^^^^ +Python +"""""" + +The ``WebBrowser`` utilises :ref:`DNSClient` and :ref:`DNSServer` to resolve a URL. + +The :ref:`DNSClient` must be configured to use the :ref:`DNSServer`. The :ref:`DNSServer` should be configured to have the ``WebBrowser`` ``target_url`` within its ``domain_mapping``. .. code-block:: python - from primaite.simulator.network.container import Network - from primaite.simulator.network.hardware.nodes.computer import Computer - from primaite.simulator.network.hardware.nodes.server import Server + from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.system.applications.web_browser import WebBrowser - from primaite.simulator.system.services.web_server.web_server_service import WebServer -Example peer to peer network -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + # Create Computer + computer = Computer( + hostname="computer", + ip_address="192.168.1.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + computer.power_on() -.. code-block:: python + # Install WebBrowser on computer + computer.software_manager.install(WebBrowser) + web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser") + web_browser.run() - net = Network() + # configure the WebBrowser + web_browser.target_url = "arcd.com" - pc1 = Computer(hostname="pc1", ip_address="192.168.1.50", subnet_mask="255.255.255.0") - srv = Server(hostname="srv", ip_address="192.168.1.10", subnet_mask="255.255.255.0") - pc1.power_on() - srv.power_on() - net.connect(pc1.network_interface[1], srv.network_interface[1]) + # once DNS server is configured with the correct domain mapping + # this should work + web_browser.get_webpage() -Install the Web Server -^^^^^^^^^^^^^^^^^^^^^^ +Via Configuration +""""""""""""""""" -.. code-block:: python +.. code-block:: yaml - # web browser is automatically installed in computer nodes - # IRL this is usually included with an OS - client: WebBrowser = pc1.software_manager.software['WebBrowser'] + simulation: + network: + nodes: + - ref: example_computer + hostname: example_computer + type: computer + ... + applications: + - ref: web_browser + type: WebBrowser + options: + target_url: http://arcd.com/ - # install web server - srv.software_manager.install(WebServer) - webserv: WebServer = srv.software_manager.software['WebServer'] +Configuration +============= -Open the web page -^^^^^^^^^^^^^^^^^ +.. include:: ../common/common_configuration.rst -Using a domain name to connect to a website requires setting up DNS Servers. For this example, it is possible to use the IP address directly +.. |SOFTWARE_NAME| replace:: WebBrowser +.. |SOFTWARE_NAME_BACKTICK| replace:: ``WebBrowser`` -.. code-block:: python +``target_url`` +"""""""""""""" - # check that the get request succeeded - print(client.get_webpage("http://192.168.1.10")) # should be True +The URL that the ``WebBrowser`` will request when ``get_webpage`` is called without parameters. + +The URL can be in any format so long as the domain is within it e.g. + +The domain ``arcd.com`` can be matched by + +- http://arcd.com/ +- http://arcd.com/users/ +- arcd.com diff --git a/docs/source/simulation_components/system/common/common_configuration.rst b/docs/source/simulation_components/system/common/common_configuration.rst new file mode 100644 index 00000000..86991655 --- /dev/null +++ b/docs/source/simulation_components/system/common/common_configuration.rst @@ -0,0 +1,14 @@ +``ref`` +======= + +Human readable name used as reference for the |SOFTWARE_NAME_BACKTICK|. Not used in code. + +``type`` +======== + +The type of software that should be added. To add |SOFTWARE_NAME| this must be |SOFTWARE_NAME_BACKTICK|. + +``options`` +=========== + +The configuration options are the attributes that fall under the options for an application. diff --git a/docs/source/simulation_components/system/list_of_applications.rst b/docs/source/simulation_components/system/list_of_applications.rst index 9aac23de..0ba0c45c 100644 --- a/docs/source/simulation_components/system/list_of_applications.rst +++ b/docs/source/simulation_components/system/list_of_applications.rst @@ -1,11 +1,11 @@ .. toctree:: :maxdepth: 1 + :glob: - applications/data_manipulation_bot.rst - applications/database_client.rst - applications/dos_bot.rst - applications/web_browser.rst + applications/* More info :py:mod:`primaite.game.game.APPLICATION_TYPES_MAPPING` .. include:: list_of_system_applications.rst + +.. |SOFTWARE_TYPE| replace:: application diff --git a/docs/source/simulation_components/system/list_of_services.rst b/docs/source/simulation_components/system/list_of_services.rst index 07bc25ee..e24b26dc 100644 --- a/docs/source/simulation_components/system/list_of_services.rst +++ b/docs/source/simulation_components/system/list_of_services.rst @@ -1,15 +1,11 @@ .. toctree:: :maxdepth: 1 + :glob: - services/database_service.rst - services/dns_client.rst - services/dns_server.rst - services/ftp_client.rst - services/ftp_server.rst - services/ntp_client.rst - services/ntp_server.rst - services/web_server.rst + services/* More info :py:mod:`primaite.game.game.SERVICE_TYPES_MAPPING` .. include:: list_of_system_services.rst + +.. |SOFTWARE_TYPE| replace:: service diff --git a/docs/source/simulation_components/system/list_of_system_applications.rst b/docs/source/simulation_components/system/list_of_system_applications.rst index ca5a7457..fae0f5d4 100644 --- a/docs/source/simulation_components/system/list_of_system_applications.rst +++ b/docs/source/simulation_components/system/list_of_system_applications.rst @@ -11,9 +11,6 @@ The application may not be configured as needed, in which case, see the relevant The list of applications that are considered system software are: -.. toctree:: - :maxdepth: 1 - - applications/web_browser.rst +- ``WebBrowser`` More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` diff --git a/docs/source/simulation_components/system/list_of_system_services.rst b/docs/source/simulation_components/system/list_of_system_services.rst index 657faa52..4ff6f245 100644 --- a/docs/source/simulation_components/system/list_of_system_services.rst +++ b/docs/source/simulation_components/system/list_of_system_services.rst @@ -11,11 +11,8 @@ The service may not be configured as needed, in which case, see the relevant ser The list of services that are considered system software are: -.. toctree:: - :maxdepth: 1 - - services/dns_client.rst - services/ftp_client.rst - services/ntp_client.rst +- ``DNSClient`` +- ``FTPClient`` +- ``NTPClient`` More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` diff --git a/docs/source/simulation_components/system/services/database_service.rst b/docs/source/simulation_components/system/services/database_service.rst index a4591d15..30d6b3ba 100644 --- a/docs/source/simulation_components/system/services/database_service.rst +++ b/docs/source/simulation_components/system/services/database_service.rst @@ -2,13 +2,15 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _DatabaseService: + DatabaseService -=============== +############### The ``DatabaseService`` provides a SQL database server simulation by extending the base Service class. Key capabilities -^^^^^^^^^^^^^^^^ +================ - Creates a database file in the ``Node`` 's ``FileSystem`` upon creation. - Handles connecting clients by maintaining a dictionary of connections mapped to session IDs. @@ -18,16 +20,90 @@ Key capabilities - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the database service. - Clients connect, execute queries, and disconnect. - Service runs on TCP port 5432 by default. Implementation -^^^^^^^^^^^^^^ +============== - Creates the database file within the node's file system. - Manages client connections in a dictionary by session ID. - Processes SQL queries. - Returns results and status codes in a standard dictionary format. - Extends Service class for integration with ``SoftwareManager``. + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from ipaddress import IPv4Address + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.database.database_service import DatabaseService + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install DatabaseService on server + server.software_manager.install(DatabaseService) + db_service: DatabaseService = server.software_manager.software.get("DatabaseService") + db_service.start() + + # configure DatabaseService + db_service.configure_backup(IPv4Address("192.168.0.10")) + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: database_service + type: DatabaseService + options: + backup_server_ip: 192.168.0.10 + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: DatabaseService +.. |SOFTWARE_NAME_BACKTICK| replace:: ``DatabaseService`` + +``backup_server_ip`` +"""""""""""""""""""" + +Optional. Default value is ``None``. + +The IP Address of the backup server that the ``DatabaseService`` will use to create backups of the database. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. + +``password`` +"""""""""""" + +Optional. Default value is ``None``. + +The password that needs to be provided by connecting clients in order to create a successful connection. diff --git a/docs/source/simulation_components/system/services/dns_client.rst b/docs/source/simulation_components/system/services/dns_client.rst index f961ece3..91461590 100644 --- a/docs/source/simulation_components/system/services/dns_client.rst +++ b/docs/source/simulation_components/system/services/dns_client.rst @@ -2,20 +2,22 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK -DNSClient -========= +.. _DNSClient: -The DNSClient provides a client interface for connecting to the ``DNSServer``. +DNSClient +######### + +The DNSClient provides a client interface for connecting to the :ref:`DNSServer`. Key features -^^^^^^^^^^^^ +============ -- Connects to the ``DNSServer`` via the ``SoftwareManager``. +- Connects to the :ref:`DNSServer` via the ``SoftwareManager``. - Executes DNS lookup requests and keeps a cache of known domain name IP addresses. - Handles connection to DNSServer and querying for domain name IP addresses. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the database service. - Service runs on TCP port 53 by default. (TODO: TCP for now, should be UDP in future) @@ -23,8 +25,75 @@ Usage - ``DNSClient`` will automatically add the IP Address of the domain into its cache Implementation -^^^^^^^^^^^^^^ +============== - Leverages ``SoftwareManager`` for sending payloads over the network. - Provides easy interface for Nodes to find IP addresses via domain names. - Extends base Service class. + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from ipaddress import IPv4Address + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.dns.dns_client import DNSClient + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install DNSClient on server + server.software_manager.install(DNSClient) + dns_client: DNSClient = server.software_manager.software.get("DNSClient") + dns_client.start() + + # configure DatabaseService + dns_client.dns_server = IPv4Address("192.168.0.10") + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: dns_client + type: DNSClient + options: + dns_server: 192.168.0.10 + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: DNSClient +.. |SOFTWARE_NAME_BACKTICK| replace:: ``DNSClient`` + +``dns_server`` +"""""""""""""" + +Optional. Default value is ``None``. + +The IP Address of the :ref:`DNSServer`. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. diff --git a/docs/source/simulation_components/system/services/dns_server.rst b/docs/source/simulation_components/system/services/dns_server.rst index ef463d9a..89ce7fc1 100644 --- a/docs/source/simulation_components/system/services/dns_server.rst +++ b/docs/source/simulation_components/system/services/dns_server.rst @@ -2,12 +2,15 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _DNSServer: + DNSServer -========= +######### + Also known as a DNS Resolver, the ``DNSServer`` provides a DNS Server simulation by extending the base Service class. Key capabilities -^^^^^^^^^^^^^^^^ +================ - Simulates DNS requests and DNSPacket transfer across a network - Registers domain names and the IP Address linked to the domain name @@ -15,12 +18,81 @@ Key capabilities - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the database service. - Service runs on TCP port 53 by default. (TODO: TCP for now, should be UDP in future) Implementation -^^^^^^^^^^^^^^ +============== - DNS request and responses use a ``DNSPacket`` object - Extends Service class for integration with ``SoftwareManager``. + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from ipaddress import IPv4Address + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.dns.dns_server import DNSServer + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install DNSServer on server + server.software_manager.install(DNSServer) + dns_server: DNSServer = server.software_manager.software.get("DNSServer") + dns_server.start() + + # configure DatabaseService + dns_server.dns_register("arcd.com", IPv4Address("192.168.10.10")) + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: dns_server + type: DNSServer + options: + domain_mapping: + arcd.com: 192.168.0.10 + another-example.com: 192.168.10.10 + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: DNSServer +.. |SOFTWARE_NAME_BACKTICK| replace:: ``DNSServer`` + +domain_mapping +"""""""""""""" + +Domain mapping takes the domain and IP Addresses as a key-value pairs i.e. + +If the domain is "arcd.com" and the IP Address attributed to the domain is 192.168.0.10, then the value should be ``arcd.com: 192.168.0.10`` + +The key must be a string and the IP Address must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. diff --git a/docs/source/simulation_components/system/services/ftp_client.rst b/docs/source/simulation_components/system/services/ftp_client.rst index 77111938..82b85770 100644 --- a/docs/source/simulation_components/system/services/ftp_client.rst +++ b/docs/source/simulation_components/system/services/ftp_client.rst @@ -2,16 +2,17 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _FTPClient: FTPClient -========= +######### -The ``FTPClient`` provides a client interface for connecting to the ``FTPServer``. +The ``FTPClient`` provides a client interface for connecting to the :ref:`FTPServer`. Key features -^^^^^^^^^^^^ +============ -- Connects to the ``FTPServer`` via the ``SoftwareManager``. +- Connects to the :ref:`FTPServer` via the ``SoftwareManager``. - Simulates FTP requests and FTPPacket transfer across a network - Allows the emulation of FTP commands between an FTP client and server: - PORT: specifies the port that server should connect to on the client (currently only uses ``Port.FTP``) @@ -21,7 +22,7 @@ Key features - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the FTP client service. - Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command) @@ -29,81 +30,61 @@ Usage - Execute retrieving a file from the FTP server with ``request_file`` Implementation -^^^^^^^^^^^^^^ +============== - Leverages ``SoftwareManager`` for sending payloads over the network. - Provides easy interface for Nodes to transfer files between each other. - Extends base Service class. +Examples +======== -Example Usage -------------- - -Dependencies -^^^^^^^^^^^^ +Python +"""""" .. code-block:: python - from ipaddress import IPv4Address - - from primaite.simulator.network.container import Network - from primaite.simulator.network.hardware.nodes.computer import Computer - from primaite.simulator.network.hardware.nodes.server import Server - from primaite.simulator.system.services.ftp.ftp_server import FTPServer + from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.system.services.ftp.ftp_client import FTPClient - from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState -Example peer to peer network -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - net = Network() - - pc1 = Computer( - hostname="pc1", - ip_address="120.10.10.10", + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", subnet_mask="255.255.255.0", - operating_state=NodeOperatingState.ON # initialise the computer in an ON state + default_gateway="192.168.1.1Ó", + start_up_duration=0, ) - srv = Server( - hostname="srv", - ip_address="120.10.10.20", - subnet_mask="255.255.255.0", - operating_state=NodeOperatingState.ON # initialise the server in an ON state - ) - net.connect(pc1.network_interface[1], srv.network_interface[1]) + server.power_on() -Install the FTP Server -^^^^^^^^^^^^^^^^^^^^^^ + # Install FTPClient on server + server.software_manager.install(FTPClient) + ftp_client: FTPClient = server.software_manager.software.get("FTPClient") + ftp_client.start() -FTP Client should be pre installed on nodes -.. code-block:: python +Via Configuration +""""""""""""""""" - srv.software_manager.install(FTPServer) - ftpserv: FTPServer = srv.software_manager.software['FTPServer'] +.. code-block:: yaml -Setting up the FTP Server -^^^^^^^^^^^^^^^^^^^^^^^^^ + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: ftp_client + type: FTPClient -Set up the FTP Server with a file that the client will need to retrieve +Configuration +============= -.. code-block:: python +.. include:: ../common/common_configuration.rst - srv.file_system.create_file('my_file.png') +.. |SOFTWARE_NAME| replace:: FTPClient +.. |SOFTWARE_NAME_BACKTICK| replace:: ``FTPClient`` -Check that file was retrieved -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - client.request_file( - src_folder_name='root', - src_file_name='my_file.png', - dest_folder_name='root', - dest_file_name='test.png', - dest_ip_address=IPv4Address("120.10.10.20") - ) - - print(client.get_file(folder_name="root", file_name="test.png")) +**FTPClient has no configuration options** diff --git a/docs/source/simulation_components/system/services/ftp_server.rst b/docs/source/simulation_components/system/services/ftp_server.rst index 81f51e6b..d807a14f 100644 --- a/docs/source/simulation_components/system/services/ftp_server.rst +++ b/docs/source/simulation_components/system/services/ftp_server.rst @@ -2,12 +2,15 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _FTPServer: + FTPServer -========= +######### + Provides a FTP Client-Server simulation by extending the base Service class. Key capabilities -^^^^^^^^^^^^^^^^ +================ - Simulates FTP requests and FTPPacket transfer across a network - Allows the emulation of FTP commands between an FTP client and server: @@ -16,12 +19,75 @@ Key capabilities - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== + - Install on a Node via the ``SoftwareManager`` to start the FTP server service. - Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command) Implementation -^^^^^^^^^^^^^^ +============== - FTP request and responses use a ``FTPPacket`` object - Extends Service class for integration with ``SoftwareManager``. + + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.ftp.ftp_server import FTPServer + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install FTPServer on server + server.software_manager.install(FTPServer) + ftp_server: FTPServer = server.software_manager.software.get("FTPServer") + ftp_server.start() + + ftp_server.server_password = "test" + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: ftp_server + type: FTPServer + options: + server_password: test + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: FTPServer +.. |SOFTWARE_NAME_BACKTICK| replace:: ``FTPServer`` + +``server_password`` +""""""""""""""""""" + +Optional. Default value is ``None``. + +The password that needs to be provided by a connecting :ref:`FTPClient` in order to create a successful connection. diff --git a/docs/source/simulation_components/system/services/ntp_client.rst b/docs/source/simulation_components/system/services/ntp_client.rst index 27cd27e4..aaba3261 100644 --- a/docs/source/simulation_components/system/services/ntp_client.rst +++ b/docs/source/simulation_components/system/services/ntp_client.rst @@ -2,25 +2,94 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _NTPClient: + NTPClient -========= +######### The NTPClient provides a client interface for connecting to the ``NTPServer``. Key features -^^^^^^^^^^^^ +============ - Connects to the ``NTPServer`` via the ``SoftwareManager``. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the database service. - Service runs on UDP port 123 by default. Implementation -^^^^^^^^^^^^^^ +============== - Leverages ``SoftwareManager`` for sending payloads over the network. - Provides easy interface for Nodes to find IP addresses via domain names. - Extends base Service class. + + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from ipaddress import IPv4Address + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.ntp.ntp_client import NTPClient + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install NTPClient on server + server.software_manager.install(NTPClient) + ntp_client: NTPClient = server.software_manager.software.get("NTPClient") + ntp_client.start() + + ntp_client.configure(ntp_server_ip_address=IPv4Address("192.168.0.10")) + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: ntp_client + type: NTPClient + options: + ntp_server_ip: 192.168.0.10 + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: NTPClient +.. |SOFTWARE_NAME_BACKTICK| replace:: ``NTPClient`` + +``ntp_server_ip`` +""""""""""""""""" + +Optional. Default value is ``None``. + +The IP address of an NTP Server which provides a time that the ``NTPClient`` can synchronise to. + +This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. diff --git a/docs/source/simulation_components/system/services/ntp_server.rst b/docs/source/simulation_components/system/services/ntp_server.rst index 066ad5ac..0025b428 100644 --- a/docs/source/simulation_components/system/services/ntp_server.rst +++ b/docs/source/simulation_components/system/services/ntp_server.rst @@ -2,27 +2,85 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _NTPServer: + NTPServer -========= +######### + The ``NTPServer`` provides a NTP Server simulation by extending the base Service class. NTP Client ----------- +========== + The ``NTPClient`` provides a NTP Client simulation by extending the base Service class. Key capabilities -^^^^^^^^^^^^^^^^ +================ - Simulates NTP requests and NTPPacket transfer across a network - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== - Install on a Node via the ``SoftwareManager`` to start the database service. - Service runs on UDP port 123 by default. Implementation -^^^^^^^^^^^^^^ +============== - NTP request and responses use a ``NTPPacket`` object - Extends Service class for integration with ``SoftwareManager``. + + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.ntp.ntp_server import NTPServer + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install NTPServer on server + server.software_manager.install(NTPServer) + ntp_server: NTPServer = server.software_manager.software.get("NTPServer") + ntp_server.start() + + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: ntp_server + type: NTPServer + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: NTPServer +.. |SOFTWARE_NAME_BACKTICK| replace:: ``NTPServer`` + +**NTPServer has no configuration options** diff --git a/docs/source/simulation_components/system/services/web_server.rst b/docs/source/simulation_components/system/services/web_server.rst index ae3f32e6..62b1d090 100644 --- a/docs/source/simulation_components/system/services/web_server.rst +++ b/docs/source/simulation_components/system/services/web_server.rst @@ -2,12 +2,15 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _WebServer: + WebServer -========= +######### + Provides a Web Server simulation by extending the base Service class. Key capabilities -^^^^^^^^^^^^^^^^ +================ - Simulates a web server with the capability to also request data from a database - Allows the emulation of HTTP requests between client (e.g. a web browser) and server @@ -15,13 +18,69 @@ Key capabilities - Leverages the Service base class for install/uninstall, status tracking, etc. Usage -^^^^^ +===== + - Install on a Node via the ``SoftwareManager`` to start the `WebServer`. - Service runs on HTTP port 80 by default. (TODO: HTTPS) +- A :ref:`DatabaseClient` must be installed and configured on the same node as the ``WebServer`` if it is intended to send a users request i.e. + in the case that the :ref:`WebBrowser` sends a request with users in its request path, the ``WebServer`` will utilise the ``DatabaseClient`` to send a request to the ``DatabaseService`` Implementation -^^^^^^^^^^^^^^ +============== - HTTP request uses a ``HttpRequestPacket`` object - HTTP response uses a ``HttpResponsePacket`` object - Extends Service class for integration with ``SoftwareManager``. + + +Examples +======== + +Python +"""""" + +.. code-block:: python + + from primaite.simulator.network.hardware.nodes.host.server import Server + from primaite.simulator.system.services.web_server.web_server import WebServer + + # Create Server + server = Server( + hostname="server", + ip_address="192.168.2.2", + subnet_mask="255.255.255.0", + default_gateway="192.168.1.1", + start_up_duration=0, + ) + server.power_on() + + # Install WebServer on server + server.software_manager.install(WebServer) + web_server: WebServer = server.software_manager.software.get("WebServer") + web_server.start() + +Via Configuration +""""""""""""""""" + +.. code-block:: yaml + + simulation: + network: + nodes: + - ref: example_server + hostname: example_server + type: server + ... + services: + - ref: web_server + type: WebServer + +Configuration +============= + +.. include:: ../common/common_configuration.rst + +.. |SOFTWARE_NAME| replace:: WebServer +.. |SOFTWARE_NAME_BACKTICK| replace:: ``WebServer`` + +**WebServer has no configuration options** diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index 8e78f636..ef54893e 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -296,6 +296,7 @@ class PrimaiteGame: if service_type == "DatabaseService": if "options" in service_cfg: opt = service_cfg["options"] + new_service.password = opt.get("backup_server_ip", None) new_service.configure_backup(backup_server=IPv4Address(opt.get("backup_server_ip"))) if service_type == "FTPServer": if "options" in service_cfg: @@ -327,7 +328,7 @@ class PrimaiteGame: new_application.configure( server_ip_address=IPv4Address(opt.get("server_ip")), server_password=opt.get("server_password"), - payload=opt.get("payload"), + payload=opt.get("payload", "DELETE"), port_scan_p_of_success=float(opt.get("port_scan_p_of_success", "0.1")), data_manipulation_p_of_success=float(opt.get("data_manipulation_p_of_success", "0.1")), ) diff --git a/src/primaite/simulator/system/services/database/database_service.py b/src/primaite/simulator/system/services/database/database_service.py index 0b9554d5..c0390b4f 100644 --- a/src/primaite/simulator/system/services/database/database_service.py +++ b/src/primaite/simulator/system/services/database/database_service.py @@ -23,6 +23,7 @@ class DatabaseService(Service): """ password: Optional[str] = None + """Password that needs to be provided by clients if they want to connect to the DatabaseService.""" backup_server_ip: IPv4Address = None """IP address of the backup server.""" @@ -194,6 +195,8 @@ class DatabaseService(Service): """ Executes the given SQL query and returns the result. + .. _Database Payload List: + Possible queries: - SELECT : returns the data - DELETE : deletes the data From 07373d941eab4ea4d03caad49e8db327d2e1b84e Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 26 Feb 2024 08:44:08 +0000 Subject: [PATCH 10/18] #2257: Downgrade version of sphinx - 7.2.0 drops support for Python 3.8 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 44ce75c6..19b5b7fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,7 @@ dev = [ "pytest-cov==4.0.0", "pytest-flake8==1.1.1", "setuptools==66", - "Sphinx==7.2.6", + "Sphinx==7.1.2", "sphinx-copybutton==0.5.2", "wheel==0.38.4" ] From 1d5c153752269428c67bda75652bcbd8cef5f3fc Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 26 Feb 2024 08:49:11 +0000 Subject: [PATCH 11/18] #2257: changelog update --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01e45d2e..e96bf4a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,12 @@ SessionManager. - `AirSpace` class to simulate wireless communications, managing wireless interfaces and facilitating the transmission of frames within specified frequencies. - `AirSpaceFrequency` enum for defining standard wireless frequencies, including 2.4 GHz and 5 GHz bands, to support realistic wireless network simulations. - `WirelessRouter` class, extending the `Router` class, to incorporate wireless networking capabilities alongside traditional wired connections. This class allows the configuration of wireless access points with specific IP settings and operating frequencies. +- Configuration examples in documentation: + - Examples include how to set up PrimAITE session + - Examples include how to create nodes and install software +- Ability to add Firewall node via config +- Ability to add Router routes via config +- Ability to add Router/Firewall ACL Rules via config ### Changed From e964b8a3eaebf3f3415dc089ccca9c6db4412183 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 26 Feb 2024 08:58:03 +0000 Subject: [PATCH 12/18] #2257: more in depth changelog --- CHANGELOG.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e96bf4a6..e51a912e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,12 +82,19 @@ SessionManager. - `AirSpace` class to simulate wireless communications, managing wireless interfaces and facilitating the transmission of frames within specified frequencies. - `AirSpaceFrequency` enum for defining standard wireless frequencies, including 2.4 GHz and 5 GHz bands, to support realistic wireless network simulations. - `WirelessRouter` class, extending the `Router` class, to incorporate wireless networking capabilities alongside traditional wired connections. This class allows the configuration of wireless access points with specific IP settings and operating frequencies. -- Configuration examples in documentation: - - Examples include how to set up PrimAITE session - - Examples include how to create nodes and install software -- Ability to add Firewall node via config -- Ability to add Router routes via config -- Ability to add Router/Firewall ACL Rules via config +- Documentation Updates: + - Examples include how to set up PrimAITE session via config + - Examples include how to create nodes and install software via config + - Examples include how to set up PrimAITE session via Python + - Examples include how to create nodes and install software via Python + - Added missing ``DoSBot`` documentation page + - Added diagrams where needed to make understanding some things easier + - Templated parts of the documentation to prevent unnecessary repetition and for easier maintaining of documentation + - Separated documentation pages of some items i.e. client and server software were on the same pages - which may make things confusing + - Configuration section at the bottom of the software pages specifying the configuration options available (and which ones are optional) +- Ability to add ``Firewall`` node via config +- Ability to add ``Router`` routes via config +- Ability to add ``Router``/``Firewall`` ``ACLRule`` via config ### Changed From 634f6340973eca2b2927f03e897593714034ded0 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 26 Feb 2024 09:47:12 +0000 Subject: [PATCH 13/18] #2257: fix text and make examples in node configs more specific --- .../common/common_network_node_attributes.rst | 2 +- .../simulation/nodes/computer.rst | 26 ++++---- .../simulation/nodes/firewall.rst | 64 ++++++++++--------- .../configuration/simulation/nodes/router.rst | 20 +++--- .../configuration/simulation/nodes/server.rst | 26 ++++---- .../configuration/simulation/nodes/switch.rst | 12 ++-- 6 files changed, 80 insertions(+), 70 deletions(-) diff --git a/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst index 83007145..d0b3e65b 100644 --- a/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst +++ b/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst @@ -23,7 +23,7 @@ e.g. ``address`` """"""""""" -The target IP address for the route. If the packet destination IP address matches this, the router will route the packet according to the ``next_hop_ip_address``. +The target IP address for the route. If the packet destination IP address matches this, the |NODE| will route the packet according to the ``next_hop_ip_address``. This must be a valid octet i.e. in the range of ``0.0.0.0`` and ``255.255.255.255``. diff --git a/docs/source/configuration/simulation/nodes/computer.rst b/docs/source/configuration/simulation/nodes/computer.rst index bbdf087d..04a45766 100644 --- a/docs/source/configuration/simulation/nodes/computer.rst +++ b/docs/source/configuration/simulation/nodes/computer.rst @@ -16,18 +16,20 @@ example computer .. code-block:: yaml - nodes: - - ref: client_1 - hostname: client_1 - type: computer - ip_address: 192.168.0.10 - subnet_mask: 255.255.255.0 - default_gateway: 192.168.0.1 - dns_server: 192.168.1.10 - applications: - ... - services: - ... + simulation: + network: + nodes: + - ref: client_1 + hostname: client_1 + type: computer + ip_address: 192.168.0.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.0.1 + dns_server: 192.168.1.10 + applications: + ... + services: + ... .. include:: common/common_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/firewall.rst b/docs/source/configuration/simulation/nodes/firewall.rst index c8a21a02..3c1fce0a 100644 --- a/docs/source/configuration/simulation/nodes/firewall.rst +++ b/docs/source/configuration/simulation/nodes/firewall.rst @@ -18,37 +18,39 @@ example firewall .. code-block:: yaml - nodes: - - ref: firewall - hostname: firewall - type: firewall - start_up_duration: 0 - shut_down_duration: 0 - ports: - external_port: # port 1 - ip_address: 192.168.20.1 - subnet_mask: 255.255.255.0 - internal_port: # port 2 - ip_address: 192.168.1.2 - subnet_mask: 255.255.255.0 - dmz_port: # port 3 - ip_address: 192.168.10.1 - subnet_mask: 255.255.255.0 - acl: - internal_inbound_acl: - ... - internal_outbound_acl: - ... - dmz_inbound_acl: - ... - dmz_outbound_acl: - ... - external_inbound_acl: - ... - external_outbound_acl: - ... - routes: - ... + simulation: + network: + nodes: + - ref: firewall + hostname: firewall + type: firewall + start_up_duration: 0 + shut_down_duration: 0 + ports: + external_port: # port 1 + ip_address: 192.168.20.1 + subnet_mask: 255.255.255.0 + internal_port: # port 2 + ip_address: 192.168.1.2 + subnet_mask: 255.255.255.0 + dmz_port: # port 3 + ip_address: 192.168.10.1 + subnet_mask: 255.255.255.0 + acl: + internal_inbound_acl: + ... + internal_outbound_acl: + ... + dmz_inbound_acl: + ... + dmz_outbound_acl: + ... + external_inbound_acl: + ... + external_outbound_acl: + ... + routes: + ... .. include:: common/common_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/router.rst b/docs/source/configuration/simulation/nodes/router.rst index 8a8efc06..b9ba1ad5 100644 --- a/docs/source/configuration/simulation/nodes/router.rst +++ b/docs/source/configuration/simulation/nodes/router.rst @@ -16,15 +16,17 @@ example router .. code-block:: yaml - nodes: - - ref: router_1 - hostname: router_1 - type: router - num_ports: 5 - ports: - ... - acl: - ... + simulation: + network: + nodes: + - ref: router_1 + hostname: router_1 + type: router + num_ports: 5 + ports: + ... + acl: + ... .. include:: common/common_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/server.rst b/docs/source/configuration/simulation/nodes/server.rst index 7f51eaf2..dbc32235 100644 --- a/docs/source/configuration/simulation/nodes/server.rst +++ b/docs/source/configuration/simulation/nodes/server.rst @@ -16,18 +16,20 @@ example server .. code-block:: yaml - nodes: - - ref: server_1 - hostname: server_1 - type: server - ip_address: 192.168.10.10 - subnet_mask: 255.255.255.0 - default_gateway: 192.168.10.1 - dns_server: 192.168.1.10 - applications: - ... - services: - ... + simulation: + network: + nodes: + - ref: server_1 + hostname: server_1 + type: server + ip_address: 192.168.10.10 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.10.1 + dns_server: 192.168.1.10 + applications: + ... + services: + ... .. include:: common/common_node_attributes.rst diff --git a/docs/source/configuration/simulation/nodes/switch.rst b/docs/source/configuration/simulation/nodes/switch.rst index 4d57f76e..263bedbb 100644 --- a/docs/source/configuration/simulation/nodes/switch.rst +++ b/docs/source/configuration/simulation/nodes/switch.rst @@ -16,11 +16,13 @@ example switch .. code-block:: yaml - nodes: - - ref: switch_1 - hostname: switch_1 - type: switch - num_ports: 8 + simulation: + network: + nodes: + - ref: switch_1 + hostname: switch_1 + type: switch + num_ports: 8 .. include:: common/common_node_attributes.rst From d738a2370935c408973777ae5aeea542ba6e5294 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 26 Feb 2024 11:35:17 +0000 Subject: [PATCH 14/18] #2257: list of db payloads --- .../system/applications/data_manipulation_bot.rst | 2 +- .../system/applications/dos_bot.rst | 4 +++- .../system/common/common_configuration.rst | 4 ++++ .../system/common/db_payload_list.rst | 11 +++++++++++ .../system/services/database/database_service.py | 2 -- 5 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 docs/source/simulation_components/system/common/db_payload_list.rst diff --git a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst index 209cdcbd..d0e89f2e 100644 --- a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -178,7 +178,7 @@ Optional. Default value is ``DELETE``. The payload that the ``DataManipulationBot`` will send to the :ref:`DatabaseService`. -See :ref:`Database Payload List` +.. include:: ../common/db_payload_list.rst ``port_scan_p_of_success`` """""""""""""""""""""""""" diff --git a/docs/source/simulation_components/system/applications/dos_bot.rst b/docs/source/simulation_components/system/applications/dos_bot.rst index fcf3f207..6ddbac72 100644 --- a/docs/source/simulation_components/system/applications/dos_bot.rst +++ b/docs/source/simulation_components/system/applications/dos_bot.rst @@ -123,6 +123,8 @@ Optional. Default value is ``None``. The payload that the ``DoSBot`` sends as part of its attack. +.. include:: ../common/db_payload_list.rst + ``repeat`` """""""""" @@ -155,4 +157,4 @@ Optional. Default value is ``1000``. The maximum number of sessions the ``DoSBot`` is able to make. -This must be an integer value above equal to or greater than ``0``. +This must be an integer value equal to or greater than ``0``. diff --git a/docs/source/simulation_components/system/common/common_configuration.rst b/docs/source/simulation_components/system/common/common_configuration.rst index 86991655..27625407 100644 --- a/docs/source/simulation_components/system/common/common_configuration.rst +++ b/docs/source/simulation_components/system/common/common_configuration.rst @@ -1,3 +1,7 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + ``ref`` ======= diff --git a/docs/source/simulation_components/system/common/db_payload_list.rst b/docs/source/simulation_components/system/common/db_payload_list.rst new file mode 100644 index 00000000..f51227c6 --- /dev/null +++ b/docs/source/simulation_components/system/common/db_payload_list.rst @@ -0,0 +1,11 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _Database Payload List: + +Available Database Payloads: + +- ``SELECT`` +- ``INSERT`` +- ``DELETE`` diff --git a/src/primaite/simulator/system/services/database/database_service.py b/src/primaite/simulator/system/services/database/database_service.py index c0390b4f..726d213e 100644 --- a/src/primaite/simulator/system/services/database/database_service.py +++ b/src/primaite/simulator/system/services/database/database_service.py @@ -195,8 +195,6 @@ class DatabaseService(Service): """ Executes the given SQL query and returns the result. - .. _Database Payload List: - Possible queries: - SELECT : returns the data - DELETE : deletes the data From f2d7a2fc1646e86f1c2fbb2d3f47020ac785a7c5 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Mon, 26 Feb 2024 14:34:34 +0000 Subject: [PATCH 15/18] #2257: added way to ensure nodes are on at start + more test to make sure nodes are on when added via config --- src/primaite/game/game.py | 9 +++++++-- .../nodes/network/test_firewall_config.py | 11 ++++++++++- .../nodes/network/test_router_config.py | 6 +++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index ef54893e..fbf6ea50 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -359,13 +359,18 @@ class PrimaiteGame: for nic_num, nic_cfg in node_cfg["network_interfaces"].items(): new_node.connect_nic(NIC(ip_address=nic_cfg["ip_address"], subnet_mask=nic_cfg["subnet_mask"])) - new_node.start_up_duration = int(node_cfg.get("start_up_duration", 3)) - new_node.shut_down_duration = int(node_cfg.get("shut_down_duration", 3)) + # temporarily set to 0 so all nodes are initially on + new_node.start_up_duration = 0 + new_node.shut_down_duration = 0 net.add_node(new_node) new_node.power_on() game.ref_map_nodes[node_ref] = new_node.uuid + # set start up and shut down duration + new_node.start_up_duration = int(node_cfg.get("start_up_duration", 3)) + new_node.shut_down_duration = int(node_cfg.get("shut_down_duration", 3)) + # 2. create links between nodes for link_cfg in links_cfg: node_a = net.nodes[game.ref_map_nodes[link_cfg["endpoint_a_ref"]]] diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py b/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py index ae71809b..2e0556e9 100644 --- a/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py +++ b/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py @@ -1,6 +1,7 @@ import pytest from primaite.simulator.network.container import Network +from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.network.firewall import Firewall @@ -20,7 +21,10 @@ def test_firewall_is_in_configuration(dmz_config): """Test that the firewall exists in the configuration file.""" network: Network = dmz_config - assert network.get_node_by_hostname("firewall") + firewall: Firewall = network.get_node_by_hostname("firewall") + + assert firewall + assert firewall.operating_state == NodeOperatingState.ON def test_firewall_routes_are_correctly_added(dmz_config): @@ -39,6 +43,11 @@ def test_firewall_routes_are_correctly_added(dmz_config): assert external_computer.ping(client_1.network_interface[1].ip_address) assert external_server.ping(client_1.network_interface[1].ip_address) + # client_1 should be able to ping other nodes + assert client_1.ping(dmz_server.network_interface[1].ip_address) + assert client_1.ping(external_computer.network_interface[1].ip_address) + assert client_1.ping(external_server.network_interface[1].ip_address) + def test_firewall_acl_rules_correctly_added(dmz_config): """ diff --git a/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py b/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py index fbaca12d..4382cc30 100644 --- a/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py +++ b/tests/integration_tests/configuration_file_parsing/nodes/network/test_router_config.py @@ -1,6 +1,7 @@ import pytest from primaite.simulator.network.container import Network +from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router @@ -19,7 +20,10 @@ def test_router_is_in_configuration(dmz_config): """Test that the router exists in the configuration file.""" network: Network = dmz_config - assert network.get_node_by_hostname("router_1") + router_1: Router = network.get_node_by_hostname("router_1") + + assert router_1 + assert router_1.operating_state == NodeOperatingState.ON def test_router_routes_are_correctly_added(dmz_config): From 6d43c61058f4d342b2ed1f62bf601cb9bd824729 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Wed, 28 Feb 2024 15:08:00 +0000 Subject: [PATCH 16/18] #2257: apply PR suggestions --- .../common/common_host_node_attributes.rst | 2 +- .../simulation/nodes/firewall.rst | 38 ++++++++++++++++++- .../applications/data_manipulation_bot.rst | 4 +- .../system/list_of_applications.rst | 4 ++ .../system/list_of_services.rst | 4 ++ .../system/services/database_service.rst | 2 +- .../system/services/ftp_client.rst | 3 +- .../system/services/ftp_server.rst | 3 +- src/primaite/game/agent/rewards.py | 6 +-- .../hardware/nodes/network/firewall.py | 38 +++++++++---------- .../network/hardware/nodes/network/router.py | 12 +++--- 11 files changed, 81 insertions(+), 35 deletions(-) diff --git a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst index a95f98d4..b9f173c6 100644 --- a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst +++ b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst @@ -24,7 +24,7 @@ The IP address that the |NODE| will use as the default gateway. Typically, this Optional. Default value is ``None`` -The IP address of the node which holds an instance of the DNS server. Some applications may use a domain name e.g. the WebBrowser (TODO: WebBrowser page) +The IP address of the node which holds an instance of the :ref:`DNSServer`. Some applications may use a domain name e.g. the :ref:`WebBrowser` .. include:: ../software/applications.rst diff --git a/docs/source/configuration/simulation/nodes/firewall.rst b/docs/source/configuration/simulation/nodes/firewall.rst index 3c1fce0a..47db4001 100644 --- a/docs/source/configuration/simulation/nodes/firewall.rst +++ b/docs/source/configuration/simulation/nodes/firewall.rst @@ -7,7 +7,7 @@ ``firewall`` ============ -A basic representation of a network router within the simulation. +A basic representation of a network firewall within the simulation. The firewall is similar to how :ref:`Router ` works, with the difference being how firewall has specific ACL rules for inbound and outbound traffic as well as firewall being limited to 3 ports. @@ -133,6 +133,10 @@ example: ... acl: internal_inbound_acl: + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port 22: # position 22 on ACL list action: PERMIT # allow packets that src_port: ARP # are emitted from the ARP port @@ -155,6 +159,10 @@ example: ... acl: internal_outbound_acl: + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port 22: # position 22 on ACL list action: PERMIT # allow packets that src_port: ARP # are emitted from the ARP port @@ -178,6 +186,18 @@ example: ... acl: dmz_inbound_acl: + 19: # position 19 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port + 20: # position 20 on ACL list + action: PERMIT # allow packets that + src_port: HTTP # are emitted from the HTTP port + dst_port: HTTP # are going towards an HTTP port + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: HTTPS # are emitted from the HTTPS port + dst_port: HTTPS # are going towards an HTTPS port 22: # position 22 on ACL list action: PERMIT # allow packets that src_port: ARP # are emitted from the ARP port @@ -200,6 +220,18 @@ example: ... acl: dmz_outbound_acl: + 19: # position 19 on ACL list + action: PERMIT # allow packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port + 20: # position 20 on ACL list + action: PERMIT # allow packets that + src_port: HTTP # are emitted from the HTTP port + dst_port: HTTP # are going towards an HTTP port + 21: # position 21 on ACL list + action: PERMIT # allow packets that + src_port: HTTPS # are emitted from the HTTPS port + dst_port: HTTPS # are going towards an HTTPS port 22: # position 22 on ACL list action: PERMIT # allow packets that src_port: ARP # are emitted from the ARP port @@ -226,6 +258,10 @@ example: ... acl: external_inbound_acl: + 21: # position 19 on ACL list + action: DENY # deny packets that + src_port: POSTGRES_SERVER # are emitted from the POSTGRES_SERVER port + dst_port: POSTGRES_SERVER # are going towards an POSTGRES_SERVER port 22: # position 22 on ACL list action: PERMIT # allow packets that src_port: ARP # are emitted from the ARP port diff --git a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst index d0e89f2e..d67e82d4 100644 --- a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -99,7 +99,7 @@ If not using the data manipulation bot manually, it needs to be used with a data type: UC2RedObservation options: nodes: - - node_ref: client_1 + - node_name: client_1 observations: - logon_status - operating_status @@ -116,7 +116,7 @@ If not using the data manipulation bot manually, it needs to be used with a data - type: NODE_APPLICATION_EXECUTE options: nodes: - - node_ref: client_1 + - node_name: client_1 applications: - application_ref: data_manipulation_bot max_folders_per_node: 1 diff --git a/docs/source/simulation_components/system/list_of_applications.rst b/docs/source/simulation_components/system/list_of_applications.rst index 0ba0c45c..8f792e4c 100644 --- a/docs/source/simulation_components/system/list_of_applications.rst +++ b/docs/source/simulation_components/system/list_of_applications.rst @@ -1,3 +1,7 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + .. toctree:: :maxdepth: 1 :glob: diff --git a/docs/source/simulation_components/system/list_of_services.rst b/docs/source/simulation_components/system/list_of_services.rst index e24b26dc..9f1c9fe2 100644 --- a/docs/source/simulation_components/system/list_of_services.rst +++ b/docs/source/simulation_components/system/list_of_services.rst @@ -1,3 +1,7 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + .. toctree:: :maxdepth: 1 :glob: diff --git a/docs/source/simulation_components/system/services/database_service.rst b/docs/source/simulation_components/system/services/database_service.rst index 30d6b3ba..2c962c0a 100644 --- a/docs/source/simulation_components/system/services/database_service.rst +++ b/docs/source/simulation_components/system/services/database_service.rst @@ -12,7 +12,7 @@ The ``DatabaseService`` provides a SQL database server simulation by extending t Key capabilities ================ -- Creates a database file in the ``Node`` 's ``FileSystem`` upon creation. +- Creates a database file in the ``FileSystem`` of the ``Node`` (which the ``DatabaseService`` is installed on) upon creation. - Handles connecting clients by maintaining a dictionary of connections mapped to session IDs. - Authenticates connections using a configurable password. - Simulates ``SELECT``, ``DELETE`` and ``INSERT`` SQL queries. diff --git a/docs/source/simulation_components/system/services/ftp_client.rst b/docs/source/simulation_components/system/services/ftp_client.rst index 82b85770..604ef8e8 100644 --- a/docs/source/simulation_components/system/services/ftp_client.rst +++ b/docs/source/simulation_components/system/services/ftp_client.rst @@ -20,6 +20,7 @@ Key features - RETR: retrieves a file from the FTP server - QUIT: disconnect from server - Leverages the Service base class for install/uninstall, status tracking, etc. +- :ref:`FTPClient` and ``FTPServer`` utilise port 21 (FTP) throughout all file transfer / request Usage ===== @@ -52,7 +53,7 @@ Python hostname="server", ip_address="192.168.2.2", subnet_mask="255.255.255.0", - default_gateway="192.168.1.1Ó", + default_gateway="192.168.1.10", start_up_duration=0, ) server.power_on() diff --git a/docs/source/simulation_components/system/services/ftp_server.rst b/docs/source/simulation_components/system/services/ftp_server.rst index d807a14f..fb57a762 100644 --- a/docs/source/simulation_components/system/services/ftp_server.rst +++ b/docs/source/simulation_components/system/services/ftp_server.rst @@ -17,12 +17,13 @@ Key capabilities - STOR: stores a file from client to server - RETR: retrieves a file from the FTP server - Leverages the Service base class for install/uninstall, status tracking, etc. +- :ref:`FTPClient` and ``FTPServer`` utilise port 21 (FTP) throughout all file transfer / request Usage ===== - Install on a Node via the ``SoftwareManager`` to start the FTP server service. -- Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command) +- Service runs on FTP (command) port 21 by default Implementation ============== diff --git a/src/primaite/game/agent/rewards.py b/src/primaite/game/agent/rewards.py index 27c39b65..ba6d1fa3 100644 --- a/src/primaite/game/agent/rewards.py +++ b/src/primaite/game/agent/rewards.py @@ -13,7 +13,7 @@ the structure: - type: DATABASE_FILE_INTEGRITY weight: 0.5 options: - node_ref: database_server + node_name: database_server folder_name: database file_name: database.db @@ -21,7 +21,7 @@ the structure: - type: WEB_SERVER_404_PENALTY weight: 0.5 options: - node_ref: web_server + node_name: web_server service_ref: web_server_database_client ``` """ @@ -184,7 +184,7 @@ class WebServer404Penalty(AbstractReward): service_name = config.get("service_name") if not (node_hostname and service_name): msg = ( - f"{cls.__name__} could not be initialised from config because node_ref and service_ref were not " + f"{cls.__name__} could not be initialised from config because node_name and service_ref were not " "found in reward config." ) _LOGGER.warning(msg) diff --git a/src/primaite/simulator/network/hardware/nodes/network/firewall.py b/src/primaite/simulator/network/hardware/nodes/network/firewall.py index 903ce3f3..ce98cec4 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/firewall.py +++ b/src/primaite/simulator/network/hardware/nodes/network/firewall.py @@ -497,66 +497,66 @@ class Firewall(Router): @classmethod def from_config(cls, cfg: dict) -> "Firewall": """Create a firewall based on a config dict.""" - new = Firewall(hostname=cfg["hostname"], operating_state=NodeOperatingState.ON) + firewall = Firewall(hostname=cfg["hostname"], operating_state=NodeOperatingState.ON) if "ports" in cfg: internal_port = cfg["ports"]["internal_port"] external_port = cfg["ports"]["external_port"] dmz_port = cfg["ports"]["dmz_port"] # configure internal port - new.configure_internal_port( + firewall.configure_internal_port( ip_address=IPV4Address(internal_port.get("ip_address")), subnet_mask=IPV4Address(internal_port.get("subnet_mask", "255.255.255.0")), ) # configure external port - new.configure_external_port( + firewall.configure_external_port( ip_address=IPV4Address(external_port.get("ip_address")), subnet_mask=IPV4Address(external_port.get("subnet_mask", "255.255.255.0")), ) # configure dmz port - new.configure_dmz_port( + firewall.configure_dmz_port( ip_address=IPV4Address(dmz_port.get("ip_address")), subnet_mask=IPV4Address(dmz_port.get("subnet_mask", "255.255.255.0")), ) if "acl" in cfg: # acl rules for internal_inbound_acl if cfg["acl"]["internal_inbound_acl"]: - new.internal_inbound_acl.max_acl_rules - new.internal_inbound_acl._default_config = cfg["acl"]["internal_inbound_acl"] - new.internal_inbound_acl._reset_rules_to_default() + firewall.internal_inbound_acl.max_acl_rules + firewall.internal_inbound_acl._default_config = cfg["acl"]["internal_inbound_acl"] + firewall.internal_inbound_acl._reset_rules_to_default() # acl rules for internal_outbound_acl if cfg["acl"]["internal_outbound_acl"]: - new.internal_outbound_acl._default_config = cfg["acl"]["internal_outbound_acl"] - new.internal_outbound_acl._reset_rules_to_default() + firewall.internal_outbound_acl._default_config = cfg["acl"]["internal_outbound_acl"] + firewall.internal_outbound_acl._reset_rules_to_default() # acl rules for dmz_inbound_acl if cfg["acl"]["dmz_inbound_acl"]: - new.dmz_inbound_acl._default_config = cfg["acl"]["dmz_inbound_acl"] - new.dmz_inbound_acl._reset_rules_to_default() + firewall.dmz_inbound_acl._default_config = cfg["acl"]["dmz_inbound_acl"] + firewall.dmz_inbound_acl._reset_rules_to_default() # acl rules for dmz_outbound_acl if cfg["acl"]["dmz_outbound_acl"]: - new.dmz_outbound_acl._default_config = cfg["acl"]["dmz_outbound_acl"] - new.dmz_outbound_acl._reset_rules_to_default() + firewall.dmz_outbound_acl._default_config = cfg["acl"]["dmz_outbound_acl"] + firewall.dmz_outbound_acl._reset_rules_to_default() # acl rules for external_inbound_acl if cfg["acl"]["external_inbound_acl"]: - new.external_inbound_acl._default_config = cfg["acl"]["external_inbound_acl"] - new.external_inbound_acl._reset_rules_to_default() + firewall.external_inbound_acl._default_config = cfg["acl"]["external_inbound_acl"] + firewall.external_inbound_acl._reset_rules_to_default() # acl rules for external_outbound_acl if cfg["acl"]["external_outbound_acl"]: - new.external_outbound_acl._default_config = cfg["acl"]["external_outbound_acl"] - new.external_outbound_acl._reset_rules_to_default() + firewall.external_outbound_acl._default_config = cfg["acl"]["external_outbound_acl"] + firewall.external_outbound_acl._reset_rules_to_default() if "routes" in cfg: for route in cfg.get("routes"): - new.route_table.add_route( + firewall.route_table.add_route( address=IPv4Address(route.get("address")), subnet_mask=IPv4Address(route.get("subnet_mask", "255.255.255.0")), next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")), metric=float(route.get("metric", 0)), ) - return new + return firewall diff --git a/src/primaite/simulator/network/hardware/nodes/network/router.py b/src/primaite/simulator/network/hardware/nodes/network/router.py index b3d7f7bf..a9e12401 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/router.py +++ b/src/primaite/simulator/network/hardware/nodes/network/router.py @@ -1480,27 +1480,27 @@ class Router(NetworkNode): :return: Configured router. :rtype: Router """ - new = Router( + router = Router( hostname=cfg["hostname"], num_ports=int(cfg.get("num_ports", "5")), operating_state=NodeOperatingState.ON, ) if "ports" in cfg: for port_num, port_cfg in cfg["ports"].items(): - new.configure_port( + router.configure_port( port=port_num, ip_address=port_cfg["ip_address"], subnet_mask=IPv4Address(port_cfg.get("subnet_mask", "255.255.255.0")), ) if "acl" in cfg: - new.acl._default_config = cfg["acl"] # save the config to allow resetting - new.acl._reset_rules_to_default() # read the config and apply rules + router.acl._default_config = cfg["acl"] # save the config to allow resetting + router.acl._reset_rules_to_default() # read the config and apply rules if "routes" in cfg: for route in cfg.get("routes"): - new.route_table.add_route( + router.route_table.add_route( address=IPv4Address(route.get("address")), subnet_mask=IPv4Address(route.get("subnet_mask", "255.255.255.0")), next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")), metric=float(route.get("metric", 0)), ) - return new + return router From 9a4587155b4c3eab5b50f272a1d214fe9e7ed878 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Thu, 29 Feb 2024 11:07:21 +0000 Subject: [PATCH 17/18] #2257: specifically stating that enpoint refs are node hostnames + remove TODO --- docs/source/configuration/simulation.rst | 4 ++-- .../simulation_components/system/services/ftp_client.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst index 89c1669b..e2fa5476 100644 --- a/docs/source/configuration/simulation.rst +++ b/docs/source/configuration/simulation.rst @@ -73,7 +73,7 @@ The human readable name for the link. Not used in code, however is useful for a ``endpoint_a_ref`` ^^^^^^^^^^^^^^^^^^ -The name of the node which must be connected. +The ``hostname`` of the node which must be connected. ``endpoint_a_port`` ^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ This accepts an integer value e.g. if port 1 is to be connected, the configurati ``endpoint_b_ref`` ^^^^^^^^^^^^^^^^^^ -The name of the node which must be connected. +The ``hostname`` of the node which must be connected. ``endpoint_b_port`` ^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/simulation_components/system/services/ftp_client.rst b/docs/source/simulation_components/system/services/ftp_client.rst index 604ef8e8..259a626d 100644 --- a/docs/source/simulation_components/system/services/ftp_client.rst +++ b/docs/source/simulation_components/system/services/ftp_client.rst @@ -26,7 +26,7 @@ Usage ===== - Install on a Node via the ``SoftwareManager`` to start the FTP client service. -- Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command) +- Service runs on FTP (command) port 21 by default - Execute sending a file to the FTP server with ``send_file`` - Execute retrieving a file from the FTP server with ``request_file`` From 49a4e1fb5655f83d2d13437927bff71148d30c57 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Thu, 29 Feb 2024 15:20:54 +0000 Subject: [PATCH 18/18] #2257: added common node attributes page + ability to set node operating state via config + tests --- .../simulation/nodes/common/common.rst | 35 ++++++++ .../common/common_host_node_attributes.rst | 9 +- .../common/common_network_node_attributes.rst | 2 + .../nodes/common/common_node_attributes.rst | 42 ++++++++++ .../network/base_hardware.rst | 22 ++--- .../applications/data_manipulation_bot.rst | 2 +- .../system/applications/database_client.rst | 6 -- .../system/list_of_system_applications.rst | 2 +- .../system/list_of_system_services.rst | 2 +- .../simulation_components/system/software.rst | 2 +- src/primaite/game/game.py | 16 +++- src/primaite/simulator/core.py | 4 +- .../network/hardware/nodes/host/host_node.py | 25 +++--- .../hardware/nodes/network/firewall.py | 83 +++++++++++++++---- .../network/hardware/nodes/network/router.py | 4 +- .../configs/basic_switched_network.yaml | 11 +++ .../nodes/test_node_config.py | 20 ++++- ...software_installation_and_configuration.py | 10 ++- 18 files changed, 227 insertions(+), 70 deletions(-) create mode 100644 docs/source/configuration/simulation/nodes/common/common.rst diff --git a/docs/source/configuration/simulation/nodes/common/common.rst b/docs/source/configuration/simulation/nodes/common/common.rst new file mode 100644 index 00000000..d1c8f307 --- /dev/null +++ b/docs/source/configuration/simulation/nodes/common/common.rst @@ -0,0 +1,35 @@ +.. only:: comment + + © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK + +.. _Node Attributes: + +Common Attributes +################# + +Node Attributes +=============== + +Attributes that are shared by all nodes. + +.. include:: common_node_attributes.rst + +.. _Network Node Attributes: + +Network Node Attributes +======================= + +Attributes that are shared by nodes that inherit from :py:mod:`primaite.simulator.network.hardware.nodes.network.network_node.NetworkNode` + +.. include:: common_host_node_attributes.rst + +.. _Host Node Attributes: + +Host Node Attributes +==================== + +Attributes that are shared by nodes that inherit from :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.HostNode` + +.. include:: common_host_node_attributes.rst + +.. |NODE| replace:: node diff --git a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst index b9f173c6..929d5714 100644 --- a/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst +++ b/docs/source/configuration/simulation/nodes/common/common_host_node_attributes.rst @@ -2,6 +2,8 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _common_host_node_attributes: + ``ip_address`` -------------- @@ -19,13 +21,6 @@ The subnet mask for the |NODE| to use. The IP address that the |NODE| will use as the default gateway. Typically, this is the IP address of the closest router that the |NODE| is connected to. -``dns_server`` --------------- - -Optional. Default value is ``None`` - -The IP address of the node which holds an instance of the :ref:`DNSServer`. Some applications may use a domain name e.g. the :ref:`WebBrowser` - .. include:: ../software/applications.rst .. include:: ../software/services.rst diff --git a/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst index d0b3e65b..1161059f 100644 --- a/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst +++ b/docs/source/configuration/simulation/nodes/common/common_network_node_attributes.rst @@ -2,6 +2,8 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _common_network_node_attributes: + ``routes`` ---------- diff --git a/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst b/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst index c1523518..34519adc 100644 --- a/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst +++ b/docs/source/configuration/simulation/nodes/common/common_node_attributes.rst @@ -2,6 +2,8 @@ © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK +.. _common_node_attributes: + ``ref`` ------- @@ -11,3 +13,43 @@ Human readable name used as reference for the |NODE|. Not used in code. ------------ The hostname of the |NODE|. This will be used to reference the |NODE|. + +``operating_state`` +------------------- + +The initial operating state of the node. + +Optional. Default value is ``ON``. + +Options available are: + +- ``ON`` +- ``OFF`` +- ``BOOTING`` +- ``SHUTTING_DOWN`` + +Note that YAML may assume non quoted ``ON`` and ``OFF`` as ``True`` and ``False`` respectively. To prevent this, use ``"ON"`` or ``"OFF"`` + +See :py:mod:`primaite.simulator.network.hardware.node_operating_state.NodeOperatingState` + + +``dns_server`` +-------------- + +Optional. Default value is ``None``. + +The IP address of the node which holds an instance of the :ref:`DNSServer`. Some applications may use a domain name e.g. the :ref:`WebBrowser` + +``start_up_duration`` +--------------------- + +Optional. Default value is ``3``. + +The number of time steps required to occur in order for the node to cycle from ``OFF`` to ``BOOTING_UP`` and then finally ``ON``. + +``shut_down_duration`` +---------------------- + +Optional. Default value is ``3``. + +The number of time steps required to occur in order for the node to cycle from ``ON`` to ``SHUTTING_DOWN`` and then finally ``OFF``. diff --git a/docs/source/simulation_components/network/base_hardware.rst b/docs/source/simulation_components/network/base_hardware.rst index 3aa6b073..1b83f3f4 100644 --- a/docs/source/simulation_components/network/base_hardware.rst +++ b/docs/source/simulation_components/network/base_hardware.rst @@ -12,34 +12,22 @@ complex, specialized hardware components inherit from and build upon. The key elements defined in ``base.py`` are: -NetworkInterface -================ +``NetworkInterface`` +==================== - Abstract base class for network interfaces like NICs. Defines common attributes like MAC address, speed, MTU. - Requires subclasses to implement ``enable()``, ``disable()``, ``send_frame()`` and ``receive_frame()``. - Provides basic state description and request handling capabilities. -Node -==== +``Node`` +======== The Node class stands as a central component in ``base.py``, acting as the superclass for all network nodes within a PrimAITE simulation. - - Node Attributes --------------- - -- **hostname**: The network hostname of the node. -- **operating_state**: Indicates the current hardware state of the node. -- **network_interfaces**: Maps interface names to NetworkInterface objects on the node. -- **network_interface**: Maps port IDs to ``NetworkInterface`` objects on the node. -- **dns_server**: Specifies DNS servers for domain name resolution. -- **start_up_duration**: The time it takes for the node to become fully operational after being powered on. -- **shut_down_duration**: The time required for the node to properly shut down. -- **sys_log**: A system log for recording events related to the node. -- **session_manager**: Manages user sessions within the node. -- **software_manager**: Controls the installation and management of software and services on the node. +See :ref:`Node Attributes` .. _Node Start up and Shut down: diff --git a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst index d67e82d4..304621dd 100644 --- a/docs/source/simulation_components/system/applications/data_manipulation_bot.rst +++ b/docs/source/simulation_components/system/applications/data_manipulation_bot.rst @@ -79,7 +79,7 @@ Python data_manipulation_bot.configure(server_ip_address=IPv4Address("192.168.1.14"), payload="DELETE") data_manipulation_bot.run() -This would connect to the database service at 192.168.1.14, authenticate, and execute the SQL statement to drop the 'users' table. +This would connect to the database service at 192.168.1.14, authenticate, and execute the SQL statement to delete database contents. Example with ``DataManipulationAgent`` """""""""""""""""""""""""""""""""""""" diff --git a/docs/source/simulation_components/system/applications/database_client.rst b/docs/source/simulation_components/system/applications/database_client.rst index 61d955f2..ddf6db11 100644 --- a/docs/source/simulation_components/system/applications/database_client.rst +++ b/docs/source/simulation_components/system/applications/database_client.rst @@ -24,12 +24,6 @@ Usage - Retrieve results in a dictionary. - Disconnect when finished. -To create database backups: - -- Configure the backup server on the :ref:`DatabaseService` by providing the Backup server ``IPv4Address`` with ``configure_backup`` -- Create a backup using ``backup_database``. This fails if the backup server is not configured. -- Restore a backup using ``restore_backup``. By default, this uses the database created via ``backup_database``. - Implementation ============== diff --git a/docs/source/simulation_components/system/list_of_system_applications.rst b/docs/source/simulation_components/system/list_of_system_applications.rst index fae0f5d4..193b3dc6 100644 --- a/docs/source/simulation_components/system/list_of_system_applications.rst +++ b/docs/source/simulation_components/system/list_of_system_applications.rst @@ -13,4 +13,4 @@ The list of applications that are considered system software are: - ``WebBrowser`` -More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` +More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.HostNode.SYSTEM_SOFTWARE` diff --git a/docs/source/simulation_components/system/list_of_system_services.rst b/docs/source/simulation_components/system/list_of_system_services.rst index 4ff6f245..5acfc12e 100644 --- a/docs/source/simulation_components/system/list_of_system_services.rst +++ b/docs/source/simulation_components/system/list_of_system_services.rst @@ -15,4 +15,4 @@ The list of services that are considered system software are: - ``FTPClient`` - ``NTPClient`` -More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE` +More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.HostNode.SYSTEM_SOFTWARE` diff --git a/docs/source/simulation_components/system/software.rst b/docs/source/simulation_components/system/software.rst index 459064f0..2ba8e841 100644 --- a/docs/source/simulation_components/system/software.rst +++ b/docs/source/simulation_components/system/software.rst @@ -10,7 +10,7 @@ Software Base Software ------------- -All software which inherits ``IOSoftware`` installed on a node will not work unless the node has been turned on. +Software which inherits ``IOSoftware`` installed on a node will not work unless the node has been turned on. See :ref:`Node Start up and Shut down` diff --git a/src/primaite/game/game.py b/src/primaite/game/game.py index 8d272418..42d998c7 100644 --- a/src/primaite/game/game.py +++ b/src/primaite/game/game.py @@ -234,7 +234,9 @@ class PrimaiteGame: subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")), default_gateway=node_cfg["default_gateway"], dns_server=node_cfg.get("dns_server", None), - operating_state=NodeOperatingState.ON, + operating_state=NodeOperatingState.ON + if not (p := node_cfg.get("operating_state")) + else NodeOperatingState[p.upper()], ) elif n_type == "server": new_node = Server( @@ -243,13 +245,17 @@ class PrimaiteGame: subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")), default_gateway=node_cfg["default_gateway"], dns_server=node_cfg.get("dns_server", None), - operating_state=NodeOperatingState.ON, + operating_state=NodeOperatingState.ON + if not (p := node_cfg.get("operating_state")) + else NodeOperatingState[p.upper()], ) elif n_type == "switch": new_node = Switch( hostname=node_cfg["hostname"], num_ports=int(node_cfg.get("num_ports", "8")), - operating_state=NodeOperatingState.ON, + operating_state=NodeOperatingState.ON + if not (p := node_cfg.get("operating_state")) + else NodeOperatingState[p.upper()], ) elif n_type == "router": new_node = Router.from_config(node_cfg) @@ -359,7 +365,9 @@ class PrimaiteGame: new_node.shut_down_duration = 0 net.add_node(new_node) - new_node.power_on() + # run through the power on step if the node is to be turned on at the start + if new_node.operating_state == NodeOperatingState.ON: + new_node.power_on() game.ref_map_nodes[node_ref] = new_node.uuid # set start up and shut down duration diff --git a/src/primaite/simulator/core.py b/src/primaite/simulator/core.py index 99e9be7f..6ab7c6e3 100644 --- a/src/primaite/simulator/core.py +++ b/src/primaite/simulator/core.py @@ -1,7 +1,7 @@ # flake8: noqa """Core of the PrimAITE Simulator.""" -from abc import ABC, abstractmethod -from typing import Callable, ClassVar, Dict, List, Optional, Union +from abc import abstractmethod +from typing import Callable, Dict, List, Optional, Union from uuid import uuid4 from pydantic import BaseModel, ConfigDict, Field diff --git a/src/primaite/simulator/network/hardware/nodes/host/host_node.py b/src/primaite/simulator/network/hardware/nodes/host/host_node.py index cb3c1bd7..703c2538 100644 --- a/src/primaite/simulator/network/hardware/nodes/host/host_node.py +++ b/src/primaite/simulator/network/hardware/nodes/host/host_node.py @@ -1,7 +1,7 @@ from __future__ import annotations from ipaddress import IPv4Address -from typing import Any, Dict, Optional +from typing import Any, ClassVar, Dict, Optional from primaite import getLogger from primaite.simulator.network.hardware.base import IPWiredNetworkInterface, Link, Node @@ -253,17 +253,6 @@ class NIC(IPWiredNetworkInterface): return f"Port {self.port_num}: {self.mac_address}/{self.ip_address}" -SYSTEM_SOFTWARE = { - "HostARP": HostARP, - "ICMP": ICMP, - "DNSClient": DNSClient, - "FTPClient": FTPClient, - "NTPClient": NTPClient, - "WebBrowser": WebBrowser, -} -"""List of system software that is automatically installed on nodes.""" - - class HostNode(Node): """ Represents a host node in the network. @@ -308,6 +297,16 @@ class HostNode(Node): * Web Browser: Provides web browsing capabilities. """ + SYSTEM_SOFTWARE: ClassVar[Dict] = { + "HostARP": HostARP, + "ICMP": ICMP, + "DNSClient": DNSClient, + "FTPClient": FTPClient, + "NTPClient": NTPClient, + "WebBrowser": WebBrowser, + } + """List of system software that is automatically installed on nodes.""" + network_interfaces: Dict[str, NIC] = {} "The Network Interfaces on the node." network_interface: Dict[int, NIC] = {} @@ -324,7 +323,7 @@ class HostNode(Node): This method equips the host with essential network services and applications, preparing it for various network-related tasks and operations. """ - for _, software_class in SYSTEM_SOFTWARE.items(): + for _, software_class in self.SYSTEM_SOFTWARE.items(): self.software_manager.install(software_class) super()._install_system_software() diff --git a/src/primaite/simulator/network/hardware/nodes/network/firewall.py b/src/primaite/simulator/network/hardware/nodes/network/firewall.py index b4d5cdba..26c50ff0 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/firewall.py +++ b/src/primaite/simulator/network/hardware/nodes/network/firewall.py @@ -12,6 +12,8 @@ from primaite.simulator.network.hardware.nodes.network.router import ( RouterInterface, ) from primaite.simulator.network.transmission.data_link_layer import Frame +from primaite.simulator.network.transmission.network_layer import IPProtocol +from primaite.simulator.network.transmission.transport_layer import Port from primaite.simulator.system.core.sys_log import SysLog from primaite.utils.validators import IPV4Address @@ -479,7 +481,12 @@ class Firewall(Router): @classmethod def from_config(cls, cfg: dict) -> "Firewall": """Create a firewall based on a config dict.""" - firewall = Firewall(hostname=cfg["hostname"], operating_state=NodeOperatingState.ON) + firewall = Firewall( + hostname=cfg["hostname"], + operating_state=NodeOperatingState.ON + if not (p := cfg.get("operating_state")) + else NodeOperatingState[p.upper()], + ) if "ports" in cfg: internal_port = cfg["ports"]["internal_port"] external_port = cfg["ports"]["external_port"] @@ -505,34 +512,82 @@ class Firewall(Router): if "acl" in cfg: # acl rules for internal_inbound_acl if cfg["acl"]["internal_inbound_acl"]: - firewall.internal_inbound_acl.max_acl_rules - firewall.internal_inbound_acl._default_config = cfg["acl"]["internal_inbound_acl"] - firewall.internal_inbound_acl._reset_rules_to_default() + for r_num, r_cfg in cfg["acl"]["internal_inbound_acl"].items(): + firewall.internal_inbound_acl.add_rule( + action=ACLAction[r_cfg["action"]], + src_port=None if not (p := r_cfg.get("src_port")) else Port[p], + dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p], + protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p], + src_ip_address=r_cfg.get("src_ip"), + dst_ip_address=r_cfg.get("dst_ip"), + position=r_num, + ) # acl rules for internal_outbound_acl if cfg["acl"]["internal_outbound_acl"]: - firewall.internal_outbound_acl._default_config = cfg["acl"]["internal_outbound_acl"] - firewall.internal_outbound_acl._reset_rules_to_default() + for r_num, r_cfg in cfg["acl"]["internal_outbound_acl"].items(): + firewall.internal_outbound_acl.add_rule( + action=ACLAction[r_cfg["action"]], + src_port=None if not (p := r_cfg.get("src_port")) else Port[p], + dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p], + protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p], + src_ip_address=r_cfg.get("src_ip"), + dst_ip_address=r_cfg.get("dst_ip"), + position=r_num, + ) # acl rules for dmz_inbound_acl if cfg["acl"]["dmz_inbound_acl"]: - firewall.dmz_inbound_acl._default_config = cfg["acl"]["dmz_inbound_acl"] - firewall.dmz_inbound_acl._reset_rules_to_default() + for r_num, r_cfg in cfg["acl"]["dmz_inbound_acl"].items(): + firewall.dmz_inbound_acl.add_rule( + action=ACLAction[r_cfg["action"]], + src_port=None if not (p := r_cfg.get("src_port")) else Port[p], + dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p], + protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p], + src_ip_address=r_cfg.get("src_ip"), + dst_ip_address=r_cfg.get("dst_ip"), + position=r_num, + ) # acl rules for dmz_outbound_acl if cfg["acl"]["dmz_outbound_acl"]: - firewall.dmz_outbound_acl._default_config = cfg["acl"]["dmz_outbound_acl"] - firewall.dmz_outbound_acl._reset_rules_to_default() + for r_num, r_cfg in cfg["acl"]["dmz_outbound_acl"].items(): + firewall.dmz_outbound_acl.add_rule( + action=ACLAction[r_cfg["action"]], + src_port=None if not (p := r_cfg.get("src_port")) else Port[p], + dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p], + protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p], + src_ip_address=r_cfg.get("src_ip"), + dst_ip_address=r_cfg.get("dst_ip"), + position=r_num, + ) # acl rules for external_inbound_acl if cfg["acl"]["external_inbound_acl"]: - firewall.external_inbound_acl._default_config = cfg["acl"]["external_inbound_acl"] - firewall.external_inbound_acl._reset_rules_to_default() + for r_num, r_cfg in cfg["acl"]["external_inbound_acl"].items(): + firewall.external_inbound_acl.add_rule( + action=ACLAction[r_cfg["action"]], + src_port=None if not (p := r_cfg.get("src_port")) else Port[p], + dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p], + protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p], + src_ip_address=r_cfg.get("src_ip"), + dst_ip_address=r_cfg.get("dst_ip"), + position=r_num, + ) # acl rules for external_outbound_acl if cfg["acl"]["external_outbound_acl"]: - firewall.external_outbound_acl._default_config = cfg["acl"]["external_outbound_acl"] - firewall.external_outbound_acl._reset_rules_to_default() + for r_num, r_cfg in cfg["acl"]["external_outbound_acl"].items(): + firewall.external_outbound_acl.add_rule( + action=ACLAction[r_cfg["action"]], + src_port=None if not (p := r_cfg.get("src_port")) else Port[p], + dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p], + protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p], + src_ip_address=r_cfg.get("src_ip"), + dst_ip_address=r_cfg.get("dst_ip"), + position=r_num, + ) + if "routes" in cfg: for route in cfg.get("routes"): firewall.route_table.add_route( diff --git a/src/primaite/simulator/network/hardware/nodes/network/router.py b/src/primaite/simulator/network/hardware/nodes/network/router.py index 5b45f59c..d5302345 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/router.py +++ b/src/primaite/simulator/network/hardware/nodes/network/router.py @@ -1401,7 +1401,9 @@ class Router(NetworkNode): router = Router( hostname=cfg["hostname"], num_ports=int(cfg.get("num_ports", "5")), - operating_state=NodeOperatingState.ON, + operating_state=NodeOperatingState.ON + if not (p := cfg.get("operating_state")) + else NodeOperatingState[p.upper()], ) if "ports" in cfg: for port_num, port_cfg in cfg["ports"].items(): diff --git a/tests/assets/configs/basic_switched_network.yaml b/tests/assets/configs/basic_switched_network.yaml index a248065c..daa40aa7 100644 --- a/tests/assets/configs/basic_switched_network.yaml +++ b/tests/assets/configs/basic_switched_network.yaml @@ -141,6 +141,17 @@ simulation: default_gateway: 192.168.10.1 dns_server: 192.168.1.10 # pre installed services and applications + - ref: client_3 + type: computer + hostname: client_3 + ip_address: 192.168.10.23 + subnet_mask: 255.255.255.0 + default_gateway: 192.168.10.1 + dns_server: 192.168.1.10 + start_up_duration: 0 + shut_down_duration: 0 + operating_state: "OFF" + # pre installed services and applications links: - ref: switch_1___client_1 diff --git a/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py b/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py index e222bfaf..f23e7612 100644 --- a/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py +++ b/tests/integration_tests/configuration_file_parsing/nodes/test_node_config.py @@ -1,6 +1,8 @@ from primaite.config.load import example_config_path from primaite.simulator.network.container import Network -from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config +from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState +from primaite.simulator.network.hardware.nodes.host.computer import Computer +from tests.integration_tests.configuration_file_parsing import BASIC_CONFIG, DMZ_NETWORK, load_config def test_example_config(): @@ -24,3 +26,19 @@ def test_dmz_config(): assert len(network.routers) == 2 # 2 routers in network assert len(network.switches) == 3 # 3 switches in network assert len(network.servers) == 2 # 2 servers in network + + +def test_basic_config(): + """Test that the basic_switched_network config can be parsed properly.""" + game = load_config(BASIC_CONFIG) + network: Network = game.simulation.network + assert len(network.nodes) == 4 # 4 nodes in network + + client_1: Computer = network.get_node_by_hostname("client_1") + assert client_1.operating_state == NodeOperatingState.ON + client_2: Computer = network.get_node_by_hostname("client_2") + assert client_2.operating_state == NodeOperatingState.ON + + # client 3 should not be online + client_3: Computer = network.get_node_by_hostname("client_3") + assert client_3.operating_state == NodeOperatingState.OFF diff --git a/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py b/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py index 306f591d..f3dc51bd 100644 --- a/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py +++ b/tests/integration_tests/configuration_file_parsing/software_installation_and_configuration.py @@ -1,6 +1,14 @@ from ipaddress import IPv4Address +from pathlib import Path +from typing import Union -from primaite.game.game import APPLICATION_TYPES_MAPPING, SERVICE_TYPES_MAPPING +import yaml + +from primaite.config.load import example_config_path +from primaite.game.agent.data_manipulation_bot import DataManipulationAgent +from primaite.game.agent.interface import ProxyAgent, RandomAgent +from primaite.game.game import APPLICATION_TYPES_MAPPING, PrimaiteGame, SERVICE_TYPES_MAPPING +from primaite.simulator.network.container import Network from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.system.applications.database_client import DatabaseClient from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot