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