├── .gitignore ├── README.md └── RemoteNetwork ├── RemoteNetwork.ClientHosted ├── Dockerfile ├── Program.cs ├── RemoteNetwork.ClientHosted.csproj ├── appsettings.json ├── 安装说明.txt └── 打包命令 ├── RemoteNetwork.ListenerHosted ├── Dockerfile ├── HostedServices │ ├── ListenerHostedService.cs │ └── P2PListenerHostedService.cs ├── Program.cs └── RemoteNetwork.ListenerHosted.csproj ├── RemoteNetwork.sln └── RemoteNetwork ├── Config └── TunDriveConfig.cs ├── HostedServices ├── LinuxTunDriveHostedService.cs ├── P2PUDPSocketHostedService.cs ├── TunDriveHostedService.cs ├── TunNetWorkFrameHostedService.cs └── WinTunDriveHostedService.cs ├── P2PUDPSocket.cs ├── RemoteNetwork.csproj ├── TunDriveExtensions.cs ├── amd64.zip └── i386.zip /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | launchSettings.json 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | *.conifg/ 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | [Pp]ublishProfiles/ 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RemoteNetwork 是一个简单的远程组网样例代码,使用tun 网卡作为基础,p2p暂时只做了udp的打洞,后续会加上tcp的打洞实现 2 | 暂时没有做权限、数据加密等,需要做的也可以自行实现, 3 | IP包目前只处理了 IPV4,而且没提过完整的解析,后续实现NAT网络时 一并加上 4 | 网络测速 5 | ![image](https://github.com/hn-lyf/RemoteNetwork/assets/40068201/482dde85-dd43-48ab-ba53-b23e995a4c6e) 6 | 7 | 8 | ![未命名文件(10)](https://github.com/hn-lyf/RemoteNetwork/assets/40068201/91d6b881-12a3-423e-a0b7-79ecb3a54ecd) 9 | 10 | 11 | ![image](https://github.com/hn-lyf/RemoteNetwork/assets/40068201/6a4dcdb5-48ba-47c0-9c33-7a5b845e0951) 12 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ClientHosted/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ 3 | && echo 'Asia/Shanghai' >/etc/timezone 4 | RUN apt-get update && apt install -y --no-install-recommends ca-certificates iproute2 5 | WORKDIR /app 6 | COPY //publish . 7 | ENV enableDistribution=false 8 | LABEL appName="远程网络" 9 | LABEL update="1" 10 | ENTRYPOINT ["dotnet","RemoteNetwork.ClientHosted.dll"] -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ClientHosted/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using RemoteNetwork.Config; 4 | using RemoteNetwork.HostedServices; 5 | 6 | namespace RemoteNetwork.ClientHosted 7 | { 8 | internal class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | int workerThreads = 0; 13 | int completionPortThreads = 0; 14 | ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); 15 | ThreadPool.SetMaxThreads(Math.Max(workerThreads, 5000), Math.Max(workerThreads, 5000)); 16 | ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); 17 | var builder = new HostApplicationBuilder(args); 18 | builder.Services.AddMemoryCache(); 19 | builder.Services.Configure(builder.Configuration.GetSection("TunDrive")); 20 | builder.Services.AddTunDriveHostedService(); 21 | var app = builder.Build(); 22 | app.Run(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ClientHosted/RemoteNetwork.ClientHosted.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ClientHosted/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "TunDrive": { 10 | "TunDriveName": "qcxt", 11 | "TunDriveIP": "6.6.6.6" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ClientHosted/安装说明.txt: -------------------------------------------------------------------------------- 1 | docker run -d --name=remotenetwork -e TunDrive:TunDriveIP=6.6.6.11 --device=/dev/net/tun --net=host --restart=always --cap-add=NET_ADMIN --cap-add=SYS_ADMIN harbor.qcxt.com:65110/iothub/remotenetwork:latest -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ClientHosted/打包命令: -------------------------------------------------------------------------------- 1 | docker build -t remotenetwork:latest . -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ListenerHosted/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ 3 | && echo 'Asia/Shanghai' >/etc/timezone 4 | WORKDIR /app 5 | COPY //publish . 6 | ENV enableDistribution=false 7 | LABEL appName="远程组网服务器" 8 | LABEL update="1" 9 | LABEL appconfig="/app/appsettings.json" 10 | ENTRYPOINT ["dotnet","RemoteNetwork.ListenerHosted.dll"] -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ListenerHosted/HostedServices/ListenerHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.Sockets; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace RemoteNetwork.ListenerHosted.HostedServices 13 | { 14 | public class ListenerHostedService : BackgroundService 15 | { 16 | private readonly ILogger _logger; 17 | private readonly UdpClient udpClient; 18 | private readonly ConcurrentDictionary remoteEndPoints = new ConcurrentDictionary(); 19 | public ListenerHostedService(ILogger logger) 20 | { 21 | _logger = logger; 22 | udpClient = new UdpClient(61000); 23 | if (Environment.OSVersion.Platform == PlatformID.Win32NT) 24 | { 25 | const int SIP_UDP_CONNRESET = -1744830452; 26 | udpClient.Client.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null); 27 | } 28 | } 29 | private bool IsRun = false; 30 | 31 | public ILogger Logger => _logger; 32 | 33 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 34 | { 35 | IsRun = true; 36 | Logger.LogInformation($"远程组网服务端中转服务已开启,端口{61000}"); 37 | 38 | udpClient.BeginReceive(ReceiveCallback, udpClient); 39 | await Task.Delay(-1, stoppingToken).ConfigureAwait(false); 40 | IsRun = false; 41 | } 42 | protected virtual void ReceiveCallback(IAsyncResult ar) 43 | { 44 | System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(0, 0); 45 | byte[] bytes = null; 46 | try 47 | { 48 | 49 | bytes = udpClient.EndReceive(ar, ref remoteEndPoint); 50 | 51 | } 52 | finally 53 | { 54 | if (IsRun) 55 | { 56 | udpClient.BeginReceive(ReceiveCallback, udpClient); 57 | } 58 | } 59 | var sourceId = BitConverter.ToInt32(bytes, 0); 60 | remoteEndPoints.AddOrUpdate(sourceId, remoteEndPoint, (k, o) => { 61 | 62 | Logger.LogWarning($"{string.Join('.', bytes.Take(4))} 从原来的{o} 变化为{remoteEndPoint}"); 63 | return remoteEndPoint; 64 | }); 65 | if (bytes.Length == 4) 66 | { 67 | udpClient.Send(bytes, remoteEndPoint); 68 | return; 69 | } 70 | var destId = BitConverter.ToInt32(bytes, 4); 71 | if (bytes.Length == 8) 72 | { 73 | Logger.LogInformation($"{string.Join('.', bytes.Take(4))} 准备向 {string.Join('.', bytes.Skip(4).Take(4))} 打洞 {remoteEndPoint}"); 74 | return; 75 | } 76 | if (remoteEndPoints.TryGetValue(destId, out var remotePoint)) 77 | { 78 | udpClient.Send(bytes.Skip(8).ToArray(), remotePoint);//发送到客户 79 | } 80 | else 81 | { 82 | Logger.LogWarning($"【{remoteEndPoint}】{string.Join('.', bytes.Take(4))} 准备向 {string.Join('.', bytes.Skip(4).Take(4))} 发送的数据无客户端,抛弃"); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ListenerHosted/HostedServices/P2PListenerHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Net.Sockets; 8 | using System.Net; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Security.Cryptography; 12 | 13 | namespace RemoteNetwork.ListenerHosted.HostedServices 14 | { 15 | public class P2PListenerHostedService : BackgroundService 16 | { 17 | private readonly ILogger _logger; 18 | private readonly UdpClient udpClient; 19 | private readonly ConcurrentDictionary p2pUdpEndPoints = new ConcurrentDictionary(); 20 | private readonly TcpListener tcpListener; 21 | public P2PListenerHostedService(ILogger logger) 22 | { 23 | _logger = logger; 24 | udpClient = new UdpClient(61001); 25 | if (Environment.OSVersion.Platform == PlatformID.Win32NT) 26 | { 27 | const int SIP_UDP_CONNRESET = -1744830452; 28 | udpClient.Client.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null); 29 | } 30 | } 31 | private bool IsRun = false; 32 | 33 | public ILogger Logger => _logger; 34 | 35 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 36 | { 37 | IsRun = true; 38 | Logger.LogInformation($"打洞服务器 UDP开启,端口{61001}"); 39 | udpClient.BeginReceive(ReceiveCallback, udpClient); 40 | await Task.Delay(-1, stoppingToken).ConfigureAwait(false); 41 | IsRun = false; 42 | } 43 | protected virtual async void ReceiveCallback(IAsyncResult ar) 44 | { 45 | System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(0, 0); 46 | byte[] bytes = null; 47 | try 48 | { 49 | 50 | bytes = udpClient.EndReceive(ar, ref remoteEndPoint); 51 | 52 | } 53 | finally 54 | { 55 | if (IsRun) 56 | { 57 | udpClient.BeginReceive(ReceiveCallback, udpClient); 58 | } 59 | } 60 | if (bytes.Length != 8) 61 | { 62 | return; 63 | } 64 | var sourceId = BitConverter.ToInt32(bytes, 0); 65 | var destId = BitConverter.ToInt32(bytes, 4); 66 | _logger.LogWarning($"{string.Join('.', bytes.Take(4))} 打洞到{string.Join('.', bytes.Skip(4).Take(4))} 链接{remoteEndPoint}"); 67 | var id= BitConverter.ToInt64(bytes, 0); 68 | if (p2pUdpEndPoints.TryAdd(id, remoteEndPoint)) 69 | { 70 | await Task.Delay(3000).ConfigureAwait(false); 71 | if (p2pUdpEndPoints.ContainsKey(id))//间隔5s还没被接受,就认为是死链 72 | { 73 | p2pUdpEndPoints.TryRemove(id, out _); 74 | _logger.LogWarning($"{remoteEndPoint} udp 无接受端 被关闭"); 75 | } 76 | return; 77 | } 78 | if (p2pUdpEndPoints.TryRemove(id,out var endPoint)) 79 | { 80 | udpClient.Send(System.Text.Encoding.UTF8.GetBytes(endPoint.ToString()), remoteEndPoint); 81 | udpClient.Send(System.Text.Encoding.UTF8.GetBytes(remoteEndPoint.ToString()), endPoint); 82 | return; 83 | } 84 | 85 | 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ListenerHosted/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using RemoteNetwork.ListenerHosted.HostedServices; 4 | 5 | namespace RemoteNetwork.ListenerHosted 6 | { 7 | internal class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | var builder = new HostApplicationBuilder(args); 12 | builder.Services.AddHostedService(); 13 | builder.Services.AddHostedService(); 14 | builder.Services.AddWindowsService(); 15 | var app = builder.Build(); 16 | app.Run(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.ListenerHosted/RemoteNetwork.ListenerHosted.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.34928.147 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteNetwork.ClientHosted", "RemoteNetwork.ClientHosted\RemoteNetwork.ClientHosted.csproj", "{D02111CE-B3F4-4E49-A870-EFF837732F2C}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteNetwork", "RemoteNetwork\RemoteNetwork.csproj", "{E9403999-269D-40EB-82AC-73D18501463B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteNetwork.ListenerHosted", "RemoteNetwork.ListenerHosted\RemoteNetwork.ListenerHosted.csproj", "{2806E3D0-F5DE-42EF-94F8-717CA8818BA0}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {D02111CE-B3F4-4E49-A870-EFF837732F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {D02111CE-B3F4-4E49-A870-EFF837732F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {D02111CE-B3F4-4E49-A870-EFF837732F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {D02111CE-B3F4-4E49-A870-EFF837732F2C}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {E9403999-269D-40EB-82AC-73D18501463B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E9403999-269D-40EB-82AC-73D18501463B}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E9403999-269D-40EB-82AC-73D18501463B}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {E9403999-269D-40EB-82AC-73D18501463B}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {2806E3D0-F5DE-42EF-94F8-717CA8818BA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {2806E3D0-F5DE-42EF-94F8-717CA8818BA0}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {2806E3D0-F5DE-42EF-94F8-717CA8818BA0}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {2806E3D0-F5DE-42EF-94F8-717CA8818BA0}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {50AC20CD-CAF6-4964-99A3-AF8984140A56} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/Config/TunDriveConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RemoteNetwork.Config 8 | { 9 | public class TunDriveConfig 10 | { 11 | public virtual string TunDriveIP { get; set; } 12 | public virtual string TunDriveName { get; set; } = "网卡名称"; 13 | 14 | public virtual string P2PHostName { get; set; } = "P2P打洞域名"; 15 | public virtual string DataExchangeHostName { get; set; } = "数据交换域名"; 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/HostedServices/LinuxTunDriveHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using RemoteNetwork.Config; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Runtime.InteropServices; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | namespace RemoteNetwork.HostedServices 14 | { 15 | public class LinuxTunDriveHostedService : TunDriveHostedService 16 | { 17 | public LinuxTunDriveHostedService(IOptions tunDriveConfigOptions, ILogger logger) : base(tunDriveConfigOptions, logger) 18 | { 19 | } 20 | public override bool ConnectionState(bool connection) 21 | { 22 | StartProcess("ip", $"link set {TunDriveConfig.TunDriveName} up"); 23 | Logger.LogInformation($"设置网卡“{TunDriveConfig.TunDriveName}” 为启用状态 mtu:1400"); 24 | StartProcess("ip", $"link set dev {TunDriveConfig.TunDriveName} mtu 1400"); 25 | return true; 26 | } 27 | 28 | protected override void ConfigIP(string ip, string netmask) 29 | { 30 | 31 | Logger.LogInformation($"设置网卡“{TunDriveConfig.TunDriveName}” IP地址:{ip}/24"); 32 | StartProcess("ip", $"addr add {ip}/24 dev {TunDriveConfig.TunDriveName}"); 33 | } 34 | [DllImport("libc.so.6", EntryPoint = "ioctl", SetLastError = true)] 35 | private static extern int Ioctl(SafeHandle device, UInt32 request, byte[] dat); 36 | private byte[] BytesPlusBytes(byte[] A, byte[] B) 37 | { 38 | byte[] ret = new byte[A.Length + B.Length - 1 + 1]; 39 | int k = 0; 40 | for (var i = 0; i <= A.Length - 1; i++) 41 | ret[i] = A[i]; 42 | k = A.Length; 43 | for (var i = k; i <= ret.Length - 1; i++) 44 | ret[i] = B[i - k]; 45 | return ret; 46 | } 47 | protected override FileStream OpenDrive() 48 | { 49 | var safeFileHandle = System.IO.File.OpenHandle("/dev/net/tun", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous); 50 | const UInt32 TUNSETIFF = 1074025674; 51 | byte[] ifreqFREG0 = System.Text.Encoding.ASCII.GetBytes(TunDriveConfig.TunDriveName); 52 | Array.Resize(ref ifreqFREG0, 16); 53 | byte[] ifreqFREG1 = { 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 54 | //IFF_TUN | IFF_NO_PI == 4097 == 1001 == 0x10,0x01 tun0 55 | byte[] ifreq = BytesPlusBytes(ifreqFREG0, ifreqFREG1); 56 | int stat = Ioctl(safeFileHandle, TUNSETIFF, ifreq); 57 | return new FileStream(safeFileHandle, FileAccess.ReadWrite, 1500); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/HostedServices/P2PUDPSocketHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Memory; 2 | using Microsoft.Extensions.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Options; 5 | using RemoteNetwork.Config; 6 | using System; 7 | using System.Collections.Concurrent; 8 | using System.Collections.Generic; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Net; 12 | using System.Net.Sockets; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | 16 | namespace RemoteNetwork.HostedServices 17 | { 18 | /// 19 | /// P2P UDP打洞服务 20 | /// 21 | public class P2PUDPSocketHostedService : BackgroundService 22 | { 23 | private readonly string P2PHost = ""; 24 | private const int P2PPort = 61001; 25 | 26 | private readonly ILogger _logger; 27 | private readonly ConcurrentDictionary p2pSocket = new ConcurrentDictionary(); 28 | private readonly IMemoryCache memoryCache; 29 | private readonly ConcurrentQueue queue; 30 | public IMemoryCache MemoryCache => memoryCache; 31 | public static P2PUDPSocketHostedService Instance { get; private set; } 32 | 33 | public ConcurrentDictionary P2pSocket => p2pSocket; 34 | 35 | public ILogger Logger => _logger; 36 | 37 | public P2PUDPSocketHostedService(ILogger logger, IMemoryCache memoryCache, IOptions tunDriveConfigOptions) 38 | { 39 | P2PHost = tunDriveConfigOptions.Value.P2PHostName; 40 | _logger = logger; 41 | this.memoryCache = memoryCache; 42 | Instance = this; 43 | } 44 | 45 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 46 | { 47 | await Task.Delay(-1,stoppingToken).ConfigureAwait(false); 48 | } 49 | void ReceiveCallback(IAsyncResult ar) 50 | { 51 | var udpClient = ar.AsyncState as UdpClient; 52 | System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(0, 0); 53 | byte[] bytes = null; 54 | try 55 | { 56 | 57 | bytes = udpClient.EndReceive(ar, ref remoteEndPoint); 58 | 59 | } 60 | finally 61 | { 62 | udpClient.BeginReceive(ReceiveCallback, udpClient); 63 | } 64 | if (bytes.Length > 8) 65 | { 66 | TunDriveHostedService.Instance.WriteFrameBuffer(bytes); 67 | } 68 | } 69 | public virtual async Task TestP2P(byte[] destId,bool sendRequest=true) 70 | { 71 | try 72 | { 73 | long p2pId = 0; 74 | if (sendRequest) 75 | { 76 | _logger.LogInformation($"请求打洞到{string.Join('.', destId)},发送打洞请求"); 77 | await TunNetWorkFrameHostedService.Instance.SendP2PRequestAsync(destId, default).ConfigureAwait(false); 78 | } 79 | _logger.LogInformation($"收到请求打洞到{string.Join('.', destId)}"); 80 | UdpClient client = new UdpClient(new System.Net.IPEndPoint(IPAddress.Any, 0)); 81 | if (Environment.OSVersion.Platform == PlatformID.Win32NT) 82 | { 83 | uint IOC_IN = 0x80000000; 84 | uint IOC_VENDOR = 0x18000000; 85 | uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; 86 | client.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { 0 }, null); 87 | } 88 | client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 89 | using (System.IO.MemoryStream memoryStream = new MemoryStream()) 90 | { 91 | if (sendRequest) 92 | { 93 | memoryStream.Write(TunDriveHostedService.Instance.Id); 94 | memoryStream.Write(destId); 95 | } 96 | else 97 | { 98 | memoryStream.Write(destId); 99 | memoryStream.Write(TunDriveHostedService.Instance.Id); 100 | } 101 | p2pId = BitConverter.ToInt64(memoryStream.ToArray()); 102 | await client.SendAsync(memoryStream.ToArray(), 8, new System.Net.IPEndPoint(Dns.GetHostAddresses(P2PHost)[0], P2PPort));//发送此次打洞的id 103 | } 104 | using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(3000)) 105 | { 106 | var receiveResult = await client.ReceiveAsync(cancellationTokenSource.Token); 107 | var text = Encoding.UTF8.GetString(receiveResult.Buffer); 108 | var remoteEndPoint = IPEndPoint.Parse(text);//远程端口 109 | Logger.LogInformation($"对方【{string.Join('.', destId)}】 的IP:{remoteEndPoint}"); 110 | 111 | await client.SendAsync(new byte[] { 1 }, 1, remoteEndPoint); 112 | using (CancellationTokenSource cancellationTokenSource1 = new CancellationTokenSource(3000)) 113 | { 114 | receiveResult = await client.ReceiveAsync(cancellationTokenSource1.Token); 115 | await client.SendAsync(new byte[] { 2 }, 1, receiveResult.RemoteEndPoint); 116 | 117 | if (P2pSocket.TryAdd(p2pId, new P2PUDPSocket(destId, p2pId, client, receiveResult.RemoteEndPoint))) 118 | { 119 | Logger.LogInformation($"与【{string.Join('.', destId)}】打洞成功 通道{p2pId} {remoteEndPoint} "); 120 | } 121 | else 122 | { 123 | Logger.LogWarning($"与【{string.Join('.', destId)}】打洞通道{p2pId}存在 "); 124 | } 125 | return; 126 | } 127 | } 128 | } 129 | catch 130 | { 131 | 132 | } 133 | _logger.LogInformation($"请求打洞到{string.Join('.', destId)} 失败"); 134 | } 135 | public virtual ITunNetWorkFrameSend GetP2PClient(byte[] dest) 136 | { 137 | long p2pId = 0; 138 | using (System.IO.MemoryStream memoryStream = new MemoryStream()) 139 | { 140 | memoryStream.Write(TunDriveHostedService.Instance.Id); 141 | memoryStream.Write(dest); 142 | p2pId = BitConverter.ToInt64(memoryStream.ToArray()); 143 | if (P2pSocket.TryGetValue(p2pId, out var client)) 144 | { 145 | return client; 146 | } 147 | memoryStream.Position = 0; 148 | memoryStream.Write(dest); 149 | memoryStream.Write(TunDriveHostedService.Instance.Id); 150 | p2pId = BitConverter.ToInt64(memoryStream.ToArray()); 151 | if (P2pSocket.TryGetValue(p2pId, out client)) 152 | { 153 | return client; 154 | } 155 | } 156 | MemoryCache.GetOrCreate(BitConverter.ToInt32(dest), (ic) => 157 | { 158 | ic.SetSlidingExpiration(TimeSpan.FromMinutes(3)); 159 | System.Threading.ThreadPool.QueueUserWorkItem((s) => { 160 | TestP2P(s as byte[]).ConfigureAwait(false); 161 | },dest); 162 | return true; 163 | }); 164 | return null; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/HostedServices/TunDriveHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using RemoteNetwork.Config; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace RemoteNetwork.HostedServices 13 | { 14 | //TunDriveExtensions 15 | public abstract class TunDriveHostedService : BackgroundService 16 | { 17 | private readonly TunDriveConfig _tunDriveConfig; 18 | private readonly ILogger _logger; 19 | public static TunDriveHostedService Instance { get; private set; } 20 | public TunDriveConfig TunDriveConfig => _tunDriveConfig; 21 | 22 | public FileStream TunStream { get => tunStream; } 23 | 24 | public TunDriveHostedService(IOptions tunDriveConfigOptions, ILogger logger) 25 | { 26 | _tunDriveConfig = tunDriveConfigOptions.Value ?? new TunDriveConfig(); 27 | _logger = logger; 28 | Instance=this; 29 | Id = TunDriveConfig.TunDriveIP.Split('.').Select(x => byte.Parse(x)).ToArray(); 30 | } 31 | private FileStream tunStream; 32 | /// 33 | /// 本机Id 34 | /// 35 | public virtual byte[] Id { get; set; } = new byte[] { 6,6,6,6 }; 36 | 37 | public ILogger Logger => _logger; 38 | 39 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 40 | { 41 | tunStream = OpenDrive(); 42 | Logger.LogInformation($"本机IP:{TunDriveConfig.TunDriveIP}"); 43 | ConfigIP(TunDriveConfig.TunDriveIP, "255.255.255.0"); 44 | ConnectionState(true); 45 | try 46 | { 47 | while (!stoppingToken.IsCancellationRequested) 48 | { 49 | await Task.Yield(); 50 | var buffer = new Memory(new byte[10240]); 51 | int length = await TunStream.ReadAsync(buffer, stoppingToken).ConfigureAwait(false); 52 | _= OnTunReceiveAsync(buffer.Slice(0, length), stoppingToken).ConfigureAwait(false); 53 | } 54 | } 55 | catch (Exception ex) 56 | { 57 | 58 | } 59 | finally 60 | { 61 | tunStream.Dispose(); 62 | } 63 | if (!stoppingToken.IsCancellationRequested) 64 | { 65 | await Task.Yield(); 66 | await ExecuteAsync(stoppingToken).ConfigureAwait(false); 67 | } 68 | } 69 | protected virtual async ValueTask OnTunReceiveAsync(Memory buffer, CancellationToken stoppingToken) 70 | { 71 | if (buffer.Span[0] != 0x45)//暂时不考虑别的,只考虑IPV4 72 | { 73 | return; 74 | } 75 | 76 | await TunNetWorkFrameHostedService.Instance.WriteFrameBufferAsync(buffer, stoppingToken).ConfigureAwait(false); 77 | //var destId = BitConverter.ToInt32(buffer.Slice(16,4).ToArray(), 0);// string.Join(".", buffer.Slice(16, 4).ToArray());// span[16] << 24 | span[17] << 16 | span[18] << 8 | span[19]; 78 | // var sourceId = BitConverter.ToInt32(buffer.Slice(12, 4).ToArray(), 0); 79 | 80 | // return ValueTask.CompletedTask; 81 | } 82 | public virtual void WriteFrameBuffer(byte[] buffer) 83 | { 84 | try 85 | { 86 | TunStream.Write(buffer); 87 | TunStream.Flush(); 88 | } 89 | catch (Exception ex) 90 | { 91 | 92 | } 93 | } 94 | 95 | public virtual string StartProcess(string fileName, string arguments, string verb = null, string workingDirectory = null) 96 | { 97 | string empty = string.Empty; 98 | using (Process process = new Process()) 99 | { 100 | process.StartInfo = new ProcessStartInfo 101 | { 102 | UseShellExecute = false, 103 | Arguments = arguments, 104 | RedirectStandardInput = true, 105 | RedirectStandardOutput = true, 106 | RedirectStandardError = true, 107 | CreateNoWindow = true, 108 | WorkingDirectory = workingDirectory ?? Environment.CurrentDirectory, 109 | FileName = fileName, 110 | Verb = verb 111 | }; 112 | process.Start(); 113 | process.WaitForExit(); 114 | empty = process.StandardOutput.ReadToEnd(); 115 | process.Close(); 116 | } 117 | return empty; 118 | } 119 | protected abstract void ConfigIP(string ip, string netmask); 120 | public abstract bool ConnectionState(bool connection); 121 | protected abstract FileStream OpenDrive(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/HostedServices/TunNetWorkFrameHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using RemoteNetwork.Config; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Net.Sockets; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace RemoteNetwork.HostedServices 13 | { 14 | public class TunNetWorkFrameHostedService : BackgroundService 15 | { 16 | private readonly string exchangeHostName = ""; 17 | private readonly int P2PPort = 61000; 18 | protected readonly ILogger _logger; 19 | public static TunNetWorkFrameHostedService Instance { get; private set; } 20 | private readonly UdpClient udpClient; 21 | private readonly System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(0, 0); 22 | public TunNetWorkFrameHostedService(ILogger logger, IOptions tunDriveConfigOptions) 23 | { 24 | exchangeHostName = tunDriveConfigOptions.Value.DataExchangeHostName; 25 | _logger = logger; 26 | Instance = this; 27 | udpClient = new UdpClient(0); if (Environment.OSVersion.Platform == PlatformID.Win32NT) 28 | { 29 | const int SIP_UDP_CONNRESET = -1744830452; 30 | udpClient.Client.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null); 31 | } 32 | } 33 | 34 | 35 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 36 | { 37 | udpClient.BeginReceive(ReceiveCallback, udpClient); 38 | while (!stoppingToken.IsCancellationRequested) 39 | { 40 | await udpClient.SendAsync(TunDriveHostedService.Instance.Id, exchangeHostName, P2PPort, stoppingToken).ConfigureAwait(false); 41 | await Task.Delay(1000*30, stoppingToken).ConfigureAwait(false); 42 | } 43 | } 44 | void ReceiveCallback(IAsyncResult ar) 45 | { 46 | System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(0, 0); 47 | byte[] bytes = null; 48 | try 49 | { 50 | 51 | bytes = udpClient.EndReceive(ar, ref remoteEndPoint); 52 | 53 | } 54 | finally 55 | { 56 | udpClient.BeginReceive(ReceiveCallback, udpClient); 57 | } 58 | if (bytes.Length == 4) 59 | { 60 | return; 61 | } 62 | if (bytes.Length == 5) 63 | { 64 | if (bytes[0] == 2) 65 | { 66 | P2PUDPSocketHostedService.Instance.TestP2P(bytes.Skip(1).ToArray(),false); 67 | } 68 | return; 69 | } 70 | 71 | TunDriveHostedService.Instance.WriteFrameBuffer(bytes); 72 | } 73 | public virtual async Task WriteFrameBufferAsync(Memory buffer, CancellationToken stoppingToken) 74 | { 75 | var destId = BitConverter.ToInt32(buffer.Slice(16, 4).ToArray(), 0); 76 | 77 | var tunNetWorkFrameSend= P2PUDPSocketHostedService.Instance.GetP2PClient(buffer.Slice(16, 4).ToArray()); 78 | if (tunNetWorkFrameSend != null) 79 | { 80 | await tunNetWorkFrameSend.SendAsync(buffer, stoppingToken).ConfigureAwait(false); 81 | return; 82 | } 83 | var bytes = new byte[buffer.Length + 8]; 84 | buffer.Slice(12, 8).CopyTo(bytes); 85 | Array.Copy(buffer.ToArray(), 0,bytes,8,buffer.Length); 86 | await udpClient.SendAsync(bytes, exchangeHostName, P2PPort, stoppingToken).ConfigureAwait(false); 87 | //var destId = BitConverter.ToInt32(buffer.Slice(16, 4).ToArray(), 0);// string.Join(".", buffer.Slice(16, 4).ToArray());// span[16] << 24 | span[17] << 16 | span[18] << 8 | span[19]; 88 | //var sourceId = BitConverter.ToInt32(buffer.Slice(12, 4).ToArray(), 0); 89 | //_logger.LogInformation($"{sourceId} 发送到{destId}"); 90 | } 91 | /// 92 | /// 发送打洞请求 93 | /// 94 | /// 95 | /// 96 | /// 97 | public virtual async Task SendP2PRequestAsync(byte[] destId, CancellationToken stoppingToken) 98 | { 99 | using (MemoryStream memoryStream = new MemoryStream()) { 100 | memoryStream.Write(TunDriveHostedService.Instance.Id); 101 | memoryStream.Write(destId); 102 | memoryStream.WriteByte(2); 103 | memoryStream.Write(TunDriveHostedService.Instance.Id); 104 | await udpClient.SendAsync(memoryStream.ToArray(), exchangeHostName, P2PPort, stoppingToken).ConfigureAwait(false); 105 | } 106 | 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/HostedServices/WinTunDriveHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.Extensions.Options; 3 | using Microsoft.Win32; 4 | using RemoteNetwork.Config; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO.Compression; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Runtime.InteropServices; 11 | using System.Runtime.Versioning; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | 15 | namespace RemoteNetwork.HostedServices 16 | { 17 | /// 18 | /// LinuxTunDriveHostedService 19 | /// 20 | [SupportedOSPlatform("windows")] 21 | public class WinTunDriveHostedService : TunDriveHostedService 22 | { 23 | private readonly static string DriverPath = AppDomain.CurrentDomain.BaseDirectory + "Drivers"; 24 | private const string AdapterKey = "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"; 25 | private const string ConnectionKey = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"; 26 | 27 | 28 | public const int TAP_WIN_IOCTL_GET_MAC = 1; 29 | public const int TAP_WIN_IOCTL_GET_VERSION = 2; 30 | public const int TAP_WIN_IOCTL_GET_MTU = 3; 31 | public const int TAP_WIN_IOCTL_GET_INFO = 4; 32 | public const int TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT = 5; 33 | public const int TAP_WIN_IOCTL_SET_MEDIA_STATUS = 6; 34 | public const int TAP_WIN_IOCTL_CONFIG_DHCP_MASQ = 7; 35 | public const int TAP_WIN_IOCTL_GET_LOG_LINE = 8; 36 | public const int TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT = 9; 37 | public const int TAP_WIN_IOCTL_CONFIG_TUN = 10; 38 | 39 | public const uint FILE_ATTRIBUTE_SYSTEM = 0x4; 40 | public const uint FILE_FLAG_OVERLAPPED = 0x40000000; 41 | public const uint METHOD_BUFFERED = 0; 42 | public const uint FILE_ANY_ACCESS = 0; 43 | public const uint FILE_DEVICE_UNKNOWN = 0x22; 44 | public WinTunDriveHostedService(IOptions tunDriveConfigOptions, ILogger logger) : base(tunDriveConfigOptions, logger) 45 | { 46 | } 47 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 48 | public static extern bool DeviceIoControl(SafeHandle device, uint IoControlCode, IntPtr InBuffer, uint InBufferSize, IntPtr OutBuffer, uint OutBufferSize, ref uint BytesReturned, IntPtr Overlapped); 49 | 50 | 51 | protected override FileStream OpenDrive() 52 | { 53 | var className = InstallOrGetClassNameDrive(); 54 | var safeFileHandle = System.IO.File.OpenHandle($@"\\.\\Global\\{className}.tap", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous); 55 | return new FileStream(safeFileHandle, FileAccess.ReadWrite, 1500); 56 | } 57 | protected virtual string InstallOrGetClassNameDrive() 58 | { 59 | using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(ConnectionKey)) 60 | { 61 | var names = registryKey.GetSubKeyNames(); 62 | foreach (var name in names) 63 | { 64 | using (var connectionRegistryKey = registryKey.OpenSubKey(name).OpenSubKey("Connection")) 65 | { 66 | if (connectionRegistryKey != null && connectionRegistryKey.GetValue("Name").ToString() == TunDriveConfig.TunDriveName) 67 | { 68 | return name; 69 | } 70 | } 71 | } 72 | 73 | Directory.CreateDirectory(DriverPath); 74 | ZipArchive zipArchive = new ZipArchive(typeof(WinTunDriveHostedService).Assembly.GetManifestResourceStream($"RemoteNetwork.{(Environment.Is64BitOperatingSystem ? "amd64" : "i386")}.zip"), ZipArchiveMode.Read); 75 | foreach (ZipArchiveEntry entry in zipArchive.Entries) 76 | { 77 | entry.ExtractToFile(Path.Combine(DriverPath, entry.FullName), overwrite: true); 78 | } 79 | StartProcess(Path.Combine(DriverPath, "tapinstall.exe"), $"install OemVista.inf TAP0901", "runas", DriverPath); 80 | foreach (var name in registryKey.GetSubKeyNames()) 81 | { 82 | if (!names.Contains(name)) 83 | { 84 | using (var connectionRegistryKey = registryKey.OpenSubKey(name).OpenSubKey("Connection")) 85 | { 86 | if (connectionRegistryKey != null) 87 | { 88 | StartProcess("netsh", @$"interface set interface name=""{connectionRegistryKey.GetValue("Name")}"" newname=""{TunDriveConfig.TunDriveName}"""); 89 | return name; 90 | } 91 | } 92 | } 93 | } 94 | return string.Empty; 95 | } 96 | } 97 | private static int ParseIP(string address) 98 | { 99 | byte[] addressBytes = address.Split('.').Select(s => byte.Parse(s)).ToArray(); 100 | return addressBytes[0] | (addressBytes[1] << 8) | (addressBytes[2] << 16) | (addressBytes[3] << 24); 101 | } 102 | protected override void ConfigIP(string ip, string netmask) 103 | { 104 | StartProcess("netsh", $"interface ip set address name=\"{TunDriveConfig.TunDriveName}\" source=static addr={ip} mask={netmask} gateway=none"); 105 | IntPtr intPtr = Marshal.AllocHGlobal(12); 106 | Marshal.WriteInt32(intPtr, 0, ParseIP(ip)); 107 | Marshal.WriteInt32(intPtr, 4, 0); 108 | Marshal.WriteInt32(intPtr, 8,0); 109 | uint lpBytesReturned = 0; 110 | bool result = DeviceIoControl(TunStream.SafeFileHandle, 2228264, intPtr, 12u, intPtr, 12u, ref lpBytesReturned, IntPtr.Zero); 111 | Marshal.FreeHGlobal(intPtr); 112 | } 113 | private static uint CTL_CODE(uint iDeviceType, uint iFunction, uint iMethod, uint iAccess) 114 | { 115 | return ((iDeviceType << 16) | (iAccess << 14) | (iFunction << 2) | iMethod); 116 | } 117 | public override bool ConnectionState(bool connection) 118 | { 119 | uint Length = 0; 120 | IntPtr cconfig = Marshal.AllocHGlobal(4); 121 | Marshal.WriteInt32(cconfig, connection ? 1 : 0); 122 | 123 | var b = DeviceIoControl(TunStream.SafeFileHandle, CTL_CODE(FILE_DEVICE_UNKNOWN, TAP_WIN_IOCTL_SET_MEDIA_STATUS, METHOD_BUFFERED, FILE_ANY_ACCESS), cconfig, 4, cconfig, 4, ref Length, IntPtr.Zero); 124 | StartProcess("netsh", $"netsh interface ipv4 set subinterface \"{TunDriveConfig.TunDriveName}\" mtu=\"1400\" store=persistent"); 125 | return b; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/P2PUDPSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Sockets; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using RemoteNetwork.HostedServices; 9 | using Microsoft.Extensions.Logging; 10 | using Microsoft.Extensions.Caching.Memory; 11 | 12 | namespace RemoteNetwork 13 | { 14 | public interface ITunNetWorkFrameSend 15 | { 16 | Task SendAsync(Memory buffer, CancellationToken stoppingToken); 17 | } 18 | public class P2PUDPSocket : IDisposable, ITunNetWorkFrameSend 19 | { 20 | private readonly UdpClient client; 21 | private readonly IPEndPoint _remoteEndPoint; 22 | public virtual IPEndPoint RemoteEndPoint => _remoteEndPoint; 23 | private readonly byte[] _destId; 24 | private readonly System.Threading.Timer timer; 25 | private DateTime lastDateTime; 26 | private DateTime lastReceiveDateTime; 27 | 28 | private bool isRun = true; 29 | private long p2pId; 30 | public P2PUDPSocket(byte[] destId,long p2pId, UdpClient client, IPEndPoint remoteEndPoint) 31 | { 32 | lastDateTime = DateTime.Now; 33 | _destId =destId; 34 | this.client = client; 35 | _remoteEndPoint = remoteEndPoint; 36 | this.p2pId=p2pId; 37 | timer = new System.Threading.Timer(TimerCallback, this, 1000*3, 1000 * 3); 38 | client.BeginReceive(ReceiveCallback, client); 39 | lastReceiveDateTime = DateTime.Now; 40 | } 41 | 42 | protected virtual void TimerCallback(object state) 43 | { 44 | 45 | if((DateTime.Now- lastDateTime).Seconds > 10) 46 | { 47 | P2PUDPSocketHostedService.Instance.P2pSocket.TryRemove(p2pId, out _); 48 | P2PUDPSocketHostedService.Instance.MemoryCache.Remove(BitConverter.ToInt32(_destId)); 49 | this.Dispose(); 50 | P2PUDPSocketHostedService.Instance.Logger.LogWarning($"与【{string.Join('.', _destId)}】 通道{p2pId} {RemoteEndPoint} 已废弃"); 51 | return; 52 | } 53 | if ((DateTime.Now - lastReceiveDateTime).TotalSeconds > 100) 54 | { 55 | _ = SendAsync(new byte[] { 0 }, default).ConfigureAwait(false); 56 | P2PUDPSocketHostedService.Instance.MemoryCache.Remove(BitConverter.ToInt32(_destId)); 57 | P2PUDPSocketHostedService.Instance.P2pSocket.TryRemove(p2pId, out _); 58 | this.Dispose(); 59 | P2PUDPSocketHostedService.Instance.Logger.LogWarning($"与【{string.Join('.', _destId)}】通道{p2pId} 长期无消息 通道 {RemoteEndPoint} 已废弃"); 60 | return; 61 | } 62 | _ = SendAsync(new byte[] { 2 }, default).ConfigureAwait(false); 63 | } 64 | public virtual async Task SendAsync(Memory buffer, CancellationToken stoppingToken) 65 | { 66 | await client.SendAsync(buffer, RemoteEndPoint, stoppingToken).ConfigureAwait(false); 67 | } 68 | void ReceiveCallback(IAsyncResult ar) 69 | { 70 | 71 | var udpClient = ar.AsyncState as UdpClient; 72 | System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(0, 0); 73 | byte[] bytes = null; 74 | try 75 | { 76 | 77 | bytes = udpClient.EndReceive(ar, ref remoteEndPoint); 78 | 79 | } 80 | catch(Exception) 81 | { 82 | 83 | } 84 | finally 85 | { 86 | if (isRun) 87 | { 88 | udpClient.BeginReceive(ReceiveCallback, udpClient); 89 | } 90 | 91 | } 92 | if (isRun) 93 | { 94 | lastDateTime = DateTime.Now; 95 | timer.Change(1000 * 3, 1000 * 3); 96 | if (bytes.Length == 1 ) 97 | { 98 | if( bytes[0] == 2) 99 | { 100 | _ = SendAsync(new byte[] { 1 }, default).ConfigureAwait(false); 101 | 102 | } 103 | else if (bytes[0] == 0) 104 | { 105 | P2PUDPSocketHostedService.Instance.P2pSocket.TryRemove(p2pId, out _); 106 | P2PUDPSocketHostedService.Instance.MemoryCache.Remove(BitConverter.ToInt32(_destId)); 107 | 108 | P2PUDPSocketHostedService.Instance.Logger.LogWarning($"与【{string.Join('.', _destId)}】 通道{p2pId} {RemoteEndPoint} 对方发来关闭 已废弃"); 109 | this.Dispose(); 110 | return; 111 | } 112 | return; 113 | } 114 | if (bytes.Length > 8) 115 | { 116 | lastReceiveDateTime = DateTime.Now; 117 | TunDriveHostedService.Instance.WriteFrameBuffer(bytes); 118 | } 119 | } 120 | } 121 | public void Dispose() 122 | { 123 | isRun = false; 124 | timer.Dispose(); 125 | client.Dispose(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/RemoteNetwork.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | disable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/TunDriveExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using RemoteNetwork.HostedServices; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics.CodeAnalysis; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace RemoteNetwork 12 | { 13 | public static class TunDriveExtensions 14 | { 15 | public static IServiceCollection AddTunDriveHostedService(this IServiceCollection services) 16 | { 17 | if (Environment.OSVersion.Platform == PlatformID.Win32NT) 18 | { 19 | services.AddHostedService(); 20 | } 21 | else 22 | { 23 | services.AddHostedService(); 24 | } 25 | services.AddHostedService(); 26 | services.AddHostedService(); 27 | return services; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/amd64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hn-lyf/RemoteNetwork/35b213d4ca7b593baf17d89ce9fa23a2e399017d/RemoteNetwork/RemoteNetwork/amd64.zip -------------------------------------------------------------------------------- /RemoteNetwork/RemoteNetwork/i386.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hn-lyf/RemoteNetwork/35b213d4ca7b593baf17d89ce9fa23a2e399017d/RemoteNetwork/RemoteNetwork/i386.zip --------------------------------------------------------------------------------