From 6f19af76c0713d6e2c294e8a98da1462176a98cb Mon Sep 17 00:00:00 2001 From: snltty <1069410172@qq.com> Date: Wed, 24 Sep 2025 20:19:20 +0800 Subject: [PATCH] 192 --- src/linker.libs/ChecksumHelper.cs | 14 ++++- src/linker.messenger.tuntap/TuntapProxy.cs | 4 +- src/linker.nat/LinkerDstMapping.cs | 8 +-- src/linker.nat/LinkerDstProxy.cs | 3 +- src/linker.nat/LinkerFakeAck.cs | 4 +- src/linker.nat/LinkerFirewall.cs | 4 +- src/linker.nat/LinkerSrcNat.cs | 2 +- src/linker.tun/Example.cs | 4 +- src/linker.tun/LinkerTunDeviceAdapter.cs | 26 ++++++--- src/linker.tun/device/ILinkerTunDevice.cs | 65 ++++++--------------- src/linker.tun/hook/ILinkerTunPacketHook.cs | 5 +- version.txt | 2 +- 12 files changed, 65 insertions(+), 76 deletions(-) diff --git a/src/linker.libs/ChecksumHelper.cs b/src/linker.libs/ChecksumHelper.cs index 6ea15414..e5b4767e 100644 --- a/src/linker.libs/ChecksumHelper.cs +++ b/src/linker.libs/ChecksumHelper.cs @@ -5,6 +5,17 @@ namespace linker.libs { public sealed class ChecksumHelper { + public static unsafe void ClearChecksum(ReadOnlyMemory packet, bool ipHeader = true, bool payload = true) + { + ClearChecksum(packet.Span, ipHeader, payload); + } + public static unsafe void ClearChecksum(ReadOnlySpan packet, bool ipHeader = true, bool payload = true) + { + fixed (byte* ptr = packet) + { + ClearChecksum(ptr, ipHeader, payload); + } + } /// /// 清空IP包的校验和 /// @@ -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); } diff --git a/src/linker.messenger.tuntap/TuntapProxy.cs b/src/linker.messenger.tuntap/TuntapProxy.cs index a7b463f6..9fd6c96f 100644 --- a/src/linker.messenger.tuntap/TuntapProxy.cs +++ b/src/linker.messenger.tuntap/TuntapProxy.cs @@ -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) { /* diff --git a/src/linker.nat/LinkerDstMapping.cs b/src/linker.nat/LinkerDstMapping.cs index 4aaa7a7a..86f9bb4d 100644 --- a/src/linker.nat/LinkerDstMapping.cs +++ b/src/linker.nat/LinkerDstMapping.cs @@ -66,7 +66,7 @@ namespace linker.nat public void ToFakeDst(ReadOnlyMemory 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 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); } } diff --git a/src/linker.nat/LinkerDstProxy.cs b/src/linker.nat/LinkerDstProxy.cs index bbd64db3..a6967669 100644 --- a/src/linker.nat/LinkerDstProxy.cs +++ b/src/linker.nat/LinkerDstProxy.cs @@ -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) { diff --git a/src/linker.nat/LinkerFakeAck.cs b/src/linker.nat/LinkerFakeAck.cs index a909f4cd..e24f5493 100644 --- a/src/linker.nat/LinkerFakeAck.cs +++ b/src/linker.nat/LinkerFakeAck.cs @@ -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; } diff --git a/src/linker.nat/LinkerFirewall.cs b/src/linker.nat/LinkerFirewall.cs index fd379942..f6511b2b 100644 --- a/src/linker.nat/LinkerFirewall.cs +++ b/src/linker.nat/LinkerFirewall.cs @@ -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); diff --git a/src/linker.nat/LinkerSrcNat.cs b/src/linker.nat/LinkerSrcNat.cs index 1628b560..987ad6e4 100644 --- a/src/linker.nat/LinkerSrcNat.cs +++ b/src/linker.nat/LinkerSrcNat.cs @@ -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; } diff --git a/src/linker.tun/Example.cs b/src/linker.tun/Example.cs index 3c6e17b9..b73a665d 100644 --- a/src/linker.tun/Example.cs +++ b/src/linker.tun/Example.cs @@ -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); diff --git a/src/linker.tun/LinkerTunDeviceAdapter.cs b/src/linker.tun/LinkerTunDeviceAdapter.cs index d2711503..76d4cd01 100644 --- a/src/linker.tun/LinkerTunDeviceAdapter.cs +++ b/src/linker.tun/LinkerTunDeviceAdapter.cs @@ -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 /// /// /// - public bool Write(string srcId, ReadOnlyMemory buffer) + public unsafe bool Write(string srcId, ReadOnlyMemory 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); + } } /// diff --git a/src/linker.tun/device/ILinkerTunDevice.cs b/src/linker.tun/device/ILinkerTunDevice.cs index 759810c6..bbfb374c 100644 --- a/src/linker.tun/device/ILinkerTunDevice.cs +++ b/src/linker.tun/device/ILinkerTunDevice.cs @@ -173,7 +173,7 @@ namespace linker.tun.device public int Offset { get; private set; } public int Length { get; private set; } - public Memory IPPacket => Buffer.AsMemory(Offset + 4, Length - 4); + public Memory RawPacket => Buffer.AsMemory(Offset + 4, Length - 4); /// /// 协议版本,4或者6 @@ -188,95 +188,68 @@ namespace linker.tun.device /// /// 源IP /// - public ReadOnlyMemory SourceIPAddress { get; private set; } + public ReadOnlyMemory SrcIp { get; private set; } /// /// 源端口 /// - public ushort SourcePort { get; private set; } + public ushort SrcPort { get; private set; } /// /// 目标IP /// - public ReadOnlyMemory DistIPAddress { get; private set; } + public ReadOnlyMemory DstIp { get; private set; } /// /// 目标端口 /// - 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 ipPacket = Buffer.AsMemory(Offset + 4, Length - 4); + ReadOnlyMemory 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 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 - }; - } - } - } /// /// 添加路由项 diff --git a/src/linker.tun/hook/ILinkerTunPacketHook.cs b/src/linker.tun/hook/ILinkerTunPacketHook.cs index f266491f..0d19506d 100644 --- a/src/linker.tun/hook/ILinkerTunPacketHook.cs +++ b/src/linker.tun/hook/ILinkerTunPacketHook.cs @@ -1,7 +1,4 @@ - -using linker.tun.device; - -namespace linker.tun.hook +namespace linker.tun.hook { /// /// 数据包钩子 diff --git a/version.txt b/version.txt index df27aeab..b435c846 100644 --- a/version.txt +++ b/version.txt @@ -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则不监听