This commit is contained in:
snltty
2025-01-04 18:18:23 +08:00
parent 75e3d9767e
commit cb269b05f3
78 changed files with 563 additions and 298 deletions

View File

@@ -60,62 +60,6 @@
<p><img src="./readme/full.png"></p>
</div>
## 收费项目
<div align="center">
<table width="100%">
<thead>
<tr>
<th></th>
<th>2设备内</th>
<th>2-5设备</th>
<th>5-10设备</th>
<th>10设备以上</th>
</tr>
</thead>
<tbody>
<tr>
<td>使用</td>
<td>免费</td>
<td>免费</td>
<td>免费</td>
<td>免费</td>
</tr>
<tr>
<td>开源集成</td>
<td>免费</td>
<td>免费</td>
<td>免费</td>
<td>免费</td>
</tr>
<tr>
<td>安装维护/次</td>
<td>免费</td>
<td>9.9/台</td>
<td>9.9/台</td>
<td>9.9/台</td>
</tr>
<tr>
<td>安装维护/年</td>
<td>19.9/年</td>
<td>39.9/年</td>
<td>79.9/年</td>
<td>9.9/年/台</td>
</tr>
<tr>
<td>商业集成</td>
<td colspan="4" align="center">详谈</td>
</tr>
<tr>
<td>商业功能定制</td>
<td colspan="4" align="center">详谈</td>
</tr>
</tbody>
</table>
</div>
## 可怜作者
<div align="center">

View File

@@ -0,0 +1,7 @@
---
sidebar_position: 10
---
# 10、公益赞助
![Docusaurus Plushie](./img/qr.jpg)

View File

@@ -4,12 +4,10 @@ sidebar_position: 6
# 6、自定义验证
## 1、不修改源码的Action方式
:::tip[说明]
1. 服务端`action.json`中的,`RelayActionUrl中继``SForwardActionUrl穿透``SignInActionUrl信标`都可以设置支持HTTP POST的URL当不为空时这些操作都会发送HTTP POST请求到`ActionUrl`并携带json参数可用于自定义验证。
2.`Action验证`中,设置静态参数,或者使用管理接口动态配置参数
3. 优先采用动态参数,动态参数为空则使用信标服务器配置的参数。
3. 优先采用动态参数,动态参数为空则使用页面配置的静态参数。
4. `HTTP POST`返回`ok`表示验证成功,其余均为错误信息。
@@ -118,115 +116,3 @@ public sealed class JsonArgSForwardInfo
}
```
:::
## 2、修改源码方式
:::tip[说明]
你可以在任意对方编写这些代码,可以参考 `plugins->action`action插件就是使用以下方式实现。
### 2.1、连接服务器验证
```
public sealed class MySignArgs:ISignInArgs
{
//客户端连接服务器时调用你可以往args里添加你自定义的参数
public async Task<string> Invoke(Dictionary<string, string> args)
{
args.TryAdd("myArg", "");
//返回空字符串表示成功操作,非空将断开连接
return string.Empty;
}
public async Task<string> Verify(SignInfo signInfo, SignCacheInfo cache)
{
//本地连接的参数
signInfo.Args.TryGetValue("myArg", out string argNew);
//之前连接的参数
cache.Args.TryGetValue("myArg", out string argOld);
//返回空字符串表示验证通过,非空将断开连接
return string.Empty;
}
}
```
### 2.2、中继验证
```
public sealed class MyRelayValidator : IRelayValidator
{
public MyRelayValidator()
{
}
// <summary>
/// 验证
/// </summary>
/// <param name="fromMachine">来源客户端</param>
/// <param name="toMachine">目标客户端可能为null</param>
/// <returns></returns>
public async Task<string> Validate(SignCacheInfo fromMachine, SignCacheInfo toMachine)
{
//返回空字符串表示验证通过,非空将断开连接
return string.Empty;
}
}
```
### 2.3、内网穿透验证
```
public sealed class MySForwardValidator : ISForwardValidator
{
public MySForwardValidator()
{
}
/// <summary>
/// 验证
/// </summary>
/// <param name="signCacheInfo">来源客户端</param>
/// <param name="sForwardAddInfo">穿透信息</param>
/// <returns></returns>
public async Task<string> Validate(SignCacheInfo cache, SForwardAddInfo sForwardAddInfo)
{
//返回空字符串表示验证通过,非空将不允许添加穿透
return string.Empty;
}
}
```
### 2.4、实现一个启动器,将你的这些实现注入
```
public sealed class MyValidatorStartup : IStartup
{
public StartupLevel Level => StartupLevel.Normal;
public string Name => "myValdator";
public bool Required => false;
public string[] Dependent => new string[] {};
public StartupLoadType LoadType => StartupLoadType.Normal;
//客户端
public void AddClient(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<MySignArgs>();
serviceCollection.AddSingleton<MyRelayValidator>();
serviceCollection.AddSingleton<MySForwardValidator>();
}
//服务端
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<MySignArgs>();
serviceCollection.AddSingleton<MyRelayValidator>();
serviceCollection.AddSingleton<MySForwardValidator>();
}
public void UseClient(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, FileConfig config, Assembly[] assemblies)
{
}
}
```
:::

View File

@@ -2,7 +2,10 @@
sidebar_position: 1
---
# 8.1、集成linker
# 8.1、开始运行
## 1、入口
:::tip[说明]
1. 在你的.NET8.0+项目中集成linker
2. 在nuget安装`linker.messenger.entry`
@@ -26,13 +29,13 @@ LinkerMessengerEntry.Build();
//apiStore.SetWebPort(0);
//apiStore.Confirm();
//启动
LinkerMessengerEntry.Setup();
//启动在这里可以排除一些模块ExcludeModule.Node 不排除,比如我不需要检测更新和管理接口和网页
LinkerMessengerEntry.Setup(ExcludeModule.Updater | ExcludeModule.Api );
```
:::
# 1、一些配置接口
## 2、一些配置接口
:::tip[说明]
1. 你可以在initialize之后注入覆盖这些实现和build之后获取这些接口来操作配置
3. 管理接口详情请看各个组件里的`IApiController`实现,包含了全部的管理接口

View File

@@ -1,8 +1,8 @@
---
sidebar_position: 2
sidebar_position: 22
---
# 8.2、单独使用虚拟网卡
# 8.22、单独使用虚拟网卡
## 1、说明

View File

@@ -0,0 +1,20 @@
---
sidebar_position: 2
---
# 8.2、配置信息存储库
:::tip[说明]
1. 在解决方案中,找到以`linker.messenger`开头的项目里以`Store`结尾的`interface`,实现它们
2. 然后注入覆盖原本的文件存储库实现
```
//初始化
LinkerMessengerEntry.Initialize();
//在这里可以注入覆盖实现
LinkerMessengerEntry.AddService<ICommonStore, MyCommonStore>();
LinkerMessengerEntry.Build();
//排除默认的文件存储库,让它不要生成文件
LinkerMessengerEntry.Setup(ExcludeModule.StoreFile);
```
:::

View File

@@ -1,8 +1,8 @@
---
sidebar_position: 3
sidebar_position: 33
---
# 8.3、组网和内网穿透流程图
# 8.33、组网和内网穿透流程图
:::tip[说明]

View File

@@ -0,0 +1,20 @@
---
sidebar_position: 3
---
# 8.3、序列化库
:::tip[说明]
1. 实现`linker.libs.ISerializer`接口
2. 然后注入覆盖原本的序列化库实现
```
//初始化
LinkerMessengerEntry.Initialize();
//在这里可以注入覆盖实现
LinkerMessengerEntry.AddService<linker.libs.ISerializer, MySerializer>();
LinkerMessengerEntry.Build();
//排除默认的序列化库
LinkerMessengerEntry.Setup(ExcludeModule.SerializerMemoryPack);
```
:::

View File

@@ -0,0 +1,96 @@
---
sidebar_position: 4
---
# 8.4、登入信标验证
:::tip[说明]
登入信标,注入自定义参数,或者使用已有参数验证
```
//初始化
LinkerMessengerEntry.Initialize();
//在这里注入
LinkerMessengerEntry.AddService<MyClientSignInArgs>();
LinkerMessengerEntry.AddService<MyServerSignInArgs>();
//构建
LinkerMessengerEntry.Build();
SignInArgsTransfer signInArgsTransfer = LinkerMessengerEntry.GetService<SignInArgsTransfer>();
//可以删除默认的一些验证,group分组密码machineId设备唯一编号secretKey信标密钥version版本验证
//signInArgsTransfer.RemoveArgs(new List<string>{ "group","machineId","secretKey","version" });
ICommonStore commonStore = LinkerMessengerEntry.GetService<ICommonStore>();
//客户端则添加客户端类
if((commonStore.Modes & CommonModes.Client) == CommonModes.Client)
{
signInArgsTransfer.AddArgs(new List<ISignInArgs> {
LinkerMessengerEntry.GetService<MyClientSignInArgs>()
});
}
//服务端则添加服务端类
if((commonStore.Modes & CommonModes.Server) == CommonModes.Server)
{
signInArgsTransfer.AddArgs(new List<ISignInArgs> {
LinkerMessengerEntry.GetService<MyServerSignInArgs>()
});
}
//运行
LinkerMessengerEntry.Setup();
/// <summary>
/// 客户端
/// </summary>
public sealed class MyClientSignInArgs : ISignInArgs
{
public string Name => "mySigninArgs";
/// <summary>
/// 客户端调用
/// </summary>
/// <param name="host">登入的服务器</param>
/// <param name="args">往这里面添加参数</param>
/// <returns>返回不为空则为错误信息,中断登录操作</returns>
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
args.Add("myArgs", "myArgs")
await Task.CompletedTask;
return string.Empty;
}
public async Task<string> Validate(SignInfo signInfo, SignCacheInfo cache)
{
await Task.CompletedTask;
return string.Empty;
}
}
/// <summary>
/// 服务端
/// </summary>
public sealed class MyServerSignInArgs : ISignInArgs
{
public string Name => "mySigninArgs";
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
await Task.CompletedTask;
return string.Empty;
}
/// <summary>
/// 服务端调用
/// </summary>
/// <param name="signInfo">本次登录参数</param>
/// <param name="cache">之前的登录信息,如果以前登录过的话</param>
/// <returns>返回不为空则为错误信息,登录失败</returns>
public async Task<string> Validate(SignInfo signInfo, SignCacheInfo cache)
{
if (signInfo.Args.TryGetValue("myArgs", out string arg) == false)
{
return $"myArgs validate fail";
}
await Task.CompletedTask;
return string.Empty;
}
}
```
:::

View File

@@ -0,0 +1,55 @@
---
sidebar_position: 5
---
# 8.5、中继验证
:::tip[说明]
验证通过则允许中继
```
//初始化
LinkerMessengerEntry.Initialize();
//在这里注入
LinkerMessengerEntry.AddService<MyRelayServerValidator>();
//构建
LinkerMessengerEntry.Build();
RelayServerValidatorTransfer relayServerValidatorTransfer
= LinkerMessengerEntry.GetService<RelayServerValidatorTransfer>();
//可以删除默认的一些验证,secretKey中继密钥
//relayServerValidatorTransfer.RemoveValidators(new List<string>{ "secretKey"});
ICommonStore commonStore = LinkerMessengerEntry.GetService<ICommonStore>();
//服务端则添加
if((commonStore.Modes & CommonModes.Server) == CommonModes.Server)
{
relayServerValidatorTransfer.AddArgs(new List<IRelayServerValidator> {
LinkerMessengerEntry.GetService<MyRelayServerValidator>()
});
}
//运行
LinkerMessengerEntry.Setup();
public sealed class MyRelayServerValidator : IRelayServerValidator
{
public string Name => "myRelayServerValidator";
/// <summary>
/// 验证
/// </summary>
/// <param name="relayInfo">中继信息</param>
/// <param name="fromMachine">来源客户端</param>
/// <param name="toMachine">目标客户端可能为null</param>
/// <returns>返回不为空则为错误信息,中继失败</returns>
public async Task<string> Validate(linker.messenger.relay.client.transport.RelayInfo relayInfo,
SignCacheInfo fromMachine, SignCacheInfo toMachine)
{
await Task.CompletedTask;
return string.Empty;
}
}
```
:::

View File

@@ -1,5 +1,5 @@
{
"label": "8、集成",
"label": "8、集成和二次开发",
"position": 8,
"link": {
"type": "generated-index",

View File

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 168 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -12,6 +12,7 @@ sidebar_position: 9
<th>2-5设备</th>
<th>5-10设备</th>
<th>10设备以上</th>
<th>权益</th>
</tr>
</thead>
<tbody>
@@ -21,6 +22,7 @@ sidebar_position: 9
<td>免费</td>
<td>免费</td>
<td>免费</td>
<td>/</td>
</tr>
<tr>
<td>开源集成</td>
@@ -28,28 +30,31 @@ sidebar_position: 9
<td>免费</td>
<td>免费</td>
<td>免费</td>
<td>/</td>
</tr>
<tr>
<td>安装维护/次</td>
<td>免费</td>
<td>9.9/台</td>
<td>9.9/台</td>
<td>9.9/台</td>
<td>安装配置维护/次</td>
<td>20/次</td>
<td>50/次</td>
<td>100/次</td>
<td>10/台/次</td>
<td>私有化部署、配置、BUG修复</td>
</tr>
<tr>
<td>安装维护/年</td>
<td>19.9/年</td>
<td>39.9/年</td>
<td>79.9/年</td>
<td>9.9/年/台</td>
<td>安装配置维护/年</td>
<td>99/年</td>
<td>239/年</td>
<td>399/年</td>
<td>29/台/年</td>
<td>私有化部署、配置、BUG修复、技术解答</td>
</tr>
<tr>
<td>商业集成</td>
<td colspan="4" align="center">详谈</td>
<td colspan="5" align="center">详谈,技术解答,原理讲解,二开指导</td>
</tr>
<tr>
<td>商业功能定制</td>
<td colspan="4" align="center">详谈</td>
<td>功能定制</td>
<td colspan="5" align="center">详谈,技术解答,原理讲解,二开指导</td>
</tr>
</tbody>
</table>

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@@ -103,6 +103,7 @@ namespace linker.messenger.action
public sealed class SignInArgsAction : JsonArgReplace, ISignInArgs
{
public string Name => "action";
private readonly ActionTransfer actionTransfer;
private readonly IActionClientStore actionStore;
private readonly IActionServerStore actionServerStore;

View File

@@ -113,7 +113,7 @@ namespace linker.messenger.entry
if (builded.StartOperation() == false) return;
serviceProvider = serviceCollection.BuildServiceProvider();
serviceProvider.UseMessenger().UseStoreFile().UseSerializerMemoryPack();
}
/// <summary>
/// 获取服务
@@ -129,28 +129,110 @@ namespace linker.messenger.entry
/// <summary>
/// 开始运行
/// </summary>
public static void Setup()
/// <param name="modules">排除哪些模块,默认无</param>
public static void Setup(ExcludeModule modules = ExcludeModule.None)
{
if (setuped.StartOperation() == false) return;
ICommonStore commonStore = serviceProvider.GetService<ICommonStore>();
serviceProvider.UseMessenger();
if ((modules & ExcludeModule.StoreFile) != ExcludeModule.StoreFile)
serviceProvider.UseStoreFile();
if ((modules & ExcludeModule.SerializerMemoryPack) != ExcludeModule.SerializerMemoryPack)
serviceProvider.UseSerializerMemoryPack();
if ((commonStore.Modes & CommonModes.Server) == CommonModes.Server)
{
serviceProvider.UseAccessServer().UseActionServer().UseDecenterServer().UseForwardServer().UsePcpServer().UseRelayServer().UseSForwardServer().UseSignInServer().UseSocks5Server().UseSyncServer().UseTunnelServer().UseTuntapServer().UseUpdaterServer().UseFlowServer();
if ((modules & ExcludeModule.Action) != ExcludeModule.Action)
serviceProvider.UseActionServer();
if ((modules & ExcludeModule.Forward) != ExcludeModule.Forward)
serviceProvider.UseForwardServer();
if ((modules & ExcludeModule.SForward) != ExcludeModule.SForward)
serviceProvider.UseSForwardServer();
if ((modules & ExcludeModule.Socks5) != ExcludeModule.Socks5)
serviceProvider.UseSocks5Server();
if ((modules & ExcludeModule.Tuntap) != ExcludeModule.Tuntap)
serviceProvider.UseTuntapServer();
if ((modules & ExcludeModule.Updater) != ExcludeModule.Updater)
serviceProvider.UseUpdaterServer();
serviceProvider.UseAccessServer().UseDecenterServer().UsePcpServer().UseRelayServer()
.UseSignInServer().UseSyncServer().UseTunnelServer().UseFlowServer();
serviceProvider.UseListen();
}
if ((commonStore.Modes & CommonModes.Client) == CommonModes.Client)
{
serviceProvider.UseLoggerClient().UseApiClient().UseExRoute().UseAccessClient().UseActionClient().UseDecenterClient().UseForwardClient().UsePcpClient().UseRelayClient().UseSForwardClient().UseSocks5Client().UseSyncClient().UseTunnelClient().UseTuntapClient().UseUpdaterClient().UseFlowClient();
serviceProvider.UseLoggerClient();
if ((modules & ExcludeModule.Api) != ExcludeModule.Api)
serviceProvider.UseApiClient();
if ((modules & ExcludeModule.Action) != ExcludeModule.Action)
serviceProvider.UseActionClient();
if ((modules & ExcludeModule.Forward) != ExcludeModule.Forward)
serviceProvider.UseForwardClient();
if ((modules & ExcludeModule.SForward) != ExcludeModule.SForward)
serviceProvider.UseSForwardClient();
if ((modules & ExcludeModule.Socks5) != ExcludeModule.Socks5)
serviceProvider.UseSocks5Client();
if ((modules & ExcludeModule.Tuntap) != ExcludeModule.Tuntap)
serviceProvider.UseTuntapClient();
if ((modules & ExcludeModule.Updater) != ExcludeModule.Updater)
serviceProvider.UseUpdaterClient();
serviceProvider.UseExRoute().UseAccessClient().UseDecenterClient().UsePcpClient().UseRelayClient().UseSyncClient().UseTunnelClient().UseFlowClient();
serviceProvider.UseSignInClient();
}
}
}
/// <summary>
/// 排除那些模块
/// </summary>
[Flags]
public enum ExcludeModule : uint
{
/// <summary>
/// 无
/// </summary>
None = 0,
/// <summary>
/// 端口转发
/// </summary>
Forward = 1,
/// <summary>
/// 内网穿透
/// </summary>
SForward = 2,
/// <summary>
/// socks5
/// </summary>
Socks5 = 4,
/// <summary>
/// 虚拟网卡
/// </summary>
Tuntap = 8,
/// <summary>
/// 更新检测
/// </summary>
Updater = 16,
/// <summary>
/// 文件存储库
/// </summary>
StoreFile = 32,
/// <summary>
/// MemoryPack序列化库
/// </summary>
SerializerMemoryPack = 64,
/// <summary>
/// 管理接口和网页
/// </summary>
Api = 128,
/// <summary>
/// 自定义认证
/// </summary>
Action = 256,
}
}

View File

@@ -148,6 +148,27 @@ namespace linker.messenger.forward
Payload = serializer.Serialize(info)
});
}
/// <summary>
/// 检测
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public async Task<bool> Test(ApiControllerParamsInfo param)
{
if (param.Content == signInClientStore.Id)
{
forwardTransfer.SubscribeTest();
return true;
}
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)ForwardMessengerIds.TestClientForward,
Payload = serializer.Serialize(param.Content)
});
return true;
}
}
public sealed class ForwardListInfo

View File

@@ -86,6 +86,22 @@ namespace linker.messenger.forward
}
}
[MessengerId((ushort)ForwardMessengerIds.TestClientForward)]
public async Task TestClientForward(IConnection connection)
{
string machineid = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(machineid, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
{
uint requestid = connection.ReceiveRequestWrap.RequestId;
await sender.SendOnly(new MessageRequestWrap
{
Connection = cacheTo.Connection,
MessengerId = (ushort)ForwardMessengerIds.TestClientForward
});
}
}
}
public sealed class ForwardClientMessenger : IMessenger
@@ -125,7 +141,14 @@ namespace linker.messenger.forward
uint id = serializer.Deserialize<uint>(connection.ReceiveRequestWrap.Payload.Span);
forwardTransfer.Remove(id);
}
[MessengerId((ushort)ForwardMessengerIds.TestClient)]
public void TestClient(IConnection connection)
{
forwardTransfer.SubscribeTest();
}
}
}

View File

@@ -2,6 +2,7 @@
using linker.libs.extends;
using linker.messenger.forward.proxy;
using linker.messenger.signin;
using System.Net.Sockets;
namespace linker.messenger.forward
{
@@ -200,5 +201,43 @@ namespace linker.messenger.forward
forwardClientStore.Confirm();
return true;
}
private readonly OperatingManager testing = new OperatingManager();
public void SubscribeTest()
{
if (testing.StartOperation() == false)
{
return;
}
IEnumerable<Task<bool>> tasks = Get().Select(Connect);
Task.WhenAll(tasks).ContinueWith((result) =>
{
testing.StopOperation();
OnChanged();
});
async Task<bool> Connect(ForwardInfo info)
{
Socket socket = new Socket(info.TargetEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
await socket.ConnectAsync(info.TargetEP).WaitAsync(TimeSpan.FromMilliseconds(500));
info.TargetMsg = string.Empty;
return true;
}
catch (Exception ex)
{
info.TargetMsg = ex.Message;
}
finally
{
socket.SafeClose();
}
return false;
}
}
}
}

View File

@@ -40,6 +40,13 @@ namespace linker.messenger.pcp
}
}
}
/// <summary>
/// 连接
/// </summary>
/// <param name="remoteMachineId">目标id</param>
/// <param name="transactionId">事务ID属于什么事务的端口转发还是虚拟网卡</param>
/// <param name="denyProtocols">不想使用哪些打洞协议</param>
/// <returns></returns>
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineId, string transactionId, TunnelProtocolType denyProtocols)
{
await Task.CompletedTask;

View File

@@ -8,6 +8,7 @@ namespace linker.messenger.relay.server.validator
/// </summary>
public interface IRelayServerValidator
{
public string Name { get; }
/// <summary>
/// 验证
/// </summary>

View File

@@ -4,12 +4,15 @@ namespace linker.messenger.relay.server.validator
{
public sealed class RelayServerValidatorSecretKey : IRelayServerValidator
{
public string Name => "secretKey";
private readonly IRelayServerStore relayServerStore;
public RelayServerValidatorSecretKey(IRelayServerStore relayServerStore)
{
this.relayServerStore = relayServerStore;
}
public async Task<string> Validate(linker.messenger.relay.client.transport.RelayInfo relayInfo, SignCacheInfo fromMachine, SignCacheInfo toMachine)
{
if (relayInfo.SecretKey != relayServerStore.SecretKey)

View File

@@ -26,6 +26,19 @@ namespace linker.messenger.relay.server.validator
validators = validators.Concat(list).Distinct(new RelayServerValidatorEqualityComparer()).ToList();
LoggerHelper.Instance.Info($"load relay server validator :{string.Join(",", list.Select(c => c.GetType().Name))}");
}
/// <summary>
/// 删除一些验证实现类
/// </summary>
/// <param name="names"></param>
public void RemoveValidators(List<string> names)
{
foreach (string name in names)
{
IRelayServerValidator item = validators.FirstOrDefault(c => c.Name == name);
if (item != null)
validators.Remove(item);
}
}
/// <summary>
/// 验证

View File

@@ -154,7 +154,7 @@ namespace linker.messenger.sforward.client
{
if (param.Content == signInClientStore.Id)
{
forwardTransfer.TestLocal();
forwardTransfer.SubscribeTest();
return true;
}
await messengerSender.SendOnly(new MessageRequestWrap

View File

@@ -19,7 +19,7 @@ namespace linker.messenger.sforward.client
private readonly ISerializer serializer;
private readonly NumberSpaceUInt32 ns = new NumberSpaceUInt32();
private readonly OperatingManager operatingManager = new OperatingManager();
public SForwardClientTransfer(SignInClientState signInClientState, IMessengerSender messengerSender, ISignInClientStore signInClientStore, ISForwardClientStore sForwardClientStore, ISerializer serializer)
{
@@ -214,49 +214,39 @@ namespace linker.messenger.sforward.client
return arr.Length == 2 && int.TryParse(arr[0], out min) && int.TryParse(arr[1], out max);
}
/// <summary>
/// 测试本机服务
/// </summary>
public void TestLocal()
private readonly OperatingManager testing = new OperatingManager();
public void SubscribeTest()
{
if (operatingManager.StartOperation() == false) return;
TimerHelper.Async(async () =>
if (testing.StartOperation() == false)
{
try
{
var results = sForwardClientStore.Get().Select(c => c.LocalEP).Select(ConnectAsync);
await Task.Delay(200).ConfigureAwait(false);
return;
}
foreach (var item in results.Select(c => c.Result))
{
var forward = sForwardClientStore.Get().FirstOrDefault(c => c.LocalEP.Equals(item.Item1));
if (forward != null)
{
forward.LocalMsg = item.Item2;
}
}
OnChanged();
}
catch (Exception)
{
}
operatingManager.StopOperation();
IEnumerable<Task<bool>> tasks = sForwardClientStore.Get().Select(Connect);
Task.WhenAll(tasks).ContinueWith((result) =>
{
testing.StopOperation();
OnChanged();
});
async Task<(IPEndPoint, string)> ConnectAsync(IPEndPoint ep)
async Task<bool> Connect(SForwardInfo info)
{
Socket socket = new Socket(info.LocalEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
using Socket socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
socket.SafeClose();
return (ep, string.Empty);
await socket.ConnectAsync(info.LocalEP).WaitAsync(TimeSpan.FromMilliseconds(500));
info.LocalMsg = string.Empty;
return true;
}
catch (Exception ex)
{
return (ep, ex.Message);
info.LocalMsg = ex.Message;
}
finally
{
socket.SafeClose();
}
return false;
}
}
}

View File

@@ -416,13 +416,13 @@ namespace linker.plugins.sforward.messenger
sForwardTransfer.Remove(id);
}
// <summary>
/// 删除
/// 测试
/// </summary>
/// <param name="connection"></param>
[MessengerId((ushort)SForwardMessengerIds.TestClient)]
public void TestClient(IConnection connection)
{
sForwardTransfer.TestLocal();
sForwardTransfer.SubscribeTest();
}

View File

@@ -5,6 +5,7 @@
/// </summary>
public interface ISignInArgs
{
public string Name { get; }
/// <summary>
/// 添加参数,客户端调用
/// </summary>

View File

@@ -5,11 +5,16 @@
/// </summary>
public sealed class SignInArgsGroupPasswordClient : ISignInArgs
{
public string Name => "group";
private readonly ISignInClientStore signInClientStore;
public SignInArgsGroupPasswordClient(ISignInClientStore signInClientStore)
{
this.signInClientStore = signInClientStore;
}
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
args.TryAdd("signin-gpwd", signInClientStore.Group.Password);
@@ -29,6 +34,7 @@
/// </summary>
public sealed class SignInArgsGroupPasswordServer : ISignInArgs
{
public string Name => "group";
public SignInArgsGroupPasswordServer()
{
}

View File

@@ -1,6 +1,4 @@
using linker.libs;
using linker.messenger.signin;
using linker.messenger.signin.args;
namespace linker.messenger.signin.args
{
@@ -9,6 +7,7 @@ namespace linker.messenger.signin.args
/// </summary>
public sealed class SignInArgsMachineKeyClient : ISignInArgs
{
public string Name => "machineId";
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
string machineKey = SystemIdHelper.GetSystemId();
@@ -38,6 +37,7 @@ namespace linker.messenger.signin.args
/// </summary>
public sealed class SignInArgsMachineKeyServer : ISignInArgs
{
public string Name => "machineId";
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
await Task.CompletedTask;

View File

@@ -5,6 +5,8 @@
/// </summary>
public sealed class SignInArgsSecretKeyClient : ISignInArgs
{
public string Name => "secretKey";
private readonly ISignInClientStore signInClientStore;
public SignInArgsSecretKeyClient(ISignInClientStore signInClientStore)
{
@@ -29,6 +31,7 @@
/// </summary>
public sealed class SignInArgsSecretKeyServer : ISignInArgs
{
public string Name => "secretKey";
private readonly ISignInServerStore signInServerStore;
public SignInArgsSecretKeyServer(ISignInServerStore signInServerStore)
{

View File

@@ -20,6 +20,20 @@
startups = startups.Concat(list).Distinct().ToList();
}
/// <summary>
/// 删除实现类
/// </summary>
/// <param name="names"></param>
public void RemoveArgs(List<string> names)
{
foreach (string name in names)
{
ISignInArgs item = startups.FirstOrDefault(c => c.Name == name);
if (item != null)
startups.Remove(item);
}
}
/// <summary>
/// 客户端调用
/// </summary>

View File

@@ -1,6 +1,4 @@
using linker.libs;
using linker.messenger.signin;
using linker.messenger.signin.args;
namespace linker.messenger.signin.args
{
@@ -9,6 +7,7 @@ namespace linker.messenger.signin.args
/// </summary>
public sealed class SignInArgsVersionClient : ISignInArgs
{
public string Name => "version";
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
args.TryAdd("version", VersionHelper.version);
@@ -30,6 +29,13 @@ namespace linker.messenger.signin.args
/// </summary>
public sealed class SignInArgsVersionServer : ISignInArgs
{
public string Name => "version";
/// <summary>
/// 客户端调用
/// </summary>
/// <param name="host"></param>
/// <param name="args"></param>
/// <returns></returns>
public async Task<string> Invoke(string host, Dictionary<string, string> args)
{
await Task.CompletedTask;
@@ -37,7 +43,7 @@ namespace linker.messenger.signin.args
}
/// <summary>
/// 验证参数
/// 服务端调用
/// </summary>
/// <param name="signInfo">新登录参数</param>
/// <param name="cache">之前的登录信息</param>

View File

@@ -42,7 +42,7 @@ namespace linker.messenger.tuntap
tuntapTransfer.OnShutdownSuccess += () => { DeleteForward(); tuntapConfigTransfer.SetRunning(false); };
//配置有更新,去同步一下
tuntapConfigTransfer.OnUpdate += tuntapDecenter.Refresh;
tuntapConfigTransfer.OnUpdate += () => { _ = CheckDevice(); tuntapDecenter.Refresh(); };
//收到新的信息,添加一下路由
tuntapDecenter.OnChangeBefore += DelRoute;
@@ -60,22 +60,28 @@ namespace linker.messenger.tuntap
CheckDeviceTask();
}
private void CheckDeviceTask()
{
ulong configVersion = 0;
TimerHelper.SetInterval(async () =>
{
bool restart =
(tuntapConfigTransfer.Version.Eq(configVersion, out ulong _version) == false || await tuntapTransfer.CheckAvailable() == false)
&& tuntapConfigTransfer.Running && tuntapTransfer.Status != TuntapStatus.Running && tuntapTransfer.Status != TuntapStatus.Operating;
if (restart)
{
configVersion = _version;
await RetstartDevice();
}
await CheckDevice();
return true;
}, () => 30000);
}
ulong configVersion = 0;
private async Task CheckDevice()
{
bool restart =
(tuntapConfigTransfer.Version.Eq(configVersion, out ulong _version) == false || await tuntapTransfer.CheckAvailable() == false)
&& tuntapConfigTransfer.Running && tuntapTransfer.Status != TuntapStatus.Operating;
if (restart)
{
configVersion = _version;
await RetstartDevice();
}
}
private TuntapInfo GetCurrentInfo()
{
return new TuntapInfo
@@ -188,9 +194,8 @@ namespace linker.messenger.tuntap
return infos
.Where(c => c.MachineId != signInClientStore.Id)
.OrderByDescending(c => c.Status)
.OrderBy(c => c.IP, new IPAddressComparer())
.OrderByDescending(c => c.Status)
.Select(c =>
{
var lans = c.Lans.Where(c => c.Disabled == false && c.IP.Equals(IPAddress.Any) == false).Where(c =>

View File

@@ -64,7 +64,7 @@ namespace linker.messenger.tuntap
await LeaseIP();
SetGroupIP();
if ((ip.Equals(Info.IP) == false || prefixLength != Info.PrefixLength) && Info.Running)
if ((ip.Equals(Info.IP) == false || prefixLength != Info.PrefixLength))
{
Version.Add();
}
@@ -77,19 +77,7 @@ namespace linker.messenger.tuntap
/// </summary>
public void RefreshIP()
{
TimerHelper.Async(async () =>
{
IPAddress oldIP = Info.IP;
byte prefixLength = Info.PrefixLength;
await RefreshIPASync();
if ((oldIP.Equals(Info.IP) == false || prefixLength != Info.PrefixLength) && Info.Running)
{
Version.Add();
}
OnUpdate();
});
_ = RefreshIPASync();
}
/// <summary>
/// 刷新IP不会触发OnChanged
@@ -97,9 +85,18 @@ namespace linker.messenger.tuntap
/// <returns></returns>
public async Task RefreshIPASync()
{
IPAddress oldIP = Info.IP;
byte prefixLength = Info.PrefixLength;
LoadGroupIP();
await LeaseIP();
SetGroupIP();
if ((oldIP.Equals(Info.IP) == false || prefixLength != Info.PrefixLength) && Info.Running)
{
Version.Add();
}
OnUpdate();
}
private async Task LeaseIP()

View File

@@ -67,7 +67,7 @@ namespace linker.messenger.tuntap
public async Task SubscribeForwardTest(List<TuntapForwardTestInfo> list)
{
await Task.WhenAll(list.Select(async c =>
await Task.WhenAll(list.Where(c=>c.ConnectAddr.Equals(IPAddress.Any)==false && c.ConnectPort > 0 && c.ListenPort > 0).Select(async c =>
{
try
{

View File

@@ -8,7 +8,8 @@ using System.Buffers;
using linker.messenger.relay.client;
using linker.messenger.signin;
using linker.messenger.pcp;
using System;
using System.Net;
using System.Reflection.PortableExecutable;
namespace linker.messenger.tuntap
{
@@ -113,6 +114,7 @@ namespace linker.messenger.tuntap
}, ip);
return;
}
await connection.SendAsync(packet.Packet);
}
@@ -177,8 +179,10 @@ namespace linker.messenger.tuntap
{
string machineId = item.Value[0];
ip2MachineDic.AddOrUpdate(item.Key, machineId, (a, b) => machineId);
if (ipConnections.TryGetValue(item.Key, out ITunnelConnection connection) && item.Value.Count > 0 && machineId != connection.RemoteMachineId)
}
foreach (var ip in ips)
{
foreach (var item in ipConnections.Where(c=>(c.Key & ip.NetWork)==ip.NetWork && c.Value.RemoteMachineId != ip.MachineId).ToList())
{
ipConnections.TryRemove(item.Key, out _);
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.187" ProductVersion="0.0.0.187" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.188" ProductVersion="0.0.0.188" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>

Binary file not shown.

View File

@@ -1 +1 @@
.table-sort th[data-v-4b2df38c]{border-bottom:0}.dropdown[data-v-6638f97d]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-6638f97d]{vertical-align:middle}.dropdown .badge[data-v-6638f97d]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}a[data-v-6653ef00]{color:#666;text-decoration:underline}a.green[data-v-6653ef00]{color:green;font-weight:700}a.download[data-v-6653ef00]{margin-left:.6rem}a.download .el-icon[data-v-6653ef00]{vertical-align:middle;font-weight:700;margin-left:.3rem}a.download .el-icon.loading[data-v-6653ef00]{animation:loading-6653ef00 1s linear infinite}a.download+a.download[data-v-6653ef00]{margin-left:.2rem}@keyframes loading-6653ef00{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}img.system[data-v-ffd0d512]{height:1.6rem;vertical-align:middle;margin-right:.4rem}.self[data-v-ffd0d512]{color:#d400ff}.self .el-icon[data-v-ffd0d512]{vertical-align:text-bottom}.ipaddress span[data-v-5db71b03]{vertical-align:middle}.el-input[data-v-5db71b03]{width:12rem;margin-right:.6rem}.el-col[data-v-5d52ca48]{text-align:left}span.point[data-v-39aee530]{width:.8rem;height:.8rem;border-radius:50%;display:inline-block;vertical-align:middle;margin:-.2rem .3rem 0 -1.3rem;background-color:#eee;border:1px solid #ddd}span.point.p2p[data-v-39aee530]{background-color:#01c901;border:1px solid #049538}span.point.relay[data-v-39aee530]{background-color:#e3e811;border:1px solid #b3c410}span.point.node[data-v-39aee530]{background-color:#09dda9;border:1px solid #0cac90}.el-icon.loading[data-v-f8059b00],a.loading[data-v-f8059b00]{vertical-align:middle;font-weight:700;animation:loading-f8059b00 1s linear infinite}.el-switch.is-disabled[data-v-f8059b00]{opacity:1}.el-input[data-v-f8059b00]{width:8rem}.delay[data-v-f8059b00]{position:absolute;right:0;bottom:0;line-height:normal}.switch-btn[data-v-f8059b00]{font-size:1.5rem}@keyframes loading-f8059b00{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.wrap[data-v-786fe646]{padding-right:1rem}.remark[data-v-786fe646]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wrap[data-v-4abaaeaf]{padding-right:1rem}.el-switch.is-disabled[data-v-34275839]{opacity:1}.upgrade-wrap[data-v-34275839]{border:1px solid #ddd;margin-bottom:2rem;padding:0 0 1rem 0}.el-switch.is-disabled[data-v-4a28804a]{opacity:1}.calc span[data-v-4a28804a]{display:inline-block}.calc span.label[data-v-4a28804a]{width:6rem}.el-icon.loading[data-v-d37c5992],a.loading[data-v-d37c5992]{vertical-align:middle;font-weight:700;animation:loading-d37c5992 1s linear infinite}.el-switch.is-disabled[data-v-d37c5992]{opacity:1}.el-input[data-v-d37c5992]{width:8rem}.switch-btn[data-v-d37c5992]{font-size:1.5rem}@keyframes loading-d37c5992{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-switch.is-disabled[data-v-022e3781]{opacity:1}.upgrade-wrap[data-v-022e3781]{border:1px solid #ddd;margin-bottom:2rem;padding:1rem 0 1rem 0}.lan-item[data-v-022e3781]{margin-bottom:0}.el-switch.is-disabled[data-v-49e16cac]{opacity:1}.green[data-v-49e16cac]{font-weight:700}.el-switch.is-disabled[data-v-6ea047f9]{opacity:1}a[data-v-6e9936ec]{text-decoration:underline}a+a[data-v-6e9936ec]{margin-left:1rem}a.green[data-v-6e9936ec]{font-weight:700}.head[data-v-15b05a01]{padding-bottom:1rem}.green[data-v-15b05a01]{color:green;font-weight:700}.error[data-v-15b05a01]{font-weight:700}.error .el-icon[data-v-15b05a01]{vertical-align:text-bottom}.head[data-v-7eb8e7cc]{padding-bottom:1rem}.error[data-v-7eb8e7cc]{font-weight:700}.error .el-icon[data-v-7eb8e7cc]{vertical-align:text-bottom}.head[data-v-7891b902]{padding-bottom:1rem}.table-sort.el-table th.el-table__cell.is-leaf{border-bottom:0}.table-sort.el-table .el-table__inner-wrapper:before{height:0}.home-list-wrap[data-v-3d1c480c]{padding:1rem}.home-list-wrap .page[data-v-3d1c480c]{padding-top:1rem}.home-list-wrap .page-wrap[data-v-3d1c480c]{display:inline-block}
.table-sort th[data-v-4b2df38c]{border-bottom:0}.dropdown[data-v-6638f97d]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-6638f97d]{vertical-align:middle}.dropdown .badge[data-v-6638f97d]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}a[data-v-6653ef00]{color:#666;text-decoration:underline}a.green[data-v-6653ef00]{color:green;font-weight:700}a.download[data-v-6653ef00]{margin-left:.6rem}a.download .el-icon[data-v-6653ef00]{vertical-align:middle;font-weight:700;margin-left:.3rem}a.download .el-icon.loading[data-v-6653ef00]{animation:loading-6653ef00 1s linear infinite}a.download+a.download[data-v-6653ef00]{margin-left:.2rem}@keyframes loading-6653ef00{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}img.system[data-v-ffd0d512]{height:1.6rem;vertical-align:middle;margin-right:.4rem}.self[data-v-ffd0d512]{color:#d400ff}.self .el-icon[data-v-ffd0d512]{vertical-align:text-bottom}.ipaddress span[data-v-5db71b03]{vertical-align:middle}.el-input[data-v-5db71b03]{width:12rem;margin-right:.6rem}.el-col[data-v-7a697708]{text-align:left}span.point[data-v-39aee530]{width:.8rem;height:.8rem;border-radius:50%;display:inline-block;vertical-align:middle;margin:-.2rem .3rem 0 -1.3rem;background-color:#eee;border:1px solid #ddd}span.point.p2p[data-v-39aee530]{background-color:#01c901;border:1px solid #049538}span.point.relay[data-v-39aee530]{background-color:#e3e811;border:1px solid #b3c410}span.point.node[data-v-39aee530]{background-color:#09dda9;border:1px solid #0cac90}.el-icon.loading[data-v-f8059b00],a.loading[data-v-f8059b00]{vertical-align:middle;font-weight:700;animation:loading-f8059b00 1s linear infinite}.el-switch.is-disabled[data-v-f8059b00]{opacity:1}.el-input[data-v-f8059b00]{width:8rem}.delay[data-v-f8059b00]{position:absolute;right:0;bottom:0;line-height:normal}.switch-btn[data-v-f8059b00]{font-size:1.5rem}@keyframes loading-f8059b00{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.wrap[data-v-786fe646]{padding-right:1rem}.remark[data-v-786fe646]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wrap[data-v-4abaaeaf]{padding-right:1rem}.el-switch.is-disabled[data-v-34275839]{opacity:1}.upgrade-wrap[data-v-34275839]{border:1px solid #ddd;margin-bottom:2rem;padding:0 0 1rem 0}.el-switch.is-disabled[data-v-4a28804a]{opacity:1}.calc span[data-v-4a28804a]{display:inline-block}.calc span.label[data-v-4a28804a]{width:6rem}.el-icon.loading[data-v-d37c5992],a.loading[data-v-d37c5992]{vertical-align:middle;font-weight:700;animation:loading-d37c5992 1s linear infinite}.el-switch.is-disabled[data-v-d37c5992]{opacity:1}.el-input[data-v-d37c5992]{width:8rem}.switch-btn[data-v-d37c5992]{font-size:1.5rem}@keyframes loading-d37c5992{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-switch.is-disabled[data-v-022e3781]{opacity:1}.upgrade-wrap[data-v-022e3781]{border:1px solid #ddd;margin-bottom:2rem;padding:1rem 0 1rem 0}.lan-item[data-v-022e3781]{margin-bottom:0}.el-switch.is-disabled[data-v-49e16cac]{opacity:1}.green[data-v-49e16cac]{font-weight:700}.el-switch.is-disabled[data-v-6ea047f9]{opacity:1}a[data-v-6e9936ec]{text-decoration:underline}a+a[data-v-6e9936ec]{margin-left:1rem}a.green[data-v-6e9936ec]{font-weight:700}.head[data-v-15b05a01]{padding-bottom:1rem}.green[data-v-15b05a01]{color:green;font-weight:700}.error[data-v-15b05a01]{font-weight:700}.error .el-icon[data-v-15b05a01]{vertical-align:text-bottom}.head[data-v-7eb8e7cc]{padding-bottom:1rem}.error[data-v-7eb8e7cc]{font-weight:700}.error .el-icon[data-v-7eb8e7cc]{vertical-align:text-bottom}.head[data-v-7891b902]{padding-bottom:1rem}.table-sort.el-table th.el-table__cell.is-leaf{border-bottom:0}.table-sort.el-table .el-table__inner-wrapper:before{height:0}.home-list-wrap[data-v-3d1c480c]{padding:1rem}.home-list-wrap .page[data-v-3d1c480c]{padding-top:1rem}.home-list-wrap .page-wrap[data-v-3d1c480c]{display:inline-block}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.action-wrap[data-v-3cb5be52]{font-size:1.3rem;padding:1.5rem}

View File

@@ -0,0 +1 @@
.action-wrap[data-v-7e144fd0]{font-size:1.3rem;padding:1.5rem}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.delay[data-v-3a883663]{margin-left:3rem}.servers-wrap[data-v-57813473]{padding:1rem;font-size:1.3rem;color:#555}.servers-wrap a[data-v-57813473]{color:#333}.el-checkbox[data-v-57813473]{vertical-align:middle;margin-right:1rem}

View File

@@ -1 +0,0 @@
.delay[data-v-3a883663]{margin-left:3rem}.servers-wrap[data-v-11926c68]{padding:1rem;font-size:1.3rem;color:#555}.servers-wrap a[data-v-11926c68]{color:#333}.el-checkbox[data-v-11926c68]{vertical-align:middle;margin-right:1rem}

View File

@@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><script defer="defer" src="js/chunk-vendors.7b81ea90.js"></script><script defer="defer" src="js/app.1a3b60a6.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.1dca501b.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><script defer="defer" src="js/chunk-vendors.7b81ea90.js"></script><script defer="defer" src="js/app.d49dc293.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.1dca501b.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[402],{402:function(e,t,n){n.r(t),n.d(t,{default:function(){return h}});var r=n(6768);const o={class:"action-wrap"},s={class:"t-c"};function a(e,t,n,a,l,c){const i=(0,r.g2)("el-input"),u=(0,r.g2)("el-button"),d=(0,r.g2)("el-card");return(0,r.uX)(),(0,r.CE)("div",o,[(0,r.bF)(d,{shadow:"never"},{header:(0,r.k6)((()=>[(0,r.eW)("设置定义验证的静态Json参数")])),footer:(0,r.k6)((()=>[(0,r.Lk)("div",s,[(0,r.bF)(u,{type:"success",onClick:a.handleSave},{default:(0,r.k6)((()=>[(0,r.eW)("确定更改")])),_:1},8,["onClick"])])])),default:(0,r.k6)((()=>[(0,r.Lk)("div",null,[(0,r.bF)(i,{modelValue:a.state.list,"onUpdate:modelValue":t[0]||(t[0]=e=>a.state.list=e),rows:10,type:"textarea",resize:"none",onChange:a.handleSave},null,8,["modelValue","onChange"])])])),_:1})])}var l=n(4);const c=e=>(0,l.zG)("action/SetServerArgs",e);var i=n(3830),u=n(1219),d=n(144),v={setup(e){const t=(0,i.B)(),n=(0,d.Kh)({list:t.value.config.Client.Action.Args[t.value.config.Client.Server.Host]||""}),r=()=>{try{if(n.list&&"object"!=typeof JSON.parse(n.list))return void u.nk.error("Json格式错误")}catch(r){return void u.nk.error("Json格式错误")}const e={};e[t.value.config.Client.Server.Host]=n.list,c(e).then((()=>{u.nk.success("已操作")})).catch((e=>{console.log(e),u.nk.error("操作失败")}))};return{state:n,handleSave:r}}},k=n(1241);const f=(0,k.A)(v,[["render",a],["__scopeId","data-v-3cb5be52"]]);var h=f}}]);

View File

@@ -0,0 +1 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[57],{2057:function(e,n,t){t.r(n),t.d(n,{default:function(){return g}});var r=t(6768);const o={class:"action-wrap"},s={class:"t-c"};function a(e,n,t,a,l,c){const i=(0,r.g2)("el-input"),u=(0,r.g2)("el-button"),d=(0,r.g2)("el-card");return(0,r.uX)(),(0,r.CE)("div",o,[(0,r.bF)(d,{shadow:"never"},{header:(0,r.k6)((()=>[(0,r.eW)("设置定义验证的静态Json参数")])),footer:(0,r.k6)((()=>[(0,r.Lk)("div",s,[(0,r.bF)(u,{type:"success",onClick:a.handleSave},{default:(0,r.k6)((()=>[(0,r.eW)("确定更改")])),_:1},8,["onClick"])])])),default:(0,r.k6)((()=>[(0,r.Lk)("div",null,[(0,r.bF)(i,{modelValue:a.state.list,"onUpdate:modelValue":n[0]||(n[0]=e=>a.state.list=e),rows:10,type:"textarea",resize:"none",onChange:a.handleSave},null,8,["modelValue","onChange"])])])),_:1})])}var l=t(4);const c=e=>(0,l.zG)("action/SetServerArgs",e);var i=t(3830),u=t(1219),d=t(144),v={setup(e){const n=(0,i.B)(),t=(0,d.Kh)({list:n.value.config.Client.Action.Args[n.value.config.Client.Server.Host]||""}),r=()=>{try{if(t.list&&"object"!=typeof JSON.parse(t.list))return void u.nk.error("Json格式错误")}catch(r){return void u.nk.error("Json格式错误")}const e=JSON.parse(JSON.stringify(n.value.config.Client.Action.Args));e[n.value.config.Client.Server.Host]=t.list,c(e).then((()=>{u.nk.success("已操作")})).catch((e=>{console.log(e),u.nk.error("操作失败")}))};return{state:t,handleSave:r}}},k=t(1241);const f=(0,k.A)(v,[["render",a],["__scopeId","data-v-7e144fd0"]]);var g=f}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[966],{673:function(e,a,t){t.r(a),t.d(a,{default:function(){return M}});var n=t(6768);const l={class:"net-wrap app-wrap"},s={class:"inner absolute flex flex-column flex-nowrap"},r={class:"head"},i={class:"body flex-1 relative"},u={class:"status"};function c(e,a,t,c,d,o){const g=(0,n.g2)("Head"),p=(0,n.g2)("List"),v=(0,n.g2)("Status");return(0,n.uX)(),(0,n.CE)("div",l,[(0,n.Lk)("div",s,[(0,n.Lk)("div",r,[(0,n.bF)(g)]),(0,n.Lk)("div",i,[(0,n.bF)(p)]),(0,n.Lk)("div",u,[(0,n.bF)(v,{config:!1})])])])}t(4114);const d=e=>((0,n.Qi)("data-v-3bb95ac8"),e=e(),(0,n.jt)(),e),o={class:"head-wrap"},g={class:"tools flex"},p=d((()=>(0,n.Lk)("span",{class:"label"},"服务器 ",-1))),v=d((()=>(0,n.Lk)("span",{class:"flex-1"},null,-1))),h={style:{"margin-left":"1rem"}};function f(e,a,t,l,s,r){const i=(0,n.g2)("el-option"),u=(0,n.g2)("el-select"),c=(0,n.g2)("Refresh"),d=(0,n.g2)("el-icon"),f=(0,n.g2)("el-button"),k=(0,n.g2)("Background");return(0,n.uX)(),(0,n.CE)("div",o,[(0,n.Lk)("div",g,[p,(0,n.bF)(u,{modelValue:l.state.server,"onUpdate:modelValue":a[0]||(a[0]=e=>l.state.server=e),placeholder:"服务器",style:{width:"16rem"},size:"small"},{default:(0,n.k6)((()=>[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(l.state.servers,(e=>((0,n.uX)(),(0,n.Wv)(i,{key:e.Host,label:e.Name,value:e.Host},null,8,["label","value"])))),128))])),_:1},8,["modelValue"]),v,(0,n.bF)(f,{size:"small",onClick:l.handleRefresh},{default:(0,n.k6)((()=>[(0,n.eW)(" 刷新(F5)"),(0,n.bF)(d,null,{default:(0,n.k6)((()=>[(0,n.bF)(c)])),_:1})])),_:1},8,["onClick"]),(0,n.Lk)("div",h,[(0,n.bF)(k,{name:"net"})])])])}var k=t(3830),b=t(144),m=t(7477),C=t(5096),L={components:{Edit:m.ffu,Refresh:m.C42,Background:C.A},setup(){const e=(0,k.B)(),a=(0,b.Kh)({server:"linker.snltty.com:1802",servers:[]});(0,n.wB)((()=>e.value.config.Client.Servers),(()=>{a.servers=(e.value.config.Client.Servers||[]).slice(0,1),a.server=e.value.config.Client.Server.Host}));const t=()=>{window.location.reload()};return{state:a,handleRefresh:t}}},w=t(1241);const S=(0,w.A)(L,[["render",f],["__scopeId","data-v-3bb95ac8"]]);var _=S;const F=e=>((0,n.Qi)("data-v-b6ab4f06"),e=e(),(0,n.jt)(),e),x={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},I=F((()=>(0,n.Lk)("div",{class:"flex-1"},null,-1))),T={class:"tuntap"},A={class:"page t-c"},B={class:"page-wrap t-c"};function P(e,a,t,l,s,r){const i=(0,n.g2)("DeviceName"),u=(0,n.g2)("UpdaterBtn"),c=(0,n.g2)("TuntapShow"),d=(0,n.g2)("el-pagination");return(0,n.uX)(),(0,n.CE)("div",x,[(0,n.Lk)("div",z,[(0,n.Lk)("ul",null,[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(l.devices.page.List,((e,a)=>((0,n.uX)(),(0,n.CE)("li",{key:a},[(0,n.Lk)("dl",null,[(0,n.Lk)("dt",E,[(0,n.Lk)("div",null,[(0,n.bF)(i,{item:e},null,8,["item"])]),I,(0,n.Lk)("div",null,[(0,n.bF)(u,{config:!1,item:e},null,8,["item"])])]),(0,n.Lk)("dd",T,[l.tuntap.list[e.MachineId]?((0,n.uX)(),(0,n.Wv)(c,{key:0,item:e},null,8,["item"])):(0,n.Q3)("",!0)])])])))),128))])]),(0,n.Lk)("div",A,[(0,n.Lk)("div",B,[(0,n.bF)(d,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:l.devices.page.Count,"page-size":l.devices.page.Request.Size,"current-page":l.devices.page.Request.Page,onCurrentChange:l.handlePageChange,onSizeChange:l.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var y=t(8104),X=t(7985),R=t(9383),D=t(167),U=t(3347),H=t(2950),N={components:{StarFilled:m.BQ2,UpdaterBtn:D.A,DeviceName:U.A,TuntapShow:H.A},setup(e){(0,k.B)();const a=(0,b.Kh)({}),{devices:t,machineId:l,_getSignList:s,_getSignList1:r,handleDeviceEdit:i,handlePageChange:u,handlePageSizeChange:c,handleDel:d,clearDevicesTimeout:o}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:m}=(0,y.O)(),{_getUpdater:C,_subscribeUpdater:L,clearUpdaterTimeout:w}=(0,R.d)();return(0,n.sV)((()=>{u(),v(),s(),r(),p(),C(),L()})),(0,n.hi)((()=>{o(),h(),w()})),{state:a,devices:t,machineId:l,handlePageChange:u,handlePageSizeChange:c,tuntap:g}}};const V=(0,w.A)(N,[["render",P],["__scopeId","data-v-b6ab4f06"]]);var K=V,Q=t(3269),W=t(1387),j={components:{Head:_,List:K,Status:Q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,k.B)(),a=(0,W.rd)();return(0,n.sV)((()=>{0==e.value.hasAccess("NetManager")&&a.push({name:"NoPermission"})})),{}}};const q=(0,w.A)(j,[["render",c],["__scopeId","data-v-6a3f3b43"]]);var M=q}}]);
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[836],{673:function(e,a,t){t.r(a),t.d(a,{default:function(){return M}});var n=t(6768);const l={class:"net-wrap app-wrap"},s={class:"inner absolute flex flex-column flex-nowrap"},r={class:"head"},i={class:"body flex-1 relative"},u={class:"status"};function c(e,a,t,c,d,o){const g=(0,n.g2)("Head"),p=(0,n.g2)("List"),v=(0,n.g2)("Status");return(0,n.uX)(),(0,n.CE)("div",l,[(0,n.Lk)("div",s,[(0,n.Lk)("div",r,[(0,n.bF)(g)]),(0,n.Lk)("div",i,[(0,n.bF)(p)]),(0,n.Lk)("div",u,[(0,n.bF)(v,{config:!1})])])])}t(4114);const d=e=>((0,n.Qi)("data-v-3bb95ac8"),e=e(),(0,n.jt)(),e),o={class:"head-wrap"},g={class:"tools flex"},p=d((()=>(0,n.Lk)("span",{class:"label"},"服务器 ",-1))),v=d((()=>(0,n.Lk)("span",{class:"flex-1"},null,-1))),h={style:{"margin-left":"1rem"}};function f(e,a,t,l,s,r){const i=(0,n.g2)("el-option"),u=(0,n.g2)("el-select"),c=(0,n.g2)("Refresh"),d=(0,n.g2)("el-icon"),f=(0,n.g2)("el-button"),k=(0,n.g2)("Background");return(0,n.uX)(),(0,n.CE)("div",o,[(0,n.Lk)("div",g,[p,(0,n.bF)(u,{modelValue:l.state.server,"onUpdate:modelValue":a[0]||(a[0]=e=>l.state.server=e),placeholder:"服务器",style:{width:"16rem"},size:"small"},{default:(0,n.k6)((()=>[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(l.state.servers,(e=>((0,n.uX)(),(0,n.Wv)(i,{key:e.Host,label:e.Name,value:e.Host},null,8,["label","value"])))),128))])),_:1},8,["modelValue"]),v,(0,n.bF)(f,{size:"small",onClick:l.handleRefresh},{default:(0,n.k6)((()=>[(0,n.eW)(" 刷新(F5)"),(0,n.bF)(d,null,{default:(0,n.k6)((()=>[(0,n.bF)(c)])),_:1})])),_:1},8,["onClick"]),(0,n.Lk)("div",h,[(0,n.bF)(k,{name:"net"})])])])}var k=t(3830),b=t(144),m=t(7477),C=t(5096),L={components:{Edit:m.ffu,Refresh:m.C42,Background:C.A},setup(){const e=(0,k.B)(),a=(0,b.Kh)({server:"linker.snltty.com:1802",servers:[]});(0,n.wB)((()=>e.value.config.Client.Servers),(()=>{a.servers=(e.value.config.Client.Servers||[]).slice(0,1),a.server=e.value.config.Client.Server.Host}));const t=()=>{window.location.reload()};return{state:a,handleRefresh:t}}},w=t(1241);const S=(0,w.A)(L,[["render",f],["__scopeId","data-v-3bb95ac8"]]);var _=S;const F=e=>((0,n.Qi)("data-v-b6ab4f06"),e=e(),(0,n.jt)(),e),x={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},I=F((()=>(0,n.Lk)("div",{class:"flex-1"},null,-1))),T={class:"tuntap"},A={class:"page t-c"},B={class:"page-wrap t-c"};function P(e,a,t,l,s,r){const i=(0,n.g2)("DeviceName"),u=(0,n.g2)("UpdaterBtn"),c=(0,n.g2)("TuntapShow"),d=(0,n.g2)("el-pagination");return(0,n.uX)(),(0,n.CE)("div",x,[(0,n.Lk)("div",z,[(0,n.Lk)("ul",null,[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(l.devices.page.List,((e,a)=>((0,n.uX)(),(0,n.CE)("li",{key:a},[(0,n.Lk)("dl",null,[(0,n.Lk)("dt",E,[(0,n.Lk)("div",null,[(0,n.bF)(i,{item:e},null,8,["item"])]),I,(0,n.Lk)("div",null,[(0,n.bF)(u,{config:!1,item:e},null,8,["item"])])]),(0,n.Lk)("dd",T,[l.tuntap.list[e.MachineId]?((0,n.uX)(),(0,n.Wv)(c,{key:0,item:e},null,8,["item"])):(0,n.Q3)("",!0)])])])))),128))])]),(0,n.Lk)("div",A,[(0,n.Lk)("div",B,[(0,n.bF)(d,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:l.devices.page.Count,"page-size":l.devices.page.Request.Size,"current-page":l.devices.page.Request.Page,onCurrentChange:l.handlePageChange,onSizeChange:l.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var y=t(8104),X=t(7985),R=t(9383),D=t(167),U=t(3347),H=t(2950),N={components:{StarFilled:m.BQ2,UpdaterBtn:D.A,DeviceName:U.A,TuntapShow:H.A},setup(e){(0,k.B)();const a=(0,b.Kh)({}),{devices:t,machineId:l,_getSignList:s,_getSignList1:r,handleDeviceEdit:i,handlePageChange:u,handlePageSizeChange:c,handleDel:d,clearDevicesTimeout:o}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:m}=(0,y.O)(),{_getUpdater:C,_subscribeUpdater:L,clearUpdaterTimeout:w}=(0,R.d)();return(0,n.sV)((()=>{u(),v(),s(),r(),p(),C(),L()})),(0,n.hi)((()=>{o(),h(),w()})),{state:a,devices:t,machineId:l,handlePageChange:u,handlePageSizeChange:c,tuntap:g}}};const V=(0,w.A)(N,[["render",P],["__scopeId","data-v-b6ab4f06"]]);var K=V,Q=t(3847),W=t(1387),j={components:{Head:_,List:K,Status:Q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,k.B)(),a=(0,W.rd)();return(0,n.sV)((()=>{0==e.value.hasAccess("NetManager")&&a.push({name:"NoPermission"})})),{}}};const q=(0,w.A)(j,[["render",c],["__scopeId","data-v-6a3f3b43"]]);var M=q}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -537,7 +537,6 @@ namespace linker.tunnel
connection = await ConnectAsync(remoteMachineId, transactionId, denyProtocols);
if (connection != null)
{
break;
}
await Task.Delay(i * 3000);

View File

@@ -26,5 +26,5 @@ export const refreshForward = () => {
}
export const testTargetForwardInfo = (machineid) => {
return sendWebsocketMsg('forward/TestTarget', machineid);
return sendWebsocketMsg('forward/Test', machineid);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -126,8 +126,8 @@
</el-dialog>
</template>
<script>
import { onMounted,reactive, watch } from 'vue';
import { getForwardInfo, removeForwardInfo, addForwardInfo ,getForwardIpv4 } from '@/apis/forward'
import { onMounted,onUnmounted,reactive, watch } from 'vue';
import { getForwardInfo, removeForwardInfo, addForwardInfo ,getForwardIpv4,testTargetForwardInfo } from '@/apis/forward'
import { ElMessage } from 'element-plus';
import {WarnTriangleFilled,Delete} from '@element-plus/icons-vue'
import { injectGlobalData } from '@/provide';
@@ -165,6 +165,14 @@ export default {
}
});
const _testTargetForwardInfo = ()=>{
testTargetForwardInfo(forward.value.machineId).then((res)=>{
state.timer = setTimeout(_testTargetForwardInfo,1000);
}).catch(()=>{
state.timer = setTimeout(_testTargetForwardInfo,1000);
});
}
const _getForwardIpv4 = ()=>{
getForwardIpv4().then((res)=>{
res.splice(0,0,'127.0.0.1');
@@ -265,6 +273,10 @@ export default {
onMounted(()=>{
_getForwardInfo();
_getForwardIpv4();
_testTargetForwardInfo();
});
onUnmounted(()=>{
clearTimeout(state.timer);
});
return {

View File

@@ -107,7 +107,6 @@ export default {
}
});
const _testLocalSForwardInfo = ()=>{
console.log(sforward.value.machineid);
testLocalSForwardInfo(sforward.value.machineid).then((res)=>{
state.timerTestLocal = setTimeout(_testLocalSForwardInfo,1000);
}).catch(()=>{

View File

@@ -1,4 +1,4 @@
import { getForwardCountInfo, refreshForward, testTargetForwardInfo } from "@/apis/forward";
import { getForwardCountInfo, refreshForward } from "@/apis/forward";
import { injectGlobalData } from "@/provide";
import { inject, provide, ref } from "vue";

View File

@@ -13,10 +13,9 @@
<div class="api"><Api :config="config"></Api></div>
<div class="server"><Server :config="config"></Server></div>
<el-dialog v-model="state.showPay" title="赞助linker" width="300" top="1vh">
<el-dialog v-model="state.showPay" title="赞助linker" width="400">
<div class="pay">
<img src="@/assets/wechat.jpg" alt=""/>
<img src="@/assets/alipay.jpg" alt=""/>
<img src="@/assets/qr.jpg" alt=""/>
</div>
</el-dialog>
</div>

View File

@@ -3,7 +3,6 @@ using System.ServiceProcess;
using System.Diagnostics;
using linker.messenger.entry;
using linker.messenger;
using linker.messenger.api;
namespace linker
{
@@ -52,7 +51,12 @@ namespace linker
{
LinkerMessengerEntry.Initialize();
LinkerMessengerEntry.Build();
LinkerMessengerEntry.Setup();
ICommonStore commonStore = LinkerMessengerEntry.GetService<ICommonStore>();
if((commonStore.Modes & CommonModes.Client) == CommonModes.Client)
if((commonStore.Modes & CommonModes.Server) == CommonModes.Server)
LinkerMessengerEntry.Setup(ExcludeModule.None);
LoggerHelper.Instance.Warning($"current version : {VersionHelper.version}");
LoggerHelper.Instance.Warning($"linker env is docker : {Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")}");

View File

@@ -1,5 +1,5 @@
v1.6.4
2025-01-02 17:30:25
2025-01-04 18:18:23
1. 优化代码,解耦,简单几步将打洞和中继集成到你自己的项目中
2. 增加了组件组合demo
3. 测试中,不要更,不要更,不要更