mirror of
https://github.com/snltty/linker.git
synced 2025-10-23 17:13:12 +08:00
sync
This commit is contained in:
@@ -8,6 +8,7 @@ using System.Net.NetworkInformation;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace linker.libs
|
namespace linker.libs
|
||||||
{
|
{
|
||||||
@@ -184,6 +185,18 @@ namespace linker.libs
|
|||||||
{
|
{
|
||||||
return new IPAddress(BinaryPrimitives.ReverseEndianness(ip & maskvalue).ToBytes());
|
return new IPAddress(BinaryPrimitives.ReverseEndianness(ip & maskvalue).ToBytes());
|
||||||
}
|
}
|
||||||
|
public static IPAddress ToGatewayIP(IPAddress ip, byte maskLength)
|
||||||
|
{
|
||||||
|
uint network = BinaryPrimitives.ReadUInt32BigEndian(ToNetworkIp(ip, NetworkHelper.MaskValue(maskLength)).GetAddressBytes());
|
||||||
|
IPAddress gateway = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(network + 1)));
|
||||||
|
return gateway;
|
||||||
|
}
|
||||||
|
public static IPAddress ToGatewayIP(uint ip, uint maskValue)
|
||||||
|
{
|
||||||
|
uint network = BinaryPrimitives.ReadUInt32BigEndian(ToNetworkIp(ip, maskValue).GetAddressBytes());
|
||||||
|
IPAddress gateway = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(network + 1)));
|
||||||
|
return gateway;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool NotIPv6Support(IPAddress ip)
|
public static bool NotIPv6Support(IPAddress ip)
|
||||||
{
|
{
|
||||||
|
@@ -55,7 +55,7 @@ namespace linker.libs.extends
|
|||||||
public static bool GetIsBroadcastAddress(this ReadOnlySpan<byte> address)
|
public static bool GetIsBroadcastAddress(this ReadOnlySpan<byte> address)
|
||||||
{
|
{
|
||||||
uint ip = BinaryPrimitives.ReadUInt32BigEndian(address);
|
uint ip = BinaryPrimitives.ReadUInt32BigEndian(address);
|
||||||
return (ip >= 0xE0000000 && ip <= 0xEFFFFFFF) || ip == 0xFFFFFFFF;
|
return address[3] == 255 || (ip >= 0xE0000000 && ip <= 0xEFFFFFFF) || ip == 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Buffers.Binary;
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -10,25 +9,28 @@ namespace linker.tun.test
|
|||||||
public static LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
public static LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
linkerTunDeviceAdapter = new LinkerTunDeviceAdapter();
|
||||||
linkerTunDeviceAdapter = new LinkerTunDeviceAdapter(new LinkerTunDeviceCallback());
|
linkerTunDeviceAdapter.SetCallback(new LinkerTunDeviceCallback());
|
||||||
linkerTunDeviceAdapter.SetUp("linker111"
|
linkerTunDeviceAdapter.SetUp("linker111"
|
||||||
, Guid.Parse("dc6d4efa-2b53-41bd-a403-f416c9bf7129")
|
, Guid.Parse("dc6d4efa-2b53-41bd-a403-f416c9bf7129")
|
||||||
, IPAddress.Parse("192.168.55.2")
|
, IPAddress.Parse("192.168.55.2"), 24);
|
||||||
, IPAddress.Parse("192.168.55.1"), 24);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(linkerTunDeviceAdapter.Error))
|
if (string.IsNullOrWhiteSpace(linkerTunDeviceAdapter.Error))
|
||||||
{
|
{
|
||||||
Console.WriteLine(linkerTunDeviceAdapter.Error);
|
Console.WriteLine(linkerTunDeviceAdapter.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe sealed class LinkerTunDeviceCallback : ILinkerTunDeviceCallback
|
public sealed class LinkerTunDeviceCallback : ILinkerTunDeviceCallback
|
||||||
{
|
{
|
||||||
public void Callback(LinkerTunDevicPacket packet)
|
public async Task Callback(LinkerTunDevicPacket packet)
|
||||||
|
{
|
||||||
|
ICMPAnswer(packet);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
private unsafe void ICMPAnswer(LinkerTunDevicPacket packet)
|
||||||
{
|
{
|
||||||
Memory<byte> writableMemory = MemoryMarshal.AsMemory(packet.Packet);
|
Memory<byte> writableMemory = MemoryMarshal.AsMemory(packet.Packet);
|
||||||
fixed (byte* ptr = writableMemory.Span)
|
fixed (byte* ptr = writableMemory.Span)
|
||||||
@@ -36,12 +38,12 @@ namespace linker.tun.test
|
|||||||
//icmp && request
|
//icmp && request
|
||||||
if (ptr[9] == 1 && ptr[20] == 8)
|
if (ptr[9] == 1 && ptr[20] == 8)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"ICMP to {new IPAddress(writableMemory.Span.Slice(16,4))}");
|
Console.WriteLine($"ICMP to {new IPAddress(writableMemory.Span.Slice(16, 4))}");
|
||||||
|
|
||||||
uint dist = BinaryPrimitives.ReadUInt32LittleEndian(writableMemory.Span.Slice(16, 4));
|
uint dist = BinaryPrimitives.ReadUInt32LittleEndian(writableMemory.Span.Slice(16, 4));
|
||||||
|
|
||||||
//目的地址变源地址,
|
//目的地址变源地址,
|
||||||
* (uint*)(ptr + 16) = *(uint*)(ptr + 12);
|
*(uint*)(ptr + 16) = *(uint*)(ptr + 12);
|
||||||
//假装是网关回复的
|
//假装是网关回复的
|
||||||
*(uint*)(ptr + 12) = dist;
|
*(uint*)(ptr + 12) = dist;
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@ namespace linker.tun
|
|||||||
|
|
||||||
public interface ILinkerTunDeviceCallback
|
public interface ILinkerTunDeviceCallback
|
||||||
{
|
{
|
||||||
public void Callback(LinkerTunDevicPacket packet);
|
public Task Callback(LinkerTunDevicPacket packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct LinkerTunDevicPacket
|
public struct LinkerTunDevicPacket
|
||||||
@@ -33,8 +33,8 @@ namespace linker.tun
|
|||||||
|
|
||||||
public sealed class LinkerTunDeviceRouteItem
|
public sealed class LinkerTunDeviceRouteItem
|
||||||
{
|
{
|
||||||
public IPAddress Address { get; }
|
public IPAddress Address { get; set; }
|
||||||
public byte Mask { get; }
|
public byte Mask { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum LinkerTunDeviceStatus
|
public enum LinkerTunDeviceStatus
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
using System.Net;
|
using linker.libs;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace linker.tun
|
namespace linker.tun
|
||||||
{
|
{
|
||||||
public unsafe sealed class LinkerTunDeviceAdapter
|
public sealed class LinkerTunDeviceAdapter
|
||||||
{
|
{
|
||||||
private ILinkerTunDevice linkerTunDevice;
|
private ILinkerTunDevice linkerTunDevice;
|
||||||
private ILinkerTunDeviceCallback linkerTunDeviceCallback;
|
private ILinkerTunDeviceCallback linkerTunDeviceCallback;
|
||||||
@@ -13,31 +14,45 @@ namespace linker.tun
|
|||||||
|
|
||||||
|
|
||||||
private bool starting = false;
|
private bool starting = false;
|
||||||
public LinkerTunDeviceStatus Status => linkerTunDevice.Running ? LinkerTunDeviceStatus.Running : (starting ? LinkerTunDeviceStatus.Starting : LinkerTunDeviceStatus.Normal);
|
public LinkerTunDeviceStatus Status
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (linkerTunDevice == null) return LinkerTunDeviceStatus.Normal;
|
||||||
|
|
||||||
|
return linkerTunDevice.Running
|
||||||
|
? LinkerTunDeviceStatus.Running
|
||||||
|
: starting
|
||||||
|
? LinkerTunDeviceStatus.Starting
|
||||||
|
: LinkerTunDeviceStatus.Normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造
|
/// 构造
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="linkerTunDeviceCallback">数据包回调</param>
|
/// <param name="linkerTunDeviceCallback">数据包回调</param>
|
||||||
public LinkerTunDeviceAdapter(ILinkerTunDeviceCallback linkerTunDeviceCallback)
|
public LinkerTunDeviceAdapter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCallback(ILinkerTunDeviceCallback linkerTunDeviceCallback)
|
||||||
{
|
{
|
||||||
this.linkerTunDeviceCallback = linkerTunDeviceCallback;
|
this.linkerTunDeviceCallback = linkerTunDeviceCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开启网卡
|
/// 开启网卡
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">网卡名,如果是osx,需要utunX的命名,X是一个数字</param>
|
/// <param name="name">网卡名,如果是osx,需要utunX的命名,X是一个数字</param>
|
||||||
/// <param name="guid">windows的时候,需要一个固定guid,不然网卡编号一直递增,注册表一直新增记录</param>
|
/// <param name="guid">windows的时候,需要一个固定guid,不然网卡编号一直递增,注册表一直新增记录</param>
|
||||||
/// <param name="address">网卡IP</param>
|
/// <param name="address">网卡IP</param>
|
||||||
/// <param name="gateway">网卡网关</param>
|
|
||||||
/// <param name="mask">掩码。一般24即可</param>
|
/// <param name="mask">掩码。一般24即可</param>
|
||||||
public void SetUp(string name, Guid guid, IPAddress address, IPAddress gateway, byte mask)
|
public void SetUp(string name, Guid guid, IPAddress address, byte mask)
|
||||||
{
|
{
|
||||||
if (starting) return;
|
if (starting) return;
|
||||||
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
|
||||||
starting = true;
|
starting = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -55,7 +70,8 @@ namespace linker.tun
|
|||||||
if (linkerTunDevice != null)
|
if (linkerTunDevice != null)
|
||||||
{
|
{
|
||||||
linkerTunDevice.Shutdown();
|
linkerTunDevice.Shutdown();
|
||||||
linkerTunDevice.SetUp(address, gateway, mask, out error);
|
|
||||||
|
linkerTunDevice.SetUp(address, NetworkHelper.ToGatewayIP(address, mask), mask, out error);
|
||||||
if (string.IsNullOrWhiteSpace(error))
|
if (string.IsNullOrWhiteSpace(error))
|
||||||
{
|
{
|
||||||
cancellationTokenSource = new CancellationTokenSource();
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
@@ -63,28 +79,35 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
while (cancellationTokenSource.IsCancellationRequested == false)
|
while (cancellationTokenSource.IsCancellationRequested == false)
|
||||||
{
|
{
|
||||||
ReadOnlyMemory<byte> buffer = linkerTunDevice.Read();
|
try
|
||||||
if (buffer.Length == 0)
|
{
|
||||||
|
ReadOnlyMemory<byte> buffer = linkerTunDevice.Read();
|
||||||
|
if (buffer.Length == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkerTunDevicPacket packet = new LinkerTunDevicPacket();
|
||||||
|
packet.Packet = buffer;
|
||||||
|
packet.Version = (byte)(buffer.Span[0] >> 4 & 0b1111);
|
||||||
|
|
||||||
|
if (packet.Version == 4)
|
||||||
|
{
|
||||||
|
packet.SourceIPAddress = buffer.Slice(12, 4);
|
||||||
|
packet.DistIPAddress = buffer.Slice(16, 4);
|
||||||
|
}
|
||||||
|
else if (packet.Version == 6)
|
||||||
|
{
|
||||||
|
packet.SourceIPAddress = buffer.Slice(8, 16);
|
||||||
|
packet.DistIPAddress = buffer.Slice(24, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
await linkerTunDeviceCallback.Callback(packet);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkerTunDevicPacket packet = new LinkerTunDevicPacket();
|
|
||||||
packet.Packet = buffer;
|
|
||||||
packet.Version = (byte)(buffer.Span[0] >> 4 & 0b1111);
|
|
||||||
|
|
||||||
if (packet.Version == 4)
|
|
||||||
{
|
|
||||||
packet.SourceIPAddress = buffer.Slice(12, 4);
|
|
||||||
packet.DistIPAddress = buffer.Slice(16, 4);
|
|
||||||
}
|
|
||||||
else if (packet.Version == 6)
|
|
||||||
{
|
|
||||||
packet.SourceIPAddress = buffer.Slice(8, 16);
|
|
||||||
packet.DistIPAddress = buffer.Slice(24, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
linkerTunDeviceCallback.Callback(packet);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -157,7 +180,7 @@ namespace linker.tun
|
|||||||
/// <param name="addr">包头开始位置</param>
|
/// <param name="addr">包头开始位置</param>
|
||||||
/// <param name="count">包头长度</param>
|
/// <param name="count">包头长度</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ushort Checksum(ushort* addr, uint count)
|
public unsafe ushort Checksum(ushort* addr, uint count)
|
||||||
{
|
{
|
||||||
ulong sum = 0;
|
ulong sum = 0;
|
||||||
while (count > 1)
|
while (count > 1)
|
||||||
@@ -167,7 +190,7 @@ namespace linker.tun
|
|||||||
}
|
}
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
sum += (ulong)((*addr) & Ntohs(0xFF00));
|
sum += (ulong)((*addr) & ((((0xff00) & 0xff) << 8) | (((0xff00) & 0xff00) >> 8)));
|
||||||
}
|
}
|
||||||
while ((sum >> 16) != 0)
|
while ((sum >> 16) != 0)
|
||||||
{
|
{
|
||||||
@@ -176,9 +199,5 @@ namespace linker.tun
|
|||||||
sum = ~sum;
|
sum = ~sum;
|
||||||
return ((ushort)sum);
|
return ((ushort)sum);
|
||||||
}
|
}
|
||||||
private ushort Ntohs(ushort value)
|
|
||||||
{
|
|
||||||
return ((ushort)((((value) & 0xff) << 8) | (((value) & 0xff00) >> 8)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ using System.Buffers.Binary;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using static linker.libs.winapis.SECUR32;
|
||||||
|
|
||||||
namespace linker.tun
|
namespace linker.tun
|
||||||
{
|
{
|
||||||
@@ -12,10 +13,12 @@ namespace linker.tun
|
|||||||
public string Name => name;
|
public string Name => name;
|
||||||
public bool Running => session != 0;
|
public bool Running => session != 0;
|
||||||
|
|
||||||
private IntPtr waitHandle = IntPtr.Zero, adapter = IntPtr.Zero, session = IntPtr.Zero;
|
private IntPtr waitHandle = IntPtr.Zero, adapter = IntPtr.Zero, session = IntPtr.Zero, session1 = IntPtr.Zero;
|
||||||
private Guid guid;
|
private Guid guid;
|
||||||
private int interfaceNumber = 0;
|
private int interfaceNumber = 0;
|
||||||
|
|
||||||
|
private CancellationTokenSource tokenSource;
|
||||||
|
|
||||||
public LinkerWinTunDevice(string name, Guid guid)
|
public LinkerWinTunDevice(string name, Guid guid)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -24,6 +27,7 @@ namespace linker.tun
|
|||||||
|
|
||||||
public bool SetUp(IPAddress address, IPAddress gateway, byte prefixLength, out string error)
|
public bool SetUp(IPAddress address, IPAddress gateway, byte prefixLength, out string error)
|
||||||
{
|
{
|
||||||
|
|
||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
if (adapter != 0)
|
if (adapter != 0)
|
||||||
{
|
{
|
||||||
@@ -47,6 +51,11 @@ namespace linker.tun
|
|||||||
|
|
||||||
waitHandle = WintunGetReadWaitEvent(session);
|
waitHandle = WintunGetReadWaitEvent(session);
|
||||||
|
|
||||||
|
WintunSetLogger((WINTUN_LOGGER_LEVEL level, ulong timestamp,string message) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[{level}]->{timestamp}->{message}");
|
||||||
|
});
|
||||||
|
|
||||||
WintunGetAdapterLUID(adapter, out ulong luid);
|
WintunGetAdapterLUID(adapter, out ulong luid);
|
||||||
{
|
{
|
||||||
MIB_UNICASTIPADDRESS_ROW AddressRow = default;
|
MIB_UNICASTIPADDRESS_ROW AddressRow = default;
|
||||||
@@ -59,6 +68,7 @@ namespace linker.tun
|
|||||||
uint LastError = CreateUnicastIpAddressEntry(ref AddressRow);
|
uint LastError = CreateUnicastIpAddressEntry(ref AddressRow);
|
||||||
if (LastError != 0) throw new InvalidOperationException();
|
if (LastError != 0) throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
MIB_IPFORWARD_ROW2 row = default;
|
MIB_IPFORWARD_ROW2 row = default;
|
||||||
InitializeIpForwardEntry(ref row);
|
InitializeIpForwardEntry(ref row);
|
||||||
@@ -71,13 +81,20 @@ namespace linker.tun
|
|||||||
uint LastError = CreateIpForwardEntry2(ref row);
|
uint LastError = CreateIpForwardEntry2(ref row);
|
||||||
if (LastError != 0) throw new InvalidOperationException();
|
if (LastError != 0) throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
GetWindowsInterfaceNum();
|
GetWindowsInterfaceNum();
|
||||||
|
|
||||||
|
tokenSource = new CancellationTokenSource();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
|
tokenSource?.Cancel();
|
||||||
|
if (waitHandle != 0)
|
||||||
|
{
|
||||||
|
SetEvent(waitHandle);
|
||||||
|
waitHandle = 0;
|
||||||
|
}
|
||||||
if (session != 0)
|
if (session != 0)
|
||||||
{
|
{
|
||||||
WintunEndSession(session);
|
WintunEndSession(session);
|
||||||
@@ -126,8 +143,7 @@ namespace linker.tun
|
|||||||
private byte[] buffer = new byte[2 * 1024];
|
private byte[] buffer = new byte[2 * 1024];
|
||||||
public unsafe ReadOnlyMemory<byte> Read()
|
public unsafe ReadOnlyMemory<byte> Read()
|
||||||
{
|
{
|
||||||
if (session == 0) return Helper.EmptyArray;
|
for (; tokenSource.IsCancellationRequested == false;)
|
||||||
for (; ; )
|
|
||||||
{
|
{
|
||||||
IntPtr packet = WintunReceivePacket(session, out var packetSize);
|
IntPtr packet = WintunReceivePacket(session, out var packetSize);
|
||||||
if (packet != 0)
|
if (packet != 0)
|
||||||
@@ -144,6 +160,7 @@ namespace linker.tun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Helper.EmptyArray;
|
||||||
}
|
}
|
||||||
public unsafe bool Write(ReadOnlyMemory<byte> buffer)
|
public unsafe bool Write(ReadOnlyMemory<byte> buffer)
|
||||||
{
|
{
|
||||||
@@ -220,6 +237,8 @@ namespace linker.tun
|
|||||||
private static extern uint CreateIpForwardEntry2(ref MIB_IPFORWARD_ROW2 Row);
|
private static extern uint CreateIpForwardEntry2(ref MIB_IPFORWARD_ROW2 Row);
|
||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern bool SetEvent(IntPtr hEvent);
|
||||||
|
|
||||||
[DllImport("wintun.dll", SetLastError = true)]
|
[DllImport("wintun.dll", SetLastError = true)]
|
||||||
private static extern IntPtr WintunCreateAdapter(
|
private static extern IntPtr WintunCreateAdapter(
|
||||||
|
@@ -102,7 +102,7 @@ namespace linker.tunnel.connection
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓冲区大小
|
/// 缓冲区大小
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte BufferSize { get; }
|
public byte BufferSize { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 已连接
|
/// 已连接
|
||||||
|
@@ -250,6 +250,7 @@ namespace linker.tunnel.connection
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
ticks = 0;
|
ticks = 0;
|
||||||
|
@@ -68,7 +68,7 @@ namespace linker.tunnel.connection
|
|||||||
|
|
||||||
cancellationTokenSource = new CancellationTokenSource();
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
_ = ProcessWrite();
|
_ = ProcessWrite();
|
||||||
_ = ProcessHeart();
|
//_ = ProcessHeart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessWrite()
|
private async Task ProcessWrite()
|
||||||
|
@@ -187,10 +187,7 @@ namespace linker.tunnel.proxy
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
asyncUserUdpToken.Connection = tunnelToken.Connection;
|
asyncUserUdpToken.Connection = tunnelToken.Connection;
|
||||||
if (await ConnectionReceiveUdp(tunnelToken, asyncUserUdpToken).ConfigureAwait(false) == false)
|
await asyncUserUdpToken.SourceSocket.SendToAsync(tunnelToken.Proxy.Data, tunnelToken.Proxy.SourceEP).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await asyncUserUdpToken.SourceSocket.SendToAsync(tunnelToken.Proxy.Data, tunnelToken.Proxy.SourceEP).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -91,7 +91,6 @@ namespace linker.tunnel.transport
|
|||||||
if (length > 0)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
string key = bytes.AsMemory(0, length).GetString();
|
string key = bytes.AsMemory(0, length).GetString();
|
||||||
LoggerHelper.Instance.Debug(key);
|
|
||||||
if (distDic.TryRemove(key, out TaskCompletionSource<Socket> tcs))
|
if (distDic.TryRemove(key, out TaskCompletionSource<Socket> tcs))
|
||||||
{
|
{
|
||||||
await client.SendAsync(bytes.AsMemory(0, length));
|
await client.SendAsync(bytes.AsMemory(0, length));
|
||||||
|
@@ -49,9 +49,6 @@
|
|||||||
<None Update="msquic.dll" Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-arm64'">
|
<None Update="msquic.dll" Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-arm64'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="plugins\tuntap\tun2socks.exe" Condition="'$(Configuration)'=='Debug'">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="Plugins\Tuntap\wintun.dll" Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-arm64' or '$(Configuration)'=='Debug'">
|
<None Update="Plugins\Tuntap\wintun.dll" Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-arm64' or '$(Configuration)'=='Debug'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
@@ -62,6 +59,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\linker.tunnel\linker.tunnel.csproj" />
|
<ProjectReference Include="..\linker.tunnel\linker.tunnel.csproj" />
|
||||||
<ProjectReference Include="..\linker.libs\linker.libs.csproj" />
|
<ProjectReference Include="..\linker.libs\linker.libs.csproj" />
|
||||||
|
<ProjectReference Include="..\linker.tun\linker.tun.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using linker.libs.api;
|
using linker.libs.api;
|
||||||
using linker.plugins.tuntap.vea;
|
|
||||||
using linker.plugins.tuntap.messenger;
|
using linker.plugins.tuntap.messenger;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
using linker.libs.extends;
|
using linker.libs.extends;
|
||||||
@@ -8,9 +7,9 @@ using linker.config;
|
|||||||
using linker.tunnel.connection;
|
using linker.tunnel.connection;
|
||||||
using linker.plugins.tuntap.proxy;
|
using linker.plugins.tuntap.proxy;
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
using linker.plugins.server;
|
|
||||||
using linker.plugins.capi;
|
using linker.plugins.capi;
|
||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
|
using linker.plugins.tuntap.config;
|
||||||
|
|
||||||
namespace linker.plugins.tuntap
|
namespace linker.plugins.tuntap
|
||||||
{
|
{
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
using linker.config;
|
using linker.config;
|
||||||
using linker.plugins.tuntap.messenger;
|
using linker.plugins.tuntap.messenger;
|
||||||
using linker.plugins.tuntap.proxy;
|
using linker.plugins.tuntap.proxy;
|
||||||
using linker.plugins.tuntap.vea;
|
|
||||||
using linker.startup;
|
using linker.startup;
|
||||||
|
using linker.tun;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
@@ -23,12 +23,8 @@ namespace linker.plugins.tuntap
|
|||||||
|
|
||||||
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
|
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
|
||||||
{
|
{
|
||||||
//不同平台下的虚拟网卡
|
|
||||||
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<ITuntapVea, TuntapVeaWindows>();
|
|
||||||
if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<ITuntapVea, TuntapVeaLinux>();
|
|
||||||
if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<ITuntapVea, TuntapVeaMacOs>();
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<TuntapClientApiController>();
|
serviceCollection.AddSingleton<TuntapClientApiController>();
|
||||||
|
serviceCollection.AddSingleton<LinkerTunDeviceAdapter>();
|
||||||
serviceCollection.AddSingleton<TuntapTransfer>();
|
serviceCollection.AddSingleton<TuntapTransfer>();
|
||||||
serviceCollection.AddSingleton<TuntapProxy>();
|
serviceCollection.AddSingleton<TuntapProxy>();
|
||||||
|
|
||||||
|
@@ -2,18 +2,16 @@
|
|||||||
using linker.config;
|
using linker.config;
|
||||||
using linker.plugins.tuntap.messenger;
|
using linker.plugins.tuntap.messenger;
|
||||||
using linker.plugins.tuntap.proxy;
|
using linker.plugins.tuntap.proxy;
|
||||||
using linker.plugins.tuntap.vea;
|
|
||||||
using linker.libs;
|
using linker.libs;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
|
||||||
using linker.libs.extends;
|
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
using System;
|
using linker.plugins.tuntap.config;
|
||||||
|
using linker.tun;
|
||||||
|
|
||||||
namespace linker.plugins.tuntap
|
namespace linker.plugins.tuntap
|
||||||
{
|
{
|
||||||
@@ -21,31 +19,31 @@ namespace linker.plugins.tuntap
|
|||||||
{
|
{
|
||||||
private readonly MessengerSender messengerSender;
|
private readonly MessengerSender messengerSender;
|
||||||
private readonly ClientSignInState clientSignInState;
|
private readonly ClientSignInState clientSignInState;
|
||||||
private readonly ITuntapVea tuntapVea;
|
|
||||||
private readonly FileConfig config;
|
private readonly FileConfig config;
|
||||||
private readonly TuntapProxy tuntapProxy;
|
private readonly TuntapProxy tuntapProxy;
|
||||||
private readonly RunningConfig runningConfig;
|
private readonly RunningConfig runningConfig;
|
||||||
|
private readonly LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
||||||
|
|
||||||
|
private string interfaceName = "linker";
|
||||||
|
|
||||||
private uint infosVersion = 0;
|
private uint infosVersion = 0;
|
||||||
private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>();
|
|
||||||
public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos;
|
|
||||||
public uint InfosVersion => infosVersion;
|
public uint InfosVersion => infosVersion;
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>();
|
||||||
|
public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos;
|
||||||
|
|
||||||
private bool starting = false;
|
public TuntapStatus Status => (TuntapStatus)(byte)linkerTunDeviceAdapter.Status;
|
||||||
public TuntapStatus Status => tuntapVea.Running ? TuntapStatus.Running : (starting ? TuntapStatus.Starting : TuntapStatus.Normal);
|
|
||||||
|
|
||||||
public TuntapTransfer(MessengerSender messengerSender, ClientSignInState clientSignInState, ITuntapVea tuntapVea, FileConfig config, TuntapProxy tuntapProxy, RunningConfig runningConfig)
|
public TuntapTransfer(MessengerSender messengerSender, ClientSignInState clientSignInState, LinkerTunDeviceAdapter linkerTunDeviceAdapter, FileConfig config, TuntapProxy tuntapProxy, RunningConfig runningConfig)
|
||||||
{
|
{
|
||||||
this.messengerSender = messengerSender;
|
this.messengerSender = messengerSender;
|
||||||
this.clientSignInState = clientSignInState;
|
this.clientSignInState = clientSignInState;
|
||||||
this.tuntapVea = tuntapVea;
|
this.linkerTunDeviceAdapter = linkerTunDeviceAdapter;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.tuntapProxy = tuntapProxy;
|
this.tuntapProxy = tuntapProxy;
|
||||||
this.runningConfig = runningConfig;
|
this.runningConfig = runningConfig;
|
||||||
|
|
||||||
GetRouteIps();
|
GetRouteIps();
|
||||||
tuntapVea.Kill();
|
|
||||||
clientSignInState.NetworkEnabledHandle += (times) =>
|
clientSignInState.NetworkEnabledHandle += (times) =>
|
||||||
{
|
{
|
||||||
OnChange();
|
OnChange();
|
||||||
@@ -60,14 +58,16 @@ namespace linker.plugins.tuntap
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AppDomain.CurrentDomain.ProcessExit += (s, e) => OnExit();
|
linkerTunDeviceAdapter.SetCallback(tuntapProxy);
|
||||||
Console.CancelKeyPress += (s, e) => OnExit();
|
linkerTunDeviceAdapter.Shutdown();
|
||||||
|
AppDomain.CurrentDomain.ProcessExit += (s, e) => Shutdown();
|
||||||
|
Console.CancelKeyPress += (s, e) => Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 程序关闭
|
/// 程序关闭
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnExit()
|
private void Shutdown()
|
||||||
{
|
{
|
||||||
bool running = runningConfig.Data.Tuntap.Running;
|
bool running = runningConfig.Data.Tuntap.Running;
|
||||||
Stop();
|
Stop();
|
||||||
@@ -80,12 +80,7 @@ namespace linker.plugins.tuntap
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
if (BooleanHelper.CompareExchange(ref starting, true, false))
|
Task.Run(() =>
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
OnChange();
|
OnChange();
|
||||||
try
|
try
|
||||||
@@ -95,18 +90,13 @@ namespace linker.plugins.tuntap
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tuntapProxy.Start();
|
linkerTunDeviceAdapter.SetUp(interfaceName, runningConfig.Data.Tuntap.InterfaceGuid, runningConfig.Data.Tuntap.IP, 24);
|
||||||
while (tuntapProxy.LocalEndpoint == null)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = await tuntapVea.Run(tuntapProxy.LocalEndpoint.Port, runningConfig.Data.Tuntap.IP).ConfigureAwait(false);
|
|
||||||
runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running;
|
runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running;
|
||||||
runningConfig.Data.Update();
|
runningConfig.Data.Update();
|
||||||
if (result == false)
|
|
||||||
|
if (string.IsNullOrWhiteSpace(linkerTunDeviceAdapter.Error) == false)
|
||||||
{
|
{
|
||||||
Stop();
|
LoggerHelper.Instance.Error(linkerTunDeviceAdapter.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -115,7 +105,6 @@ namespace linker.plugins.tuntap
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BooleanHelper.CompareExchange(ref starting, false, true);
|
|
||||||
OnChange();
|
OnChange();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -125,15 +114,10 @@ namespace linker.plugins.tuntap
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
if (BooleanHelper.CompareExchange(ref starting, true, false))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tuntapProxy.Stop();
|
|
||||||
OnChange();
|
OnChange();
|
||||||
tuntapVea.Kill();
|
linkerTunDeviceAdapter.Shutdown();
|
||||||
runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running;
|
runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running;
|
||||||
runningConfig.Data.Update();
|
runningConfig.Data.Update();
|
||||||
}
|
}
|
||||||
@@ -146,7 +130,6 @@ namespace linker.plugins.tuntap
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BooleanHelper.CompareExchange(ref starting, false, true);
|
|
||||||
OnChange();
|
OnChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,7 +220,7 @@ namespace linker.plugins.tuntap
|
|||||||
Masks = runningConfig.Data.Tuntap.Masks,
|
Masks = runningConfig.Data.Tuntap.Masks,
|
||||||
MachineId = config.Data.Client.Id,
|
MachineId = config.Data.Client.Id,
|
||||||
Status = Status,
|
Status = Status,
|
||||||
Error = tuntapVea.Error,
|
Error = linkerTunDeviceAdapter.Error,
|
||||||
BufferSize = runningConfig.Data.Tuntap.BufferSize,
|
BufferSize = runningConfig.Data.Tuntap.BufferSize,
|
||||||
HostIP = GetHostIP()
|
HostIP = GetHostIP()
|
||||||
};
|
};
|
||||||
@@ -279,7 +262,7 @@ namespace linker.plugins.tuntap
|
|||||||
{
|
{
|
||||||
List<TuntapVeaLanIPAddressList> ipsList = ParseIPs(tuntapInfos.Values.ToList());
|
List<TuntapVeaLanIPAddressList> ipsList = ParseIPs(tuntapInfos.Values.ToList());
|
||||||
TuntapVeaLanIPAddress[] ips = ipsList.SelectMany(c => c.IPS).ToArray();
|
TuntapVeaLanIPAddress[] ips = ipsList.SelectMany(c => c.IPS).ToArray();
|
||||||
tuntapVea.DelRoute(ips);
|
linkerTunDeviceAdapter.DelRoute(ipsList.SelectMany(c => c.IPS).Select(c => new LinkerTunDeviceRouteItem { Address = c.OriginIPAddress, Mask = c.MaskLength }).ToArray());
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加路由
|
/// 添加路由
|
||||||
@@ -288,7 +271,7 @@ namespace linker.plugins.tuntap
|
|||||||
{
|
{
|
||||||
List<TuntapVeaLanIPAddressList> ipsList = ParseIPs(tuntapInfos.Values.ToList());
|
List<TuntapVeaLanIPAddressList> ipsList = ParseIPs(tuntapInfos.Values.ToList());
|
||||||
TuntapVeaLanIPAddress[] ips = ipsList.SelectMany(c => c.IPS).ToArray();
|
TuntapVeaLanIPAddress[] ips = ipsList.SelectMany(c => c.IPS).ToArray();
|
||||||
tuntapVea.AddRoute(ips, runningConfig.Data.Tuntap.IP);
|
linkerTunDeviceAdapter.AddRoute(ipsList.SelectMany(c => c.IPS).Select(c => new LinkerTunDeviceRouteItem { Address = c.OriginIPAddress, Mask = c.MaskLength }).ToArray(), runningConfig.Data.Tuntap.IP);
|
||||||
|
|
||||||
tuntapProxy.SetIPs(ipsList);
|
tuntapProxy.SetIPs(ipsList);
|
||||||
foreach (var item in tuntapInfos.Values)
|
foreach (var item in tuntapInfos.Values)
|
||||||
@@ -345,6 +328,7 @@ namespace linker.plugins.tuntap
|
|||||||
MaskValue = maskValue,
|
MaskValue = maskValue,
|
||||||
NetWork = ipInt & maskValue,
|
NetWork = ipInt & maskValue,
|
||||||
Broadcast = ipInt | (~maskValue),
|
Broadcast = ipInt | (~maskValue),
|
||||||
|
OriginIPAddress = ip,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,9 +345,8 @@ namespace linker.plugins.tuntap
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (tuntapVea.Running)
|
if (Status == TuntapStatus.Running)
|
||||||
{
|
{
|
||||||
await CheckProxy().ConfigureAwait(false);
|
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
await CheckInterface().ConfigureAwait(false);
|
await CheckInterface().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -377,33 +360,15 @@ namespace linker.plugins.tuntap
|
|||||||
}
|
}
|
||||||
private async Task CheckInterface()
|
private async Task CheckInterface()
|
||||||
{
|
{
|
||||||
NetworkInterface networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(c => c.Name == tuntapVea.InterfaceName);
|
NetworkInterface networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(c => c.Name == interfaceName);
|
||||||
if (networkInterface != null && networkInterface.OperationalStatus != OperationalStatus.Up)
|
if (networkInterface != null && networkInterface.OperationalStatus != OperationalStatus.Up)
|
||||||
{
|
{
|
||||||
LoggerHelper.Instance.Error($"tuntap inerface {tuntapVea.InterfaceName} is {networkInterface.OperationalStatus}, restarting");
|
LoggerHelper.Instance.Error($"tuntap inerface {interfaceName} is {networkInterface.OperationalStatus}, restarting");
|
||||||
Stop();
|
Stop();
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
Run();
|
Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async Task CheckProxy()
|
|
||||||
{
|
|
||||||
if (tuntapProxy.LocalEndpoint == null || tuntapProxy.LocalEndpoint.Port == 0) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var socket = new Socket(tuntapProxy.LocalEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
|
||||||
await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, tuntapProxy.LocalEndpoint.Port)).WaitAsync(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
|
|
||||||
socket.SafeClose();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Error($"tuntap proxy {ex.Message}, restarting");
|
|
||||||
Stop();
|
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
|
||||||
Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IPAddress GetHostIP()
|
private IPAddress GetHostIP()
|
||||||
{
|
{
|
||||||
string hostip = Environment.GetEnvironmentVariable("SNLTTY_LINKER_HOST_IP");
|
string hostip = Environment.GetEnvironmentVariable("SNLTTY_LINKER_HOST_IP");
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using linker.plugins.tuntap.config;
|
using linker.plugins.tuntap.config;
|
||||||
|
using MemoryPack;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
@@ -37,7 +38,66 @@ namespace linker.plugins.tuntap.config
|
|||||||
/// 是否在运行中
|
/// 是否在运行中
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Running { get; set; }
|
public bool Running { get; set; }
|
||||||
|
|
||||||
|
public Guid InterfaceGuid { get; set; } = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class TuntapVeaLanIPAddress
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ip,存小端
|
||||||
|
/// </summary>
|
||||||
|
public uint IPAddress { get; set; }
|
||||||
|
public byte MaskLength { get; set; }
|
||||||
|
public uint MaskValue { get; set; }
|
||||||
|
public uint NetWork { get; set; }
|
||||||
|
public uint Broadcast { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public IPAddress OriginIPAddress { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class TuntapVeaLanIPAddressList
|
||||||
|
{
|
||||||
|
public string MachineId { get; set; }
|
||||||
|
public List<TuntapVeaLanIPAddress> IPS { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TuntapStatus : byte
|
||||||
|
{
|
||||||
|
Normal = 0,
|
||||||
|
Starting = 1,
|
||||||
|
Running = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class TuntapInfo
|
||||||
|
{
|
||||||
|
public string MachineId { get; set; }
|
||||||
|
|
||||||
|
public TuntapStatus Status { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackAllowSerialize]
|
||||||
|
public IPAddress IP { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackAllowSerialize]
|
||||||
|
public IPAddress[] LanIPs { get; set; } = Array.Empty<IPAddress>();
|
||||||
|
public int[] Masks { get; set; } = Array.Empty<int>();
|
||||||
|
|
||||||
|
public string Error { get; set; }
|
||||||
|
|
||||||
|
public byte BufferSize { get; set; } = 3;
|
||||||
|
|
||||||
|
[MemoryPackAllowSerialize]
|
||||||
|
public IPAddress HostIP { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
using linker.plugins.signin.messenger;
|
using linker.plugins.signin.messenger;
|
||||||
using linker.plugins.tuntap.vea;
|
using linker.plugins.tuntap.config;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.messenger
|
namespace linker.plugins.tuntap.messenger
|
||||||
|
@@ -1,60 +1,48 @@
|
|||||||
using linker.client.config;
|
using linker.client.config;
|
||||||
using linker.config;
|
using linker.config;
|
||||||
using linker.plugins.relay;
|
using linker.plugins.relay;
|
||||||
using linker.plugins.tuntap.vea;
|
|
||||||
using linker.tunnel;
|
using linker.tunnel;
|
||||||
using linker.tunnel.connection;
|
using linker.tunnel.connection;
|
||||||
using linker.tunnel.proxy;
|
|
||||||
using linker.libs;
|
using linker.libs;
|
||||||
using linker.libs.extends;
|
using linker.libs.extends;
|
||||||
using linker.libs.socks5;
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using linker.plugins.tuntap.config;
|
||||||
|
using linker.tun;
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.proxy
|
namespace linker.plugins.tuntap.proxy
|
||||||
{
|
{
|
||||||
public sealed class TuntapProxy : TunnelProxy
|
public sealed class TuntapProxy : ILinkerTunDeviceCallback, ITunnelConnectionReceiveCallback
|
||||||
{
|
{
|
||||||
private readonly TunnelTransfer tunnelTransfer;
|
private readonly TunnelTransfer tunnelTransfer;
|
||||||
private readonly RelayTransfer relayTransfer;
|
private readonly RelayTransfer relayTransfer;
|
||||||
private readonly RunningConfig runningConfig;
|
private readonly RunningConfig runningConfig;
|
||||||
private readonly FileConfig config;
|
private readonly FileConfig config;
|
||||||
|
private readonly LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
||||||
private IPEndPoint proxyEP;
|
|
||||||
|
|
||||||
public override IPAddress UdpBindAdress { get; set; }
|
|
||||||
|
|
||||||
private uint[] maskValues = Array.Empty<uint>();
|
private uint[] maskValues = Array.Empty<uint>();
|
||||||
private readonly ConcurrentDictionary<uint, string> dic = new ConcurrentDictionary<uint, string>();
|
private readonly ConcurrentDictionary<uint, string> ip2MachineCic = new ConcurrentDictionary<uint, string>();
|
||||||
private readonly ConcurrentDictionary<uint, IPAddress> hostipCic = new ConcurrentDictionary<uint, IPAddress>();
|
private readonly ConcurrentDictionary<uint, IPAddress> hostipCic = new ConcurrentDictionary<uint, IPAddress>();
|
||||||
private readonly ConcurrentDictionary<string, ITunnelConnection> connections = new ConcurrentDictionary<string, ITunnelConnection>();
|
private readonly ConcurrentDictionary<string, ITunnelConnection> connections = new ConcurrentDictionary<string, ITunnelConnection>();
|
||||||
private readonly ConcurrentDictionary<string, SemaphoreSlim> dicLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
|
|
||||||
private ConcurrentDictionary<IPEndPoint, BroadcastCacheInfo> broadcastDic = new(new IPEndpointComparer());
|
|
||||||
|
|
||||||
public TuntapProxy(TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, RunningConfig runningConfig, FileConfig config)
|
SemaphoreSlim slimGlobal = new SemaphoreSlim(1);
|
||||||
|
private readonly ConcurrentDictionary<string, SemaphoreSlim> dicLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
|
||||||
|
|
||||||
|
public TuntapProxy(TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, RunningConfig runningConfig, FileConfig config, LinkerTunDeviceAdapter linkerTunDeviceAdapter)
|
||||||
{
|
{
|
||||||
this.tunnelTransfer = tunnelTransfer;
|
this.tunnelTransfer = tunnelTransfer;
|
||||||
this.relayTransfer = relayTransfer;
|
this.relayTransfer = relayTransfer;
|
||||||
this.runningConfig = runningConfig;
|
this.runningConfig = runningConfig;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.linkerTunDeviceAdapter = linkerTunDeviceAdapter;
|
||||||
|
|
||||||
//监听打洞连接成功
|
//监听打洞连接成功
|
||||||
tunnelTransfer.SetConnectedCallback("tuntap", OnConnected);
|
tunnelTransfer.SetConnectedCallback("tuntap", OnConnected);
|
||||||
//监听中继连接成功
|
//监听中继连接成功
|
||||||
relayTransfer.SetConnectedCallback("tuntap", OnConnected);
|
relayTransfer.SetConnectedCallback("tuntap", OnConnected);
|
||||||
}
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
if (proxyEP != null)
|
|
||||||
{
|
|
||||||
Stop(proxyEP.Port);
|
|
||||||
}
|
|
||||||
Start(new IPEndPoint(IPAddress.Any, 0), runningConfig.Data.Tuntap.BufferSize);
|
|
||||||
proxyEP = new IPEndPoint(IPAddress.Any, LocalEndpoint.Port);
|
|
||||||
|
|
||||||
ClearTask();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -71,8 +59,51 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
//connectionOld?.Dispose();
|
//connectionOld?.Dispose();
|
||||||
}
|
}
|
||||||
connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
|
connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
|
||||||
BindConnectionReceive(connection);
|
|
||||||
|
connection.BeginReceive(this, null, false);
|
||||||
}
|
}
|
||||||
|
public async Task Receive(ITunnelConnection connection, ReadOnlyMemory<byte> buffer, object state)
|
||||||
|
{
|
||||||
|
linkerTunDeviceAdapter.Write(buffer);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
public async Task Closed(ITunnelConnection connection, object state)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Callback(LinkerTunDevicPacket packet)
|
||||||
|
{
|
||||||
|
if (packet.Version == 4)
|
||||||
|
{
|
||||||
|
uint ip = BinaryPrimitives.ReadUInt32BigEndian(packet.DistIPAddress.Span);
|
||||||
|
if (packet.DistIPAddress.GetIsBroadcastAddress())
|
||||||
|
{
|
||||||
|
if (connections.IsEmpty == false)
|
||||||
|
{
|
||||||
|
await Task.WhenAll(connections.Values.Select(c => c.SendAsync(packet.Packet)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ITunnelConnection connection = await ConnectTunnel(ip);
|
||||||
|
if (connection != null)
|
||||||
|
{
|
||||||
|
await connection.SendAsync(packet.Packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (packet.Version == 6 && (packet.DistIPAddress.Span[0] & 0xFF) == 0xFF)
|
||||||
|
{
|
||||||
|
if (connections.IsEmpty == false)
|
||||||
|
{
|
||||||
|
await Task.WhenAll(connections.Values.Select(c => c.SendAsync(packet.Packet)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"IPV{packet.Version}->{new IPAddress(packet.SourceIPAddress.Span)}->{new IPAddress(packet.DistIPAddress.Span)}->{packet.Packet.Length}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置IP,等下有连接进来,用IP匹配,才能知道这个连接是要连谁
|
/// 设置IP,等下有连接进来,用IP匹配,才能知道这个连接是要连谁
|
||||||
@@ -80,197 +111,25 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
/// <param name="ips"></param>
|
/// <param name="ips"></param>
|
||||||
public void SetIPs(List<TuntapVeaLanIPAddressList> ips)
|
public void SetIPs(List<TuntapVeaLanIPAddressList> ips)
|
||||||
{
|
{
|
||||||
dic.Clear();
|
ip2MachineCic.Clear();
|
||||||
foreach (var item in ips)
|
foreach (var item in ips)
|
||||||
{
|
{
|
||||||
foreach (var ip in item.IPS)
|
foreach (var ip in item.IPS)
|
||||||
{
|
{
|
||||||
dic.AddOrUpdate(ip.NetWork, item.MachineId, (a, b) => item.MachineId);
|
ip2MachineCic.AddOrUpdate(ip.NetWork, item.MachineId, (a, b) => item.MachineId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maskValues = ips.SelectMany(c => c.IPS.Select(c => c.MaskValue)).Distinct().OrderBy(c => c).ToArray();
|
maskValues = ips.SelectMany(c => c.IPS.Select(c => c.MaskValue)).Distinct().OrderBy(c => c).ToArray();
|
||||||
UdpBindAdress = runningConfig.Data.Tuntap.IP;
|
|
||||||
}
|
}
|
||||||
public void SetIP(string machineId, uint ip)
|
public void SetIP(string machineId, uint ip)
|
||||||
{
|
{
|
||||||
dic.AddOrUpdate(ip, machineId, (a, b) => machineId);
|
ip2MachineCic.AddOrUpdate(ip, machineId, (a, b) => machineId);
|
||||||
|
|
||||||
UdpBindAdress = runningConfig.Data.Tuntap.IP;
|
|
||||||
}
|
}
|
||||||
public void SetHostIP(uint ip, IPAddress hostip)
|
public void SetHostIP(uint ip, IPAddress hostip)
|
||||||
{
|
{
|
||||||
hostipCic.AddOrUpdate(ip, hostip, (a, b) => hostip);
|
hostipCic.AddOrUpdate(ip, hostip, (a, b) => hostip);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tcp连接隧道
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override async ValueTask<bool> ConnectTunnelConnection(AsyncUserToken token)
|
|
||||||
{
|
|
||||||
int length = await token.Socket.ReceiveAsync(token.Buffer.AsMemory(), SocketFlags.None);
|
|
||||||
if (length == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
token.Proxy.Data = token.Buffer.AsMemory(0, length);
|
|
||||||
|
|
||||||
token.Proxy.TargetEP = null;
|
|
||||||
|
|
||||||
//步骤,request
|
|
||||||
token.Proxy.Rsv = (byte)Socks5EnumStep.Request;
|
|
||||||
if (await ReceiveCommandData(token) == false)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
await token.Socket.SendAsync(new byte[] { 0x05, 0x00 }).ConfigureAwait(false);
|
|
||||||
|
|
||||||
//步骤,command
|
|
||||||
token.Proxy.Data = Helper.EmptyArray;
|
|
||||||
token.Proxy.Rsv = (byte)Socks5EnumStep.Command;
|
|
||||||
if (await ReceiveCommandData(token).ConfigureAwait(false) == false)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Socks5EnumRequestCommand command = (Socks5EnumRequestCommand)token.Proxy.Data.Span[1];
|
|
||||||
|
|
||||||
//获取远端地址
|
|
||||||
ReadOnlyMemory<byte> ipArray = Socks5Parser.GetRemoteEndPoint(token.Proxy.Data, out Socks5EnumAddressType addressType, out ushort port, out int index);
|
|
||||||
token.Proxy.Data = token.Proxy.Data.Slice(index);
|
|
||||||
token.Proxy.TargetEP = new IPEndPoint(new IPAddress(ipArray.Span), port);
|
|
||||||
uint targetIP = BinaryPrimitives.ReadUInt32BigEndian(ipArray.Span);
|
|
||||||
|
|
||||||
//不支持域名 和 IPV6
|
|
||||||
if (addressType == Socks5EnumAddressType.Domain || addressType == Socks5EnumAddressType.IPV6)
|
|
||||||
{
|
|
||||||
byte[] response1 = Socks5Parser.MakeConnectResponse(new IPEndPoint(IPAddress.Any, 0), (byte)Socks5EnumResponseCommand.AddressNotAllow);
|
|
||||||
await token.Socket.SendAsync(response1.AsMemory()).ConfigureAwait(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//是UDP中继,不做连接操作,等UDP数据过去的时候再绑定
|
|
||||||
if (targetIP == 0 || command == Socks5EnumRequestCommand.UdpAssociate)
|
|
||||||
{
|
|
||||||
await token.Socket.SendAsync(Socks5Parser.MakeConnectResponse(new IPEndPoint(IPAddress.Any, proxyEP.Port), (byte)Socks5EnumResponseCommand.ConnecSuccess).AsMemory()).ConfigureAwait(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReplaceTargetIP(token.Proxy.TargetEP, targetIP);
|
|
||||||
token.Connection = await ConnectTunnel(targetIP).ConfigureAwait(false);
|
|
||||||
|
|
||||||
Socks5EnumResponseCommand resp = token.Connection != null && token.Connection.Connected ? Socks5EnumResponseCommand.ConnecSuccess : Socks5EnumResponseCommand.NetworkError;
|
|
||||||
byte[] response = Socks5Parser.MakeConnectResponse(new IPEndPoint(IPAddress.Any, 0), (byte)resp);
|
|
||||||
await token.Socket.SendAsync(response.AsMemory()).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// udp连接隧道
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override async ValueTask ConnectTunnelConnection(AsyncUserUdpToken token)
|
|
||||||
{
|
|
||||||
ReadOnlyMemory<byte> ipArray = Socks5Parser.GetRemoteEndPoint(token.Proxy.Data, out Socks5EnumAddressType addressType, out ushort port, out int index);
|
|
||||||
if (addressType == Socks5EnumAddressType.IPV6)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint targetIP = BinaryPrimitives.ReadUInt32BigEndian(ipArray.Span);
|
|
||||||
token.Proxy.TargetEP = new IPEndPoint(new IPAddress(ipArray.Span), port);
|
|
||||||
IPEndPoint target = new IPEndPoint(new IPAddress(ipArray.Span), port);
|
|
||||||
|
|
||||||
//解析出udp包的数据部分
|
|
||||||
token.Proxy.Data = Socks5Parser.GetUdpData(token.Proxy.Data);
|
|
||||||
|
|
||||||
//是广播消息
|
|
||||||
if (ipArray.Span[3] == 255 || token.Proxy.TargetEP.Address.GetIsBroadcastAddress())
|
|
||||||
{
|
|
||||||
token.Proxy.TargetEP.Address = IPAddress.Loopback;
|
|
||||||
|
|
||||||
//我们替换了IP,但是等下要回复UDP数据给socks5时,要用原来的IP,所以缓存一下,等下回复要用
|
|
||||||
if (broadcastDic.TryGetValue(token.Proxy.SourceEP, out BroadcastCacheInfo cache) == false)
|
|
||||||
{
|
|
||||||
cache = new BroadcastCacheInfo { TargetEP = target };
|
|
||||||
broadcastDic.TryAdd(token.Proxy.SourceEP, cache);
|
|
||||||
}
|
|
||||||
cache.LastTime = Environment.TickCount64;
|
|
||||||
|
|
||||||
//广播不去连接,直接获取已经有的所有连接
|
|
||||||
token.Connections = connections.Values.ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReplaceTargetIP(token.Proxy.TargetEP, targetIP);
|
|
||||||
token.Connection = await ConnectTunnel(targetIP).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// //在docker内,我们不应该直接访问自己的虚拟IP,而是去访问宿主机的IP
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetEP"></param>
|
|
||||||
/// <param name="targetIP"></param>
|
|
||||||
private void ReplaceTargetIP(IPEndPoint targetEP, uint targetIP)
|
|
||||||
{
|
|
||||||
if (hostipCic.TryGetValue(targetIP, out IPAddress hostip) && hostip.Equals(IPAddress.Any) == false)
|
|
||||||
{
|
|
||||||
targetEP.Address = hostip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// udp回复消息自定义处理,因为socks5,要打包一些格式才能返回
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <param name="asyncUserUdpToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override async ValueTask<bool> ConnectionReceiveUdp(AsyncUserTunnelToken token, AsyncUserUdpToken asyncUserUdpToken)
|
|
||||||
{
|
|
||||||
IPEndPoint target = token.Proxy.TargetEP;
|
|
||||||
if (broadcastDic.TryGetValue(token.Proxy.SourceEP, out BroadcastCacheInfo cache))
|
|
||||||
{
|
|
||||||
target = cache.TargetEP;
|
|
||||||
cache.LastTime = Environment.TickCount64;
|
|
||||||
}
|
|
||||||
byte[] data = Socks5Parser.MakeUdpResponse(target, token.Proxy.Data, out int length);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await asyncUserUdpToken.SourceSocket.SendToAsync(data.AsMemory(0, length), token.Proxy.SourceEP).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Socks5Parser.Return(data);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
private void ClearTask()
|
|
||||||
{
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
long time = Environment.TickCount64;
|
|
||||||
foreach (var item in broadcastDic.Where(c => time - c.Value.LastTime > 30000).Select(c => c.Key).ToList())
|
|
||||||
{
|
|
||||||
broadcastDic.TryRemove(item, out _);
|
|
||||||
};
|
|
||||||
await Task.Delay(30000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SemaphoreSlim slimGlobal = new SemaphoreSlim(1);
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 打洞或者中继
|
/// 打洞或者中继
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -279,7 +138,7 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
private async ValueTask<ITunnelConnection> ConnectTunnel(uint ip)
|
private async ValueTask<ITunnelConnection> ConnectTunnel(uint ip)
|
||||||
{
|
{
|
||||||
//直接按IP查找
|
//直接按IP查找
|
||||||
if (dic.TryGetValue(ip, out string machineId))
|
if (ip2MachineCic.TryGetValue(ip, out string machineId))
|
||||||
{
|
{
|
||||||
return await ConnectTunnel(machineId).ConfigureAwait(false);
|
return await ConnectTunnel(machineId).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -288,8 +147,9 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
for (int i = 0; i < maskValues.Length; i++)
|
for (int i = 0; i < maskValues.Length; i++)
|
||||||
{
|
{
|
||||||
uint network = ip & maskValues[i];
|
uint network = ip & maskValues[i];
|
||||||
if (dic.TryGetValue(network, out machineId))
|
if (ip2MachineCic.TryGetValue(network, out machineId))
|
||||||
{
|
{
|
||||||
|
ip2MachineCic.TryAdd(ip, machineId);
|
||||||
return await ConnectTunnel(machineId).ConfigureAwait(false);
|
return await ConnectTunnel(machineId).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,48 +224,6 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 接收socks5完整数据包
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<bool> ReceiveCommandData(AsyncUserToken token)
|
|
||||||
{
|
|
||||||
int totalLength = token.Proxy.Data.Length;
|
|
||||||
EnumProxyValidateDataResult validate = ValidateData(token.Proxy);
|
|
||||||
//太短
|
|
||||||
while ((validate & EnumProxyValidateDataResult.TooShort) == EnumProxyValidateDataResult.TooShort)
|
|
||||||
{
|
|
||||||
totalLength += await token.Socket.ReceiveAsync(token.Buffer.AsMemory(totalLength), SocketFlags.None).ConfigureAwait(false);
|
|
||||||
token.Proxy.Data = token.Buffer.AsMemory(0, totalLength);
|
|
||||||
validate = ValidateData(token.Proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
//不短,又不相等,直接关闭连接
|
|
||||||
if ((validate & EnumProxyValidateDataResult.Equal) != EnumProxyValidateDataResult.Equal)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 验证socks5数据包完整性
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private EnumProxyValidateDataResult ValidateData(ProxyInfo info)
|
|
||||||
{
|
|
||||||
return (Socks5EnumStep)info.Rsv switch
|
|
||||||
{
|
|
||||||
Socks5EnumStep.Request => Socks5Parser.ValidateRequestData(info.Data),
|
|
||||||
Socks5EnumStep.Command => Socks5Parser.ValidateCommandData(info.Data),
|
|
||||||
Socks5EnumStep.Auth => Socks5Parser.ValidateAuthData(info.Data, Socks5EnumAuthType.Password),
|
|
||||||
Socks5EnumStep.Forward => EnumProxyValidateDataResult.Equal,
|
|
||||||
Socks5EnumStep.ForwardUdp => EnumProxyValidateDataResult.Equal,
|
|
||||||
_ => EnumProxyValidateDataResult.Equal
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConcurrentDictionary<string, ITunnelConnection> GetConnections()
|
public ConcurrentDictionary<string, ITunnelConnection> GetConnections()
|
||||||
{
|
{
|
||||||
return connections;
|
return connections;
|
||||||
@@ -424,24 +242,6 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class BroadcastCacheInfo
|
|
||||||
{
|
|
||||||
public IPEndPoint TargetEP { get; set; }
|
|
||||||
public long LastTime { get; set; } = Environment.TickCount64;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class IPEndpointComparer : IEqualityComparer<IPEndPoint>
|
|
||||||
{
|
|
||||||
public bool Equals(IPEndPoint x, IPEndPoint y)
|
|
||||||
{
|
|
||||||
return x.Equals(y);
|
|
||||||
}
|
|
||||||
public int GetHashCode(IPEndPoint obj)
|
|
||||||
{
|
|
||||||
return obj.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,89 +0,0 @@
|
|||||||
using MemoryPack;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.vea
|
|
||||||
{
|
|
||||||
public interface ITuntapVea
|
|
||||||
{
|
|
||||||
public bool Running { get; }
|
|
||||||
public string InterfaceName { get; }
|
|
||||||
public string Error { get; }
|
|
||||||
|
|
||||||
public Task<bool> Run(int proxyPort,IPAddress ip);
|
|
||||||
public Task<bool> SetIp(IPAddress ip);
|
|
||||||
public void Kill();
|
|
||||||
|
|
||||||
public void AddRoute(TuntapVeaLanIPAddress[] ips, IPAddress ip);
|
|
||||||
public void DelRoute(TuntapVeaLanIPAddress[] ips);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemoryPackable]
|
|
||||||
public sealed partial class TuntapVeaLanIPAddress
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ip,存小端
|
|
||||||
/// </summary>
|
|
||||||
public uint IPAddress { get; set; }
|
|
||||||
public byte MaskLength { get; set; }
|
|
||||||
public uint MaskValue { get; set; }
|
|
||||||
public uint NetWork { get; set; }
|
|
||||||
public uint Broadcast { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemoryPackable]
|
|
||||||
public sealed partial class TuntapVeaLanIPAddressList
|
|
||||||
{
|
|
||||||
public string MachineId { get; set; }
|
|
||||||
public List<TuntapVeaLanIPAddress> IPS { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TuntapStatus : byte
|
|
||||||
{
|
|
||||||
Normal = 0,
|
|
||||||
Starting = 1,
|
|
||||||
Running = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemoryPackable]
|
|
||||||
public sealed partial class TuntapInfo
|
|
||||||
{
|
|
||||||
public string MachineId { get; set; }
|
|
||||||
|
|
||||||
public TuntapStatus Status { get; set; }
|
|
||||||
|
|
||||||
[MemoryPackAllowSerialize]
|
|
||||||
public IPAddress IP { get; set; }
|
|
||||||
|
|
||||||
[MemoryPackAllowSerialize]
|
|
||||||
public IPAddress[] LanIPs { get; set; } = Array.Empty<IPAddress>();
|
|
||||||
public int[] Masks { get; set; } = Array.Empty<int>();
|
|
||||||
|
|
||||||
public string Error { get; set; }
|
|
||||||
|
|
||||||
public byte BufferSize { get; set; } = 3;
|
|
||||||
|
|
||||||
[MemoryPackAllowSerialize]
|
|
||||||
public IPAddress HostIP { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemoryPackable]
|
|
||||||
public sealed partial class TuntapOnlineInfo
|
|
||||||
{
|
|
||||||
public string[] MachineIds { get; set; }
|
|
||||||
public byte[] Status { get; set; }
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
[MemoryPackInclude]
|
|
||||||
public List<Task<IPHostEntry>> HostTasks { get; set; }
|
|
||||||
[JsonIgnore]
|
|
||||||
[MemoryPackInclude]
|
|
||||||
public List<Task<PingReply>> PingTasks { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,156 +0,0 @@
|
|||||||
using linker.libs;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.vea
|
|
||||||
{
|
|
||||||
public sealed class TuntapVeaLinux : ITuntapVea
|
|
||||||
{
|
|
||||||
private string interfaceLinux = string.Empty;
|
|
||||||
private Process Tun2SocksProcess;
|
|
||||||
private IPAddress ip;
|
|
||||||
|
|
||||||
public bool Running => string.IsNullOrWhiteSpace(interfaceLinux) == false;
|
|
||||||
public string InterfaceName => "linker";
|
|
||||||
public string Error { get; private set; }
|
|
||||||
|
|
||||||
public TuntapVeaLinux()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.SetUnixFileMode("./plugins/tuntap/tun2socks", UnixFileMode.GroupExecute | UnixFileMode.OtherExecute | UnixFileMode.UserExecute);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Run(int proxyPort, IPAddress ip)
|
|
||||||
{
|
|
||||||
CommandHelper.Linux(string.Empty, new string[] { $"ip tuntap add mode tun dev {InterfaceName}" });
|
|
||||||
await SetIp(ip).ConfigureAwait(false);
|
|
||||||
string str = CommandHelper.Linux(string.Empty, new string[] { $"ifconfig" });
|
|
||||||
if (str.Contains(InterfaceName) == false)
|
|
||||||
{
|
|
||||||
Error = CommandHelper.Linux(string.Empty, new string[] { $"ip tuntap add mode tun dev {InterfaceName}" });
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
interfaceLinux = GetLinuxInterfaceNum();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string command = $" -device {InterfaceName} -proxy socks5://127.0.0.1:{proxyPort} -interface {interfaceLinux} -loglevel silent";
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Warning($"vea linux ->exec:{command}");
|
|
||||||
}
|
|
||||||
Tun2SocksProcess = CommandHelper.Execute("./plugins/tuntap/tun2socks", command);
|
|
||||||
if (Tun2SocksProcess.HasExited)
|
|
||||||
{
|
|
||||||
Error = CommandHelper.Execute("./plugins/tuntap/tun2socks", command, Array.Empty<string>());
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(10).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Error = ex.Message;
|
|
||||||
LoggerHelper.Instance.Error(ex.Message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.IsNullOrWhiteSpace(interfaceLinux) == false;
|
|
||||||
}
|
|
||||||
public async Task<bool> SetIp(IPAddress ip)
|
|
||||||
{
|
|
||||||
if (this.ip != null)
|
|
||||||
{
|
|
||||||
CommandHelper.Linux(string.Empty, new string[] { $"ip addr del {this.ip}/24 dev {InterfaceName}" });
|
|
||||||
}
|
|
||||||
this.ip = ip;
|
|
||||||
CommandHelper.Linux(string.Empty, new string[] { $"ip addr add {ip}/24 dev {InterfaceName}", $"ip link set dev {InterfaceName} up" });
|
|
||||||
return await Task.FromResult(true).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Kill()
|
|
||||||
{
|
|
||||||
if (Tun2SocksProcess != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Tun2SocksProcess.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Tun2SocksProcess = null;
|
|
||||||
}
|
|
||||||
foreach (var item in Process.GetProcesses().Where(c => c.ProcessName.Contains("tun2socks")))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
item.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interfaceLinux = string.Empty;
|
|
||||||
CommandHelper.Linux(string.Empty, new string[] { $"ip tuntap del mode tun dev {InterfaceName}" });
|
|
||||||
Error = string.Empty;
|
|
||||||
}
|
|
||||||
public void AddRoute(TuntapVeaLanIPAddress[] ips, IPAddress ip)
|
|
||||||
{
|
|
||||||
string[] commands = ips.Where(c => c.IPAddress > 0).Select(item =>
|
|
||||||
{
|
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.IPAddress, item.MaskValue);
|
|
||||||
return $"ip route add {_ip}/{item.MaskLength} via {ip} dev {InterfaceName} metric 1 ";
|
|
||||||
}).ToArray();
|
|
||||||
if (commands.Length > 0)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Warning($"vea linux ->add route:{string.Join(Environment.NewLine, commands)}");
|
|
||||||
}
|
|
||||||
CommandHelper.Linux(string.Empty, commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DelRoute(TuntapVeaLanIPAddress[] ip)
|
|
||||||
{
|
|
||||||
string[] commands = ip.Select(item =>
|
|
||||||
{
|
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.IPAddress, item.MaskValue);
|
|
||||||
return $"ip route del {_ip}/{item.MaskLength}";
|
|
||||||
}).ToArray();
|
|
||||||
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Warning($"vea linux ->del route:{string.Join(Environment.NewLine, commands)}");
|
|
||||||
}
|
|
||||||
CommandHelper.Linux(string.Empty, commands);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetLinuxInterfaceNum()
|
|
||||||
{
|
|
||||||
string output = CommandHelper.Linux(string.Empty, new string[] { "ip route" });
|
|
||||||
foreach (var item in output.Split(Environment.NewLine))
|
|
||||||
{
|
|
||||||
if (item.StartsWith("default via"))
|
|
||||||
{
|
|
||||||
var strs = item.Split(' ');
|
|
||||||
for (int i = 0; i < strs.Length; i++)
|
|
||||||
{
|
|
||||||
if (strs[i] == "dev")
|
|
||||||
{
|
|
||||||
return strs[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,159 +0,0 @@
|
|||||||
using linker.libs;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.vea
|
|
||||||
{
|
|
||||||
public sealed class TuntapVeaMacOs : ITuntapVea
|
|
||||||
{
|
|
||||||
private string interfaceOsx = string.Empty;
|
|
||||||
private Process Tun2SocksProcess;
|
|
||||||
private IPAddress ip;
|
|
||||||
|
|
||||||
public bool Running => string.IsNullOrWhiteSpace(interfaceOsx) == false;
|
|
||||||
public string InterfaceName => "utun12138";
|
|
||||||
public string Error { get; private set; }
|
|
||||||
|
|
||||||
public TuntapVeaMacOs()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.SetUnixFileMode("./plugins/tuntap/tun2socks", UnixFileMode.GroupExecute | UnixFileMode.OtherExecute | UnixFileMode.UserExecute);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Run(int proxyPort, IPAddress ip)
|
|
||||||
{
|
|
||||||
interfaceOsx = GetOsxInterfaceNum();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Tun2SocksProcess = CommandHelper.Execute("./plugins/tuntap/tun2socks", $" -device {InterfaceName} -proxy socks5://127.0.0.1:{proxyPort} -interface {interfaceOsx} -loglevel silent");
|
|
||||||
if (Tun2SocksProcess.HasExited)
|
|
||||||
{
|
|
||||||
Error = CommandHelper.Execute("./plugins/tuntap/tun2socks", $" -device {InterfaceName} -proxy socks5://127.0.0.1:{proxyPort} -interface {interfaceOsx} -loglevel silent", Array.Empty<string>());
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Error = ex.Message;
|
|
||||||
LoggerHelper.Instance.Error(ex.Message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
string output = CommandHelper.Osx(string.Empty, new string[] { "ifconfig" });
|
|
||||||
if (output.Contains(InterfaceName))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await SetIp(ip).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return string.IsNullOrWhiteSpace(interfaceOsx) == false;
|
|
||||||
}
|
|
||||||
public async Task<bool> SetIp(IPAddress ip)
|
|
||||||
{
|
|
||||||
if (this.ip != null)
|
|
||||||
{
|
|
||||||
var ips = this.ip.GetAddressBytes();
|
|
||||||
ips[^1] = 0;
|
|
||||||
CommandHelper.Osx(string.Empty, new string[] { $"route delete -net {new IPAddress(ips)}/24 {this.ip}" });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ip = ip;
|
|
||||||
CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {InterfaceName} {ip} {ip} up" });
|
|
||||||
await Task.Delay(10).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var ipBytes = ip.GetAddressBytes();
|
|
||||||
ipBytes[^1] = 0;
|
|
||||||
CommandHelper.Osx(string.Empty, new string[] { $"route add -net {new IPAddress(ipBytes)}/24 {ip}" });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Kill()
|
|
||||||
{
|
|
||||||
if (Tun2SocksProcess != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Tun2SocksProcess.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Tun2SocksProcess = null;
|
|
||||||
}
|
|
||||||
foreach (var item in Process.GetProcesses().Where(c => c.ProcessName.Contains("tun2socks")))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
item.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interfaceOsx = string.Empty;
|
|
||||||
var ip = this.ip.GetAddressBytes();
|
|
||||||
ip[^1] = 0;
|
|
||||||
CommandHelper.Osx(string.Empty, new string[] { $"route delete -net {new IPAddress(ip)}/24 {this.ip}" });
|
|
||||||
Error = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRoute(TuntapVeaLanIPAddress[] ips, IPAddress ip)
|
|
||||||
{
|
|
||||||
string[] commands = ips.Where(c => c.IPAddress > 0).Select(item =>
|
|
||||||
{
|
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.IPAddress, item.MaskValue);
|
|
||||||
return $"route add -net {_ip}/{item.MaskLength} {ip}";
|
|
||||||
}).ToArray();
|
|
||||||
if (commands.Length > 0)
|
|
||||||
{
|
|
||||||
CommandHelper.Osx(string.Empty, commands.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DelRoute(TuntapVeaLanIPAddress[] ip)
|
|
||||||
{
|
|
||||||
string[] commands = ip.Select(item =>
|
|
||||||
{
|
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.IPAddress, item.MaskValue);
|
|
||||||
return $"route delete -net {_ip}/{item.MaskLength}";
|
|
||||||
}).ToArray();
|
|
||||||
if (commands.Length > 0)
|
|
||||||
{
|
|
||||||
CommandHelper.Osx(string.Empty, commands.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetOsxInterfaceNum()
|
|
||||||
{
|
|
||||||
string output = CommandHelper.Osx(string.Empty, new string[] { "ifconfig" });
|
|
||||||
var arr = output.Split(Environment.NewLine);
|
|
||||||
for (int i = 0; i < arr.Length; i++)
|
|
||||||
{
|
|
||||||
var item = arr[i];
|
|
||||||
if (item.Contains("inet "))
|
|
||||||
{
|
|
||||||
for (int k = i; k >= 0; k--)
|
|
||||||
{
|
|
||||||
var itemk = arr[k];
|
|
||||||
if (itemk.Contains("flags=") && itemk.StartsWith("en"))
|
|
||||||
{
|
|
||||||
return itemk.Split(": ")[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,299 +0,0 @@
|
|||||||
using linker.libs;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.vea
|
|
||||||
{
|
|
||||||
public sealed class TuntapVeaWindows : ITuntapVea
|
|
||||||
{
|
|
||||||
private int interfaceNumber = 0;
|
|
||||||
private Process Tun2SocksProcess;
|
|
||||||
|
|
||||||
public bool Running => interfaceNumber > 0;
|
|
||||||
public string InterfaceName => "linker";
|
|
||||||
public string Error { get; private set; }
|
|
||||||
|
|
||||||
|
|
||||||
public TuntapVeaWindows()
|
|
||||||
{
|
|
||||||
ClearRegistry();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> Run(int proxyPort, IPAddress ip)
|
|
||||||
{
|
|
||||||
string command = $" -device tun://{InterfaceName} -proxy socks5://127.0.0.1:{proxyPort} -loglevel silent";
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Warning($"vea windows ->exec:{command}");
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Tun2SocksProcess = CommandHelper.Execute("./plugins/tuntap/tun2socks.exe", command);
|
|
||||||
if (Tun2SocksProcess.HasExited)
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (await GetWindowsHasInterface(InterfaceName).ConfigureAwait(false) == false)
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (await GetWindowsInterfaceNum().ConfigureAwait(false) == false)
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (await SetIp(ip).ConfigureAwait(false) == false)
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await GetWindowsHasRoute(ip).ConfigureAwait(false) == false)
|
|
||||||
{
|
|
||||||
Kill();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Error(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interfaceNumber <= 0)
|
|
||||||
{
|
|
||||||
Error = CommandHelper.Execute("./plugins/tuntap/tun2socks.exe", command, Array.Empty<string>());
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return interfaceNumber > 0;
|
|
||||||
}
|
|
||||||
public async Task<bool> SetIp(IPAddress ip)
|
|
||||||
{
|
|
||||||
if (interfaceNumber == 0) return false;
|
|
||||||
CommandHelper.Windows(string.Empty, new string[] { $"netsh interface ip set address name=\"{InterfaceName}\" source=static addr={ip} mask=255.255.255.0 gateway=none" });
|
|
||||||
for (int k = 0; k < 5; k++)
|
|
||||||
{
|
|
||||||
string output = CommandHelper.Windows(string.Empty, new string[] { $"ipconfig" });
|
|
||||||
if (output.Contains("Windows IP") == false)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"ipconfig command not found";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (output.Contains(ip.ToString()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"vea windows ->set ip fail";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void ClearRegistry()
|
|
||||||
{
|
|
||||||
string[] delValues = ["p2p-tunnel", "cmonitor", "linker"];
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles");
|
|
||||||
foreach (var item in key.GetSubKeyNames())
|
|
||||||
{
|
|
||||||
RegistryKey itemKey = key.OpenSubKey(item);
|
|
||||||
string value = itemKey.GetValue("Description", string.Empty).ToString();
|
|
||||||
itemKey.Close();
|
|
||||||
if (delValues.Contains(value))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Registry.LocalMachine.DeleteSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles\\{item}");
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
key.Close();
|
|
||||||
|
|
||||||
key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged");
|
|
||||||
foreach (var item in key.GetSubKeyNames())
|
|
||||||
{
|
|
||||||
RegistryKey itemKey = key.OpenSubKey(item);
|
|
||||||
string value = itemKey.GetValue("Description", string.Empty).ToString();
|
|
||||||
itemKey.Close();
|
|
||||||
if (delValues.Any(c => value.Contains($"{c} ") || value == c))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Registry.LocalMachine.DeleteSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged\\{item}");
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
key.Close();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Kill()
|
|
||||||
{
|
|
||||||
interfaceNumber = 0;
|
|
||||||
if (Tun2SocksProcess != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Tun2SocksProcess.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Tun2SocksProcess = null;
|
|
||||||
}
|
|
||||||
foreach (var item in Process.GetProcesses().Where(c => c.ProcessName.Contains("tun2socks")))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
item.Kill();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Error = string.Empty;
|
|
||||||
}
|
|
||||||
public void AddRoute(TuntapVeaLanIPAddress[] ips, IPAddress ip)
|
|
||||||
{
|
|
||||||
if (interfaceNumber > 0)
|
|
||||||
{
|
|
||||||
string[] commands = ips.Where(c => c.IPAddress > 0).Select(item =>
|
|
||||||
{
|
|
||||||
IPAddress mask = NetworkHelper.GetMaskIp(item.MaskValue);
|
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.IPAddress, item.MaskValue);
|
|
||||||
|
|
||||||
return $"route add {_ip} mask {mask} {ip} metric 5 if {interfaceNumber}";
|
|
||||||
}).ToArray();
|
|
||||||
if (commands.Length > 0)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Warning($"vea windows ->add route:{string.Join(Environment.NewLine, commands)}");
|
|
||||||
}
|
|
||||||
CommandHelper.Windows(string.Empty, commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DelRoute(TuntapVeaLanIPAddress[] ip)
|
|
||||||
{
|
|
||||||
if (interfaceNumber > 0)
|
|
||||||
{
|
|
||||||
string[] commands = ip.Where(c => c.IPAddress > 0).Select(item =>
|
|
||||||
{
|
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.IPAddress, item.MaskValue);
|
|
||||||
return $"route delete {_ip}";
|
|
||||||
}).ToArray();
|
|
||||||
if (commands.Length > 0)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
LoggerHelper.Instance.Warning($"vea windows ->del route:{string.Join(Environment.NewLine, commands)}");
|
|
||||||
}
|
|
||||||
CommandHelper.Windows(string.Empty, commands.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async Task<bool> GetWindowsInterfaceNum()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
NetworkInterface adapter = NetworkInterface.GetAllNetworkInterfaces()
|
|
||||||
.FirstOrDefault(c => c.Name == InterfaceName);
|
|
||||||
if (adapter != null)
|
|
||||||
{
|
|
||||||
interfaceNumber = adapter.GetIPProperties().GetIPv4Properties().Index;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"interface number not found";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private async Task<bool> GetWindowsHasInterface(string name)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
string output = CommandHelper.Windows(string.Empty, new string[] { $"ipconfig" });
|
|
||||||
if (output.Contains("Windows IP") == false)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"ipconfig command not found";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (output.Contains(name))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"interface {name} not found";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private async Task<bool> GetWindowsHasRoute(IPAddress ip)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
string output = CommandHelper.Windows(string.Empty, new string[] { "route print" });
|
|
||||||
if (output.Contains("IPv4") == false)
|
|
||||||
{
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"route command not found";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (output.Contains(ip.ToString()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
|
||||||
{
|
|
||||||
Error = $"interface route set fail";
|
|
||||||
LoggerHelper.Instance.Error(Error);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user