mirror of
https://github.com/snltty/linker.git
synced 2025-12-18 01:16:46 +08:00
170
This commit is contained in:
@@ -153,9 +153,9 @@ action.json
|
||||
|
||||
:::tip[v1.7.0+]
|
||||
1. 如果你使用第三方程序启动linker,`仅配置文件不存在时初始化,后续不会覆盖`,可以传入参数进行初始化,`client.json`、`server.json`、`action.json`、`common.json`,
|
||||
2. 像这样,不填写的字段将以默认值生成,json的双引号需要转义,json里不能有空格
|
||||
2. 像这样,不填写的字段将以默认值生成,将json转为base64
|
||||
```
|
||||
linker.exe --config-client {\"a\":\"1\"} --config-server {\"a\":\"1\"} --config-action {\"a\":\"1\"} --config-common {\"a\":\"1\"}
|
||||
linker.exe --config-client base641 --config-server base642 --config-action base643 --config-common base644
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ using linker.messenger.updater;
|
||||
using linker.messenger.store.file;
|
||||
using linker.messenger.serializer.memorypack;
|
||||
using linker.libs;
|
||||
using linker.libs.extends;
|
||||
|
||||
namespace linker.messenger.entry
|
||||
{
|
||||
@@ -30,11 +29,6 @@ namespace linker.messenger.entry
|
||||
private static OperatingManager builded = new OperatingManager();
|
||||
private static OperatingManager setuped = new OperatingManager();
|
||||
|
||||
public static void InputJsonConfig(string str)
|
||||
{
|
||||
|
||||
Console.WriteLine(str.DeJson<ConfigClientInfo>().ToJsonFormat());
|
||||
}
|
||||
/// <summary>
|
||||
/// 开始初始化
|
||||
/// </summary>
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace linker.messenger.listen
|
||||
{
|
||||
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, port);
|
||||
Socket socket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
socket.IPv6Only(localEndPoint.AddressFamily, false);
|
||||
//socket.IPv6Only(localEndPoint.AddressFamily, false);
|
||||
socket.Bind(localEndPoint);
|
||||
socket.Listen(int.MaxValue);
|
||||
|
||||
|
||||
@@ -329,4 +329,318 @@ namespace linker.messenger.relay.client.transport
|
||||
return new List<RelayServerNodeReportInfo170>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class RelayClientTransportSelfHostUdp : IRelayClientTransport
|
||||
{
|
||||
public string Name => "LinkerUdp";
|
||||
public RelayClientType Type => RelayClientType.Linker;
|
||||
public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp;
|
||||
|
||||
private readonly IMessengerSender messengerSender;
|
||||
private readonly ISerializer serializer;
|
||||
private readonly IRelayClientStore relayClientStore;
|
||||
private readonly SignInClientState signInClientState;
|
||||
private readonly IMessengerStore messengerStore;
|
||||
|
||||
public RelayClientTransportSelfHostUdp(IMessengerSender messengerSender, ISerializer serializer, IRelayClientStore relayClientStore, SignInClientState signInClientState, IMessengerStore messengerStore)
|
||||
{
|
||||
this.messengerSender = messengerSender;
|
||||
this.serializer = serializer;
|
||||
this.relayClientStore = relayClientStore;
|
||||
this.signInClientState = signInClientState;
|
||||
this.messengerStore = messengerStore;
|
||||
}
|
||||
|
||||
public async Task<ITunnelConnection> RelayAsync(RelayInfo170 relayInfo)
|
||||
{
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
|
||||
try
|
||||
{
|
||||
//问一下能不能中继
|
||||
RelayAskResultInfo170 relayAskResultInfo = await RelayAsk(relayInfo);
|
||||
relayInfo.FlowingId = relayAskResultInfo.FlowingId;
|
||||
if (relayInfo.FlowingId == 0 || relayAskResultInfo.Nodes.Count == 0)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay ask fail,flowid:{relayInfo.FlowingId},nodes:{relayAskResultInfo.Nodes.Count}");
|
||||
return null;
|
||||
}
|
||||
|
||||
//测试一下延迟
|
||||
if (relayAskResultInfo.Nodes.Count > 1)
|
||||
{
|
||||
//relayAskResultInfo.Nodes = await TestDelay(relayAskResultInfo.Nodes);
|
||||
}
|
||||
|
||||
//连接中继节点服务器
|
||||
Socket socket = await ConnectNodeServer(relayInfo, relayAskResultInfo.Nodes);
|
||||
if (socket == null)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay connect server fail,flowid:{relayInfo.FlowingId},nodes:{relayAskResultInfo.Nodes.Count}");
|
||||
return null;
|
||||
}
|
||||
|
||||
//让对方确认中继
|
||||
if (await RelayConfirm(relayInfo) == false)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay confirm fail,flowid:{relayInfo.FlowingId},nodes:{relayAskResultInfo.Nodes.Count}");
|
||||
return null;
|
||||
}
|
||||
|
||||
//成功建立连接,
|
||||
SslStream sslStream = null;
|
||||
if (relayInfo.SSL)
|
||||
{
|
||||
sslStream = new SslStream(new NetworkStream(socket, false), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
|
||||
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
|
||||
{
|
||||
EnabledSslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return new TunnelConnectionTcp
|
||||
{
|
||||
Direction = TunnelDirection.Forward,
|
||||
ProtocolType = TunnelProtocolType.Tcp,
|
||||
RemoteMachineId = relayInfo.RemoteMachineId,
|
||||
RemoteMachineName = relayInfo.RemoteMachineName,
|
||||
Stream = sslStream,
|
||||
Socket = socket,
|
||||
Mode = TunnelMode.Client,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = relayInfo.TransactionId,
|
||||
TransportName = Name,
|
||||
Type = TunnelType.Relay,
|
||||
NodeId = relayInfo.NodeId,
|
||||
SSL = relayInfo.SSL,
|
||||
BufferSize = 3
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<RelayAskResultInfo170> RelayAsk(RelayInfo170 relayInfo)
|
||||
{
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.RelayAsk170,
|
||||
Payload = serializer.Serialize(relayInfo),
|
||||
Timeout = 2000
|
||||
}).ConfigureAwait(false);
|
||||
if (resp.Code != MessageResponeCodes.OK)
|
||||
{
|
||||
return new RelayAskResultInfo170();
|
||||
}
|
||||
|
||||
RelayAskResultInfo170 result = serializer.Deserialize<RelayAskResultInfo170>(resp.Data.Span);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
private async Task<Socket> ConnectNodeServer(RelayInfo170 relayInfo, List<RelayServerNodeReportInfo170> nodes)
|
||||
{
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(1 * 1024);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var node in nodes.Where(c => c.Id == relayInfo.NodeId).Concat(nodes.Where(c => c.Id != relayInfo.NodeId)))
|
||||
{
|
||||
try
|
||||
{
|
||||
IPEndPoint ep = node.EndPoint;
|
||||
if (ep == null || ep.Address.Equals(IPAddress.Any))
|
||||
{
|
||||
ep = signInClientState.Connection.Address;
|
||||
}
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Debug($"connect relay server {ep}");
|
||||
|
||||
//连接中继服务器
|
||||
Socket socket = new Socket(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
|
||||
socket.KeepAlive();
|
||||
await socket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
|
||||
//建立关联
|
||||
RelayMessageInfo relayMessage = new RelayMessageInfo
|
||||
{
|
||||
FlowId = relayInfo.FlowingId,
|
||||
Type = RelayMessengerType.Ask,
|
||||
FromId = relayInfo.FromMachineId,
|
||||
ToId = relayInfo.RemoteMachineId,
|
||||
NodeId = node.Id,
|
||||
};
|
||||
await socket.SendAsync(new byte[] { (byte)ResolverType.Relay });
|
||||
await socket.SendAsync(serializer.Serialize(relayMessage));
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"relay connected {ep}");
|
||||
|
||||
//是否允许连接
|
||||
int length = await socket.ReceiveAsync(buffer.AsMemory(0, 1));
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Debug($"relay connected {ep}->{buffer[0]}");
|
||||
if (buffer[0] == 0)
|
||||
{
|
||||
relayInfo.Server = node.EndPoint;
|
||||
relayInfo.NodeId = node.Id;
|
||||
return socket;
|
||||
}
|
||||
socket.SafeClose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private async Task<bool> RelayConfirm(RelayInfo170 relayInfo)
|
||||
{
|
||||
//通知对方去确认中继
|
||||
var resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.RelayForward170,
|
||||
Payload = serializer.Serialize(relayInfo),
|
||||
});
|
||||
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
||||
}
|
||||
|
||||
|
||||
private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public async Task<bool> OnBeginAsync(RelayInfo170 relayInfo, Action<ITunnelConnection> callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPEndPoint ep = relayInfo.Server == null || relayInfo.Server.Address.Equals(IPAddress.Any) ? signInClientState.Connection.Address : relayInfo.Server;
|
||||
|
||||
Socket socket = new Socket(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
|
||||
socket.KeepAlive();
|
||||
await socket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
|
||||
RelayMessageInfo relayMessage = new RelayMessageInfo
|
||||
{
|
||||
FlowId = relayInfo.FlowingId,
|
||||
Type = RelayMessengerType.Answer,
|
||||
FromId = relayInfo.FromMachineId,
|
||||
ToId = relayInfo.RemoteMachineId,
|
||||
NodeId = relayInfo.NodeId,
|
||||
};
|
||||
await socket.SendAsync(new byte[] { (byte)ResolverType.Relay });
|
||||
await socket.SendAsync(serializer.Serialize(relayMessage));
|
||||
|
||||
_ = WaitSSL(socket, relayInfo).ContinueWith((result) =>
|
||||
{
|
||||
callback(result.Result);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
callback(null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<TunnelConnectionTcp> WaitSSL(Socket socket, RelayInfo170 relayInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
SslStream sslStream = null;
|
||||
if (relayInfo.SSL)
|
||||
{
|
||||
sslStream = new SslStream(new NetworkStream(socket, false), false);
|
||||
await sslStream.AuthenticateAsServerAsync(messengerStore.Certificate, false, SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false).ConfigureAwait(false);
|
||||
}
|
||||
return new TunnelConnectionTcp
|
||||
{
|
||||
Direction = TunnelDirection.Reverse,
|
||||
ProtocolType = TunnelProtocolType.Tcp,
|
||||
RemoteMachineId = relayInfo.RemoteMachineId,
|
||||
RemoteMachineName = relayInfo.RemoteMachineName,
|
||||
Stream = sslStream,
|
||||
Socket = socket,
|
||||
Mode = TunnelMode.Server,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = relayInfo.TransactionId,
|
||||
TransportName = Name,
|
||||
Type = TunnelType.Relay,
|
||||
NodeId = relayInfo.NodeId,
|
||||
SSL = relayInfo.SSL,
|
||||
BufferSize = 3,
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
socket.SafeClose();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<List<RelayServerNodeReportInfo170>> RelayTestAsync(RelayTestInfo170 relayTestInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.RelayTest170,
|
||||
Payload = serializer.Serialize(relayTestInfo),
|
||||
Timeout = 2000
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
if (resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
return serializer.Deserialize<List<RelayServerNodeReportInfo170>>(resp.Data.Span);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return new List<RelayServerNodeReportInfo170>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +168,15 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
return limitTotal.TryLimit(ref length);
|
||||
}
|
||||
/// <summary>
|
||||
/// 总限速
|
||||
/// </summary>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryLimitPacket(int length)
|
||||
{
|
||||
return limitTotal.TryLimitPacket(length);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -342,7 +351,7 @@ namespace linker.messenger.relay.server
|
||||
MaxGbTotal = node.MaxGbTotal,
|
||||
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
||||
MaxConnection = node.MaxConnection,
|
||||
ConnectionRatio = Math.Round(connectionNum / 2.0),
|
||||
ConnectionRatio = connectionNum,
|
||||
EndPoint = endPoint,
|
||||
Url = node.Url
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ using linker.libs.extends;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using linker.libs;
|
||||
using System;
|
||||
|
||||
namespace linker.messenger.relay.server
|
||||
{
|
||||
@@ -20,9 +21,12 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
this.relayServerNodeTransfer = relayServerNodeTransfer;
|
||||
this.serializer = serializer;
|
||||
ClearTask();
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, RelayWrapInfo> relayDic = new ConcurrentDictionary<ulong, RelayWrapInfo>();
|
||||
private readonly ConcurrentDictionary<ulong, TaskCompletionSource<Socket>> relayDic = new ConcurrentDictionary<ulong, TaskCompletionSource<Socket>>();
|
||||
private readonly ConcurrentDictionary<IPEndPoint, RelayUdpNatInfo> udpNat = new ConcurrentDictionary<IPEndPoint, RelayUdpNatInfo>();
|
||||
private readonly ConcurrentDictionary<ulong, RelayUdpNatInfo> relayUdpDic = new ConcurrentDictionary<ulong, RelayUdpNatInfo>();
|
||||
|
||||
public virtual void AddReceive(string key, string from, string to, string groupid, long bytes)
|
||||
{
|
||||
@@ -40,15 +44,100 @@ namespace linker.messenger.relay.server
|
||||
|
||||
public async Task Resolve(Socket socket, IPEndPoint ep, Memory<byte> memory)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
RelayUdpStep step = (RelayUdpStep)memory.Span[0];
|
||||
memory = memory.Slice(1);
|
||||
|
||||
if (step == RelayUdpStep.Forward)
|
||||
{
|
||||
if (udpNat.TryGetValue(ep, out RelayUdpNatInfo natTarget) && natTarget.Target != null)
|
||||
{
|
||||
natTarget.LastTicks = Environment.TickCount64;
|
||||
await CopyToAsync(natTarget, socket,ep,memory);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RelayMessageInfo relayMessage = serializer.Deserialize<RelayMessageInfo>(memory.Span);
|
||||
|
||||
//ask 是发起端来的,那key就是 发起端->目标端, answer的,目标和来源会交换,所以转换一下
|
||||
string key = relayMessage.Type == RelayMessengerType.Ask ? $"{relayMessage.FromId}->{relayMessage.ToId}->{relayMessage.FlowId}" : $"{relayMessage.ToId}->{relayMessage.FromId}->{relayMessage.FlowId}";
|
||||
//获取缓存
|
||||
RelayCacheInfo relayCache = await relayServerNodeTransfer.TryGetRelayCache(key);
|
||||
if (relayCache == null)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
|
||||
await socket.SendToAsync(new byte[] { 1 }, ep);
|
||||
return;
|
||||
}
|
||||
|
||||
if (relayMessage.Type == RelayMessengerType.Ask && relayServerNodeTransfer.Validate(relayCache) == false)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay {relayMessage.Type} Validate false,flowid:{relayMessage.FlowId}");
|
||||
await socket.SendToAsync(new byte[] { 1 }, ep);
|
||||
return;
|
||||
}
|
||||
|
||||
//流量统计
|
||||
AddReceive(relayCache.FromId, relayCache.FromName, relayCache.ToName, relayCache.GroupId, memory.Length);
|
||||
|
||||
//回应
|
||||
if (relayMessage.Type == RelayMessengerType.Answer)
|
||||
{
|
||||
if (relayUdpDic.TryRemove(relayCache.FlowId, out RelayUdpNatInfo natAsk))
|
||||
{
|
||||
natAsk.Target = ep;
|
||||
|
||||
RelayUdpNatInfo natAnswer = new RelayUdpNatInfo { Target = natAsk.Source, Traffic = natAsk.Traffic, Source = ep };
|
||||
udpNat.AddOrUpdate(ep, natAnswer, (a, b) => natAnswer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//请求
|
||||
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
|
||||
RelayUdpNatInfo nat = new RelayUdpNatInfo { IsAsk = true, Source = ep, Traffic = trafficCacheInfo };
|
||||
udpNat.AddOrUpdate(ep, nat, (a, b) => nat);
|
||||
relayUdpDic.TryAdd(relayCache.FlowId, nat);
|
||||
|
||||
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
|
||||
relayServerNodeTransfer.IncrementConnectionNum();
|
||||
|
||||
}
|
||||
private async Task CopyToAsync(RelayUdpNatInfo nat, Socket socket, IPEndPoint ep, Memory<byte> memory)
|
||||
{
|
||||
RelayTrafficCacheInfo trafficCacheInfo = nat.Traffic;
|
||||
int bytesRead = memory.Length;
|
||||
|
||||
//流量限制
|
||||
if (relayServerNodeTransfer.AddBytes(trafficCacheInfo, bytesRead) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//总速度
|
||||
if (relayServerNodeTransfer.NeedLimit(trafficCacheInfo) && relayServerNodeTransfer.TryLimitPacket(bytesRead) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//单个速度
|
||||
if (trafficCacheInfo.Limit.NeedLimit() && trafficCacheInfo.Limit.TryLimitPacket(bytesRead) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
AddReceive(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
|
||||
AddSendt(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
|
||||
await socket.SendToAsync(memory, nat.Target).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
public async Task Resolve(Socket socket, Memory<byte> memory)
|
||||
{
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
|
||||
byte[] buffer1 = new byte[8 * 1024];
|
||||
try
|
||||
{
|
||||
int length = await socket.ReceiveAsync(buffer.AsMemory(), SocketFlags.None).ConfigureAwait(false);
|
||||
RelayMessageInfo relayMessage = serializer.Deserialize<RelayMessageInfo>(buffer.AsMemory(0, length).Span);
|
||||
int length = await socket.ReceiveAsync(buffer1.AsMemory(), SocketFlags.None).ConfigureAwait(false);
|
||||
RelayMessageInfo relayMessage = serializer.Deserialize<RelayMessageInfo>(buffer1.AsMemory(0, length).Span);
|
||||
|
||||
//ask 是发起端来的,那key就是 发起端->目标端, answer的,目标和来源会交换,所以转换一下
|
||||
string key = relayMessage.Type == RelayMessengerType.Ask ? $"{relayMessage.FromId}->{relayMessage.ToId}->{relayMessage.FlowId}" : $"{relayMessage.ToId}->{relayMessage.FromId}->{relayMessage.FlowId}";
|
||||
@@ -66,7 +155,7 @@ namespace linker.messenger.relay.server
|
||||
if (relayMessage.Type == RelayMessengerType.Ask && relayServerNodeTransfer.Validate(relayCache) == false)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay {relayMessage.Type} Validate false,flowid:{relayMessage.FlowId}");
|
||||
LoggerHelper.Instance.Error($"relay {relayMessage.Type} validate false,flowid:{relayMessage.FlowId}");
|
||||
await socket.SendAsync(new byte[] { 1 });
|
||||
socket.SafeClose();
|
||||
return;
|
||||
@@ -74,61 +163,42 @@ namespace linker.messenger.relay.server
|
||||
|
||||
//流量统计
|
||||
AddReceive(relayCache.FromId, relayCache.FromName, relayCache.ToName, relayCache.GroupId, length);
|
||||
|
||||
if (relayMessage.Type == RelayMessengerType.Answer)
|
||||
{
|
||||
if (relayDic.TryRemove(relayCache.FlowId, out TaskCompletionSource<Socket> tcsAsk))
|
||||
{
|
||||
tcsAsk.SetResult(socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
socket.SafeClose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (relayMessage.Type)
|
||||
{
|
||||
case RelayMessengerType.Ask:
|
||||
{
|
||||
//添加本地缓存
|
||||
RelayWrapInfo relayWrap = new RelayWrapInfo { Socket = socket, Tcs = new TaskCompletionSource() };
|
||||
await socket.SendAsync(new byte[] { 0 });
|
||||
|
||||
relayDic.TryAdd(relayCache.FlowId, relayWrap);
|
||||
TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
|
||||
relayDic.TryAdd(relayCache.FlowId, tcs);
|
||||
Socket answerSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000));
|
||||
|
||||
await socket.SendAsync(new byte[] { 0 });
|
||||
//等待对方连接
|
||||
await relayWrap.Tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000));
|
||||
}
|
||||
break;
|
||||
case RelayMessengerType.Answer:
|
||||
{
|
||||
//看发起端缓存
|
||||
if (relayDic.TryRemove(relayCache.FlowId, out RelayWrapInfo relayWrap) == false || relayWrap.Socket == null)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
|
||||
socket.SafeClose();
|
||||
return;
|
||||
}
|
||||
relayWrap.Tcs.SetResult();
|
||||
|
||||
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
|
||||
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
|
||||
relayServerNodeTransfer.IncrementConnectionNum();
|
||||
_ = Task.WhenAll(CopyToAsync(trafficCacheInfo, socket, relayWrap.Socket), CopyToAsync(trafficCacheInfo, relayWrap.Socket, socket)).ContinueWith((result) =>
|
||||
{
|
||||
relayServerNodeTransfer.DecrementConnectionNum();
|
||||
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"relay {relayMessage.Type} unknow type,flowid:{relayMessage.FlowId}");
|
||||
socket.SafeClose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
byte[] buffer2 = new byte[8 * 1024];
|
||||
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
|
||||
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
|
||||
relayServerNodeTransfer.IncrementConnectionNum();
|
||||
await Task.WhenAll(CopyToAsync(trafficCacheInfo, socket, answerSocket, buffer1), CopyToAsync(trafficCacheInfo, answerSocket, socket, buffer2)).ConfigureAwait(false);
|
||||
relayServerNodeTransfer.DecrementConnectionNum();
|
||||
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"{ex},flowid:{relayMessage.FlowId}");
|
||||
if (relayDic.TryRemove(relayCache.FlowId, out RelayWrapInfo remove))
|
||||
{
|
||||
remove.Socket?.SafeClose();
|
||||
}
|
||||
relayDic.TryRemove(relayCache.FlowId, out _);
|
||||
socket.SafeClose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -137,18 +207,13 @@ namespace linker.messenger.relay.server
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
socket.SafeClose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
private async Task CopyToAsync(RelayTrafficCacheInfo trafficCacheInfo, Socket source, Socket destination)
|
||||
private async Task CopyToAsync(RelayTrafficCacheInfo trafficCacheInfo, Socket source, Socket destination, Memory<byte> memory)
|
||||
{
|
||||
byte[] buffer = new byte[8 * 1024];
|
||||
try
|
||||
{
|
||||
int bytesRead;
|
||||
while ((bytesRead = await source.ReceiveAsync(buffer.AsMemory(), SocketFlags.None).ConfigureAwait(false)) != 0)
|
||||
while ((bytesRead = await source.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
//流量限制
|
||||
if (relayServerNodeTransfer.AddBytes(trafficCacheInfo, bytesRead) == false)
|
||||
@@ -182,7 +247,7 @@ namespace linker.messenger.relay.server
|
||||
|
||||
AddReceive(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
|
||||
AddSendt(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
|
||||
await destination.SendAsync(buffer.AsMemory(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
|
||||
await destination.SendAsync(memory.Slice(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -194,6 +259,47 @@ namespace linker.messenger.relay.server
|
||||
destination.SafeClose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearTask()
|
||||
{
|
||||
TimerHelper.SetIntervalLong(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
long ticks = Environment.TickCount64;
|
||||
foreach (var item in udpNat.Values.Where(c => c.IsAsk && ticks - c.LastTicks > 30000).ToList())
|
||||
{
|
||||
relayServerNodeTransfer.DecrementConnectionNum();
|
||||
relayServerNodeTransfer.RemoveTrafficCache(item.Traffic);
|
||||
|
||||
relayUdpDic.TryRemove(item.Traffic.Cache.FlowId, out _);
|
||||
if (item.Target != null)
|
||||
{
|
||||
udpNat.TryRemove(item.Target, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
return true;
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
public enum RelayUdpStep : byte
|
||||
{
|
||||
Connect = 0,
|
||||
Forward = 1,
|
||||
}
|
||||
public sealed class RelayUdpNatInfo
|
||||
{
|
||||
public bool IsAsk { get; set; }
|
||||
public IPEndPoint Source { get; set; }
|
||||
public IPEndPoint Target { get; set; }
|
||||
public long LastTicks { get; set; } = Environment.TickCount64;
|
||||
public RelayTrafficCacheInfo Traffic { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +327,7 @@ namespace linker.messenger.relay.server
|
||||
}
|
||||
public bool TryLimit(ref int length)
|
||||
{
|
||||
if (relayLimit == 0) return false;
|
||||
if (relayLimit == 0) return true;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
@@ -244,6 +350,26 @@ namespace linker.messenger.relay.server
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool TryLimitPacket(int length)
|
||||
{
|
||||
if (relayLimit == 0) return true;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
long _relayLimitTicks = Environment.TickCount64;
|
||||
long relayLimitTicksTemp = _relayLimitTicks - relayLimitTicks;
|
||||
relayLimitTicks = _relayLimitTicks;
|
||||
relayLimitBucket += relayLimitTicksTemp * relayLimitToken;
|
||||
if (relayLimitBucket > relayLimit) relayLimitBucket = relayLimit;
|
||||
|
||||
if (relayLimitBucket >= length)
|
||||
{
|
||||
relayLimitBucket -= length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class RelayCacheInfo
|
||||
@@ -279,13 +405,6 @@ namespace linker.messenger.relay.server
|
||||
public long LastBytes { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public sealed class RelayWrapInfo
|
||||
{
|
||||
public TaskCompletionSource Tcs { get; set; }
|
||||
public Socket Socket { get; set; }
|
||||
}
|
||||
|
||||
public sealed partial class RelayMessageInfo
|
||||
{
|
||||
public RelayMessengerType Type { get; set; }
|
||||
|
||||
@@ -69,9 +69,9 @@ namespace linker.messenger.store.file
|
||||
{
|
||||
text = File.ReadAllText(item.Value.Path, encoding: System.Text.Encoding.UTF8);
|
||||
}
|
||||
else if (dic != null && dic.ContainsKey(item.Value.Property.Name))
|
||||
else if (dic != null && dic.TryGetValue(item.Value.Property.Name, out string base64))
|
||||
{
|
||||
text = dic[item.Value.Property.Name];
|
||||
text = Encoding.UTF8.GetString(Convert.FromBase64String(base64));
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
|
||||
@@ -162,13 +162,14 @@ namespace linker.tun
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
CommandHelper.Windows(string.Empty, [$"net start SharedAccess"]);
|
||||
string result = CommandHelper.Windows(string.Empty, [$"linker.ics.exe {defaultInterfaceName} {Name} enable"]);
|
||||
if (result.Contains($"enable success"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
*/
|
||||
error = "NetNat and ICS not supported";
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -185,7 +186,7 @@ namespace linker.tun
|
||||
{
|
||||
CommandHelper.PowerShell($"start-service WinNat", [], out error);
|
||||
CommandHelper.PowerShell($"Remove-NetNat -Name {Name} -Confirm:$false", [], out error);
|
||||
CommandHelper.Windows(string.Empty, [$"linker.ics.exe {Name} disable"]);
|
||||
//CommandHelper.Windows(string.Empty, [$"linker.ics.exe {Name} disable"]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace linker
|
||||
Dictionary<string, string> configDic = new Dictionary<string, string>();
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (args[i] == "--config-cient")
|
||||
if (args[i] == "--config-client")
|
||||
{
|
||||
configDic.Add("Client", args[i+1]);
|
||||
i++;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
v1.7.0
|
||||
2025-03-13 09:36:12
|
||||
2025-03-14 21:19:03
|
||||
1. 优化linux下路由跟踪问题,提高启动速度
|
||||
2. 优化linux下获取本机IP问题,提升虚拟网卡稳定性
|
||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||
|
||||
Reference in New Issue
Block a user