#1800 - Synced with dev.

- Added the UC2 network.
- Added a Computer class.
This commit is contained in:
Chris McCarthy
2023-08-31 13:35:56 +01:00
parent 415ee3b3a7
commit 89ad22aceb
3 changed files with 221 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
from typing import Any, Dict, Union from typing import Any, Dict, Union, Optional
from primaite import getLogger from primaite import getLogger
from primaite.simulator.core import Action, ActionManager, AllowAllValidator, SimComponent from primaite.simulator.core import Action, ActionManager, AllowAllValidator, SimComponent
@@ -58,6 +58,19 @@ class Network(SimComponent):
node.parent = self node.parent = self
_LOGGER.info(f"Added node {node.uuid} to Network {self.uuid}") _LOGGER.info(f"Added node {node.uuid} to Network {self.uuid}")
def get_node_by_hostname(self, hostname: str) -> Optional[Node]:
"""
Get a Node from the Network by its hostname.
.. note:: Assumes hostnames on the network are unique.
:param hostname: The Node hostname.
:return: The Node if it exists in the network.
"""
for node in self.nodes.values():
if node.hostname == hostname:
return node
def remove_node(self, node: Node) -> None: def remove_node(self, node: Node) -> None:
""" """
Remove a node from the network. Remove a node from the network.
@@ -72,7 +85,8 @@ class Network(SimComponent):
node.parent = None node.parent = None
_LOGGER.info(f"Removed node {node.uuid} from network {self.uuid}") _LOGGER.info(f"Removed node {node.uuid} from network {self.uuid}")
def connect(self, endpoint_a: Union[NIC, SwitchPort], endpoint_b: Union[NIC, SwitchPort], **kwargs) -> None: def connect(self, endpoint_a: Union[Node, NIC, SwitchPort], endpoint_b: Union[Node, NIC, SwitchPort], **kwargs) -> \
None:
"""Connect two nodes on the network by creating a link between an NIC/SwitchPort of each one. """Connect two nodes on the network by creating a link between an NIC/SwitchPort of each one.
:param endpoint_a: The endpoint to which to connect the link on the first node :param endpoint_a: The endpoint to which to connect the link on the first node
@@ -81,16 +95,19 @@ class Network(SimComponent):
:type endpoint_b: Union[NIC, SwitchPort] :type endpoint_b: Union[NIC, SwitchPort]
:raises RuntimeError: _description_ :raises RuntimeError: _description_
""" """
node_a = endpoint_a.parent node_a: Node = endpoint_a.parent if not isinstance(endpoint_a, Node) else endpoint_a
node_b = endpoint_b.parent node_b: Node = endpoint_b.parent if not isinstance(endpoint_b, Node) else endpoint_b
if node_a not in self: if node_a not in self:
self.add_node(node_a) self.add_node(node_a)
if node_b not in self: if node_b not in self:
self.add_node(node_b) self.add_node(node_b)
if node_a is node_b: if node_a is node_b:
_LOGGER.warn(f"Cannot link endpoint {endpoint_a} to {endpoint_b} because they belong to the same node.") _LOGGER.warning(f"Cannot link endpoint {endpoint_a} to {endpoint_b} because they belong to the same node.")
return return
if isinstance(endpoint_a, Node) and len(endpoint_a.nics) == 1:
endpoint_a = list(endpoint_a.nics.values())[0]
if isinstance(endpoint_b, Node) and len(endpoint_b.nics) == 1:
endpoint_b = list(endpoint_b.nics.values())[0]
link = Link(endpoint_a=endpoint_a, endpoint_b=endpoint_b, **kwargs) link = Link(endpoint_a=endpoint_a, endpoint_b=endpoint_b, **kwargs)
self.links[link.uuid] = link self.links[link.uuid] = link
link.parent = self link.parent = self

View File

@@ -0,0 +1,44 @@
from ipaddress import IPv4Address
from primaite.simulator.network.hardware.base import Node, NIC
class Computer(Node):
"""
A basic computer class.
Example:
>>> pc_a = Computer(
hostname="pc_a",
ip_address="192.168.1.10",
subnet_mask="255.255.255.0",
default_gateway="192.168.1.1"
)
>>> pc_a.power_on()
Instances of computer come 'pre-packaged' with the following:
* Core Functionality:
* ARP.
* ICMP.
* Packet Capture.
* Sys Log.
* Services:
* DNS Client.
* FTP Client.
* LDAP Client.
* NTP Client.
* Applications:
* Email Client.
* Web Browser.
* Processes:
* Placeholder.
"""
def __init__(self, **kwargs):
for key in {"ip_address", "subnet_mask", "default_gateway"}:
if key in kwargs:
if not isinstance(kwargs[key], IPv4Address):
kwargs[key] = IPv4Address(kwargs[key])
super().__init__(**kwargs)
self.connect_nic(NIC(ip_address=kwargs["ip_address"], subnet_mask=kwargs["subnet_mask"]))

View File

@@ -0,0 +1,154 @@
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.base import Switch, NIC
from primaite.simulator.network.hardware.nodes.computer import Computer
from primaite.simulator.network.hardware.nodes.router import Router, ACLAction
from primaite.simulator.network.transmission.network_layer import IPProtocol
from primaite.simulator.network.transmission.transport_layer import Port
def arcd_uc2_network() -> Network:
"""
Models the ARCD Use Case 2 Network.
+------------+
| domain_ |
+------------+ controller |
| | |
| +------------+
|
|
+------------+ | +------------+
| | | | |
| client_1 +---------+ | +---------+ web_server |
| | | | | | |
+------------+ | | | +------------+
+--+---------+ +------------+ +------+--+--+
| | | | | |
| switch_2 +------+ router_1 +------+ switch_1 |
| | | | | |
+--+------+--+ +------------+ +--+---+--+--+
+------------+ | | | | | +------------+
| | | | | | | | database |
| client_2 +---------+ | | | +---------+ _server |
| | | | | | |
+------------+ | | | +------------+
| +------------+ | |
| | security | | |
+---------+ _suite +---------+ | +------------+
| | | | backup_ |
+------------+ +------------+ server |
| |
+------------+
Example:
>>> network = arcd_uc2_network()
>>> network.get_node_by_hostname("client_1").ping("192.168.1.10")
"""
network = Network()
# Router 1
router_1 = Router(hostname="router_1", num_ports=5)
router_1.power_on()
router_1.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0")
router_1.configure_port(port=2, ip_address="192.168.10.1", subnet_mask="255.255.255.0")
# Switch 1
switch_1 = Switch(hostname="switch_1", num_ports=8)
switch_1.power_on()
network.connect(endpoint_a=router_1.ethernet_ports[1], endpoint_b=switch_1.switch_ports[8])
router_1.enable_port(1)
# Switch 2
switch_2 = Switch(hostname="switch_2", num_ports=8)
switch_2.power_on()
network.connect(endpoint_a=router_1.ethernet_ports[2], endpoint_b=switch_2.switch_ports[8])
router_1.enable_port(2)
# Client 1
client_1 = Computer(
hostname="client_1",
ip_address="192.168.10.21",
subnet_mask="255.255.255.0",
default_gateway="192.168.10.1"
)
client_1.power_on()
network.connect(endpoint_a=client_1, endpoint_b=switch_2.switch_ports[1])
# Client 2
client_2 = Computer(
hostname="client_2",
ip_address="192.168.10.22",
subnet_mask="255.255.255.0",
default_gateway="192.168.10.1"
)
client_2.power_on()
network.connect(endpoint_a=client_2, endpoint_b=switch_2.switch_ports[2])
# Domain Controller
domain_controller = Computer(
hostname="domain_controller",
ip_address="192.168.1.10",
subnet_mask="255.255.255.0",
default_gateway="192.168.1.1"
)
domain_controller.power_on()
network.connect(endpoint_a=domain_controller, endpoint_b=switch_1.switch_ports[1])
# Web Server
web_server = Computer(
hostname="web_server",
ip_address="192.168.1.12",
subnet_mask="255.255.255.0",
default_gateway="192.168.1.1"
)
web_server.power_on()
network.connect(endpoint_a=web_server, endpoint_b=switch_1.switch_ports[2])
# Database Server
database_server = Computer(
hostname="database_server",
ip_address="192.168.1.14",
subnet_mask="255.255.255.0",
default_gateway="192.168.1.1"
)
database_server.power_on()
network.connect(endpoint_a=database_server, endpoint_b=switch_1.switch_ports[3])
# Backup Server
backup_server = Computer(
hostname="backup_server",
ip_address="192.168.1.16",
subnet_mask="255.255.255.0",
default_gateway="192.168.1.1"
)
backup_server.power_on()
network.connect(endpoint_a=backup_server, endpoint_b=switch_1.switch_ports[4])
# Security Suite
security_suite = Computer(
hostname="security_suite",
ip_address="192.168.1.110",
subnet_mask="255.255.255.0",
default_gateway="192.168.1.1"
)
security_suite.power_on()
network.connect(endpoint_a=security_suite, endpoint_b=switch_1.switch_ports[7])
security_suite_external_nic = NIC(ip_address="192.168.10.110", subnet_mask="255.255.255.0")
security_suite.connect_nic(security_suite_external_nic)
network.connect(endpoint_a=security_suite_external_nic, endpoint_b=switch_2.switch_ports[7])
router_1.acl.add_rule(
action=ACLAction.PERMIT,
src_port=Port.ARP,
dst_port=Port.ARP,
position=22
)
router_1.acl.add_rule(
action=ACLAction.PERMIT,
protocol=IPProtocol.ICMP,
position=23
)
return network