From 36aa9b1da307dbe5ea3a66f79f9f1fcd0914663a Mon Sep 17 00:00:00 2001 From: snltty <1069410172@qq.com> Date: Fri, 2 Aug 2024 17:46:04 +0800 Subject: [PATCH] sync --- .../2、首次运行/2.3、使用你自己的服务器.md | 3 ++ .../docs/3、打洞和中继/4.2、中继.md | 3 +- .../docs/4、通信功能/3.1、虚拟网卡.md | 29 +++++++++-- .../docs/4、通信功能/3.2、端口转发.md | 5 +- .../docs/4、通信功能/3.3、服务器代理穿透.md | 16 ++---- linker.libs/CommandHelper.cs | 5 ++ linker.tun/ILinkerTunDevice.cs | 4 ++ linker.tun/LinkerLinuxTunDevice.cs | 28 +++++++++++ linker.tun/LinkerTunDeviceAdapter.cs | 50 +++++++++++++++---- linker.tun/LinkerWinTunDevice.cs | 39 +++++++++++---- linker.tunnel/TunnelTransfer.cs | 1 + .../connection/TunnelConnectionTcp.cs | 2 +- linker/plugins/tuntap/TuntapTransfer.cs | 3 ++ linker/plugins/tuntap/proxy/TuntapProxy.cs | 18 +++++-- 14 files changed, 160 insertions(+), 46 deletions(-) diff --git a/linker.doc.web/docs/2、首次运行/2.3、使用你自己的服务器.md b/linker.doc.web/docs/2、首次运行/2.3、使用你自己的服务器.md index b11d7dde..24fdfcb5 100644 --- a/linker.doc.web/docs/2、首次运行/2.3、使用你自己的服务器.md +++ b/linker.doc.web/docs/2、首次运行/2.3、使用你自己的服务器.md @@ -10,10 +10,13 @@ sidebar_position: 3 ## 2、看图 + +:::tip[] 1. **信标服务器**,客户端之间交换信息,比如打洞,需要交换外网IP和外网端口 2. **端口服务器**,用于获取客户端外网IP和外网端口,协助打洞 3. **中继服务器**,用于在打洞失败后使用服务器中转进行通信,请填写你服务端的中继密钥 4. **服务器穿透**,就是内网穿透,你需要填写服务端的密钥 5. **服务器更新**,填写你服务器的更新密钥,让你的客户端有权自动更新服务器 +::: ![Docusaurus Plushie](./img/server.png) diff --git a/linker.doc.web/docs/3、打洞和中继/4.2、中继.md b/linker.doc.web/docs/3、打洞和中继/4.2、中继.md index 58547c2a..8e2b61a3 100644 --- a/linker.doc.web/docs/3、打洞和中继/4.2、中继.md +++ b/linker.doc.web/docs/3、打洞和中继/4.2、中继.md @@ -14,8 +14,7 @@ sidebar_position: 2 ## 1、配置中继密钥 -1. 在服务端 config/server.json 复制中继密钥 -2. 在客户端中,配置、中继服务器、中,双击密钥一栏,填写中继密钥 +在服务端 config/server.json 复制中继密钥,然后在客户端中,配置、中继服务器、中,双击密钥一栏,填写中继密钥 ![Docusaurus Plushie](./img/relay.png) ![Docusaurus Plushie](./img/relay1.png) \ No newline at end of file diff --git a/linker.doc.web/docs/4、通信功能/3.1、虚拟网卡.md b/linker.doc.web/docs/4、通信功能/3.1、虚拟网卡.md index d8114abc..a6c44806 100644 --- a/linker.doc.web/docs/4、通信功能/3.1、虚拟网卡.md +++ b/linker.doc.web/docs/4、通信功能/3.1、虚拟网卡.md @@ -7,8 +7,8 @@ sidebar_position: 1 :::tip[说明] 1. 各个设备的`网卡IP`,不要一样,要同一网段,且不应该使用`1`、`255` -2. `局域网IP`,是选填的,可以不填,不懂是啥时,不要填 - +2. `局域网IP`,是选填的,可以不填,不懂是啥时,不要填、不要填、不要填 +3. 虽然支持UDP广播,但是UDP广播不会去主动连接所有设备,所以,你可以先 ping 以下对方,让两端相互连接 ::: @@ -25,4 +25,27 @@ sidebar_position: 1 开启网卡成功后,即可通过`虚拟IP`访问目标设备(当然,前提是能够打洞成功,或者中继成功) ![Docusaurus Plushie](./img/tuntap2.png) -![Docusaurus Plushie](./img/tuntap3.png) \ No newline at end of file +![Docusaurus Plushie](./img/tuntap3.png) + + +## 3、点对网(局域网IP) + +:::tip[说明] + +1. 在各端,已经自动添加NAT,只需要填写自己的局域网IP,对方即可访问你局域网内的所有设备 +2. 局域网IP,是你设备所在局域网的IP,不是虚拟网卡IP、不是虚拟网卡IP、不是虚拟网卡IP + +::: + + +## 4、网对网 + +:::tip[说明] + +1. 如果你把linker安装在路由器上,你可以 +2. 在使用**A端**使用 `iptables -t nat -A POSTROUTING -o linker -s 192.168.1.0/24 -j MASQUERADE` 添加转发规则,**192.168.1.0/24**是**B端**的局域网IP +3. 这样在**A端**的所有局域网设备,都可以访问**B端**的所有局域网设备 +4. 反之B端想要访问A端,也是一样 + +::: + diff --git a/linker.doc.web/docs/4、通信功能/3.2、端口转发.md b/linker.doc.web/docs/4、通信功能/3.2、端口转发.md index d52c5009..853943d6 100644 --- a/linker.doc.web/docs/4、通信功能/3.2、端口转发.md +++ b/linker.doc.web/docs/4、通信功能/3.2、端口转发.md @@ -11,8 +11,7 @@ sidebar_position: 2 ::: ## 1、配置端口转发 - -1. 在 **非本机** 设备上,端口转发一栏,管理你的端口转发,表示要使用`本机`的某个端口,去访问它的服务 +在 **非本机** 设备上,端口转发一栏,管理你的端口转发,表示要使用`本机`的某个端口,去访问它的服务 ![Docusaurus Plushie](./img/forward.png) @@ -27,7 +26,7 @@ sidebar_position: 2 ## 2、可能存在的问题 :::danger[说明] -1. 开启后,如果红色,表示无法访问 +开启后,如果红色,表示无法访问 ::: ![Docusaurus Plushie](./img/forward3.png) diff --git a/linker.doc.web/docs/4、通信功能/3.3、服务器代理穿透.md b/linker.doc.web/docs/4、通信功能/3.3、服务器代理穿透.md index 40c46250..122ff109 100644 --- a/linker.doc.web/docs/4、通信功能/3.3、服务器代理穿透.md +++ b/linker.doc.web/docs/4、通信功能/3.3、服务器代理穿透.md @@ -13,32 +13,25 @@ sidebar_position: 3 ## 1、配置穿透密钥 - -1. 在服务端 configs/server.json 中,复制密钥 -2. 添加到配置中 +在服务端 configs/server.json 中,复制密钥,添加到客户端配置中 ![Docusaurus Plushie](./img/sforward-key.png) ![Docusaurus Plushie](./img/sforward-key1.png) ## 2、配置端口转发 - -1. 在 **本机** 设备上,端口转发一栏,表示要从 **服务器**指定端口,或指定域名访问本机指定服务 -2. 如果显示 **暂无配置**,表示未配置端口转发,可以点击,展开配置端口转发窗口。 -3. 如果已经配置过端口转发,则显示端口转发列表 +在 **本机** 设备上,端口转发一栏 ![Docusaurus Plushie](./img/sforward1.png) -1. 点击**添加**按钮,添加一项转发 -2. 可以双击 **名称**、**远程域名/端口**、**本机服务**一栏进行修改 -3. 监听端口不可为0,需指定端口 -4. 配置完成后,在 **状态**一栏,选择开启或关闭转发 +点击**添加**按钮,添加一项转发,未开启转发时,可以双击 **名称**、**远程域名/端口**、**本机服务**一栏进行修改 ![Docusaurus Plushie](./img/sforward2.png) ## 3、注意事项 +:::danger[注意] 1. 如果你使用域名,则需要将域名解析到你的服务器,且,服务端需配置web端口 1. 假设我端口转发 **远程端口/域名** 一栏,填写 **aaa.linker.snltty.com**,则需要将域名泛解析 ***.linker.snltty.com** 到服务器 2. 在本机服务一栏,填写 **127.0.0.1:8880** @@ -48,6 +41,7 @@ sidebar_position: 3 1. 假设我端口转发 **远程端口/域名** 一栏,填写 **20480**,这时候 2. 在本机服务一栏,填写 **127.0.0.1:8880** 3. 在访问 **linker.snltty.com:20480** 时,能访问到本机的**127.0.0.1:8880**服务 +::: ![Docusaurus Plushie](./img/sforward-port.png) diff --git a/linker.libs/CommandHelper.cs b/linker.libs/CommandHelper.cs index ed400914..c82fb4f0 100644 --- a/linker.libs/CommandHelper.cs +++ b/linker.libs/CommandHelper.cs @@ -9,6 +9,11 @@ namespace linker.libs { return Execute("cmd.exe", arg, commands, readResult); } + public static string PowerShell(string arg, string[] commands, bool readResult = true) + { + return Execute("powershell.exe", arg, commands, readResult); + } + public static string Linux(string arg, string[] commands, bool readResult = true) { return Execute("/bin/bash", arg, commands, readResult); diff --git a/linker.tun/ILinkerTunDevice.cs b/linker.tun/ILinkerTunDevice.cs index 88b7fb47..f4e40456 100644 --- a/linker.tun/ILinkerTunDevice.cs +++ b/linker.tun/ILinkerTunDevice.cs @@ -10,6 +10,10 @@ namespace linker.tun public bool SetUp(IPAddress address, IPAddress gateway, byte prefixLength, out string error); public void Shutdown(); + public void SetMtu(int value); + public void SetNat(); + public void RemoveNat(); + public void AddRoute(LinkerTunDeviceRouteItem[] ips, IPAddress ip); public void DelRoute(LinkerTunDeviceRouteItem[] ip); diff --git a/linker.tun/LinkerLinuxTunDevice.cs b/linker.tun/LinkerLinuxTunDevice.cs index 95b99ac4..c3e8c355 100644 --- a/linker.tun/LinkerLinuxTunDevice.cs +++ b/linker.tun/LinkerLinuxTunDevice.cs @@ -3,6 +3,7 @@ using Microsoft.Win32.SafeHandles; using System.Net; using System.Runtime.InteropServices; using System.Text; +using System.Threading.Tasks; namespace linker.tun { @@ -15,6 +16,9 @@ namespace linker.tun private string interfaceLinux = string.Empty; private FileStream fs = null; + private string iptableLineNumber = string.Empty; + private IPAddress address; + private byte prefixLength = 24; public LinkerLinuxTunDevice(string name) { @@ -23,6 +27,8 @@ namespace linker.tun public bool SetUp(IPAddress address, IPAddress gateway, byte prefixLength, out string error) { + this.address = address; + this.prefixLength = prefixLength; error = string.Empty; if (fs != null) { @@ -69,6 +75,28 @@ namespace linker.tun CommandHelper.Linux(string.Empty, new string[] { $"ip tuntap del mode tun dev {Name}" }); } + public void SetMtu(int value) + { + CommandHelper.Linux(string.Empty, new string[] { $"ip link set dev {Name} mtu {value}" }); + } + public void SetNat() + { + IPAddress network = NetworkHelper.ToNetworkIp(address, NetworkHelper.MaskValue(prefixLength)); + CommandHelper.PowerShell(string.Empty, new string[] { + $"sysctl -w net.ipv4.ip_forward=1", + $"iptables -t nat -A POSTROUTING ! -o {Name} -s {network}/{prefixLength} -j MASQUERADE", + }); + iptableLineNumber = CommandHelper.Linux(string.Empty, new string[] { $"iptables -t nat -L --line-numbers | grep {network}/{prefixLength} | cut -d' ' -f1" }); + } + public void RemoveNat() + { + if (string.IsNullOrWhiteSpace(iptableLineNumber) == false) + { + CommandHelper.PowerShell(string.Empty, new string[] { $"iptables -t nat -D POSTROUTING {iptableLineNumber}" }); + } + } + + public void AddRoute(LinkerTunDeviceRouteItem[] ips, IPAddress ip) { string[] commands = ips.Select(item => diff --git a/linker.tun/LinkerTunDeviceAdapter.cs b/linker.tun/LinkerTunDeviceAdapter.cs index 76100821..0e86c7b6 100644 --- a/linker.tun/LinkerTunDeviceAdapter.cs +++ b/linker.tun/LinkerTunDeviceAdapter.cs @@ -1,5 +1,6 @@ using linker.libs; using System.Net; +using System.Xml.Linq; namespace linker.tun { @@ -12,7 +13,6 @@ namespace linker.tun private string error = string.Empty; public string Error => error; - private bool starting = false; public LinkerTunDeviceStatus Status { @@ -48,11 +48,12 @@ namespace linker.tun /// 网卡名,如果是osx,需要utunX的命名,X是一个数字 /// windows的时候,需要一个固定guid,不然网卡编号一直递增,注册表一直新增记录 /// 网卡IP - /// 掩码。一般24即可 - public void SetUp(string name, Guid guid, IPAddress address, byte mask) + /// 掩码。一般24即可 + public void SetUp(string name, Guid guid, IPAddress address, byte prefixLength) { if (starting) return; Shutdown(); + starting = true; try { @@ -70,8 +71,8 @@ namespace linker.tun if (linkerTunDevice != null) { linkerTunDevice.Shutdown(); + linkerTunDevice.SetUp(address, NetworkHelper.ToGatewayIP(address, prefixLength), prefixLength, out error); - linkerTunDevice.SetUp(address, NetworkHelper.ToGatewayIP(address, mask), mask, out error); if (string.IsNullOrWhiteSpace(error)) { cancellationTokenSource = new CancellationTokenSource(); @@ -87,22 +88,25 @@ namespace linker.tun break; } + LinkerTunDevicPacket packet = new LinkerTunDevicPacket(); packet.Packet = buffer; - packet.Version = (byte)(buffer.Span[0] >> 4 & 0b1111); + + ReadOnlyMemory ipPacket = buffer.Slice(4); + + packet.Version = (byte)(ipPacket.Span[0] >> 4 & 0b1111); if (packet.Version == 4) { - packet.SourceIPAddress = buffer.Slice(12, 4); - packet.DistIPAddress = buffer.Slice(16, 4); + packet.SourceIPAddress = ipPacket.Slice(12, 4); + packet.DistIPAddress = ipPacket.Slice(16, 4); } else if (packet.Version == 6) { - packet.SourceIPAddress = buffer.Slice(8, 16); - packet.DistIPAddress = buffer.Slice(24, 16); + packet.SourceIPAddress = ipPacket.Slice(8, 16); + packet.DistIPAddress = ipPacket.Slice(24, 16); } - - await linkerTunDeviceCallback.Callback(packet); + await linkerTunDeviceCallback.Callback(packet).ConfigureAwait(false); } catch (Exception) { @@ -131,11 +135,35 @@ namespace linker.tun if (linkerTunDevice != null) { linkerTunDevice.Shutdown(); + linkerTunDevice.RemoveNat(); } error = string.Empty; } + + public void SetMtu(int value) + { + if (linkerTunDevice != null) + { + linkerTunDevice.SetMtu(value); + } + } + public void SetNat() + { + if (linkerTunDevice != null) + { + linkerTunDevice.SetNat(); + } + } + public void RemoveNat() + { + if (linkerTunDevice != null) + { + linkerTunDevice.RemoveNat(); + } + } + /// /// 添加路由 /// diff --git a/linker.tun/LinkerWinTunDevice.cs b/linker.tun/LinkerWinTunDevice.cs index 8874bb17..7e413cb3 100644 --- a/linker.tun/LinkerWinTunDevice.cs +++ b/linker.tun/LinkerWinTunDevice.cs @@ -1,4 +1,5 @@ using linker.libs; +using linker.libs.extends; using System.Buffers.Binary; using System.Net; using System.Net.NetworkInformation; @@ -16,6 +17,8 @@ namespace linker.tun private IntPtr waitHandle = IntPtr.Zero, adapter = IntPtr.Zero, session = IntPtr.Zero, session1 = IntPtr.Zero; private Guid guid; private int interfaceNumber = 0; + private IPAddress address; + private byte prefixLength = 24; private CancellationTokenSource tokenSource; @@ -27,7 +30,9 @@ namespace linker.tun public bool SetUp(IPAddress address, IPAddress gateway, byte prefixLength, out string error) { - + this.address = address; + this.prefixLength = prefixLength; + error = string.Empty; if (adapter != 0) { @@ -51,11 +56,6 @@ namespace linker.tun waitHandle = WintunGetReadWaitEvent(session); - WintunSetLogger((WINTUN_LOGGER_LEVEL level, ulong timestamp,string message) => - { - Console.WriteLine($"[{level}]->{timestamp}->{message}"); - }); - WintunGetAdapterLUID(adapter, out ulong luid); { MIB_UNICASTIPADDRESS_ROW AddressRow = default; @@ -106,6 +106,22 @@ namespace linker.tun interfaceNumber = 0; } + + public void SetMtu(int value) + { + CommandHelper.Windows(string.Empty, new string[] { $"netsh interface ipv4 set subinterface {interfaceNumber} mtu={value} store=persistent" }); + } + public void SetNat() + { + IPAddress network = NetworkHelper.ToNetworkIp(this.address, NetworkHelper.MaskValue(prefixLength)); + CommandHelper.PowerShell(string.Empty, new string[] { $"New-NetNat -Name {Name} -InternalIPInterfaceAddressPrefix {network}/{prefixLength}" }); + } + public void RemoveNat() + { + CommandHelper.PowerShell(string.Empty, new string[] { $"Remove-NetNat -Name {Name}" }); + } + + public void AddRoute(LinkerTunDeviceRouteItem[] ips, IPAddress ip) { if (interfaceNumber > 0) @@ -146,11 +162,13 @@ namespace linker.tun for (; tokenSource.IsCancellationRequested == false;) { IntPtr packet = WintunReceivePacket(session, out var packetSize); + if (packet != 0) { - new Span((byte*)packet, (int)packetSize).CopyTo(buffer.AsSpan(0, (int)packetSize)); + new Span((byte*)packet, (int)packetSize).CopyTo(buffer.AsSpan(4, (int)packetSize)); + ((int)packetSize).ToBytes(buffer); WintunReleaseReceivePacket(session, packet); - return buffer.AsMemory(0, (int)packetSize); + return buffer.AsMemory(0, (int)packetSize + 4); } else { @@ -164,7 +182,7 @@ namespace linker.tun } public unsafe bool Write(ReadOnlyMemory buffer) { - if (session == 0) return false; + if (session == 0 || tokenSource.IsCancellationRequested) return false; IntPtr packet = WintunAllocateSendPacket(session, (uint)buffer.Length); if (packet != 0) @@ -192,6 +210,8 @@ namespace linker.tun } } + + [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 80)] private struct MIB_UNICASTIPADDRESS_ROW { @@ -289,7 +309,6 @@ namespace linker.tun [DllImport("wintun.dll", SetLastError = true)] private static extern void WintunSetLogger(WINTUN_LOGGER_CALLBACK newLogger); - private delegate void WINTUN_LOGGER_CALLBACK( WINTUN_LOGGER_LEVEL level, ulong timestamp, diff --git a/linker.tunnel/TunnelTransfer.cs b/linker.tunnel/TunnelTransfer.cs index 85ba27aa..eb2094a3 100644 --- a/linker.tunnel/TunnelTransfer.cs +++ b/linker.tunnel/TunnelTransfer.cs @@ -172,6 +172,7 @@ namespace linker.tunnel } LoggerHelper.Instance.Info($"tunnel {transport.Name} got local external ip {localInfo.Result.ToJson()}"); LoggerHelper.Instance.Info($"tunnel {transport.Name} got remote external ip {remoteInfo.Result.ToJson()}"); + LoggerHelper.Instance.Info($"tunnel {transportItem.ToJson()}"); tunnelTransportInfo = new TunnelTransportInfo diff --git a/linker.tunnel/connection/TunnelConnectionTcp.cs b/linker.tunnel/connection/TunnelConnectionTcp.cs index c6f2f820..b3475cd9 100644 --- a/linker.tunnel/connection/TunnelConnectionTcp.cs +++ b/linker.tunnel/connection/TunnelConnectionTcp.cs @@ -68,7 +68,7 @@ namespace linker.tunnel.connection cancellationTokenSource = new CancellationTokenSource(); _ = ProcessWrite(); - //_ = ProcessHeart(); + _ = ProcessHeart(); } private async Task ProcessWrite() diff --git a/linker/plugins/tuntap/TuntapTransfer.cs b/linker/plugins/tuntap/TuntapTransfer.cs index 5dd005be..61b082a0 100644 --- a/linker/plugins/tuntap/TuntapTransfer.cs +++ b/linker/plugins/tuntap/TuntapTransfer.cs @@ -91,6 +91,8 @@ namespace linker.plugins.tuntap } linkerTunDeviceAdapter.SetUp(interfaceName, runningConfig.Data.Tuntap.InterfaceGuid, runningConfig.Data.Tuntap.IP, 24); + linkerTunDeviceAdapter.SetMtu(1416); + linkerTunDeviceAdapter.SetNat(); runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running; runningConfig.Data.Update(); @@ -118,6 +120,7 @@ namespace linker.plugins.tuntap { OnChange(); linkerTunDeviceAdapter.Shutdown(); + linkerTunDeviceAdapter.RemoveNat(); runningConfig.Data.Tuntap.Running = Status == TuntapStatus.Running; runningConfig.Data.Update(); } diff --git a/linker/plugins/tuntap/proxy/TuntapProxy.cs b/linker/plugins/tuntap/proxy/TuntapProxy.cs index e5d16e45..67154c66 100644 --- a/linker/plugins/tuntap/proxy/TuntapProxy.cs +++ b/linker/plugins/tuntap/proxy/TuntapProxy.cs @@ -10,7 +10,7 @@ using System.Net; using linker.plugins.tuntap.config; using linker.tun; using System.Buffers.Binary; -using System.Text; +using System.Net.Sockets; namespace linker.plugins.tuntap.proxy { @@ -30,6 +30,10 @@ namespace linker.plugins.tuntap.proxy SemaphoreSlim slimGlobal = new SemaphoreSlim(1); private readonly ConcurrentDictionary dicLocks = new ConcurrentDictionary(); + + private ITunnelConnection[] cache = new ITunnelConnection[255]; + + public TuntapProxy(TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, RunningConfig runningConfig, FileConfig config, LinkerTunDeviceAdapter linkerTunDeviceAdapter) { this.tunnelTransfer = tunnelTransfer; @@ -60,7 +64,7 @@ namespace linker.plugins.tuntap.proxy } connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection); - connection.BeginReceive(this, null, false); + connection.BeginReceive(this, null); } public async Task Receive(ITunnelConnection connection, ReadOnlyMemory buffer, object state) { @@ -86,7 +90,13 @@ namespace linker.plugins.tuntap.proxy } else { - ITunnelConnection connection = await ConnectTunnel(ip); + ITunnelConnection connection = cache[packet.DistIPAddress.Span[3]]; + if (connection == null || connection.Connected == false) + { + connection = await ConnectTunnel(ip); + cache[packet.DistIPAddress.Span[3]] = connection; + } + cache[packet.DistIPAddress.Span[3]] = connection; if (connection != null) { await connection.SendAsync(packet.Packet); @@ -100,8 +110,6 @@ namespace linker.plugins.tuntap.proxy await Task.WhenAll(connections.Values.Select(c => c.SendAsync(packet.Packet))); } } - - Console.WriteLine($"IPV{packet.Version}->{new IPAddress(packet.SourceIPAddress.Span)}->{new IPAddress(packet.DistIPAddress.Span)}->{packet.Packet.Length}"); }