基于代理的NAT和webapi

This commit is contained in:
snltty
2025-09-21 19:19:29 +08:00
parent a8e5ff1f6f
commit bafb41cfdd
2 changed files with 49 additions and 8 deletions

View File

@@ -1,7 +1,6 @@
using linker.libs; using linker.libs;
using linker.libs.extends; using linker.libs.extends;
using linker.libs.timer; using linker.libs.timer;
using System;
using System.Buffers; using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@@ -27,6 +26,7 @@ namespace linker.nat
private ValueTuple<uint, uint>[] lans = []; private ValueTuple<uint, uint>[] lans = [];
private readonly ConcurrentDictionary<(uint srcIp, ushort srcPort), DstCacheInfo> dic = new(); private readonly ConcurrentDictionary<(uint srcIp, ushort srcPort), DstCacheInfo> dic = new();
private readonly ConcurrentDictionary<(uint srcIp, ushort srcPort, uint dstIp, ushort dstPort), UdpState> udpMap = new(); private readonly ConcurrentDictionary<(uint srcIp, ushort srcPort, uint dstIp, ushort dstPort), UdpState> udpMap = new();
private readonly ConcurrentDictionary<uint, IcmpState> icmpMap = new();
public LinkerDstProxy() public LinkerDstProxy()
{ {
Clear(); Clear();
@@ -120,7 +120,7 @@ namespace linker.nat
state.Target.SafeClose(); state.Target.SafeClose();
} }
} }
private async Task CopyToAsync(Memory<byte> buffer, Socket source, Socket target) private static async Task CopyToAsync(Memory<byte> buffer, Socket source, Socket target)
{ {
try try
{ {
@@ -281,12 +281,18 @@ namespace linker.nat
(uint srcIp, ushort srcPort) key = (p.SrcAddr, p.SrcPort); (uint srcIp, ushort srcPort) key = (p.SrcAddr, p.SrcPort);
if (dic.TryGetValue(key, out DstCacheInfo cache) == false || cache.IP != p.DstAddr || cache.Port != p.DstPort) if (dic.TryGetValue(key, out DstCacheInfo cache) == false || cache.IP != p.DstAddr || cache.Port != p.DstPort)
{ {
if (p.IsOnlySyn == false) return true; //仅SYN包建立映射
if (p.IsOnlySyn == false)
{
return true;
}
cache = new DstCacheInfo { IP = p.DstAddr, Port = p.DstPort }; cache = new DstCacheInfo { IP = p.DstAddr, Port = p.DstPort };
dic.AddOrUpdate(key, cache, (a, b) => cache); dic.AddOrUpdate(key, cache, (a, b) => cache);
} }
//更新最后使用时间
cache.LastTime = Environment.TickCount64; cache.LastTime = Environment.TickCount64;
//FIN或RST包标记为结束
if (p.TcpFlagFin || p.TcpFlagRst) if (p.TcpFlagFin || p.TcpFlagRst)
{ {
cache.Fin = true; cache.Fin = true;
@@ -324,9 +330,20 @@ namespace linker.nat
{ {
if (p.IcmpType == 8) if (p.IcmpType == 8)
{ {
using Ping ping = new Ping(); if (icmpMap.TryGetValue(p.DstAddr, out IcmpState state) == false)
PingReply reply = ping.Send(NetworkHelper.ToIP(p.DstAddr), 1000); {
if (reply.Status != IPStatus.Success) state = new IcmpState();
icmpMap.AddOrUpdate(p.DstAddr, state, (a, b) => state);
Ping(NetworkHelper.ToIP(p.DstAddr), state);
}
if (state.Times > 5 || Environment.TickCount64 - state.LastTime > 15 * 1000)
{
_ = PingAsync(NetworkHelper.ToIP(p.DstAddr), state);
}
state.Times++;
state.LastTime = Environment.TickCount64;
if (state.Status != IPStatus.Success)
{ {
return false; return false;
} }
@@ -340,6 +357,20 @@ namespace linker.nat
} }
return true; return true;
} }
private static void Ping(IPAddress ip, IcmpState state)
{
state.Times = 0;
using Ping ping = new Ping();
PingReply reply = ping.Send(ip, 1000);
state.Status = reply.Status;
}
private static async Task PingAsync(IPAddress ip, IcmpState state)
{
state.Times = 0;
using Ping ping = new Ping();
PingReply reply = await ping.SendPingAsync(ip, 1000);
state.Status = reply.Status;
}
private void Clear() private void Clear()
{ {
@@ -349,6 +380,10 @@ namespace linker.nat
{ {
dic.TryRemove(item, out _); dic.TryRemove(item, out _);
} }
foreach (var item in icmpMap.Where(c => Environment.TickCount64 - c.Value.LastTime > 30 * 1000).Select(c => c.Key).ToList())
{
icmpMap.TryRemove(item, out _);
}
}, 30000); }, 30000);
} }
@@ -357,7 +392,6 @@ namespace linker.nat
public long LastTime { get; set; } = Environment.TickCount64; public long LastTime { get; set; } = Environment.TickCount64;
public uint IP { get; set; } public uint IP { get; set; }
public ushort Port { get; set; } public ushort Port { get; set; }
public bool Fin { get; set; } public bool Fin { get; set; }
} }
@@ -373,6 +407,13 @@ namespace linker.nat
public Socket Target { get; set; } public Socket Target { get; set; }
public IPEndPoint TargetEP { get; set; } public IPEndPoint TargetEP { get; set; }
} }
sealed class IcmpState
{
public long LastTime { get; set; } = Environment.TickCount64;
public IPStatus Status { get; set; } = IPStatus.Unknown;
public int Times { get; set; }
}
readonly unsafe struct DstProxyPacket readonly unsafe struct DstProxyPacket
{ {
private readonly byte* ptr; private readonly byte* ptr;

View File

@@ -1,5 +1,5 @@
v1.9.1 v1.9.1
2025-09-21 18:35:14 2025-09-21 19:19:29
1. 一些累计更新 1. 一些累计更新
2. 服务器转发多节点 2. 服务器转发多节点
3. 虚拟网卡下伪造ACK为TCP-in-TCP隧道提速 3. 虚拟网卡下伪造ACK为TCP-in-TCP隧道提速