Merge 'origin/feature/1812' into feature/1924
This commit is contained in:
@@ -6,7 +6,7 @@ from networkx import MultiGraph
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
|
||||
from primaite import getLogger
|
||||
from primaite.simulator.core import Action, ActionManager, SimComponent
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node, SwitchPort
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.router import Router
|
||||
@@ -37,21 +37,18 @@ class Network(SimComponent):
|
||||
Initialise the network.
|
||||
|
||||
Constructs the network and sets up its initial state including
|
||||
the action manager and an empty MultiGraph for topology representation.
|
||||
the request manager and an empty MultiGraph for topology representation.
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self._nx_graph = MultiGraph()
|
||||
|
||||
def _init_action_manager(self) -> ActionManager:
|
||||
am = super()._init_action_manager()
|
||||
self._node_action_manager = ActionManager()
|
||||
am.add_action(
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
am = super()._init_request_manager()
|
||||
self._node_request_manager = RequestManager()
|
||||
am.add_request(
|
||||
"node",
|
||||
Action(
|
||||
func=self._node_action_manager
|
||||
# func=lambda request, context: self.nodes[request.pop(0)].apply_action(request, context),
|
||||
),
|
||||
RequestType(func=self._node_request_manager),
|
||||
)
|
||||
return am
|
||||
|
||||
@@ -185,7 +182,7 @@ class Network(SimComponent):
|
||||
node.parent = self
|
||||
self._nx_graph.add_node(node.hostname)
|
||||
_LOGGER.info(f"Added node {node.uuid} to Network {self.uuid}")
|
||||
self._node_action_manager.add_action(name=node.uuid, action=Action(func=node._action_manager))
|
||||
self._node_request_manager.add_request(name=node.uuid, request_type=RequestType(func=node._request_manager))
|
||||
|
||||
def get_node_by_hostname(self, hostname: str) -> Optional[Node]:
|
||||
"""
|
||||
@@ -219,9 +216,11 @@ class Network(SimComponent):
|
||||
break
|
||||
node.parent = None
|
||||
_LOGGER.info(f"Removed node {node.uuid} from network {self.uuid}")
|
||||
self._node_action_manager.remove_action(name=node.uuid)
|
||||
self._node_request_manager.remove_request(name=node.uuid)
|
||||
|
||||
def connect(self, endpoint_a: Union[NIC, SwitchPort], endpoint_b: Union[NIC, SwitchPort], **kwargs) -> Optional[Link]:
|
||||
def connect(
|
||||
self, endpoint_a: Union[NIC, SwitchPort], endpoint_b: Union[NIC, SwitchPort], **kwargs
|
||||
) -> Optional[Link]:
|
||||
"""
|
||||
Connect two endpoints on the network by creating a link between their NICs/SwitchPorts.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from prettytable import MARKDOWN, PrettyTable
|
||||
from primaite import getLogger
|
||||
from primaite.exceptions import NetworkError
|
||||
from primaite.simulator import SIM_OUTPUT
|
||||
from primaite.simulator.core import Action, ActionManager, SimComponent
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
from primaite.simulator.domain.account import Account
|
||||
from primaite.simulator.file_system.file_system import FileSystem
|
||||
from primaite.simulator.network.protocols.arp import ARPEntry, ARPPacket
|
||||
@@ -144,11 +144,11 @@ class NIC(SimComponent):
|
||||
)
|
||||
return state
|
||||
|
||||
def _init_action_manager(self) -> ActionManager:
|
||||
am = super()._init_action_manager()
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
am = super()._init_request_manager()
|
||||
|
||||
am.add_action("enable", Action(func=lambda request, context: self.enable()))
|
||||
am.add_action("disable", Action(func=lambda request, context: self.disable()))
|
||||
am.add_request("enable", RequestType(func=lambda request, context: self.enable()))
|
||||
am.add_request("disable", RequestType(func=lambda request, context: self.disable()))
|
||||
|
||||
return am
|
||||
|
||||
@@ -502,7 +502,9 @@ class Link(SimComponent):
|
||||
def _can_transmit(self, frame: Frame) -> bool:
|
||||
if self.is_up:
|
||||
frame_size_Mbits = frame.size_Mbits # noqa - Leaving it as Mbits as this is how they're expressed
|
||||
return self.current_load + frame_size_Mbits <= self.bandwidth
|
||||
# return self.current_load + frame_size_Mbits <= self.bandwidth
|
||||
# TODO: re add this check once packet size limiting and MTU checks are implemented
|
||||
return True
|
||||
return False
|
||||
|
||||
def transmit_frame(self, sender_nic: Union[NIC, SwitchPort], frame: Frame) -> bool:
|
||||
@@ -942,35 +944,40 @@ class Node(SimComponent):
|
||||
super().__init__(**kwargs)
|
||||
self.arp.nics = self.nics
|
||||
self.session_manager.software_manager = self.software_manager
|
||||
self._install_system_software()
|
||||
|
||||
def _init_action_manager(self) -> ActionManager:
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
# TODO: I see that this code is really confusing and hard to read right now... I think some of these things will
|
||||
# need a better name and better documentation.
|
||||
am = super()._init_action_manager()
|
||||
# since there are potentially many services, create an action manager that can map service name
|
||||
self._service_action_manager = ActionManager()
|
||||
am.add_action("service", Action(func=self._service_action_manager))
|
||||
self._nic_action_manager = ActionManager()
|
||||
am.add_action("nic", Action(func=self._nic_action_manager))
|
||||
am = super()._init_request_manager()
|
||||
# since there are potentially many services, create an request manager that can map service name
|
||||
self._service_request_manager = RequestManager()
|
||||
am.add_request("service", RequestType(func=self._service_request_manager))
|
||||
self._nic_request_manager = RequestManager()
|
||||
am.add_request("nic", RequestType(func=self._nic_request_manager))
|
||||
|
||||
am.add_action("file_system", Action(func=self.file_system._action_manager))
|
||||
am.add_request("file_system", RequestType(func=self.file_system._request_manager))
|
||||
|
||||
# currently we don't have any applications nor processes, so these will be empty
|
||||
self._process_action_manager = ActionManager()
|
||||
am.add_action("process", Action(func=self._process_action_manager))
|
||||
self._application_action_manager = ActionManager()
|
||||
am.add_action("application", Action(func=self._application_action_manager))
|
||||
self._process_request_manager = RequestManager()
|
||||
am.add_request("process", RequestType(func=self._process_request_manager))
|
||||
self._application_request_manager = RequestManager()
|
||||
am.add_request("application", RequestType(func=self._application_request_manager))
|
||||
|
||||
am.add_action("scan", Action(func=lambda request, context: ...)) # TODO implement OS scan
|
||||
am.add_request("scan", RequestType(func=lambda request, context: ...)) # TODO implement OS scan
|
||||
|
||||
am.add_action("shutdown", Action(func=lambda request, context: self.power_off()))
|
||||
am.add_action("startup", Action(func=lambda request, context: self.power_on()))
|
||||
am.add_action("reset", Action(func=lambda request, context: ...)) # TODO implement node reset
|
||||
am.add_action("logon", Action(func=lambda request, context: ...)) # TODO implement logon action
|
||||
am.add_action("logoff", Action(func=lambda request, context: ...)) # TODO implement logoff action
|
||||
am.add_request("shutdown", RequestType(func=lambda request, context: self.power_off()))
|
||||
am.add_request("startup", RequestType(func=lambda request, context: self.power_on()))
|
||||
am.add_request("reset", RequestType(func=lambda request, context: ...)) # TODO implement node reset
|
||||
am.add_request("logon", RequestType(func=lambda request, context: ...)) # TODO implement logon request
|
||||
am.add_request("logoff", RequestType(func=lambda request, context: ...)) # TODO implement logoff request
|
||||
|
||||
return am
|
||||
|
||||
def _install_system_software(self):
|
||||
"""Install System Software - software that is usually provided with the OS."""
|
||||
pass
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Produce a dictionary describing the current state of this object.
|
||||
@@ -1064,7 +1071,7 @@ class Node(SimComponent):
|
||||
self.sys_log.info(f"Connected NIC {nic}")
|
||||
if self.operating_state == NodeOperatingState.ON:
|
||||
nic.enable()
|
||||
self._nic_action_manager.add_action(nic.uuid, Action(func=nic._action_manager))
|
||||
self._nic_request_manager.add_request(nic.uuid, RequestType(func=nic._request_manager))
|
||||
else:
|
||||
msg = f"Cannot connect NIC {nic} as it is already connected"
|
||||
self.sys_log.logger.error(msg)
|
||||
@@ -1089,7 +1096,7 @@ class Node(SimComponent):
|
||||
nic.parent = None
|
||||
nic.disable()
|
||||
self.sys_log.info(f"Disconnected NIC {nic}")
|
||||
self._nic_action_manager.remove_action(nic.uuid)
|
||||
self._nic_request_manager.remove_request(nic.uuid)
|
||||
else:
|
||||
msg = f"Cannot disconnect NIC {nic} as it is not connected"
|
||||
self.sys_log.logger.error(msg)
|
||||
@@ -1187,7 +1194,7 @@ class Node(SimComponent):
|
||||
service.install() # Perform any additional setup, such as creating files for this service on the node.
|
||||
self.sys_log.info(f"Installed service {service.name}")
|
||||
_LOGGER.info(f"Added service {service.uuid} to node {self.uuid}")
|
||||
self._service_action_manager.add_action(service.uuid, Action(func=service._action_manager))
|
||||
self._service_request_manager.add_request(service.uuid, RequestType(func=service._request_manager))
|
||||
|
||||
def uninstall_service(self, service: Service) -> None:
|
||||
"""Uninstall and completely remove service from this node.
|
||||
@@ -1203,7 +1210,7 @@ class Node(SimComponent):
|
||||
service.parent = None
|
||||
self.sys_log.info(f"Uninstalled service {service.name}")
|
||||
_LOGGER.info(f"Removed service {service.uuid} from node {self.uuid}")
|
||||
self._service_action_manager.remove_action(service.uuid)
|
||||
self._service_request_manager.remove_request(service.uuid)
|
||||
|
||||
def __contains__(self, item: Any) -> bool:
|
||||
if isinstance(item, Service):
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from primaite.simulator.network.hardware.base import NIC, Node
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
|
||||
|
||||
class Computer(Node):
|
||||
@@ -36,3 +38,14 @@ class Computer(Node):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.connect_nic(NIC(ip_address=kwargs["ip_address"], subnet_mask=kwargs["subnet_mask"]))
|
||||
self._install_system_software()
|
||||
|
||||
def _install_system_software(self):
|
||||
"""Install System Software - software that is usually provided with the OS."""
|
||||
# DNS Client
|
||||
self.software_manager.install(DNSClient)
|
||||
|
||||
# FTP
|
||||
self.software_manager.install(FTPClient)
|
||||
|
||||
super()._install_system_software()
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
|
||||
from primaite.simulator.core import Action, ActionManager, SimComponent
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
from primaite.simulator.network.hardware.base import ARPCache, ICMP, NIC, Node
|
||||
from primaite.simulator.network.transmission.data_link_layer import EthernetHeader, Frame
|
||||
from primaite.simulator.network.transmission.network_layer import ICMPPacket, ICMPType, IPPacket, IPProtocol
|
||||
@@ -43,7 +43,7 @@ class ACLRule(SimComponent):
|
||||
|
||||
def __str__(self) -> str:
|
||||
rule_strings = []
|
||||
for key, value in self.model_dump(exclude={"uuid", "action_manager"}).items():
|
||||
for key, value in self.model_dump(exclude={"uuid", "request_manager"}).items():
|
||||
if value is None:
|
||||
value = "ANY"
|
||||
if isinstance(value, Enum):
|
||||
@@ -94,8 +94,8 @@ class AccessControlList(SimComponent):
|
||||
super().__init__(**kwargs)
|
||||
self._acl = [None] * (self.max_acl_rules - 1)
|
||||
|
||||
def _init_action_manager(self) -> ActionManager:
|
||||
am = super()._init_action_manager()
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
am = super()._init_request_manager()
|
||||
|
||||
# When the request reaches this action, it should now contain solely positional args for the 'add_rule' action.
|
||||
# POSITIONAL ARGUMENTS:
|
||||
@@ -106,22 +106,22 @@ class AccessControlList(SimComponent):
|
||||
# 4: destination ip address (str castable to IPV4Address (e.g. '10.10.1.2'))
|
||||
# 5: destination port (str name of a Port (e.g. "HTTP"))
|
||||
# 6: position (int)
|
||||
am.add_action(
|
||||
am.add_request(
|
||||
"add_rule",
|
||||
Action(
|
||||
RequestType(
|
||||
func=lambda request, context: self.add_rule(
|
||||
ACLAction[request[0]],
|
||||
None if request[1] is "ALL" else IPProtocol[request[1]],
|
||||
None if request[1] == "ALL" else IPProtocol[request[1]],
|
||||
IPv4Address(request[2]),
|
||||
None if request[3] is "ALL" else Port[request[3]],
|
||||
None if request[3] == "ALL" else Port[request[3]],
|
||||
IPv4Address(request[4]),
|
||||
None if request[5] is "ALL" else Port[request[5]],
|
||||
None if request[5] == "ALL" else Port[request[5]],
|
||||
int(request[6]),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
am.add_action("remove_rule", Action(func=lambda request, context: self.remove_rule(int(request[0]))))
|
||||
am.add_request("remove_rule", RequestType(func=lambda request, context: self.remove_rule(int(request[0]))))
|
||||
return am
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
@@ -638,9 +638,9 @@ class Router(Node):
|
||||
self.arp.nics = self.nics
|
||||
self.icmp.arp = self.arp
|
||||
|
||||
def _init_action_manager(self) -> ActionManager:
|
||||
am = super()._init_action_manager()
|
||||
am.add_action("acl", Action(func=self.acl._action_manager))
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
am = super()._init_request_manager()
|
||||
am.add_request("acl", RequestType(func=self.acl._request_manager))
|
||||
return am
|
||||
|
||||
def _get_port_of_nic(self, target_nic: NIC) -> Optional[int]:
|
||||
|
||||
@@ -9,9 +9,9 @@ from primaite.simulator.network.hardware.nodes.switch import Switch
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.services.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.ftp.ftp_server import FTPServer
|
||||
from primaite.simulator.system.services.red_services.data_manipulation_bot import DataManipulationBot
|
||||
|
||||
|
||||
@@ -135,9 +135,6 @@ def arcd_uc2_network() -> Network:
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
)
|
||||
client_1.power_on()
|
||||
client_1.software_manager.install(DNSClient)
|
||||
client_1_dns_client_service: DNSServer = client_1.software_manager.software["DNSClient"] # noqa
|
||||
client_1_dns_client_service.start()
|
||||
network.connect(endpoint_b=client_1.ethernet_port[1], endpoint_a=switch_2.switch_ports[1])
|
||||
client_1.software_manager.install(DataManipulationBot)
|
||||
db_manipulation_bot: DataManipulationBot = client_1.software_manager.software["DataManipulationBot"]
|
||||
@@ -152,9 +149,6 @@ def arcd_uc2_network() -> Network:
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
)
|
||||
client_2.power_on()
|
||||
client_2.software_manager.install(DNSClient)
|
||||
client_2_dns_client_service: DNSServer = client_2.software_manager.software["DNSClient"] # noqa
|
||||
client_2_dns_client_service.start()
|
||||
network.connect(endpoint_b=client_2.ethernet_port[1], endpoint_a=switch_2.switch_ports[2])
|
||||
|
||||
# Domain Controller
|
||||
@@ -191,24 +185,53 @@ def arcd_uc2_network() -> Network:
|
||||
);"""
|
||||
|
||||
user_insert_statements = [
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('John Doe', 'johndoe@example.com', 32, 'New York', 'Engineer');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Jane Smith', 'janesmith@example.com', 27, 'Los Angeles', 'Designer');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Bob Johnson', 'bobjohnson@example.com', 45, 'Chicago', 'Manager');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Alice Lee', 'alicelee@example.com', 22, 'San Francisco', 'Student');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('David Kim', 'davidkim@example.com', 38, 'Houston', 'Consultant');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Emily Chen', 'emilychen@example.com', 29, 'Seattle', 'Software Developer');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Frank Wang', 'frankwang@example.com', 55, 'New York', 'Entrepreneur');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Grace Park', 'gracepark@example.com', 31, 'Los Angeles', 'Marketing Specialist');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Henry Wu', 'henrywu@example.com', 40, 'Chicago', 'Accountant');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Isabella Kim', 'isabellakim@example.com', 26, 'San Francisco', 'Graphic Designer');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Jake Lee', 'jakelee@example.com', 33, 'Houston', 'Sales Manager');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Kelly Chen', 'kellychen@example.com', 28, 'Seattle', 'Web Developer');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Lucas Liu', 'lucasliu@example.com', 42, 'New York', 'Lawyer');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) VALUES ('Maggie Wang', 'maggiewang@example.com', 30, 'Los Angeles', 'Data Analyst');", # noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('John Doe', 'johndoe@example.com', 32, 'New York', 'Engineer');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Jane Smith', 'janesmith@example.com', 27, 'Los Angeles', 'Designer');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Bob Johnson', 'bobjohnson@example.com', 45, 'Chicago', 'Manager');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Alice Lee', 'alicelee@example.com', 22, 'San Francisco', 'Student');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('David Kim', 'davidkim@example.com', 38, 'Houston', 'Consultant');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Emily Chen', 'emilychen@example.com', 29, 'Seattle', 'Software Developer');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Frank Wang', 'frankwang@example.com', 55, 'New York', 'Entrepreneur');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Grace Park', 'gracepark@example.com', 31, 'Los Angeles', 'Marketing Specialist');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Henry Wu', 'henrywu@example.com', 40, 'Chicago', 'Accountant');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Isabella Kim', 'isabellakim@example.com', 26, 'San Francisco', 'Graphic Designer');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Jake Lee', 'jakelee@example.com', 33, 'Houston', 'Sales Manager');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Kelly Chen', 'kellychen@example.com', 28, 'Seattle', 'Web Developer');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Lucas Liu', 'lucasliu@example.com', 42, 'New York', 'Lawyer');",
|
||||
# noqa
|
||||
"INSERT INTO user (name, email, age, city, occupation) "
|
||||
"VALUES ('Maggie Wang', 'maggiewang@example.com', 30, 'Los Angeles', 'Data Analyst');",
|
||||
# noqa
|
||||
]
|
||||
database_server.software_manager.install(DatabaseService)
|
||||
database_service: DatabaseService = database_server.software_manager.software["DatabaseService"] # noqa
|
||||
database_service.start()
|
||||
database_service.configure_backup(backup_server=IPv4Address("192.168.1.16"))
|
||||
database_service._process_sql(ddl, None) # noqa
|
||||
for insert_statement in user_insert_statements:
|
||||
database_service._process_sql(insert_statement, None) # noqa
|
||||
@@ -232,7 +255,6 @@ def arcd_uc2_network() -> Network:
|
||||
|
||||
# register the web_server to a domain
|
||||
dns_server_service: DNSServer = domain_controller.software_manager.software["DNSServer"] # noqa
|
||||
dns_server_service.start()
|
||||
dns_server_service.dns_register("arcd.com", web_server.ip_address)
|
||||
|
||||
# Backup Server
|
||||
@@ -246,6 +268,8 @@ def arcd_uc2_network() -> Network:
|
||||
backup_server.power_on()
|
||||
network.connect(endpoint_b=backup_server.ethernet_port[1], endpoint_a=switch_1.switch_ports[4])
|
||||
|
||||
backup_server.software_manager.install(FTPServer)
|
||||
|
||||
# Security Suite
|
||||
security_suite = Server(
|
||||
hostname="security_suite",
|
||||
@@ -271,4 +295,7 @@ def arcd_uc2_network() -> Network:
|
||||
# Allow DNS requests
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.DNS, dst_port=Port.DNS, position=1)
|
||||
|
||||
# Allow FTP requests
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.FTP, dst_port=Port.FTP, position=2)
|
||||
|
||||
return network
|
||||
|
||||
@@ -5,6 +5,8 @@ from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from primaite.simulator.network.protocols.packet import DataPacket
|
||||
|
||||
|
||||
class ARPEntry(BaseModel):
|
||||
"""
|
||||
@@ -18,7 +20,7 @@ class ARPEntry(BaseModel):
|
||||
nic_uuid: str
|
||||
|
||||
|
||||
class ARPPacket(BaseModel):
|
||||
class ARPPacket(DataPacket):
|
||||
"""
|
||||
Represents the ARP layer of a network frame.
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from primaite.simulator.network.protocols.packet import DataPacket
|
||||
|
||||
|
||||
class DNSRequest(BaseModel):
|
||||
"""Represents a DNS Request packet of a network frame.
|
||||
@@ -26,7 +28,7 @@ class DNSReply(BaseModel):
|
||||
"IP Address of the Domain Name requested."
|
||||
|
||||
|
||||
class DNSPacket(BaseModel):
|
||||
class DNSPacket(DataPacket):
|
||||
"""
|
||||
Represents the DNS layer of a network frame.
|
||||
|
||||
|
||||
55
src/primaite/simulator/network/protocols/ftp.py
Normal file
55
src/primaite/simulator/network/protocols/ftp.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from enum import Enum
|
||||
from typing import Any, Optional
|
||||
|
||||
from primaite.simulator.network.protocols.packet import DataPacket
|
||||
|
||||
|
||||
class FTPCommand(Enum):
|
||||
"""FTP Commands that are allowed."""
|
||||
|
||||
PORT = "PORT"
|
||||
"""Set a port to be used for the FTP transfer."""
|
||||
|
||||
STOR = "STOR"
|
||||
"""Copy or put data to the FTP server."""
|
||||
|
||||
RETR = "RETR"
|
||||
"""Retrieve data from the FTP server."""
|
||||
|
||||
DELE = "DELE"
|
||||
"""Delete the file in the specified path."""
|
||||
|
||||
RMD = "RMD"
|
||||
"""Remove the directory in the specified path."""
|
||||
|
||||
MKD = "MKD"
|
||||
"""Make a directory in the specified path."""
|
||||
|
||||
LIST = "LIST"
|
||||
"""Return a list of files in the specified path."""
|
||||
|
||||
QUIT = "QUIT"
|
||||
"""Ends connection between client and server."""
|
||||
|
||||
|
||||
class FTPStatusCode(Enum):
|
||||
"""Status code of the current FTP request."""
|
||||
|
||||
OK = 200
|
||||
"""Command successful."""
|
||||
|
||||
ERROR = 500
|
||||
"""General error code."""
|
||||
|
||||
|
||||
class FTPPacket(DataPacket):
|
||||
"""Represents an FTP Packet."""
|
||||
|
||||
ftp_command: FTPCommand
|
||||
"""Command type of the packet."""
|
||||
|
||||
ftp_command_args: Optional[Any] = None
|
||||
"""Arguments for command."""
|
||||
|
||||
status_code: FTPStatusCode = None
|
||||
"""Status of the response."""
|
||||
12
src/primaite/simulator/network/protocols/packet.py
Normal file
12
src/primaite/simulator/network/protocols/packet.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DataPacket(BaseModel):
|
||||
"""Data packet abstract class."""
|
||||
|
||||
packet_payload_size: float = 0
|
||||
"""Size of the packet."""
|
||||
|
||||
def get_packet_size(self) -> float:
|
||||
"""Returns the size of the packet header and payload."""
|
||||
return self.packet_payload_size + float(len(self.model_dump_json().encode("utf-8")))
|
||||
@@ -5,6 +5,7 @@ from pydantic import BaseModel
|
||||
|
||||
from primaite import getLogger
|
||||
from primaite.simulator.network.protocols.arp import ARPPacket
|
||||
from primaite.simulator.network.protocols.packet import DataPacket
|
||||
from primaite.simulator.network.transmission.network_layer import ICMPPacket, IPPacket, IPProtocol
|
||||
from primaite.simulator.network.transmission.primaite_layer import PrimaiteHeader
|
||||
from primaite.simulator.network.transmission.transport_layer import TCPHeader, UDPHeader
|
||||
@@ -132,6 +133,10 @@ class Frame(BaseModel):
|
||||
@property
|
||||
def size(self) -> float: # noqa - Keep it as MBits as this is how they're expressed
|
||||
"""The size of the Frame in Bytes."""
|
||||
# get the payload size if it is a data packet
|
||||
if isinstance(self.payload, DataPacket):
|
||||
return self.payload.get_packet_size()
|
||||
|
||||
return float(len(self.model_dump_json().encode("utf-8")))
|
||||
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user