-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathTunnelDevice.cs
158 lines (138 loc) · 4.95 KB
/
TunnelDevice.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
using SharpPcap.Tunneling.WinTap;
using System;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Threading;
using SharpPcap.Tunneling.Unix;
using System.Threading.Tasks;
using System.Net;
using Microsoft.Win32.SafeHandles;
namespace SharpPcap.Tunneling
{
public partial class TunnelDevice : BaseLiveDevice, ILiveDevice
{
private static readonly ITunnelDriver Driver = GetDriver();
private static ITunnelDriver GetDriver()
{
if (
#if NET6_0_OR_GREATER
OperatingSystem.IsWindows()
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
#endif
)
{
return WinTapDriver.Instance;
}
return TuntapDriver.Instance;
}
private readonly NetworkInterface Interface;
private readonly IPAddressConfiguration AddressConfiguration;
private Stream Stream;
private SafeFileHandle FileHandle;
protected Stream GetFileStream()
{
return Stream ?? throw new DeviceNotReadyException("Device not open");
}
protected SafeFileHandle GetFileHandle()
{
return FileHandle ?? throw new DeviceNotReadyException("Device not open");
}
public string Name => "tap:" + Interface.Name;
public string FriendlyName => Interface.Name;
public string Description => Interface.Description;
public string LastError => null;
public Version Version
{
get => Driver.GetVersion(Interface, GetFileHandle());
}
public PhysicalAddress MacAddress => Interface.GetPhysicalAddress();
public TunnelDevice(NetworkInterface networkInterface, IPAddressConfiguration address = null)
{
this.Interface = networkInterface;
// Copy configuration
this.AddressConfiguration = new IPAddressConfiguration()
{
Address = address?.Address,
IPv4Mask = address?.IPv4Mask ?? new IPAddress(new byte[] { 255, 255, 255, 0 }),
};
}
public static NetworkInterface[] GetTunnelInterfaces()
{
var nics = NetworkInterface.GetAllNetworkInterfaces();
return nics.Where(Driver.IsTunnelInterface)
.OrderBy(n => n.Id)
.ToArray();
}
public void Open(DeviceConfiguration configuration)
{
if (Stream != null)
{
return;
}
var fs = Driver.Open(Interface, AddressConfiguration, configuration);
Stream = Stream.Synchronized(fs);
FileHandle = fs.SafeFileHandle;
ReadTimeout = TimeSpan.FromMilliseconds(configuration.ReadTimeout);
Snaplen = configuration.Snaplen;
}
public override void Close()
{
base.Close();
Stream?.Close();
Stream = null;
FileHandle = null;
}
private int Snaplen = Pcap.MAX_PACKET_SIZE;
private readonly byte[] ReadBuffer = new byte[0x4000];
protected override GetPacketStatus GetUnfilteredPacket(out PacketCapture e, TimeSpan timeout)
{
var fs = GetFileStream();
var cts = new CancellationTokenSource(timeout);
var task = fs.ReadAsync(ReadBuffer, 0, ReadBuffer.Length, cts.Token);
var index = Task.WaitAny(new[] { task }, timeout);
if (index == -1 || task.IsCanceled)
{
e = default;
return GetPacketStatus.ReadTimeout;
}
if (task.IsFaulted)
{
e = default;
return GetPacketStatus.Error;
}
if (task.Result == 0)
{
e = default;
return GetPacketStatus.NoRemainingPackets;
}
var data = new Span<byte>(ReadBuffer).Slice(0, Math.Min(task.Result, Snaplen));
e = new PacketCapture(this, new TunnelHeader(), data);
return GetPacketStatus.PacketRead;
}
protected override void CaptureLoop(CancellationToken token)
{
var fs = GetFileStream();
while (!token.IsCancellationRequested)
{
var task = fs.ReadAsync(ReadBuffer, 0, ReadBuffer.Length, token);
task.Wait();
if (!task.IsFaulted)
{
var data = new Span<byte>(ReadBuffer).Slice(0, task.Result);
var p = new PacketCapture(this, new TunnelHeader(), data);
RaiseOnPacketArrival(p);
}
}
}
public void SendPacket(ReadOnlySpan<byte> p, ICaptureHeader header = null)
{
var data = p.ToArray();
var fs = GetFileStream();
fs.Write(data, 0, data.Length);
fs.Flush();
}
}
}