1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Peripherals.Wireless; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Peripherals; 13 using Antmicro.Renode.Peripherals.Network; 14 using Antmicro.Renode.Exceptions; 15 using Antmicro.Renode.Tools.Network; 16 17 namespace Antmicro.Renode.Plugins.WiresharkPlugin 18 { 19 public class Wireshark : IHostMachineElement, IExternal 20 { Wireshark(string sinkName, LinkLayer layer, string wiresharkPath)21 public Wireshark(string sinkName, LinkLayer layer, string wiresharkPath) 22 { 23 currentEmulation = EmulationManager.Instance.CurrentEmulation; 24 EmulationManager.Instance.EmulationChanged += ClearLog; 25 currentEmulation.MachineRemoved += OnMachineRemoved; 26 wiresharkSinkName = sinkName; 27 bleSniffer = new BLESniffer(); 28 wiresharkSender = new WiresharkSender(wiresharkSinkName, (uint)layer, wiresharkPath); 29 this.layer = layer; 30 } 31 LogToWireshark(INetworkLog<INetworkInterface> reporter)32 public void LogToWireshark(INetworkLog<INetworkInterface> reporter) 33 { 34 lock(innerLock) 35 { 36 if(IsConfiguredForMediumType(reporter)) 37 { 38 AddMedium(reporter); 39 } 40 } 41 } 42 LogToWireshark(INetworkLog<INetworkInterface> reporter, INetworkInterface iface)43 public void LogToWireshark(INetworkLog<INetworkInterface> reporter, INetworkInterface iface) 44 { 45 lock(innerLock) 46 { 47 if(IsConfiguredForMediumType(reporter)) 48 { 49 AddInterface(reporter, iface); 50 } 51 } 52 } 53 DetachFrom(INetworkLog<INetworkInterface> reporter)54 public void DetachFrom(INetworkLog<INetworkInterface> reporter) 55 { 56 DetachMedium(reporter); 57 } 58 DetachFrom(INetworkInterface iface)59 public void DetachFrom(INetworkInterface iface) 60 { 61 DetachInterface(iface); 62 } 63 Run()64 public void Run() 65 { 66 lock(innerLock) 67 { 68 if(!wiresharkSender.TryOpenWireshark()) 69 { 70 throw new RecoverableException("Wireshark is already running."); 71 } 72 } 73 } 74 IsConfiguredForMediumType(INetworkLog<INetworkInterface> medium)75 private bool IsConfiguredForMediumType(INetworkLog<INetworkInterface> medium) 76 { 77 var typeOfInterface = medium.GetType(); 78 79 lock(innerLock) 80 { 81 if(linkLayerToMedium[layer] == typeOfInterface) 82 { 83 return true; 84 } 85 86 } 87 88 throw new RecoverableException($"Cannot log {typeOfInterface.Name} traffic to {layer}-configured Wireshark."); 89 } 90 DetachMedium(INetworkLog<INetworkInterface> reporter)91 private void DetachMedium(INetworkLog<INetworkInterface> reporter) 92 { 93 lock(innerLock) 94 { 95 if(observedMedium.Contains(reporter)) 96 { 97 observedMedium.Remove(reporter); 98 reporter.FrameProcessed -= SendProcessedFrame; 99 } 100 else 101 { 102 throw new RecoverableException("Wireshark doesn't contain this medium"); 103 } 104 } 105 } 106 DetachInterface(INetworkInterface iface)107 private void DetachInterface(INetworkInterface iface) 108 { 109 var removed = false; 110 111 lock(innerLock) 112 { 113 foreach(var i in observedInterfaces) 114 { 115 if(i.Value.Contains(iface)) 116 { 117 i.Value.Remove(iface); 118 removed = true; 119 } 120 } 121 } 122 123 if(!removed) 124 { 125 throw new RecoverableException("Wireshark doesn't contain this interface"); 126 } 127 } 128 AddMedium(INetworkLog<INetworkInterface> reporter)129 private void AddMedium(INetworkLog<INetworkInterface> reporter) 130 { 131 lock(innerLock) 132 { 133 if(!observedMedium.Contains(reporter)) 134 { 135 observedMedium.Add(reporter); 136 wiresharkSender.TryOpenWireshark(); 137 reporter.FrameProcessed += SendProcessedFrame; 138 } 139 else 140 { 141 if(!wiresharkSender.TryOpenWireshark()) 142 { 143 throw new RecoverableException("The medium is already being logged in this Wireshark instance."); 144 } 145 } 146 } 147 } 148 AddInterface(INetworkLog<INetworkInterface> reporter, INetworkInterface iface)149 private void AddInterface(INetworkLog<INetworkInterface> reporter, INetworkInterface iface) 150 { 151 lock(innerLock) 152 { 153 if(observedInterfaces.ContainsKey(reporter)) 154 { 155 if(!observedInterfaces[reporter].Contains(iface)) 156 { 157 observedInterfaces[reporter].Add(iface); 158 wiresharkSender.TryOpenWireshark(); 159 reporter.FrameTransmitted += SendTransmittedFrame; 160 reporter.FrameProcessed += SendTransmittedFrame; 161 } 162 else 163 { 164 if(!wiresharkSender.TryOpenWireshark()) 165 { 166 throw new RecoverableException("The interface is already being logged in this Wireshark instance."); 167 } 168 } 169 } 170 else 171 { 172 observedInterfaces.Add(reporter, new List<INetworkInterface>() { iface }); 173 wiresharkSender.TryOpenWireshark(); 174 reporter.FrameTransmitted += SendTransmittedFrame; 175 reporter.FrameProcessed += SendTransmittedFrame; 176 } 177 } 178 } 179 ClearLog()180 private void ClearLog() 181 { 182 lock(innerLock) 183 { 184 observedInterfaces.Clear(); 185 observedMedium.Clear(); 186 wiresharkSender.CloseWireshark(); 187 wiresharkSender.ClearPipe(); 188 } 189 } 190 OnMachineRemoved(IMachine machine)191 private void OnMachineRemoved(IMachine machine) 192 { 193 lock(innerLock) 194 { 195 var observedCopy = new Dictionary<IExternal, List<INetworkInterface>>(observedInterfaces); 196 197 foreach(var external in observedCopy) 198 { 199 foreach(var iface in external.Value.ToList()) 200 { 201 if(iface is IPeripheral && machine.IsRegistered((IPeripheral)iface)) 202 { 203 observedInterfaces[external.Key].Remove(iface); 204 } 205 } 206 207 if(observedInterfaces[external.Key].Count == 0) 208 { 209 observedInterfaces.Remove(external.Key); 210 } 211 } 212 213 if(observedInterfaces.Count == 0 && observedMedium.Count == 0) 214 { 215 currentEmulation.MachineRemoved -= OnMachineRemoved; 216 ClearLog(); 217 currentEmulation.HostMachine.RemoveHostMachineElement(this); 218 } 219 } 220 } 221 SendProcessedFrame(IExternal reporter, INetworkInterface sender, byte[] buffer)222 private void SendProcessedFrame(IExternal reporter, INetworkInterface sender, byte[] buffer) 223 { 224 lock(innerLock) 225 { 226 if(linkLayerToMedium[layer] == typeof(BLEMedium)) 227 { 228 buffer = bleSniffer.InsertHeaderToPacket((IRadio)sender, buffer); 229 } 230 wiresharkSender.SendProcessedFrames(buffer); 231 } 232 } 233 SendTransmittedFrame(IExternal reporter, INetworkInterface sender, INetworkInterface receiver, byte[] buffer)234 private void SendTransmittedFrame(IExternal reporter, INetworkInterface sender, INetworkInterface receiver, byte[] buffer) 235 { 236 lock(innerLock) 237 { 238 if(observedInterfaces.ContainsKey(reporter) 239 && (observedInterfaces[reporter].Contains(sender) || observedInterfaces[reporter].Contains(receiver))) 240 { 241 wiresharkSender.SendReportedFrames(buffer); 242 } 243 } 244 } 245 SendTransmittedFrame(IExternal reporter, INetworkInterface sender, byte[] buffer)246 private void SendTransmittedFrame(IExternal reporter, INetworkInterface sender, byte[] buffer) 247 { 248 lock(innerLock) 249 { 250 if(observedInterfaces.ContainsKey(reporter) && observedInterfaces[reporter].Contains(sender)) 251 { 252 wiresharkSender.SendReportedFrames(buffer); 253 } 254 } 255 } 256 257 private readonly object innerLock = new object(); 258 private readonly BLESniffer bleSniffer; 259 private WiresharkSender wiresharkSender; 260 private string wiresharkSinkName; 261 private Dictionary<IExternal, List<INetworkInterface>> observedInterfaces = new Dictionary<IExternal, List<INetworkInterface>>(); 262 private HashSet<IExternal> observedMedium = new HashSet<IExternal>(); 263 private LinkLayer layer; 264 private Emulation currentEmulation; 265 266 private readonly Dictionary<LinkLayer, Type> linkLayerToMedium = new Dictionary<LinkLayer, Type> 267 { 268 {LinkLayer.Ethernet, typeof(Switch)}, 269 {LinkLayer.IEEE802_15_4, typeof(IEEE802_15_4Medium)}, 270 {LinkLayer.Bluetooth_LE, typeof(BLEMedium)}, 271 {LinkLayer.CAN, typeof(CANHub)}, 272 }; 273 } 274 } 275