中继有BUG

This commit is contained in:
snltty
2024-07-23 16:01:15 +08:00
parent 20d8400dff
commit 4dbd17452e
15 changed files with 167 additions and 59 deletions

View File

@@ -49,11 +49,29 @@ systemctl enable linker
1. 服务端端口 `1802` TCP+UDP
2. 客户端端口 `1804``1803` TCP
3. 配置文件夹 `./configs`
4. 插件文件夹 `./plugins`
5. 网页文件夹 `./web`
6. 日志文件夹 `./logs`
4. 日志文件夹 `./logs`
5. x64 `snltty/linker-debian-x64`
6. arm64 `snltty/linker-debian-arm64`
#### 客户端
```
snltty/linker-musl-x64
snltty/linker-musl-arm64
docker run -it -d --name linker \
-p 1804:1804/tcp -p 1803:1803/tcp \
-v /usr/local/linker-docker/configs:/app/configs \
-v /usr/local/linker-docker/logs:/app/logs \
--device /dev/net/tun \
--restart=always \
--privileged=true \
snltty/linker-debian-x64
```
#### 服务端
```
docker run -it -d --name linker \
-p 1802:1802/tcp -p 1802:1802/udp \
-v /usr/local/linker-docker/configs:/app/configs \
-v /usr/local/linker-docker/logs:/app/logs \
--restart=always \
--privileged=true \
snltty/linker-debian-x64
```

View File

@@ -4,8 +4,8 @@ import { sendWebsocketMsg } from './request'
export const getUpdater = () => {
return sendWebsocketMsg('updaterclient/get');
}
export const confirm = (machineId, version) => {
return sendWebsocketMsg('updaterclient/confirm', { machineId, version });
export const confirm = (data) => {
return sendWebsocketMsg('updaterclient/confirm', data);
}
export const exit = (machineId) => {
return sendWebsocketMsg('updaterclient/exit', machineId);

View File

@@ -130,9 +130,13 @@ export default {
if(updateInfo.Status == 2){
const selectedValue = ref(updaterVersion.value);
const selectOptions = [h(ElOption, { label: `${updaterVersion.value} - 最新版本`, value: updaterVersion.value })];
const selectOptions = [
h(ElOption, { label: `仅[${row.MachineName}] -> ${updaterVersion.value}(最新版本)`, value: updaterVersion.value }),
h(ElOption, { label: `[所有] -> ${updaterVersion.value}(最新版本)`, value: `all->${updaterVersion.value}` }),
];
if(row.Version != serverVersion.value && updaterVersion.value != serverVersion.value){
selectOptions.push(h(ElOption, { label: `${serverVersion.value} - 服务器版本`, value: serverVersion.value }));
selectOptions.push(h(ElOption, { label: `仅[${row.MachineName}] -> ${serverVersion.value}(服务器版本)`, value: serverVersion.value }));
selectOptions.push(h(ElOption, { label: `[所有] -> ${serverVersion.value}(服务器版本)`, value: `all->${serverVersion.value}` }));
}
ElMessageBox({
@@ -148,7 +152,15 @@ export default {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
confirm(row.MachineId,selectedValue.value);
const data = {
MachineId:row.MachineId,
Version:selectedValue.value.replace('all->',''),
All:selectedValue.value.indexOf('all->') >= 0
};
if(data.All){
data.MachineId = '';
}
confirm(data);
}).catch(() => {});
}
}

View File

@@ -14,7 +14,6 @@ export const provideUpdater = () => {
const _getUpdater = () => {
if (globalData.value.api.connected) {
getUpdater().then((res) => {
console.log(res);
const self = Object.values(res).filter(c => !!c.Version)[0];
if (self) {
updater.value.current.DateTime = self.DateTime;

View File

@@ -1,5 +1,12 @@
<template>
<Version ckey="relayServers"/>
<Version ckey="relayServers">
<div>
<el-radio-group v-model="state.byRelay" size="small" style="vertical-align:bottom" @change="handleByRelayChange">
<el-radio-button label="延迟优先" :value="true" />
<el-radio-button label="顺序优先" :value="false" />
</el-radio-group>
</div>
</Version>
<el-table :data="state.list" border size="small" width="100%" :height="`${state.height}px`" @cell-dblclick="handleCellClick">
<el-table-column prop="Name" label="名称" width="100">
<template #default="scope">
@@ -94,12 +101,14 @@ export default {
const globalData = injectGlobalData();
const state = reactive({
list:globalData.value.config.Running.Relay.Servers.sort((a,b)=>a.Disabled - b.Disabled),
byRelay:globalData.value.config.Running.Relay.ByRelay,
types:[],
height: computed(()=>globalData.value.height-127)
});
watch(()=>globalData.value.config.Running.Relay.Servers,()=>{
if(state.list.filter(c=>c['__editing']).length == 0){
state.list = globalData.value.config.Running.Relay.Servers.sort((a,b)=>a.Disabled - b.Disabled);
state.byRelay = globalData.value.config.Running.Relay.ByRelay;
}
})
@@ -151,9 +160,15 @@ export default {
handleSave(state.list);
}
const handleByRelayChange = ()=>{
handleSave();
}
const handleSave = ()=>{
state.list = state.list.slice().sort((a,b)=>a.Disabled - b.Disabled);
setRelayServers(state.list).then(()=>{
setRelayServers({
servers:state.list,
byRelay:state.byRelay
}).then(()=>{
ElMessage.success('已操作');
}).catch(()=>{
ElMessage.success('操作失败');
@@ -164,7 +179,7 @@ export default {
_getRelayTypes();
});
return {state,handleCellClick,handleEditBlur,handleDel,handleAdd,handleSort}
return {state,handleCellClick,handleEditBlur,handleDel,handleAdd,handleSort,handleByRelayChange}
}
}
</script>

View File

@@ -1,8 +1,10 @@
<template>
<div class="running-version-wrap">
<div class="running-version-wrap flex">
<span>配置版本 : {{version || 1}}</span>
<el-button size="small" @click=handleEdit>手动修改版本</el-button>
<span>高版本一端自动同步到低版本一端</span>
<span class="flex-1"></span>
<slot></slot>
</div>
</template>
<script>

View File

@@ -27,5 +27,6 @@ COPY . .
RUN chmod +x ./linker \
&& chmod +x ./plugins/tuntap/tun2socks
ENV LINKER_IS_DOCKER="linker"
ENTRYPOINT ["./linker"]

View File

@@ -2,11 +2,10 @@ FROM alpine:latest
ENV TZ=Asia/Shanghai DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
RUN echo "https://mirrors.ustc.edu.cn/alpine/latest-stable/main/" > /etc/apk/repositories \
&& apk add --no-cache libstdc++ libintl tzdata zeromq bash \
&& apk add --no-cache libstdc++ libintl tzdata zeromq bash net-tools iproute2 \
&& ln -snf /usr/share/zoneinfo/$clTZ /etc/localtime \
&& echo $TZ > /etc/timezone
EXPOSE 1802/tcp
EXPOSE 1802/udp
EXPOSE 1803/tcp
@@ -20,5 +19,7 @@ COPY . .
RUN chmod +x ./linker \
&& chmod +x ./plugins/tuntap/tun2socks
RUN mkdir -p /dev/net && mknod /dev/net/tun c 10 200 && chmod 600 /dev/net/tun
ENTRYPOINT ["./linker"]

View File

@@ -6,6 +6,7 @@ using MemoryPack;
using linker.plugins.client;
using linker.plugins.capi;
using linker.plugins.messenger;
using linker.client.config;
namespace linker.plugins.relay
{
@@ -42,7 +43,7 @@ namespace linker.plugins.relay
/// <returns></returns>
public bool SetServers(ApiControllerParamsInfo param)
{
RelayServerInfo[] info = param.Content.DeJson<RelayServerInfo[]>();
RelayRunningSyncInfo info = param.Content.DeJson<RelayRunningSyncInfo>();
relayTransfer.OnServers(info);
return true;
}

View File

@@ -84,9 +84,10 @@ namespace linker.plugins.relay
/// 收到中继协议列表
/// </summary>
/// <param name="servers"></param>
public void OnServers(RelayServerInfo[] servers)
public void OnServers(RelayRunningSyncInfo info)
{
running.Data.Relay.Servers = servers;
running.Data.Relay.Servers = info.Servers;
running.Data.Relay.ByRelay = info.ByRelay;
running.Data.Update();
runningConfigTransfer.IncrementVersion(configKey);
SyncServers();
@@ -94,13 +95,19 @@ namespace linker.plugins.relay
}
private void SetServers(Memory<byte> data)
{
running.Data.Relay.Servers = MemoryPackSerializer.Deserialize<RelayServerInfo[]>(data.Span);
RelayRunningSyncInfo relayRunningSyncInfo = MemoryPackSerializer.Deserialize<RelayRunningSyncInfo>(data.Span);
running.Data.Relay.Servers = relayRunningSyncInfo.Servers;
running.Data.Relay.ByRelay = relayRunningSyncInfo.ByRelay;
running.Data.Update();
_ = TaskRelay();
}
private void SyncServers()
{
runningConfigTransfer.Sync(configKey, MemoryPackSerializer.Serialize(running.Data.Relay.Servers));
runningConfigTransfer.Sync(configKey, MemoryPackSerializer.Serialize(new RelayRunningSyncInfo
{
Servers = running.Data.Relay.Servers,
ByRelay = running.Data.Relay.ByRelay,
}));
}
@@ -145,10 +152,13 @@ namespace linker.plugins.relay
}
try
{
IEnumerable<ITransport> _transports = transports.OrderBy(c => c.Type);
foreach (RelayServerInfo item in running.Data.Relay.Servers.Where(c => c.Disabled == false && string.IsNullOrWhiteSpace(c.Host) == false))
var servers = running.Data.Relay.Servers
.Where(c => c.Disabled == false)
.Where(c => string.IsNullOrWhiteSpace(c.Host) == false)
.Where(c => c.Delay >= 0).OrderBy(c => c.Delay);
foreach (RelayServerInfo item in servers)
{
ITransport transport = _transports.FirstOrDefault(c => c.Type == item.RelayType);
ITransport transport = transports.FirstOrDefault(c => c.Type == item.RelayType);
if (transport == null)
{
continue;
@@ -218,6 +228,10 @@ namespace linker.plugins.relay
LoggerHelper.Instance.Debug($"relay from {relayInfo.RemoteMachineId}->{relayInfo.RemoteMachineName} success,{relayInfo.ToJson()}");
ConnectedCallback(relayInfo, connection);
}
else
{
LoggerHelper.Instance.Error($"relay from {relayInfo.RemoteMachineId}->{relayInfo.RemoteMachineName} error,{relayInfo.ToJson()}");
}
}).ConfigureAwait(false);
return true;
}

View File

@@ -21,6 +21,19 @@ namespace linker.client.config
/// 中继服务器列表
/// </summary>
public RelayServerInfo[] Servers { get; set; } = Array.Empty<RelayServerInfo>();
public bool ByRelay { get; set; }
}
[MemoryPackable]
public sealed partial class RelayRunningSyncInfo
{
/// <summary>
/// 中继服务器列表
/// </summary>
public RelayServerInfo[] Servers { get; set; } = Array.Empty<RelayServerInfo>();
public bool ByRelay { get; set; }
}
}

View File

@@ -71,7 +71,6 @@ namespace linker.plugins.relay.transport
return null;
}
connection.Cancel();
ClearSocket(socket);
//通知对方,确认中继
resp = await messengerSender.SendReply(new MessageRequestWrap
@@ -85,6 +84,7 @@ namespace linker.plugins.relay.transport
connection.Disponse(7);
return null;
}
ClearSocket(socket);
SslStream sslStream = null;
if (relayInfo.SSL)
@@ -133,7 +133,6 @@ namespace linker.plugins.relay.transport
Socket socket = new Socket(relayInfo.Server.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false);
IConnection connection = await messengerResolver.BeginReceiveClient(socket);
await messengerSender.SendOnly(new MessageRequestWrap
{
@@ -141,10 +140,9 @@ namespace linker.plugins.relay.transport
MessengerId = (ushort)RelayMessengerIds.RelayConfirm,
Payload = MemoryPackSerializer.Serialize(relayInfo)
}).ConfigureAwait(false);
connection.Cancel();
await Task.Delay(30).ConfigureAwait(false);
ClearSocket(socket);
_ = WaitSSL(connection, socket, relayInfo).ContinueWith((result) =>
{
callback(result.Result);
@@ -164,33 +162,46 @@ namespace linker.plugins.relay.transport
private async Task<TunnelConnectionTcp> WaitSSL(IConnection connection, Socket socket, RelayInfo relayInfo)
{
SslStream sslStream = null;
if (relayInfo.SSL)
try
{
if (certificate == null)
SslStream sslStream = null;
if (relayInfo.SSL)
{
connection.Disponse(8);
return null;
if (certificate == null)
{
connection.Disponse(8);
return null;
}
sslStream = new SslStream(connection.SourceNetworkStream, false);
Console.WriteLine(socket.Available);
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false).ConfigureAwait(false);
}
sslStream = new SslStream(connection.SourceNetworkStream, false);
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false).ConfigureAwait(false);
return new TunnelConnectionTcp
{
Direction = TunnelDirection.Reverse,
ProtocolType = TunnelProtocolType.Tcp,
RemoteMachineId = relayInfo.RemoteMachineId,
RemoteMachineName = relayInfo.RemoteMachineName,
Stream = sslStream,
Socket = socket,
Mode = TunnelMode.Server,
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
TransactionId = relayInfo.TransactionId,
TransportName = Name,
Type = TunnelType.Relay,
SSL = relayInfo.SSL,
BufferSize = 3,
};
}
return new TunnelConnectionTcp
catch (Exception ex)
{
Direction = TunnelDirection.Reverse,
ProtocolType = TunnelProtocolType.Tcp,
RemoteMachineId = relayInfo.RemoteMachineId,
RemoteMachineName = relayInfo.RemoteMachineName,
Stream = sslStream,
Socket = socket,
Mode = TunnelMode.Server,
IPEndPoint = socket.RemoteEndPoint as IPEndPoint,
TransactionId = relayInfo.TransactionId,
TransportName = Name,
Type = TunnelType.Relay,
SSL = relayInfo.SSL,
BufferSize = 3,
};
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
connection?.Disponse();
}
return null;
}
private void ClearSocket(Socket socket)
{

View File

@@ -43,7 +43,7 @@ namespace linker.plugins.updater
public UpdateInfo GetCurrent(ApiControllerParamsInfo param)
{
var updaters = updaterTransfer.Get();
if(updaters.TryGetValue(config.Data.Client.Id,out UpdateInfo info))
if (updaters.TryGetValue(config.Data.Client.Id, out UpdateInfo info))
{
return info;
}
@@ -90,11 +90,7 @@ namespace linker.plugins.updater
{
UpdaterConfirmInfo confirm = param.Content.DeJson<UpdaterConfirmInfo>();
if (string.IsNullOrWhiteSpace(confirm.MachineId) || confirm.MachineId == config.Data.Client.Id)
{
updaterTransfer.Confirm(confirm.Version);
}
else
if (confirm.All)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
@@ -102,6 +98,11 @@ namespace linker.plugins.updater
MessengerId = (ushort)UpdaterMessengerIds.ConfirmForward,
Payload = MemoryPackSerializer.Serialize(confirm)
});
updaterTransfer.Confirm(confirm.Version);
}
else if (confirm.MachineId == config.Data.Client.Id)
{
updaterTransfer.Confirm(confirm.Version);
}
}
public async Task Exit(ApiControllerParamsInfo param)

View File

@@ -21,6 +21,7 @@ namespace linker.plugins.updater.config
{
public string MachineId { get; set; }
public string Version { get; set; }
public bool All { get; set; }
}
[MemoryPackable]

View File

@@ -79,7 +79,7 @@ namespace linker.plugins.updater.messenger
public void ConfirmServer(IConnection connection)
{
UpdaterConfirmServerInfo confirm = MemoryPackSerializer.Deserialize<UpdaterConfirmServerInfo>(connection.ReceiveRequestWrap.Payload.Span);
if(fileConfig.Data.Server.Updater.SecretKey == confirm.SecretKey)
if (fileConfig.Data.Server.Updater.SecretKey == confirm.SecretKey)
{
updaterServerTransfer.Confirm(confirm.Version);
}
@@ -108,7 +108,26 @@ namespace linker.plugins.updater.messenger
public async Task ConfirmForward(IConnection connection)
{
UpdaterConfirmInfo confirm = MemoryPackSerializer.Deserialize<UpdaterConfirmInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) && signCaching.TryGet(confirm.MachineId, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
return;
}
if (confirm.All)
{
var tasks = signCaching.Get(cache.GroupId).Where(c => c.MachineId != connection.Id).Select(c =>
{
return messengerSender.SendOnly(new MessageRequestWrap
{
Connection = c.Connection,
MessengerId = (ushort)UpdaterMessengerIds.Confirm,
Payload = connection.ReceiveRequestWrap.Payload
});
});
await Task.WhenAll(tasks);
}
else if (signCaching.TryGet(confirm.MachineId, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
{
await messengerSender.SendOnly(new MessageRequestWrap
{