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.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace linker.libs
|
||||
{
|
||||
@@ -184,6 +185,18 @@ namespace linker.libs
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@@ -55,7 +55,7 @@ namespace linker.libs.extends
|
||||
public static bool GetIsBroadcastAddress(this ReadOnlySpan<byte> 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.Runtime.InteropServices;
|
||||
|
||||
@@ -10,25 +9,28 @@ namespace linker.tun.test
|
||||
public static LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
linkerTunDeviceAdapter = new LinkerTunDeviceAdapter(new LinkerTunDeviceCallback());
|
||||
linkerTunDeviceAdapter = new LinkerTunDeviceAdapter();
|
||||
linkerTunDeviceAdapter.SetCallback(new LinkerTunDeviceCallback());
|
||||
linkerTunDeviceAdapter.SetUp("linker111"
|
||||
, Guid.Parse("dc6d4efa-2b53-41bd-a403-f416c9bf7129")
|
||||
, IPAddress.Parse("192.168.55.2")
|
||||
, IPAddress.Parse("192.168.55.1"), 24);
|
||||
, IPAddress.Parse("192.168.55.2"), 24);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(linkerTunDeviceAdapter.Error))
|
||||
{
|
||||
Console.WriteLine(linkerTunDeviceAdapter.Error);
|
||||
}
|
||||
|
||||
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);
|
||||
fixed (byte* ptr = writableMemory.Span)
|
||||
@@ -36,12 +38,12 @@ namespace linker.tun.test
|
||||
//icmp && request
|
||||
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*)(ptr + 16) = *(uint*)(ptr + 12);
|
||||
*(uint*)(ptr + 16) = *(uint*)(ptr + 12);
|
||||
//假装是网关回复的
|
||||
*(uint*)(ptr + 12) = dist;
|
||||
|
||||
|
@@ -20,7 +20,7 @@ namespace linker.tun
|
||||
|
||||
public interface ILinkerTunDeviceCallback
|
||||
{
|
||||
public void Callback(LinkerTunDevicPacket packet);
|
||||
public Task Callback(LinkerTunDevicPacket packet);
|
||||
}
|
||||
|
||||
public struct LinkerTunDevicPacket
|
||||
@@ -33,8 +33,8 @@ namespace linker.tun
|
||||
|
||||
public sealed class LinkerTunDeviceRouteItem
|
||||
{
|
||||
public IPAddress Address { get; }
|
||||
public byte Mask { get; }
|
||||
public IPAddress Address { get; set; }
|
||||
public byte Mask { get; set; }
|
||||
}
|
||||
|
||||
public enum LinkerTunDeviceStatus
|
||||
|
@@ -1,8 +1,9 @@
|
||||
using System.Net;
|
||||
using linker.libs;
|
||||
using System.Net;
|
||||
|
||||
namespace linker.tun
|
||||
{
|
||||
public unsafe sealed class LinkerTunDeviceAdapter
|
||||
public sealed class LinkerTunDeviceAdapter
|
||||
{
|
||||
private ILinkerTunDevice linkerTunDevice;
|
||||
private ILinkerTunDeviceCallback linkerTunDeviceCallback;
|
||||
@@ -13,31 +14,45 @@ namespace linker.tun
|
||||
|
||||
|
||||
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>
|
||||
/// <param name="linkerTunDeviceCallback">数据包回调</param>
|
||||
public LinkerTunDeviceAdapter(ILinkerTunDeviceCallback linkerTunDeviceCallback)
|
||||
public LinkerTunDeviceAdapter()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetCallback(ILinkerTunDeviceCallback linkerTunDeviceCallback)
|
||||
{
|
||||
this.linkerTunDeviceCallback = linkerTunDeviceCallback;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 开启网卡
|
||||
/// </summary>
|
||||
/// <param name="name">网卡名,如果是osx,需要utunX的命名,X是一个数字</param>
|
||||
/// <param name="guid">windows的时候,需要一个固定guid,不然网卡编号一直递增,注册表一直新增记录</param>
|
||||
/// <param name="address">网卡IP</param>
|
||||
/// <param name="gateway">网卡网关</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;
|
||||
|
||||
Shutdown();
|
||||
|
||||
starting = true;
|
||||
try
|
||||
{
|
||||
@@ -55,13 +70,16 @@ namespace linker.tun
|
||||
if (linkerTunDevice != null)
|
||||
{
|
||||
linkerTunDevice.Shutdown();
|
||||
linkerTunDevice.SetUp(address, gateway, mask, out error);
|
||||
|
||||
linkerTunDevice.SetUp(address, NetworkHelper.ToGatewayIP(address, mask), mask, out error);
|
||||
if (string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (cancellationTokenSource.IsCancellationRequested == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReadOnlyMemory<byte> buffer = linkerTunDevice.Read();
|
||||
if (buffer.Length == 0)
|
||||
@@ -84,7 +102,12 @@ namespace linker.tun
|
||||
packet.DistIPAddress = buffer.Slice(24, 16);
|
||||
}
|
||||
|
||||
linkerTunDeviceCallback.Callback(packet);
|
||||
await linkerTunDeviceCallback.Callback(packet);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -157,7 +180,7 @@ namespace linker.tun
|
||||
/// <param name="addr">包头开始位置</param>
|
||||
/// <param name="count">包头长度</param>
|
||||
/// <returns></returns>
|
||||
public ushort Checksum(ushort* addr, uint count)
|
||||
public unsafe ushort Checksum(ushort* addr, uint count)
|
||||
{
|
||||
ulong sum = 0;
|
||||
while (count > 1)
|
||||
@@ -167,7 +190,7 @@ namespace linker.tun
|
||||
}
|
||||
if (count > 0)
|
||||
{
|
||||
sum += (ulong)((*addr) & Ntohs(0xFF00));
|
||||
sum += (ulong)((*addr) & ((((0xff00) & 0xff) << 8) | (((0xff00) & 0xff00) >> 8)));
|
||||
}
|
||||
while ((sum >> 16) != 0)
|
||||
{
|
||||
@@ -176,9 +199,5 @@ namespace linker.tun
|
||||
sum = ~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.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using static linker.libs.winapis.SECUR32;
|
||||
|
||||
namespace linker.tun
|
||||
{
|
||||
@@ -12,10 +13,12 @@ namespace linker.tun
|
||||
public string Name => name;
|
||||
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 int interfaceNumber = 0;
|
||||
|
||||
private CancellationTokenSource tokenSource;
|
||||
|
||||
public LinkerWinTunDevice(string name, Guid guid)
|
||||
{
|
||||
this.name = name;
|
||||
@@ -24,6 +27,7 @@ namespace linker.tun
|
||||
|
||||
public bool SetUp(IPAddress address, IPAddress gateway, byte prefixLength, out string error)
|
||||
{
|
||||
|
||||
error = string.Empty;
|
||||
if (adapter != 0)
|
||||
{
|
||||
@@ -47,6 +51,11 @@ namespace linker.tun
|
||||
|
||||
waitHandle = WintunGetReadWaitEvent(session);
|
||||
|
||||
WintunSetLogger((WINTUN_LOGGER_LEVEL level, ulong timestamp,string message) =>
|
||||
{
|
||||
Console.WriteLine($"[{level}]->{timestamp}->{message}");
|
||||
});
|
||||
|
||||
WintunGetAdapterLUID(adapter, out ulong luid);
|
||||
{
|
||||
MIB_UNICASTIPADDRESS_ROW AddressRow = default;
|
||||
@@ -59,6 +68,7 @@ namespace linker.tun
|
||||
uint LastError = CreateUnicastIpAddressEntry(ref AddressRow);
|
||||
if (LastError != 0) throw new InvalidOperationException();
|
||||
}
|
||||
/*
|
||||
{
|
||||
MIB_IPFORWARD_ROW2 row = default;
|
||||
InitializeIpForwardEntry(ref row);
|
||||
@@ -71,13 +81,20 @@ namespace linker.tun
|
||||
uint LastError = CreateIpForwardEntry2(ref row);
|
||||
if (LastError != 0) throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
*/
|
||||
GetWindowsInterfaceNum();
|
||||
|
||||
tokenSource = new CancellationTokenSource();
|
||||
return true;
|
||||
}
|
||||
public void Shutdown()
|
||||
{
|
||||
tokenSource?.Cancel();
|
||||
if (waitHandle != 0)
|
||||
{
|
||||
SetEvent(waitHandle);
|
||||
waitHandle = 0;
|
||||
}
|
||||
if (session != 0)
|
||||
{
|
||||
WintunEndSession(session);
|
||||
@@ -126,8 +143,7 @@ namespace linker.tun
|
||||
private byte[] buffer = new byte[2 * 1024];
|
||||
public unsafe ReadOnlyMemory<byte> Read()
|
||||
{
|
||||
if (session == 0) return Helper.EmptyArray;
|
||||
for (; ; )
|
||||
for (; tokenSource.IsCancellationRequested == false;)
|
||||
{
|
||||
IntPtr packet = WintunReceivePacket(session, out var packetSize);
|
||||
if (packet != 0)
|
||||
@@ -144,6 +160,7 @@ namespace linker.tun
|
||||
}
|
||||
}
|
||||
}
|
||||
return Helper.EmptyArray;
|
||||
}
|
||||
public unsafe bool Write(ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
@@ -220,6 +237,8 @@ namespace linker.tun
|
||||
private static extern uint CreateIpForwardEntry2(ref MIB_IPFORWARD_ROW2 Row);
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool SetEvent(IntPtr hEvent);
|
||||
|
||||
[DllImport("wintun.dll", SetLastError = true)]
|
||||
private static extern IntPtr WintunCreateAdapter(
|
||||
|
@@ -250,6 +250,7 @@ namespace linker.tunnel.connection
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ticks = 0;
|
||||
|
@@ -68,7 +68,7 @@ namespace linker.tunnel.connection
|
||||
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
_ = ProcessWrite();
|
||||
_ = ProcessHeart();
|
||||
//_ = ProcessHeart();
|
||||
}
|
||||
|
||||
private async Task ProcessWrite()
|
||||
|
@@ -187,11 +187,8 @@ namespace linker.tunnel.proxy
|
||||
try
|
||||
{
|
||||
asyncUserUdpToken.Connection = tunnelToken.Connection;
|
||||
if (await ConnectionReceiveUdp(tunnelToken, asyncUserUdpToken).ConfigureAwait(false) == false)
|
||||
{
|
||||
await asyncUserUdpToken.SourceSocket.SendToAsync(tunnelToken.Proxy.Data, tunnelToken.Proxy.SourceEP).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
|
@@ -91,7 +91,6 @@ namespace linker.tunnel.transport
|
||||
if (length > 0)
|
||||
{
|
||||
string key = bytes.AsMemory(0, length).GetString();
|
||||
LoggerHelper.Instance.Debug(key);
|
||||
if (distDic.TryRemove(key, out TaskCompletionSource<Socket> tcs))
|
||||
{
|
||||
await client.SendAsync(bytes.AsMemory(0, length));
|
||||
|
@@ -49,9 +49,6 @@
|
||||
<None Update="msquic.dll" Condition="'$(RuntimeIdentifier)'=='win-x64' or '$(RuntimeIdentifier)'=='win-arm64'">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</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'">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -62,6 +59,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\linker.tunnel\linker.tunnel.csproj" />
|
||||
<ProjectReference Include="..\linker.libs\linker.libs.csproj" />
|
||||
<ProjectReference Include="..\linker.tun\linker.tun.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using linker.libs.api;
|
||||
using linker.plugins.tuntap.vea;
|
||||
using linker.plugins.tuntap.messenger;
|
||||
using MemoryPack;
|
||||
using linker.libs.extends;
|
||||
@@ -8,9 +7,9 @@ using linker.config;
|
||||
using linker.tunnel.connection;
|
||||
using linker.plugins.tuntap.proxy;
|
||||
using linker.plugins.client;
|
||||
using linker.plugins.server;
|
||||
using linker.plugins.capi;
|
||||
using linker.plugins.messenger;
|
||||
using linker.plugins.tuntap.config;
|
||||
|
||||
namespace linker.plugins.tuntap
|
||||
{
|
||||
|
@@ -1,8 +1,8 @@
|
||||
using linker.config;
|
||||
using linker.plugins.tuntap.messenger;
|
||||
using linker.plugins.tuntap.proxy;
|
||||
using linker.plugins.tuntap.vea;
|
||||
using linker.startup;
|
||||
using linker.tun;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -23,12 +23,8 @@ namespace linker.plugins.tuntap
|
||||
|
||||
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<LinkerTunDeviceAdapter>();
|
||||
serviceCollection.AddSingleton<TuntapTransfer>();
|
||||
serviceCollection.AddSingleton<TuntapProxy>();
|
||||
|
||||
|
@@ -2,18 +2,16 @@
|
||||
using linker.config;
|
||||
using linker.plugins.tuntap.messenger;
|
||||
using linker.plugins.tuntap.proxy;
|
||||
using linker.plugins.tuntap.vea;
|
||||
using linker.libs;
|
||||
using MemoryPack;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using linker.libs.extends;
|
||||
using linker.plugins.client;
|
||||
using linker.plugins.messenger;
|
||||
using System;
|
||||
using linker.plugins.tuntap.config;
|
||||
using linker.tun;
|
||||
|
||||
namespace linker.plugins.tuntap
|
||||
{
|
||||
@@ -21,31 +19,31 @@ namespace linker.plugins.tuntap
|
||||
{
|
||||
private readonly MessengerSender messengerSender;
|
||||
private readonly ClientSignInState clientSignInState;
|
||||
private readonly ITuntapVea tuntapVea;
|
||||
private readonly FileConfig config;
|
||||
private readonly TuntapProxy tuntapProxy;
|
||||
private readonly RunningConfig runningConfig;
|
||||
private readonly LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
||||
|
||||
private string interfaceName = "linker";
|
||||
|
||||
private uint infosVersion = 0;
|
||||
private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>();
|
||||
public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos;
|
||||
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 => tuntapVea.Running ? TuntapStatus.Running : (starting ? TuntapStatus.Starting : TuntapStatus.Normal);
|
||||
public TuntapStatus Status => (TuntapStatus)(byte)linkerTunDeviceAdapter.Status;
|
||||
|
||||
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.clientSignInState = clientSignInState;
|
||||
this.tuntapVea = tuntapVea;
|
||||
this.linkerTunDeviceAdapter = linkerTunDeviceAdapter;
|
||||
this.config = config;
|
||||
this.tuntapProxy = tuntapProxy;
|
||||
this.runningConfig = runningConfig;
|
||||
|
||||
GetRouteIps();
|
||||
tuntapVea.Kill();
|
||||
clientSignInState.NetworkEnabledHandle += (times) =>
|
||||
{
|
||||
OnChange();
|
||||
@@ -60,14 +58,16 @@ namespace linker.plugins.tuntap
|
||||
}
|
||||
};
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += (s, e) => OnExit();
|
||||
Console.CancelKeyPress += (s, e) => OnExit();
|
||||
linkerTunDeviceAdapter.SetCallback(tuntapProxy);
|
||||
linkerTunDeviceAdapter.Shutdown();
|
||||
AppDomain.CurrentDomain.ProcessExit += (s, e) => Shutdown();
|
||||
Console.CancelKeyPress += (s, e) => Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序关闭
|
||||
/// </summary>
|
||||
private void OnExit()
|
||||
private void Shutdown()
|
||||
{
|
||||
bool running = runningConfig.Data.Tuntap.Running;
|
||||
Stop();
|
||||
@@ -80,12 +80,7 @@ namespace linker.plugins.tuntap
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
if (BooleanHelper.CompareExchange(ref starting, true, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
OnChange();
|
||||
try
|
||||
@@ -95,18 +90,13 @@ namespace linker.plugins.tuntap
|
||||
return;
|
||||
}
|
||||
|
||||
tuntapProxy.Start();
|
||||
while (tuntapProxy.LocalEndpoint == null)
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
bool result = await tuntapVea.Run(tuntapProxy.LocalEndpoint.Port, runningConfig.Data.Tuntap.IP).ConfigureAwait(false);
|
||||
linkerTunDeviceAdapter.SetUp(interfaceName, runningConfig.Data.Tuntap.InterfaceGuid, runningConfig.Data.Tuntap.IP, 24);
|
||||
runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running;
|
||||
runningConfig.Data.Update();
|
||||
if (result == false)
|
||||
|
||||
if (string.IsNullOrWhiteSpace(linkerTunDeviceAdapter.Error) == false)
|
||||
{
|
||||
Stop();
|
||||
LoggerHelper.Instance.Error(linkerTunDeviceAdapter.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -115,7 +105,6 @@ namespace linker.plugins.tuntap
|
||||
}
|
||||
finally
|
||||
{
|
||||
BooleanHelper.CompareExchange(ref starting, false, true);
|
||||
OnChange();
|
||||
}
|
||||
});
|
||||
@@ -125,15 +114,10 @@ namespace linker.plugins.tuntap
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (BooleanHelper.CompareExchange(ref starting, true, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
tuntapProxy.Stop();
|
||||
OnChange();
|
||||
tuntapVea.Kill();
|
||||
linkerTunDeviceAdapter.Shutdown();
|
||||
runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running;
|
||||
runningConfig.Data.Update();
|
||||
}
|
||||
@@ -146,7 +130,6 @@ namespace linker.plugins.tuntap
|
||||
}
|
||||
finally
|
||||
{
|
||||
BooleanHelper.CompareExchange(ref starting, false, true);
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
@@ -237,7 +220,7 @@ namespace linker.plugins.tuntap
|
||||
Masks = runningConfig.Data.Tuntap.Masks,
|
||||
MachineId = config.Data.Client.Id,
|
||||
Status = Status,
|
||||
Error = tuntapVea.Error,
|
||||
Error = linkerTunDeviceAdapter.Error,
|
||||
BufferSize = runningConfig.Data.Tuntap.BufferSize,
|
||||
HostIP = GetHostIP()
|
||||
};
|
||||
@@ -279,7 +262,7 @@ namespace linker.plugins.tuntap
|
||||
{
|
||||
List<TuntapVeaLanIPAddressList> ipsList = ParseIPs(tuntapInfos.Values.ToList());
|
||||
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>
|
||||
/// 添加路由
|
||||
@@ -288,7 +271,7 @@ namespace linker.plugins.tuntap
|
||||
{
|
||||
List<TuntapVeaLanIPAddressList> ipsList = ParseIPs(tuntapInfos.Values.ToList());
|
||||
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);
|
||||
foreach (var item in tuntapInfos.Values)
|
||||
@@ -345,6 +328,7 @@ namespace linker.plugins.tuntap
|
||||
MaskValue = maskValue,
|
||||
NetWork = ipInt & maskValue,
|
||||
Broadcast = ipInt | (~maskValue),
|
||||
OriginIPAddress = ip,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -361,9 +345,8 @@ namespace linker.plugins.tuntap
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tuntapVea.Running)
|
||||
if (Status == TuntapStatus.Running)
|
||||
{
|
||||
await CheckProxy().ConfigureAwait(false);
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
await CheckInterface().ConfigureAwait(false);
|
||||
}
|
||||
@@ -377,33 +360,15 @@ namespace linker.plugins.tuntap
|
||||
}
|
||||
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)
|
||||
{
|
||||
LoggerHelper.Instance.Error($"tuntap inerface {tuntapVea.InterfaceName} is {networkInterface.OperationalStatus}, restarting");
|
||||
LoggerHelper.Instance.Error($"tuntap inerface {interfaceName} is {networkInterface.OperationalStatus}, restarting");
|
||||
Stop();
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
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()
|
||||
{
|
||||
string hostip = Environment.GetEnvironmentVariable("SNLTTY_LINKER_HOST_IP");
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.plugins.tuntap.config;
|
||||
using MemoryPack;
|
||||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
|
||||
@@ -37,7 +38,66 @@ namespace linker.plugins.tuntap.config
|
||||
/// 是否在运行中
|
||||
/// </summary>
|
||||
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.signin.messenger;
|
||||
using linker.plugins.tuntap.vea;
|
||||
using linker.plugins.tuntap.config;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.tuntap.messenger
|
||||
|
@@ -1,60 +1,48 @@
|
||||
using linker.client.config;
|
||||
using linker.config;
|
||||
using linker.plugins.relay;
|
||||
using linker.plugins.tuntap.vea;
|
||||
using linker.tunnel;
|
||||
using linker.tunnel.connection;
|
||||
using linker.tunnel.proxy;
|
||||
using linker.libs;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.socks5;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Concurrent;
|
||||
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
|
||||
{
|
||||
public sealed class TuntapProxy : TunnelProxy
|
||||
public sealed class TuntapProxy : ILinkerTunDeviceCallback, ITunnelConnectionReceiveCallback
|
||||
{
|
||||
private readonly TunnelTransfer tunnelTransfer;
|
||||
private readonly RelayTransfer relayTransfer;
|
||||
private readonly RunningConfig runningConfig;
|
||||
private readonly FileConfig config;
|
||||
|
||||
private IPEndPoint proxyEP;
|
||||
|
||||
public override IPAddress UdpBindAdress { get; set; }
|
||||
private readonly LinkerTunDeviceAdapter linkerTunDeviceAdapter;
|
||||
|
||||
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<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.relayTransfer = relayTransfer;
|
||||
this.runningConfig = runningConfig;
|
||||
this.config = config;
|
||||
this.linkerTunDeviceAdapter = linkerTunDeviceAdapter;
|
||||
|
||||
//监听打洞连接成功
|
||||
tunnelTransfer.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>
|
||||
@@ -71,8 +59,51 @@ namespace linker.plugins.tuntap.proxy
|
||||
//connectionOld?.Dispose();
|
||||
}
|
||||
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>
|
||||
/// 设置IP,等下有连接进来,用IP匹配,才能知道这个连接是要连谁
|
||||
@@ -80,197 +111,25 @@ namespace linker.plugins.tuntap.proxy
|
||||
/// <param name="ips"></param>
|
||||
public void SetIPs(List<TuntapVeaLanIPAddressList> ips)
|
||||
{
|
||||
dic.Clear();
|
||||
ip2MachineCic.Clear();
|
||||
foreach (var item in 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();
|
||||
UdpBindAdress = runningConfig.Data.Tuntap.IP;
|
||||
}
|
||||
public void SetIP(string machineId, uint ip)
|
||||
{
|
||||
dic.AddOrUpdate(ip, machineId, (a, b) => machineId);
|
||||
|
||||
UdpBindAdress = runningConfig.Data.Tuntap.IP;
|
||||
ip2MachineCic.AddOrUpdate(ip, machineId, (a, b) => machineId);
|
||||
}
|
||||
public void SetHostIP(uint ip, IPAddress 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>
|
||||
@@ -279,7 +138,7 @@ namespace linker.plugins.tuntap.proxy
|
||||
private async ValueTask<ITunnelConnection> ConnectTunnel(uint ip)
|
||||
{
|
||||
//直接按IP查找
|
||||
if (dic.TryGetValue(ip, out string machineId))
|
||||
if (ip2MachineCic.TryGetValue(ip, out string machineId))
|
||||
{
|
||||
return await ConnectTunnel(machineId).ConfigureAwait(false);
|
||||
}
|
||||
@@ -288,8 +147,9 @@ namespace linker.plugins.tuntap.proxy
|
||||
for (int i = 0; i < maskValues.Length; 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);
|
||||
}
|
||||
}
|
||||
@@ -364,48 +224,6 @@ namespace linker.plugins.tuntap.proxy
|
||||
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()
|
||||
{
|
||||
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