This commit is contained in:
snltty
2024-08-01 22:33:53 +08:00
parent 4663856b4c
commit c813f2f577
29 changed files with 265 additions and 1100 deletions

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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)));
}
}
}

View File

@@ -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(

View File

@@ -250,6 +250,7 @@ namespace linker.tunnel.connection
return false;
}
public void Dispose()
{
ticks = 0;

View File

@@ -68,7 +68,7 @@ namespace linker.tunnel.connection
cancellationTokenSource = new CancellationTokenSource();
_ = ProcessWrite();
_ = ProcessHeart();
//_ = ProcessHeart();
}
private async Task ProcessWrite()

View File

@@ -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)

View File

@@ -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));

View File

@@ -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" />

View File

@@ -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
{

View File

@@ -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>();

View File

@@ -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");

View File

@@ -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; }
}
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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; }
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}