mirror of
https://github.com/snltty/linker.git
synced 2025-12-19 01:46:46 +08:00
cdkey
This commit is contained in:
42
.github/workflows/dotnet.yml
vendored
42
.github/workflows/dotnet.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
release_name: v1.6.9.${{ steps.date.outputs.today }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: "1. 优化linux下路由跟踪问题\r\n2. 优化linux下获取本机IP问题\r\n3. 增加ICS,让win7+、win server2008+支持NAT\r\n4. 增加中继cdkey,使用cdkey解锁公开中继节点的带宽、流量、连接数限制\r\n5. 增加内外穿透定时开关功能\r\n6. 优化管理页面连接接口的体验\r\n7. 优化一些UI体验,去除同步页面,将同步功能放至各个实际的位置\r\n8. 优化端口转发,让不同分组间可以使用相同端口\r\n9. 其它一些修复优化"
|
||||
body: "1. 优化linux下路由跟踪问题,提高启动速度\r\n2. 优化linux下获取本机IP问题,提升虚拟网卡稳定性\r\n3. 增加ICS,让win7+、win server2008+支持NAT\r\n4. 增加中继cdkey,使用cdkey解锁公开中继节点的带宽、流量、连接数限制\r\n5. 增加内外穿透定时开关功能\r\n6. 优化管理页面连接接口的体验\r\n7. 优化一些UI体验,去除同步页面,将同步功能放至各个实际的位置\r\n8. 优化端口转发,让不同分组间可以使用相同端口\r\n9. 从命令行参数初始化配置\r\n10. 优化打洞,IPV6支持的更多了\r\n11. 其它一些修复优化"
|
||||
- name: publish projects
|
||||
run: ./publish.bat
|
||||
- name: upload-win-x86-oss
|
||||
@@ -218,46 +218,6 @@ jobs:
|
||||
asset_path: ./public/publish-zip/linker-linux-musl-arm64.zip
|
||||
asset_name: linker-linux-musl-arm64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: upload-osx-x64-oss
|
||||
id: upload-osx-x64-oss
|
||||
uses: tvrcgo/oss-action@v0.1.1
|
||||
with:
|
||||
region: oss-cn-shenzhen
|
||||
key-id: ${{ secrets.ALIYUN_OSS_ID }}
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-osx-x64.zip
|
||||
target-path: /downloads/linker/v1.6.9/linker-osx-x64.zip
|
||||
- name: upload-osx-x64
|
||||
id: upload-osx-x64
|
||||
uses: actions/upload-release-asset@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./public/publish-zip/linker-osx-x64.zip
|
||||
asset_name: linker-osx-x64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: upload-osx-arm64-oss
|
||||
id: upload-osx-arm64-oss
|
||||
uses: tvrcgo/oss-action@v0.1.1
|
||||
with:
|
||||
region: oss-cn-shenzhen
|
||||
key-id: ${{ secrets.ALIYUN_OSS_ID }}
|
||||
key-secret: ${{ secrets.ALIYUN_OSS_SECRET }}
|
||||
bucket: ide-qbcode
|
||||
asset-path: ./public/publish-zip/linker-osx-arm64.zip
|
||||
target-path: /downloads/linker/v1.6.9/linker-osx-arm64.zip
|
||||
- name: upload-osx-arm64
|
||||
id: upload-osx-arm64
|
||||
uses: actions/upload-release-asset@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./public/publish-zip/linker-osx-arm64.zip
|
||||
asset_name: linker-osx-arm64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: upload-version-oss
|
||||
id: upload-version-oss
|
||||
uses: tvrcgo/oss-action@v0.1.1
|
||||
|
||||
@@ -50,8 +50,7 @@ function writeUpload(data, tagName) {
|
||||
const platforms = {
|
||||
'win': ['x86', 'x64', 'arm64'],
|
||||
'linux': ['x64', 'arm', 'arm64'],
|
||||
'linux-musl': ['x64', 'arm', 'arm64'],
|
||||
'osx': ['x64', 'arm64'],
|
||||
'linux-musl': ['x64', 'arm', 'arm64']
|
||||
};
|
||||
for (let plat in platforms) {
|
||||
let archs = platforms[plat];
|
||||
|
||||
@@ -30,7 +30,7 @@ del /f .\public\extends\win-arm64\linker-win-arm64\linker.ics.pdb
|
||||
msbuild "src\\linker.ics\\linker.ics.csproj" -p:Configuration=Release -p:OutputPath=../../public/extends/win-x86/linker-win-x86
|
||||
del /f .\public\extends\win-x86\linker-win-x86\linker.ics.pdb
|
||||
|
||||
for %%r in (win-x86,win-x64,win-arm64,linux-x64,linux-arm,linux-arm64,linux-musl-x64,linux-musl-arm,linux-musl-arm64,osx-x64,osx-arm64) do (
|
||||
for %%r in (win-x86,win-x64,win-arm64,linux-x64,linux-arm,linux-arm64,linux-musl-x64,linux-musl-arm,linux-musl-arm64) do (
|
||||
|
||||
dotnet publish ./src/linker -c release -f net8.0 -o ./public/publish/%%r/linker-%%r -r %%r -p:PublishSingleFile=true --self-contained true -p:TrimMode=partial -p:TieredPGO=true -p:DebugType=full -p:EventSourceSupport=false -p:DebugSymbols=true -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true -p:MetricsSupport=false -p:StackTraceSupport=false -p:XmlResolverIsNetworkingEnabledByDefault=false
|
||||
echo F|xcopy "public\\extends\\%%r\\linker-%%r\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace linker.app
|
||||
using Microsoft.Maui.Controls.PlatformConfiguration;
|
||||
using System.Diagnostics;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace linker.app
|
||||
{
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
@@ -19,6 +23,7 @@
|
||||
CounterBtn.Text = $"Clicked {count} times";
|
||||
|
||||
SemanticScreenReader.Announce(CounterBtn.Text);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Health.Connect.DataTypes.Units;
|
||||
using Android.Net;
|
||||
using Android.Nfc;
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using AndroidX.Core.App;
|
||||
@@ -35,6 +36,8 @@ namespace linker.app
|
||||
StartActivityForResult(intent, 0);
|
||||
}
|
||||
StartForegroundService(new Intent(this, typeof(VpnServiceLinker)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
@@ -77,6 +80,13 @@ namespace linker.app
|
||||
if (vpnInterface != null)
|
||||
{
|
||||
Android.Util.Log.Error(TAG, "==============================================VPN is connected");
|
||||
|
||||
/*
|
||||
Task.Run(async () =>
|
||||
{
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ sidebar_position: 3
|
||||
## 1、公共配置文件,客户端服务端都有的
|
||||
|
||||
:::tip[服务端运行流程]
|
||||
common.json
|
||||
```
|
||||
{
|
||||
//运行在哪个模式下,多个模式可同时存在
|
||||
@@ -41,24 +42,20 @@ sidebar_position: 3
|
||||
4. 修改server.json,可以去在线生成一些GUID作为各个功能的密钥
|
||||
5. 再次运行程序
|
||||
|
||||
|
||||
common.json
|
||||
```
|
||||
{
|
||||
"Modes": ["server"]
|
||||
}
|
||||
```
|
||||
server.json
|
||||
```
|
||||
{
|
||||
//中继
|
||||
"Relay": {
|
||||
//中继密钥,客户端密钥不准确时无法使用本中继
|
||||
"SecretKey": ""
|
||||
"SecretKey": "",
|
||||
"Cdkey": {
|
||||
//cdkey 加密密钥
|
||||
"SecretKey": "snltty"
|
||||
},
|
||||
},
|
||||
//信标服务器端口
|
||||
"ServicePort": 1802,
|
||||
|
||||
//内网穿透配置
|
||||
"SForward": {
|
||||
//内网穿透密钥
|
||||
@@ -82,6 +79,14 @@ server.json
|
||||
}
|
||||
}
|
||||
```
|
||||
action.json
|
||||
```
|
||||
{
|
||||
"SignInActionUrl": "", //登入信标的验证接口
|
||||
"RelayActionUrl": "", //中继验证接口
|
||||
"SForwardActionUrl": ""//服务器穿透的验证接口
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
## 3、客户端使用web初始化
|
||||
@@ -93,6 +98,63 @@ server.json
|
||||

|
||||

|
||||

|
||||
|
||||
对应配置文件 client.json
|
||||
```
|
||||
{
|
||||
"Name": "A", //客户端名
|
||||
"Access": 4503599627370495, //权限值,可以看`src/linker.messenger.api/Config.cs`里的`AccessValue`枚举
|
||||
"CApi": {
|
||||
"ApiPort": 1803, //api接口
|
||||
"ApiPassword": "snltty", //api密码
|
||||
"WebPort": 1804, //web端口
|
||||
"WebRoot": "./web/" //web根目录
|
||||
},
|
||||
"Servers": [
|
||||
{
|
||||
"Name": "Linker", //信标服务器名称
|
||||
"Host": "127.0.0.1:1802", //信标服务器地址
|
||||
"SecretKey": null, //信标密钥
|
||||
"UserId": "8225e9d4-0ac7-4d76-9946-c4fe04ad4696" //用户标识,多个客户端可相同
|
||||
}
|
||||
],
|
||||
"Groups": [
|
||||
{
|
||||
"Name": "snltty", //分组名
|
||||
"Id": "snltty", //分组id
|
||||
"Password": "snltty" //分组密码
|
||||
}
|
||||
],
|
||||
"Relay": {
|
||||
"Servers": [
|
||||
{
|
||||
"SecretKey": "snltty", //中继密钥
|
||||
"Disabled": false, //是否禁用
|
||||
"SSL": true //启用ssl
|
||||
}
|
||||
]
|
||||
},
|
||||
"SForward": {
|
||||
"SecretKey": "snltty" //服务器穿透密钥
|
||||
},
|
||||
"Updater": {
|
||||
"SecretKey": "snltty" //更新密钥
|
||||
},
|
||||
"Action": {
|
||||
"Args": {} //自定义验证的参数
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
## 4、使用参数初始化
|
||||
|
||||
:::tip[v1.7.0+]
|
||||
1. 如果你使用第三方程序启动linker,`仅配置文件不存在时初始化,后续不会覆盖`,可以传入参数进行初始化,`client.json`、`server.json`、`action.json`、`common.json`,
|
||||
2. 像这样,不填写的字段将以默认值生成,json的双引号需要转义,json里不能有空格
|
||||
```
|
||||
linker.exe --config-client {\"a\":\"1\"} --config-server {\"a\":\"1\"} --config-action {\"a\":\"1\"} --config-common {\"a\":\"1\"}
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
149
src/linker.doc.web/docs/8、集成和二次开发/8.9、中继CDKEY.md
Normal file
149
src/linker.doc.web/docs/8、集成和二次开发/8.9、中继CDKEY.md
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
---
|
||||
|
||||
# 8.9、中继CDKEY
|
||||
:::tip[v1.7.0+]
|
||||
在哪里发卡都可以,可以自己开发卡密商城,只要最后按一定的字段,和加密方式生成cdkey,就可以导入使用
|
||||
:::
|
||||
|
||||
### 1、CDKEY参数字段
|
||||
:::tip[说明]
|
||||
```
|
||||
{
|
||||
"GB":100, //流量GB
|
||||
"Speed":100, //带宽 Mbps
|
||||
"Time":"1-0-0 0:0:0", //持续时间 年-月-日 时:分:秒
|
||||
"WidgetUserId":"2b9c9fef-c342-c968-9dc0-c15e3bc23646",//用户标识
|
||||
"OrderId":"ACG1234567890", //订单号
|
||||
"Contact":"111@qq.com", //联系方式
|
||||
"CostPrice":1, //成本元 double
|
||||
"Price":1, //原价元 double
|
||||
"UserPrice":1, //会员价元 double
|
||||
"PayPrice":1, //支付金额元 double
|
||||
"Count":1, //数量,导入后,会 GB*Count
|
||||
"Type":"Relay", //类型 固定 Relay
|
||||
}
|
||||
```
|
||||
:::
|
||||
### 2、加密方式AES-128-ECB
|
||||
:::tip[说明]
|
||||
1. C#样例
|
||||
```
|
||||
AesCrypto crypto = new AesCrypto("加密密钥", System.Security.Cryptography.PaddingMode.PKCS7);
|
||||
|
||||
//加密
|
||||
byte[] bytes = crypto.Encode(jsonString);
|
||||
string cdkey = Convert.ToBase64String(bytes);
|
||||
|
||||
public sealed class AesCrypto : ISymmetricCrypto
|
||||
{
|
||||
private ICryptoTransform encryptoTransform;
|
||||
private ICryptoTransform decryptoTransform;
|
||||
|
||||
public string Password { get; set; }
|
||||
|
||||
public AesCrypto(string password, PaddingMode mode = PaddingMode.ANSIX923)
|
||||
{
|
||||
Password = password;
|
||||
using Aes aes = Aes.Create();
|
||||
aes.Padding = mode;
|
||||
(aes.Key, aes.IV) = GenerateKeyAndIV(password);
|
||||
|
||||
encryptoTransform = aes.CreateEncryptor(aes.Key, aes.IV);
|
||||
decryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||
}
|
||||
public byte[] Encode(byte[] buffer)
|
||||
{
|
||||
return Encode(buffer, 0, buffer.Length);
|
||||
}
|
||||
public byte[] Encode(byte[] buffer, int offset, int length)
|
||||
{
|
||||
return encryptoTransform.TransformFinalBlock(buffer, offset, length);
|
||||
}
|
||||
public Memory<byte> Decode(byte[] buffer)
|
||||
{
|
||||
return Decode(buffer, 0, buffer.Length);
|
||||
}
|
||||
public Memory<byte> Decode(byte[] buffer, int offset, int length)
|
||||
{
|
||||
return decryptoTransform.TransformFinalBlock(buffer, offset, length);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
encryptoTransform.Dispose();
|
||||
decryptoTransform.Dispose();
|
||||
}
|
||||
|
||||
private (byte[] Key, byte[] IV) GenerateKeyAndIV(string password)
|
||||
{
|
||||
byte[] key = new byte[16];
|
||||
byte[] iv = new byte[16];
|
||||
|
||||
using SHA384 sha = SHA384.Create();
|
||||
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
|
||||
|
||||
Array.Copy(hash, 0, key, 0, key.Length);
|
||||
Array.Copy(hash, key.Length, iv, 0, iv.Length);
|
||||
return (Key: key, IV: iv);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
2. PHP样例
|
||||
```
|
||||
//加密
|
||||
$aesCrypto = new AesCrypto("加密密钥");
|
||||
$cdkey = base64_encode($aesCrypto->encode($jsonString));
|
||||
|
||||
class AesCrypto
|
||||
{
|
||||
private $key;
|
||||
private $iv;
|
||||
private $password;
|
||||
|
||||
public function __construct($password)
|
||||
{
|
||||
$this->password = $password;
|
||||
$this->initAes();
|
||||
}
|
||||
|
||||
private function initAes()
|
||||
{
|
||||
$keyAndIV = $this->generateKeyAndIV($this->password);
|
||||
$this->key = $keyAndIV['key'];
|
||||
$this->iv = $keyAndIV['iv'];
|
||||
}
|
||||
|
||||
public function encode($data)
|
||||
{
|
||||
return $this->encodeWithOffset($data, 0, strlen($data));
|
||||
}
|
||||
|
||||
public function encodeWithOffset($data, $offset, $length)
|
||||
{
|
||||
$data = substr($data, $offset, $length);
|
||||
return openssl_encrypt($data, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
||||
}
|
||||
|
||||
public function decode($data)
|
||||
{
|
||||
return $this->decodeWithOffset($data, 0, strlen($data));
|
||||
}
|
||||
|
||||
public function decodeWithOffset($data, $offset, $length)
|
||||
{
|
||||
$data = substr($data, $offset, $length);
|
||||
return openssl_decrypt($data, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
||||
}
|
||||
|
||||
private function generateKeyAndIV($password)
|
||||
{
|
||||
$hash = hash('sha384', $password, true);
|
||||
$key = substr($hash, 0, 16);
|
||||
$iv = substr($hash, 16, 16);
|
||||
return ['key' => $key, 'iv' => $iv];
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
sidebar_position: 9
|
||||
---
|
||||
|
||||
# 10、公益赞助
|
||||
# 9、公益赞助
|
||||
|
||||

|
||||
@@ -1,74 +0,0 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
---
|
||||
|
||||
# 9、收费项目
|
||||
|
||||
<table width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Linker</th>
|
||||
<th>2设备内</th>
|
||||
<th>2-5设备</th>
|
||||
<th>5-10设备</th>
|
||||
<th>10设备以上</th>
|
||||
<th>权益</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>使用</td>
|
||||
<td>免费</td>
|
||||
<td>免费</td>
|
||||
<td>免费</td>
|
||||
<td>免费</td>
|
||||
<td>/</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>开源集成</td>
|
||||
<td>免费</td>
|
||||
<td>免费</td>
|
||||
<td>免费</td>
|
||||
<td>免费</td>
|
||||
<td>/</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>安装配置维护/次</td>
|
||||
<td>20/次</td>
|
||||
<td>50/次</td>
|
||||
<td>100/次</td>
|
||||
<td>10/台/次</td>
|
||||
<td>私有化部署、配置、BUG修复</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>安装配置维护/年</td>
|
||||
<td>99/年</td>
|
||||
<td>239/年</td>
|
||||
<td>399/年</td>
|
||||
<td>29/台/年</td>
|
||||
<td>私有化部署、配置、BUG修复、技术解答</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>商业集成</td>
|
||||
<td colspan="5" align="center">详谈,技术解答,原理讲解,二开指导</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>功能定制</td>
|
||||
<td colspan="5" align="center">详谈,技术解答,原理讲解,二开指导</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>证书</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>3个月泛域名证书</td>
|
||||
<td align="center">9.9/个</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -73,6 +73,10 @@ namespace linker.libs
|
||||
}
|
||||
Enqueue(new LoggerModel { Type = LoggerTypes.WARNING, Content = content });
|
||||
}
|
||||
public void Warning(Exception ex)
|
||||
{
|
||||
Enqueue(new LoggerModel { Type = LoggerTypes.WARNING, Content = ex + "" });
|
||||
}
|
||||
public void Error(string content, params object[] args)
|
||||
{
|
||||
if (args != null && args.Length > 0)
|
||||
|
||||
@@ -42,6 +42,15 @@ namespace linker.libs
|
||||
|
||||
public static class NetworkHelper
|
||||
{
|
||||
public static IPEndPoint TransEndpointFamily(IPEndPoint ep)
|
||||
{
|
||||
if (ep.Address.AddressFamily == AddressFamily.InterNetworkV6 && ep.Address.IsIPv4MappedToIPv6)
|
||||
{
|
||||
return new IPEndPoint(new IPAddress(ep.Address.GetAddressBytes()[^4..]), ep.Port);
|
||||
}
|
||||
return ep;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 域名解析
|
||||
@@ -217,7 +226,9 @@ namespace linker.libs
|
||||
{
|
||||
return GetIP()
|
||||
.Where(c => c.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
.Where(c => c.GetAddressBytes().AsSpan(0, 8).SequenceEqual(ipv6LocalBytes) == false).Distinct().ToArray(); ;
|
||||
.Where(c => c.GetAddressBytes().AsSpan(0, 8).SequenceEqual(ipv6LocalBytes) == false)
|
||||
.Where(c=>c.Equals(IPAddress.IPv6Loopback) == false)
|
||||
.Distinct().ToArray();
|
||||
}
|
||||
public static IPAddress[] GetIPV4()
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ using linker.messenger.updater;
|
||||
using linker.messenger.store.file;
|
||||
using linker.messenger.serializer.memorypack;
|
||||
using linker.libs;
|
||||
using linker.libs.extends;
|
||||
|
||||
namespace linker.messenger.entry
|
||||
{
|
||||
@@ -29,6 +30,11 @@ namespace linker.messenger.entry
|
||||
private static OperatingManager builded = new OperatingManager();
|
||||
private static OperatingManager setuped = new OperatingManager();
|
||||
|
||||
public static void InputJsonConfig(string str)
|
||||
{
|
||||
|
||||
Console.WriteLine(str.DeJson<ConfigClientInfo>().ToJsonFormat());
|
||||
}
|
||||
/// <summary>
|
||||
/// 开始初始化
|
||||
/// </summary>
|
||||
@@ -131,7 +137,7 @@ namespace linker.messenger.entry
|
||||
/// 开始运行
|
||||
/// </summary>
|
||||
/// <param name="modules">排除哪些模块,默认无</param>
|
||||
public static void Setup(ExcludeModule modules = ExcludeModule.None)
|
||||
public static void Setup(ExcludeModule modules = ExcludeModule.None, Dictionary<string, string> configDic = null)
|
||||
{
|
||||
if (setuped.StartOperation() == false) return;
|
||||
|
||||
@@ -139,7 +145,7 @@ namespace linker.messenger.entry
|
||||
|
||||
serviceProvider.UseMessenger();
|
||||
if ((modules & ExcludeModule.StoreFile) != ExcludeModule.StoreFile)
|
||||
serviceProvider.UseStoreFile();
|
||||
serviceProvider.UseStoreFile(configDic);
|
||||
if ((modules & ExcludeModule.SerializerMemoryPack) != ExcludeModule.SerializerMemoryPack)
|
||||
serviceProvider.UseSerializerMemoryPack();
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace linker.messenger.relay.client.transport
|
||||
Stream = sslStream,
|
||||
Socket = socket,
|
||||
Mode = TunnelMode.Client,
|
||||
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = relayInfo.TransactionId,
|
||||
TransportName = Name,
|
||||
Type = TunnelType.Relay,
|
||||
@@ -286,7 +286,7 @@ namespace linker.messenger.relay.client.transport
|
||||
Stream = sslStream,
|
||||
Socket = socket,
|
||||
Mode = TunnelMode.Server,
|
||||
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = relayInfo.TransactionId,
|
||||
TransportName = Name,
|
||||
Type = TunnelType.Relay,
|
||||
|
||||
@@ -6,6 +6,7 @@ using linker.messenger.relay.server;
|
||||
using linker.messenger.signin;
|
||||
using linker.messenger.relay.server.validator;
|
||||
using linker.libs.extends;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace linker.messenger.relay.messenger
|
||||
{
|
||||
@@ -73,6 +74,7 @@ namespace linker.messenger.relay.messenger
|
||||
await RelayTest(connection, info, (validated) =>
|
||||
{
|
||||
List<RelayServerNodeReportInfo> list = relayServerTransfer.GetNodes(validated).Select(c => (RelayServerNodeReportInfo)c).ToList();
|
||||
|
||||
return serializer.Serialize(list);
|
||||
});
|
||||
}
|
||||
@@ -264,10 +266,6 @@ namespace linker.messenger.relay.messenger
|
||||
public void NodeReport(IConnection connection)
|
||||
{
|
||||
RelayServerNodeReportInfo170 info = serializer.Deserialize<RelayServerNodeReportInfo170>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Debug($"relay node report : {info.ToJson()}");
|
||||
}
|
||||
relayServerTransfer.SetNodeReport(connection, info);
|
||||
}
|
||||
/// <summary>
|
||||
@@ -279,10 +277,7 @@ namespace linker.messenger.relay.messenger
|
||||
public void UpdateNode(IConnection connection)
|
||||
{
|
||||
RelayServerNodeUpdateInfo info = serializer.Deserialize<RelayServerNodeUpdateInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (relayServerNodeTransfer.Id == info.Id)
|
||||
{
|
||||
relayServerNodeTransfer.UpdateNode(info);
|
||||
}
|
||||
relayServerNodeTransfer.UpdateNode(info);
|
||||
}
|
||||
/// <summary>
|
||||
/// 更新节点转发
|
||||
|
||||
@@ -45,8 +45,6 @@ namespace linker.messenger.relay.server
|
||||
|
||||
public sealed class RelayServerNodeInfo
|
||||
{
|
||||
public const string MASTER_NODE_ID = "824777CF-2804-83FE-DE71-69B7B7D3BBA7";
|
||||
|
||||
private string id = Guid.NewGuid().ToString().ToUpper();
|
||||
public string Id
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using linker.libs;
|
||||
using linker.libs.extends;
|
||||
using linker.messenger.relay.messenger;
|
||||
using linker.messenger.relay.server.caching;
|
||||
using System.Collections.Concurrent;
|
||||
@@ -66,17 +67,23 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
try
|
||||
{
|
||||
if (info.Id == RelayServerNodeInfo.MASTER_NODE_ID)
|
||||
{
|
||||
info.EndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
}
|
||||
else if (info.EndPoint.Address.Equals(IPAddress.Any))
|
||||
|
||||
if (info.EndPoint.Address.Equals(IPAddress.Any))
|
||||
{
|
||||
info.EndPoint.Address = connection.Address.Address;
|
||||
}
|
||||
if (info.EndPoint.Address.Equals(IPAddress.Loopback))
|
||||
{
|
||||
info.EndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
}
|
||||
info.LastTicks = Environment.TickCount64;
|
||||
info.Connection = connection;
|
||||
reports.AddOrUpdate(info.Id, info, (a, b) => info);
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Debug($"relay node report : {info.ToJson()}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -92,8 +99,6 @@ namespace linker.messenger.relay.server
|
||||
/// <param name="info"></param>
|
||||
public async Task UpdateNodeReport(RelayServerNodeUpdateInfo info)
|
||||
{
|
||||
if (RelayServerNodeInfo.MASTER_NODE_ID == info.Id) return;
|
||||
|
||||
if (reports.TryGetValue(info.Id, out RelayServerNodeReportInfo170 cache))
|
||||
{
|
||||
await messengerSender.SendOnly(new MessageRequestWrap
|
||||
@@ -143,7 +148,7 @@ namespace linker.messenger.relay.server
|
||||
/// </summary>
|
||||
/// <param name="relayTrafficUpdateInfo"></param>
|
||||
/// <returns></returns>
|
||||
public void AddTraffic(Dictionary<long,long> dic)
|
||||
public void AddTraffic(Dictionary<long, long> dic)
|
||||
{
|
||||
if (dic.Count > 0)
|
||||
trafficQueue.Enqueue(dic);
|
||||
|
||||
@@ -13,11 +13,13 @@ namespace linker.messenger.relay.server
|
||||
/// </summary>
|
||||
public class RelayServerNodeTransfer
|
||||
{
|
||||
public string Id => relayServerNodeStore.Node.Id;
|
||||
/// <summary>
|
||||
/// 配置了就用配置的,每配置就用一个默认的
|
||||
/// </summary>
|
||||
public RelayServerNodeInfo node = null;
|
||||
|
||||
private uint connectionNum = 0;
|
||||
private IConnection localConnection;
|
||||
private IConnection remoteConnection;
|
||||
private IConnection connection;
|
||||
|
||||
private long bytes = 0;
|
||||
private long lastBytes = 0;
|
||||
@@ -38,7 +40,23 @@ namespace linker.messenger.relay.server
|
||||
this.messengerResolver = messengerResolver;
|
||||
this.messengerSender = messengerSender;
|
||||
|
||||
limitTotal.SetLimit((uint)Math.Ceiling((relayServerNodeStore.Node.MaxBandwidthTotal * 1024 * 1024) / 8.0));
|
||||
node = string.IsNullOrWhiteSpace(relayServerNodeStore.Node.MasterHost) ? new RelayServerNodeInfo
|
||||
{
|
||||
Id = "824777CF-2804-83FE-DE71-69B7B7D3BBA7",
|
||||
Host = new IPEndPoint(IPAddress.Any, relayServerNodeStore.ServicePort).ToString(),
|
||||
MasterHost = new IPEndPoint(IPAddress.Loopback, relayServerNodeStore.ServicePort).ToString(),
|
||||
MasterSecretKey = relayServerMasterStore.Master.SecretKey,
|
||||
MaxBandwidth = 0,
|
||||
MaxConnection = 0,
|
||||
MaxBandwidthTotal = 0,
|
||||
MaxGbTotal = 0,
|
||||
MaxGbTotalLastBytes = 0,
|
||||
MaxGbTotalMonth = 0,
|
||||
Name = "default",
|
||||
Public = false,
|
||||
} : relayServerNodeStore.Node;
|
||||
|
||||
limitTotal.SetLimit((uint)Math.Ceiling((node.MaxBandwidthTotal * 1024 * 1024) / 8.0));
|
||||
|
||||
TrafficTask();
|
||||
ReportTask();
|
||||
@@ -46,12 +64,10 @@ namespace linker.messenger.relay.server
|
||||
|
||||
}
|
||||
|
||||
public async ValueTask<RelayCacheInfo> TryGetRelayCache(string key, string nodeid)
|
||||
public async ValueTask<RelayCacheInfo> TryGetRelayCache(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
IConnection connection = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection;
|
||||
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = connection,
|
||||
@@ -73,7 +89,8 @@ namespace linker.messenger.relay.server
|
||||
|
||||
public void UpdateNode(RelayServerNodeUpdateInfo info)
|
||||
{
|
||||
relayServerNodeStore.UpdateInfo(info);
|
||||
if (info.Id == node.Id)
|
||||
relayServerNodeStore.UpdateInfo(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -84,6 +101,7 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
//已认证的没有流量限制
|
||||
if (relayCache.Validated) return true;
|
||||
if (node.Public == false) return false;
|
||||
//流量卡有的,就能继续用
|
||||
if (relayCache.Cdkey.Any(c => c.LastBytes > 0)) return true;
|
||||
|
||||
@@ -95,9 +113,9 @@ namespace linker.messenger.relay.server
|
||||
/// <returns></returns>
|
||||
private bool ValidateConnection(RelayCacheInfo relayCache)
|
||||
{
|
||||
bool res = relayServerNodeStore.Node.MaxConnection == 0 || relayServerNodeStore.Node.MaxConnection * 2 > connectionNum;
|
||||
bool res = node.MaxConnection == 0 || node.MaxConnection * 2 > connectionNum;
|
||||
if (res == false && LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Debug($"relay ValidateConnection false,{connectionNum}/{relayServerNodeStore.Node.MaxConnection * 2}");
|
||||
LoggerHelper.Instance.Debug($"relay ValidateConnection false,{connectionNum}/{node.MaxConnection * 2}");
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -107,11 +125,11 @@ namespace linker.messenger.relay.server
|
||||
/// <returns></returns>
|
||||
private bool ValidateBytes(RelayCacheInfo relayCache)
|
||||
{
|
||||
bool res = relayServerNodeStore.Node.MaxGbTotal == 0
|
||||
|| (relayServerNodeStore.Node.MaxGbTotal > 0 && relayServerNodeStore.Node.MaxGbTotalLastBytes > 0);
|
||||
bool res = node.MaxGbTotal == 0
|
||||
|| (node.MaxGbTotal > 0 && node.MaxGbTotalLastBytes > 0);
|
||||
|
||||
if (res == false && LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Debug($"relay ValidateBytes false,{relayServerNodeStore.Node.MaxGbTotalLastBytes}bytes/{relayServerNodeStore.Node.MaxGbTotal}gb");
|
||||
LoggerHelper.Instance.Debug($"relay ValidateBytes false,{node.MaxGbTotalLastBytes}bytes/{node.MaxGbTotal}gb");
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -181,14 +199,14 @@ namespace linker.messenger.relay.server
|
||||
//验证过的,不消耗流量
|
||||
if (cache.Cache.Validated) return true;
|
||||
//节点无流量限制的,不消耗流量
|
||||
if (relayServerNodeStore.Node.MaxGbTotal == 0) return true;
|
||||
if (node.MaxGbTotal == 0) return true;
|
||||
|
||||
Interlocked.Add(ref cache.Sendt, length);
|
||||
|
||||
var current = cache.CurrentCdkey;
|
||||
if (current != null) return current.LastBytes > 0;
|
||||
|
||||
return relayServerNodeStore.Node.MaxGbTotalLastBytes > 0;
|
||||
return node.MaxGbTotalLastBytes > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,7 +216,7 @@ namespace linker.messenger.relay.server
|
||||
private void SetLimit(RelayTrafficCacheInfo relayCache)
|
||||
{
|
||||
//无限制
|
||||
if (relayCache.Cache.Validated || relayServerNodeStore.Node.MaxBandwidth == 0)
|
||||
if (relayCache.Cache.Validated || node.MaxBandwidth == 0)
|
||||
{
|
||||
relayCache.Limit.SetLimit(0);
|
||||
return;
|
||||
@@ -206,14 +224,14 @@ namespace linker.messenger.relay.server
|
||||
|
||||
RelayServerCdkeyInfo currentCdkey = relayCache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
|
||||
//有cdkey,且带宽大于节点带宽,就用cdkey的带宽
|
||||
if (currentCdkey != null && (currentCdkey.Bandwidth == 0 || currentCdkey.Bandwidth >= relayServerNodeStore.Node.MaxBandwidth || relayServerNodeStore.Node.MaxGbTotalLastBytes == 0))
|
||||
if (currentCdkey != null && (currentCdkey.Bandwidth == 0 || currentCdkey.Bandwidth >= node.MaxBandwidth || node.MaxGbTotalLastBytes == 0))
|
||||
{
|
||||
relayCache.CurrentCdkey = currentCdkey;
|
||||
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayCache.CurrentCdkey.Bandwidth * 1024 * 1024) / 8.0));
|
||||
return;
|
||||
}
|
||||
relayCache.CurrentCdkey = null;
|
||||
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayServerNodeStore.Node.MaxBandwidth * 1024 * 1024) / 8.0));
|
||||
relayCache.Limit.SetLimit((uint)Math.Ceiling((node.MaxBandwidth * 1024 * 1024) / 8.0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -236,18 +254,20 @@ namespace linker.messenger.relay.server
|
||||
}
|
||||
private void ResetNodeBytes()
|
||||
{
|
||||
if (node.MaxGbTotal == 0) return;
|
||||
|
||||
foreach (var cache in trafficDict.Values.Where(c => c.CurrentCdkey == null))
|
||||
{
|
||||
long length = Interlocked.Exchange(ref cache.Sendt, 0);
|
||||
|
||||
if (relayServerNodeStore.Node.MaxGbTotalLastBytes >= length)
|
||||
relayServerNodeStore.SetMaxGbTotalLastBytes(relayServerNodeStore.Node.MaxGbTotalLastBytes - length);
|
||||
if (node.MaxGbTotalLastBytes >= length)
|
||||
relayServerNodeStore.SetMaxGbTotalLastBytes(node.MaxGbTotalLastBytes - length);
|
||||
else relayServerNodeStore.SetMaxGbTotalLastBytes(0);
|
||||
}
|
||||
if (relayServerNodeStore.Node.MaxGbTotalMonth != DateTime.Now.Month)
|
||||
if (node.MaxGbTotalMonth != DateTime.Now.Month)
|
||||
{
|
||||
relayServerNodeStore.SetMaxGbTotalMonth(DateTime.Now.Month);
|
||||
relayServerNodeStore.SetMaxGbTotalLastBytes((long)(relayServerNodeStore.Node.MaxGbTotal * 1024 * 1024 * 1024));
|
||||
relayServerNodeStore.SetMaxGbTotalLastBytes((long)(node.MaxGbTotal * 1024 * 1024 * 1024));
|
||||
}
|
||||
relayServerNodeStore.Confirm();
|
||||
}
|
||||
@@ -259,14 +279,12 @@ namespace linker.messenger.relay.server
|
||||
|
||||
bool result = await messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
Connection = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection,
|
||||
Connection = connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.TrafficReport,
|
||||
Payload = serializer.Serialize(new RelayTrafficUpdateInfo
|
||||
{
|
||||
Dic = id2sent,
|
||||
SecretKey = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID
|
||||
? relayServerMasterStore.Master.SecretKey
|
||||
: relayServerNodeStore.Node.MasterSecretKey
|
||||
SecretKey = relayServerMasterStore.Master.SecretKey
|
||||
}),
|
||||
Timeout = 4000
|
||||
});
|
||||
@@ -307,67 +325,39 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
TimerHelper.SetIntervalLong(async () =>
|
||||
{
|
||||
IEnumerable<RelayServerNodeInfo> nodes = new List<RelayServerNodeInfo>
|
||||
{
|
||||
//默认报告给自己,作为本服务器的一个默认中继节点
|
||||
new RelayServerNodeInfo{
|
||||
Id = RelayServerNodeInfo.MASTER_NODE_ID,
|
||||
Host = new IPEndPoint(IPAddress.Any, relayServerNodeStore.ServicePort).ToString(),
|
||||
MasterHost = new IPEndPoint(IPAddress.Loopback, relayServerNodeStore.ServicePort).ToString(),
|
||||
MasterSecretKey = relayServerMasterStore.Master.SecretKey,
|
||||
MaxBandwidth = 0,
|
||||
MaxConnection = 0,
|
||||
MaxBandwidthTotal=0,
|
||||
MaxGbTotal=0,
|
||||
MaxGbTotalLastBytes=0,
|
||||
MaxGbTotalMonth=0,
|
||||
Name = "default",
|
||||
Public = false
|
||||
},
|
||||
//配置的中继节点
|
||||
relayServerNodeStore.Node
|
||||
}.Where(c => string.IsNullOrWhiteSpace(c.MasterHost) == false && string.IsNullOrWhiteSpace(c.MasterSecretKey) == false)
|
||||
.Where(c => string.IsNullOrWhiteSpace(c.Name) == false && string.IsNullOrWhiteSpace(c.Id) == false);
|
||||
|
||||
double diff = (bytes - lastBytes) * 8 / 1024.0 / 1024.0;
|
||||
lastBytes = bytes;
|
||||
|
||||
foreach (var node in nodes)
|
||||
try
|
||||
{
|
||||
try
|
||||
IPEndPoint endPoint = await NetworkHelper.GetEndPointAsync(node.Host, relayServerNodeStore.ServicePort) ?? new IPEndPoint(IPAddress.Any, relayServerNodeStore.ServicePort);
|
||||
RelayServerNodeReportInfo170 relayNodeReportInfo = new RelayServerNodeReportInfo170
|
||||
{
|
||||
IConnection connection = node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection;
|
||||
IPEndPoint endPoint = await NetworkHelper.GetEndPointAsync(node.Host, relayServerNodeStore.ServicePort) ?? new IPEndPoint(IPAddress.Any, relayServerNodeStore.ServicePort);
|
||||
|
||||
RelayServerNodeReportInfo170 relayNodeReportInfo = new RelayServerNodeReportInfo170
|
||||
{
|
||||
Id = node.Id,
|
||||
Name = node.Name,
|
||||
Public = node.Public,
|
||||
MaxBandwidth = node.MaxBandwidth,
|
||||
BandwidthRatio = Math.Round(diff / 5, 2),
|
||||
MaxBandwidthTotal = node.MaxBandwidthTotal,
|
||||
MaxGbTotal = node.MaxGbTotal,
|
||||
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
||||
MaxConnection = node.MaxConnection,
|
||||
ConnectionRatio = Math.Round(connectionNum / 2.0),
|
||||
EndPoint = endPoint,
|
||||
Url = node.Url
|
||||
};
|
||||
|
||||
await messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
Connection = connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.NodeReport,
|
||||
Payload = serializer.Serialize(relayNodeReportInfo)
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
Id = node.Id,
|
||||
Name = node.Name,
|
||||
Public = node.Public,
|
||||
MaxBandwidth = node.MaxBandwidth,
|
||||
BandwidthRatio = Math.Round(diff / 5, 2),
|
||||
MaxBandwidthTotal = node.MaxBandwidthTotal,
|
||||
MaxGbTotal = node.MaxGbTotal,
|
||||
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
||||
MaxConnection = node.MaxConnection,
|
||||
ConnectionRatio = Math.Round(connectionNum / 2.0),
|
||||
EndPoint = endPoint,
|
||||
Url = node.Url
|
||||
};
|
||||
await messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error($"relay report : {ex}");
|
||||
}
|
||||
Connection = connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.NodeReport,
|
||||
Payload = serializer.Serialize(relayNodeReportInfo)
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Error($"relay report : {ex}");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -378,13 +368,9 @@ namespace linker.messenger.relay.server
|
||||
{
|
||||
TimerHelper.SetIntervalLong(async () =>
|
||||
{
|
||||
if ((remoteConnection == null || remoteConnection.Connected == false) && string.IsNullOrWhiteSpace(relayServerNodeStore.Node.MasterHost) == false)
|
||||
if (connection == null || connection.Connected == false)
|
||||
{
|
||||
remoteConnection = await SignIn(relayServerNodeStore.Node.MasterHost, relayServerNodeStore.Node.MasterSecretKey).ConfigureAwait(false);
|
||||
}
|
||||
if (localConnection == null || localConnection.Connected == false)
|
||||
{
|
||||
localConnection = await SignIn(new IPEndPoint(IPAddress.Loopback, relayServerNodeStore.ServicePort).ToString(), relayServerMasterStore.Master.SecretKey).ConfigureAwait(false);
|
||||
connection = await SignIn(node.MasterHost, node.MasterSecretKey).ConfigureAwait(false);
|
||||
}
|
||||
return true;
|
||||
}, 3000);
|
||||
@@ -401,6 +387,10 @@ namespace linker.messenger.relay.server
|
||||
|
||||
|
||||
IPEndPoint remote = await NetworkHelper.GetEndPointAsync(host, 1802);
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Warning($"relay node sign in to {remote}");
|
||||
}
|
||||
|
||||
Socket socket = new Socket(remote.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
socket.KeepAlive();
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace linker.messenger.relay.server
|
||||
//ask 是发起端来的,那key就是 发起端->目标端, answer的,目标和来源会交换,所以转换一下
|
||||
string key = relayMessage.Type == RelayMessengerType.Ask ? $"{relayMessage.FromId}->{relayMessage.ToId}->{relayMessage.FlowId}" : $"{relayMessage.ToId}->{relayMessage.FromId}->{relayMessage.FlowId}";
|
||||
//获取缓存
|
||||
RelayCacheInfo relayCache = await relayServerNodeTransfer.TryGetRelayCache(key, relayMessage.NodeId);
|
||||
RelayCacheInfo relayCache = await relayServerNodeTransfer.TryGetRelayCache(key);
|
||||
if (relayCache == null)
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
|
||||
@@ -100,11 +100,12 @@ namespace linker.messenger.store.file
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
public static ServiceProvider UseStoreFile(this ServiceProvider serviceProvider)
|
||||
public static ServiceProvider UseStoreFile(this ServiceProvider serviceProvider,Dictionary<string,string> configDic)
|
||||
{
|
||||
LoggerHelper.Instance.Info("use store file");
|
||||
|
||||
FileConfig fileConfig = serviceProvider.GetService<FileConfig>();
|
||||
fileConfig.Initialize(configDic);
|
||||
RunningConfig runningConfig = serviceProvider.GetService<RunningConfig>();
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
|
||||
@@ -18,9 +18,12 @@ namespace linker.messenger.store.file
|
||||
public ConfigInfo Data { get; private set; } = new ConfigInfo();
|
||||
|
||||
public FileConfig()
|
||||
{
|
||||
}
|
||||
public void Initialize(Dictionary<string, string> dic)
|
||||
{
|
||||
Init();
|
||||
Load();
|
||||
Load(dic);
|
||||
Save();
|
||||
SaveTask();
|
||||
}
|
||||
@@ -47,7 +50,7 @@ namespace linker.messenger.store.file
|
||||
});
|
||||
}
|
||||
}
|
||||
private void Load()
|
||||
private void Load(Dictionary<string, string> dic)
|
||||
{
|
||||
slim.Wait();
|
||||
try
|
||||
@@ -61,13 +64,15 @@ namespace linker.messenger.store.file
|
||||
LoggerHelper.Instance.Error($"{item.Value.Property.Name} not found");
|
||||
continue;
|
||||
}
|
||||
if (File.Exists(item.Value.Path) == false)
|
||||
string text = string.Empty;
|
||||
if (File.Exists(item.Value.Path))
|
||||
{
|
||||
LoggerHelper.Instance.Error($"{item.Value.Path} not exists");
|
||||
continue;
|
||||
text = File.ReadAllText(item.Value.Path, encoding: System.Text.Encoding.UTF8);
|
||||
}
|
||||
else if (dic != null && dic.ContainsKey(item.Value.Property.Name))
|
||||
{
|
||||
text = dic[item.Value.Property.Name];
|
||||
}
|
||||
|
||||
string text = File.ReadAllText(item.Value.Path, encoding: System.Text.Encoding.UTF8);
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
LoggerHelper.Instance.Error($"{item.Value.Path} empty");
|
||||
|
||||
@@ -4,6 +4,7 @@ using linker.messenger.signin;
|
||||
using linker.tunnel;
|
||||
using System.Net;
|
||||
using System.Net.Quic;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace linker.messenger.tunnel
|
||||
{
|
||||
@@ -45,23 +46,55 @@ namespace linker.messenger.tunnel
|
||||
LoggerHelper.Instance.Warning($"tunnel route level:{Info.RouteLevel}");
|
||||
}
|
||||
|
||||
private async Task GetIsp()
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpClient httpClient = new HttpClient();
|
||||
string str = await httpClient.GetStringAsync($"http://ip-api.com/json").WaitAsync(TimeSpan.FromMilliseconds(3000));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str) == false)
|
||||
{
|
||||
TunnelNetInfo net = str.DeJson<TunnelNetInfo>();
|
||||
Info.Net.Isp = net.Isp;
|
||||
Info.Net.As = net.As;
|
||||
Info.Net.Org = net.Org;
|
||||
Info.Net.Region = net.Region;
|
||||
Info.Net.RegionName = net.RegionName;
|
||||
Info.Net.Country = net.Country;
|
||||
Info.Net.CountryCode = net.CountryCode;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Warning(ex);
|
||||
}
|
||||
}
|
||||
private async Task GetPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpClient httpClient = new HttpClient();
|
||||
string str = await httpClient.GetStringAsync($"https://api.myip.la/en?json").WaitAsync(TimeSpan.FromMilliseconds(5000));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str) == false)
|
||||
{
|
||||
JsonNode json = JsonObject.Parse(str);
|
||||
Info.Net.City = json["location"]["city"].ToString();
|
||||
Info.Net.Lat = double.Parse(json["location"]["latitude"].ToString());
|
||||
Info.Net.Lon = double.Parse(json["location"]["longitude"].ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Warning(ex);
|
||||
}
|
||||
}
|
||||
private async Task GetNet()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Info.Net.City))
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpClient httpClient = new HttpClient();
|
||||
string str = await httpClient.GetStringAsync($"http://ip-api.com/json").WaitAsync(TimeSpan.FromMilliseconds(3000));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str) == false)
|
||||
{
|
||||
Info.Net = str.DeJson<TunnelNetInfo>();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
await Task.WhenAll(GetIsp(), GetPosition());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,17 +252,8 @@ namespace linker.messenger
|
||||
SourceStream = stream;
|
||||
SourceNetworkStream = networkStream;
|
||||
SourceSocket = socket;
|
||||
if (remote.Address.AddressFamily == AddressFamily.InterNetworkV6 && remote.Address.IsIPv4MappedToIPv6)
|
||||
{
|
||||
remote = new IPEndPoint(new IPAddress(remote.Address.GetAddressBytes()[^4..]), remote.Port);
|
||||
}
|
||||
Address = remote;
|
||||
|
||||
if (local.Address.AddressFamily == AddressFamily.InterNetworkV6 && local.Address.IsIPv4MappedToIPv6)
|
||||
{
|
||||
local = new IPEndPoint(new IPAddress(local.Address.GetAddressBytes()[^4..]), local.Port);
|
||||
}
|
||||
LocalAddress = local;
|
||||
Address = NetworkHelper.TransEndpointFamily(remote) ;
|
||||
LocalAddress = NetworkHelper.TransEndpointFamily(local);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace linker.tunnel.connection
|
||||
private async Task ProcessWrite()
|
||||
{
|
||||
byte[] buffer = new byte[65 * 1024];
|
||||
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
|
||||
IPEndPoint ep = new IPEndPoint(IPEndPoint.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);
|
||||
try
|
||||
{
|
||||
while (cancellationTokenSource.IsCancellationRequested == false)
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace linker.tunnel.transport
|
||||
RemoteUdp = remoteUdp,
|
||||
Stream = quicStream,
|
||||
Connection = connection,
|
||||
IPEndPoint = remoteEP,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(remoteEP),
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
RemoteMachineId = tunnelTransportInfo.Remote.MachineId,
|
||||
@@ -626,7 +626,7 @@ namespace linker.tunnel.transport
|
||||
TransactionId = state.TransactionId,
|
||||
TransactionTag = state.TransactionTag,
|
||||
TransportName = state.TransportName,
|
||||
IPEndPoint = remoteEP,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(remoteEP),
|
||||
Label = string.Empty,
|
||||
BufferSize = state.BufferSize,
|
||||
};
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace linker.tunnel.transport
|
||||
{
|
||||
Stream = sslStream,
|
||||
Socket = targetSocket,
|
||||
IPEndPoint = targetSocket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(targetSocket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
RemoteMachineId = tunnelTransportInfo.Remote.MachineId,
|
||||
@@ -291,7 +291,7 @@ namespace linker.tunnel.transport
|
||||
TransactionId = _state.TransactionId,
|
||||
TransactionTag = _state.TransactionTag,
|
||||
TransportName = _state.TransportName,
|
||||
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
Label = string.Empty,
|
||||
SSL = _state.SSL,
|
||||
BufferSize = _state.BufferSize,
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace linker.tunnel.transport
|
||||
{
|
||||
Stream = sslStream,
|
||||
Socket = socket,
|
||||
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = state.TransactionId,
|
||||
TransactionTag = state.TransactionTag,
|
||||
RemoteMachineId = state.Remote.MachineId,
|
||||
@@ -238,7 +238,7 @@ namespace linker.tunnel.transport
|
||||
TransactionId = state.TransactionId,
|
||||
TransactionTag = state.TransactionTag,
|
||||
TransportName = state.TransportName,
|
||||
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
Label = string.Empty,
|
||||
SSL = state.SSL,
|
||||
BufferSize = state.BufferSize,
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace linker.tunnel.transport
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
TransportName = tunnelTransportInfo.TransportName,
|
||||
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
|
||||
Label = string.Empty,
|
||||
SSL = tunnelTransportInfo.SSL,
|
||||
BufferSize = tunnelTransportInfo.BufferSize,
|
||||
@@ -338,7 +338,7 @@ namespace linker.tunnel.transport
|
||||
{
|
||||
Stream = sslStream,
|
||||
Socket = targetSocket,
|
||||
IPEndPoint = targetSocket.RemoteEndPoint as IPEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(targetSocket.RemoteEndPoint as IPEndPoint),
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
RemoteMachineId = tunnelTransportInfo.Remote.MachineId,
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace linker.tunnel.transport
|
||||
return new TunnelConnectionUdp
|
||||
{
|
||||
UdpClient = remoteUdp,
|
||||
IPEndPoint = remoteEP,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily( remoteEP),
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
RemoteMachineId = tunnelTransportInfo.Remote.MachineId,
|
||||
@@ -224,7 +224,7 @@ namespace linker.tunnel.transport
|
||||
TimerHelper.Async(async () =>
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
SocketReceiveFromResult result = await socket.ReceiveFromAsync(buffer, new IPEndPoint(IPAddress.Any, 0)).ConfigureAwait(false);
|
||||
SocketReceiveFromResult result = await socket.ReceiveFromAsync(buffer, new IPEndPoint(IPAddress.IPv6Any, 0)).ConfigureAwait(false);
|
||||
await socket.SendToAsync(endBytes, result.RemoteEndPoint);
|
||||
tcs.SetResult(result.RemoteEndPoint as IPEndPoint);
|
||||
});
|
||||
@@ -408,7 +408,7 @@ namespace linker.tunnel.transport
|
||||
TransactionId = state.TransactionId,
|
||||
TransactionTag = state.TransactionTag,
|
||||
TransportName = state.TransportName,
|
||||
IPEndPoint = remoteEP,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(remoteEP),
|
||||
Label = string.Empty,
|
||||
Receive = true,
|
||||
SSL = state.SSL,
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace linker.tunnel.transport
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
TransportName = tunnelTransportInfo.TransportName,
|
||||
IPEndPoint = state.RemoteEndPoint,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(state.RemoteEndPoint),
|
||||
Label = string.Empty,
|
||||
BufferSize = tunnelTransportInfo.BufferSize,
|
||||
Receive = false,
|
||||
@@ -323,14 +323,14 @@ namespace linker.tunnel.transport
|
||||
}
|
||||
|
||||
await targetSocket.SendToAsync($"{flagTexts}-{tunnelTransportInfo.Local.MachineId}-{tunnelTransportInfo.FlowId}".ToBytes(), ep).ConfigureAwait(false);
|
||||
await targetSocket.ReceiveFromAsync(new byte[1024], new IPEndPoint(IPAddress.IPv6Any, 0)).WaitAsync(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false);
|
||||
await targetSocket.ReceiveFromAsync(new byte[1024], new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0)).WaitAsync(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false);
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Debug($"{Name} connect to {tunnelTransportInfo.Remote.MachineId}->{tunnelTransportInfo.Remote.MachineName} {ep} success");
|
||||
|
||||
TunnelConnectionUdp result = new TunnelConnectionUdp
|
||||
{
|
||||
IPEndPoint = ep,
|
||||
IPEndPoint = NetworkHelper.TransEndpointFamily(ep),
|
||||
TransactionId = tunnelTransportInfo.TransactionId,
|
||||
TransactionTag = tunnelTransportInfo.TransactionTag,
|
||||
RemoteMachineId = tunnelTransportInfo.Remote.MachineId,
|
||||
|
||||
1
src/linker.web/public/armbian.svg
Normal file
1
src/linker.web/public/armbian.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
@@ -17,6 +17,7 @@ export const provideTuntap = () => {
|
||||
|
||||
const systems = {
|
||||
linux: ['debian', 'ubuntu', 'alpine', 'rocky', 'centos', 'fedora', 'archlinux'],
|
||||
armbian: ['armbian'],
|
||||
openwrt: ['openwrt'],
|
||||
ubuntu: ['ubuntu'],
|
||||
windows: ['windows'],
|
||||
|
||||
@@ -54,9 +54,11 @@ namespace linker
|
||||
|
||||
public static void Run(string[] args)
|
||||
{
|
||||
Dictionary<string, string> configDic = ParseArgs(args);
|
||||
|
||||
LinkerMessengerEntry.Initialize();
|
||||
LinkerMessengerEntry.Build();
|
||||
LinkerMessengerEntry.Setup(ExcludeModule.None);
|
||||
LinkerMessengerEntry.Setup(ExcludeModule.None, configDic);
|
||||
|
||||
|
||||
LoggerHelper.Instance.Warning($"current version : {VersionHelper.version}");
|
||||
@@ -66,6 +68,34 @@ namespace linker
|
||||
|
||||
GCHelper.FlushMemory();
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> ParseArgs(string[] args)
|
||||
{
|
||||
Dictionary<string, string> configDic = new Dictionary<string, string>();
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (args[i] == "--config-cient")
|
||||
{
|
||||
configDic.Add("Client", args[i+1]);
|
||||
i++;
|
||||
}else if (args[i] == "--config-server")
|
||||
{
|
||||
configDic.Add("Server", args[i + 1]);
|
||||
i++;
|
||||
}
|
||||
else if (args[i] == "--config-action")
|
||||
{
|
||||
configDic.Add("Action", args[i + 1]);
|
||||
i++;
|
||||
}
|
||||
else if (args[i] == "--config-common")
|
||||
{
|
||||
configDic.Add("Common", args[i + 1]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return configDic;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,15 +20,17 @@
|
||||
<Title>linker</Title>
|
||||
<Authors>snltty</Authors>
|
||||
<Company>snltty</Company>
|
||||
<Description>1. 优化linux下路由跟踪问题
|
||||
2. 优化linux下获取本机IP问题
|
||||
<Description>1. 优化linux下路由跟踪问题,提高启动速度
|
||||
2. 优化linux下获取本机IP问题,提升虚拟网卡稳定性
|
||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||
4. 增加中继cdkey,使用cdkey解锁公开中继节点的带宽、流量、连接数限制
|
||||
5. 增加内外穿透定时开关功能
|
||||
6. 优化管理页面连接接口的体验
|
||||
7. 优化一些UI体验,去除同步页面,将同步功能放至各个实际的位置
|
||||
8. 优化端口转发,让不同分组间可以使用相同端口
|
||||
9. 其它一些修复优化</Description>
|
||||
9. 从命令行参数初始化配置
|
||||
10. 优化打洞,IPV6支持的更多了
|
||||
11. 其它一些修复优化</Description>
|
||||
<Copyright>snltty</Copyright>
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
|
||||
10
version.txt
10
version.txt
@@ -1,11 +1,13 @@
|
||||
v1.6.9
|
||||
2025-03-10 17:55:39
|
||||
1. 优化linux下路由跟踪问题
|
||||
2. 优化linux下获取本机IP问题
|
||||
2025-03-11 21:12:44
|
||||
1. 优化linux下路由跟踪问题,提高启动速度
|
||||
2. 优化linux下获取本机IP问题,提升虚拟网卡稳定性
|
||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||
4. 增加中继cdkey,使用cdkey解锁公开中继节点的带宽、流量、连接数限制
|
||||
5. 增加内外穿透定时开关功能
|
||||
6. 优化管理页面连接接口的体验
|
||||
7. 优化一些UI体验,去除同步页面,将同步功能放至各个实际的位置
|
||||
8. 优化端口转发,让不同分组间可以使用相同端口
|
||||
9. 其它一些修复优化
|
||||
9. 从命令行参数初始化配置
|
||||
10. 优化打洞,IPV6支持的更多了
|
||||
11. 其它一些修复优化
|
||||
Reference in New Issue
Block a user