#2248 - Initial work has been done on moving ICMP into services. still tidying up to be done. Need to fix tests too.
This commit is contained in:
67
src/primaite/simulator/network/hardware/nodes/host.py
Normal file
67
src/primaite/simulator/network/hardware/nodes/host.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from primaite.simulator.network.hardware.base import NIC, Node
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
from primaite.simulator.system.services.arp.host_arp import HostARP
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
from primaite.simulator.system.services.icmp.icmp import ICMP
|
||||
from primaite.simulator.system.services.ntp.ntp_client import NTPClient
|
||||
|
||||
|
||||
class Host(Node):
|
||||
"""
|
||||
A basic Host class.
|
||||
|
||||
Example:
|
||||
>>> pc_a = Host(
|
||||
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):
|
||||
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."""
|
||||
# ARP Service
|
||||
self.software_manager.install(HostARP)
|
||||
|
||||
# ICMP Service
|
||||
self.software_manager.install(ICMP)
|
||||
|
||||
# DNS Client
|
||||
self.software_manager.install(DNSClient)
|
||||
|
||||
# FTP Client
|
||||
self.software_manager.install(FTPClient)
|
||||
|
||||
# NTP Client
|
||||
self.software_manager.install(NTPClient)
|
||||
|
||||
# Web Browser
|
||||
self.software_manager.install(WebBrowser)
|
||||
|
||||
super()._install_system_software()
|
||||
@@ -8,10 +8,10 @@ from typing import Dict, List, Optional, Tuple, Union
|
||||
from prettytable import MARKDOWN, PrettyTable
|
||||
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
from primaite.simulator.network.hardware.base import ARPCache, ICMP, NIC, Node
|
||||
from primaite.simulator.network.hardware.base import ARPCache, NIC, Node
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.transmission.data_link_layer import EthernetHeader, Frame
|
||||
from primaite.simulator.network.transmission.network_layer import ICMPPacket, ICMPType, IPPacket, IPProtocol
|
||||
from primaite.simulator.network.transmission.network_layer import IPPacket, IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port, TCPHeader
|
||||
from primaite.simulator.system.core.sys_log import SysLog
|
||||
|
||||
@@ -628,96 +628,6 @@ class RouterARPCache(ARPCache):
|
||||
# return
|
||||
|
||||
|
||||
class RouterICMP(ICMP):
|
||||
"""
|
||||
A class to represent a router's Internet Control Message Protocol (ICMP) handler.
|
||||
|
||||
:param sys_log: System log for logging network events and errors.
|
||||
:type sys_log: SysLog
|
||||
:param arp_cache: The ARP cache for resolving MAC addresses.
|
||||
:type arp_cache: ARPCache
|
||||
:param router: The router to which this ICMP handler belongs.
|
||||
:type router: Router
|
||||
"""
|
||||
|
||||
router: Router
|
||||
|
||||
def __init__(self, sys_log: SysLog, arp_cache: ARPCache, router: Router):
|
||||
super().__init__(sys_log, arp_cache)
|
||||
self.router = router
|
||||
|
||||
def process_icmp(self, frame: Frame, from_nic: NIC, is_reattempt: bool = False):
|
||||
"""
|
||||
Process incoming ICMP frames based on ICMP type.
|
||||
|
||||
:param frame: The incoming frame to process.
|
||||
:param from_nic: The network interface where the frame is coming from.
|
||||
:param is_reattempt: Flag to indicate if the process is a reattempt.
|
||||
"""
|
||||
if frame.icmp.icmp_type == ICMPType.ECHO_REQUEST:
|
||||
# determine if request is for router interface or whether it needs to be routed
|
||||
|
||||
for nic in self.router.nics.values():
|
||||
if nic.ip_address == frame.ip.dst_ip_address:
|
||||
if nic.enabled:
|
||||
# reply to the request
|
||||
if not is_reattempt:
|
||||
self.sys_log.info(f"Received echo request from {frame.ip.src_ip_address}")
|
||||
target_mac_address = self.arp.get_arp_cache_mac_address(frame.ip.src_ip_address)
|
||||
src_nic = self.arp.get_arp_cache_nic(frame.ip.src_ip_address)
|
||||
tcp_header = TCPHeader(src_port=Port.ARP, dst_port=Port.ARP)
|
||||
|
||||
# Network Layer
|
||||
ip_packet = IPPacket(
|
||||
src_ip_address=nic.ip_address,
|
||||
dst_ip_address=frame.ip.src_ip_address,
|
||||
protocol=IPProtocol.ICMP,
|
||||
)
|
||||
# Data Link Layer
|
||||
ethernet_header = EthernetHeader(
|
||||
src_mac_addr=src_nic.mac_address, dst_mac_addr=target_mac_address
|
||||
)
|
||||
icmp_reply_packet = ICMPPacket(
|
||||
icmp_type=ICMPType.ECHO_REPLY,
|
||||
icmp_code=0,
|
||||
identifier=frame.icmp.identifier,
|
||||
sequence=frame.icmp.sequence + 1,
|
||||
)
|
||||
payload = secrets.token_urlsafe(int(32 / 1.3)) # Standard ICMP 32 bytes size
|
||||
frame = Frame(
|
||||
ethernet=ethernet_header,
|
||||
ip=ip_packet,
|
||||
tcp=tcp_header,
|
||||
icmp=icmp_reply_packet,
|
||||
payload=payload,
|
||||
)
|
||||
self.sys_log.info(f"Sending echo reply to {frame.ip.dst_ip_address}")
|
||||
|
||||
src_nic.send_frame(frame)
|
||||
return
|
||||
|
||||
# Route the frame
|
||||
self.router.process_frame(frame, from_nic)
|
||||
|
||||
elif frame.icmp.icmp_type == ICMPType.ECHO_REPLY:
|
||||
for nic in self.router.nics.values():
|
||||
if nic.ip_address == frame.ip.dst_ip_address:
|
||||
if nic.enabled:
|
||||
time = frame.transmission_duration()
|
||||
time_str = f"{time}ms" if time > 0 else "<1ms"
|
||||
self.sys_log.info(
|
||||
f"Reply from {frame.ip.src_ip_address}: "
|
||||
f"bytes={len(frame.payload)}, "
|
||||
f"time={time_str}, "
|
||||
f"TTL={frame.ip.ttl}"
|
||||
)
|
||||
if not self.request_replies.get(frame.icmp.identifier):
|
||||
self.request_replies[frame.icmp.identifier] = 0
|
||||
self.request_replies[frame.icmp.identifier] += 1
|
||||
|
||||
return
|
||||
# Route the frame
|
||||
self.router.process_frame(frame, from_nic)
|
||||
|
||||
|
||||
class RouterNIC(NIC):
|
||||
@@ -786,9 +696,10 @@ class Router(Node):
|
||||
kwargs["route_table"] = RouteTable(sys_log=kwargs["sys_log"])
|
||||
if not kwargs.get("arp"):
|
||||
kwargs["arp"] = RouterARPCache(sys_log=kwargs.get("sys_log"), router=self)
|
||||
if not kwargs.get("icmp"):
|
||||
kwargs["icmp"] = RouterICMP(sys_log=kwargs.get("sys_log"), arp_cache=kwargs.get("arp"), router=self)
|
||||
# if not kwargs.get("icmp"):
|
||||
# kwargs["icmp"] = RouterICMP(sys_log=kwargs.get("sys_log"), arp_cache=kwargs.get("arp"), router=self)
|
||||
super().__init__(hostname=hostname, num_ports=num_ports, **kwargs)
|
||||
# TODO: Install RoputerICMP
|
||||
for i in range(1, self.num_ports + 1):
|
||||
nic = RouterNIC(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0")
|
||||
self.connect_nic(nic)
|
||||
|
||||
Reference in New Issue
Block a user