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 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>
/// 清空IP包的校验和
/// </summary>
@@ -70,7 +81,7 @@ namespace linker.libs
{
byte ipHeaderLength = (byte)((*ptr & 0b1111) * 4);
byte* packetPtr = ptr + ipHeaderLength;
ipHeader = ipHeader && *(ushort*)(ptr + 10) == 0;
payload = payload && ((ProtocolType)(*(ptr + 9)) switch
{
@@ -79,6 +90,7 @@ namespace linker.libs
ProtocolType.Udp => *(ushort*)(packetPtr + 6) == 0,
_ => false,
});
if (ipHeader || payload)
Checksum(ptr, ipHeader, payload);
}

View File

@@ -91,14 +91,14 @@ namespace linker.messenger.tuntap
public async Task InputPacket(LinkerTunDevicPacket packet)
{
//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)));
return;
}
//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)
{
/*

View File

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

View File

@@ -84,7 +84,6 @@ namespace linker.nat
source.SafeClose();
continue;
}
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 });
}
@@ -266,7 +265,7 @@ namespace linker.nat
fixed (byte* ptr = packet.Span)
{
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)
{

View File

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

View File

@@ -128,7 +128,7 @@ namespace linker.nat
if (state != LinkerFirewallState.Enabled) return;
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);
if (cacheSrcMap.TryGetValue(key, out SrcCacheInfo cache) == false)
@@ -176,7 +176,7 @@ namespace linker.nat
IPV4Packet ipv4 = new IPV4Packet(packet.Span);
//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);

View File

@@ -196,7 +196,7 @@ namespace linker.nat
IPV4Packet ipv4 = new IPV4Packet(packet.Span);
//不是 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;
}

View File

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

View File

@@ -2,7 +2,9 @@
using linker.libs.timer;
using linker.tun.device;
using linker.tun.hook;
using System.Buffers.Binary;
using System.Net;
using System.Net.Sockets;
using static linker.nat.LinkerDstMapping;
namespace linker.tun
@@ -49,7 +51,10 @@ namespace linker.tun
public LinkerTunDeviceAdapter()
{
hooks = new ILinkerTunPacketHook[] { lanMap, lanDnat };
hooks = new ILinkerTunPacketHook[] {
lanMap,
lanDnat
};
hooks1 = hooks.OrderByDescending(c => c.Level).ToArray();
}
@@ -298,10 +303,10 @@ namespace linker.tun
}
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;
ChecksumHelper.ChecksumWithZero(packet.IPPacket);
for (int i = 0; i < hooks1.Length; i++) if (hooks1[i].Read(packet.RawPacket) == false) goto end;
ChecksumHelper.ChecksumWithZero(packet.RawPacket);
await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false);
@@ -322,14 +327,17 @@ namespace linker.tun
/// </summary>
/// <param name="buffer"></param>
/// <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;
ChecksumHelper.ChecksumWithZero(buffer);
for (int i = 0; i < hooks.Length; i++) if (hooks[i].Write(srcId, buffer) == false) return false;
ChecksumHelper.ChecksumWithZero(buffer);
return linkerTunDevice.Write(buffer);
return linkerTunDevice.Write(buffer);
}
}
/// <summary>

View File

@@ -173,7 +173,7 @@ namespace linker.tun.device
public int Offset { 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>
/// 协议版本4或者6
@@ -188,95 +188,68 @@ namespace linker.tun.device
/// <summary>
/// 源IP
/// </summary>
public ReadOnlyMemory<byte> SourceIPAddress { get; private set; }
public ReadOnlyMemory<byte> SrcIp { get; private set; }
/// <summary>
/// 源端口
/// </summary>
public ushort SourcePort { get; private set; }
public ushort SrcPort { get; private set; }
/// <summary>
/// 目标IP
/// </summary>
public ReadOnlyMemory<byte> DistIPAddress { get; private set; }
public ReadOnlyMemory<byte> DstIp { get; private set; }
/// <summary>
/// 目标端口
/// </summary>
public ushort DistPort { get; private set; }
public ushort DstPort { get; private set; }
public bool IPV4Broadcast => Version == 4 && DistIPAddress.IsCast();
public bool IPV6Multicast => Version == 6 && (DistIPAddress.Span[0] & 0xFF) == 0xFF;
public bool IPV4Broadcast => Version == 4 && DstIp.IsCast();
public bool IPV6Multicast => Version == 6 && (DstIp.Span[0] & 0xFF) == 0xFF;
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;
Offset = offset;
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);
SourceIPAddress = Helper.EmptyArray;
DistIPAddress = Helper.EmptyArray;
SrcIp = Helper.EmptyArray;
DstIp = Helper.EmptyArray;
if (Version == 4)
{
SourceIPAddress = ipPacket.Slice(12, 4);
DistIPAddress = ipPacket.Slice(16, 4);
SrcIp = ipPacket.Slice(12, 4);
DstIp = ipPacket.Slice(16, 4);
ProtocolType = (ProtocolType)ipPacket.Span[9];
if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp)
{
SourcePort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(20, 2).ToUInt16());
DistPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(22, 2).ToUInt16());
SrcPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(20, 2).ToUInt16());
DstPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(22, 2).ToUInt16());
}
}
else if (Version == 6)
{
SourceIPAddress = ipPacket.Slice(8, 16);
DistIPAddress = ipPacket.Slice(24, 16);
SrcIp = ipPacket.Slice(8, 16);
DstIp = ipPacket.Slice(24, 16);
ProtocolType = (ProtocolType)ipPacket.Span[6];
if (ProtocolType == ProtocolType.Tcp || ProtocolType == ProtocolType.Udp)
{
SourcePort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(42, 2).ToUInt16());
DistPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(44, 2).ToUInt16());
SrcPort = BinaryPrimitives.ReverseEndianness(ipPacket.Slice(42, 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>
/// 添加路由项

View File

@@ -1,7 +1,4 @@

using linker.tun.device;
namespace linker.tun.hook
namespace linker.tun.hook
{
/// <summary>
/// 数据包钩子

View File

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