This commit is contained in:
snltty
2025-09-24 20:19:20 +08:00
parent 5e20069672
commit 6f19af76c0
12 changed files with 65 additions and 76 deletions

View File

@@ -5,6 +5,17 @@ namespace linker.libs
{ {
public sealed class ChecksumHelper public sealed class ChecksumHelper
{ {
public static unsafe void ClearChecksum(ReadOnlyMemory<byte> packet, bool ipHeader = true, bool payload = true)
{
ClearChecksum(packet.Span, ipHeader, payload);
}
public static unsafe void ClearChecksum(ReadOnlySpan<byte> packet, bool ipHeader = true, bool payload = true)
{
fixed (byte* ptr = packet)
{
ClearChecksum(ptr, ipHeader, payload);
}
}
/// <summary> /// <summary>
/// 清空IP包的校验和 /// 清空IP包的校验和
/// </summary> /// </summary>
@@ -70,7 +81,7 @@ namespace linker.libs
{ {
byte ipHeaderLength = (byte)((*ptr & 0b1111) * 4); byte ipHeaderLength = (byte)((*ptr & 0b1111) * 4);
byte* packetPtr = ptr + ipHeaderLength; byte* packetPtr = ptr + ipHeaderLength;
ipHeader = ipHeader && *(ushort*)(ptr + 10) == 0; ipHeader = ipHeader && *(ushort*)(ptr + 10) == 0;
payload = payload && ((ProtocolType)(*(ptr + 9)) switch payload = payload && ((ProtocolType)(*(ptr + 9)) switch
{ {
@@ -79,6 +90,7 @@ namespace linker.libs
ProtocolType.Udp => *(ushort*)(packetPtr + 6) == 0, ProtocolType.Udp => *(ushort*)(packetPtr + 6) == 0,
_ => false, _ => false,
}); });
if (ipHeader || payload) if (ipHeader || payload)
Checksum(ptr, ipHeader, payload); Checksum(ptr, ipHeader, payload);
} }

View File

@@ -91,14 +91,14 @@ namespace linker.messenger.tuntap
public async Task InputPacket(LinkerTunDevicPacket packet) public async Task InputPacket(LinkerTunDevicPacket packet)
{ {
//IPV4广播组播、IPV6 多播 //IPV4广播组播、IPV6 多播
if ((packet.IPV4Broadcast /*|| packet.IPV6Multicast*/) && tuntapConfigTransfer.Info.Multicast == false && connections.IsEmpty == false) if ((packet.IPV4Broadcast || packet.IPV6Multicast) && tuntapConfigTransfer.Info.Multicast == false && connections.IsEmpty == false)
{ {
await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Buffer, packet.Offset, packet.Length))); await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Buffer, packet.Offset, packet.Length)));
return; return;
} }
//IPV4+IPV6 单播 //IPV4+IPV6 单播
uint ip = BinaryPrimitives.ReadUInt32BigEndian(packet.DistIPAddress.Span[^4..]); uint ip = BinaryPrimitives.ReadUInt32BigEndian(packet.DstIp.Span[^4..]);
if (tuntapCidrConnectionManager.TryGet(ip, out ITunnelConnection connection) && connection.Connected) if (tuntapCidrConnectionManager.TryGet(ip, out ITunnelConnection connection) && connection.Connected)
{ {
/* /*

View File

@@ -66,7 +66,7 @@ namespace linker.nat
public void ToFakeDst(ReadOnlyMemory<byte> packet) public void ToFakeDst(ReadOnlyMemory<byte> packet)
{ {
//只支持映射IPV4 //只支持映射IPV4
//if ((byte)(packet.Span[0] >> 4 & 0b1111) != 4) return; if ((byte)(packet.Span[0] >> 4 & 0b1111) != 4) return;
//映射表不为空 //映射表不为空
if (natDic.IsEmpty) return; if (natDic.IsEmpty) return;
@@ -86,7 +86,7 @@ namespace linker.nat
public void ToRealDst(ReadOnlyMemory<byte> packet) public void ToRealDst(ReadOnlyMemory<byte> packet)
{ {
//只支持映射IPV4 //只支持映射IPV4
//if ((byte)(packet.Span[0] >> 4 & 0b1111) != 4) return; if ((byte)(packet.Span[0] >> 4 & 0b1111) != 4) return;
//映射表不为空 //映射表不为空
if (masks.Length == 0 || mapDic.Count == 0) return; if (masks.Length == 0 || mapDic.Count == 0) return;
//广播包 //广播包
@@ -122,8 +122,8 @@ namespace linker.nat
{ {
//修改目标IP需要小端写入IP计算都是按大端的操作是小端的所以转换一下 //修改目标IP需要小端写入IP计算都是按大端的操作是小端的所以转换一下
*(uint*)(ptr + pos) = BinaryPrimitives.ReverseEndianness(newIP); *(uint*)(ptr + pos) = BinaryPrimitives.ReverseEndianness(newIP);
//清校验和,等待重新计算 //清校验和,由于IP头和传输层协议头都修改了所以都需要重新计算
*(ushort*)(ptr + 10) = 0; ChecksumHelper.ClearChecksum(ptr);
} }
} }

View File

@@ -84,7 +84,6 @@ namespace linker.nat
source.SafeClose(); source.SafeClose();
continue; continue;
} }
Socket dst = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Socket dst = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
dst.BeginConnect(new IPEndPoint(NetworkHelper.ToIP(cache.IP), cache.Port), ConnectCallback, new TcpState { Source = source, Target = dst }); dst.BeginConnect(new IPEndPoint(NetworkHelper.ToIP(cache.IP), cache.Port), ConnectCallback, new TcpState { Source = source, Target = dst });
} }
@@ -266,7 +265,7 @@ namespace linker.nat
fixed (byte* ptr = packet.Span) fixed (byte* ptr = packet.Span)
{ {
DstProxyPacket p = new DstProxyPacket(ptr); DstProxyPacket p = new DstProxyPacket(ptr);
if (/*p.Version != 4 ||*/ p.DstAddr == tunIp || p.DstAddrSpan.IsCast()) return true; if (p.Version != 4 || p.DstAddr == tunIp || p.DstAddrSpan.IsCast()) return true;
if (lans.Any(c => p.DstAddr >= c.Item1 && p.DstAddr <= c.Item2) == false) if (lans.Any(c => p.DstAddr >= c.Item1 && p.DstAddr <= c.Item2) == false)
{ {

View File

@@ -355,7 +355,7 @@ namespace linker.nat
fixed (byte* ptr = packet.Span) fixed (byte* ptr = packet.Span)
{ {
FakeAckPacket originPacket = new(ptr); FakeAckPacket originPacket = new(ptr);
if (/*originPacket.Version != 4 ||*/ originPacket.Protocol != ProtocolType.Tcp) if (originPacket.Version != 4 || originPacket.Protocol != ProtocolType.Tcp)
{ {
return; return;
} }
@@ -376,7 +376,7 @@ namespace linker.nat
fixed (byte* ptr = packet.Span) fixed (byte* ptr = packet.Span)
{ {
FakeAckPacket originPacket = new(ptr); FakeAckPacket originPacket = new(ptr);
if (/*originPacket.Version != 4 ||*/ originPacket.Protocol != ProtocolType.Tcp) if (originPacket.Version != 4 || originPacket.Protocol != ProtocolType.Tcp)
{ {
return; return;
} }

View File

@@ -128,7 +128,7 @@ namespace linker.nat
if (state != LinkerFirewallState.Enabled) return; if (state != LinkerFirewallState.Enabled) return;
IPV4Packet ipv4 = new IPV4Packet(packet.Span); IPV4Packet ipv4 = new IPV4Packet(packet.Span);
if (/*ipv4.Version == 4 &&*/ (ipv4.Protocol == ProtocolType.Udp || ipv4.Protocol == ProtocolType.Tcp)) if (ipv4.Version == 4 && (ipv4.Protocol == ProtocolType.Udp || ipv4.Protocol == ProtocolType.Tcp))
{ {
(uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro) key = (ipv4.SrcAddr, ipv4.SrcPort, ipv4.DstAddr, ipv4.DstPort, ipv4.Protocol); (uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro) key = (ipv4.SrcAddr, ipv4.SrcPort, ipv4.DstAddr, ipv4.DstPort, ipv4.Protocol);
if (cacheSrcMap.TryGetValue(key, out SrcCacheInfo cache) == false) if (cacheSrcMap.TryGetValue(key, out SrcCacheInfo cache) == false)
@@ -176,7 +176,7 @@ namespace linker.nat
IPV4Packet ipv4 = new IPV4Packet(packet.Span); IPV4Packet ipv4 = new IPV4Packet(packet.Span);
//IPV4 TCP 和 UDP //IPV4 TCP 和 UDP
if (/*ipv4.Version == 4 &&*/ (ipv4.Protocol == ProtocolType.Udp || ipv4.Protocol == ProtocolType.Tcp)) if (ipv4.Version == 4 && (ipv4.Protocol == ProtocolType.Udp || ipv4.Protocol == ProtocolType.Tcp))
{ {
//连接状态 //连接状态
(uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro) key = (ipv4.DstAddr, ipv4.DstPort, ipv4.SrcAddr, ipv4.SrcPort, ipv4.Protocol); (uint src, ushort srcPort, uint dst, ushort dstPort, ProtocolType pro) key = (ipv4.DstAddr, ipv4.DstPort, ipv4.SrcAddr, ipv4.SrcPort, ipv4.Protocol);

View File

@@ -196,7 +196,7 @@ namespace linker.nat
IPV4Packet ipv4 = new IPV4Packet(packet.Span); IPV4Packet ipv4 = new IPV4Packet(packet.Span);
//不是 ipv4是虚拟网卡ip是广播不nat //不是 ipv4是虚拟网卡ip是广播不nat
if (/*ipv4.Version != 4 ||*/ ipv4.DstAddr == srcIp || ipv4.DstAddrSpan.IsCast()) if (ipv4.Version != 4 || ipv4.DstAddr == srcIp || ipv4.DstAddrSpan.IsCast())
{ {
return false; return false;
} }

View File

@@ -43,8 +43,8 @@ namespace linker.tun
//6tcp 17udp //6tcp 17udp
if (ptr[9] == 6 || ptr[9] == 17) if (ptr[9] == 6 || ptr[9] == 17)
{ {
IPAddress sourceIP = new IPAddress(packet.SourceIPAddress.Span); IPAddress sourceIP = new IPAddress(packet.SrcIp.Span);
IPAddress distIP = new IPAddress(packet.DistIPAddress.Span); IPAddress distIP = new IPAddress(packet.DstIp.Span);
ushort sourcePort = *(ushort*)(ptr + 20); ushort sourcePort = *(ushort*)(ptr + 20);
ushort distPort = *(ushort*)(ptr + 22); ushort distPort = *(ushort*)(ptr + 22);

View File

@@ -2,7 +2,9 @@
using linker.libs.timer; using linker.libs.timer;
using linker.tun.device; using linker.tun.device;
using linker.tun.hook; using linker.tun.hook;
using System.Buffers.Binary;
using System.Net; using System.Net;
using System.Net.Sockets;
using static linker.nat.LinkerDstMapping; using static linker.nat.LinkerDstMapping;
namespace linker.tun namespace linker.tun
@@ -49,7 +51,10 @@ namespace linker.tun
public LinkerTunDeviceAdapter() public LinkerTunDeviceAdapter()
{ {
hooks = new ILinkerTunPacketHook[] { lanMap, lanDnat }; hooks = new ILinkerTunPacketHook[] {
lanMap,
lanDnat
};
hooks1 = hooks.OrderByDescending(c => c.Level).ToArray(); hooks1 = hooks.OrderByDescending(c => c.Level).ToArray();
} }
@@ -298,10 +303,10 @@ namespace linker.tun
} }
packet.Unpacket(buffer, 0, length); packet.Unpacket(buffer, 0, length);
if (packet.DistIPAddress.Length == 0 || packet.Version != 4) continue; if (packet.DstIp.Length == 0 || packet.Version != 4) continue;
for (int i = 0; i < hooks1.Length; i++) if (hooks1[i].Read(packet.IPPacket) == false) goto end; for (int i = 0; i < hooks1.Length; i++) if (hooks1[i].Read(packet.RawPacket) == false) goto end;
ChecksumHelper.ChecksumWithZero(packet.IPPacket); ChecksumHelper.ChecksumWithZero(packet.RawPacket);
await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false); await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false);
@@ -322,14 +327,17 @@ namespace linker.tun
/// </summary> /// </summary>
/// <param name="buffer"></param> /// <param name="buffer"></param>
/// <returns></returns> /// <returns></returns>
public bool Write(string srcId, ReadOnlyMemory<byte> buffer) public unsafe bool Write(string srcId, ReadOnlyMemory<byte> buffer)
{ {
if (linkerTunDevice == null || Status != LinkerTunDeviceStatus.Running || new LinkerTunDevicValidatePacket(buffer).IsValid == false) return false; fixed (byte* ptr = buffer.Span)
{
if (Status != LinkerTunDeviceStatus.Running || BinaryPrimitives.ReverseEndianness(*(ushort*)(ptr + 2)) != buffer.Length) return false;
for (int i = 0; i < hooks.Length; i++) if (hooks[i].Write(srcId, buffer) == false) return false; for (int i = 0; i < hooks.Length; i++) if (hooks[i].Write(srcId, buffer) == false) return false;
ChecksumHelper.ChecksumWithZero(buffer); ChecksumHelper.ChecksumWithZero(buffer);
return linkerTunDevice.Write(buffer); return linkerTunDevice.Write(buffer);
}
} }
/// <summary> /// <summary>

View File

@@ -173,7 +173,7 @@ namespace linker.tun.device
public int Offset { get; private set; } public int Offset { get; private set; }
public int Length { get; private set; } public int Length { get; private set; }
public Memory<byte> IPPacket => Buffer.AsMemory(Offset + 4, Length - 4); public Memory<byte> RawPacket => Buffer.AsMemory(Offset + 4, Length - 4);
/// <summary> /// <summary>
/// 协议版本4或者6 /// 协议版本4或者6
@@ -188,95 +188,68 @@ namespace linker.tun.device
/// <summary> /// <summary>
/// 源IP /// 源IP
/// </summary> /// </summary>
public ReadOnlyMemory<byte> SourceIPAddress { get; private set; } public ReadOnlyMemory<byte> SrcIp { get; private set; }
/// <summary> /// <summary>
/// 源端口 /// 源端口
/// </summary> /// </summary>
public ushort SourcePort { get; private set; } public ushort SrcPort { get; private set; }
/// <summary> /// <summary>
/// 目标IP /// 目标IP
/// </summary> /// </summary>
public ReadOnlyMemory<byte> DistIPAddress { get; private set; } public ReadOnlyMemory<byte> DstIp { get; private set; }
/// <summary> /// <summary>
/// 目标端口 /// 目标端口
/// </summary> /// </summary>
public ushort DistPort { get; private set; } public ushort DstPort { get; private set; }
public bool IPV4Broadcast => Version == 4 && DistIPAddress.IsCast(); public bool IPV4Broadcast => Version == 4 && DstIp.IsCast();
public bool IPV6Multicast => Version == 6 && (DistIPAddress.Span[0] & 0xFF) == 0xFF; public bool IPV6Multicast => Version == 6 && (DstIp.Span[0] & 0xFF) == 0xFF;
public LinkerTunDevicPacket() public LinkerTunDevicPacket()
{ {
} }
public void Unpacket(byte[] buffer, int offset, int length) public void Unpacket(byte[] buffer, int offset, int length, int pad = 4)
{ {
Buffer = buffer; Buffer = buffer;
Offset = offset; Offset = offset;
Length = length; Length = length;
ReadOnlyMemory<byte> ipPacket = Buffer.AsMemory(Offset + 4, Length - 4); ReadOnlyMemory<byte> ipPacket = Buffer.AsMemory(Offset + pad, Length - pad);
Version = (byte)(ipPacket.Span[0] >> 4 & 0b1111); Version = (byte)(ipPacket.Span[0] >> 4 & 0b1111);
SourceIPAddress = Helper.EmptyArray; SrcIp = Helper.EmptyArray;
DistIPAddress = Helper.EmptyArray; DstIp = Helper.EmptyArray;
if (Version == 4) if (Version == 4)
{ {
SourceIPAddress = ipPacket.Slice(12, 4); SrcIp = ipPacket.Slice(12, 4);
DistIPAddress = ipPacket.Slice(16, 4); DstIp = ipPacket.Slice(16, 4);
ProtocolType = (ProtocolType)ipPacket.Span[9]; ProtocolType = (ProtocolType)ipPacket.Span[9];
if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp) if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp)
{ {
SourcePort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(20, 2).ToUInt16()); SrcPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(20, 2).ToUInt16());
DistPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(22, 2).ToUInt16()); DstPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(22, 2).ToUInt16());
} }
} }
else if (Version == 6) else if (Version == 6)
{ {
SourceIPAddress = ipPacket.Slice(8, 16); SrcIp = ipPacket.Slice(8, 16);
DistIPAddress = ipPacket.Slice(24, 16); DstIp = ipPacket.Slice(24, 16);
ProtocolType = (ProtocolType)ipPacket.Span[6]; ProtocolType = (ProtocolType)ipPacket.Span[6];
if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp) if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp)
{ {
SourcePort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(42, 2).ToUInt16()); SrcPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(42, 2).ToUInt16());
DistPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(44, 2).ToUInt16()); DstPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(44, 2).ToUInt16());
} }
} }
} }
} }
public struct LinkerTunDevicValidatePacket
{
public bool IsValid { get; private set; }
public LinkerTunDevicValidatePacket(ReadOnlyMemory<byte> packet)
{
if (packet.Length >= 1)
{
byte version = (byte)(packet.Span[0] >> 4 & 0b1111);
int headLength = /*version == 4 ?*/ (packet.Span[0] & 0b1111) * 4 /*: 40*/;
if (packet.Length < headLength) return;
ProtocolType protocolType = version switch
{
4 => (ProtocolType)packet.Span[9],
6 => (ProtocolType)packet.Span[6],
_ => ProtocolType.Unknown
};
IsValid = protocolType switch
{
ProtocolType.Tcp => packet.Length >= headLength + 20,
ProtocolType.Udp => packet.Length >= headLength + 8,
ProtocolType.Icmp => packet.Length >= headLength + 8,
_ => false
};
}
}
}
/// <summary> /// <summary>
/// 添加路由项 /// 添加路由项

View File

@@ -1,7 +1,4 @@
 namespace linker.tun.hook
using linker.tun.device;
namespace linker.tun.hook
{ {
/// <summary> /// <summary>
/// 数据包钩子 /// 数据包钩子

View File

@@ -1,5 +1,5 @@
v1.9.2 v1.9.2
2025-09-23 16:48:18 2025-09-24 20:19:20
1. 一些累计更新一些BUG修复 1. 一些累计更新一些BUG修复
2. 使用代理方式重写应用层NAT 2. 使用代理方式重写应用层NAT
3. 新增服务端webapi对外提供公开数据监听1803端口设置为0则不监听 3. 新增服务端webapi对外提供公开数据监听1803端口设置为0则不监听