This commit is contained in:
snltty
2024-07-02 16:50:59 +08:00
parent db49b61f37
commit 8b47c5533c
34 changed files with 560 additions and 237 deletions

View File

@@ -14,7 +14,7 @@ namespace linker.tunnel
{ {
private List<ITunnelTransport> transports; private List<ITunnelTransport> transports;
private TunnelWanPortTransfer compactTransfer; private TunnelWanPortTransfer compactTransfer;
private ITunnelAdapter tunnelAdapter ; private ITunnelAdapter tunnelAdapter;
private ConcurrentDictionary<string, bool> connectingDic = new ConcurrentDictionary<string, bool>(); private ConcurrentDictionary<string, bool> connectingDic = new ConcurrentDictionary<string, bool>();
private Dictionary<string, List<Action<ITunnelConnection>>> OnConnected { get; } = new Dictionary<string, List<Action<ITunnelConnection>>>(); private Dictionary<string, List<Action<ITunnelConnection>>> OnConnected { get; } = new Dictionary<string, List<Action<ITunnelConnection>>>();
@@ -42,11 +42,38 @@ namespace linker.tunnel
} }
var transportItems = tunnelAdapter.GetTunnelTransports(); var transportItems = tunnelAdapter.GetTunnelTransports();
transportItems = transportItems.Concat(transports.Select(c => new TunnelTransportItemInfo { Label = c.Label, Name = c.Name, ProtocolType = c.ProtocolType.ToString() })) transportItems = transportItems.Concat(transports.Select(c => new TunnelTransportItemInfo
{
Label = c.Label,
Name = c.Name,
ProtocolType = c.ProtocolType.ToString(),
Reverse = c.Reverse,
DisableReverse = c.DisableReverse,
SSL = c.SSL,
DisableSSL = c.DisableSSL
}))
.Distinct(new TunnelTransportItemInfoEqualityComparer()) .Distinct(new TunnelTransportItemInfoEqualityComparer())
.Where(c=> transports.Select(c=>c.Name).Contains(c.Name)) .Where(c => transports.Select(c => c.Name).Contains(c.Name))
.ToList(); .ToList();
foreach (var item in transportItems)
{
var transport = transports.FirstOrDefault(c => c.Name == item.Name);
if (transport != null)
{
item.DisableReverse = transport.DisableReverse;
item.DisableSSL = transport.DisableSSL;
if (transport.DisableReverse)
{
item.Reverse = transport.Reverse;
}
if (transport.DisableSSL)
{
item.SSL = transport.SSL;
}
}
}
tunnelAdapter.SetTunnelTransports(transportItems); tunnelAdapter.SetTunnelTransports(transportItems);
@@ -98,66 +125,87 @@ namespace linker.tunnel
try try
{ {
foreach (TunnelTransportItemInfo transportItem in tunnelAdapter.GetTunnelTransports().Where(c => c.Disabled == false)) foreach (var wanPortProtocol in tunnelAdapter.GetTunnelWanPortProtocols().Where(c => c.Disabled == false && string.IsNullOrWhiteSpace(c.Host) == false))
{ {
ITunnelTransport transport = transports.FirstOrDefault(c => c.Name == transportItem.Name); foreach (TunnelTransportItemInfo transportItem in tunnelAdapter.GetTunnelTransports().Where(c => c.Disabled == false))
if (transport == null) continue;
TunnelTransportInfo tunnelTransportInfo = null;
//是否在失败后尝试反向连接
int times = transportItem.Reverse ? 1 : 0;
for (int i = 0; i <= times; i++)
{ {
try ITunnelTransport transport = transports.FirstOrDefault(c => c.Name == transportItem.Name);
//找不到这个打洞协议
if (transport == null)
{ {
//获取自己的外网ip continue;
TunnelTransportWanPortInfo localInfo = await GetLocalInfo(); }
if (localInfo == null) //这个打洞协议不支持这个外网端口协议
{ if((transport.AllowWanPortProtocolType & wanPortProtocol.ProtocolType) != wanPortProtocol.ProtocolType)
LoggerHelper.Instance.Error($"tunnel {transport.Name} get local external ip fail "); {
break; continue;
} }
LoggerHelper.Instance.Info($"tunnel {transport.Name} got local external ip {localInfo.ToJson()}");
//获取对方的外网ip
TunnelTransportWanPortInfo remoteInfo = await tunnelAdapter.GetRemoteWanPort(remoteMachineId);
if (remoteInfo == null)
{
LoggerHelper.Instance.Error($"tunnel {transport.Name} get remote {remoteMachineId} external ip fail ");
break;
}
LoggerHelper.Instance.Info($"tunnel {transport.Name} got remote external ip {remoteInfo.ToJson()}");
tunnelTransportInfo = new TunnelTransportInfo TunnelTransportInfo tunnelTransportInfo = null;
//是否在失败后尝试反向连接
int times = transportItem.Reverse ? 1 : 0;
for (int i = 0; i <= times; i++)
{
try
{ {
Direction = (TunnelDirection)i, //获取自己的外网ip
TransactionId = transactionId, Task<TunnelTransportWanPortInfo> localInfo = GetLocalInfo(wanPortProtocol);
TransportName = transport.Name, //获取对方的外网ip
TransportType = transport.ProtocolType, Task<TunnelTransportWanPortInfo> remoteInfo = tunnelAdapter.GetRemoteWanPort(new TunnelWanPortProtocolInfo
Local = localInfo, {
Remote = remoteInfo, MachineId = remoteMachineId,
SSL = transportItem.SSL ProtocolType = wanPortProtocol.ProtocolType,
}; Type = wanPortProtocol.Type,
OnConnecting(tunnelTransportInfo); });
ParseRemoteEndPoint(tunnelTransportInfo); await Task.WhenAll(localInfo, remoteInfo);
ITunnelConnection connection = await transport.ConnectAsync(tunnelTransportInfo);
if (connection != null) if (localInfo.Result == null)
{
LoggerHelper.Instance.Error($"tunnel {transport.Name} get local external ip fail ");
break;
}
if (remoteInfo.Result == null)
{
LoggerHelper.Instance.Error($"tunnel {transport.Name} get remote {remoteMachineId} external ip fail ");
break;
}
LoggerHelper.Instance.Info($"tunnel {transport.Name} got local external ip {localInfo.ToJson()}");
LoggerHelper.Instance.Info($"tunnel {transport.Name} got remote external ip {remoteInfo.ToJson()}");
tunnelTransportInfo = new TunnelTransportInfo
{
Direction = (TunnelDirection)i,
TransactionId = transactionId,
TransportName = transport.Name,
TransportType = transport.ProtocolType,
Local = localInfo.Result,
Remote = remoteInfo.Result,
SSL = transportItem.SSL
};
OnConnecting(tunnelTransportInfo);
ParseRemoteEndPoint(tunnelTransportInfo);
ITunnelConnection connection = await transport.ConnectAsync(tunnelTransportInfo);
if (connection != null)
{
_OnConnected(connection);
return connection;
}
}
catch (Exception ex)
{ {
_OnConnected(connection); if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
return connection; {
LoggerHelper.Instance.Error(ex);
}
} }
} }
catch (Exception ex) if (tunnelTransportInfo != null)
{ {
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) OnConnectFail(tunnelTransportInfo);
{
LoggerHelper.Instance.Error(ex);
}
} }
} }
if (tunnelTransportInfo != null)
{
OnConnectFail(tunnelTransportInfo);
}
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -239,18 +287,19 @@ namespace linker.tunnel
/// 获取自己的外网IP给别人调用 /// 获取自己的外网IP给别人调用
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<TunnelTransportWanPortInfo> GetWanPort() public async Task<TunnelTransportWanPortInfo> GetWanPort(TunnelWanPortProtocolInfo _info)
{ {
return await GetLocalInfo(); TunnelWanPortInfo info = tunnelAdapter.GetTunnelWanPortProtocols().FirstOrDefault(c => c.Type == _info.Type && c.ProtocolType == _info.ProtocolType);
return await GetLocalInfo(info);
} }
/// <summary> /// <summary>
/// 获取自己的外网IP /// 获取自己的外网IP
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<TunnelTransportWanPortInfo> GetLocalInfo() private async Task<TunnelTransportWanPortInfo> GetLocalInfo(TunnelWanPortInfo info)
{ {
TunnelWanPortEndPoint ip = await compactTransfer.GetWanPortAsync(tunnelAdapter.LocalIP); TunnelWanPortEndPoint ip = await compactTransfer.GetWanPortAsync(tunnelAdapter.LocalIP, info);
if (ip != null) if (ip != null)
{ {
var config = tunnelAdapter.GetLocalConfig(); var config = tunnelAdapter.GetLocalConfig();

View File

@@ -21,12 +21,12 @@ namespace linker.tunnel.adapter
/// 获取外网端口协议列表 /// 获取外网端口协议列表
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public List<TunnelWanPortInfo> GetTunnelWanPortCompacts(); public List<TunnelWanPortInfo> GetTunnelWanPortProtocols();
/// <summary> /// <summary>
/// 保存外网端口协议列表 /// 保存外网端口协议列表
/// </summary> /// </summary>
/// <param name="compacts"></param> /// <param name="compacts"></param>
public void SetTunnelWanPortCompacts(List<TunnelWanPortInfo> compacts); public void SetTunnelWanPortProtocols(List<TunnelWanPortInfo> protocols);
/// <summary> /// <summary>
/// 获取打洞协议列表 /// 获取打洞协议列表
@@ -49,7 +49,7 @@ namespace linker.tunnel.adapter
/// </summary> /// </summary>
/// <param name="remoteMachineId"></param> /// <param name="remoteMachineId"></param>
/// <returns></returns> /// <returns></returns>
public Task<TunnelTransportWanPortInfo> GetRemoteWanPort(string remoteMachineId); public Task<TunnelTransportWanPortInfo> GetRemoteWanPort(TunnelWanPortProtocolInfo info);
/// <summary> /// <summary>
/// 发送开始打洞 /// 发送开始打洞
@@ -86,4 +86,20 @@ namespace linker.tunnel.adapter
/// </summary> /// </summary>
public string MachineId { get; set; } public string MachineId { get; set; }
} }
public sealed class TunnelWanPortProtocolInfo
{
/// <summary>
/// 类别
/// </summary>
public TunnelWanPortType Type { get; set; }
/// <summary>
/// 协议
/// </summary>
public TunnelWanPortProtocolType ProtocolType { get; set; } = TunnelWanPortProtocolType.Udp;
/// <summary>
/// 本机名
/// </summary>
public string MachineId { get; set; }
}
} }

View File

@@ -1,13 +1,43 @@
using linker.tunnel.connection; using linker.tunnel.connection;
using linker.tunnel.wanport;
using System.Net; using System.Net;
namespace linker.tunnel.transport namespace linker.tunnel.transport
{ {
public interface ITunnelTransport public interface ITunnelTransport
{ {
/// <summary>
/// 打洞协议名
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary>
/// 打洞协议说明
/// </summary>
public string Label { get; } public string Label { get; }
/// <summary>
/// 隧道协议
/// </summary>
public TunnelProtocolType ProtocolType { get; } public TunnelProtocolType ProtocolType { get; }
/// <summary>
/// 允许哪些端口协议
/// </summary>
public TunnelWanPortProtocolType AllowWanPortProtocolType { get; }
/// <summary>
/// 是否反向打洞
/// </summary>
public bool Reverse { get; }
/// <summary>
/// 是否允许修改反向打洞配置
/// </summary>
public bool DisableReverse { get; }
/// <summary>
/// 是否ssl
/// </summary>
public bool SSL { get; }
/// <summary>
/// 是否允许修改ssl配置
/// </summary>
public bool DisableSSL { get; }
/// <summary> /// <summary>
/// 发送连接开始信息 /// 发送连接开始信息
@@ -91,7 +121,9 @@ namespace linker.tunnel.transport
public bool Disabled { get; set; } = false; public bool Disabled { get; set; } = false;
public bool Reverse { get; set; } = true; public bool Reverse { get; set; } = true;
public bool DisableReverse { get; set; } = false;
public bool SSL { get; set; } = true; public bool SSL { get; set; } = true;
public bool DisableSSL { get; set; } = false;
public byte BufferSize { get; set; } = 4; public byte BufferSize { get; set; } = 4;
} }

View File

@@ -2,7 +2,6 @@
using linker.tunnel.connection; using linker.tunnel.connection;
using linker.libs; using linker.libs;
using linker.libs.extends; using linker.libs.extends;
using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Net; using System.Net;
using System.Net.Quic; using System.Net.Quic;
@@ -10,6 +9,7 @@ using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication; using System.Security.Authentication;
using System.Text; using System.Text;
using linker.tunnel.wanport;
namespace linker.tunnel.transport namespace linker.tunnel.transport
{ {
@@ -20,12 +20,22 @@ namespace linker.tunnel.transport
public string Label => "MsQuicwin10+、linux"; public string Label => "MsQuicwin10+、linux";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Quic; public TunnelProtocolType ProtocolType => TunnelProtocolType.Quic;
public TunnelWanPortProtocolType AllowWanPortProtocolType => TunnelWanPortProtocolType.Udp;
public bool Reverse => true;
public bool DisableReverse => false;
public bool SSL => true;
public bool DisableSSL => true;
public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; } = async (info) => { return await Task.FromResult<bool>(false); }; public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; } = async (info) => { return await Task.FromResult<bool>(false); };
public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } = async (info) => { await Task.CompletedTask; }; public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } = async (info) => { await Task.CompletedTask; };
public Func<TunnelTransportInfo, Task> OnSendConnectSuccess { get; set; } = async (info) => { await Task.CompletedTask; }; public Func<TunnelTransportInfo, Task> OnSendConnectSuccess { get; set; } = async (info) => { await Task.CompletedTask; };
public Action<ITunnelConnection> OnConnected { get; set; } = (state) => { }; public Action<ITunnelConnection> OnConnected { get; set; } = (state) => { };
private ConcurrentDictionary<int, ListenAsyncToken> stateDic = new ConcurrentDictionary<int, ListenAsyncToken>(); private ConcurrentDictionary<int, ListenAsyncToken> stateDic = new ConcurrentDictionary<int, ListenAsyncToken>();
private byte[] authBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.ttl"); private byte[] authBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.ttl");

View File

@@ -8,6 +8,7 @@ using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using linker.tunnel.wanport;
namespace linker.tunnel.transport namespace linker.tunnel.transport
{ {
@@ -16,6 +17,15 @@ namespace linker.tunnel.transport
public string Name => "TcpNutssb"; public string Name => "TcpNutssb";
public string Label => "TCP、低TTL"; public string Label => "TCP、低TTL";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp; public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp;
public TunnelWanPortProtocolType AllowWanPortProtocolType => TunnelWanPortProtocolType.Udp;
public bool Reverse => true;
public bool DisableReverse => false;
public bool SSL => true;
public bool DisableSSL => false;
/// <summary> /// <summary>
/// 发送开始连接消息 /// 发送开始连接消息

View File

@@ -8,6 +8,7 @@ using System.Net.Sockets;
using System.Security.Authentication; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using linker.tunnel.wanport;
namespace linker.tunnel.transport namespace linker.tunnel.transport
{ {
@@ -16,6 +17,14 @@ namespace linker.tunnel.transport
public string Name => "TcpP2PNAT"; public string Name => "TcpP2PNAT";
public string Label => "TCP、同时打开"; public string Label => "TCP、同时打开";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp; public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp;
public TunnelWanPortProtocolType AllowWanPortProtocolType => TunnelWanPortProtocolType.Tcp;
public bool Reverse => false;
public bool DisableReverse => true;
public bool SSL => true;
public bool DisableSSL => false;
/// <summary> /// <summary>
/// 发送开始连接消息 /// 发送开始连接消息
@@ -56,6 +65,7 @@ namespace linker.tunnel.transport
{ {
return null; return null;
} }
await Task.Delay(50);
ITunnelConnection connection = await ConnectForward(tunnelTransportInfo, TunnelMode.Client); ITunnelConnection connection = await ConnectForward(tunnelTransportInfo, TunnelMode.Client);
if (connection != null) if (connection != null)
{ {
@@ -110,7 +120,7 @@ namespace linker.tunnel.transport
try try
{ {
targetSocket.KeepAlive(); targetSocket.KeepAlive();
targetSocket.ReuseBind(new IPEndPoint(IPAddress.Any, tunnelTransportInfo.Local.Local.Port)); targetSocket.ReuseBind(new IPEndPoint(tunnelTransportInfo.Local.Local.Address, tunnelTransportInfo.Local.Local.Port));
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{ {
@@ -137,6 +147,12 @@ namespace linker.tunnel.transport
private async Task<ITunnelConnection> TcpClient(TunnelTransportInfo state, Socket socket) private async Task<ITunnelConnection> TcpClient(TunnelTransportInfo state, Socket socket)
{ {
//随便发个消息看对方有没有收到
await socket.SendAsync(authBytes);
//如果对方收到,会回个消息,不管是啥,回了就行
int length = await socket.ReceiveAsync(new byte[1024]);
if (length == 0) return null;
//需要ssl //需要ssl
SslStream sslStream = null; SslStream sslStream = null;
if (state.SSL) if (state.SSL)
@@ -167,6 +183,15 @@ namespace linker.tunnel.transport
{ {
try try
{ {
//对方会随便发个消息,不管是啥
int length = await socket.ReceiveAsync(new byte[1024]);
if (length == 0)
{
return null;
}
//回个消息给它就完了
await socket.SendAsync(endBytes);
socket.KeepAlive(); socket.KeepAlive();
SslStream sslStream = null; SslStream sslStream = null;
if (state.SSL) if (state.SSL)

View File

@@ -5,6 +5,7 @@ using System.Collections.Concurrent;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using linker.tunnel.wanport;
namespace linker.tunnel.transport namespace linker.tunnel.transport
{ {
@@ -15,12 +16,22 @@ namespace linker.tunnel.transport
public string Label => "udp"; public string Label => "udp";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp; public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp;
public TunnelWanPortProtocolType AllowWanPortProtocolType => TunnelWanPortProtocolType.Udp;
public bool Reverse => true;
public bool DisableReverse => false;
public bool SSL => true;
public bool DisableSSL => false;
public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; } = async (info) => { return await Task.FromResult<bool>(false); }; public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; } = async (info) => { return await Task.FromResult<bool>(false); };
public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } = async (info) => { await Task.CompletedTask; }; public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } = async (info) => { await Task.CompletedTask; };
public Func<TunnelTransportInfo, Task> OnSendConnectSuccess { get; set; } = async (info) => { await Task.CompletedTask; }; public Func<TunnelTransportInfo, Task> OnSendConnectSuccess { get; set; } = async (info) => { await Task.CompletedTask; };
public Action<ITunnelConnection> OnConnected { get; set; } = (state) => { }; public Action<ITunnelConnection> OnConnected { get; set; } = (state) => { };
private byte[] authBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.ttl"); private byte[] authBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.ttl");
private byte[] endBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.end"); private byte[] endBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.end");

View File

@@ -5,10 +5,11 @@ namespace linker.tunnel.wanport
/// <summary> /// <summary>
/// 外网端口协议 /// 外网端口协议
/// </summary> /// </summary>
public interface ITunnelWanPort public interface ITunnelWanPortProtocol
{ {
public string Name { get; } public string Name { get; }
public TunnelWanPortType Type { get; } public TunnelWanPortType Type { get; }
public TunnelWanPortProtocolType ProtocolType { get; }
/// <summary> /// <summary>
/// 获取外网端口 /// 获取外网端口
/// </summary> /// </summary>
@@ -39,6 +40,7 @@ namespace linker.tunnel.wanport
/// 协议类别 /// 协议类别
/// </summary> /// </summary>
public TunnelWanPortType Type { get; set; } public TunnelWanPortType Type { get; set; }
public TunnelWanPortProtocolType ProtocolType { get; set; } = TunnelWanPortProtocolType.Udp;
/// <summary> /// <summary>
/// 地址 /// 地址
/// </summary> /// </summary>
@@ -55,6 +57,13 @@ namespace linker.tunnel.wanport
Stun = 1 Stun = 1
} }
[Flags]
public enum TunnelWanPortProtocolType : byte
{
Tcp = 1,
Udp = 2,
}
public sealed class TunnelWanPortTypeInfo public sealed class TunnelWanPortTypeInfo
{ {
public TunnelWanPortType Value { get; set; } public TunnelWanPortType Value { get; set; }

View File

@@ -1,54 +0,0 @@
using linker.libs.extends;
using System.Net;
using System.Net.Sockets;
namespace linker.tunnel.wanport
{
public sealed class TunnelWanPortLinker : ITunnelWanPort
{
public string Name => "默认";
public TunnelWanPortType Type => TunnelWanPortType.Linker;
public TunnelWanPortLinker()
{
}
public async Task<TunnelWanPortEndPoint> GetAsync(IPEndPoint server)
{
UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork);
udpClient.Client.Reuse();
udpClient.Client.WindowsUdpBug();
for (int i = 0; i < 5; i++)
{
try
{
await udpClient.SendAsync(new byte[1] { 0 }, server);
UdpReceiveResult result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromMilliseconds(500));
if (result.Buffer.Length == 0)
{
return null;
}
for (int j = 0; j < result.Buffer.Length; j++)
{
result.Buffer[j] = (byte)(result.Buffer[j] ^ byte.MaxValue);
}
AddressFamily addressFamily = (AddressFamily)result.Buffer[0];
int length = addressFamily == AddressFamily.InterNetwork ? 4 : 16;
IPAddress ip = new IPAddress(result.Buffer.AsSpan(1, length));
ushort port = result.Buffer.AsMemory(1 + length).ToUInt16();
IPEndPoint remoteEP = new IPEndPoint(ip, port);
return new TunnelWanPortEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = remoteEP };
}
catch (Exception)
{
}
}
return null;
}
}
}

View File

@@ -0,0 +1,109 @@
using linker.libs.extends;
using System.Buffers;
using System.Net;
using System.Net.Sockets;
namespace linker.tunnel.wanport
{
public sealed class TunnelWanPortProtocolLinkerUdp : ITunnelWanPortProtocol
{
public string Name => "Linker Udp";
public TunnelWanPortType Type => TunnelWanPortType.Linker;
public TunnelWanPortProtocolType ProtocolType => TunnelWanPortProtocolType.Udp;
public TunnelWanPortProtocolLinkerUdp()
{
}
public async Task<TunnelWanPortEndPoint> GetAsync(IPEndPoint server)
{
UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork);
udpClient.Client.Reuse();
udpClient.Client.WindowsUdpBug();
for (int i = 0; i < 5; i++)
{
try
{
await udpClient.SendAsync(new byte[1] { 0 }, server);
UdpReceiveResult result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromMilliseconds(500));
if (result.Buffer.Length == 0)
{
return null;
}
for (int j = 0; j < result.Buffer.Length; j++)
{
result.Buffer[j] = (byte)(result.Buffer[j] ^ byte.MaxValue);
}
AddressFamily addressFamily = (AddressFamily)result.Buffer[0];
int length = addressFamily == AddressFamily.InterNetwork ? 4 : 16;
IPAddress ip = new IPAddress(result.Buffer.AsSpan(1, length));
ushort port = result.Buffer.AsMemory(1 + length).ToUInt16();
IPEndPoint remoteEP = new IPEndPoint(ip, port);
return new TunnelWanPortEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = remoteEP };
}
catch (Exception)
{
}
}
return null;
}
}
public sealed class TunnelWanPortProtocolLinkerTcp : ITunnelWanPortProtocol
{
public string Name => "Linker Tcp";
public TunnelWanPortType Type => TunnelWanPortType.Linker;
public TunnelWanPortProtocolType ProtocolType => TunnelWanPortProtocolType.Tcp;
public TunnelWanPortProtocolLinkerTcp()
{
}
public async Task<TunnelWanPortEndPoint> GetAsync(IPEndPoint server)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(20);
try
{
Socket socket = new Socket(server.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
await socket.ConnectAsync(server);
await socket.SendAsync(new byte[] { 0 });
int length = await socket.ReceiveAsync(buffer.AsMemory(), SocketFlags.None);
for (int j = 0; j < length; j++)
{
buffer[j] = (byte)(buffer[j] ^ byte.MaxValue);
}
AddressFamily addressFamily = (AddressFamily)buffer[0];
int iplength = addressFamily == AddressFamily.InterNetwork ? 4 : 16;
IPAddress ip = new IPAddress(buffer.AsSpan(1, iplength));
ushort port = buffer.AsMemory(1 + iplength).ToUInt16();
IPEndPoint remoteEP = new IPEndPoint(ip, port);
IPEndPoint localEP = socket.LocalEndPoint as IPEndPoint;
socket.Close();
return new TunnelWanPortEndPoint { Local = localEP, Remote = remoteEP };
}
catch (Exception)
{
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
return null;
}
}
}

View File

@@ -5,12 +5,14 @@ using System.Net.Sockets;
namespace linker.tunnel.wanport namespace linker.tunnel.wanport
{ {
public sealed class TunnelWanPortStun : ITunnelWanPort public sealed class TunnelWanPortProtocolStun : ITunnelWanPortProtocol
{ {
public string Name => "Stun"; public string Name => "Stun Udp";
public TunnelWanPortType Type => TunnelWanPortType.Stun; public TunnelWanPortType Type => TunnelWanPortType.Stun;
public TunnelWanPortStun() public TunnelWanPortProtocolType ProtocolType => TunnelWanPortProtocolType.Udp;
public TunnelWanPortProtocolStun()
{ {
} }

View File

@@ -1,5 +1,4 @@
using linker.tunnel.adapter; using linker.libs;
using linker.libs;
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
@@ -10,8 +9,7 @@ namespace linker.tunnel.wanport
/// </summary> /// </summary>
public sealed class TunnelWanPortTransfer public sealed class TunnelWanPortTransfer
{ {
private List<ITunnelWanPort> tunnelWanPorts; private List<ITunnelWanPortProtocol> tunnelWanPorts;
private ITunnelAdapter tunnelAdapter;
public TunnelWanPortTransfer() public TunnelWanPortTransfer()
{ {
@@ -21,10 +19,8 @@ namespace linker.tunnel.wanport
/// 加载所有外网端口协议 /// 加载所有外网端口协议
/// </summary> /// </summary>
/// <param name="assembs"></param> /// <param name="assembs"></param>
public void Init(ITunnelAdapter tunnelAdapter, List<ITunnelWanPort> tunnelWanPorts) public void Init(List<ITunnelWanPortProtocol> tunnelWanPorts)
{ {
this.tunnelAdapter = tunnelAdapter;
this.tunnelWanPorts = tunnelWanPorts; this.tunnelWanPorts = tunnelWanPorts;
LoggerHelper.Instance.Warning($"load tunnel wanport compacts:{string.Join(",", tunnelWanPorts.Select(c => c.Name))}"); LoggerHelper.Instance.Warning($"load tunnel wanport compacts:{string.Join(",", tunnelWanPorts.Select(c => c.Name))}");
} }
@@ -39,37 +35,31 @@ namespace linker.tunnel.wanport
/// </summary> /// </summary>
/// <param name="localIP">你的局域网IP</param> /// <param name="localIP">你的局域网IP</param>
/// <returns></returns> /// <returns></returns>
public async Task<TunnelWanPortEndPoint> GetWanPortAsync(IPAddress localIP) public async Task<TunnelWanPortEndPoint> GetWanPortAsync(IPAddress localIP, TunnelWanPortInfo info)
{ {
var tunnelWanPortItems = tunnelAdapter.GetTunnelWanPortCompacts(); if (info == null) return null;
foreach (TunnelWanPortInfo item in tunnelWanPortItems) var tunnelWanPort = tunnelWanPorts.FirstOrDefault(c => c.Type == info.Type && c.ProtocolType == info.ProtocolType);
try
{ {
if (item.Disabled || string.IsNullOrWhiteSpace(item.Host)) continue; Stopwatch sw = new Stopwatch();
ITunnelWanPort tunnelWanPort = tunnelWanPorts.FirstOrDefault(c => c.Type == item.Type); sw.Start();
if (tunnelWanPort == null) continue; IPEndPoint server = NetworkHelper.GetEndPoint(info.Host, 3478);
sw.Stop();
try if (sw.ElapsedMilliseconds > 1000)
{ {
Stopwatch sw = new Stopwatch(); LoggerHelper.Instance.Warning($"get domain ip time:{sw.ElapsedMilliseconds}ms");
sw.Start();
IPEndPoint server = NetworkHelper.GetEndPoint(item.Host, 3478);
sw.Stop();
if (sw.ElapsedMilliseconds > 1000)
{
LoggerHelper.Instance.Warning($"get domain ip time:{sw.ElapsedMilliseconds}ms");
}
TunnelWanPortEndPoint WanPort = await tunnelWanPort.GetAsync(server);
if (WanPort != null)
{
WanPort.Local.Address = localIP;
return WanPort;
}
} }
catch (Exception ex) TunnelWanPortEndPoint WanPort = await tunnelWanPort.GetAsync(server);
if (WanPort != null)
{ {
LoggerHelper.Instance.Error(ex); WanPort.Local.Address = localIP;
return WanPort;
} }
} }
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
}
return null; return null;
} }
} }

View File

@@ -8,7 +8,7 @@
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick"> <el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
<el-table-column property="Name" label="名称"> <el-table-column property="Name" label="名称">
<template #default="scope"> <template #default="scope">
<template v-if="scope.row.NameEditing"> <template v-if="scope.row.NameEditing && scope.row.Started==false">
<el-input autofocus size="small" v-model="scope.row.Name" <el-input autofocus size="small" v-model="scope.row.Name"
@blur="handleEditBlur(scope.row, 'Name')"></el-input> @blur="handleEditBlur(scope.row, 'Name')"></el-input>
</template> </template>
@@ -26,14 +26,14 @@
</el-table-column> </el-table-column>
<el-table-column property="BindIPAddress" label="监听IP" width="140"> <el-table-column property="BindIPAddress" label="监听IP" width="140">
<template #default="scope"> <template #default="scope">
<el-select v-model="scope.row.BindIPAddress" size="small"> <el-select v-model="scope.row.BindIPAddress" size="small" :disabled="scope.row.Started">
<el-option v-for="item in state.ips" :key="item" :label="item" :value="item"/> <el-option v-for="item in state.ips" :key="item" :label="item" :value="item"/>
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column property="Port" label="监听端口" width="80"> <el-table-column property="Port" label="监听端口" width="80">
<template #default="scope"> <template #default="scope">
<template v-if="scope.row.PortEditing"> <template v-if="scope.row.PortEditing && scope.row.Started==false">
<el-input type="number" autofocus size="small" v-model="scope.row.Port" <el-input type="number" autofocus size="small" v-model="scope.row.Port"
@blur="handleEditBlur(scope.row, 'Port')"></el-input> @blur="handleEditBlur(scope.row, 'Port')"></el-input>
</template> </template>
@@ -56,7 +56,7 @@
</el-table-column> </el-table-column>
<el-table-column property="TargetEP" label="目标服务" width="140"> <el-table-column property="TargetEP" label="目标服务" width="140">
<template #default="scope"> <template #default="scope">
<template v-if="scope.row.TargetEPEditing"> <template v-if="scope.row.TargetEPEditing && scope.row.Started==false">
<el-input autofocus size="small" v-model="scope.row.TargetEP" <el-input autofocus size="small" v-model="scope.row.TargetEP"
@blur="handleEditBlur(scope.row, 'TargetEP')"></el-input> @blur="handleEditBlur(scope.row, 'TargetEP')"></el-input>
</template> </template>
@@ -173,6 +173,10 @@ export default {
saveRow({ ID: 0, Name: '', Port: 0, TargetEP: '127.0.0.1:80', machineId: state.machineId }); saveRow({ ID: 0, Name: '', Port: 0, TargetEP: '127.0.0.1:80', machineId: state.machineId });
} }
const handleEdit = (row, p) => { const handleEdit = (row, p) => {
if(row.Started){
ElMessage.error('请先停止');
return;
}
state.data.forEach(c => { state.data.forEach(c => {
c[`NameEditing`] = false; c[`NameEditing`] = false;
c[`PortEditing`] = false; c[`PortEditing`] = false;
@@ -182,6 +186,10 @@ export default {
row[`${p}Editing`] = true; row[`${p}Editing`] = true;
} }
const handleEditBlur = (row, p) => { const handleEditBlur = (row, p) => {
if(row.Started){
ElMessage.error('请先停止');
return;
}
row[`${p}Editing`] = false; row[`${p}Editing`] = false;
saveRow(row); saveRow(row);
} }

View File

@@ -8,7 +8,7 @@
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick"> <el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
<el-table-column property="Name" label="名称"> <el-table-column property="Name" label="名称">
<template #default="scope"> <template #default="scope">
<template v-if="scope.row.NameEditing"> <template v-if="scope.row.NameEditing && scope.row.Started==false ">
<el-input autofocus size="small" v-model="scope.row.Name" <el-input autofocus size="small" v-model="scope.row.Name"
@blur="handleEditBlur(scope.row, 'Name')"></el-input> @blur="handleEditBlur(scope.row, 'Name')"></el-input>
</template> </template>
@@ -24,7 +24,7 @@
</el-table-column> </el-table-column>
<el-table-column property="Temp" label="远程端口/域名" width="160"> <el-table-column property="Temp" label="远程端口/域名" width="160">
<template #default="scope"> <template #default="scope">
<template v-if="scope.row.TempEditing"> <template v-if="scope.row.TempEditing && scope.row.Started==false">
<el-input autofocus size="small" v-model="scope.row.Temp" <el-input autofocus size="small" v-model="scope.row.Temp"
@blur="handleEditBlur(scope.row, 'Temp')"></el-input> @blur="handleEditBlur(scope.row, 'Temp')"></el-input>
</template> </template>
@@ -45,7 +45,7 @@
</el-table-column> </el-table-column>
<el-table-column property="LocalEP" label="本机服务" width="140"> <el-table-column property="LocalEP" label="本机服务" width="140">
<template #default="scope"> <template #default="scope">
<template v-if="scope.row.LocalEPEditing"> <template v-if="scope.row.LocalEPEditing && scope.row.Started==false">
<el-input autofocus size="small" v-model="scope.row.LocalEP" <el-input autofocus size="small" v-model="scope.row.LocalEP"
@blur="handleEditBlur(scope.row, 'LocalEP')"></el-input> @blur="handleEditBlur(scope.row, 'LocalEP')"></el-input>
</template> </template>
@@ -152,6 +152,10 @@ export default {
}); });
} }
const handleEdit = (row, p) => { const handleEdit = (row, p) => {
if(row.Started){
ElMessage.error('请先停止运行');
return;
}
state.data.forEach(c => { state.data.forEach(c => {
c[`NameEditing`] = false; c[`NameEditing`] = false;
c[`RemotePortEditing`] = false; c[`RemotePortEditing`] = false;
@@ -162,6 +166,10 @@ export default {
row[`${p}Editing`] = true; row[`${p}Editing`] = true;
} }
const handleEditBlur = (row, p) => { const handleEditBlur = (row, p) => {
if(row.Started){
ElMessage.error('请先停止运行');
return;
}
row[`${p}Editing`] = false; row[`${p}Editing`] = false;
saveRow(row); saveRow(row);
} }

View File

@@ -17,9 +17,9 @@
</template> </template>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="Type" label="类别" width="80"> <el-table-column prop="RelayType" label="类别" width="80">
<template #default="scope"> <template #default="scope">
<el-select v-model="scope.row.Type" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'Type')"> <el-select v-model="scope.row.RelayType" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'RelayType')">
<el-option v-for="item in state.types" :key="item.Value" :label="item.Name" :value="item.Value"/> <el-option v-for="item in state.types" :key="item.Value" :label="item.Name" :value="item.Value"/>
</el-select> </el-select>
</template> </template>
@@ -109,7 +109,7 @@ export default {
const handleEdit = (row, p) => { const handleEdit = (row, p) => {
state.list.forEach(c => { state.list.forEach(c => {
c[`NameEditing`] = false; c[`NameEditing`] = false;
c[`TypeEditing`] = false; c[`RelayTypeEditing`] = false;
c[`HostEditing`] = false; c[`HostEditing`] = false;
c[`SecretKeyEditing`] = false; c[`SecretKeyEditing`] = false;
}) })
@@ -128,7 +128,7 @@ export default {
if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){ if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){
return; return;
} }
state.list.splice(index+1,0,{Name:'',Host:'',Type:0,SecretKey:'snltty',Disabled:false}); state.list.splice(index+1,0,{Name:'',Host:'',RelayType:0,SecretKey:'snltty',Disabled:false});
handleSave(); handleSave();
} }

View File

@@ -18,12 +18,12 @@
</el-table-column> </el-table-column>
<el-table-column property="Reverse" label="反向" width="60"> <el-table-column property="Reverse" label="反向" width="60">
<template #default="scope"> <template #default="scope">
<el-switch v-model="scope.row.Reverse" @change="handleSave" inline-prompt active-text="是" inactive-text="否" /> <el-switch :disabled="scope.row.DisableReverse" v-model="scope.row.Reverse" @change="handleSave" inline-prompt active-text="是" inactive-text="否" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column property="SSL" label="SSL" width="60"> <el-table-column property="SSL" label="SSL" width="60">
<template #default="scope"> <template #default="scope">
<el-switch v-model="scope.row.SSL" @change="handleSave" inline-prompt active-text="是" inactive-text="否" /> <el-switch :disabled="scope.row.DisableSSL" v-model="scope.row.SSL" @change="handleSave" inline-prompt active-text="是" inactive-text="否" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column property="Disabled" label="禁用" width="60"> <el-table-column property="Disabled" label="禁用" width="60">

View File

@@ -3,7 +3,7 @@
<div class="pdr-10 pdb-6 flex-1"> <div class="pdr-10 pdb-6 flex-1">
<el-checkbox v-model="state.sync" label="将更改同步到所有客户端" /> <el-checkbox v-model="state.sync" label="将更改同步到所有客户端" />
</div> </div>
<div>将按顺序获取IP直到其中一个成功获取连接不同地域的服务器可能会走不同线路</div> <div>将按顺序获取IP进行尝试打洞</div>
</div> </div>
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick"> <el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick">
<el-table-column prop="Name" label="名称"> <el-table-column prop="Name" label="名称">
@@ -17,6 +17,16 @@
</template> </template>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="ProtocolType" label="协议" width="100">
<template #default="scope">
<div>
<el-select v-model="scope.row.ProtocolType" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'ProtocolType')">
<el-option v-for="(item,index) in state.protocolTypes" :key="+index" :label="item" :value="+index"/>
</el-select>
</div>
</template>
</el-table-column>
<el-table-column prop="Type" label="类别" width="100"> <el-table-column prop="Type" label="类别" width="100">
<template #default="scope"> <template #default="scope">
<el-select v-model="scope.row.Type" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'Type')"> <el-select v-model="scope.row.Type" placeholder="Select" size="small" @change="handleEditBlur(scope.row, 'Type')">
@@ -81,7 +91,8 @@ export default {
list:((globalData.value.config.Running.Tunnel || {Servers:[]}).Servers || []).sort((a,b)=>a.Disabled - b.Disabled), list:((globalData.value.config.Running.Tunnel || {Servers:[]}).Servers || []).sort((a,b)=>a.Disabled - b.Disabled),
types:[], types:[],
height: computed(()=>globalData.value.height-130), height: computed(()=>globalData.value.height-130),
sync:true sync:true,
protocolTypes:{1:'tcp',2:'udp'},
}); });
const _getTunnelTypes = ()=>{ const _getTunnelTypes = ()=>{
@@ -98,6 +109,7 @@ export default {
c[`NameEditing`] = false; c[`NameEditing`] = false;
c[`TypeEditing`] = false; c[`TypeEditing`] = false;
c[`HostEditing`] = false; c[`HostEditing`] = false;
c[`ProtocolTypeEditing`] = false;
}) })
row[`${p}Editing`] = true; row[`${p}Editing`] = true;
} }
@@ -114,7 +126,7 @@ export default {
if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){ if(state.list.filter(c=>c.Host == '' || c.Name == '').length > 0){
return; return;
} }
state.list.splice(index+1,0,{Name:'',Host:'',Type:0,Disabled:false}); state.list.splice(index+1,0,{Name:'',Host:'',Type:0,Disabled:false,ProtocolType:2});
handleSave(); handleSave();
} }

View File

@@ -10,10 +10,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId> <_TargetId>Folder</_TargetId>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <SelfContained>false</SelfContained>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<History>True|2024-06-02T07:39:16.1880914Z;True|2024-06-02T15:38:26.4314913+08:00;True|2024-06-02T15:27:20.2651650+08:00;True|2024-06-02T15:26:34.3414728+08:00;True|2024-06-02T15:22:33.1407820+08:00;True|2024-06-02T15:22:01.4381533+08:00;True|2024-06-02T15:20:29.6692030+08:00;True|2024-06-02T15:19:55.9152032+08:00;True|2024-06-02T15:16:15.2278365+08:00;True|2024-04-23T09:09:03.5136215+08:00;True|2024-04-22T12:57:38.4988098+08:00;True|2023-12-23T09:50:45.7841097+08:00;True|2023-11-17T09:24:26.3650754+08:00;True|2023-11-17T09:11:28.0867966+08:00;True|2023-11-17T09:09:49.7366925+08:00;False|2023-11-17T09:08:56.6254247+08:00;False|2023-11-17T09:08:45.4560896+08:00;True|2023-11-16T11:49:56.3722044+08:00;True|2023-11-16T11:48:06.3192199+08:00;True|2023-11-16T11:47:35.3708397+08:00;True|2023-11-16T11:45:11.0208634+08:00;False|2023-11-16T11:44:01.7611210+08:00;True|2023-10-01T17:27:31.0065885+08:00;True|2023-09-04T18:19:54.7492652+08:00;True|2023-09-04T18:19:32.2969345+08:00;False|2023-09-04T18:18:51.7827366+08:00;True|2023-09-04T18:15:31.6783417+08:00;True|2023-09-04T18:14:40.9964104+08:00;</History> <History>True|2024-07-01T09:25:46.1203574Z;True|2024-06-02T15:39:16.1880914+08:00;True|2024-06-02T15:38:26.4314913+08:00;True|2024-06-02T15:27:20.2651650+08:00;True|2024-06-02T15:26:34.3414728+08:00;True|2024-06-02T15:22:33.1407820+08:00;True|2024-06-02T15:22:01.4381533+08:00;True|2024-06-02T15:20:29.6692030+08:00;True|2024-06-02T15:19:55.9152032+08:00;True|2024-06-02T15:16:15.2278365+08:00;True|2024-04-23T09:09:03.5136215+08:00;True|2024-04-22T12:57:38.4988098+08:00;True|2023-12-23T09:50:45.7841097+08:00;True|2023-11-17T09:24:26.3650754+08:00;True|2023-11-17T09:11:28.0867966+08:00;True|2023-11-17T09:09:49.7366925+08:00;False|2023-11-17T09:08:56.6254247+08:00;False|2023-11-17T09:08:45.4560896+08:00;True|2023-11-16T11:49:56.3722044+08:00;True|2023-11-16T11:48:06.3192199+08:00;True|2023-11-16T11:47:35.3708397+08:00;True|2023-11-16T11:45:11.0208634+08:00;False|2023-11-16T11:44:01.7611210+08:00;True|2023-10-01T17:27:31.0065885+08:00;True|2023-09-04T18:19:54.7492652+08:00;True|2023-09-04T18:19:32.2969345+08:00;False|2023-09-04T18:18:51.7827366+08:00;True|2023-09-04T18:15:31.6783417+08:00;True|2023-09-04T18:14:40.9964104+08:00;</History>
<LastFailureDetails /> <LastFailureDetails />
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<_LastSelectedProfileId>C:\Users\snltty\Desktop\cmonitor\cmonitor\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId> <_LastSelectedProfileId>C:\Users\snltty\Desktop\linker\linker\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
<ActiveDebugProfile>cmonitor</ActiveDebugProfile> <ActiveDebugProfile>cmonitor</ActiveDebugProfile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -31,7 +31,7 @@ namespace linker.plugins.relay
/// </summary> /// </summary>
/// <param name="param"></param> /// <param name="param"></param>
/// <returns></returns> /// <returns></returns>
public List<RelayCompactTypeInfo> GetTypes(ApiControllerParamsInfo param) public List<RelayTypeInfo> GetTypes(ApiControllerParamsInfo param)
{ {
return relayTransfer.GetTypes(); return relayTransfer.GetTypes();
} }
@@ -64,7 +64,7 @@ namespace linker.plugins.relay
public sealed class RelayCompactParamInfo public sealed class RelayCompactParamInfo
{ {
public bool Sync { get; set; } public bool Sync { get; set; }
public RelayCompactInfo[] List { get; set; } = Array.Empty<RelayCompactInfo>(); public RelayServerInfo[] List { get; set; } = Array.Empty<RelayServerInfo>();
} }
} }

View File

@@ -31,11 +31,11 @@ namespace linker.plugins.relay
if (running.Data.Relay.Servers.Length == 0) if (running.Data.Relay.Servers.Length == 0)
{ {
running.Data.Relay.Servers = new RelayCompactInfo[] running.Data.Relay.Servers = new RelayServerInfo[]
{ {
new RelayCompactInfo{ new RelayServerInfo{
Name="默认", Name="默认",
Type= RelayCompactType.linker, RelayType= RelayType.Linker,
Disabled = false, Disabled = false,
Host = running.Data.Client.Servers.FirstOrDefault().Host Host = running.Data.Client.Servers.FirstOrDefault().Host
} }
@@ -58,15 +58,15 @@ namespace linker.plugins.relay
/// 获取所有中继协议 /// 获取所有中继协议
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public List<RelayCompactTypeInfo> GetTypes() public List<RelayTypeInfo> GetTypes()
{ {
return transports.Select(c => new RelayCompactTypeInfo { Value = c.Type, Name = c.Type.ToString() }).Distinct(new RelayCompactTypeInfoEqualityComparer()).ToList(); return transports.Select(c => new RelayTypeInfo { Value = c.Type, Name = c.Type.ToString() }).Distinct(new RelayCompactTypeInfoEqualityComparer()).ToList();
} }
/// <summary> /// <summary>
/// 收到中继协议列表 /// 收到中继协议列表
/// </summary> /// </summary>
/// <param name="servers"></param> /// <param name="servers"></param>
public void OnServers(RelayCompactInfo[] servers) public void OnServers(RelayServerInfo[] servers)
{ {
running.Data.Relay.Servers = servers; running.Data.Relay.Servers = servers;
running.Data.Update(); running.Data.Update();
@@ -113,9 +113,9 @@ namespace linker.plugins.relay
try try
{ {
IEnumerable<ITransport> _transports = transports.OrderBy(c => c.Type); IEnumerable<ITransport> _transports = transports.OrderBy(c => c.Type);
foreach (RelayCompactInfo item in running.Data.Relay.Servers.Where(c => c.Disabled == false && string.IsNullOrWhiteSpace(c.Host) == false)) foreach (RelayServerInfo item in running.Data.Relay.Servers.Where(c => c.Disabled == false && string.IsNullOrWhiteSpace(c.Host) == false))
{ {
ITransport transport = _transports.FirstOrDefault(c => c.Type == item.Type); ITransport transport = _transports.FirstOrDefault(c => c.Type == item.RelayType);
if (transport == null) if (transport == null)
{ {
continue; continue;

View File

@@ -14,7 +14,7 @@ namespace linker.client.config
public sealed class RelayRunningInfo public sealed class RelayRunningInfo
{ {
public ObjectId Id { get; set; } public ObjectId Id { get; set; }
public RelayCompactInfo[] Servers { get; set; } = Array.Empty<RelayCompactInfo>(); public RelayServerInfo[] Servers { get; set; } = Array.Empty<RelayServerInfo>();
} }
} }
@@ -33,35 +33,35 @@ namespace linker.config
} }
[MemoryPackable] [MemoryPackable]
public sealed partial class RelayCompactInfo public sealed partial class RelayServerInfo
{ {
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public RelayCompactType Type { get; set; } = RelayCompactType.linker; public RelayType RelayType { get; set; } = RelayType.Linker;
public string SecretKey { get; set; } = "snltty"; public string SecretKey { get; set; } = "snltty";
public string Host { get; set; } = string.Empty; public string Host { get; set; } = string.Empty;
public bool Disabled { get; set; } public bool Disabled { get; set; }
public bool SSL { get; set; } = true; public bool SSL { get; set; } = true;
} }
public enum RelayCompactType : byte public enum RelayType : byte
{ {
linker = 0, Linker = 0,
} }
public sealed class RelayCompactTypeInfo public sealed class RelayTypeInfo
{ {
public RelayCompactType Value { get; set; } public RelayType Value { get; set; }
public string Name { get; set; } public string Name { get; set; }
} }
public sealed class RelayCompactTypeInfoEqualityComparer : IEqualityComparer<RelayCompactTypeInfo> public sealed class RelayCompactTypeInfoEqualityComparer : IEqualityComparer<RelayTypeInfo>
{ {
public bool Equals(RelayCompactTypeInfo x, RelayCompactTypeInfo y) public bool Equals(RelayTypeInfo x, RelayTypeInfo y)
{ {
return x.Value == y.Value; return x.Value == y.Value;
} }
public int GetHashCode([DisallowNull] RelayCompactTypeInfo obj) public int GetHashCode([DisallowNull] RelayTypeInfo obj)
{ {
return obj.Value.GetHashCode(); return obj.Value.GetHashCode();
} }

View File

@@ -39,7 +39,7 @@ namespace linker.plugins.relay.messenger
[MessengerId((ushort)RelayMessengerIds.Servers)] [MessengerId((ushort)RelayMessengerIds.Servers)]
public void Servers(IConnection connection) public void Servers(IConnection connection)
{ {
RelayCompactInfo[] servers = MemoryPackSerializer.Deserialize<RelayCompactInfo[]>(connection.ReceiveRequestWrap.Payload.Span); RelayServerInfo[] servers = MemoryPackSerializer.Deserialize<RelayServerInfo[]>(connection.ReceiveRequestWrap.Payload.Span);
relayTransfer.OnServers(servers); relayTransfer.OnServers(servers);
} }
} }
@@ -71,7 +71,7 @@ namespace linker.plugins.relay.messenger
[MessengerId((ushort)RelayMessengerIds.ServersForward)] [MessengerId((ushort)RelayMessengerIds.ServersForward)]
public async Task ServersForward(IConnection connection) public async Task ServersForward(IConnection connection)
{ {
RelayCompactInfo[] servers = MemoryPackSerializer.Deserialize<RelayCompactInfo[]>(connection.ReceiveRequestWrap.Payload.Span); RelayServerInfo[] servers = MemoryPackSerializer.Deserialize<RelayServerInfo[]>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache)) if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
{ {

View File

@@ -17,7 +17,7 @@ namespace linker.plugins.relay.transport
/// <summary> /// <summary>
/// 中继类型 /// 中继类型
/// </summary> /// </summary>
public RelayCompactType Type { get; } public RelayType Type { get; }
/// <summary> /// <summary>
/// 协议 /// 协议
/// </summary> /// </summary>

View File

@@ -17,7 +17,7 @@ namespace linker.plugins.relay.transport
public sealed class TransportSelfHost : ITransport public sealed class TransportSelfHost : ITransport
{ {
public string Name => "默认"; public string Name => "默认";
public RelayCompactType Type => RelayCompactType.linker; public RelayType Type => RelayType.Linker;
public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp; public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp;
private readonly TcpServer tcpServer; private readonly TcpServer tcpServer;

View File

@@ -10,8 +10,6 @@ using MemoryPack;
using System.Net; using System.Net;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using linker.tunnel.wanport; using linker.tunnel.wanport;
using System.Linq;
using linker.libs.extends;
using System.Buffers.Binary; using System.Buffers.Binary;
namespace linker.plugins.tunnel namespace linker.plugins.tunnel
@@ -42,11 +40,11 @@ namespace linker.plugins.tunnel
} }
} }
public List<TunnelWanPortInfo> GetTunnelWanPortCompacts() public List<TunnelWanPortInfo> GetTunnelWanPortProtocols()
{ {
return running.Data.Tunnel.Servers.ToList(); return running.Data.Tunnel.Servers.ToList();
} }
public void SetTunnelWanPortCompacts(List<TunnelWanPortInfo> compacts) public void SetTunnelWanPortProtocols(List<TunnelWanPortInfo> compacts)
{ {
running.Data.Tunnel.Servers = compacts.ToArray(); running.Data.Tunnel.Servers = compacts.ToArray();
running.Data.Update(); running.Data.Update();
@@ -68,16 +66,16 @@ namespace linker.plugins.tunnel
{ {
LocalIps = config.Data.Client.Tunnel.LocalIPs LocalIps = config.Data.Client.Tunnel.LocalIPs
.Where(c => c.Equals(running.Data.Tuntap.IP) == false) .Where(c => c.Equals(running.Data.Tuntap.IP) == false)
.Where(c=> .Where(c =>
{ {
if(c.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) if (c.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{ {
uint ip = BinaryPrimitives.ReadUInt32BigEndian(c.GetAddressBytes()); uint ip = BinaryPrimitives.ReadUInt32BigEndian(c.GetAddressBytes());
foreach (var item in running.Data.Tunnel.ExcludeIPs) foreach (var item in running.Data.Tunnel.ExcludeIPs)
{ {
uint maskValue = NetworkHelper.MaskValue(item.Mask); uint maskValue = NetworkHelper.MaskValue(item.Mask);
uint ip1 = BinaryPrimitives.ReadUInt32BigEndian(item.IPAddress.GetAddressBytes()); uint ip1 = BinaryPrimitives.ReadUInt32BigEndian(item.IPAddress.GetAddressBytes());
if((ip & maskValue) == (ip1 & maskValue)) if ((ip & maskValue) == (ip1 & maskValue))
{ {
return false; return false;
} }
@@ -90,13 +88,13 @@ namespace linker.plugins.tunnel
MachineId = config.Data.Client.Id MachineId = config.Data.Client.Id
}; };
} }
public async Task<TunnelTransportWanPortInfo> GetRemoteWanPort(string remoteMachineId) public async Task<TunnelTransportWanPortInfo> GetRemoteWanPort(TunnelWanPortProtocolInfo info)
{ {
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{ {
Connection = clientSignInState.Connection, Connection = clientSignInState.Connection,
MessengerId = (ushort)TunnelMessengerIds.InfoForward, MessengerId = (ushort)TunnelMessengerIds.InfoForward,
Payload = MemoryPackSerializer.Serialize(remoteMachineId) Payload = MemoryPackSerializer.Serialize(info)
}); });
if (resp.Code == MessageResponeCodes.OK && resp.Data.Length > 0) if (resp.Code == MessageResponeCodes.OK && resp.Data.Length > 0)
{ {

View File

@@ -82,7 +82,7 @@ namespace linker.plugins.tunnel
{ {
SetServersParamInfo info = param.Content.DeJson<SetServersParamInfo>(); SetServersParamInfo info = param.Content.DeJson<SetServersParamInfo>();
tunnelMessengerAdapter.SetTunnelWanPortCompacts(info.List.ToList()); tunnelMessengerAdapter.SetTunnelWanPortProtocols(info.List.ToList());
if (info.Sync) if (info.Sync)
{ {
await messengerSender.SendOnly(new MessageRequestWrap await messengerSender.SendOnly(new MessageRequestWrap

View File

@@ -38,10 +38,10 @@ namespace linker.plugins.tunnel
running.Data.Tunnel.Servers = new TunnelWanPortInfo[] running.Data.Tunnel.Servers = new TunnelWanPortInfo[]
{ {
new TunnelWanPortInfo{ new TunnelWanPortInfo{
Name="默认", Name="Linker Udp",
Type= TunnelWanPortType.Linker, Type= TunnelWanPortType.Linker,
Disabled = false, Disabled = false,
Host = running.Data.Client.Servers.FirstOrDefault().Host Host = running.Data.Client.Servers.FirstOrDefault().Host,
} }
}; };
} }

View File

@@ -42,14 +42,14 @@ namespace linker.plugins.tunnel
//外网端口协议 //外网端口协议
serviceCollection.AddSingleton<TunnelWanPortTransfer>(); serviceCollection.AddSingleton<TunnelWanPortTransfer>();
serviceCollection.AddSingleton<TunnelWanPortLinker>(); serviceCollection.AddSingleton<TunnelWanPortProtocolLinkerUdp>();
serviceCollection.AddSingleton<TunnelWanPortStun>(); serviceCollection.AddSingleton<TunnelWanPortProtocolStun>();
//打洞协议 //打洞协议
serviceCollection.AddSingleton<TunnelTransfer>(); serviceCollection.AddSingleton<TunnelTransfer>();
serviceCollection.AddSingleton<TunnelTransportTcpNutssb>(); serviceCollection.AddSingleton<TunnelTransportTcpNutssb>();
serviceCollection.AddSingleton<TransportMsQuic>(); serviceCollection.AddSingleton<TransportMsQuic>();
serviceCollection.AddSingleton<TransportMsQuic>(); serviceCollection.AddSingleton<TransportTcpP2PNAT>();
serviceCollection.AddSingleton<TunnelConfigTransfer>(); serviceCollection.AddSingleton<TunnelConfigTransfer>();
serviceCollection.AddSingleton<ITunnelAdapter, TunnelAdapter>(); serviceCollection.AddSingleton<ITunnelAdapter, TunnelAdapter>();
@@ -77,10 +77,10 @@ namespace linker.plugins.tunnel
{ {
ITunnelAdapter tunnelAdapter = serviceProvider.GetService<ITunnelAdapter>(); ITunnelAdapter tunnelAdapter = serviceProvider.GetService<ITunnelAdapter>();
IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assemblies.Concat(new Assembly[] { typeof(TunnelWanPortTransfer).Assembly }).ToArray(), typeof(ITunnelWanPort)); IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assemblies.Concat(new Assembly[] { typeof(TunnelWanPortTransfer).Assembly }).ToArray(), typeof(ITunnelWanPortProtocol));
List<ITunnelWanPort> compacts = types.Select(c => (ITunnelWanPort)serviceProvider.GetService(c)).Where(c => c != null).Where(c => string.IsNullOrWhiteSpace(c.Name) == false).ToList(); List<ITunnelWanPortProtocol> compacts = types.Select(c => (ITunnelWanPortProtocol)serviceProvider.GetService(c)).Where(c => c != null).Where(c => string.IsNullOrWhiteSpace(c.Name) == false).ToList();
TunnelWanPortTransfer compack = serviceProvider.GetService<TunnelWanPortTransfer>(); TunnelWanPortTransfer compack = serviceProvider.GetService<TunnelWanPortTransfer>();
compack.Init(tunnelAdapter,compacts); compack.Init(compacts);
types = ReflectionHelper.GetInterfaceSchieves(assemblies.Concat(new Assembly[] { typeof(TunnelTransfer).Assembly }).ToArray(), typeof(ITunnelTransport)); types = ReflectionHelper.GetInterfaceSchieves(assemblies.Concat(new Assembly[] { typeof(TunnelTransfer).Assembly }).ToArray(), typeof(ITunnelTransport));

View File

@@ -5,6 +5,8 @@ using LiteDB;
using MemoryPack; using MemoryPack;
using System.Net; using System.Net;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using linker.tunnel.adapter;
using System.Net.Sockets;
namespace linker.client.config namespace linker.client.config
@@ -29,7 +31,7 @@ namespace linker.client.config
public sealed partial class ExcludeIPItem public sealed partial class ExcludeIPItem
{ {
[MemoryPackAllowSerialize] [MemoryPackAllowSerialize]
public IPAddress IPAddress { get; set;} public IPAddress IPAddress { get; set; }
public byte Mask { get; set; } = 32; public byte Mask { get; set; } = 32;
} }
} }
@@ -60,6 +62,60 @@ namespace linker.config
} }
[MemoryPackable]
public readonly partial struct SerializableTunnelWanPortProtocolInfo
{
[MemoryPackIgnore]
public readonly TunnelWanPortProtocolInfo info;
[MemoryPackInclude]
string MachineId => info.MachineId;
[MemoryPackInclude]
TunnelWanPortType Type => info.Type;
[MemoryPackInclude]
TunnelWanPortProtocolType ProtocolType => info.ProtocolType;
[MemoryPackConstructor]
SerializableTunnelWanPortProtocolInfo(string machineId, TunnelWanPortType type, TunnelWanPortProtocolType protocolType)
{
var info = new TunnelWanPortProtocolInfo { MachineId = machineId, Type = type, ProtocolType = protocolType };
this.info = info;
}
public SerializableTunnelWanPortProtocolInfo(TunnelWanPortProtocolInfo tunnelCompactInfo)
{
this.info = tunnelCompactInfo;
}
}
public class TunnelWanPortProtocolInfoFormatter : MemoryPackFormatter<TunnelWanPortProtocolInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref TunnelWanPortProtocolInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableTunnelWanPortProtocolInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref TunnelWanPortProtocolInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableTunnelWanPortProtocolInfo>();
value = wrapped.info;
}
}
[MemoryPackable] [MemoryPackable]
public readonly partial struct SerializableTunnelWanPortInfo public readonly partial struct SerializableTunnelWanPortInfo
{ {

View File

@@ -39,7 +39,8 @@ namespace linker.plugins.tunnel.messenger
[MessengerId((ushort)TunnelMessengerIds.Info)] [MessengerId((ushort)TunnelMessengerIds.Info)]
public async Task Info(IConnection connection) public async Task Info(IConnection connection)
{ {
TunnelTransportWanPortInfo tunnelTransportPortInfo = await tunnel.GetWanPort(); TunnelWanPortProtocolInfo info = MemoryPackSerializer.Deserialize<TunnelWanPortProtocolInfo>(connection.ReceiveRequestWrap.Payload.Span);
TunnelTransportWanPortInfo tunnelTransportPortInfo = await tunnel.GetWanPort(info);
if (tunnelTransportPortInfo != null) if (tunnelTransportPortInfo != null)
{ {
connection.Write(MemoryPackSerializer.Serialize(tunnelTransportPortInfo)); connection.Write(MemoryPackSerializer.Serialize(tunnelTransportPortInfo));
@@ -95,7 +96,7 @@ namespace linker.plugins.tunnel.messenger
public void Servers(IConnection connection) public void Servers(IConnection connection)
{ {
TunnelWanPortInfo[] servers = MemoryPackSerializer.Deserialize<TunnelWanPortInfo[]>(connection.ReceiveRequestWrap.Payload.Span); TunnelWanPortInfo[] servers = MemoryPackSerializer.Deserialize<TunnelWanPortInfo[]>(connection.ReceiveRequestWrap.Payload.Span);
tunnelMessengerAdapter.SetTunnelWanPortCompacts(servers.ToList()); tunnelMessengerAdapter.SetTunnelWanPortProtocols(servers.ToList());
} }
[MessengerId((ushort)TunnelMessengerIds.ExcludeIPs)] [MessengerId((ushort)TunnelMessengerIds.ExcludeIPs)]
@@ -119,8 +120,8 @@ namespace linker.plugins.tunnel.messenger
[MessengerId((ushort)TunnelMessengerIds.InfoForward)] [MessengerId((ushort)TunnelMessengerIds.InfoForward)]
public void InfoForward(IConnection connection) public void InfoForward(IConnection connection)
{ {
string remoteMachineId = MemoryPackSerializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span); TunnelWanPortProtocolInfo info = MemoryPackSerializer.Deserialize<TunnelWanPortProtocolInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(remoteMachineId, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId) if (signCaching.TryGet(info.MachineId, out SignCacheInfo cache) && signCaching.TryGet(connection.Id, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
{ {
uint requestid = connection.ReceiveRequestWrap.RequestId; uint requestid = connection.ReceiveRequestWrap.RequestId;
_ = messengerSender.SendReply(new MessageRequestWrap _ = messengerSender.SendReply(new MessageRequestWrap

View File

@@ -1,5 +1,6 @@
using linker.libs; using linker.libs;
using linker.libs.extends; using linker.libs.extends;
using System.Buffers;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
@@ -64,6 +65,20 @@ namespace linker.server
} }
private Memory<byte> BuildSendData(byte[] data, IPEndPoint ep)
{
//给客户端返回他的IP+端口
data[0] = (byte)ep.AddressFamily;
ep.Address.TryWriteBytes(data.AsSpan(1), out int length);
((ushort)ep.Port).ToBytes(data.AsMemory(1 + length));
//防止一些网关修改掉它的外网IP
for (int i = 0; i < 1 + length + 2; i++)
{
data[i] = (byte)(data[i] ^ byte.MaxValue);
}
return data.AsMemory(0, 1 + length + 2);
}
private async Task BindUdp(int port) private async Task BindUdp(int port)
{ {
@@ -81,18 +96,9 @@ namespace linker.server
IPEndPoint ep = result.RemoteEndPoint as IPEndPoint; IPEndPoint ep = result.RemoteEndPoint as IPEndPoint;
try try
{ {
//给客户端返回他的IP+端口 Memory<byte> memory = BuildSendData(sendData, ep);
sendData[0] = (byte)ep.AddressFamily;
ep.Address.TryWriteBytes(sendData.AsSpan(1), out int length);
((ushort)ep.Port).ToBytes(sendData.AsMemory(1 + length));
//防止一些网关修改掉它的外网IP await socketUdp.SendToAsync(memory, ep);
for (int i = 0; i < 1 + length + 2; i++)
{
sendData[i] = (byte)(sendData[i] ^ byte.MaxValue);
}
await socketUdp.SendToAsync(sendData.AsMemory(0, 1 + length + 2), ep);
} }
catch (Exception) catch (Exception)
{ {
@@ -140,15 +146,45 @@ namespace linker.server
StartAccept(e); StartAccept(e);
} }
} }
private async Task<IConnection> BeginReceiveServer(Socket socket)
private async Task<byte> ReceiveType(Socket socket)
{
byte[] sendData = ArrayPool<byte>.Shared.Rent(20);
try
{
await socket.ReceiveAsync(sendData.AsMemory(0, 1), SocketFlags.None);
byte type = sendData[0];
if (type == 0)
{
Memory<byte> memory = BuildSendData(sendData, socket.RemoteEndPoint as IPEndPoint);
await socket.SendAsync(memory, SocketFlags.None);
}
return type;
}
catch (Exception)
{
}
finally
{
ArrayPool<byte>.Shared.Return(sendData);
}
return 1;
}
private async Task BeginReceiveServer(Socket socket)
{ {
try try
{ {
if (socket == null || socket.RemoteEndPoint == null) if (socket == null || socket.RemoteEndPoint == null)
{ {
return null; return;
} }
socket.KeepAlive(); socket.KeepAlive();
if (await ReceiveType(socket) == 0)
{
return;
}
NetworkStream networkStream = new NetworkStream(socket, false); NetworkStream networkStream = new NetworkStream(socket, false);
SslStream sslStream = new SslStream(networkStream, true); SslStream sslStream = new SslStream(networkStream, true);
await sslStream.AuthenticateAsServerAsync(serverCertificate, false, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false); await sslStream.AuthenticateAsServerAsync(serverCertificate, false, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false);
@@ -156,14 +192,12 @@ namespace linker.server
connection.BeginReceive(connectionReceiveCallback, null, true); connection.BeginReceive(connectionReceiveCallback, null, true);
return connection;
} }
catch (Exception ex) catch (Exception ex)
{ {
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error(ex); LoggerHelper.Instance.Error(ex);
} }
return null;
} }
private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
@@ -179,6 +213,7 @@ namespace linker.server
return null; return null;
} }
socket.KeepAlive(); socket.KeepAlive();
await socket.SendAsync(new byte[] { 1 });
NetworkStream networkStream = new NetworkStream(socket, false); NetworkStream networkStream = new NetworkStream(socket, false);
SslStream sslStream = new SslStream(networkStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); SslStream sslStream = new SslStream(networkStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions

View File

@@ -17,6 +17,7 @@ for %%r in (win-x64,win-arm64) do (
echo F|xcopy "linker\\msquic.dll" "public\\extends\\%%r\\linker-%%r\\msquic.dll" /s /f /h /y echo F|xcopy "linker\\msquic.dll" "public\\extends\\%%r\\linker-%%r\\msquic.dll" /s /f /h /y
echo F|xcopy "linker\\msquic-openssl.dll" "public\\extends\\%%r\\linker-%%r\\msquic-openssl.dll" /s /f /h /y echo F|xcopy "linker\\msquic-openssl.dll" "public\\extends\\%%r\\linker-%%r\\msquic-openssl.dll" /s /f /h /y
) )
for %%r in (linux-x64,linux-arm64,osx-x64,osx-arm64) do ( for %%r in (linux-x64,linux-arm64,osx-x64,osx-arm64) do (
echo F|xcopy "linker\\plugins\\tuntap\\tun2socks-%%r" "public\\extends\\%%r\\linker-%%r\\plugins\\tuntap\\tun2socks" /s /f /h /y echo F|xcopy "linker\\plugins\\tuntap\\tun2socks-%%r" "public\\extends\\%%r\\linker-%%r\\plugins\\tuntap\\tun2socks" /s /f /h /y
) )
@@ -24,7 +25,6 @@ for %%r in (win-x64,win-arm64) do (
echo F|xcopy "linker\\plugins\\tuntap\\tun2socks-%%r" "public\\extends\\%%r\\linker-%%r\\plugins\\tuntap\\tun2socks.exe" /s /f /h /y echo F|xcopy "linker\\plugins\\tuntap\\tun2socks-%%r" "public\\extends\\%%r\\linker-%%r\\plugins\\tuntap\\tun2socks.exe" /s /f /h /y
) )
for %%r in (win-x64,win-arm64,linux-x64,linux-arm64,osx-x64,osx-arm64) do ( for %%r in (win-x64,win-arm64,linux-x64,linux-arm64,osx-x64,osx-arm64) do (
dotnet publish ./linker -c release -f net8.0 -o ./public/publish/%%r/linker-%%r -r %%r -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:PublishSingleFile=true -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true dotnet publish ./linker -c release -f net8.0 -o ./public/publish/%%r/linker-%%r -r %%r -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:PublishSingleFile=true -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
@@ -33,4 +33,4 @@ for %%r in (win-x64,win-arm64,linux-x64,linux-arm64,osx-x64,osx-arm64) do (
echo F|xcopy "public\\extends\\any\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y echo F|xcopy "public\\extends\\any\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y
7z a -tzip ./public/publish-zip/linker-%%r.zip ./public/publish/%%r/* 7z a -tzip ./public/publish-zip/linker-%%r.zip ./public/publish/%%r/*
) )