#2887 - Correct networking troubles causing test failures

This commit is contained in:
Charlie Crane
2025-01-28 19:35:27 +00:00
parent d5e4d3d2ad
commit f85aace31b
11 changed files with 53 additions and 57 deletions

View File

@@ -278,11 +278,11 @@ class PrimaiteGame:
# TODO: handle simulation defaults more cleanly # TODO: handle simulation defaults more cleanly
if "node_start_up_duration" in defaults_config: if "node_start_up_duration" in defaults_config:
new_node.start_up_duration = defaults_config["node_startup_duration"] new_node.config.start_up_duration = defaults_config["node_startup_duration"]
if "node_shut_down_duration" in defaults_config: if "node_shut_down_duration" in defaults_config:
new_node.shut_down_duration = defaults_config["node_shut_down_duration"] new_node.config.shut_down_duration = defaults_config["node_shut_down_duration"]
if "node_scan_duration" in defaults_config: if "node_scan_duration" in defaults_config:
new_node.node_scan_duration = defaults_config["node_scan_duration"] new_node.config.node_scan_duration = defaults_config["node_scan_duration"]
if "folder_scan_duration" in defaults_config: if "folder_scan_duration" in defaults_config:
new_node.file_system._default_folder_scan_duration = defaults_config["folder_scan_duration"] new_node.file_system._default_folder_scan_duration = defaults_config["folder_scan_duration"]
if "folder_restore_duration" in defaults_config: if "folder_restore_duration" in defaults_config:
@@ -337,7 +337,7 @@ class PrimaiteGame:
# TODO: handle simulation defaults more cleanly # TODO: handle simulation defaults more cleanly
if "service_fix_duration" in defaults_config: if "service_fix_duration" in defaults_config:
new_service.fixing_duration = defaults_config["service_fix_duration"] new_service.config.fixing_duration = defaults_config["service_fix_duration"]
if "service_restart_duration" in defaults_config: if "service_restart_duration" in defaults_config:
new_service.restart_duration = defaults_config["service_restart_duration"] new_service.restart_duration = defaults_config["service_restart_duration"]
if "service_install_duration" in defaults_config: if "service_install_duration" in defaults_config:
@@ -394,8 +394,8 @@ class PrimaiteGame:
new_node.connect_nic(NIC(ip_address=nic_cfg["ip_address"], subnet_mask=nic_cfg["subnet_mask"])) new_node.connect_nic(NIC(ip_address=nic_cfg["ip_address"], subnet_mask=nic_cfg["subnet_mask"]))
# temporarily set to 0 so all nodes are initially on # temporarily set to 0 so all nodes are initially on
new_node.start_up_duration = 0 new_node.config.start_up_duration = 0
new_node.shut_down_duration = 0 new_node.config.shut_down_duration = 0
net.add_node(new_node) net.add_node(new_node)
# run through the power on step if the node is to be turned on at the start # run through the power on step if the node is to be turned on at the start
@@ -403,8 +403,8 @@ class PrimaiteGame:
new_node.power_on() new_node.power_on()
# set start up and shut down duration # set start up and shut down duration
new_node.start_up_duration = int(node_cfg.get("start_up_duration", 3)) new_node.config.start_up_duration = int(node_cfg.get("start_up_duration", 3))
new_node.shut_down_duration = int(node_cfg.get("shut_down_duration", 3)) new_node.config.shut_down_duration = int(node_cfg.get("shut_down_duration", 3))
# 1.1 Create Node Sets # 1.1 Create Node Sets
for node_set_cfg in node_sets_cfg: for node_set_cfg in node_sets_cfg:

View File

@@ -201,7 +201,7 @@ class Network(SimComponent):
port_str, port_str,
port.ip_address, port.ip_address,
port.subnet_mask, port.subnet_mask,
node.default_gateway, node.config.default_gateway,
] ]
) )
print(table) print(table)

View File

@@ -1493,17 +1493,12 @@ class Node(SimComponent, ABC):
:param hostname: The node hostname on the network. :param hostname: The node hostname on the network.
:param operating_state: The node operating state, either ON or OFF. :param operating_state: The node operating state, either ON or OFF.
""" """
default_gateway: Optional[IPV4Address] = None
"The default gateway IP address for forwarding network traffic to other networks."
operating_state: NodeOperatingState = NodeOperatingState.OFF operating_state: NodeOperatingState = NodeOperatingState.OFF
"The hardware state of the node." "The hardware state of the node."
network_interfaces: Dict[str, NetworkInterface] = {} network_interfaces: Dict[str, NetworkInterface] = {}
"The Network Interfaces on the node." "The Network Interfaces on the node."
network_interface: Dict[int, NetworkInterface] = {} network_interface: Dict[int, NetworkInterface] = {}
"The Network Interfaces on the node by port id." "The Network Interfaces on the node by port id."
dns_server: Optional[IPv4Address] = None
"List of IP addresses of DNS servers used for name resolution."
accounts: Dict[str, Account] = {} accounts: Dict[str, Account] = {}
"All accounts on the node." "All accounts on the node."
applications: Dict[str, Application] = {} applications: Dict[str, Application] = {}
@@ -1567,6 +1562,16 @@ class Node(SimComponent, ABC):
red_scan_countdown: int = 0 red_scan_countdown: int = 0
"Time steps until reveal to red scan is complete." "Time steps until reveal to red scan is complete."
dns_server: Optional[IPv4Address] = None
"List of IP addresses of DNS servers used for name resolution."
default_gateway: Optional[IPV4Address] = None
"The default gateway IP address for forwarding network traffic to other networks."
@property
def dns_server(self) -> Optional[IPv4Address]:
return self.config.dns_server
@classmethod @classmethod
def from_config(cls, config: Dict) -> "Node": def from_config(cls, config: Dict) -> "Node":
"""Create Node object from a given configuration dictionary.""" """Create Node object from a given configuration dictionary."""
@@ -1615,7 +1620,7 @@ class Node(SimComponent, ABC):
sys_log=kwargs.get("sys_log"), sys_log=kwargs.get("sys_log"),
session_manager=kwargs.get("session_manager"), session_manager=kwargs.get("session_manager"),
file_system=kwargs.get("file_system"), file_system=kwargs.get("file_system"),
dns_server=kwargs.get("dns_server"), dns_server=kwargs["config"].dns_server,
) )
super().__init__(**kwargs) super().__init__(**kwargs)
self._install_system_software() self._install_system_software()

View File

@@ -46,8 +46,8 @@ class HostARP(ARP):
:return: The MAC address of the default gateway if present in the ARP cache; otherwise, None. :return: The MAC address of the default gateway if present in the ARP cache; otherwise, None.
""" """
if self.software_manager.node.default_gateway: if self.software_manager.node.config.default_gateway:
return self.get_arp_cache_mac_address(self.software_manager.node.default_gateway) return self.get_arp_cache_mac_address(self.software_manager.node.config.default_gateway)
def get_default_gateway_network_interface(self) -> Optional[NIC]: def get_default_gateway_network_interface(self) -> Optional[NIC]:
""" """
@@ -55,8 +55,8 @@ class HostARP(ARP):
:return: The NIC associated with the default gateway if it exists in the ARP cache; otherwise, None. :return: The NIC associated with the default gateway if it exists in the ARP cache; otherwise, None.
""" """
if self.software_manager.node.default_gateway and self.software_manager.node.has_enabled_network_interface: if self.software_manager.node.config.default_gateway and self.software_manager.node.has_enabled_network_interface:
return self.get_arp_cache_network_interface(self.software_manager.node.default_gateway) return self.get_arp_cache_network_interface(self.software_manager.node.config.default_gateway)
def _get_arp_cache_mac_address( def _get_arp_cache_mac_address(
self, ip_address: IPV4Address, is_reattempt: bool = False, is_default_gateway_attempt: bool = False self, ip_address: IPV4Address, is_reattempt: bool = False, is_default_gateway_attempt: bool = False
@@ -75,7 +75,7 @@ class HostARP(ARP):
if arp_entry: if arp_entry:
return arp_entry.mac_address return arp_entry.mac_address
if ip_address == self.software_manager.node.default_gateway: if ip_address == self.software_manager.node.config.default_gateway:
is_reattempt = True is_reattempt = True
if not is_reattempt: if not is_reattempt:
self.send_arp_request(ip_address) self.send_arp_request(ip_address)
@@ -83,11 +83,11 @@ class HostARP(ARP):
ip_address=ip_address, is_reattempt=True, is_default_gateway_attempt=is_default_gateway_attempt ip_address=ip_address, is_reattempt=True, is_default_gateway_attempt=is_default_gateway_attempt
) )
else: else:
if self.software_manager.node.default_gateway: if self.software_manager.node.config.default_gateway:
if not is_default_gateway_attempt: if not is_default_gateway_attempt:
self.send_arp_request(self.software_manager.node.default_gateway) self.send_arp_request(self.software_manager.node.config.default_gateway)
return self._get_arp_cache_mac_address( return self._get_arp_cache_mac_address(
ip_address=self.software_manager.node.default_gateway, ip_address=self.software_manager.node.config.default_gateway,
is_reattempt=True, is_reattempt=True,
is_default_gateway_attempt=True, is_default_gateway_attempt=True,
) )
@@ -118,7 +118,7 @@ class HostARP(ARP):
if arp_entry: if arp_entry:
return self.software_manager.node.network_interfaces[arp_entry.network_interface_uuid] return self.software_manager.node.network_interfaces[arp_entry.network_interface_uuid]
else: else:
if ip_address == self.software_manager.node.default_gateway: if ip_address == self.software_manager.node.config.default_gateway:
is_reattempt = True is_reattempt = True
if not is_reattempt: if not is_reattempt:
self.send_arp_request(ip_address) self.send_arp_request(ip_address)
@@ -126,11 +126,11 @@ class HostARP(ARP):
ip_address=ip_address, is_reattempt=True, is_default_gateway_attempt=is_default_gateway_attempt ip_address=ip_address, is_reattempt=True, is_default_gateway_attempt=is_default_gateway_attempt
) )
else: else:
if self.software_manager.node.default_gateway: if self.software_manager.node.config.default_gateway:
if not is_default_gateway_attempt: if not is_default_gateway_attempt:
self.send_arp_request(self.software_manager.node.default_gateway) self.send_arp_request(self.software_manager.node.config.default_gateway)
return self._get_arp_cache_network_interface( return self._get_arp_cache_network_interface(
ip_address=self.software_manager.node.default_gateway, ip_address=self.software_manager.node.config.default_gateway,
is_reattempt=True, is_reattempt=True,
is_default_gateway_attempt=True, is_default_gateway_attempt=True,
) )
@@ -333,9 +333,8 @@ class HostNode(Node, identifier="HostNode"):
"""Configuration Schema for HostNode class.""" """Configuration Schema for HostNode class."""
hostname: str = "HostNode" hostname: str = "HostNode"
ip_address: IPV4Address = "192.168.0.1"
subnet_mask: IPV4Address = "255.255.255.0" subnet_mask: IPV4Address = "255.255.255.0"
default_gateway: IPV4Address = "192.168.10.1" ip_address: IPV4Address
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)

View File

@@ -141,6 +141,7 @@ class Firewall(Router, identifier="firewall"):
self.external_outbound_acl.sys_log = kwargs["sys_log"] self.external_outbound_acl.sys_log = kwargs["sys_log"]
self.external_outbound_acl.name = f"{kwargs['config'].hostname} - External Outbound" self.external_outbound_acl.name = f"{kwargs['config'].hostname} - External Outbound"
self.power_on()
def _init_request_manager(self) -> RequestManager: def _init_request_manager(self) -> RequestManager:
""" """

View File

@@ -1211,32 +1211,22 @@ class Router(NetworkNode, identifier="router"):
"The Router Interfaces on the node." "The Router Interfaces on the node."
network_interface: Dict[int, RouterInterface] = {} network_interface: Dict[int, RouterInterface] = {}
"The Router Interfaces on the node by port id." "The Router Interfaces on the node by port id."
sys_log: SysLog
acl: AccessControlList acl: AccessControlList
route_table: RouteTable route_table: RouteTable
config: "Router.ConfigSchema" = Field(default_factory=lambda: Router.ConfigSchema()) config: "Router.ConfigSchema"
class ConfigSchema(NetworkNode.ConfigSchema): class ConfigSchema(NetworkNode.ConfigSchema):
"""Configuration Schema for Router Objects."""
num_ports: int = 5 hostname: str = "router"
"""Number of ports available for this Router. Default is 5""" num_ports: int
hostname: str = "Router"
ports: Dict[Union[int, str], Dict] = {}
def __init__(self, **kwargs): def __init__(self, **kwargs):
if not kwargs.get("sys_log"): if not kwargs.get("sys_log"):
kwargs["sys_log"] = SysLog(kwargs["config"].hostname) kwargs["sys_log"] = SysLog(kwargs["config"].hostname)
if not kwargs.get("acl"): if not kwargs.get("acl"):
kwargs["acl"] = AccessControlList( kwargs["acl"] = AccessControlList(sys_log=kwargs["sys_log"], implicit_action=ACLAction.DENY, name=kwargs["config"].hostname)
sys_log=kwargs["sys_log"], implicit_action=ACLAction.DENY, name=kwargs["config"].hostname
)
if not kwargs.get("route_table"): if not kwargs.get("route_table"):
kwargs["route_table"] = RouteTable(sys_log=kwargs["sys_log"]) kwargs["route_table"] = RouteTable(sys_log=kwargs["sys_log"])
super().__init__(**kwargs) super().__init__(**kwargs)
@@ -1562,7 +1552,7 @@ class Router(NetworkNode, identifier="router"):
if markdown: if markdown:
table.set_style(MARKDOWN) table.set_style(MARKDOWN)
table.align = "l" table.align = "l"
table.title = f"{self.hostname} Network Interfaces" table.title = f"{self.config.hostname} Network Interfaces"
for port, network_interface in self.network_interface.items(): for port, network_interface in self.network_interface.items():
table.add_row( table.add_row(
[ [
@@ -1666,4 +1656,5 @@ class Router(NetworkNode, identifier="router"):
next_hop_ip_address = config["default_route"].get("next_hop_ip_address", None) next_hop_ip_address = config["default_route"].get("next_hop_ip_address", None)
if next_hop_ip_address: if next_hop_ip_address:
router.route_table.set_default_route_next_hop_ip_address(next_hop_ip_address) router.route_table.set_default_route_next_hop_ip_address(next_hop_ip_address)
router.operating_state = NodeOperatingState.ON if not (p := config.get("operating_state")) else NodeOperatingState[p.upper()]
return router return router

View File

@@ -40,42 +40,42 @@ def client_server_routed() -> Network:
network = Network() network = Network()
# Router 1 # Router 1
router_1 = Router(hostname="router_1", num_ports=3) router_1 = Router(config=dict(hostname="router_1", num_ports=3))
router_1.power_on() 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=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0")
router_1.configure_port(port=2, ip_address="192.168.2.1", subnet_mask="255.255.255.0") router_1.configure_port(port=2, ip_address="192.168.2.1", subnet_mask="255.255.255.0")
# Switch 1 # Switch 1
switch_1 = Switch(hostname="switch_1", num_ports=6) switch_1 = Switch(config=dict(hostname="switch_1", num_ports=6))
switch_1.power_on() switch_1.power_on()
network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.network_interface[6]) network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.network_interface[6])
router_1.enable_port(1) router_1.enable_port(1)
# Switch 2 # Switch 2
switch_2 = Switch(hostname="switch_2", num_ports=6) switch_2 = Switch(config=dict(hostname="switch_2", num_ports=6))
switch_2.power_on() switch_2.power_on()
network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.network_interface[6]) network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.network_interface[6])
router_1.enable_port(2) router_1.enable_port(2)
# Client 1 # Client 1
client_1 = Computer( client_1 = Computer(config=dict(
hostname="client_1", hostname="client_1",
ip_address="192.168.2.2", ip_address="192.168.2.2",
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.2.1", default_gateway="192.168.2.1",
start_up_duration=0, start_up_duration=0,
) ))
client_1.power_on() client_1.power_on()
network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1]) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1])
# Server 1 # Server 1
server_1 = Server( server_1 = Server(config=dict(
hostname="server_1", hostname="server_1",
ip_address="192.168.1.2", ip_address="192.168.1.2",
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
start_up_duration=0, start_up_duration=0,
) ))
server_1.power_on() server_1.power_on()
network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.network_interface[1]) network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.network_interface[1])

View File

@@ -41,7 +41,7 @@ def test_multi_nic():
"""Tests that Computers with multiple NICs can ping each other and the data go across the correct links.""" """Tests that Computers with multiple NICs can ping each other and the data go across the correct links."""
network = Network() network = Network()
node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0) node_a = Computer(config=dict(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0))
node_a.power_on() node_a.power_on()
node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0) node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0)

View File

@@ -338,7 +338,7 @@ def test_database_client_cannot_query_offline_database_server(uc2_network):
assert db_connection.query("INSERT") is True assert db_connection.query("INSERT") is True
db_server.power_off() db_server.power_off()
for i in range(db_server.shut_down_duration + 1): for i in range(db_server.config.shut_down_duration + 1):
uc2_network.apply_timestep(timestep=i) uc2_network.apply_timestep(timestep=i)
assert db_server.operating_state is NodeOperatingState.OFF assert db_server.operating_state is NodeOperatingState.OFF

View File

@@ -87,7 +87,7 @@ def test_ftp_client_tries_to_connect_to_offline_server(ftp_client_and_ftp_server
server.power_off() server.power_off()
for i in range(server.shut_down_duration + 1): for i in range(server.config.shut_down_duration + 1):
server.apply_timestep(timestep=i) server.apply_timestep(timestep=i)
assert ftp_client.operating_state == ServiceOperatingState.RUNNING assert ftp_client.operating_state == ServiceOperatingState.RUNNING

View File

@@ -140,9 +140,9 @@ class TestDataManipulationGreenRequests:
client_1 = net.get_node_by_hostname("client_1") client_1 = net.get_node_by_hostname("client_1")
client_2 = net.get_node_by_hostname("client_2") client_2 = net.get_node_by_hostname("client_2")
client_1.shut_down_duration = 0 client_1.config.shut_down_duration = 0
client_1.power_off() client_1.power_off()
client_2.shut_down_duration = 0 client_2.config.shut_down_duration = 0
client_2.power_off() client_2.power_off()
client_1_browser_execute_off = net.apply_request(["node", "client_1", "application", "WebBrowser", "execute"]) client_1_browser_execute_off = net.apply_request(["node", "client_1", "application", "WebBrowser", "execute"])