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. **服务器更新**,填写你服务器的更新密钥,让你的客户端有权自动更新服务器
+:::

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 复制中继密钥,然后在客户端中,配置、中继服务器、中,双击密钥一栏,填写中继密钥


\ 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`访问目标设备(当然,前提是能够打洞成功,或者中继成功)

-
\ No newline at end of file
+
+
+
+## 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. 在 **非本机** 设备上,端口转发一栏,管理你的端口转发,表示要使用`本机`的某个端口,去访问它的服务
+在 **非本机** 设备上,端口转发一栏,管理你的端口转发,表示要使用`本机`的某个端口,去访问它的服务

@@ -27,7 +26,7 @@ sidebar_position: 2
## 2、可能存在的问题
:::danger[说明]
-1. 开启后,如果红色,表示无法访问
+开启后,如果红色,表示无法访问
:::

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 中,复制密钥,添加到客户端配置中


## 2、配置端口转发
-
-1. 在 **本机** 设备上,端口转发一栏,表示要从 **服务器**指定端口,或指定域名访问本机指定服务
-2. 如果显示 **暂无配置**,表示未配置端口转发,可以点击,展开配置端口转发窗口。
-3. 如果已经配置过端口转发,则显示端口转发列表
+在 **本机** 设备上,端口转发一栏

-1. 点击**添加**按钮,添加一项转发
-2. 可以双击 **名称**、**远程域名/端口**、**本机服务**一栏进行修改
-3. 监听端口不可为0,需指定端口
-4. 配置完成后,在 **状态**一栏,选择开启或关闭转发
+点击**添加**按钮,添加一项转发,未开启转发时,可以双击 **名称**、**远程域名/端口**、**本机服务**一栏进行修改

## 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**服务
+:::

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}");
}