-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathPcapInterface.cs
320 lines (279 loc) · 11.7 KB
/
PcapInterface.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
This file is part of SharpPcap.
SharpPcap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SharpPcap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with SharpPcap. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2005 Tamir Gal <[email protected]>
* Copyright 2009 Chris Morgan <[email protected]>
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Net;
using System.Net.NetworkInformation;
using static SharpPcap.LibPcap.PcapUnmanagedStructures;
namespace SharpPcap.LibPcap
{
/// <summary>
/// managed version of struct pcap_if
/// NOTE: we can't use pcap_if directly because the class contains
/// a pointer to pcap_if that will be freed when the
/// device memory is freed, so instead convert the unmanaged structure
/// to a managed one to avoid this issue
/// </summary>
public class PcapInterface
{
/// <value>
/// Name of the interface. Used internally when passed to pcap_open_live()
/// </value>
public string Name { get; internal set; }
/// <value>
/// Human readable interface name derived from System.Net.NetworkInformation.NetworkInterface.Name
/// </value>
public string FriendlyName { get; internal set; }
/// <value>
/// Text description of the interface as given by pcap/npcap
/// </value>
public string Description { get; internal set; }
/// <value>
/// Gateway address of this device
/// NOTE: May only be available on Windows
/// </value>
public List<IPAddress> GatewayAddresses { get; internal set; }
/// <value>
/// Addresses associated with this device
/// </value>
public List<PcapAddress> Addresses { get; internal set; }
/// <summary>
/// Credentials to use in case of remote pcap
/// </summary>
internal RemoteAuthentication Credentials { get; }
/// <value>
/// Pcap interface flags
/// </value>
public uint Flags { get; internal set; }
/// <summary>
/// MacAddress of the interface
/// </summary>
public PhysicalAddress MacAddress { get; }
internal PcapInterface(pcap_if pcapIf, NetworkInterface networkInterface, RemoteAuthentication credentials)
{
Name = pcapIf.Name;
Description = pcapIf.Description;
Flags = pcapIf.Flags;
Addresses = new List<PcapAddress>();
GatewayAddresses = new List<IPAddress>();
Credentials = credentials;
// retrieve addresses
var address = pcapIf.Addresses;
while (address != IntPtr.Zero)
{
// Marshal memory pointer into a sockaddr struct
var addr = Marshal.PtrToStructure<pcap_addr>(address);
PcapAddress newAddress = new PcapAddress(addr);
Addresses.Add(newAddress);
// is this a hardware address?
// if so we should set our MacAddress
if (newAddress.Addr?.type == Sockaddr.AddressTypes.HARDWARE)
{
if (MacAddress == null)
{
MacAddress = newAddress.Addr.hardwareAddress;
}
else if (!MacAddress.Equals(newAddress.Addr.hardwareAddress))
{
throw new InvalidOperationException("found multiple hardware addresses, existing addr "
+ MacAddress.ToString() + ", new address " + newAddress.Addr.hardwareAddress.ToString());
}
}
address = addr.Next; // move to the next address
}
// attempt to populate the mac address,
// friendly name etc of this device
if (networkInterface != null)
{
var ipProperties = networkInterface.GetIPProperties();
int gatewayAddressCount = ipProperties.GatewayAddresses.Count;
if (gatewayAddressCount != 0)
{
foreach (GatewayIPAddressInformation gatewayInfo in ipProperties.GatewayAddresses)
{
GatewayAddresses.Add(gatewayInfo.Address);
}
}
FriendlyName = networkInterface.Name;
PhysicalAddress mac = networkInterface.GetPhysicalAddress();
if (MacAddress == null && mac != null)
{
PcapAddress pcapAddress = new PcapAddress();
pcapAddress.Addr = new Sockaddr(mac);
Addresses.Add(pcapAddress);
if (pcapAddress.Addr.hardwareAddress.GetAddressBytes().Length != 0)
{
MacAddress = pcapAddress.Addr.hardwareAddress;
}
}
}
else if (
#if NET6_0_OR_GREATER
OperatingSystem.IsWindows()
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
#endif
)
{
FriendlyName = WindowsNativeMethods.GetInterfaceAlias(Name);
}
}
/// <summary>
/// ToString override
/// </summary>
/// <returns>
/// A <see cref="string"/>
/// </returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Name: {0}\n", Name);
if (FriendlyName != null)
{
sb.AppendFormat("FriendlyName: {0}\n", FriendlyName);
}
if (GatewayAddresses != null)
{
sb.AppendFormat("GatewayAddresses:\n");
int i = 0;
foreach (IPAddress gatewayAddr in GatewayAddresses)
{
sb.AppendFormat("{0}) {1}\n", i + 1, gatewayAddr);
i++;
}
}
sb.AppendFormat("Description: {0}\n", Description);
foreach (PcapAddress addr in Addresses)
{
sb.AppendFormat("Addresses:\n{0}\n", addr);
}
sb.AppendFormat("Flags: {0}\n", Flags);
return sb.ToString();
}
static public IReadOnlyList<PcapInterface> GetAllPcapInterfaces(IPEndPoint source, RemoteAuthentication credentials)
{
return GetAllPcapInterfaces("rpcap://" + source, credentials);
}
static public IReadOnlyList<PcapInterface> GetAllPcapInterfaces(string source, RemoteAuthentication credentials)
{
var devicePtr = IntPtr.Zero;
var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE);
var auth = RemoteAuthentication.CreateAuth(credentials);
try
{
var result = LibPcapSafeNativeMethods.pcap_findalldevs_ex(source, ref auth, ref devicePtr, errorBuffer);
if (result < 0)
{
throw new PcapException(errorBuffer.ToString());
}
}
catch (TypeLoadException ex)
{
throw new PlatformNotSupportedException(
"Operation is not supported on this platform.",
ex
);
}
var pcapInterfaces = GetAllPcapInterfaces(devicePtr, credentials);
// Free unmanaged memory allocation
LibPcapSafeNativeMethods.pcap_freealldevs(devicePtr);
return pcapInterfaces;
}
static public IReadOnlyList<PcapInterface> GetAllPcapInterfaces()
{
var devicePtr = IntPtr.Zero;
var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE);
int result = LibPcapSafeNativeMethods.pcap_findalldevs(ref devicePtr, errorBuffer);
if (result < 0)
{
throw new PcapException(errorBuffer.ToString());
}
var pcapInterfaces = GetAllPcapInterfaces(devicePtr, null);
// Free unmanaged memory allocation
LibPcapSafeNativeMethods.pcap_freealldevs(devicePtr);
return pcapInterfaces;
}
static private IReadOnlyList<PcapInterface> GetAllPcapInterfaces(IntPtr devicePtr, RemoteAuthentication credentials)
{
var list = new List<PcapInterface>();
var nics = NetworkInterface.GetAllNetworkInterfaces();
var nextDevPtr = devicePtr;
while (nextDevPtr != IntPtr.Zero)
{
// Marshal pointer into a struct
var pcap_if_unmanaged = Marshal.PtrToStructure<pcap_if>(nextDevPtr);
NetworkInterface networkInterface = null;
foreach (var nic in nics)
{
// if the name and id match then we have found the NetworkInterface
// that matches the PcapDevice
if (pcap_if_unmanaged.Name.EndsWith(nic.Id))
{
networkInterface = nic;
}
}
var pcap_if = new PcapInterface(pcap_if_unmanaged, networkInterface, credentials);
list.Add(pcap_if);
nextDevPtr = pcap_if_unmanaged.Next;
}
return list;
}
#region Timestamp
/// <summary>
/// Timestamps supported by this device
/// </summary>
///
/// <remarks>
/// Note: Live devices can have supported timestamps but offline devices
/// (such as file readers etc) do not. See https://www.tcpdump.org/manpages/pcap-tstamp.7.html
/// </remarks>
public System.Collections.Generic.List<PcapClock> TimestampsSupported
{
get
{
StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors
using (var handle = LibPcapSafeNativeMethods.pcap_create(Name, errbuf))
{
IntPtr typePtr = IntPtr.Zero;
// Note: typePtr must be freed with pcap_free_tstamp_types()
var typeCount = LibPcapSafeNativeMethods.pcap_list_tstamp_types(handle, ref typePtr);
var timestampTypes = new System.Collections.Generic.List<PcapClock>();
for (var i = 0; i < typeCount; i++)
{
var value = Marshal.ReadInt32(typePtr, i * sizeof(int));
var tsValue = (TimestampType)value;
timestampTypes.Add(new PcapClock(tsValue));
}
// Free unmanaged memory allocation
LibPcapSafeNativeMethods.pcap_free_tstamp_types(typePtr);
// per https://www.tcpdump.org/manpages/pcap_list_tstamp_types.3pcap.html
// PCAP_TSTAMP_HOST is the only supported version
if (typeCount == 0)
{
var tsValue = TimestampType.Host;
timestampTypes.Add(new PcapClock(tsValue));
}
return timestampTypes;
}
}
}
#endregion
}
}