{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "# PrimAITE Router Simulation Demo\n",
    "\n",
    "© Crown-owned copyright 2024, Defence Science and Technology Laboratory UK\n",
    "\n",
    "This demo uses a modified version of the ARCD Use Case 2 Network (seen below) to demonstrate the capabilities of the Network simulator in PrimAITE."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1",
   "metadata": {},
   "source": [
    "``` text\n",
    "                                                                                +------------+\n",
    "                                                                                |  domain_   |\n",
    "                                                                   +------------+ controller |\n",
    "                                                                   |            |            |\n",
    "                                                                   |            +------------+\n",
    "                                                                   |\n",
    "                                                                   |\n",
    "+------------+                                                     |            +------------+\n",
    "|            |                                                     |            |            |\n",
    "|  client_1  +---------+                                           |  +---------+ web_server |\n",
    "|            |         |                                           |  |         |            |\n",
    "+------------+         |                                           |  |         +------------+\n",
    "                    +--+---------+      +------------+      +------+--+--+\n",
    "                    |            |      |            |      |            |\n",
    "                    |  switch_2  +------+  router_1  +------+  switch_1  |\n",
    "                    |            |      |            |      |            |\n",
    "                    +--+------+--+      +------------+      +--+---+--+--+\n",
    "+------------+         |      |                                |   |  |         +------------+\n",
    "|            |         |      |                                |   |  |         |  database  |\n",
    "|  client_2  +---------+      |                                |   |  +---------+  _server   |\n",
    "|            |                |                                |   |            |            |\n",
    "+------------+                |                                |   |            +------------+\n",
    "                              |         +------------+         |   |\n",
    "                              |         |  security  |         |   |\n",
    "                              +---------+   _suite   +---------+   |            +------------+\n",
    "                                        |            |             |            |  backup_   |\n",
    "                                        +------------+             +------------+  server    |\n",
    "                                                                                |            |\n",
    "                                                                                +------------+\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2",
   "metadata": {},
   "source": [
    "## The Network\n",
    "First let's create our network. The network comes 'pre-packaged' with PrimAITE in the `primaite.simulator.network.networks` module.\n",
    "\n",
    "> ℹ️ You'll see a bunch of logs associated with parts of the Network that aren't an 'electronic' device on the Network and thus don't have a stream to log to. Soon these logs are going to be pushed to a Network Logger so we're not clogging up the PrimAITE application logs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from primaite.simulator.network.networks import network_simulator_demo_example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network = network_simulator_demo_example()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5",
   "metadata": {},
   "source": [
    "Most of the Network components have a `.show()` function that prints a table of information about that object. We can view the Nodes and Links on the Network by calling `network.show()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Nodes\n",
    "\n",
    "Now let's inspect some of the nodes. We can directly access a node on the Network by calling .`get_node_by_hostname`. Like Network, a Node, along with some core services like ARP, have a `.show()` method."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8",
   "metadata": {},
   "source": [
    "### Router Nodes\n",
    "\n",
    "First we'll inspect the Router node and some of it's core services."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9",
   "metadata": {},
   "source": [
    "Calling `router.show()` displays the Ethernet interfaces on the Router. If you need a table in markdown format, pass `markdown=True`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11",
   "metadata": {},
   "source": [
    "Calling `router.arp.show()` displays the Router ARP Cache."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").arp.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13",
   "metadata": {},
   "source": [
    "Calling `router.acl.show()` displays the Access Control List."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").acl.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15",
   "metadata": {},
   "source": [
    "Calling `router.router_table.show()` displays the static routes the Router provides. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "16",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").route_table.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17",
   "metadata": {},
   "source": [
    "Calling `router.sys_log.show()` displays the Router system log. By default, only the last 10 log entries are displayed, this can be changed by passing `last_n=<number of log entries>`.\n",
    "\n",
    "NB: For `sys_log.show()` to work correctly log files need to be created with a sys_log level of INFO or below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").sys_log.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19",
   "metadata": {},
   "source": [
    "### Switch Nodes\n",
    "\n",
    "Next we'll inspect the Switch node and some of its core services."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20",
   "metadata": {},
   "source": [
    "Calling `switch.show()` displays the Switch ports on the Switch."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "21",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"switch_1\").show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22",
   "metadata": {},
   "source": [
    "Calling `switch.sys_log.show()` displays the Switch system log. By default, only the last 10 log entries are displayed, this can be changed by passing `last_n=<number of log entries>`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "23",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"switch_1\").sys_log.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24",
   "metadata": {},
   "source": [
    "### Computer/Server Nodes\n",
    "\n",
    "Finally, we'll inspect a Computer or Server Node and some of its core services."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25",
   "metadata": {
    "tags": []
   },
   "source": [
    "Calling `computer.show()` displays the NICs on the Computer/Server."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "26",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"security_suite\").show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27",
   "metadata": {},
   "source": [
    "Calling `computer.arp.show()` displays the Computer/Server ARP Cache."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "28",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"security_suite\").arp.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29",
   "metadata": {},
   "source": [
    "Calling `computer.sys_log.show()` displays the Computer/Server system log. By default, only the last 10 log entries are displayed; this can be changed by passing `last_n=<number of log entries>`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"security_suite\").sys_log.show(last_n=25)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31",
   "metadata": {},
   "source": [
    "## Basic Network Comms Check\n",
    "\n",
    "We can perform a good old ping to check that Nodes are able to communicate with each other."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.show(nodes=False, links=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33",
   "metadata": {},
   "source": [
    "We'll first ping client_1's default gateway."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "34",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_1\").ping(\"192.168.10.1\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "35",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_1\").sys_log.show(last_n=15)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36",
   "metadata": {},
   "source": [
    "Next, we'll ping the interface of the 192.168.1.0/24 Network on the Router (port 1)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_1\").ping(\"192.168.1.1\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38",
   "metadata": {},
   "source": [
    "And finally, we'll ping the web server."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_1\").ping(\"192.168.1.12\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40",
   "metadata": {},
   "source": [
    "To confirm that the ping was received and processed by the web_server, we can view the sys log"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"web_server\").sys_log.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42",
   "metadata": {},
   "source": [
    "## Advanced Network Usage\n",
    "\n",
    "We can now use the Network to perform some more advanced things."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43",
   "metadata": {},
   "source": [
    "Let's attempt to prevent client_2 from being able to ping the web server. First, we'll confirm that it can ping the server..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_2\").ping(\"192.168.1.12\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45",
   "metadata": {},
   "source": [
    "If we look at the client_2 sys log we can see that the four ICMP echo requests were sent and four ICMP each replies were received."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "46",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_2\").sys_log.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47",
   "metadata": {},
   "source": [
    "Now we'll add an ACL to block ICMP from 192.168.10.22."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from primaite.simulator.network.hardware.nodes.network.router import  ACLAction\n",
    "from primaite.utils.validation.ip_protocol import PROTOCOL_LOOKUP\n",
    "\n",
    "network.get_node_by_hostname(\"router_1\").acl.add_rule(\n",
    "    action=ACLAction.DENY,\n",
    "    protocol=PROTOCOL_LOOKUP[\"ICMP\"],\n",
    "    src_ip_address=\"192.168.10.22\",\n",
    "    position=1\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").acl.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50",
   "metadata": {},
   "source": [
    "Now we attempt (and fail) to ping the web server."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_2\").ping(\"192.168.1.12\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52",
   "metadata": {},
   "source": [
    "We can check that the ping was actually sent by client_2 by viewing the sys log."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_2\").sys_log.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54",
   "metadata": {},
   "source": [
    "We can check the router sys log to see why the traffic was blocked."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "55",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"router_1\").sys_log.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56",
   "metadata": {},
   "source": [
    "Now a final check to ensure that client_1 can still ping the web_server."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "57",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_1\").ping(\"192.168.1.12\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "network.get_node_by_hostname(\"client_1\").sys_log.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
