Merge branch 'dev' into feature/2519_Make-airspace-an-attribute-of-Simulation

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
Chris McCarthy
2024-05-01 10:22:44 +01:00
22 changed files with 2153 additions and 24 deletions

View File

@@ -0,0 +1,65 @@
game:
ports:
- ARP
protocols:
- ICMP
- TCP
- UDP
simulation:
network:
nodes:
- hostname: pc_1
type: computer
ip_address: 192.168.1.11
subnet_mask: 255.255.255.0
default_gateway: 192.168.1.1
- hostname: pc_2
type: computer
ip_address: 192.168.1.12
subnet_mask: 255.255.255.0
default_gateway: 192.168.1.1
- hostname: server_1
type: server
ip_address: 192.168.1.13
subnet_mask: 255.255.255.0
default_gateway: 192.168.1.1
- hostname: switch_1
type: switch
num_ports: 4
- hostname: router_1
type: router
num_ports: 1
ports:
1:
ip_address: 192.168.1.1
subnet_mask: 255.255.255.0
acl:
10:
action: PERMIT
src_ip: 192.168.1.0
src_wildcard_mask: 0.0.0.255
dst_ip: 192.168.1.1
dst_wildcard_mask: 0.0.0.0
links:
- endpoint_a_hostname: pc_1
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 1
- endpoint_a_hostname: pc_2
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 2
- endpoint_a_hostname: server_1
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 3
- endpoint_a_hostname: router_1
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 4

View File

@@ -0,0 +1,26 @@
game:
ports:
- ARP
protocols:
- ICMP
- TCP
- UDP
simulation:
network:
nodes:
- hostname: pc_1
type: computer
ip_address: 192.168.1.11
subnet_mask: 255.255.255.0
- hostname: server_1
type: server
ip_address: 192.168.1.13
subnet_mask: 255.255.255.0
links:
- endpoint_a_hostname: pc_1
endpoint_a_port: 1
endpoint_b_hostname: server_1
endpoint_b_port: 1

View File

@@ -0,0 +1,439 @@
game:
ports:
- ARP
- DNS
- HTTP
- POSTGRES_SERVER
protocols:
- ICMP
- TCP
- UDP
simulation:
network:
nodes:
# Home/Office Network
- hostname: pc_1
type: computer
ip_address: 192.168.1.11
subnet_mask: 255.255.255.0
default_gateway: 192.168.1.1
dns_server: 8.8.8.2
applications:
- type: DatabaseClient
options:
db_server_ip: 10.10.1.11
- type: WebBrowser
options:
target_url: http://sometech.ai
- hostname: pc_2
type: computer
ip_address: 192.168.1.12
subnet_mask: 255.255.255.0
default_gateway: 192.168.1.1
dns_server: 8.8.8.2
applications:
- type: DatabaseClient
options:
db_server_ip: 10.10.1.11
- type: WebBrowser
options:
target_url: http://sometech.ai
- hostname: server_1
type: server
ip_address: 192.168.1.13
subnet_mask: 255.255.255.0
default_gateway: 192.168.1.1
dns_server: 8.8.8.2
- hostname: switch_1
type: switch
num_ports: 4
- hostname: router_1
type: router
num_ports: 2
ports:
1:
ip_address: 192.168.1.1
subnet_mask: 255.255.255.0
2:
ip_address: 43.35.240.2
subnet_mask: 255.255.255.252
acl:
10:
action: PERMIT
default_route: # Default route to all external networks
next_hop_ip_address: 43.35.240.1 # NI 1 on icp_router
# ISP Network
- hostname: isp_rt
type: router
num_ports: 3
ports:
1:
ip_address: 43.35.240.1
subnet_mask: 255.255.255.252
2:
ip_address: 94.10.180.1
subnet_mask: 255.255.255.252
3:
ip_address: 8.8.8.1
subnet_mask: 255.255.255.252
acl:
10:
action: PERMIT
routes:
- address: 192.168.1.0 # Route to the Home/Office LAN
subnet_mask: 255.255.255.0
next_hop_ip_address: 43.35.240.2 # NI 2 on router_1
- address: 10.10.0.0 # Route to the SomeTech internal network
subnet_mask: 255.255.0.0
next_hop_ip_address: 94.10.180.2 # NI ext on some_tech_fw
- address: 94.10.180.6 # Route to the Web Server in the SomeTech DMZ
subnet_mask: 255.255.255.255
next_hop_ip_address: 94.10.180.2 # NI ext on some_tech_fw
- hostname: isp_dns_srv
type: server
ip_address: 8.8.8.2
subnet_mask: 255.255.255.252
default_gateway: 8.8.8.1
services:
- ref: dns_server
type: DNSServer
options:
domain_mapping:
sometech.ai: 94.10.180.6
# SomeTech Network
- hostname: some_tech_fw
type: firewall
ports:
external_port: # port 1
ip_address: 94.10.180.2
subnet_mask: 255.255.255.252
internal_port: # port 2
ip_address: 10.10.4.2
subnet_mask: 255.255.255.252
dmz_port: # port 3
ip_address: 94.10.180.5
subnet_mask: 255.255.255.252
acl:
internal_inbound_acl:
8: # Permit some_tech_web_srv to connect to Database service on some_tech_db_srv
action: PERMIT
src_ip: 94.10.180.6
src_wildcard_mask: 0.0.0.0
src_port: POSTGRES_SERVER
dst_ip: 10.10.1.11
dst_wildcard_mask: 0.0.0.0
dst_port: POSTGRES_SERVER
9: # Permit SomeTech to use HTTP
action: PERMIT
src_port: HTTP
10: # Permit SomeTech to use DNS
action: PERMIT
src_port: DNS
dst_port: DNS
internal_outbound_acl:
10: # Permit all internal outbound traffic
action: PERMIT
dmz_inbound_acl:
7: # Permit Database service on some_tech_db_srv to respond to some_tech_web_srv
action: PERMIT
src_ip: 10.10.1.11
src_port: POSTGRES_SERVER
src_wildcard_mask: 0.0.0.0
dst_ip: 94.10.180.6
dst_port: POSTGRES_SERVER
dst_wildcard_mask: 0.0.0.0
8: # Permit SomeTech DMZ to use ARP
action: PERMIT
src_port: ARP
dst_port: ARP
9: # Permit SomeTech DMZ to use DNS
action: PERMIT
src_port: DNS
dst_port: DNS
10: # Permit all inbound HTTP requests
action: PERMIT
dst_port: HTTP
dmz_outbound_acl:
7: # Permit some_tech_web_srv to connect to Database service on some_tech_db_srv
action: PERMIT
src_ip: 94.10.180.6
src_port: POSTGRES_SERVER
src_wildcard_mask: 0.0.0.0
dst_ip: 10.10.1.11
dst_port: POSTGRES_SERVER
dst_wildcard_mask: 0.0.0.0
8: # Permit SomeTech DMZ to use ARP
action: PERMIT
src_port: ARP
dst_port: ARP
9: # Permit SomeTech DMZ to use DNS
action: PERMIT
src_port: DNS
dst_port: DNS
10: # Permit all outbound HTTP requests
action: PERMIT
src_port: HTTP
default_route: # Default route to all external networks
next_hop_ip_address: 94.10.180.1 # NI 2 on isp_rt
routes:
- address: 10.10.0.0 # Route to the SomeTech internal LAN
subnet_mask: 255.255.0.0
next_hop_ip_address: 10.10.4.1 # NI 1 on some_tech_rt
- hostname: some_tech_web_srv
type: server
ip_address: 94.10.180.6
subnet_mask: 255.255.255.252
default_gateway: 94.10.180.5
dns_server: 8.8.8.2
services:
- ref: web_server
type: WebServer
applications:
- type: DatabaseClient
options:
db_server_ip: 10.10.1.11
- hostname: some_tech_rt
type: router
num_ports: 4
ports:
1:
ip_address: 10.10.1.1
subnet_mask: 255.255.255.0
2:
ip_address: 10.10.4.1
subnet_mask: 255.255.255.252
3:
ip_address: 10.10.3.1
subnet_mask: 255.255.255.0
4:
ip_address: 10.10.2.1
subnet_mask: 255.255.255.0
acl:
2: # Allow the some_tech_web_srv to connect to the Database Service on some_tech_db_srv
action: PERMIT
src_ip: 94.10.180.6
src_wildcard_mask: 0.0.0.0
src_port: POSTGRES_SERVER
dst_ip: 10.10.1.11
dst_wildcard_mask: 0.0.0.0
dst_port: POSTGRES_SERVER
3: # Allow the Database Service on some_tech_db_srv to respond to some_tech_web_srv
action: PERMIT
src_ip: 10.10.1.11
src_wildcard_mask: 0.0.0.0
src_port: POSTGRES_SERVER
dst_ip: 94.10.180.6
dst_wildcard_mask: 0.0.0.0
dst_port: POSTGRES_SERVER
4: # Prevent the Junior engineer from downloading files from the some_tech_storage_srv over FTP
action: DENY
src_ip: 10.10.2.12
src_wildcard_mask: 0.0.0.0
src_port: FTP
dst_ip: 10.10.1.12
dst_wildcard_mask: 0.0.0.0
dst_port: FTP
5: # Allow communication between Engineering and the DB & Storage subnet
action: PERMIT
src_ip: 10.10.2.0
src_wildcard_mask: 0.0.0.255
dst_ip: 10.10.1.0
dst_wildcard_mask: 0.0.0.255
6: # Allow communication between the DB & Storage subnet and Engineering
action: PERMIT
src_ip: 10.10.1.0
src_wildcard_mask: 0.0.0.255
dst_ip: 10.10.2.0
dst_wildcard_mask: 0.0.0.255
7: # Allow the SomeTech network to use HTTP
action: PERMIT
src_port: HTTP
dst_port: HTTP
8: # Allow the SomeTech internal network to use ARP
action: PERMIT
src_ip: 10.10.0.0
src_wildcard_mask: 0.0.255.255
src_port: ARP
9: # Allow the SomeTech internal network to use ICMP
action: PERMIT
src_ip: 10.10.0.0
src_wildcard_mask: 0.0.255.255
protocol: ICMP
10:
action: PERMIT
src_ip: 94.10.180.6
src_wildcard_mask: 0.0.0.0
src_port: HTTP
dst_ip: 10.10.0.0
dst_wildcard_mask: 0.0.255.255
dst_port: HTTP
11: # Permit SomeTech to use DNS
action: PERMIT
src_port: DNS
dst_port: DNS
default_route: # Default route to all external networks
next_hop_ip_address: 10.10.4.2 # NI int on some_tech_fw
- hostname: some_tech_data_sw
type: switch
num_ports: 3
- hostname: some_tech_hr_sw
type: switch
num_ports: 2
- hostname: some_tech_eng_sw
type: switch
num_ports: 3
- hostname: some_tech_db_srv
type: server
ip_address: 10.10.1.11
subnet_mask: 255.255.255.0
default_gateway: 10.10.1.1
dns_server: 8.8.8.2
services:
- type: DatabaseService
options:
backup_server_ip: 10.10.1.12 # The some_tech_storage_srv server
- type: FTPClient
- hostname: some_tech_storage_srv
type: server
ip_address: 10.10.1.12
subnet_mask: 255.255.255.0
default_gateway: 10.10.1.1
dns_server: 8.8.8.2
services:
- type: FTPServer
- hostname: some_tech_hr_1
type: computer
ip_address: 10.10.3.11
subnet_mask: 255.255.255.0
default_gateway: 10.10.3.1
dns_server: 8.8.8.2
applications:
- type: DatabaseClient
options:
db_server_ip: 10.10.1.11
- type: WebBrowser
options:
target_url: http://sometech.ai
- hostname: some_tech_snr_dev_pc
type: computer
ip_address: 10.10.2.11
subnet_mask: 255.255.255.0
default_gateway: 10.10.2.1
dns_server: 8.8.8.2
applications:
- type: DatabaseClient
options:
db_server_ip: 10.10.1.11
- type: WebBrowser
options:
target_url: http://sometech.ai
- hostname: some_tech_jnr_dev_pc
type: computer
ip_address: 10.10.2.12
subnet_mask: 255.255.255.0
default_gateway: 10.10.2.1
dns_server: 8.8.8.2
applications:
- type: DatabaseClient
options:
db_server_ip: 10.10.1.11
- type: WebBrowser
options:
target_url: http://sometech.ai
links:
# Home/Office Lan Links
- endpoint_a_hostname: pc_1
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 1
- endpoint_a_hostname: pc_2
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 2
- endpoint_a_hostname: server_1
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 3
- endpoint_a_hostname: router_1
endpoint_a_port: 1
endpoint_b_hostname: switch_1
endpoint_b_port: 4
# ISP Links
- endpoint_a_hostname: isp_rt
endpoint_a_port: 1
endpoint_b_hostname: router_1
endpoint_b_port: 2
- endpoint_a_hostname: isp_rt
endpoint_a_port: 2
endpoint_b_hostname: some_tech_fw
endpoint_b_port: 1
- endpoint_a_hostname: isp_rt
endpoint_a_port: 3
endpoint_b_hostname: isp_dns_srv
endpoint_b_port: 1
# SomeTech LAN Links
- endpoint_a_hostname: some_tech_fw
endpoint_a_port: 3
endpoint_b_hostname: some_tech_web_srv
endpoint_b_port: 1
- endpoint_a_hostname: some_tech_fw
endpoint_a_port: 2
endpoint_b_hostname: some_tech_rt
endpoint_b_port: 2
- endpoint_a_hostname: some_tech_rt
endpoint_a_port: 1
endpoint_b_hostname: some_tech_data_sw
endpoint_b_port: 3
- endpoint_a_hostname: some_tech_rt
endpoint_a_port: 3
endpoint_b_hostname: some_tech_hr_sw
endpoint_b_port: 2
- endpoint_a_hostname: some_tech_rt
endpoint_a_port: 4
endpoint_b_hostname: some_tech_eng_sw
endpoint_b_port: 3
- endpoint_a_hostname: some_tech_data_sw
endpoint_a_port: 1
endpoint_b_hostname: some_tech_db_srv
endpoint_b_port: 1
- endpoint_a_hostname: some_tech_data_sw
endpoint_a_port: 2
endpoint_b_hostname: some_tech_storage_srv
endpoint_b_port: 1
- endpoint_a_hostname: some_tech_hr_sw
endpoint_a_port: 1
endpoint_b_hostname: some_tech_hr_1
endpoint_b_port: 1
- endpoint_a_hostname: some_tech_eng_sw
endpoint_a_port: 1
endpoint_b_hostname: some_tech_snr_dev_pc
endpoint_b_port: 1
- endpoint_a_hostname: some_tech_eng_sw
endpoint_a_port: 2
endpoint_b_hostname: some_tech_jnr_dev_pc
endpoint_b_port: 1

View File

@@ -242,7 +242,7 @@ class PrimaiteGame:
hostname=node_cfg["hostname"],
ip_address=node_cfg["ip_address"],
subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")),
default_gateway=node_cfg["default_gateway"],
default_gateway=node_cfg.get("default_gateway"),
dns_server=node_cfg.get("dns_server", None),
operating_state=NodeOperatingState.ON
if not (p := node_cfg.get("operating_state"))
@@ -253,7 +253,7 @@ class PrimaiteGame:
hostname=node_cfg["hostname"],
ip_address=node_cfg["ip_address"],
subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")),
default_gateway=node_cfg["default_gateway"],
default_gateway=node_cfg.get("default_gateway"),
dns_server=node_cfg.get("dns_server", None),
operating_state=NodeOperatingState.ON
if not (p := node_cfg.get("operating_state"))

View File

@@ -404,7 +404,7 @@
" # don't flatten observations so that we can see what is going on\n",
" cfg['agents'][3]['agent_settings']['flatten_obs'] = False\n",
"\n",
"env = PrimaiteGymEnv(game_config = cfg)\n",
"env = PrimaiteGymEnv(env_config = cfg)\n",
"obs, info = env.reset()\n",
"print('env created successfully')\n",
"pprint(obs)"

View File

@@ -59,7 +59,7 @@
"metadata": {},
"outputs": [],
"source": [
"gym = PrimaiteGymEnv(game_config=cfg)"
"gym = PrimaiteGymEnv(env_config=cfg)"
]
},
{

View File

@@ -35,7 +35,6 @@ class PrimaiteGymEnv(gymnasium.Env):
"""Current game."""
self._agent_name = next(iter(self.game.rl_agents))
"""Name of the RL agent. Since there should only be one RL agent we can just pull the first and only key."""
self.episode_counter: int = 0
"""Current episode number."""
@@ -49,8 +48,8 @@ class PrimaiteGymEnv(gymnasium.Env):
# make ProxyAgent store the action chosen by the RL policy
step = self.game.step_counter
self.agent.store_action(action)
# apply_agent_actions accesses the action we just stored
self.game.pre_timestep()
# apply_agent_actions accesses the action we just stored
self.game.apply_agent_actions()
self.game.advance_timestep()
state = self.game.get_sim_state()
@@ -58,6 +57,7 @@ class PrimaiteGymEnv(gymnasium.Env):
next_obs = self._get_obs() # this doesn't update observation, just gets the current observation
reward = self.agent.reward_function.current_reward
_LOGGER.info(f"step: {self.game.step_counter}, Blue reward: {reward}")
terminated = False
truncated = self.game.calculate_truncated()
info = {
@@ -204,9 +204,13 @@ class PrimaiteRayMARLEnv(MultiAgentEnv):
def reset(self, *, seed: int = None, options: dict = None) -> Tuple[ObsType, Dict]:
"""Reset the environment."""
rewards = {name: agent.reward_function.total_reward for name, agent in self.agents.items()}
_LOGGER.info(f"Resetting environment, episode {self.episode_counter}, " f"avg. reward: {rewards}")
if self.io.settings.save_agent_actions:
all_agent_actions = {name: agent.action_history for name, agent in self.game.agents.items()}
self.io.write_agent_actions(agent_actions=all_agent_actions, episode=self.episode_counter)
self.episode_counter += 1
self.game: PrimaiteGame = PrimaiteGame.from_config(self.episode_scheduler(self.episode_counter))
self.game.setup_for_episode(episode=self.episode_counter)
@@ -244,6 +248,7 @@ class PrimaiteRayMARLEnv(MultiAgentEnv):
# 4. Get rewards
rewards = {name: agent.reward_function.current_reward for name, agent in self.agents.items()}
_LOGGER.info(f"step: {self.game.step_counter}, Rewards: {rewards}")
terminateds = {name: False for name, _ in self.agents.items()}
truncateds = {name: self.game.calculate_truncated() for name, _ in self.agents.items()}
infos = {name: {} for name, _ in self.agents.items()}

View File

@@ -7,7 +7,7 @@ from pydantic import BaseModel, ConfigDict
from primaite import getLogger, PRIMAITE_PATHS
from primaite.simulator import LogLevel, SIM_OUTPUT
from src.primaite.utils.primaite_config_utils import is_dev_mode
from primaite.utils.primaite_config_utils import is_dev_mode
_LOGGER = getLogger(__name__)

View File

@@ -330,7 +330,7 @@ class Firewall(Router):
# check if External Inbound ACL Rules permit frame
permitted, rule = self.external_inbound_acl.is_permitted(frame)
if not permitted:
self.sys_log.info(f"Frame blocked at interface {from_network_interface} by rule {rule}")
self.sys_log.info(f"Frame blocked at external inbound by rule {rule}")
return
self.software_manager.arp.add_arp_cache_entry(
ip_address=frame.ip.src_ip_address,
@@ -360,7 +360,7 @@ class Firewall(Router):
# check if External Outbound ACL Rules permit frame
permitted, rule = self.external_outbound_acl.is_permitted(frame=frame)
if not permitted:
self.sys_log.info(f"Frame blocked at interface {from_network_interface} by rule {rule}")
self.sys_log.info(f"Frame blocked at external outbound by rule {rule}")
return
self.process_frame(frame=frame, from_network_interface=from_network_interface)
@@ -380,7 +380,7 @@ class Firewall(Router):
# check if Internal Inbound ACL Rules permit frame
permitted, rule = self.internal_inbound_acl.is_permitted(frame=frame)
if not permitted:
self.sys_log.info(f"Frame blocked at interface {from_network_interface} by rule {rule}")
self.sys_log.info(f"Frame blocked at internal inbound by rule {rule}")
return
self.process_frame(frame=frame, from_network_interface=from_network_interface)
@@ -398,7 +398,7 @@ class Firewall(Router):
"""
permitted, rule = self.internal_outbound_acl.is_permitted(frame)
if not permitted:
self.sys_log.info(f"Frame blocked at interface {from_network_interface} by rule {rule}")
self.sys_log.info(f"Frame blocked at internal outbound by rule {rule}")
return
self.software_manager.arp.add_arp_cache_entry(
ip_address=frame.ip.src_ip_address,
@@ -432,7 +432,7 @@ class Firewall(Router):
# check if DMZ Inbound ACL Rules permit frame
permitted, rule = self.dmz_inbound_acl.is_permitted(frame=frame)
if not permitted:
self.sys_log.info(f"Frame blocked at interface {from_network_interface} by rule {rule}")
self.sys_log.info(f"Frame blocked at DMZ inbound by rule {rule}")
return
self.process_frame(frame=frame, from_network_interface=from_network_interface)
@@ -452,7 +452,7 @@ class Firewall(Router):
"""
permitted, rule = self.dmz_outbound_acl.is_permitted(frame)
if not permitted:
self.sys_log.info(f"Frame blocked at interface {from_network_interface} by rule {rule}")
self.sys_log.info(f"Frame blocked at DMZ outbound by rule {rule}")
return
self.software_manager.arp.add_arp_cache_entry(
ip_address=frame.ip.src_ip_address,
@@ -688,4 +688,9 @@ class Firewall(Router):
next_hop_ip_address=IPv4Address(route.get("next_hop_ip_address")),
metric=float(route.get("metric", 0)),
)
if "default_route" in cfg:
next_hop_ip_address = cfg["default_route"].get("next_hop_ip_address", None)
if next_hop_ip_address:
firewall.route_table.set_default_route_next_hop_ip_address(next_hop_ip_address)
return firewall

View File

@@ -1,5 +1,9 @@
from ipaddress import IPv4Address
import yaml
from primaite import getLogger, PRIMAITE_PATHS
from primaite.game.game import PrimaiteGame
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.host.host_node import NIC
@@ -15,6 +19,8 @@ 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.web_server.web_server import WebServer
_LOGGER = getLogger(__name__)
def client_server_routed() -> Network:
"""
@@ -279,3 +285,34 @@ def arcd_uc2_network() -> Network:
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.HTTP, dst_port=Port.HTTP, position=3)
return network
def _get_example_network(path: str) -> Network:
try:
with open(path, "r") as file:
cfg = yaml.safe_load(file)
except FileNotFoundError:
msg = f"Failed to locate example network config {path}. Run `primaite setup` to load the example config files."
_LOGGER.error(msg)
raise FileNotFoundError(msg)
game = PrimaiteGame.from_config(cfg)
return game.simulation.network
def client_server_p2p_network_example() -> Network:
"""Get the Client-Server P2P example network."""
path = PRIMAITE_PATHS.user_config_path / "example_config" / "client_server_p2p_network_example.yaml"
return _get_example_network(path)
def basic_lan_network_example() -> Network:
"""Get the basic LAN example network."""
path = PRIMAITE_PATHS.user_config_path / "example_config" / "basic_network_network_example.yaml"
return _get_example_network(path)
def multi_lan_internet_network_example() -> Network:
"""Get Multi-LAN with Internet example network."""
path = PRIMAITE_PATHS.user_config_path / "example_config" / "multi_lan_internet_network_example.yaml"
return _get_example_network(path)