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 }}
|
release_name: v1.4.9.${{ steps.date.outputs.today }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: 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
|
- name: upload-win-x86-oss
|
||||||
id: upload-win-x86-oss
|
id: upload-win-x86-oss
|
||||||
uses: tvrcgo/oss-action@v0.1.1
|
uses: tvrcgo/oss-action@v0.1.1
|
||||||
|
@@ -37,6 +37,9 @@
|
|||||||
- [x] 权限管理,主客户端拥有完全权限,可导出、配置子客户端配置,分配其管理权限
|
- [x] 权限管理,主客户端拥有完全权限,可导出、配置子客户端配置,分配其管理权限
|
||||||
- [x] 自定义验证,通过`HTTP POST`让你可以自定义认证是否允许`连接信标`,`中继`,`内网穿透`
|
- [x] 自定义验证,通过`HTTP POST`让你可以自定义认证是否允许`连接信标`,`中继`,`内网穿透`
|
||||||
- [x] 流量统计,统计服务器`信标`、`中继`、`内网穿透` 的流量情况
|
- [x] 流量统计,统计服务器`信标`、`中继`、`内网穿透` 的流量情况
|
||||||
|
- [ ] 网络配置,主客户端设置网络,所有客户端自动分配IP
|
||||||
|
- [ ] 分布式,中继,内网穿透分布式,可实现负载均衡
|
||||||
|
|
||||||
|
|
||||||
## 界面预览
|
## 界面预览
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
sidebar_position: 5
|
sidebar_position: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
# 5、组网权限
|
# 5、导出配置和管理权限
|
||||||
|
|
||||||
:::tip[说明]
|
:::tip[说明]
|
||||||
1. 按 <a href="../2、首次运行/2.1、安装">首次运行,安装</a>,此设备拥有完全管理权限,可导出配置,用以作为组网子设备运行
|
1. 按 <a href="../2、首次运行/2.1、安装">首次运行,安装</a>,此设备拥有完全管理权限,可导出配置,用以作为组网子设备运行
|
@@ -157,7 +157,8 @@ namespace linker.libs
|
|||||||
return Array.Empty<IPAddress>();
|
return Array.Empty<IPAddress>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte GetPrefixLength(uint ip)
|
|
||||||
|
public static byte PrefixValue2Length(uint ip)
|
||||||
{
|
{
|
||||||
byte maskLength = 32;
|
byte maskLength = 32;
|
||||||
for (int i = 0; i < sizeof(uint); i++)
|
for (int i = 0; i < sizeof(uint); i++)
|
||||||
@@ -170,34 +171,60 @@ namespace linker.libs
|
|||||||
}
|
}
|
||||||
return maskLength;
|
return maskLength;
|
||||||
}
|
}
|
||||||
|
public static uint PrefixLength2Value(byte prefixLength)
|
||||||
public static uint GetPrefixIP(byte prefixLength)
|
|
||||||
{
|
{
|
||||||
//最多<<31 所以0需要单独计算
|
//最多<<31 所以0需要单独计算
|
||||||
if (prefixLength < 1) return 0;
|
if (prefixLength < 1) return 0;
|
||||||
return 0xffffffff << (32 - prefixLength);
|
return 0xffffffff << (32 - prefixLength);
|
||||||
}
|
}
|
||||||
public static IPAddress GetPrefixIp(uint prefixIP)
|
public static IPAddress PrefixValue2IP(uint prefixIP)
|
||||||
{
|
{
|
||||||
return new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(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());
|
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)
|
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)));
|
IPAddress gateway = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(network + 1)));
|
||||||
return gateway;
|
return gateway;
|
||||||
}
|
}
|
||||||
public static IPAddress ToGatewayIP(uint ip, uint prefixIP)
|
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)));
|
IPAddress gateway = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(network + 1)));
|
||||||
return gateway;
|
return gateway;
|
||||||
}
|
}
|
||||||
|
@@ -138,7 +138,7 @@ namespace linker.tun
|
|||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IPAddress network = NetworkHelper.ToNetworkIp(address, NetworkHelper.GetPrefixIP(prefixLength));
|
IPAddress network = NetworkHelper.NetworkIP2IP(address, NetworkHelper.PrefixLength2Value(prefixLength));
|
||||||
CommandHelper.Linux(string.Empty, new string[] {
|
CommandHelper.Linux(string.Empty, new string[] {
|
||||||
$"sysctl -w net.ipv4.ip_forward=1",
|
$"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"
|
$"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" });
|
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)
|
if (string.IsNullOrWhiteSpace(iptableLineNumbers) == false)
|
||||||
{
|
{
|
||||||
@@ -223,8 +223,8 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
string[] commands = ips.Select(item =>
|
string[] commands = ips.Select(item =>
|
||||||
{
|
{
|
||||||
uint prefixValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
uint prefixValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||||
IPAddress network = NetworkHelper.ToNetworkIp(item.Address, prefixValue);
|
IPAddress network = NetworkHelper.NetworkIP2IP(item.Address, prefixValue);
|
||||||
|
|
||||||
return $"ip route add {network}/{item.PrefixLength} via {ip} dev {Name} metric 1 ";
|
return $"ip route add {network}/{item.PrefixLength} via {ip} dev {Name} metric 1 ";
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
@@ -237,8 +237,8 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
string[] commands = ip.Select(item =>
|
string[] commands = ip.Select(item =>
|
||||||
{
|
{
|
||||||
uint prefixValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
uint prefixValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||||
IPAddress network = NetworkHelper.ToNetworkIp(item.Address, prefixValue);
|
IPAddress network = NetworkHelper.NetworkIP2IP(item.Address, prefixValue);
|
||||||
return $"ip route del {network}/{item.PrefixLength}";
|
return $"ip route del {network}/{item.PrefixLength}";
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
CommandHelper.Linux(string.Empty, commands);
|
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);
|
safeFileHandle = File.OpenHandle($"/dev/{Name}", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous);
|
||||||
fs = new FileStream(safeFileHandle, FileAccess.ReadWrite, 1500);
|
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[] {
|
CommandHelper.Osx(string.Empty, new string[] {
|
||||||
$"route delete -net {network}/{prefixLength} {address}",
|
$"route delete -net {network}/{prefixLength} {address}",
|
||||||
$"ifconfig {Name} {address} {address} up",
|
$"ifconfig {Name} {address} {address} up",
|
||||||
@@ -55,7 +55,7 @@ namespace linker.tun
|
|||||||
fs.Dispose();
|
fs.Dispose();
|
||||||
fs = null;
|
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}" });
|
CommandHelper.Osx(string.Empty, new string[] { $"route delete -net {network}/{prefixLength} {address}" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
string[] commands = ips.Select(item =>
|
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}";
|
return $"route add -net {_ip}/{item.PrefixLength} {ip}";
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
if (commands.Length > 0)
|
if (commands.Length > 0)
|
||||||
@@ -75,7 +75,7 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
string[] commands = ip.Select(item =>
|
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}";
|
return $"route delete -net {_ip}/{item.PrefixLength}";
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
if (commands.Length > 0)
|
if (commands.Length > 0)
|
||||||
|
@@ -152,7 +152,7 @@ namespace linker.tun
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
CommandHelper.PowerShell($"start-service WinNat", [], out error);
|
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);
|
CommandHelper.PowerShell($"New-NetNat -Name {Name} -InternalIPInterfaceAddressPrefix {network}/{prefixLength}", [], out error);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(error) == false)
|
if (string.IsNullOrWhiteSpace(error) == false)
|
||||||
@@ -214,9 +214,9 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
string[] commands = ips.Select(item =>
|
string[] commands = ips.Select(item =>
|
||||||
{
|
{
|
||||||
uint maskValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
uint maskValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||||
IPAddress mask = NetworkHelper.GetPrefixIp(maskValue);
|
IPAddress mask = NetworkHelper.PrefixValue2IP(maskValue);
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.Address, maskValue);
|
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, maskValue);
|
||||||
|
|
||||||
return $"route add {_ip} mask {mask} {ip} metric 5 if {interfaceNumber}";
|
return $"route add {_ip} mask {mask} {ip} metric 5 if {interfaceNumber}";
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
@@ -230,9 +230,9 @@ namespace linker.tun
|
|||||||
{
|
{
|
||||||
string[] commands = ip.Select(item =>
|
string[] commands = ip.Select(item =>
|
||||||
{
|
{
|
||||||
uint maskValue = NetworkHelper.GetPrefixIP(item.PrefixLength);
|
uint maskValue = NetworkHelper.PrefixLength2Value(item.PrefixLength);
|
||||||
IPAddress mask = NetworkHelper.GetPrefixIp(maskValue);
|
IPAddress mask = NetworkHelper.PrefixValue2IP(maskValue);
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(item.Address, maskValue);
|
IPAddress _ip = NetworkHelper.NetworkIP2IP(item.Address, maskValue);
|
||||||
return $"route delete {_ip}";
|
return $"route delete {_ip}";
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
if (commands.Length > 0)
|
if (commands.Length > 0)
|
||||||
|
@@ -17,9 +17,9 @@ export const getAccesss = (machineid) => {
|
|||||||
export const setAccess = (data) => {
|
export const setAccess = (data) => {
|
||||||
return sendWebsocketMsg('configclient/SetAccess', data);
|
return sendWebsocketMsg('configclient/SetAccess', data);
|
||||||
}
|
}
|
||||||
export const setSecretKeyAsync = (data) => {
|
export const getSyncNames = () => {
|
||||||
return sendWebsocketMsg('configclient/SecretKeyAsync', data);
|
return sendWebsocketMsg('configclient/SyncNames');
|
||||||
}
|
}
|
||||||
export const setServerAsync = (data) => {
|
export const setSync = (data) => {
|
||||||
return sendWebsocketMsg('configclient/ServerAsync', data);
|
return sendWebsocketMsg('configclient/Sync', data);
|
||||||
}
|
}
|
@@ -1,71 +1,81 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never" style="max-width: 540px;margin:0 auto;">
|
||||||
<template #header>
|
<template #header>选择你需要同步的项,将这些配置同步到本组所有客户端</template>
|
||||||
<div class="card-header flex">
|
<div>
|
||||||
<span>同步密钥</span>
|
<el-checkbox v-model="state.checkAll" :indeterminate="state.isIndeterminate" @change="handleCheckAllChange">全选</el-checkbox>
|
||||||
<span class="flex-1"></span>
|
<el-checkbox-group v-model="state.checkeds" @change="handleCheckedsChange">
|
||||||
<el-button type="success" @click="handleSyncSecretKey">确定同步</el-button>
|
<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>
|
</div>
|
||||||
</template>
|
</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>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { injectGlobalData } from '@/provide';
|
import { injectGlobalData } from '@/provide';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { reactive } from 'vue'
|
import { onMounted, reactive } from 'vue'
|
||||||
import { setSecretKeyAsync, setServerAsync } from '@/apis/config';
|
import { getSyncNames, setSync } from '@/apis/config';
|
||||||
export default {
|
export default {
|
||||||
label:'同步配置',
|
label:'同步配置',
|
||||||
name:'async',
|
name:'async',
|
||||||
order:7,
|
order:7,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const globalData = injectGlobalData();
|
const globalData = injectGlobalData();
|
||||||
const state = reactive({});
|
const state = reactive({
|
||||||
|
names:[],
|
||||||
|
checkAll:false,
|
||||||
|
isIndeterminate:false,
|
||||||
|
checkeds:[],
|
||||||
|
});
|
||||||
|
|
||||||
const handleSyncSecretKey = ()=>{
|
const handleCheckAllChange = (val)=>{
|
||||||
|
state.checkeds = val ? state.names.map(c=>c.name) : [];
|
||||||
const json = {
|
state.isIndeterminate = false
|
||||||
SignSecretKey:globalData.value.config.Client.ServerInfo.SecretKey,
|
|
||||||
RelaySecretKey:globalData.value.config.Client.Relay.Servers[0].SecretKey,
|
|
||||||
SForwardSecretKey:globalData.value.config.Client.SForward.SecretKey
|
|
||||||
}
|
|
||||||
setSecretKeyAsync(json).then(()=>{
|
|
||||||
ElMessage.success('已操作');
|
|
||||||
}).catch(()=>{
|
|
||||||
ElMessage.error('操作失败');
|
|
||||||
});;
|
|
||||||
}
|
}
|
||||||
const handleSyncServer = ()=>{
|
const handleCheckedsChange = (value)=>{
|
||||||
const json = {
|
const checkedCount = value.length
|
||||||
SignServers:globalData.value.config.Client.Servers,
|
state.checkAll = checkedCount === state.names.length
|
||||||
RelayServers:globalData.value.config.Client.Relay.Servers,
|
state.isIndeterminate = checkedCount > 0 && checkedCount < state.names.length;
|
||||||
TunnelServers:globalData.value.config.Client.Tunnel.Servers
|
|
||||||
}
|
|
||||||
setServerAsync(json).then(()=>{
|
|
||||||
ElMessage.success('已操作');
|
|
||||||
}).catch(()=>{
|
|
||||||
ElMessage.error('操作失败');
|
|
||||||
});;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {state,handleSyncSecretKey,handleSyncServer}
|
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('已操作');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {state,handleCheckAllChange,handleCheckedsChange,handleSync}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -21,13 +21,12 @@
|
|||||||
<Title>linker</Title>
|
<Title>linker</Title>
|
||||||
<Authors>snltty</Authors>
|
<Authors>snltty</Authors>
|
||||||
<Company>snltty</Company>
|
<Company>snltty</Company>
|
||||||
<Description>1. 使用原生成器替代反射
|
<Description>1. 新增多分组管理,方便分组切换
|
||||||
2. 统计所有服务端,客户端数量
|
2. 增加分组密码,提高分组隔离安全性
|
||||||
3. 创建docker镜像清单,自动识别平台
|
3. 优化配置同步,可自由选择同步哪些信息
|
||||||
4. docker镜像增加arm
|
4. 自动分配虚拟网卡IP
|
||||||
5. 优化了arm平台下获取设备ID的方法
|
5. 线程池优化
|
||||||
6. 增加了查看流量信息的权限
|
6. 一些UI优化</Description>
|
||||||
7. 有服务器更新密钥的客户端,可以更新本服务器的所有客户端</Description>
|
|
||||||
<Copyright>snltty</Copyright>
|
<Copyright>snltty</Copyright>
|
||||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||||
|
@@ -35,6 +35,9 @@ namespace linker.plugins.client
|
|||||||
serviceCollection.AddSingleton<SignInArgsSecretKeyClient>();
|
serviceCollection.AddSingleton<SignInArgsSecretKeyClient>();
|
||||||
serviceCollection.AddSingleton<SignInArgsGroupPasswordClient>();
|
serviceCollection.AddSingleton<SignInArgsGroupPasswordClient>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<ConfigSyncSignInSecretKey>();
|
||||||
|
serviceCollection.AddSingleton<ConfigSyncGroupSecretKey>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
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.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace linker.client.config
|
namespace linker.client.config
|
||||||
{
|
{
|
||||||
@@ -209,10 +208,6 @@ namespace linker.config
|
|||||||
public string Host { get; set; } = string.Empty;
|
public string Host { get; set; } = string.Empty;
|
||||||
public string SecretKey { 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();
|
return configSyncTreansfer.GetNames();
|
||||||
}
|
}
|
||||||
[ClientApiAccessAttribute(ClientApiAccess.Sync)]
|
[ClientApiAccessAttribute(ClientApiAccess.Sync)]
|
||||||
public bool Sync(ApiControllerParamsInfo param)
|
public async Task<bool> Sync(ApiControllerParamsInfo param)
|
||||||
{
|
{
|
||||||
string[] names = param.Content.DeJson<string[]>();
|
string[] names = param.Content.DeJson<string[]>();
|
||||||
configSyncTreansfer.Sync(names);
|
if (names.Length == 1)
|
||||||
|
{
|
||||||
|
await configSyncTreansfer.Sync(names[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
configSyncTreansfer.Sync(names);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,6 @@ namespace linker.plugins.config
|
|||||||
public interface IConfigSync
|
public interface IConfigSync
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public string Label { get; }
|
|
||||||
public Memory<byte> GetData();
|
public Memory<byte> GetData();
|
||||||
public void SetData(Memory<byte> data);
|
public void SetData(Memory<byte> data);
|
||||||
}
|
}
|
||||||
@@ -23,11 +22,6 @@ namespace linker.plugins.config
|
|||||||
public Memory<byte> Data { get; set; }
|
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
|
public sealed partial class ConfigSyncTreansfer
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim slim = new SemaphoreSlim(1);
|
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))}");
|
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)
|
public void Sync(string[] names)
|
||||||
@@ -63,7 +57,7 @@ namespace linker.plugins.config
|
|||||||
{
|
{
|
||||||
Connection = clientSignInState.Connection,
|
Connection = clientSignInState.Connection,
|
||||||
MessengerId = (ushort)ConfigMessengerIds.SyncForward,
|
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();
|
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)
|
public void Sync(ConfigAsyncInfo info)
|
||||||
{
|
{
|
||||||
var sync = syncs.FirstOrDefault(c => c.Name == info.Name);
|
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.config;
|
||||||
using linker.plugins.relay.messenger;
|
|
||||||
using linker.libs.api;
|
using linker.libs.api;
|
||||||
using linker.libs.extends;
|
using linker.libs.extends;
|
||||||
using linker.plugins.client;
|
using linker.plugins.client;
|
||||||
|
@@ -29,6 +29,8 @@ namespace linker.plugins.relay
|
|||||||
serviceCollection.AddSingleton<RelayTransfer>();
|
serviceCollection.AddSingleton<RelayTransfer>();
|
||||||
serviceCollection.AddSingleton<RelayFlow>();
|
serviceCollection.AddSingleton<RelayFlow>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<ConfigSyncRelaySecretKey>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
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,7 +30,9 @@ namespace linker.plugins.sforward
|
|||||||
|
|
||||||
serviceCollection.AddSingleton<SForwardFlow>();
|
serviceCollection.AddSingleton<SForwardFlow>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<ConfigSyncSForwardSecretKey>();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
@@ -405,8 +405,8 @@ namespace linker.plugins.sforward.messenger
|
|||||||
if (sForwardInfo.RemotePortMin != 0 && sForwardInfo.RemotePortMax != 0)
|
if (sForwardInfo.RemotePortMin != 0 && sForwardInfo.RemotePortMax != 0)
|
||||||
{
|
{
|
||||||
uint plus = (uint)(sForwardProxyInfo.RemotePort - sForwardInfo.RemotePortMin);
|
uint plus = (uint)(sForwardProxyInfo.RemotePort - sForwardInfo.RemotePortMin);
|
||||||
uint newIP = BinaryPrimitives.ReadUInt32BigEndian(localEP.Address.GetAddressBytes()) + plus;
|
uint newIP = NetworkHelper.IP2Value(localEP.Address) + plus;
|
||||||
localEP.Address = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(newIP)));
|
localEP.Address = NetworkHelper.Value2IP(newIP);
|
||||||
}
|
}
|
||||||
return localEP;
|
return localEP;
|
||||||
}
|
}
|
||||||
|
@@ -129,7 +129,7 @@ namespace linker.plugins.signin.messenger
|
|||||||
DateTime now = DateTime.Now;
|
DateTime now = DateTime.Now;
|
||||||
|
|
||||||
var groups = Clients.Values.GroupBy(c => c.GroupId)
|
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();
|
.Select(group => group.Key).ToList();
|
||||||
|
|
||||||
if (groups.Count > 0)
|
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)
|
if (c.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
uint ip = BinaryPrimitives.ReadUInt32BigEndian(c.GetAddressBytes());
|
uint ip = NetworkHelper.IP2Value(c);
|
||||||
foreach (var item in excludeips)
|
foreach (var item in excludeips)
|
||||||
{
|
{
|
||||||
uint maskValue = NetworkHelper.GetPrefixIP(item.Mask);
|
uint maskValue = NetworkHelper.PrefixLength2Value(item.Mask);
|
||||||
uint ip1 = BinaryPrimitives.ReadUInt32BigEndian(item.IPAddress.GetAddressBytes());
|
uint ip1 = NetworkHelper.IP2Value(item.IPAddress);
|
||||||
if ((ip & maskValue) == (ip1 & maskValue))
|
if ((ip & maskValue) == (ip1 & maskValue))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@@ -65,6 +65,8 @@ namespace linker.plugins.tunnel
|
|||||||
|
|
||||||
serviceCollection.AddSingleton<TunnelUpnpTransfer>();
|
serviceCollection.AddSingleton<TunnelUpnpTransfer>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<ConfigSyncTunnelTransports>();
|
||||||
|
|
||||||
LoggerHelper.Instance.Info($"tunnel route level getting.");
|
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.RouteLevel = NetworkHelper.GetRouteLevel(config.Data.Client.ServerInfo.Host, out List<IPAddress> ips);
|
||||||
config.Data.Client.Tunnel.RouteIPs = ips.ToArray();
|
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.config;
|
||||||
using linker.plugins.tuntap.client;
|
using linker.plugins.tuntap.client;
|
||||||
|
using linker.plugins.tuntap.lease;
|
||||||
using linker.plugins.tuntap.messenger;
|
using linker.plugins.tuntap.messenger;
|
||||||
using linker.startup;
|
using linker.startup;
|
||||||
using linker.tun;
|
using linker.tun;
|
||||||
@@ -37,6 +38,8 @@ namespace linker.plugins.tuntap
|
|||||||
{
|
{
|
||||||
serviceCollection.AddSingleton<TuntapServerMessenger>();
|
serviceCollection.AddSingleton<TuntapServerMessenger>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<LeaseServerTreansfer>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
public void UseClient(ServiceProvider serviceProvider, FileConfig config)
|
||||||
@@ -47,6 +50,7 @@ namespace linker.plugins.tuntap
|
|||||||
|
|
||||||
public void UseServer(ServiceProvider serviceProvider, FileConfig config)
|
public void UseServer(ServiceProvider serviceProvider, FileConfig config)
|
||||||
{
|
{
|
||||||
|
LeaseServerTreansfer leaseTreansfer = serviceProvider.GetService<LeaseServerTreansfer>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,9 +50,9 @@ namespace linker.plugins.tuntap.client
|
|||||||
}
|
}
|
||||||
}).Select(c =>
|
}).Select(c =>
|
||||||
{
|
{
|
||||||
uint maskValue = NetworkHelper.GetPrefixIP(c.PrefixLength);
|
uint maskValue = NetworkHelper.PrefixLength2Value(c.PrefixLength);
|
||||||
IPAddress mask = NetworkHelper.GetPrefixIp(maskValue);
|
IPAddress mask = NetworkHelper.PrefixValue2IP(maskValue);
|
||||||
IPAddress _ip = NetworkHelper.ToNetworkIp(c.Address, maskValue);
|
IPAddress _ip = NetworkHelper.NetworkIP2IP(c.Address, maskValue);
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
IP = c.Address,
|
IP = c.Address,
|
||||||
|
@@ -91,6 +91,7 @@ namespace linker.plugins.tuntap.client
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行网卡
|
/// 运行网卡
|
||||||
@@ -424,7 +425,7 @@ namespace linker.plugins.tuntap.client
|
|||||||
tuntapProxy.SetIPs(ips);
|
tuntapProxy.SetIPs(ips);
|
||||||
foreach (var item in tuntapInfos.Values)
|
foreach (var item in tuntapInfos.Values)
|
||||||
{
|
{
|
||||||
tuntapProxy.SetIP(item.MachineId, BinaryPrimitives.ReadUInt32BigEndian(item.IP.GetAddressBytes()));
|
tuntapProxy.SetIP(item.MachineId, NetworkHelper.IP2Value(item.IP));
|
||||||
}
|
}
|
||||||
CheckLanIPs();
|
CheckLanIPs();
|
||||||
}
|
}
|
||||||
@@ -464,7 +465,7 @@ namespace linker.plugins.tuntap.client
|
|||||||
.Concat(runningConfig.Data.Tuntap.LanIPs.Where(c => c != null))
|
.Concat(runningConfig.Data.Tuntap.LanIPs.Where(c => c != null))
|
||||||
//路由上的IP
|
//路由上的IP
|
||||||
.Concat(config.Data.Client.Tunnel.RouteIPs)
|
.Concat(config.Data.Client.Tunnel.RouteIPs)
|
||||||
.Select(c => BinaryPrimitives.ReadUInt32BigEndian(c.GetAddressBytes()))
|
.Select(c => NetworkHelper.IP2Value(c))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
private List<TuntapVeaLanIPAddressList> ParseIPs(List<TuntapInfo> infos)
|
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)
|
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
|
return new TuntapVeaLanIPAddress
|
||||||
{
|
{
|
||||||
IPAddress = ipInt,
|
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.signin.messenger;
|
||||||
using linker.plugins.tuntap.client;
|
using linker.plugins.tuntap.client;
|
||||||
using linker.plugins.tuntap.config;
|
using linker.plugins.tuntap.config;
|
||||||
|
using linker.plugins.tuntap.lease;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace linker.plugins.tuntap.messenger
|
namespace linker.plugins.tuntap.messenger
|
||||||
{
|
{
|
||||||
@@ -61,6 +63,14 @@ namespace linker.plugins.tuntap.messenger
|
|||||||
connection.Write(MemoryPackSerializer.Serialize(_info));
|
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 MessengerSender messengerSender;
|
||||||
private readonly SignCaching signCaching;
|
private readonly SignCaching signCaching;
|
||||||
private readonly FileConfig config;
|
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.messengerSender = messengerSender;
|
||||||
this.signCaching = signCaching;
|
this.signCaching = signCaching;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.leaseTreansfer = leaseTreansfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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,
|
Config = 2206,
|
||||||
ConfigForward = 2207,
|
ConfigForward = 2207,
|
||||||
|
|
||||||
|
|
||||||
|
LeaseAdd = 2208,
|
||||||
|
LeaseGet = 2209,
|
||||||
|
Lease = 2210,
|
||||||
|
LeaseChange = 2211,
|
||||||
|
LeaseChangeForward = 2212,
|
||||||
|
|
||||||
None = 2299
|
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<UpdaterClientMessenger>();
|
||||||
serviceCollection.AddSingleton<UpdaterClientApiController>();
|
serviceCollection.AddSingleton<UpdaterClientApiController>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<ConfigSyncUpdaterSecretKey>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
public void AddServer(ServiceCollection serviceCollection, FileConfig config)
|
||||||
|
15
version.txt
15
version.txt
@@ -1,9 +1,8 @@
|
|||||||
v1.4.9
|
v1.4.9
|
||||||
2024-10-16 17:33:40
|
2024-10-17 17:30:30
|
||||||
1. 使用原生成器替代反射
|
1. 新增多分组管理,方便分组切换
|
||||||
2. 统计所有服务端,客户端数量
|
2. 增加分组密码,提高分组隔离安全性
|
||||||
3. 创建docker镜像清单,自动识别平台
|
3. 优化配置同步,可自由选择同步哪些信息
|
||||||
4. docker镜像增加arm
|
4. 自动分配虚拟网卡IP
|
||||||
5. 优化了arm平台下获取设备ID的方法
|
5. 线程池优化
|
||||||
6. 增加了查看流量信息的权限
|
6. 一些UI优化
|
||||||
7. 有服务器更新密钥的客户端,可以更新本服务器的所有客户端
|
|
Reference in New Issue
Block a user