diff --git a/src/primaite/game/agent/observations.py b/src/primaite/game/agent/observations.py index 82e11fe0..83d1c4be 100644 --- a/src/primaite/game/agent/observations.py +++ b/src/primaite/game/agent/observations.py @@ -367,6 +367,13 @@ class NicObservation(AbstractObservation): """ super().__init__() self.where: Optional[Tuple[str]] = where + if CAPTURE_NMNE: + self.nmne_inbound_last_step: int = 0 + """NMNEs persist for the whole episode, but we want to count per step. Keeping track of last step count lets + us find the difference.""" + self.nmne_outbound_last_step: int = 0 + """NMNEs persist for the whole episode, but we want to count per step. Keeping track of last step count lets + us find the difference.""" def _categorise_mne_count(self, nmne_count: int) -> int: """ @@ -414,8 +421,10 @@ class NicObservation(AbstractObservation): inbound_count = inbound_keywords.get("*", 0) outbound_keywords = direction_dict.get("outbound", {}).get("keywords", {}) outbound_count = outbound_keywords.get("*", 0) - obs_dict["nmne"]["inbound"] = self._categorise_mne_count(inbound_count) - obs_dict["nmne"]["outbound"] = self._categorise_mne_count(outbound_count) + obs_dict["nmne"]["inbound"] = self._categorise_mne_count(inbound_count - self.nmne_inbound_last_step) + obs_dict["nmne"]["outbound"] = self._categorise_mne_count(outbound_count - self.nmne_outbound_last_step) + self.nmne_inbound_last_step = inbound_count + self.nmne_outbound_last_step = outbound_count return obs_dict @property diff --git a/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb b/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb index e35e6126..1d7cb157 100644 --- a/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb +++ b/src/primaite/notebooks/Data-Manipulation-E2E-Demonstration.ipynb @@ -426,13 +426,13 @@ "def friendly_output_red_action(info):\n", " # parse the info dict form step output and write out what the red agent is doing\n", " red_info = info['agent_actions']['data_manipulation_attacker']\n", - " red_action = red_info[0]\n", + " red_action = red_info['action']\n", " if red_action == 'DONOTHING':\n", " red_str = 'DO NOTHING'\n", " elif red_action == 'NODE_APPLICATION_EXECUTE':\n", - " client = \"client 1\" if red_info[1]['node_id'] == 0 else \"client 2\"\n", + " client = \"client 1\" if red_info['parameters']['node_id'] == 0 else \"client 2\"\n", " red_str = f\"ATTACK from {client}\"\n", - " return red_str" + " return red_str\n" ] }, { @@ -492,7 +492,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Also, the NMNE outbound of either client 1 (node 6) or client 2 (node 7) has increased from 0 to 1. This tells us which client is being used by the red agent." + "Also, the NMNE outbound of either client 1 (node 6) or client 2 (node 7) increased from 0 to 1, but only right after the red attack, so we probably cannot see it now." ] }, { @@ -510,9 +510,9 @@ "source": [ "obs, reward, terminated, truncated, info = env.step(13) # patch the database\n", "print(f\"step: {env.game.step_counter}\")\n", - "print(f\"Red action: {info['agent_actions']['data_manipulation_attacker'][0]}\" )\n", - "print(f\"Green action: {info['agent_actions']['client_1_green_user'][0]}\" )\n", - "print(f\"Green action: {info['agent_actions']['client_2_green_user'][0]}\" )\n", + "print(f\"Red action: {info['agent_actions']['data_manipulation_attacker']['action']}\" )\n", + "print(f\"Green action: {info['agent_actions']['client_1_green_user']['action']}\" )\n", + "print(f\"Green action: {info['agent_actions']['client_2_green_user']['action']}\" )\n", "print(f\"Blue reward:{reward}\" )" ] }, @@ -535,7 +535,7 @@ "source": [ "obs, reward, terminated, truncated, info = env.step(0) # patch the database\n", "print(f\"step: {env.game.step_counter}\")\n", - "print(f\"Red action: {info['agent_actions']['data_manipulation_attacker'][0]}\" )\n", + "print(f\"Red action: {info['agent_actions']['data_manipulation_attacker']['action']}\" )\n", "print(f\"Green action: {info['agent_actions']['client_2_green_user']}\" )\n", "print(f\"Green action: {info['agent_actions']['client_1_green_user']}\" )\n", "print(f\"Blue reward:{reward:.2f}\" )" @@ -557,17 +557,17 @@ "outputs": [], "source": [ "env.step(13) # Patch the database\n", - "print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker'][0]}, Blue reward:{reward:.2f}\" )\n", + "print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker']['action']}, Blue reward:{reward:.2f}\" )\n", "\n", "env.step(50) # Block client 1\n", - "print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker'][0]}, Blue reward:{reward:.2f}\" )\n", + "print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker']['action']}, Blue reward:{reward:.2f}\" )\n", "\n", "env.step(51) # Block client 2\n", - "print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker'][0]}, Blue reward:{reward:.2f}\" )\n", + "print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker']['action']}, Blue reward:{reward:.2f}\" )\n", "\n", "for step in range(30):\n", " obs, reward, terminated, truncated, info = env.step(0) # do nothing\n", - " print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker'][0]}, Blue reward:{reward:.2f}\" )" + " print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker']['action']}, Blue reward:{reward:.2f}\" )" ] }, { @@ -606,20 +606,35 @@ "metadata": {}, "outputs": [], "source": [ - "if obs['NODES'][6]['NETWORK_INTERFACES'][1]['nmne']['outbound'] == 1:\n", - " # client 1 has NMNEs, let's unblock client 2\n", - " env.step(58) # remove ACL rule 6\n", - "elif obs['NODES'][7]['NETWORK_INTERFACES'][1]['nmne']['outbound'] == 1:\n", - " env.step(57) # remove ACL rule 5\n", - "else:\n", - " print(\"something went wrong, neither client has NMNEs\")" + "env.step(58) # Remove the ACL rule that blocks client 1\n", + "env.step(57) # Remove the ACL rule that blocks client 2\n", + "\n", + "tries = 0\n", + "while True:\n", + " tries += 1\n", + " obs, reward, terminated, truncated, info = env.step(0)\n", + "\n", + " if obs['NODES'][6]['NETWORK_INTERFACES'][1]['nmne']['outbound'] == 1:\n", + " # client 1 has NMNEs, let's block it\n", + " obs, reward, terminated, truncated, info = env.step(50) # block client 1\n", + " break\n", + " elif obs['NODES'][7]['NETWORK_INTERFACES'][1]['nmne']['outbound'] == 1:\n", + " # client 2 has NMNEs, so let's block it\n", + " obs, reward, terminated, truncated, info = env.step(51) # block client 2\n", + " break\n", + " if tries>100:\n", + " print(\"Error: NMNE never increased\")\n", + " break\n", + "\n", + "env.step(13) # Patch the database\n", + "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Now, the reward will eventually increase to 1.0, even after red agent attempts subsequent attacks." + "Now, the reward will eventually increase to 0.9, even after red agent attempts subsequent attacks." ] }, { @@ -628,9 +643,10 @@ "metadata": {}, "outputs": [], "source": [ - "for step in range(30):\n", + "\n", + "for step in range(40):\n", " obs, reward, terminated, truncated, info = env.step(0) # do nothing\n", - " print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker'][0]}, Blue reward:{reward:.2f}\" )" + " print(f\"step: {env.game.step_counter}, Red action: {info['agent_actions']['data_manipulation_attacker']['action']}, Blue reward:{reward:.2f}\" )" ] }, { @@ -648,6 +664,13 @@ "source": [ "env.reset()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/src/primaite/simulator/network/hardware/base.py b/src/primaite/simulator/network/hardware/base.py index f3cf29bb..69c6b1da 100644 --- a/src/primaite/simulator/network/hardware/base.py +++ b/src/primaite/simulator/network/hardware/base.py @@ -260,10 +260,9 @@ class NetworkInterface(SimComponent, ABC): """ Apply a timestep evolution to this component. - This just clears the nmne count back to 0.tests/integration_tests/network/test_capture_nmne.py + This just clears the nmne count back to 0. """ super().apply_timestep(timestep=timestep) - self.nmne.clear() class WiredNetworkInterface(NetworkInterface, ABC):