mirror of
https://github.com/snltty/linker.git
synced 2025-10-14 21:25:51 +08:00
sync
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
release_name: v1.4.9.${{ steps.date.outputs.today }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: "1. 使用原生成器替代反射\r\n2. 统计所有服务端,客户端数量\r\n3. 创建docker镜像清单,自动识别平台\r\n4. docker镜像增加arm\r\n5. 优化了arm平台下获取设备ID的方法\r\n6. 增加了查看流量信息的权限\r\n7. 有服务器更新密钥的客户端,可以更新本服务器的所有客户端"
|
||||
body: "1. 新增多分组管理,方便分组切换\r\n2. 增加分组密码,提高分组隔离安全性\r\n3. 优化配置同步,可自由选择同步哪些信息\r\n4. 自动分配虚拟网卡IP\r\n5. 线程池优化\r\n6. 一些UI优化"
|
||||
- name: upload-win-x86-oss
|
||||
id: upload-win-x86-oss
|
||||
uses: tvrcgo/oss-action@v0.1.1
|
||||
|
@@ -37,6 +37,9 @@
|
||||
- [x] 权限管理,主客户端拥有完全权限,可导出、配置子客户端配置,分配其管理权限
|
||||
- [x] 自定义验证,通过`HTTP POST`让你可以自定义认证是否允许`连接信标`,`中继`,`内网穿透`
|
||||
- [x] 流量统计,统计服务器`信标`、`中继`、`内网穿透` 的流量情况
|
||||
- [ ] 网络配置,主客户端设置网络,所有客户端自动分配IP
|
||||
- [ ] 分布式,中继,内网穿透分布式,可实现负载均衡
|
||||
|
||||
|
||||
## 界面预览
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 5、组网权限
|
||||
# 5、导出配置和管理权限
|
||||
|
||||
:::tip[说明]
|
||||
1. 按 <a href="../2、首次运行/2.1、安装">首次运行,安装</a>,此设备拥有完全管理权限,可导出配置,用以作为组网子设备运行
|
@@ -157,7 +157,8 @@ namespace linker.libs
|
||||
return Array.Empty<IPAddress>();
|
||||
}
|
||||
|
||||
public static byte GetPrefixLength(uint ip)
|
||||
|
||||
public static byte PrefixValue2Length(uint ip)
|
||||
{
|
||||
byte maskLength = 32;
|
||||
for (int i = 0; i < sizeof(uint); i++)
|
||||
@@ -170,34 +171,60 @@ namespace linker.libs
|
||||
}
|
||||
return maskLength;
|
||||
}
|
||||
|
||||
public static uint GetPrefixIP(byte prefixLength)
|
||||
public static uint PrefixLength2Value(byte prefixLength)
|
||||
{
|
||||
//最多<<31 所以0需要单独计算
|
||||
if (prefixLength < 1) return 0;
|
||||
return 0xffffffff << (32 - prefixLength);
|
||||
}
|
||||
public static IPAddress GetPrefixIp(uint prefixIP)
|
||||
public static IPAddress PrefixValue2IP(uint prefixIP)
|
||||
{
|
||||
return new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(prefixIP)));
|
||||
}
|
||||
public static IPAddress ToNetworkIp(IPAddress ip, uint prefixIP)
|
||||
|
||||
|
||||
public static uint IP2Value(IPAddress ip)
|
||||
{
|
||||
return ToNetworkIp(BinaryPrimitives.ReadUInt32BigEndian(ip.GetAddressBytes()), prefixIP);
|
||||
return BinaryPrimitives.ReadUInt32BigEndian(ip.GetAddressBytes());
|
||||
}
|
||||
public static IPAddress ToNetworkIp(uint ip, uint prefixIP)
|
||||
public static IPAddress Value2IP(uint value)
|
||||
{
|
||||
return new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(value)));
|
||||
}
|
||||
|
||||
|
||||
public static IPAddress NetworkIP2IP(IPAddress ip, uint prefixIP)
|
||||
{
|
||||
return NetworkValue2Ip(BinaryPrimitives.ReadUInt32BigEndian(ip.GetAddressBytes()), prefixIP);
|
||||
}
|
||||
public static uint NetworkIP2Value(IPAddress ip, uint prefixIP)
|
||||
{
|
||||
return NetworkValue2Value(BinaryPrimitives.ReadUInt32BigEndian(ip.GetAddressBytes()), prefixIP);
|
||||
}
|
||||
public static IPAddress NetworkValue2Ip(uint ip, uint prefixIP)
|
||||
{
|
||||
return new IPAddress(BinaryPrimitives.ReverseEndianness(ip & prefixIP).ToBytes());
|
||||
}
|
||||
public static uint NetworkValue2Value(uint ip, uint prefixIP)
|
||||
{
|
||||
return ip & prefixIP;
|
||||
}
|
||||
|
||||
public static uint BroadcastValue2Value(uint ip, uint prefixIP)
|
||||
{
|
||||
return ip | ~prefixIP;
|
||||
}
|
||||
|
||||
|
||||
public static IPAddress ToGatewayIP(IPAddress ip, byte prefixLength)
|
||||
{
|
||||
uint network = BinaryPrimitives.ReadUInt32BigEndian(ToNetworkIp(ip, NetworkHelper.GetPrefixIP(prefixLength)).GetAddressBytes());
|
||||
uint network = BinaryPrimitives.ReadUInt32BigEndian(NetworkIP2IP(ip, NetworkHelper.PrefixLength2Value(prefixLength)).GetAddressBytes());
|
||||
IPAddress gateway = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(network + 1)));
|
||||
return gateway;
|
||||
}
|
||||
public static IPAddress ToGatewayIP(uint ip, uint prefixIP)
|
||||
{
|
||||
uint network = BinaryPrimitives.ReadUInt32BigEndian(ToNetworkIp(ip, prefixIP).GetAddressBytes());
|
||||
uint network = BinaryPrimitives.ReadUInt32BigEndian(NetworkValue2Ip(ip, prefixIP).GetAddressBytes());
|
||||
IPAddress gateway = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(network + 1)));
|
||||
return gateway;
|
||||
}
|
||||
|
@@ -138,7 +138,7 @@ namespace linker.tun
|
||||
error = string.Empty;
|
||||
try
|
||||
{
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(address, NetworkHelper.GetPrefixIP(prefixLength));
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(prefixLength));
|
||||
CommandHelper.Linux(string.Empty, new string[] {
|
||||
$"sysctl -w net.ipv4.ip_forward=1",
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace linker.tun
|
||||
$"iptables -D FORWARD -o {Name} -m state --state ESTABLISHED,RELATED -j ACCEPT"
|
||||
});
|
||||
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(address, NetworkHelper.GetPrefixIP(prefixLength));
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(prefixLength));
|
||||
string iptableLineNumbers = CommandHelper.Linux(string.Empty, new string[] { $"iptables -t nat -L --line-numbers | grep {network}/{prefixLength} | cut -d' ' -f1" });
|
||||
if (string.IsNullOrWhiteSpace(iptableLineNumbers) == false)
|
||||
{
|
||||
@@ -223,8 +223,8 @@ namespace linker.tun
|
||||
{
|
||||
string[] commands = ips.Select(item =>
|
||||
{
|
||||
uint prefixValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(item.Address, prefixValue);
|
||||
uint prefixValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(item.Address, prefixValue);
|
||||
|
||||
return $"ip route add {network}/{item.PrefixLength} via {ip} dev {Name} metric 1 ";
|
||||
}).ToArray();
|
||||
@@ -237,8 +237,8 @@ namespace linker.tun
|
||||
{
|
||||
string[] commands = ip.Select(item =>
|
||||
{
|
||||
uint prefixValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(item.Address, prefixValue);
|
||||
uint prefixValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(item.Address, prefixValue);
|
||||
return $"ip route del {network}/{item.PrefixLength}";
|
||||
}).ToArray();
|
||||
CommandHelper.Linux(string.Empty, commands);
|
||||
|
@@ -35,7 +35,7 @@ namespace linker.tun
|
||||
safeFileHandle = File.OpenHandle($"/dev/{Name}", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous);
|
||||
fs = new FileStream(safeFileHandle, FileAccess.ReadWrite, 1500);
|
||||
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(address, NetworkHelper.GetPrefixIP(prefixLength));
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(prefixLength));
|
||||
CommandHelper.Osx(string.Empty, new string[] {
|
||||
$"route delete -net {network}/{prefixLength} {address}",
|
||||
$"ifconfig {Name} {address} {address} up",
|
||||
@@ -55,7 +55,7 @@ namespace linker.tun
|
||||
fs.Dispose();
|
||||
fs = null;
|
||||
}
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(address, NetworkHelper.GetPrefixIP(this.prefixLength));
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(this.prefixLength));
|
||||
CommandHelper.Osx(string.Empty, new string[] { $"route delete -net {network}/{prefixLength} {address}" });
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace linker.tun
|
||||
{
|
||||
string[] commands = ips.Select(item =>
|
||||
{
|
||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.Address, item.PrefixLength);
|
||||
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, item.PrefixLength);
|
||||
return $"route add -net {_ip}/{item.PrefixLength} {ip}";
|
||||
}).ToArray();
|
||||
if (commands.Length > 0)
|
||||
@@ -75,7 +75,7 @@ namespace linker.tun
|
||||
{
|
||||
string[] commands = ip.Select(item =>
|
||||
{
|
||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.Address, item.PrefixLength);
|
||||
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, item.PrefixLength);
|
||||
return $"route delete -net {_ip}/{item.PrefixLength}";
|
||||
}).ToArray();
|
||||
if (commands.Length > 0)
|
||||
|
@@ -152,7 +152,7 @@ namespace linker.tun
|
||||
try
|
||||
{
|
||||
CommandHelper.PowerShell($"start-service WinNat", [], out error);
|
||||
IPAddress network = NetworkHelper.ToNetworkIp(this.address, NetworkHelper.GetPrefixIP(prefixLength));
|
||||
IPAddress network = NetworkHelper.NetworkIP2IP(this.address, NetworkHelper.PrefixLength2Value(prefixLength));
|
||||
CommandHelper.PowerShell($"New-NetNat -Name {Name} -InternalIPInterfaceAddressPrefix {network}/{prefixLength}", [], out error);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(error) == false)
|
||||
@@ -214,9 +214,9 @@ namespace linker.tun
|
||||
{
|
||||
string[] commands = ips.Select(item =>
|
||||
{
|
||||
uint maskValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
||||
IPAddress mask = NetworkHelper.GetPrefixIp(maskValue);
|
||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.Address, maskValue);
|
||||
uint maskValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||
IPAddress mask = NetworkHelper.PrefixValue2IP(maskValue);
|
||||
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, maskValue);
|
||||
|
||||
return $"route add {_ip} mask {mask} {ip} metric 5 if {interfaceNumber}";
|
||||
}).ToArray();
|
||||
@@ -230,9 +230,9 @@ namespace linker.tun
|
||||
{
|
||||
string[] commands = ip.Select(item =>
|
||||
{
|
||||
uint maskValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
||||
IPAddress mask = NetworkHelper.GetPrefixIp(maskValue);
|
||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.Address, maskValue);
|
||||
uint maskValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||
IPAddress mask = NetworkHelper.PrefixValue2IP(maskValue);
|
||||
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, maskValue);
|
||||
return $"route delete {_ip}";
|
||||
}).ToArray();
|
||||
if (commands.Length > 0)
|
||||
|
@@ -17,9 +17,9 @@ export const getAccesss = (machineid) => {
|
||||
export const setAccess = (data) => {
|
||||
return sendWebsocketMsg('configclient/SetAccess', data);
|
||||
}
|
||||
export const setSecretKeyAsync = (data) => {
|
||||
return sendWebsocketMsg('configclient/SecretKeyAsync', data);
|
||||
export const getSyncNames = () => {
|
||||
return sendWebsocketMsg('configclient/SyncNames');
|
||||
}
|
||||
export const setServerAsync = (data) => {
|
||||
return sendWebsocketMsg('configclient/ServerAsync', data);
|
||||
export const setSync = (data) => {
|
||||
return sendWebsocketMsg('configclient/Sync', data);
|
||||
}
|
@@ -1,71 +1,81 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header flex">
|
||||
<span>同步密钥</span>
|
||||
<span class="flex-1"></span>
|
||||
<el-button type="success" @click="handleSyncSecretKey">确定同步</el-button>
|
||||
<el-card shadow="never" style="max-width: 540px;margin:0 auto;">
|
||||
<template #header>选择你需要同步的项,将这些配置同步到本组所有客户端</template>
|
||||
<div>
|
||||
<el-checkbox v-model="state.checkAll" :indeterminate="state.isIndeterminate" @change="handleCheckAllChange">全选</el-checkbox>
|
||||
<el-checkbox-group v-model="state.checkeds" @change="handleCheckedsChange">
|
||||
<el-row>
|
||||
<template v-for="name in state.names">
|
||||
<el-col :span="8">
|
||||
<el-checkbox :key="name.name" :label="name.label" :value="name.name">{{ name.label }}</el-checkbox>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="t-c">
|
||||
<el-button type="success" @click="handleSync">确定同步</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
同步,信标服务器,中继服务器,服务器代理穿透,的密钥到所有客户端
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" style="margin-top:2rem">
|
||||
<template #header>
|
||||
<div class="card-header flex">
|
||||
<span>同步服务器配置</span>
|
||||
<span class="flex-1"></span>
|
||||
<el-button type="success" @click="handleSyncServer">确定同步</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
同步,信标服务器,端口服务器,中继服务器,列表到所有客户端
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { reactive } from 'vue'
|
||||
import { setSecretKeyAsync, setServerAsync } from '@/apis/config';
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { getSyncNames, setSync } from '@/apis/config';
|
||||
export default {
|
||||
label:'同步配置',
|
||||
name:'async',
|
||||
order:7,
|
||||
setup(props) {
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({});
|
||||
const state = reactive({
|
||||
names:[],
|
||||
checkAll:false,
|
||||
isIndeterminate:false,
|
||||
checkeds:[],
|
||||
});
|
||||
|
||||
const handleSyncSecretKey = ()=>{
|
||||
|
||||
const json = {
|
||||
SignSecretKey:globalData.value.config.Client.ServerInfo.SecretKey,
|
||||
RelaySecretKey:globalData.value.config.Client.Relay.Servers[0].SecretKey,
|
||||
SForwardSecretKey:globalData.value.config.Client.SForward.SecretKey
|
||||
const handleCheckAllChange = (val)=>{
|
||||
state.checkeds = val ? state.names.map(c=>c.name) : [];
|
||||
state.isIndeterminate = false
|
||||
}
|
||||
setSecretKeyAsync(json).then(()=>{
|
||||
const handleCheckedsChange = (value)=>{
|
||||
const checkedCount = value.length
|
||||
state.checkAll = checkedCount === state.names.length
|
||||
state.isIndeterminate = checkedCount > 0 && checkedCount < state.names.length;
|
||||
}
|
||||
|
||||
const labels = {
|
||||
'SignInSecretKey':'当前信标密钥',
|
||||
'GroupSecretKey':'当前分组密码',
|
||||
'RelaySecretKey':'当前中继密钥',
|
||||
'SForwardSecretKey':'当前服务器穿透密钥',
|
||||
'UpdaterSecretKey':'服务器更新密钥',
|
||||
'TunnelTransports':'打洞协议列表'
|
||||
}
|
||||
onMounted(()=>{
|
||||
getSyncNames().then(res=>{
|
||||
state.names = res.map(c=>{
|
||||
return {name:c,label:labels[c]}
|
||||
});
|
||||
});
|
||||
});
|
||||
const handleSync = ()=>{
|
||||
if(state.checkeds.length == 0) {
|
||||
ElMessage.error('至少选择一个');
|
||||
return;
|
||||
}
|
||||
setSync(state.checkeds).then(res=>{
|
||||
ElMessage.success('已操作');
|
||||
}).catch(()=>{
|
||||
ElMessage.error('操作失败');
|
||||
});;
|
||||
}
|
||||
const handleSyncServer = ()=>{
|
||||
const json = {
|
||||
SignServers:globalData.value.config.Client.Servers,
|
||||
RelayServers:globalData.value.config.Client.Relay.Servers,
|
||||
TunnelServers:globalData.value.config.Client.Tunnel.Servers
|
||||
}
|
||||
setServerAsync(json).then(()=>{
|
||||
ElMessage.success('已操作');
|
||||
}).catch(()=>{
|
||||
ElMessage.error('操作失败');
|
||||
});;
|
||||
});
|
||||
}
|
||||
|
||||
return {state,handleSyncSecretKey,handleSyncServer}
|
||||
return {state,handleCheckAllChange,handleCheckedsChange,handleSync}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -21,13 +21,12 @@
|
||||
<Title>linker</Title>
|
||||
<Authors>snltty</Authors>
|
||||
<Company>snltty</Company>
|
||||
<Description>1. 使用原生成器替代反射
|
||||
2. 统计所有服务端,客户端数量
|
||||
3. 创建docker镜像清单,自动识别平台
|
||||
4. docker镜像增加arm
|
||||
5. 优化了arm平台下获取设备ID的方法
|
||||
6. 增加了查看流量信息的权限
|
||||
7. 有服务器更新密钥的客户端,可以更新本服务器的所有客户端</Description>
|
||||
<Description>1. 新增多分组管理,方便分组切换
|
||||
2. 增加分组密码,提高分组隔离安全性
|
||||
3. 优化配置同步,可自由选择同步哪些信息
|
||||
4. 自动分配虚拟网卡IP
|
||||
5. 线程池优化
|
||||
6. 一些UI优化</Description>
|
||||
<Copyright>snltty</Copyright>
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
|
@@ -35,6 +35,9 @@ namespace linker.plugins.client
|
||||
serviceCollection.AddSingleton<SignInArgsSecretKeyClient>();
|
||||
serviceCollection.AddSingleton<SignInArgsGroupPasswordClient>();
|
||||
|
||||
serviceCollection.AddSingleton<ConfigSyncSignInSecretKey>();
|
||||
serviceCollection.AddSingleton<ConfigSyncGroupSecretKey>();
|
||||
|
||||
}
|
||||
|
||||
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
||||
|
51
linker/plugins/client/ConfigSyncSignInSecretKey.cs
Normal file
51
linker/plugins/client/ConfigSyncSignInSecretKey.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using linker.config;
|
||||
using linker.plugins.config;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.client
|
||||
{
|
||||
public sealed class ConfigSyncSignInSecretKey : IConfigSync
|
||||
{
|
||||
public string Name => "SignInSecretKey";
|
||||
|
||||
private readonly FileConfig fileConfig;
|
||||
public ConfigSyncSignInSecretKey(FileConfig fileConfig)
|
||||
{
|
||||
this.fileConfig = fileConfig;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return MemoryPackSerializer.Serialize(fileConfig.Data.Client.Servers.FirstOrDefault().SecretKey);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
string value = MemoryPackSerializer.Deserialize<string>(data.Span);
|
||||
foreach (var item in fileConfig.Data.Client.Servers)
|
||||
{
|
||||
item.SecretKey = value;
|
||||
}
|
||||
fileConfig.Data.Update();
|
||||
}
|
||||
}
|
||||
public sealed class ConfigSyncGroupSecretKey : IConfigSync
|
||||
{
|
||||
public string Name => "GroupSecretKey";
|
||||
|
||||
private readonly FileConfig fileConfig;
|
||||
public ConfigSyncGroupSecretKey(FileConfig fileConfig)
|
||||
{
|
||||
this.fileConfig = fileConfig;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return MemoryPackSerializer.Serialize(fileConfig.Data.Client.Group.Password);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
fileConfig.Data.Client.Group.Password = MemoryPackSerializer.Deserialize<string>(data.Span);
|
||||
fileConfig.Data.Update();
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,7 +6,6 @@ using MemoryPack;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace linker.client.config
|
||||
{
|
||||
@@ -209,10 +208,6 @@ namespace linker.config
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public string SecretKey { get; set; } = string.Empty;
|
||||
|
||||
public string ToStr()
|
||||
{
|
||||
return $"{Host}-{SecretKey}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -225,15 +225,23 @@ namespace linker.plugins.config
|
||||
}
|
||||
|
||||
|
||||
public List<ConfigSyncNameInfo> SyncNames(ApiControllerParamsInfo param)
|
||||
public List<string> SyncNames(ApiControllerParamsInfo param)
|
||||
{
|
||||
return configSyncTreansfer.GetNames();
|
||||
}
|
||||
[ClientApiAccessAttribute(ClientApiAccess.Sync)]
|
||||
public bool Sync(ApiControllerParamsInfo param)
|
||||
public async Task<bool> Sync(ApiControllerParamsInfo param)
|
||||
{
|
||||
string[] names = param.Content.DeJson<string[]>();
|
||||
if (names.Length == 1)
|
||||
{
|
||||
await configSyncTreansfer.Sync(names[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
configSyncTreansfer.Sync(names);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,6 @@ namespace linker.plugins.config
|
||||
public interface IConfigSync
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Label { get; }
|
||||
public Memory<byte> GetData();
|
||||
public void SetData(Memory<byte> data);
|
||||
}
|
||||
@@ -23,11 +22,6 @@ namespace linker.plugins.config
|
||||
public Memory<byte> Data { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ConfigSyncNameInfo
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Label { get; set; } = string.Empty;
|
||||
}
|
||||
public sealed partial class ConfigSyncTreansfer
|
||||
{
|
||||
private readonly SemaphoreSlim slim = new SemaphoreSlim(1);
|
||||
@@ -45,9 +39,9 @@ namespace linker.plugins.config
|
||||
LoggerHelper.Instance.Info($"load config sync transport:{string.Join(",", syncs.Select(c => c.Name))}");
|
||||
}
|
||||
|
||||
public List<ConfigSyncNameInfo> GetNames()
|
||||
public List<string> GetNames()
|
||||
{
|
||||
return syncs.Select(c => new ConfigSyncNameInfo { Label = c.Label, Name = c.Name }).ToList();
|
||||
return syncs.Select(c => c.Name).ToList();
|
||||
}
|
||||
|
||||
public void Sync(string[] names)
|
||||
@@ -63,7 +57,7 @@ namespace linker.plugins.config
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)ConfigMessengerIds.SyncForward,
|
||||
Payload = c.GetData(),
|
||||
Payload = MemoryPackSerializer.Serialize(new ConfigAsyncInfo { Name = c.Name, Data = c.GetData() }),
|
||||
|
||||
});
|
||||
});
|
||||
@@ -75,6 +69,19 @@ namespace linker.plugins.config
|
||||
slim.Release();
|
||||
});
|
||||
}
|
||||
public async Task Sync(string name)
|
||||
{
|
||||
var sync = syncs.FirstOrDefault(c => c.Name == name);
|
||||
if(sync != null)
|
||||
{
|
||||
await messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)ConfigMessengerIds.SyncForward,
|
||||
Payload = MemoryPackSerializer.Serialize(new ConfigAsyncInfo { Name = sync.Name, Data = sync.GetData() }),
|
||||
});
|
||||
}
|
||||
}
|
||||
public void Sync(ConfigAsyncInfo info)
|
||||
{
|
||||
var sync = syncs.FirstOrDefault(c => c.Name == info.Name);
|
||||
|
31
linker/plugins/relay/ConfigSyncRelaySecretKey.cs
Normal file
31
linker/plugins/relay/ConfigSyncRelaySecretKey.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using linker.config;
|
||||
using linker.plugins.config;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.relay
|
||||
{
|
||||
public sealed class ConfigSyncRelaySecretKey : IConfigSync
|
||||
{
|
||||
public string Name => "RelaySecretKey";
|
||||
|
||||
private readonly FileConfig fileConfig;
|
||||
public ConfigSyncRelaySecretKey(FileConfig fileConfig)
|
||||
{
|
||||
this.fileConfig = fileConfig;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return MemoryPackSerializer.Serialize(fileConfig.Data.Client.Relay.Servers.FirstOrDefault().SecretKey);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
string value = MemoryPackSerializer.Deserialize<string>(data.Span);
|
||||
foreach (var item in fileConfig.Data.Client.Relay.Servers)
|
||||
{
|
||||
item.SecretKey = value;
|
||||
}
|
||||
fileConfig.Data.Update();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
using linker.config;
|
||||
using linker.plugins.relay.messenger;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.plugins.client;
|
||||
|
@@ -29,6 +29,8 @@ namespace linker.plugins.relay
|
||||
serviceCollection.AddSingleton<RelayTransfer>();
|
||||
serviceCollection.AddSingleton<RelayFlow>();
|
||||
|
||||
serviceCollection.AddSingleton<ConfigSyncRelaySecretKey>();
|
||||
|
||||
}
|
||||
|
||||
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||
|
27
linker/plugins/sforward/ConfigSyncSForwardSecretKey.cs
Normal file
27
linker/plugins/sforward/ConfigSyncSForwardSecretKey.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using linker.config;
|
||||
using linker.plugins.config;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.sforward
|
||||
{
|
||||
public sealed class ConfigSyncSForwardSecretKey : IConfigSync
|
||||
{
|
||||
public string Name => "SForwardSecretKey";
|
||||
|
||||
private readonly FileConfig fileConfig;
|
||||
public ConfigSyncSForwardSecretKey(FileConfig fileConfig)
|
||||
{
|
||||
this.fileConfig = fileConfig;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return MemoryPackSerializer.Serialize(fileConfig.Data.Client.SForward.SecretKey);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
fileConfig.Data.Client.SForward.SecretKey = MemoryPackSerializer.Deserialize<string>(data.Span);
|
||||
fileConfig.Data.Update();
|
||||
}
|
||||
}
|
||||
}
|
@@ -30,6 +30,8 @@ namespace linker.plugins.sforward
|
||||
|
||||
serviceCollection.AddSingleton<SForwardFlow>();
|
||||
|
||||
serviceCollection.AddSingleton<ConfigSyncSForwardSecretKey>();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@@ -405,8 +405,8 @@ namespace linker.plugins.sforward.messenger
|
||||
if (sForwardInfo.RemotePortMin != 0 && sForwardInfo.RemotePortMax != 0)
|
||||
{
|
||||
uint plus = (uint)(sForwardProxyInfo.RemotePort - sForwardInfo.RemotePortMin);
|
||||
uint newIP = BinaryPrimitives.ReadUInt32BigEndian(localEP.Address.GetAddressBytes()) + plus;
|
||||
localEP.Address = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(newIP)));
|
||||
uint newIP = NetworkHelper.IP2Value(localEP.Address) + plus;
|
||||
localEP.Address = NetworkHelper.Value2IP(newIP);
|
||||
}
|
||||
return localEP;
|
||||
}
|
||||
|
@@ -129,7 +129,7 @@ namespace linker.plugins.signin.messenger
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
var groups = Clients.Values.GroupBy(c => c.GroupId)
|
||||
.Where(group => group.All(info => info.Connected == false && (now - info.LastSignIn).TotalMilliseconds > 7 * 24 * 60 * 60 * 1000))
|
||||
.Where(group => group.All(info => info.Connected == false && (now - info.LastSignIn).TotalDays > 7))
|
||||
.Select(group => group.Key).ToList();
|
||||
|
||||
if (groups.Count > 0)
|
||||
|
28
linker/plugins/tunnel/ConfigSyncTunnelTransports.cs
Normal file
28
linker/plugins/tunnel/ConfigSyncTunnelTransports.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using linker.config;
|
||||
using linker.plugins.config;
|
||||
using linker.tunnel.transport;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.tunnel
|
||||
{
|
||||
public sealed class ConfigSyncTunnelTransports : IConfigSync
|
||||
{
|
||||
public string Name => "TunnelTransports";
|
||||
|
||||
private readonly FileConfig fileConfig;
|
||||
public ConfigSyncTunnelTransports(FileConfig fileConfig)
|
||||
{
|
||||
this.fileConfig = fileConfig;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return MemoryPackSerializer.Serialize(fileConfig.Data.Client.Tunnel.Transports);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
fileConfig.Data.Client.Tunnel.Transports = MemoryPackSerializer.Deserialize<List<TunnelTransportItemInfo>>(data.Span);
|
||||
fileConfig.Data.Update();
|
||||
}
|
||||
}
|
||||
}
|
@@ -79,11 +79,11 @@ namespace linker.plugins.tunnel
|
||||
{
|
||||
if (c.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
||||
{
|
||||
uint ip = BinaryPrimitives.ReadUInt32BigEndian(c.GetAddressBytes());
|
||||
uint ip = NetworkHelper.IP2Value(c);
|
||||
foreach (var item in excludeips)
|
||||
{
|
||||
uint maskValue = NetworkHelper.GetPrefixIP(item.Mask);
|
||||
uint ip1 = BinaryPrimitives.ReadUInt32BigEndian(item.IPAddress.GetAddressBytes());
|
||||
uint maskValue = NetworkHelper.PrefixLength2Value(item.Mask);
|
||||
uint ip1 = NetworkHelper.IP2Value(item.IPAddress);
|
||||
if ((ip & maskValue) == (ip1 & maskValue))
|
||||
{
|
||||
return false;
|
||||
|
@@ -65,6 +65,8 @@ namespace linker.plugins.tunnel
|
||||
|
||||
serviceCollection.AddSingleton<TunnelUpnpTransfer>();
|
||||
|
||||
serviceCollection.AddSingleton<ConfigSyncTunnelTransports>();
|
||||
|
||||
LoggerHelper.Instance.Info($"tunnel route level getting.");
|
||||
config.Data.Client.Tunnel.RouteLevel = NetworkHelper.GetRouteLevel(config.Data.Client.ServerInfo.Host, out List<IPAddress> ips);
|
||||
config.Data.Client.Tunnel.RouteIPs = ips.ToArray();
|
||||
|
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace linker.plugins.tuntap
|
||||
{
|
||||
public sealed class DHCPTreansfer
|
||||
{
|
||||
public void AddNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IPAddress GetIP()
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using linker.config;
|
||||
using linker.plugins.tuntap.client;
|
||||
using linker.plugins.tuntap.lease;
|
||||
using linker.plugins.tuntap.messenger;
|
||||
using linker.startup;
|
||||
using linker.tun;
|
||||
@@ -37,6 +38,8 @@ namespace linker.plugins.tuntap
|
||||
{
|
||||
serviceCollection.AddSingleton<TuntapServerMessenger>();
|
||||
|
||||
serviceCollection.AddSingleton<LeaseServerTreansfer>();
|
||||
|
||||
}
|
||||
|
||||
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
||||
@@ -47,6 +50,7 @@ namespace linker.plugins.tuntap
|
||||
|
||||
public void UseServer(ServiceProvider serviceProvider, FileConfig config)
|
||||
{
|
||||
LeaseServerTreansfer leaseTreansfer = serviceProvider.GetService<LeaseServerTreansfer>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,9 +50,9 @@ namespace linker.plugins.tuntap.client
|
||||
}
|
||||
}).Select(c =>
|
||||
{
|
||||
uint maskValue = NetworkHelper.GetPrefixIP(c.PrefixLength);
|
||||
IPAddress mask = NetworkHelper.GetPrefixIp(maskValue);
|
||||
IPAddress _ip = NetworkHelper.ToNetworkIp(c.Address, maskValue);
|
||||
uint maskValue = NetworkHelper.PrefixLength2Value(c.PrefixLength);
|
||||
IPAddress mask = NetworkHelper.PrefixValue2IP(maskValue);
|
||||
IPAddress _ip = NetworkHelper.NetworkIP2IP(c.Address, maskValue);
|
||||
return new
|
||||
{
|
||||
IP = c.Address,
|
||||
|
@@ -92,6 +92,7 @@ namespace linker.plugins.tuntap.client
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 运行网卡
|
||||
/// </summary>
|
||||
@@ -424,7 +425,7 @@ namespace linker.plugins.tuntap.client
|
||||
tuntapProxy.SetIPs(ips);
|
||||
foreach (var item in tuntapInfos.Values)
|
||||
{
|
||||
tuntapProxy.SetIP(item.MachineId, BinaryPrimitives.ReadUInt32BigEndian(item.IP.GetAddressBytes()));
|
||||
tuntapProxy.SetIP(item.MachineId, NetworkHelper.IP2Value(item.IP));
|
||||
}
|
||||
CheckLanIPs();
|
||||
}
|
||||
@@ -464,7 +465,7 @@ namespace linker.plugins.tuntap.client
|
||||
.Concat(runningConfig.Data.Tuntap.LanIPs.Where(c => c != null))
|
||||
//路由上的IP
|
||||
.Concat(config.Data.Client.Tunnel.RouteIPs)
|
||||
.Select(c => BinaryPrimitives.ReadUInt32BigEndian(c.GetAddressBytes()))
|
||||
.Select(c => NetworkHelper.IP2Value(c))
|
||||
.ToArray();
|
||||
}
|
||||
private List<TuntapVeaLanIPAddressList> ParseIPs(List<TuntapInfo> infos)
|
||||
@@ -496,9 +497,9 @@ namespace linker.plugins.tuntap.client
|
||||
}
|
||||
private TuntapVeaLanIPAddress ParseIPAddress(IPAddress ip, byte maskLength, string machineid)
|
||||
{
|
||||
uint ipInt = BinaryPrimitives.ReadUInt32BigEndian(ip.GetAddressBytes());
|
||||
uint ipInt = NetworkHelper.IP2Value(ip);
|
||||
//掩码十进制
|
||||
uint maskValue = NetworkHelper.GetPrefixIP(maskLength);
|
||||
uint maskValue = NetworkHelper.PrefixLength2Value(maskLength);
|
||||
return new TuntapVeaLanIPAddress
|
||||
{
|
||||
IPAddress = ipInt,
|
||||
|
46
linker/plugins/tuntap/lease/LeaseClientTreansfer.cs
Normal file
46
linker/plugins/tuntap/lease/LeaseClientTreansfer.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using linker.store;
|
||||
using LiteDB;
|
||||
using System.Net;
|
||||
using linker.libs;
|
||||
using MemoryPack;
|
||||
using System.Collections.Concurrent;
|
||||
using linker.plugins.client;
|
||||
using linker.plugins.messenger;
|
||||
using linker.plugins.tuntap.messenger;
|
||||
using linker.client.config;
|
||||
|
||||
namespace linker.plugins.tuntap.lease
|
||||
{
|
||||
public sealed class LeaseClientTreansfer
|
||||
{
|
||||
private readonly MessengerSender messengerSender;
|
||||
private readonly ClientSignInState clientSignInState;
|
||||
private readonly RunningConfig runningConfig;
|
||||
|
||||
public LeaseClientTreansfer(MessengerSender messengerSender, ClientSignInState clientSignInState, RunningConfig runningConfig)
|
||||
{
|
||||
this.messengerSender = messengerSender;
|
||||
this.clientSignInState = clientSignInState;
|
||||
this.runningConfig = runningConfig;
|
||||
}
|
||||
public async Task<IPAddress> LeaseIp()
|
||||
{
|
||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = clientSignInState.Connection,
|
||||
MessengerId = (ushort)TuntapMessengerIds.Lease,
|
||||
Payload = MemoryPackSerializer.Serialize(runningConfig.Data.Tuntap.IP)
|
||||
|
||||
});
|
||||
if(resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
IPAddress ip = MemoryPackSerializer.Deserialize<IPAddress>(resp.Data.Span);
|
||||
if (ip.Equals(IPAddress.Any) == false)
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
}
|
||||
return runningConfig.Data.Tuntap.IP;
|
||||
}
|
||||
}
|
||||
}
|
283
linker/plugins/tuntap/lease/LeaseServerTreansfer.cs
Normal file
283
linker/plugins/tuntap/lease/LeaseServerTreansfer.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
using linker.store;
|
||||
using LiteDB;
|
||||
using System.Net;
|
||||
using linker.libs;
|
||||
using MemoryPack;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace linker.plugins.tuntap.lease
|
||||
{
|
||||
public sealed class LeaseServerTreansfer
|
||||
{
|
||||
private readonly Storefactory dBfactory;
|
||||
private readonly ILiteCollection<LeaseCacheInfo> liteCollection;
|
||||
|
||||
private ConcurrentDictionary<string, LeaseCacheInfo> caches { get; set; } = new ConcurrentDictionary<string, LeaseCacheInfo>();
|
||||
|
||||
public LeaseServerTreansfer(Storefactory dBfactory)
|
||||
{
|
||||
this.dBfactory = dBfactory;
|
||||
liteCollection = dBfactory.GetCollection<LeaseCacheInfo>("dhcp");
|
||||
foreach (var item in liteCollection.FindAll())
|
||||
{
|
||||
caches.TryAdd(item.Key, item);
|
||||
}
|
||||
ClearTask();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加网络配置
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="info"></param>
|
||||
public void Add(string key, LeaseInfo info)
|
||||
{
|
||||
if (info.PrefixLength < 16 || info.PrefixLength >= 32)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (caches.TryGetValue(key, out LeaseCacheInfo cache) == false)
|
||||
{
|
||||
cache = new LeaseCacheInfo { Key = key };
|
||||
cache.Id = ObjectId.NewObjectId();
|
||||
liteCollection.Insert(cache);
|
||||
caches.TryAdd(key, cache);
|
||||
}
|
||||
|
||||
uint oldIP = cache.IP;
|
||||
uint oldPrefix = cache.PrefixValue;
|
||||
|
||||
cache.IP = NetworkHelper.IP2Value(info.IP);
|
||||
cache.PrefixValue = NetworkHelper.PrefixLength2Value((byte)info.PrefixLength);
|
||||
|
||||
//网络配置有变化,清理分配,让他们重新申请
|
||||
if (oldIP != cache.IP || oldPrefix != cache.PrefixValue)
|
||||
{
|
||||
cache.Users.Clear();
|
||||
}
|
||||
|
||||
liteCollection.Update(cache);
|
||||
dBfactory.Confirm();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取配置
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public LeaseInfo Get(string key)
|
||||
{
|
||||
if (caches.TryGetValue(key, out LeaseCacheInfo cache) == false)
|
||||
{
|
||||
cache = new LeaseCacheInfo { Key = key };
|
||||
}
|
||||
return new LeaseInfo { IP = NetworkHelper.Value2IP(cache.IP), PrefixLength = NetworkHelper.PrefixValue2Length(cache.PrefixValue) };
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 租赁
|
||||
/// </summary>
|
||||
/// <param name="userId">用户id</param>
|
||||
/// <param name="key">配置项</param>
|
||||
/// <param name="ip">静态IP</param>
|
||||
/// <returns>两种种结果,0.0.0.0 和 ip</returns>
|
||||
public IPAddress Lease(string userId, string key, IPAddress ip)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key) || caches.TryGetValue(key, out LeaseCacheInfo cache) == false)
|
||||
{
|
||||
return ip;
|
||||
}
|
||||
|
||||
lock (cache)
|
||||
{
|
||||
IPAddress result = IPAddress.Any;
|
||||
|
||||
if (ip.Equals(IPAddress.Any) == false)
|
||||
{
|
||||
result = StaticIP(userId, ip, cache);
|
||||
}
|
||||
if (result.Equals(IPAddress.Any))
|
||||
{
|
||||
result = DynamicIP(userId, cache);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
private IPAddress StaticIP(string userId, IPAddress ip, LeaseCacheInfo cache)
|
||||
{
|
||||
uint value = NetworkHelper.IP2Value(ip);
|
||||
//不是同一个网络
|
||||
if (NetworkHelper.NetworkValue2Value(value, cache.PrefixValue) != NetworkHelper.NetworkValue2Value(cache.IP, cache.PrefixValue))
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
|
||||
LeaseCacheUserInfo self = cache.Users.FirstOrDefault(c => c.Id == userId);
|
||||
LeaseCacheUserInfo other = cache.Users.FirstOrDefault(c => c.IP == value && c.Id != userId);
|
||||
|
||||
//这个IP没人用
|
||||
if (other == null)
|
||||
{
|
||||
//我自己有记录,更新IP即可
|
||||
if (self != null)
|
||||
{
|
||||
self.IP = value;
|
||||
self.LastTime = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache.Users.Add(new LeaseCacheUserInfo { Id = userId, IP = value, LastTime = DateTime.Now });
|
||||
}
|
||||
liteCollection.Update(cache);
|
||||
dBfactory.Confirm();
|
||||
}
|
||||
//有人用
|
||||
else
|
||||
{
|
||||
//用之前申请到的IP
|
||||
if (self != null)
|
||||
{
|
||||
return NetworkHelper.Value2IP(self.IP);
|
||||
}
|
||||
//对方没过期,那就不能申占用了
|
||||
if ((DateTime.Now - other.LastTime).Days <= 7)
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
|
||||
other.IP = value;
|
||||
other.LastTime = DateTime.Now;
|
||||
other.Id = userId;
|
||||
liteCollection.Update(cache);
|
||||
dBfactory.Confirm();
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
private IPAddress DynamicIP(string userId, LeaseCacheInfo cache)
|
||||
{
|
||||
//网络号
|
||||
uint network = NetworkHelper.NetworkValue2Value(cache.IP, cache.PrefixValue);
|
||||
//广播
|
||||
uint broadcast = NetworkHelper.BroadcastValue2Value(cache.IP, cache.PrefixValue);
|
||||
//第一个可用IP
|
||||
uint firstValue = network + 1;
|
||||
//最后一个可用IP
|
||||
uint lastValue = broadcast - 1;
|
||||
//IP数
|
||||
uint length = lastValue - network;
|
||||
|
||||
IEnumerable<int> ips = Enumerable.Range((int)firstValue, (int)length + 1).Except(cache.Users.Select(c => (int)c.IP));
|
||||
if (ips.Any() == false)
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
|
||||
uint ipValue = (uint)ips.FirstOrDefault();
|
||||
cache.Users.Add(new LeaseCacheUserInfo { Id = userId, IP = ipValue, LastTime = DateTime.Now });
|
||||
liteCollection.Update(cache);
|
||||
dBfactory.Confirm();
|
||||
|
||||
return NetworkHelper.Value2IP(ipValue);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 租期
|
||||
/// </summary>
|
||||
/// <param name="userid"></param>
|
||||
/// <param name="key"></param>
|
||||
public void LeaseExp(string userid, string key)
|
||||
{
|
||||
if (caches.TryGetValue(key, out LeaseCacheInfo cache))
|
||||
{
|
||||
cache.LastTime = DateTime.Now;
|
||||
LeaseCacheUserInfo user = cache.Users.FirstOrDefault(c => c.Id == userid);
|
||||
if (user != null)
|
||||
{
|
||||
user.LastTime = DateTime.Now;
|
||||
}
|
||||
liteCollection.Update(cache);
|
||||
dBfactory.Confirm();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearTask()
|
||||
{
|
||||
TimerHelper.SetInterval(() =>
|
||||
{
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
LoggerHelper.Instance.Debug($"start cleaning up dhcp that have exceeded the 30-day timeout period");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
var items = caches.Values.Where(c => (now - c.LastTime).TotalDays > 30).ToList();
|
||||
if (items.Count > 0)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
caches.TryRemove(item.Key, out _);
|
||||
liteCollection.Delete(item.Id);
|
||||
}
|
||||
dBfactory.Confirm();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Debug($"cleaning up dhcp error {ex}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}, 5 * 60 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial class LeaseInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 网络号
|
||||
/// </summary>
|
||||
[MemoryPackAllowSerialize]
|
||||
public IPAddress IP { get; set; } = IPAddress.Any;
|
||||
/// <summary>
|
||||
/// 前缀,掩码长度
|
||||
/// </summary>
|
||||
public int PrefixLength { get; set; } = 32;
|
||||
}
|
||||
|
||||
public sealed class LeaseCacheInfo
|
||||
{
|
||||
public ObjectId Id { get; set; }
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 网络号
|
||||
/// </summary>
|
||||
public uint IP { get; set; }
|
||||
/// <summary>
|
||||
/// 前缀,掩码
|
||||
/// </summary>
|
||||
public uint PrefixValue { get; set; }
|
||||
/// <summary>
|
||||
/// 最后活动时间
|
||||
/// </summary>
|
||||
public DateTime LastTime { get; set; } = DateTime.Now;
|
||||
|
||||
public List<LeaseCacheUserInfo> Users { get; set; } = new List<LeaseCacheUserInfo>();
|
||||
}
|
||||
|
||||
public sealed class LeaseCacheUserInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public uint IP { get; set; }
|
||||
public DateTime LastTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
@@ -3,7 +3,9 @@ using linker.plugins.messenger;
|
||||
using linker.plugins.signin.messenger;
|
||||
using linker.plugins.tuntap.client;
|
||||
using linker.plugins.tuntap.config;
|
||||
using linker.plugins.tuntap.lease;
|
||||
using MemoryPack;
|
||||
using System.Net;
|
||||
|
||||
namespace linker.plugins.tuntap.messenger
|
||||
{
|
||||
@@ -61,6 +63,14 @@ namespace linker.plugins.tuntap.messenger
|
||||
connection.Write(MemoryPackSerializer.Serialize(_info));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新租赁
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
[MessengerId((ushort)TuntapMessengerIds.LeaseChange)]
|
||||
public void LeaseChange(IConnection connection)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,12 +79,14 @@ namespace linker.plugins.tuntap.messenger
|
||||
private readonly MessengerSender messengerSender;
|
||||
private readonly SignCaching signCaching;
|
||||
private readonly FileConfig config;
|
||||
private readonly LeaseServerTreansfer leaseTreansfer;
|
||||
|
||||
public TuntapServerMessenger(MessengerSender messengerSender, SignCaching signCaching, FileConfig config)
|
||||
public TuntapServerMessenger(MessengerSender messengerSender, SignCaching signCaching, FileConfig config, LeaseServerTreansfer leaseTreansfer)
|
||||
{
|
||||
this.messengerSender = messengerSender;
|
||||
this.signCaching = signCaching;
|
||||
this.config = config;
|
||||
this.leaseTreansfer = leaseTreansfer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -179,5 +191,71 @@ namespace linker.plugins.tuntap.messenger
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加网络配置
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
/// <returns></returns>
|
||||
[MessengerId((ushort)TuntapMessengerIds.LeaseAdd)]
|
||||
public void LeaseAdd(IConnection connection)
|
||||
{
|
||||
LeaseInfo info = MemoryPackSerializer.Deserialize<LeaseInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||
{
|
||||
leaseTreansfer.Add(cache.GroupId, info);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加网络配置
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
/// <returns></returns>
|
||||
[MessengerId((ushort)TuntapMessengerIds.LeaseGet)]
|
||||
public void LeaseGet(IConnection connection)
|
||||
{
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||
{
|
||||
connection.Write(MemoryPackSerializer.Serialize(leaseTreansfer.Get(cache.GroupId)));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 租赁IP
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
/// <returns></returns>
|
||||
[MessengerId((ushort)TuntapMessengerIds.Lease)]
|
||||
public void Lease(IConnection connection)
|
||||
{
|
||||
IPAddress info = MemoryPackSerializer.Deserialize<IPAddress>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||
{
|
||||
IPAddress result = leaseTreansfer.Lease(cache.MachineId, cache.GroupId, info);
|
||||
connection.Write(MemoryPackSerializer.Serialize(result));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 网络配置发生变化,需要重新租赁
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
[MessengerId((ushort)TuntapMessengerIds.LeaseChangeForward)]
|
||||
public void LeaseChangeForward(IConnection connection)
|
||||
{
|
||||
TuntapInfo tuntapInfo = MemoryPackSerializer.Deserialize<TuntapInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||
{
|
||||
uint requiestid = connection.ReceiveRequestWrap.RequestId;
|
||||
|
||||
List<SignCacheInfo> caches = signCaching.Get(cache.GroupId);
|
||||
IEnumerable<Task<bool>> tasks = caches.Where(c => c.MachineId != connection.Id && c.Connected).Select(c => messengerSender.SendOnly(new MessageRequestWrap
|
||||
{
|
||||
Connection = c.Connection,
|
||||
MessengerId = (ushort)TuntapMessengerIds.Config,
|
||||
Payload = connection.ReceiveRequestWrap.Payload,
|
||||
Timeout = 1000,
|
||||
}));
|
||||
Task.WhenAll(tasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,13 @@
|
||||
Config = 2206,
|
||||
ConfigForward = 2207,
|
||||
|
||||
|
||||
LeaseAdd = 2208,
|
||||
LeaseGet = 2209,
|
||||
Lease = 2210,
|
||||
LeaseChange = 2211,
|
||||
LeaseChangeForward = 2212,
|
||||
|
||||
None = 2299
|
||||
}
|
||||
}
|
||||
|
27
linker/plugins/updater/ConfigSyncUpdaterSecretKey.cs
Normal file
27
linker/plugins/updater/ConfigSyncUpdaterSecretKey.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using linker.config;
|
||||
using linker.plugins.config;
|
||||
using MemoryPack;
|
||||
|
||||
namespace linker.plugins.updater
|
||||
{
|
||||
public sealed class ConfigSyncUpdaterSecretKey : IConfigSync
|
||||
{
|
||||
public string Name => "UpdaterSecretKey";
|
||||
|
||||
private readonly FileConfig fileConfig;
|
||||
public ConfigSyncUpdaterSecretKey(FileConfig fileConfig)
|
||||
{
|
||||
this.fileConfig = fileConfig;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return MemoryPackSerializer.Serialize(fileConfig.Data.Client.Updater.SecretKey);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
fileConfig.Data.Client.Updater.SecretKey = MemoryPackSerializer.Deserialize<string>(data.Span);
|
||||
fileConfig.Data.Update();
|
||||
}
|
||||
}
|
||||
}
|
@@ -27,6 +27,8 @@ namespace linker.plugins.updater
|
||||
|
||||
serviceCollection.AddSingleton<UpdaterClientMessenger>();
|
||||
serviceCollection.AddSingleton<UpdaterClientApiController>();
|
||||
|
||||
serviceCollection.AddSingleton<ConfigSyncUpdaterSecretKey>();
|
||||
}
|
||||
|
||||
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||
|
15
version.txt
15
version.txt
@@ -1,9 +1,8 @@
|
||||
v1.4.9
|
||||
2024-10-16 17:33:40
|
||||
1. 使用原生成器替代反射
|
||||
2. 统计所有服务端,客户端数量
|
||||
3. 创建docker镜像清单,自动识别平台
|
||||
4. docker镜像增加arm
|
||||
5. 优化了arm平台下获取设备ID的方法
|
||||
6. 增加了查看流量信息的权限
|
||||
7. 有服务器更新密钥的客户端,可以更新本服务器的所有客户端
|
||||
2024-10-17 17:30:30
|
||||
1. 新增多分组管理,方便分组切换
|
||||
2. 增加分组密码,提高分组隔离安全性
|
||||
3. 优化配置同步,可自由选择同步哪些信息
|
||||
4. 自动分配虚拟网卡IP
|
||||
5. 线程池优化
|
||||
6. 一些UI优化
|
Reference in New Issue
Block a user