修复TCP代理BUG

This commit is contained in:
snltty
2025-10-19 16:03:22 +08:00
parent 721a634dab
commit 531f28ae6a
24 changed files with 237 additions and 190 deletions

View File

@@ -30,7 +30,7 @@ for %%r in (win-x86,win-x64,win-arm64) do (
echo F|xcopy "src\\linker\\wintun-%%r.dll" "public\\extends\\%%r\\linker-%%r\\wintun.dll" /s /f /h /y
)
for %%r in (win-x86,win-x64,win-arm64,linux-x64,linux-arm,linux-arm64,linux-musl-x64,linux-musl-arm,linux-musl-arm64,osx-x64,osx-arm64) do (
for %%r in (win-x86,win-x64,win-arm64,linux-x64,linux-arm,linux-arm64,linux-musl-x64,linux-musl-arm,linux-musl-arm64) do (
dotnet publish ./src/linker -c release -f net8.0 -o ./public/publish/%%r/linker-%%r -r %%r -p:PublishSingleFile=true --self-contained true -p:TrimMode=partial -p:TieredPGO=true -p:DebugType=full -p:EventSourceSupport=false -p:DebugSymbols=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 -p:MetricsSupport=false -p:StackTraceSupport=false -p:XmlResolverIsNetworkingEnabledByDefault=false
echo F|xcopy "public\\extends\\%%r\\linker-%%r\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y

View File

@@ -56,7 +56,11 @@ namespace linker.libs
using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.Bind(new IPEndPoint(IPAddress.Any, 0));
return (ushort)(socket.LocalEndPoint as IPEndPoint).Port;
ushort port = (ushort)(socket.LocalEndPoint as IPEndPoint).Port;
socket.SafeClose();
return port;
}
public static IPAddress GetDomainIp(string domain)

View File

@@ -10,26 +10,32 @@
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public Task<List<string>> Get(string userid);
public Task<List<RelayWhiteListItem>> GetNodes(string userid);
/// <summary>
/// 是否存在于白名单
/// 获取白名单
/// </summary>
/// <param name="userid"></param>
/// <param name="nodeid"></param>
/// <returns></returns>
public Task<bool> Contains(string userid, string nodeid);
public Task<List<double>> GetBandwidth(string userid,string nodeid);
}
public sealed class RelayServerWhiteListStore : IRelayServerWhiteListStore
{
public async Task<bool> Contains(string userid, string nodeid)
public async Task<List<RelayWhiteListItem>> GetNodes(string userid)
{
return await Task.FromResult(false);
return await Task.FromResult(new List<RelayWhiteListItem>());
}
public async Task<List<string>> Get(string userid)
public async Task<List<double>> GetBandwidth(string userid, string nodeid)
{
return await Task.FromResult(new List<string>());
return await Task.FromResult(new List<double>());
}
}
public sealed class RelayWhiteListItem
{
public string[] Nodes { get; set; } = [];
public double Bandwidth { get; set; } = 0;
}
}

View File

@@ -1,5 +1,4 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.timer;
using linker.messenger.relay.client.transport;
using linker.messenger.relay.messenger;
@@ -54,7 +53,7 @@ namespace linker.messenger.relay.server
ToId = to.Id,
ToName = to.MachineName,
GroupId = to.GroupId,
Validated = from.Super,
Super = from.Super,
UserId = from.UserId,
};
if (relayCaching.TryAdd($"{cache.FromId}->{cache.ToId}->{flowingId}", cache, 15000) == false)
@@ -68,11 +67,20 @@ namespace linker.messenger.relay.server
{
if (relayCaching.TryGetValue(key, out RelayCacheInfo cache) && reports.TryGetValue(nodeid, out var node))
{
cache.Validated = cache.Validated || await relayServerWhiteListStore.Contains(cache.UserId, node.Id);
if (cache.Validated == false)
var bandwidth = await relayServerWhiteListStore.GetBandwidth(cache.UserId, node.Id);
if (bandwidth.Any(c => c < 0))
{
cache.Cdkey = (await relayServerCdkeyStore.GetAvailable(cache.UserId).ConfigureAwait(false)).Select(c => new RelayCdkeyInfo { Bandwidth = c.Bandwidth, Id = c.Id, LastBytes = c.LastBytes }).ToList();
if (cache.Cdkey.Count == 0 && node.Public == false) return null;
return null;
}
cache.Bandwidth = bandwidth.Count > 0
? bandwidth.Any(c => c == 0) ? 0 : bandwidth.Max()
: cache.Super ? 0 : node.MaxBandwidth;
cache.Cdkey = (await relayServerCdkeyStore.GetAvailable(cache.UserId).ConfigureAwait(false)).Select(c => new RelayCdkeyInfo { Bandwidth = c.Bandwidth, Id = c.Id, LastBytes = c.LastBytes }).ToList();
if (cache.Cdkey.Count == 0 && node.Public == false && cache.Super == false && bandwidth.Count == 0)
{
return null;
}
return cache;
}
@@ -179,7 +187,7 @@ namespace linker.messenger.relay.server
/// <returns></returns>
public async Task<List<RelayServerNodeReportInfo188>> GetNodes(bool validated, string userid)
{
var nodes = await relayServerWhiteListStore.Get(userid);
var nodes = (await relayServerWhiteListStore.GetNodes(userid)).Where(c => c.Bandwidth >= 0).SelectMany(c => c.Nodes);
var result = reports.Values
.Where(c => Environment.TickCount64 - c.LastTicks < 15000)
@@ -216,8 +224,6 @@ namespace linker.messenger.relay.server
.ToList();
}
/// <summary>
/// 消耗流量
/// </summary>

View File

@@ -72,7 +72,12 @@ namespace linker.messenger.relay.server
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK && resp.Data.Length > 0)
{
return serializer.Deserialize<RelayCacheInfo>(resp.Data.Span);
RelayCacheInfo result = serializer.Deserialize<RelayCacheInfo>(resp.Data.Span);
if (result.Bandwidth < 0)
{
result.Bandwidth = Node.MaxBandwidth;
}
return result;
}
}
catch (Exception ex)
@@ -136,12 +141,6 @@ namespace linker.messenger.relay.server
/// <returns></returns>
public bool Validate(RelayCacheInfo relayCache)
{
//已认证的没有流量限制
if (relayCache.Validated) return true;
if (Node.Public == false) return false;
//流量卡有的,就能继续用
if (relayCache.Cdkey.Any(c => c.LastBytes > 0)) return true;
return ValidateConnection(relayCache) && ValidateBytes(relayCache);
}
/// <summary>
@@ -192,8 +191,6 @@ namespace linker.messenger.relay.server
/// <returns></returns>
public bool NeedLimit(RelayTrafficCacheInfo relayCache)
{
if (relayCache.Cache.Validated) return false;
//if (relayCache.CurrentCdkey != null) return false;
return limitTotal.NeedLimit();
}
/// <summary>
@@ -242,9 +239,6 @@ namespace linker.messenger.relay.server
{
Interlocked.Add(ref bytes, length);
//验证过的,不消耗流量
if (cache.Cache.Validated) return true;
//节点无流量限制的,不消耗流量
if (Node.MaxGbTotal == 0) return true;
Interlocked.Add(ref cache.Sendt, length);
@@ -261,23 +255,24 @@ namespace linker.messenger.relay.server
/// <param name="relayCache"></param>
private void SetLimit(RelayTrafficCacheInfo relayCache)
{
relayCache.CurrentCdkey = relayCache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
//黑白名单
if (relayCache.Cache.Bandwidth >= 0)
{
relayCache.Limit.SetLimit((uint)Math.Ceiling(relayCache.Cache.Bandwidth * 1024 * 1024 / 8.0));
return;
}
//无限制
if (relayCache.Cache.Validated || Node.MaxBandwidth == 0)
if (relayCache.Cache.Super || Node.MaxBandwidth == 0)
{
relayCache.Limit.SetLimit(0);
return;
}
RelayCdkeyInfo currentCdkey = relayCache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
//有cdkey且带宽大于节点带宽就用cdkey的带宽
if (currentCdkey != null && (currentCdkey.Bandwidth == 0 || currentCdkey.Bandwidth >= Node.MaxBandwidth || Node.MaxGbTotalLastBytes == 0))
{
relayCache.CurrentCdkey = currentCdkey;
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayCache.CurrentCdkey.Bandwidth * 1024 * 1024) / 8.0));
return;
}
relayCache.CurrentCdkey = null;
relayCache.Limit.SetLimit((uint)Math.Ceiling((Node.MaxBandwidth * 1024 * 1024) / 8.0));
//配置或cdkey最大的
double banwidth = double.Max(Node.MaxBandwidth, relayCache.CurrentCdkey?.Bandwidth ?? 1);
relayCache.Limit.SetLimit((uint)Math.Ceiling(banwidth * 1024 * 1024 / 8.0));
}
/// <summary>
@@ -319,7 +314,7 @@ namespace linker.messenger.relay.server
}
private async Task UploadBytes()
{
var cdkeys = trafficDict.Values.Where(c => c.CurrentCdkey != null && c.Sendt > 0).ToList();
var cdkeys = trafficDict.Values.Where(c => c.CurrentCdkey != null && c.Sendt > 0 && c.CurrentCdkey.Id > 0).ToList();
Dictionary<int, long> id2sent = cdkeys.GroupBy(c => c.CurrentCdkey.Id).ToDictionary(c => c.Key, d => d.Sum(d => { d.SendtCache = d.Sendt; return d.SendtCache; }));
if (id2sent.Count == 0) return;

View File

@@ -54,7 +54,7 @@ namespace linker.messenger.relay.server
{
return;
}
RelayUdpStep step = (RelayUdpStep)memory.Span[0];
memory = memory.Slice(1);
@@ -69,7 +69,7 @@ namespace linker.messenger.relay.server
return;
}
using IMemoryOwner<byte> buffer = MemoryPool<byte>.Shared.Rent(16);
buffer.Memory.Span[0] = 0;
buffer.Memory.Span[1] = 1;
@@ -78,7 +78,7 @@ namespace linker.messenger.relay.server
byte flagLength = memory.Span[0];
if (memory.Length < flagLength + 1 || memory.Slice(1, flagLength).Span.SequenceEqual(relayFlag) == false)
{
await socket.SendToAsync(buffer.Memory.Slice(1,1), ep).ConfigureAwait(false);
await socket.SendToAsync(buffer.Memory.Slice(1, 1), ep).ConfigureAwait(false);
return;
}
@@ -187,7 +187,7 @@ namespace linker.messenger.relay.server
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
await socket.SendAsync(buffer.Memory.Slice(1,1)).ConfigureAwait(false);
await socket.SendAsync(buffer.Memory.Slice(1, 1)).ConfigureAwait(false);
socket.SafeClose();
return;
}
@@ -430,9 +430,11 @@ namespace linker.messenger.relay.server
public string ToId { get; set; }
public string ToName { get; set; }
public string GroupId { get; set; }
public bool Validated { get; set; }
public bool Super { get; set; }
public List<RelayCdkeyInfo> Cdkey { get; set; } = [];
public double Bandwidth { get; set; }
/// <summary>
/// 仅本地缓存可用
/// </summary>

View File

@@ -752,14 +752,17 @@ namespace linker.messenger.serializer.memorypack
string GroupId => info.GroupId;
[MemoryPackInclude]
bool Validated => info.Validated;
bool Super => info.Super;
[MemoryPackInclude, MemoryPackAllowSerialize]
List<RelayCdkeyInfo> Cdkey => info.Cdkey;
[MemoryPackInclude]
double Bandwidth => info.Bandwidth;
[MemoryPackConstructor]
SerializableRelayCacheInfo(ulong flowId, string fromId, string fromName, string toId, string toName, string groupId, bool validated, List<RelayCdkeyInfo> cdkey)
SerializableRelayCacheInfo(ulong flowId, string fromId, string fromName, string toId, string toName, string groupId, bool super, List<RelayCdkeyInfo> cdkey, double bandwidth)
{
var info = new RelayCacheInfo
{
@@ -770,7 +773,8 @@ namespace linker.messenger.serializer.memorypack
ToId = toId,
ToName = toName,
Cdkey = cdkey,
Validated = validated
Super = super,
Bandwidth = bandwidth
};
this.info = info;
}

View File

@@ -532,14 +532,17 @@ namespace linker.messenger.serializer.memorypack
string GroupId => info.GroupId;
[MemoryPackInclude]
bool Validated => info.Validated;
bool Validated => info.Super;
[MemoryPackInclude, MemoryPackAllowSerialize]
List<SForwardCdkeyInfo> Cdkey => info.Cdkey;
[MemoryPackInclude]
double Bandwidth => info.Bandwidth;
[MemoryPackConstructor]
SerializableSForwardAddInfo191(string domain, int remotePort, string nodeid, string machineid, string groupid, bool validated, List<SForwardCdkeyInfo> cdkey)
SerializableSForwardAddInfo191(string domain, int remotePort, string nodeid, string machineid, string groupid, bool validated, double bandwidth, List<SForwardCdkeyInfo> cdkey)
{
this.info = new SForwardAddInfo191
{
@@ -549,7 +552,8 @@ namespace linker.messenger.serializer.memorypack
GroupId = groupid,
MachineId = machineid,
Cdkey = cdkey,
Validated = validated
Super = validated,
Bandwidth = bandwidth
};
}

View File

@@ -105,7 +105,8 @@ namespace linker.messenger.sforward
public string MachineId { get; set; } = string.Empty;
public string GroupId { get; set; } = string.Empty;
public bool Validated { get; set; }
public bool Super { get; set; }
public double Bandwidth { get; set; }
public List<SForwardCdkeyInfo> Cdkey { get; set; } = [];
}

View File

@@ -168,7 +168,7 @@ namespace linker.plugins.sforward.messenger
result.Message = error;
return;
}
Add(sForwardAddInfo, cache.MachineId, cache.GroupId, result, false, []);
Add(sForwardAddInfo, cache.MachineId, cache.GroupId, result, sForwardAddInfo191.Super, sForwardAddInfo191.Bandwidth, []);
}
catch (Exception ex)
{
@@ -369,7 +369,7 @@ namespace linker.plugins.sforward.messenger
{
Remove((SForwardAddInfo)sForwardAddInfo, sForwardAddInfo.MachineId, result);
}
public void Add(SForwardAddInfo sForwardAddInfo, string machineId, string groupid, SForwardAddResultInfo result, bool validated, List<SForwardCdkeyInfo> cdkeys)
public void Add(SForwardAddInfo sForwardAddInfo, string machineId, string groupid, SForwardAddResultInfo result, bool super,double bandwidth, List<SForwardCdkeyInfo> cdkeys)
{
try
{
@@ -384,7 +384,7 @@ namespace linker.plugins.sforward.messenger
if (sForwardServerCahing.TryAdd(port, machineId))
{
proxy.Stop(port);
result.Message = proxy.Start(port, 3, groupid, validated, cdkeys);
result.Message = proxy.Start(port, 3, groupid, super, bandwidth, cdkeys);
if (string.IsNullOrWhiteSpace(result.Message) == false)
{
LoggerHelper.Instance.Error(result.Message);
@@ -404,7 +404,7 @@ namespace linker.plugins.sforward.messenger
else
{
proxy.AddHttp($"{sForwardAddInfo.Domain}.{sForwardServerNodeTransfer.Node.Domain}", validated, cdkeys);
proxy.AddHttp($"{sForwardAddInfo.Domain}.{sForwardServerNodeTransfer.Node.Domain}", super, bandwidth, cdkeys);
result.Message = $"domain 【{sForwardAddInfo.Domain}】 add success";
}
}
@@ -423,7 +423,7 @@ namespace linker.plugins.sforward.messenger
else
{
proxy.Stop(sForwardAddInfo.RemotePort);
string msg = proxy.Start(sForwardAddInfo.RemotePort, 3, groupid, validated, cdkeys);
string msg = proxy.Start(sForwardAddInfo.RemotePort, 3, groupid, super,bandwidth, cdkeys);
if (string.IsNullOrWhiteSpace(msg) == false)
{
result.Success = false;
@@ -447,7 +447,7 @@ namespace linker.plugins.sforward.messenger
}
public void Add(SForwardAddInfo191 sForwardAddInfo, SForwardAddResultInfo result)
{
Add((SForwardAddInfo)sForwardAddInfo, sForwardAddInfo.MachineId, sForwardAddInfo.GroupId, result, sForwardAddInfo.Validated, sForwardAddInfo.Cdkey);
Add((SForwardAddInfo)sForwardAddInfo, sForwardAddInfo.MachineId, sForwardAddInfo.GroupId, result, sForwardAddInfo.Super, sForwardAddInfo.Bandwidth, sForwardAddInfo.Cdkey);
}
private static bool PortRange(string str, out int min, out int max)
{

View File

@@ -21,11 +21,11 @@ namespace linker.plugins.sforward.proxy
{
}
public string Start(int port, byte bufferSize, string groupid, bool validated, List<SForwardCdkeyInfo> cdkeys)
public string Start(int port, byte bufferSize, string groupid, bool super,double bandwidth, List<SForwardCdkeyInfo> cdkeys)
{
try
{
SForwardTrafficCacheInfo sForwardTrafficCacheInfo = sForwardServerNodeTransfer.AddTrafficCache(validated, cdkeys);
SForwardTrafficCacheInfo sForwardTrafficCacheInfo = sForwardServerNodeTransfer.AddTrafficCache(super, bandwidth, cdkeys);
StartTcp(port, false, bufferSize, groupid, sForwardTrafficCacheInfo);
StartUdp(port, bufferSize, groupid, sForwardTrafficCacheInfo);
return string.Empty;

View File

@@ -201,9 +201,9 @@ namespace linker.plugins.sforward.proxy
}
public void AddHttp(string host, bool validated, List<SForwardCdkeyInfo> cdkeys)
public void AddHttp(string host, bool super,double bandwidth, List<SForwardCdkeyInfo> cdkeys)
{
SForwardTrafficCacheInfo sForwardTrafficCacheInfo = sForwardServerNodeTransfer.AddTrafficCache(validated, cdkeys);
SForwardTrafficCacheInfo sForwardTrafficCacheInfo = sForwardServerNodeTransfer.AddTrafficCache(super, bandwidth, cdkeys);
httpCaches.AddOrUpdate(host, sForwardTrafficCacheInfo, (a, b) => sForwardTrafficCacheInfo);
}
public void RemoveHttp(string host)

View File

@@ -10,26 +10,20 @@
/// </summary>
/// <param name="userid"></param>
/// <returns></returns>
public Task<List<string>> Get(string userid);
/// <summary>
/// 是否存在于白名单
/// </summary>
/// <param name="userid"></param>
/// <param name="nodeid"></param>
/// <returns></returns>
public Task<bool> Contains(string userid, string nodeid);
public Task<List<SForwardWhiteListItem>> GetNodes(string userid);
}
public sealed class SForwardServerWhiteListStore : ISForwardServerWhiteListStore
{
public async Task<bool> Contains(string userid, string nodeid)
public async Task<List<SForwardWhiteListItem>> GetNodes(string userid)
{
return await Task.FromResult(false);
}
public async Task<List<string>> Get(string userid)
{
return await Task.FromResult(new List<string>());
return await Task.FromResult(new List<SForwardWhiteListItem>());
}
}
public sealed class SForwardWhiteListItem
{
public string[] Nodes { get; set; } = [];
public double Bandwidth { get; set; } = 0;
}
}

View File

@@ -3,6 +3,7 @@ using linker.libs.timer;
using linker.messenger.signin;
using linker.plugins.sforward.messenger;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
namespace linker.messenger.sforward.server
@@ -109,25 +110,37 @@ namespace linker.messenger.sforward.server
};
}
List<string> sforward = await sForwardServerWhiteListStore.Get(from.UserId);
List<SForwardWhiteListItem> sforward = await sForwardServerWhiteListStore.GetNodes(from.UserId);
string target = string.IsNullOrWhiteSpace(info.Domain) ? info.RemotePort.ToString() : info.Domain;
info.Validated = from.Super || (sforward.Contains($"sfp->{target}") || sforward.Contains($"sfp->*")) && (sforward.Contains(info.NodeId) || sforward.Contains($"*"));
info.Super = from.Super;
if (info.Validated == false)
var bandwidth = sforward.Where(c => (c.Nodes.Contains($"sfp->{target}") || c.Nodes.Contains($"sfp->*")) && (c.Nodes.Contains(info.NodeId) || c.Nodes.Contains($"*"))).ToList();
if(bandwidth.Any(c=>c.Bandwidth < 0))
{
var cdkeys = await sForwardServerCdkeyStore.GetAvailable(from.UserId, $"sfp->{target}").ConfigureAwait(false);
var anyCdkeys = await sForwardServerCdkeyStore.GetAvailable(from.UserId, $"sfp->*").ConfigureAwait(false);
info.Cdkey = cdkeys.Concat(anyCdkeys).Select(c => new SForwardCdkeyInfo { Bandwidth = c.Bandwidth, Id = c.Id, LastBytes = c.LastBytes }).ToList();
if (info.Cdkey.Count <= 0 && node.Public == false)
return new SForwardAddResultInfo
{
return new SForwardAddResultInfo
{
BufferSize = 1,
Message = "need super key or white list or cdkey",
Success = false
};
}
BufferSize = 1,
Message = "white list deney",
Success = false
};
}
info.Bandwidth = bandwidth.Count > 0
? bandwidth.Any(c => c.Bandwidth == 0) ? 0 : bandwidth.Max(c => c.Bandwidth)
: info.Super ? 0 : node.MaxBandwidth;
var cdkeys = await sForwardServerCdkeyStore.GetAvailable(from.UserId, $"sfp->{target}").ConfigureAwait(false);
var anyCdkeys = await sForwardServerCdkeyStore.GetAvailable(from.UserId, $"sfp->*").ConfigureAwait(false);
info.Cdkey = cdkeys.Concat(anyCdkeys).Select(c => new SForwardCdkeyInfo { Bandwidth = c.Bandwidth, Id = c.Id, LastBytes = c.LastBytes }).ToList();
if (info.Cdkey.Count ==0 && node.Public == false && info.Super == false && bandwidth.Count == 0)
{
return new SForwardAddResultInfo
{
BufferSize = 1,
Message = "need super key or white list or cdkey",
Success = false
};
}
@@ -175,7 +188,7 @@ namespace linker.messenger.sforward.server
Success = false
};
}
/// <summary>
/// 获取节点列表
@@ -184,7 +197,7 @@ namespace linker.messenger.sforward.server
/// <returns></returns>
public async Task<List<SForwardServerNodeReportInfo>> GetNodes(bool validated, string userid)
{
List<string> sforward = await sForwardServerWhiteListStore.Get(userid);
List<string> sforward = (await sForwardServerWhiteListStore.GetNodes(userid)).Where(c=>c.Bandwidth>=0).SelectMany(c=>c.Nodes).ToList();
var result = reports.Values
.Where(c => Environment.TickCount64 - c.LastTicks < 15000)

View File

@@ -111,7 +111,6 @@ namespace linker.messenger.sforward.server
/// <returns></returns>
public bool NeedLimit(SForwardTrafficCacheInfo relayCache)
{
if (relayCache.Cache.Validated) return false;
return limitTotal.NeedLimit();
}
/// <summary>
@@ -135,13 +134,16 @@ namespace linker.messenger.sforward.server
/// <summary>
/// 开始计算流量
/// </summary>
/// <param name="validated"></param>
/// <param name="super"></param>
/// <param name="cdkeys"></param>
/// <returns></returns>
public SForwardTrafficCacheInfo AddTrafficCache(bool validated, List<SForwardCdkeyInfo> cdkeys)
public SForwardTrafficCacheInfo AddTrafficCache(bool super, double bandwidth, List<SForwardCdkeyInfo> cdkeys)
{
SForwardTrafficCacheInfo cache = new SForwardTrafficCacheInfo { Cache = new SForwardCacheInfo { Cdkey = cdkeys, FlowId = ns.Increment(), Validated = validated }, Limit = new SForwardSpeedLimit(), Sendt = 0, SendtCache = 0 };
SForwardTrafficCacheInfo cache = new SForwardTrafficCacheInfo { Cache = new SForwardCacheInfo { Cdkey = cdkeys, FlowId = ns.Increment(), Super = super, Bandwidth = bandwidth }, Limit = new SForwardSpeedLimit(), Sendt = 0, SendtCache = 0 };
if (cache.Cache.Bandwidth < 0)
{
cache.Cache.Bandwidth = Node.MaxBandwidth;
}
SetLimit(cache);
trafficDict.TryAdd(cache.Cache.FlowId, cache);
@@ -160,9 +162,6 @@ namespace linker.messenger.sforward.server
{
Interlocked.Add(ref bytes, length);
//验证过的,不消耗流量
if (cache.Cache.Validated) return true;
//节点无流量限制的,不消耗流量
if (Node.MaxGbTotal == 0) return true;
Interlocked.Add(ref cache.Sendt, length);
@@ -176,26 +175,27 @@ namespace linker.messenger.sforward.server
/// <summary>
/// 设置限速
/// </summary>
/// <param name="relayCache"></param>
private void SetLimit(SForwardTrafficCacheInfo relayCache)
/// <param name="cache"></param>
private void SetLimit(SForwardTrafficCacheInfo cache)
{
//无限制
if (relayCache.Cache.Validated || Node.MaxBandwidth == 0)
cache.CurrentCdkey = cache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
//黑白名单
if (cache.Cache.Bandwidth >= 0)
{
relayCache.Limit.SetLimit(0);
cache.Limit.SetLimit((uint)Math.Ceiling(cache.Cache.Bandwidth * 1024 * 1024 / 8.0));
return;
}
SForwardCdkeyInfo currentCdkey = relayCache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
//有cdkey且带宽大于节点带宽就用cdkey的带宽
if (currentCdkey != null && (currentCdkey.Bandwidth == 0 || currentCdkey.Bandwidth >= Node.MaxBandwidth || Node.MaxGbTotalLastBytes == 0))
//无限制
if (cache.Cache.Super || Node.MaxBandwidth == 0)
{
relayCache.CurrentCdkey = currentCdkey;
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayCache.CurrentCdkey.Bandwidth * 1024 * 1024) / 8.0));
cache.Limit.SetLimit(0);
return;
}
relayCache.CurrentCdkey = null;
relayCache.Limit.SetLimit((uint)Math.Ceiling((Node.MaxBandwidth * 1024 * 1024) / 8.0));
//配置或cdkey最大的
double banwidth = double.Max(Node.MaxBandwidth, cache.CurrentCdkey?.Bandwidth ?? 1);
cache.Limit.SetLimit((uint)Math.Ceiling(banwidth * 1024 * 1024 / 8.0));
}
@@ -460,7 +460,8 @@ namespace linker.messenger.sforward.server
public sealed partial class SForwardCacheInfo
{
public ulong FlowId { get; set; }
public bool Validated { get; set; }
public bool Super { get; set; }
public double Bandwidth { get; set; } = double.MinValue;
public List<SForwardCdkeyInfo> Cdkey { get; set; } = [];
}
public class SForwardSpeedLimit

View File

@@ -29,7 +29,7 @@ namespace linker.messenger.store.file
public ConfigInfo Data { get; private set; } = new ConfigInfo();
public FileConfig(FileConfigInitParams? initParams = null)
public FileConfig(FileConfigInitParams initParams = null)
{
if (initParams != null)
{

View File

@@ -36,10 +36,10 @@ namespace linker.messenger.store.file.wlist
return await Task.FromResult(liteCollection.Delete(id)).ConfigureAwait(false);
}
public async Task<List<string>> Get(string type, string userid)
public async Task<List<WhiteListInfo>> Get(string type, string userid)
{
if (string.IsNullOrWhiteSpace(type) || string.IsNullOrWhiteSpace(userid)) return [];
return await Task.FromResult(liteCollection.Find(c => c.Type == type && c.UserId == userid).SelectMany(c => c.Nodes).ToList()).ConfigureAwait(false);
return await Task.FromResult(liteCollection.Find(c => c.Type == type && c.UserId == userid).ToList()).ConfigureAwait(false);
}
public async Task<WhiteListPageResultInfo> Page(WhiteListPageRequestInfo info)

View File

@@ -6,7 +6,7 @@
public Task<bool> Add(WhiteListInfo info);
public Task<bool> Del(int id);
public Task<List<string>> Get(string type, string userid);
public Task<List<WhiteListInfo>> Get(string type, string userid);
}
public sealed partial class WhiteListDelInfo
{
@@ -42,5 +42,9 @@
public DateTime AddTime { get; set; } = DateTime.Now;
public string[] Nodes { get; set; } = [];
public double Bandwidth { get; set; } = 0;
}
}

View File

@@ -9,16 +9,13 @@ namespace linker.messenger.wlist
{
this.whiteListServerStore = whiteListServerStore;
}
public async Task<bool> Contains(string userid, string nodeid)
public async Task<List<RelayWhiteListItem>> GetNodes(string userid)
{
var list = await whiteListServerStore.Get("Relay", userid).ConfigureAwait(false);
return list.Contains(nodeid);
return (await whiteListServerStore.Get("Relay", userid).ConfigureAwait(false)).Select(c => new RelayWhiteListItem { Nodes = c.Nodes, Bandwidth = c.Bandwidth }).ToList();
}
public async Task<List<string>> Get(string userid)
public async Task<List<double>> GetBandwidth(string userid, string nodeid)
{
return await whiteListServerStore.Get("Relay", userid).ConfigureAwait(false);
return (await whiteListServerStore.Get("Relay", userid).ConfigureAwait(false)).Where(c => c.Nodes.Contains(nodeid)).Select(c => c.Bandwidth).ToList();
}
}
}

View File

@@ -9,16 +9,9 @@ namespace linker.messenger.wlist
{
this.whiteListServerStore = whiteListServerStore;
}
public async Task<bool> Contains(string userid, string nodeid)
public async Task<List<SForwardWhiteListItem>> GetNodes(string userid)
{
var list = await whiteListServerStore.Get("SForward", userid).ConfigureAwait(false);
return list.Contains(nodeid);
}
public async Task<List<string>> Get(string userid)
{
return await whiteListServerStore.Get("SForward", userid).ConfigureAwait(false);
return (await whiteListServerStore.Get("SForward", userid).ConfigureAwait(false)).Select(c => new SForwardWhiteListItem { Nodes = c.Nodes, Bandwidth = c.Bandwidth }).ToList();
}
}
}

View File

@@ -37,7 +37,7 @@ namespace linker.nat
listenSocketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocketTcp.Bind(new IPEndPoint(IPAddress.Any, 0));
listenSocketTcp.Listen(int.MaxValue);
proxySrc = NetworkHelper.ToNetworkValue(srcAddr, prefixLength);
tunIp = NetworkHelper.ToValue(srcAddr);
proxyPort = (ushort)(listenSocketTcp.LocalEndPoint as IPEndPoint).Port;
@@ -118,7 +118,6 @@ namespace linker.nat
state.ReadPacket.PayloadChecksum = 1;
connections.TryAdd(key, state);
state.ReadPacket.Flags = LinkerSrcProxyFlags.Syn;
state.ReadPacket.TotalLength = 40;
state.ReadPacket.Length = 44;
@@ -127,7 +126,7 @@ namespace linker.nat
await state.Tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000)).ConfigureAwait(false);
state.ReadPacket.Flags = LinkerSrcProxyFlags.Psh;
await Task.WhenAll(Sender(state), Rcver(state, buffer)).ConfigureAwait(false);
await Task.WhenAny(Rcver(state, buffer),Sender(state)).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -238,7 +237,7 @@ namespace linker.nat
await callback.Callback(state.ReadPacket).ConfigureAwait(false);
state.ReadPacket.Flags = LinkerSrcProxyFlags.Psh;
await Task.WhenAll(Sender(state), Rcver(state, buffer)).ConfigureAwait(false);
await Task.WhenAny(Rcver(state, buffer),Sender(state)).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -272,13 +271,9 @@ namespace linker.nat
try
{
state.Sending = window > 0;
ReadOnlyMemory<byte> memory = packet.Slice(40);
if (memory.Length > 0)
{
await state.Pipe.Writer.WriteAsync(memory).ConfigureAwait(false);
state.AddReceived(memory.Length);
}
await state.Pipe.Writer.WriteAsync(memory).ConfigureAwait(false);
state.AddReceived(memory.Length);
if (state.NeedPause) await SendWindow(state, 0).ConfigureAwait(false);
}
@@ -296,7 +291,6 @@ namespace linker.nat
LoggerHelper.Instance.Error(ex);
}
}
}
private async Task SendWindow(ConnectionState state, ushort window)
@@ -334,7 +328,7 @@ namespace linker.nat
ReadOnlySequence<byte> buffer = result.Buffer;
foreach (ReadOnlyMemory<byte> memoryBlock in result.Buffer)
{
await state.Socket.SendAsync(memoryBlock, SocketFlags.None).ConfigureAwait(false);
int length = await state.Socket.SendAsync(memoryBlock, SocketFlags.None).ConfigureAwait(false);
state.AddReceived(-memoryBlock.Length);
if (state.NeedResume) await SendWindow(state, 1).ConfigureAwait(false);
}
@@ -350,7 +344,7 @@ namespace linker.nat
state.ReadPacket.TotalLength = bytesRead + 40;
state.ReadPacket.Length = bytesRead + 44;
await callback.Callback(state.ReadPacket).ConfigureAwait(false);
if (state.Sending == false)
{
while (state.Sending == false && state.Socket != null)
@@ -369,7 +363,6 @@ namespace linker.nat
}
}
public unsafe bool Read(ReadOnlyMemory<byte> packet, ref bool send, ref bool writeBack)
{
if (Running == false) return true;
@@ -407,6 +400,7 @@ namespace linker.nat
{
if (srcProxyPacket.TcpOnlySyn == false) return true; //往下走
if (callback.Callback(srcProxyPacket.DstAddr) == false) return true;//不支持代理
//1、10.18.18.2:11111->10.18.18.3:5201 [SYN] 新连接
cache = new SrcCacheInfo
{
@@ -421,7 +415,6 @@ namespace linker.nat
}
if (srcProxyPacket.TcpFinOrRst) cache.Fin = true;
cache.LastTime = Environment.TickCount64;
//2、10.18.18.2:11111->10.18.18.3:5201 改为 10.18.18.0:22222->10.18.18.2:33333 包括[SYN/PSH+ACK/ACK/FIN/RST]的任意包
srcProxyPacket.DstAddr = srcProxyPacket.SrcAddr;
srcProxyPacket.DstPort = proxyPort;
@@ -440,9 +433,9 @@ namespace linker.nat
{
TimerHelper.SetIntervalLong(() =>
{
foreach (var item in srcMap.Where(c => c.Value.Fin && Environment.TickCount64 - c.Value.LastTime > 60 * 1000).Select(c => c.Key).ToList())
foreach (var item in srcMap.Where(c => c.Value.Fin && Environment.TickCount64 - c.Value.LastTime > 60 * 1000).ToList())
{
srcMap.TryRemove(item, out _);
srcMap.TryRemove(item.Key, out _);
}
}, 30000);
}
@@ -486,7 +479,6 @@ namespace linker.nat
public bool NeedPause => Received > 512 * 1024 && Receiving;
public bool NeedResume => Received < 128 * 1024 && Receiving == false;
public void Disponse()
{
Pipe?.Writer.Complete();
@@ -509,13 +501,13 @@ namespace linker.nat
public readonly uint DstAddr => BinaryPrimitives.ReverseEndianness(*(uint*)(ptr + 16));
public readonly ushort DstPort => BinaryPrimitives.ReverseEndianness(*(ushort*)(PayloadPtr + 2));
public readonly uint Seq => BinaryPrimitives.ReverseEndianness(*(uint*)(ptr + IPHeadLength + 4));
public readonly uint Cq => BinaryPrimitives.ReverseEndianness(*(uint*)(ptr + IPHeadLength + 8));
public readonly uint Seq => BinaryPrimitives.ReverseEndianness(*(uint*)(PayloadPtr + 4));
public readonly uint Cq => BinaryPrimitives.ReverseEndianness(*(uint*)(PayloadPtr + 8));
public byte DataOffset => (byte)((*(PayloadPtr + 12) >> 4) & 0b1111);
public int HeadLength => DataOffset * 4;
public readonly LinkerSrcProxyFlags Flag => (LinkerSrcProxyFlags)(*(ptr + IPHeadLength + 13));
public readonly LinkerSrcProxyFlags Flag => (LinkerSrcProxyFlags)(*(PayloadPtr + 13));
public ushort WindowSize => BinaryPrimitives.ReverseEndianness(*(ushort*)(PayloadPtr + 14));
@@ -553,17 +545,6 @@ namespace linker.nat
*(uint*)(ptr + 12) = BinaryPrimitives.ReverseEndianness(value);
}
}
public readonly ushort SrcPort
{
get
{
return BinaryPrimitives.ReverseEndianness(*(ushort*)(PayloadPtr));
}
set
{
*(ushort*)(PayloadPtr) = BinaryPrimitives.ReverseEndianness(value);
}
}
public readonly uint DstAddr
{
get
@@ -575,6 +556,41 @@ namespace linker.nat
*(uint*)(ptr + 16) = BinaryPrimitives.ReverseEndianness(value);
}
}
public readonly ushort SrcPort
{
get
{
return BinaryPrimitives.ReverseEndianness(*(ushort*)(PayloadPtr));
}
set
{
*(ushort*)(PayloadPtr) = BinaryPrimitives.ReverseEndianness(value);
}
}
public readonly ushort DstPort
{
get
{
return BinaryPrimitives.ReverseEndianness(*(ushort*)(PayloadPtr + 2));
}
set
{
*(ushort*)(PayloadPtr + 2) = BinaryPrimitives.ReverseEndianness(value);
}
}
public byte DataOffset
{
get
{
return (byte)((*(PayloadPtr + 12) >> 4) & 0b1111);
}
set
{
*(PayloadPtr + 12) = (byte)((*(PayloadPtr + 12) & 0b00001111) | ((value & 0b1111) << 4));
}
}
const byte fin = 1;
const byte syn = 2;
@@ -582,7 +598,17 @@ namespace linker.nat
const byte psh = 8;
const byte ack = 16;
const byte urg = 32;
public readonly byte TcpFlag => *(ptr + IPHeadLength + 13);
public readonly byte TcpFlag
{
get
{
return *(PayloadPtr + 13);
}
set
{
*(PayloadPtr + 13) = value;
}
}
public readonly bool TcpFlagFin => (TcpFlag & fin) != 0;
public readonly bool TcpFlagSyn => (TcpFlag & syn) != 0;
public readonly bool TcpFlagRst => (TcpFlag & rst) != 0;
@@ -596,17 +622,7 @@ namespace linker.nat
public readonly bool TcpSynAck => TcpFlag == (syn | ack);
public readonly bool TcpFinOrRst => (TcpFlag & (fin | rst)) != 0;
public readonly ushort DstPort
{
get
{
return BinaryPrimitives.ReverseEndianness(*(ushort*)(PayloadPtr + 2));
}
set
{
*(ushort*)(PayloadPtr + 2) = BinaryPrimitives.ReverseEndianness(value);
}
}
public readonly ushort IPChecksum
{
get
@@ -726,7 +742,7 @@ namespace linker.nat
}
set
{
*(ptr + 6) = (byte)((*ptr & 0b00011111) | ((value & 0b111) << 5));
*(ptr + 6) = (byte)((*(ptr + 6) & 0b00011111) | ((value & 0b111) << 5));
}
}
public ushort FragmentOffset
@@ -853,7 +869,7 @@ namespace linker.nat
}
set
{
*(PayloadPtr + 12) = (byte)((*ptr & 0b00001111) | ((value & 0b1111) << 4));
*(PayloadPtr + 12) = (byte)((*(PayloadPtr + 12) & 0b00001111) | ((value & 0b1111) << 4));
}
}
public int HeadLength
@@ -875,7 +891,7 @@ namespace linker.nat
}
set
{
*(PayloadPtr + 12) = (byte)((*ptr & 0b11110001) | ((value & 0b111) << 1));
*(PayloadPtr + 12) = (byte)((*(PayloadPtr + 12) & 0b11110001) | ((value & 0b111) << 1));
}
}
public LinkerSrcProxyFlags Flags

View File

@@ -313,7 +313,10 @@ namespace linker.tun
}
packet.Unpacket(buffer, 0, length);
if (packet.DstIp.Length == 0 || packet.Version != 4) continue;
if (packet.DstIp.Length == 0 || packet.Version != 4)
{
continue;
}
bool send = true, writeBack = false;
for (int i = 0; i < readHooks.Length; i++)
@@ -323,9 +326,13 @@ namespace linker.tun
ChecksumHelper.ChecksumWithZero(packet.RawPacket);
if (writeBack)
{
linkerTunDevice.Write(packet.RawPacket);
}
if (send)
{
await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false);
}
}
catch (Exception ex)
@@ -352,8 +359,8 @@ namespace linker.tun
for (int i = 0; i < writeHooks.Length; i++)
{
(bool next, bool _write) = await writeHooks[i].WriteAsync(buffer, dstIp, srcId).ConfigureAwait(false);
if (next == false) break;
write &= _write;
if (next == false) break;
}
ChecksumHelper.ChecksumWithZero(buffer);

View File

@@ -39,8 +39,8 @@ namespace linker.tun.hook
}
public async ValueTask<(bool next, bool write)> WriteAsync(ReadOnlyMemory<byte> packet, uint originDstIp, string srcId)
{
bool write = await LinkerSrcProxy.WriteAsync(packet,originDstIp).ConfigureAwait(false);
return await ValueTask.FromResult((write, write));
bool write = await LinkerSrcProxy.WriteAsync(packet, originDstIp).ConfigureAwait(false);
return (write, write);
}
}
}

View File

@@ -1,5 +1,5 @@
v1.9.3
2025-10-12 17:17:51
2025-10-19 16:03:22
1. 一些累计更新一些BUG修复
2. 虚拟网卡TCP转代理为TCP隧道提速
3. 重写代理模块