1 // 2 // Copyright (c) 2010-2020 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.IO; 10 using System.Net; 11 using System.Net.NetworkInformation; 12 using System.Collections.Generic; 13 14 using PacketDotNet; 15 16 using Antmicro.Renode.Core; 17 using Antmicro.Renode.Core.Structure; 18 using Antmicro.Renode.Peripherals.Network; 19 using Antmicro.Renode.Logging; 20 using Antmicro.Renode.Exceptions; 21 22 using System.Linq; 23 24 namespace Antmicro.Renode.Network 25 { 26 public static class NetworkServerExtensions 27 { CreateNetworkServer(this Emulation emulation, string name, string ipAddress)28 public static void CreateNetworkServer(this Emulation emulation, string name, string ipAddress) 29 { 30 emulation.ExternalsManager.AddExternal(new NetworkServer(ipAddress), name); 31 } 32 } 33 34 public class NetworkServer : IExternal, IMACInterface, IHasChildren<IServerModule> 35 { NetworkServer(string ipAddress, string macAddress = null)36 public NetworkServer(string ipAddress, string macAddress = null) 37 { 38 if(!IPAddress.TryParse(ipAddress, out var parsedIP)) 39 { 40 new ConstructionException($"Invalid IP address: {ipAddress}"); 41 } 42 43 if(macAddress != null) 44 { 45 if(!MACAddress.TryParse(macAddress, out var parsedMAC)) 46 { 47 new ConstructionException($"Invalid MAC address: {macAddress}"); 48 } 49 MAC = parsedMAC; 50 } 51 else 52 { 53 MAC = new MACAddress(0xdeadbeef); 54 } 55 56 57 IP = parsedIP; 58 59 arpTable = new Dictionary<IPAddress, PhysicalAddress>(); 60 modules = new Dictionary<int, IServerModule>(); 61 modulesNames = new Dictionary<string, int>(); 62 63 this.Log(LogLevel.Info, "Network server started at IP {0}", IP); 64 } 65 GetNames()66 public IEnumerable<string> GetNames() 67 { 68 return modulesNames.Keys; 69 } 70 TryGetByName(string name, out bool success)71 public IServerModule TryGetByName(string name, out bool success) 72 { 73 if(!modulesNames.TryGetValue(name, out var port)) 74 { 75 success = false; 76 return null; 77 } 78 79 success = true; 80 return modules[port]; 81 } 82 RegisterModule(IServerModule module, int port, string name)83 public bool RegisterModule(IServerModule module, int port, string name) 84 { 85 if(modules.ContainsKey(port)) 86 { 87 this.Log(LogLevel.Error, "Couldn't register module on port {0} as it's already used", port); 88 return false; 89 } 90 91 if(modulesNames.ContainsKey(name)) 92 { 93 this.Log(LogLevel.Error, "Couldn't register module by name {0} as it's already used", name); 94 return false; 95 } 96 97 this.Log(LogLevel.Noisy, "Registering module on port {0}", port); 98 modules[port] = module; 99 modulesNames[name] = port; 100 return true; 101 } 102 ReceiveFrame(EthernetFrame frame)103 public void ReceiveFrame(EthernetFrame frame) 104 { 105 var ethernetPacket = frame.UnderlyingPacket; 106 107 this.Log(LogLevel.Noisy, "Ethernet packet details: {0}", frame); 108 #if DEBUG_PACKETS 109 this.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(frame.Bytes)); 110 #endif 111 112 switch(ethernetPacket.Type) 113 { 114 case EthernetPacketType.Arp: 115 if(TryHandleArp((ARPPacket)ethernetPacket.PayloadPacket, out var arpResponse)) 116 { 117 var ethernetResponse = new EthernetPacket((PhysicalAddress)MAC, ethernetPacket.SourceHwAddress, EthernetPacketType.None); 118 ethernetResponse.PayloadPacket = arpResponse; 119 120 this.Log(LogLevel.Noisy, "Sending response: {0}", ethernetResponse); 121 EthernetFrame.TryCreateEthernetFrame(ethernetResponse.Bytes, true, out var response); 122 FrameReady?.Invoke(response); 123 } 124 break; 125 126 case EthernetPacketType.IpV4: 127 var ipv4Packet = (IPv4Packet)ethernetPacket.PayloadPacket; 128 arpTable[ipv4Packet.SourceAddress] = ethernetPacket.SourceHwAddress; 129 HandleIPv4(ipv4Packet); 130 break; 131 132 default: 133 this.Log(LogLevel.Warning, "Unsupported packet type: {0}", ethernetPacket.Type); 134 break; 135 } 136 } 137 138 public MACAddress MAC { get; set; } 139 public IPAddress IP { get; set; } 140 141 public event Action<EthernetFrame> FrameReady; 142 HandleIPv4(IPv4Packet packet)143 private void HandleIPv4(IPv4Packet packet) 144 { 145 this.Log(LogLevel.Noisy, "Handling IPv4 packet: {0}", PacketToString(packet)); 146 147 switch(packet.Protocol) 148 { 149 case PacketDotNet.IPProtocolType.UDP: 150 HandleUdp((UdpPacket)packet.PayloadPacket); 151 break; 152 153 default: 154 this.Log(LogLevel.Warning, "Unsupported protocol: {0}", packet.Protocol); 155 break; 156 } 157 } 158 HandleUdp(UdpPacket packet)159 private void HandleUdp(UdpPacket packet) 160 { 161 this.Log(LogLevel.Noisy, "Handling UDP packet: {0}", PacketToString(packet)); 162 163 if(!modules.TryGetValue(packet.DestinationPort, out var module)) 164 { 165 this.Log(LogLevel.Warning, "Received UDP packet on port {0}, but no service is active", packet.DestinationPort); 166 return; 167 } 168 169 var src = new IPEndPoint(((IPv4Packet)packet.ParentPacket).SourceAddress, packet.SourcePort); 170 module.HandleUdp(src, packet, (s, r) => HandleUdpResponse(s, r)); 171 } 172 HandleUdpResponse(IPEndPoint source, UdpPacket response)173 private void HandleUdpResponse(IPEndPoint source, UdpPacket response) 174 { 175 var ipPacket = new IPv4Packet(IP, source.Address); 176 var ethernetPacket = new EthernetPacket((PhysicalAddress)MAC, arpTable[source.Address], EthernetPacketType.None); 177 178 ipPacket.PayloadPacket = response; 179 ethernetPacket.PayloadPacket = ipPacket; 180 response.UpdateCalculatedValues(); 181 182 this.Log(LogLevel.Noisy, "Sending UDP response: {0}", response); 183 184 EthernetFrame.TryCreateEthernetFrame(ethernetPacket.Bytes, true, out var ethernetFrame); 185 ethernetFrame.FillWithChecksums(new EtherType[] { EtherType.IpV4 }, new [] { IPProtocolType.UDP }); 186 187 FrameReady?.Invoke(ethernetFrame); 188 } 189 TryHandleArp(ARPPacket packet, out ARPPacket response)190 private bool TryHandleArp(ARPPacket packet, out ARPPacket response) 191 { 192 response = null; 193 var packetString = PacketToString(packet); 194 this.Log(LogLevel.Noisy, "Handling ARP packet: {0}", packetString); 195 196 if(packet.Operation != ARPOperation.Request) 197 { 198 this.Log(LogLevel.Warning, "Unsupported ARP packet: {0}", packetString); 199 return false; 200 } 201 202 if(!packet.TargetProtocolAddress.Equals(IP)) 203 { 204 this.Log(LogLevel.Noisy, "This ARP packet is not directed to me. Ignoring"); 205 return false; 206 } 207 208 response = new ARPPacket( 209 ARPOperation.Response, 210 packet.SenderHardwareAddress, 211 packet.SenderProtocolAddress, 212 (PhysicalAddress)MAC, 213 IP); 214 215 this.Log(LogLevel.Noisy, "Sending ARP response"); 216 return true; 217 } 218 PacketToString(Packet packet)219 private string PacketToString(Packet packet) 220 { 221 try 222 { 223 return packet.ToString(); 224 } 225 catch 226 { 227 return "<failed to decode packet>"; 228 } 229 } 230 231 private readonly Dictionary<int, IServerModule> modules; 232 private readonly Dictionary<string, int> modulesNames; 233 private readonly Dictionary<IPAddress, PhysicalAddress> arpTable; 234 } 235 } 236