From 3651d033d6f2ba5d527de70c00f796c2ff96bfeb Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Mon, 17 Feb 2025 17:34:22 +0000 Subject: [PATCH 1/3] fix instantiation of network nodes --- src/primaite/simulator/network/hardware/base.py | 4 +--- .../simulator/network/hardware/nodes/host/host_node.py | 4 ++-- .../simulator/network/hardware/nodes/network/router.py | 1 - .../simulator/network/hardware/nodes/network/switch.py | 5 ++--- src/primaite/simulator/system/services/arp/arp.py | 4 ++-- src/primaite/simulator/system/software.py | 2 +- 6 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/primaite/simulator/network/hardware/base.py b/src/primaite/simulator/network/hardware/base.py index 8653359a..b20fb351 100644 --- a/src/primaite/simulator/network/hardware/base.py +++ b/src/primaite/simulator/network/hardware/base.py @@ -639,10 +639,8 @@ class IPWiredNetworkInterface(WiredNetworkInterface, Layer3Interface, ABC): `default_gateway_hello` method is not defined, ignoring such errors to proceed without interruption. """ super().enable() - try: + if hasattr(self._connected_node, "default_gateway_hello"): self._connected_node.default_gateway_hello() - except AttributeError: - pass return True @abstractmethod 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 76d9167c..2c1910c4 100644 --- a/src/primaite/simulator/network/hardware/nodes/host/host_node.py +++ b/src/primaite/simulator/network/hardware/nodes/host/host_node.py @@ -333,7 +333,7 @@ class HostNode(Node, discriminator="host-node"): class ConfigSchema(Node.ConfigSchema): """Configuration Schema for HostNode class.""" - type: Literal["host-node"] + type: Literal["host-node"] = "host-node" hostname: str = "HostNode" subnet_mask: IPV4Address = "255.255.255.0" ip_address: IPV4Address @@ -375,7 +375,7 @@ class HostNode(Node, discriminator="host-node"): This method is invoked to ensure the host node can communicate with its default gateway, primarily to confirm network connectivity and populate the ARP cache with the gateway's MAC address. """ - if self.operating_state == NodeOperatingState.ON and self.default_gateway: + if self.operating_state == NodeOperatingState.ON and self.config.default_gateway: self.software_manager.arp.get_default_gateway_mac_address() def receive_frame(self, frame: Frame, from_network_interface: NIC): diff --git a/src/primaite/simulator/network/hardware/nodes/network/router.py b/src/primaite/simulator/network/hardware/nodes/network/router.py index 3b35600b..f2a4652c 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/router.py +++ b/src/primaite/simulator/network/hardware/nodes/network/router.py @@ -1351,7 +1351,6 @@ class Router(NetworkNode, discriminator="router"): :return: A dictionary representing the current state. """ state = super().describe_state() - state["num_ports"] = self.config.num_ports state["acl"] = self.acl.describe_state() return state diff --git a/src/primaite/simulator/network/hardware/nodes/network/switch.py b/src/primaite/simulator/network/hardware/nodes/network/switch.py index 1f2bc135..6e5814d0 100644 --- a/src/primaite/simulator/network/hardware/nodes/network/switch.py +++ b/src/primaite/simulator/network/hardware/nodes/network/switch.py @@ -103,8 +103,8 @@ class Switch(NetworkNode, discriminator="switch"): type: Literal["switch"] = "switch" hostname: str = "Switch" - num_ports: int = 24 - "The number of ports on the switch. Default is 24." + num_ports: int = 8 + "The number of ports on the switch." config: ConfigSchema = Field(default_factory=lambda: Switch.ConfigSchema()) @@ -139,7 +139,6 @@ class Switch(NetworkNode, discriminator="switch"): """ state = super().describe_state() state["ports"] = {port_num: port.describe_state() for port_num, port in self.network_interface.items()} - state["num_ports"] = self.config.num_ports # redundant? state["mac_address_table"] = {mac: port.port_num for mac, port in self.mac_address_table.items()} return state diff --git a/src/primaite/simulator/system/services/arp/arp.py b/src/primaite/simulator/system/services/arp/arp.py index b0630d5d..348cc03e 100644 --- a/src/primaite/simulator/system/services/arp/arp.py +++ b/src/primaite/simulator/system/services/arp/arp.py @@ -137,8 +137,8 @@ class ARP(Service, discriminator="arp"): break if use_default_gateway: - if self.software_manager.node.default_gateway: - target_ip_address = self.software_manager.node.default_gateway + if self.software_manager.node.config.default_gateway: + target_ip_address = self.software_manager.node.config.default_gateway else: return diff --git a/src/primaite/simulator/system/software.py b/src/primaite/simulator/system/software.py index 950f77c6..86b57818 100644 --- a/src/primaite/simulator/system/software.py +++ b/src/primaite/simulator/system/software.py @@ -82,7 +82,7 @@ class Software(SimComponent, ABC): """Configurable options for all software.""" model_config = ConfigDict(extra="forbid") - starting_health_state: SoftwareHealthState = SoftwareHealthState.UNUSED + starting_health_state: SoftwareHealthState = SoftwareHealthState.GOOD criticality: SoftwareCriticality = SoftwareCriticality.LOWEST fixing_duration: int = 2 From de88974332076c0f1841b0178674f4b73543701f Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Mon, 17 Feb 2025 18:14:07 +0000 Subject: [PATCH 2/3] Fix airspace hello --- src/primaite/simulator/network/airspace.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/primaite/simulator/network/airspace.py b/src/primaite/simulator/network/airspace.py index 7ede0bb0..434940f8 100644 --- a/src/primaite/simulator/network/airspace.py +++ b/src/primaite/simulator/network/airspace.py @@ -449,10 +449,8 @@ class IPWirelessNetworkInterface(WirelessNetworkInterface, Layer3Interface, ABC) `default_gateway_hello` method is not defined, ignoring such errors to proceed without interruption. """ super().enable() - try: + if hasattr(self._connected_node, "default_gateway_hello"): self._connected_node.default_gateway_hello() - except AttributeError: - pass @abstractmethod def receive_frame(self, frame: Frame) -> bool: From 46240e49a41510b4f2b708b6d489a6a97e27d40f Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Mon, 17 Feb 2025 18:46:09 +0000 Subject: [PATCH 3/3] update tests and make office lan creation work like previously --- src/primaite/simulator/network/creation.py | 15 +++++++++++++-- .../_network/_hardware/nodes/test_switch.py | 1 - .../_system/_applications/test_applications.py | 6 +++--- .../_simulator/_system/_services/test_services.py | 12 ++++++------ .../_primaite/_simulator/_system/test_software.py | 4 ++-- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/primaite/simulator/network/creation.py b/src/primaite/simulator/network/creation.py index 255b7bf5..089ed00d 100644 --- a/src/primaite/simulator/network/creation.py +++ b/src/primaite/simulator/network/creation.py @@ -155,7 +155,12 @@ class OfficeLANAdder(NetworkNodeAdder, discriminator="office-lan"): # Create a core switch if more than one edge switch is needed if num_of_switches > 1: core_switch = Switch.from_config( - config={"type": "switch", "hostname": f"switch_core_{config.lan_name}", "start_up_duration": 0} + config={ + "type": "switch", + "hostname": f"switch_core_{config.lan_name}", + "start_up_duration": 0, + "num_ports": 24, + } ) core_switch.power_on() network.add_node(core_switch) @@ -183,7 +188,12 @@ class OfficeLANAdder(NetworkNodeAdder, discriminator="office-lan"): switch_port = 0 switch_n = 1 switch = Switch.from_config( - config={"type": "switch", "hostname": f"switch_edge_{switch_n}_{config.lan_name}", "start_up_duration": 0} + config={ + "type": "switch", + "hostname": f"switch_edge_{switch_n}_{config.lan_name}", + "start_up_duration": 0, + "num_ports": 24, + } ) switch.power_on() network.add_node(switch) @@ -207,6 +217,7 @@ class OfficeLANAdder(NetworkNodeAdder, discriminator="office-lan"): "type": "switch", "hostname": f"switch_edge_{switch_n}_{config.lan_name}", "start_up_duration": 0, + "num_ports": 24, } ) switch.power_on() diff --git a/tests/unit_tests/_primaite/_simulator/_network/_hardware/nodes/test_switch.py b/tests/unit_tests/_primaite/_simulator/_network/_hardware/nodes/test_switch.py index e45fe45d..94b1764d 100644 --- a/tests/unit_tests/_primaite/_simulator/_network/_hardware/nodes/test_switch.py +++ b/tests/unit_tests/_primaite/_simulator/_network/_hardware/nodes/test_switch.py @@ -17,4 +17,3 @@ def switch() -> Switch: def test_describe_state(switch): state = switch.describe_state() assert len(state.get("ports")) is 8 - assert state.get("num_ports") is 8 diff --git a/tests/unit_tests/_primaite/_simulator/_system/_applications/test_applications.py b/tests/unit_tests/_primaite/_simulator/_system/_applications/test_applications.py index dd29f18e..6cccad91 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/_applications/test_applications.py +++ b/tests/unit_tests/_primaite/_simulator/_system/_applications/test_applications.py @@ -18,7 +18,7 @@ def test_scan(application): def test_run_application(application): assert application.operating_state == ApplicationOperatingState.CLOSED - assert application.health_state_actual == SoftwareHealthState.UNUSED + assert application.health_state_actual == SoftwareHealthState.GOOD application.run() assert application.operating_state == ApplicationOperatingState.RUNNING @@ -37,9 +37,9 @@ def test_close_application(application): def test_application_describe_states(application): assert application.operating_state == ApplicationOperatingState.CLOSED - assert application.health_state_actual == SoftwareHealthState.UNUSED + assert application.health_state_actual == SoftwareHealthState.GOOD - assert SoftwareHealthState.UNUSED.value == application.describe_state().get("health_state_actual") + assert SoftwareHealthState.GOOD.value == application.describe_state().get("health_state_actual") application.run() assert SoftwareHealthState.GOOD.value == application.describe_state().get("health_state_actual") diff --git a/tests/unit_tests/_primaite/_simulator/_system/_services/test_services.py b/tests/unit_tests/_primaite/_simulator/_system/_services/test_services.py index 5598e1a7..fe78aa65 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/_services/test_services.py +++ b/tests/unit_tests/_primaite/_simulator/_system/_services/test_services.py @@ -22,7 +22,7 @@ def test_scan(service): def test_start_service(service): assert service.operating_state == ServiceOperatingState.STOPPED - assert service.health_state_actual == SoftwareHealthState.UNUSED + assert service.health_state_actual == SoftwareHealthState.GOOD service.start() assert service.operating_state == ServiceOperatingState.RUNNING @@ -43,7 +43,7 @@ def test_pause_and_resume_service(service): assert service.operating_state == ServiceOperatingState.STOPPED service.resume() assert service.operating_state == ServiceOperatingState.STOPPED - assert service.health_state_actual == SoftwareHealthState.UNUSED + assert service.health_state_actual == SoftwareHealthState.GOOD service.start() assert service.health_state_actual == SoftwareHealthState.GOOD @@ -58,11 +58,11 @@ def test_pause_and_resume_service(service): def test_restart(service): assert service.operating_state == ServiceOperatingState.STOPPED - assert service.health_state_actual == SoftwareHealthState.UNUSED + assert service.health_state_actual == SoftwareHealthState.GOOD service.restart() # Service is STOPPED. Restart will only work if the service was PAUSED or RUNNING assert service.operating_state == ServiceOperatingState.STOPPED - assert service.health_state_actual == SoftwareHealthState.UNUSED + assert service.health_state_actual == SoftwareHealthState.GOOD service.start() assert service.operating_state == ServiceOperatingState.RUNNING @@ -157,11 +157,11 @@ def test_service_fixing(service): def test_enable_disable(service): service.disable() assert service.operating_state == ServiceOperatingState.DISABLED - assert service.health_state_actual == SoftwareHealthState.UNUSED + assert service.health_state_actual == SoftwareHealthState.GOOD service.enable() assert service.operating_state == ServiceOperatingState.STOPPED - assert service.health_state_actual == SoftwareHealthState.UNUSED + assert service.health_state_actual == SoftwareHealthState.GOOD def test_overwhelm_service(service): diff --git a/tests/unit_tests/_primaite/_simulator/_system/test_software.py b/tests/unit_tests/_primaite/_simulator/_system/test_software.py index 8c39c41d..9ad0dbcb 100644 --- a/tests/unit_tests/_primaite/_simulator/_system/test_software.py +++ b/tests/unit_tests/_primaite/_simulator/_system/test_software.py @@ -39,6 +39,6 @@ def test_software_creation(software): def test_software_set_health_state(software): - assert software.health_state_actual == SoftwareHealthState.UNUSED - software.set_health_state(SoftwareHealthState.GOOD) assert software.health_state_actual == SoftwareHealthState.GOOD + software.set_health_state(SoftwareHealthState.COMPROMISED) + assert software.health_state_actual == SoftwareHealthState.COMPROMISED