虚拟网卡ping值

This commit is contained in:
snltty
2024-08-12 17:02:54 +08:00
parent 06bfe7d344
commit 2750bf44b7
18 changed files with 400 additions and 138 deletions

View File

@@ -48,16 +48,24 @@ jobs:
env:
GITHUB_TOKEN: '${{ secrets.ACTIONS_TOKEN }}'
with:
tag_name: v1.2.0.5
release_name: v1.2.0.5.${{ steps.date.outputs.today }}
tag_name: v1.2.0.6
release_name: v1.2.0.6.${{ steps.date.outputs.today }}
draft: false
prerelease: false
body: |
1. UDP端口映射连接(无ssl加密)
2. UDP打洞纯净版(无ssl加密)
3. 如果当前版本小于v1.2.0.4则windows下需要重新卸载安装服务
4. 先更新所有客户端,再更新服务端(先更新服务端会获取不到客户端列表)
5. 用不上无加密UDP打洞的可以不更新
1. 显示虚拟网卡ping值
2. 更新服务器,更新服务器,更新服务器
#- name: upload win x86 oss
# id: upload-win-x86-oss
# uses: tvrcgo/oss-action@v0.1.1
# with:
# region: oss-cn-guangzhou
# key-id: '${{ secrets.ALIYUN_OSS_ID }}'
# key-secret: '${{ secrets.ALIYUN_OSS_SECRET }}'
# bucket: snltty
# asset-path: ./public/publish-zip/linker-win-x86.zip
# target-path: /linker/v1.2.0.6/linker-win-x86.zip
- name: upload win x86
id: upload-win-x86

View File

@@ -38,8 +38,21 @@ sudo pfctl -f /etc/pf.conf -e
:::tip[2、情况2你的设备无法使用NAT转发时]
1. 你的设备无法使用NAT转发(一般出现在低版本windows下win10以下),那你只能使用windows的端口转发功能来访问你当前设备局域网下的其它设备
1. 你的设备无法使用NAT转发(一般出现在低版本windows下win10以下),那你只能使用端口转发功能来访问你当前设备局域网下的其它设备
2. 按如下配置。当其它设备通过`192.168.54.2:12345` 访问时,将访问到你的局域网的`192.168.1.35:3389`
3. macos下需要你自己在**被访问端**添加端口转发
```
//编辑 pf 配置文件
sudo nano /etc/pf.conf
//添加转发规则
rdr pass on en0 inet proto tcp from any to any port 33890 -> 127.0.0.1 port 3389
rdr pass on en0 inet proto udp from any to any port 33890 -> 127.0.0.1 port 3389
//启用并重新加载 pf
sudo pfctl -f /etc/pf.conf
sudo pfctl -e
```
![Docusaurus Plushie](./img/tun-forward.png)

View File

@@ -0,0 +1,35 @@
using System.Collections.Concurrent;
using System.Reflection.PortableExecutable;
using System.Threading;
namespace linker.libs
{
public sealed class OperatingManager
{
private uint operating = 0;
public bool Operating => operating == 1;
public bool StartOperation()
{
return Interlocked.CompareExchange(ref operating, 1, 0) == 0;
}
public void StopOperation()
{
Interlocked.Exchange(ref operating, 0);
}
}
public sealed class OperatingMultipleManager
{
private readonly ConcurrentDictionary<string, bool> dicOperating = new ConcurrentDictionary<string, bool>();
public bool StartOperation(string key)
{
return dicOperating.TryAdd(key, true);
}
public void StopOperation(string key)
{
dicOperating.TryRemove(key, out _);
}
}
}

View File

@@ -0,0 +1,21 @@

using System.Threading;
namespace linker.libs
{
public sealed class VersionManager
{
private ulong version = 0;
public bool Eq(ulong outsideVersion, out ulong insideVersion)
{
insideVersion = version;
return outsideVersion == version;
}
public void Add()
{
Interlocked.Increment(ref version);
}
}
}

View File

@@ -1,6 +1,7 @@
using linker.libs;
using linker.libs.extends;
using Microsoft.Win32.SafeHandles;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
@@ -165,9 +166,33 @@ namespace linker.tun
public void AddForward(List<LinkerTunDeviceForwardItem> forwards)
{
string[] commands = forwards.Where(c => c != null && c.Enable).SelectMany(c =>
{
return new string[] {
$"sysctl -w net.ipv4.ip_forward=1",
$"iptables -t nat -A PREROUTING -p tcp --dport {c.ListenPort} -j DNAT --to-destination {c.ConnectAddr}:{c.ConnectPort}",
$"iptables -t nat -A POSTROUTING -p tcp --dport {c.ConnectPort} -j MASQUERADE",
$"iptables -t nat -A PREROUTING -p udp --dport {c.ListenPort} -j DNAT --to-destination {c.ConnectAddr}:{c.ConnectPort}",
$"iptables -t nat -A POSTROUTING -p udp --dport {c.ConnectPort} -j MASQUERADE",
};
}).ToArray();
CommandHelper.Windows(string.Empty, commands);
}
public void RemoveForward(List<LinkerTunDeviceForwardItem> forwards)
{
string[] commands = forwards.Where(c => c != null && c.Enable).SelectMany(c =>
{
return new string[] {
$"sysctl -w net.ipv4.ip_forward=1",
$"iptables -t nat -D PREROUTING -p tcp --dport {c.ListenPort} -j DNAT --to-destination {c.ConnectAddr}:{c.ConnectPort}",
$"iptables -t nat -D POSTROUTING -p tcp --dport {c.ConnectPort} -j MASQUERADE",
$"iptables -t nat -D PREROUTING -p udp --dport {c.ListenPort} -j DNAT --to-destination {c.ConnectAddr}:{c.ConnectPort}",
$"iptables -t nat -D POSTROUTING -p udp --dport {c.ConnectPort} -j MASQUERADE"
};
}).ToArray();
CommandHelper.Windows(string.Empty, commands);
}

View File

@@ -13,7 +13,7 @@ namespace linker.tunnel.transport
{
public string Name => "udp";
public string Label => "UDP、非常纯";
public string Label => "UDP、非常纯无ssl";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp;
public TunnelWanPortProtocolType AllowWanPortProtocolType => TunnelWanPortProtocolType.Udp;

View File

@@ -17,7 +17,7 @@ namespace linker.tunnel.transport
{
public string Name => "UdpPortMap";
public string Label => "UDP、端口映射";
public string Label => "UDP、端口映射无ssl";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp;

View File

@@ -55,6 +55,14 @@
</template>
</div>
</template>
<template v-if="showDelay">
<template v-if="tuntap.list[scope.row.MachineId].Delay>=0 && tuntap.list[scope.row.MachineId].Delay<=100">
<div class="delay green">{{ tuntap.list[scope.row.MachineId].Delay }}ms</div>
</template>
<template>
<div class="delay yellow">{{ tuntap.list[scope.row.MachineId].Delay }}ms</div>
</template>
</template>
</div>
</div>
</template>
@@ -65,12 +73,17 @@ import { stopTuntap, runTuntap } from '@/apis/tuntap';
import { ElMessage } from 'element-plus';
import { useTuntap } from './tuntap';
import {Loading} from '@element-plus/icons-vue'
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
export default {
emits: ['edit','refresh'],
components:{Loading},
setup(props, { emit }) {
const tuntap = useTuntap();
const globalData = injectGlobalData();
const showDelay = computed(()=>globalData.value.config.Running.Tuntap.ShowDelay);
const handleTuntap = (tuntap) => {
const fn = tuntap.running ? stopTuntap (tuntap.MachineId) : runTuntap(tuntap.MachineId);
tuntap.loading = true;
@@ -88,7 +101,7 @@ export default {
}
return {
tuntap, handleTuntap, handleTuntapIP,handleTuntapRefresh
tuntap,showDelay, handleTuntap, handleTuntapIP,handleTuntapRefresh
}
}
}
@@ -119,5 +132,7 @@ export default {
-webkit-text-fill-color:hsla(0,0%,100%,0);
}
}
.delay{position: absolute;right:0;bottom:0;line-height:normal}
</style>

View File

@@ -3,26 +3,41 @@
<div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="140">
<el-form-item prop="gateway" style="margin-bottom:0">
赐予此设备IP其它可以通过这个IP访问
赐予此设备IP其它设备可通过此IP访问
</el-form-item>
<el-form-item label="此设备的虚拟网卡IP" prop="IP">
<el-input v-model="state.ruleForm.IP" style="width:12rem" /> / <el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
<el-input v-model="state.ruleForm.IP" style="width:14rem" />
<span>/</span>
<el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
<span style="width: 3rem;"></span>
<el-checkbox v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" />
<el-popover
placement="top" title="提示" :width="400" trigger="hover"
content="在测试延迟时如果未连接将自动去打洞连接当你有一百个设备时每个设备都同时去与其它99台设备连接这数据量不小所以尽量不要个设备都勾选"
>
<template #reference>
<el-checkbox v-model="state.ruleForm.AutoConnect" label="自动连接?" size="large" />
</template>
</el-popover>
</el-form-item>
<el-form-item prop="upgrade" style="margin-bottom:0">
<el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" />
</el-form-item>
<div class="upgrade-wrap" v-if="state.ruleForm.Upgrade">
<el-form-item prop="gateway" style="margin-bottom:0">
<el-checkbox v-model="state.ruleForm.Gateway" label="此设备在路由器(网对网,将对方的 局域网IP 转发到对方)" size="large" />
<el-form-item prop="gateway" style="border-bottom: 1px solid #ddd;margin-bottom:0">
<el-checkbox v-model="state.ruleForm.Gateway" label="此设备在路由器(网对网)" size="large" />
</el-form-item>
<el-form-item prop="gateway" style="margin-bottom:0">
<span class="yellow">此设备可以用NAT转发那填写局域网IP其它交给NAT(linuxmacoswin10+)</span>
<el-form-item prop="nat" style="margin-bottom:0">
<span class="yellow">此设备能使用NAT转发只需局域网IP剩下的交给NAT(linuxmacoswin10+)</span>
</el-form-item>
<el-form-item label="此设备局域网IP" prop="LanIP">
<el-form-item label="此设备局域网IP" prop="LanIP" style="border-bottom: 1px solid #ddd;margin-bottom:0">
<template v-for="(item, index) in state.ruleForm.LanIPs" :key="index">
<div class="flex" style="margin-bottom:.6rem">
<div class="flex-1">
<el-input v-model="state.ruleForm.LanIPs[index]" style="width:12rem" /> / <el-input @change="handleMaskChange(index)" v-model="state.ruleForm.Masks[index]" style="width:4rem" />
<el-input v-model="state.ruleForm.LanIPs[index]" style="width:14rem" />
<span>/</span>
<el-input @change="handleMaskChange(index)" v-model="state.ruleForm.Masks[index]" style="width:4rem" />
</div>
<div class="pdl-10">
<el-button type="danger" @click="handleDel(index)"><el-icon><Delete /></el-icon></el-button>
@@ -31,15 +46,15 @@
</div>
</template>
</el-form-item>
<el-form-item prop="gateway" style="margin-bottom:0">
<span class="yellow">此设备不能用NAT转发那可以使用系统端口转发实现类似的效果(仅windows)</span>
<el-form-item prop="forward" style="margin-bottom:0">
<span class="yellow">此设备无法使用NAT转发或只想使用端口转发</span>
</el-form-item>
<el-form-item label="端口转发" prop="foreards">
<el-form-item label="端口转发" prop="forwards">
<template v-for="(item, index) in state.ruleForm.Forwards" :key="index">
<div class="flex" style="margin-bottom:.6rem">
<div class="flex-1">
<el-input v-model="item.ListenAddr" style="width:7rem" readonly /> : <el-input @change="handleForwardChange(index)" v-model="item.ListenPort" style="width:6rem" />
-> <el-input v-model="item.ConnectAddr" style="width:12rem" /> : <el-input @change="handleForwardChange(index)" v-model="item.ConnectPort" style="width:6rem" />
-> <el-input v-model="item.ConnectAddr" style="width:14rem" /> : <el-input @change="handleForwardChange(index)" v-model="item.ConnectPort" style="width:6rem" />
</div>
<div class="pdl-10">
@@ -85,6 +100,8 @@ export default {
Masks: tuntap.value.current.Masks.slice(0),
PrefixLength:tuntap.value.current.PrefixLength || 24,
Gateway: tuntap.value.current.Gateway,
ShowDelay: tuntap.value.current.ShowDelay,
AutoConnect: tuntap.value.current.AutoConnect,
Upgrade: tuntap.value.current.Upgrade,
Forwards:tuntap.value.current.Forwards.length == 0 ? [
@@ -144,6 +161,8 @@ export default {
json.Masks = masks;
json.PrefixLength = +state.ruleForm.PrefixLength;
json.Gateway = state.ruleForm.Gateway;
json.ShowDelay = state.ruleForm.ShowDelay;
json.AutoConnect = state.ruleForm.AutoConnect;
json.Upgrade = state.ruleForm.Upgrade;
json.Forwards = state.ruleForm.Forwards;
json.Forwards.forEach(c=>{
@@ -185,6 +204,6 @@ export default {
.upgrade-wrap{
border:1px solid #ddd;
margin-bottom:2rem
padding:1rem 0;
padding:0 0 1rem 0;
}
</style>

View File

@@ -55,7 +55,6 @@ export default {
bufferSize:globalData.value.bufferSize
});
watch(()=>globalData.value.config.Running.Tunnel.Transports,()=>{
console.log(globalData.value.config.Running.Tunnel.Transports);
state.list = globalData.value.config.Running.Tunnel.Transports.sort((a,b)=>a.Order - b.Order);
});

View File

@@ -155,7 +155,12 @@ namespace linker.plugins.relay
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);
.Where(c => c.Delay >= 0);
if (running.Data.Relay.ByRelay)
{
servers = servers.OrderBy(c => c.Delay);
}
foreach (RelayServerInfo item in servers)
{
ITransport transport = transports.FirstOrDefault(c => c.Type == item.RelayType);
@@ -278,43 +283,20 @@ namespace linker.plugins.relay
{
try
{
var tasks = running.Data.Relay.Servers.Select(c =>
foreach (var server in running.Data.Relay.Servers)
{
try
{
ITransport transport = transports.FirstOrDefault(d => d.Type == c.RelayType);
if (transport == null) return null;
ITransport transport = transports.FirstOrDefault(d => d.Type == server.RelayType);
if (transport == null) continue;
IPEndPoint server = NetworkHelper.GetEndPoint(c.Host, 3478);
return new TestInfo
{
Server = c,
Task = transport.RelayTestAsync(new RelayTestInfo
IPEndPoint serverEP = NetworkHelper.GetEndPoint(server.Host, 3478);
RelayTestResultInfo result = await transport.RelayTestAsync(new RelayTestInfo
{
MachineId = fileConfig.Data.Client.Id,
SecretKey = c.SecretKey,
Server = server,
})
};
}
catch (Exception)
{
}
return null;
SecretKey = server.SecretKey,
Server = serverEP,
});
try
{
await Task.WhenAll(tasks.Where(c => c != null).Select(c => c.Task)).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
foreach (var item in tasks.Where(c => c != null))
{
item.Server.Delay = item.Task.Result.Delay;
item.Server.Available = item.Task.Result.Available;
}
}
catch (Exception)
{
server.Delay = result.Delay;
server.Available = result.Available;
}
}
catch (Exception)

View File

@@ -228,7 +228,7 @@ namespace linker.plugins.relay.transport
{
Socket socket = new Socket(relayTestInfo.Server.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(relayTestInfo.Server).WaitAsync(TimeSpan.FromMilliseconds(500)).ConfigureAwait(false);
await socket.ConnectAsync(relayTestInfo.Server).WaitAsync(TimeSpan.FromMilliseconds(1000)).ConfigureAwait(false);
connection = await messengerResolver.BeginReceiveClient(socket);
@@ -249,7 +249,6 @@ namespace linker.plugins.relay.transport
}
catch (Exception)
{
}
finally
{

View File

@@ -46,17 +46,16 @@ namespace linker.plugins.tunnel
/// <returns></returns>
public TunnelListInfo Get(ApiControllerParamsInfo param)
{
uint hashCode = uint.Parse(param.Content);
uint _hashCode = tunnelConfigTransfer.ConfigVersion;
if (_hashCode != hashCode)
ulong hashCode = ulong.Parse(param.Content);
if (tunnelConfigTransfer.Version.Eq(hashCode,out ulong version))
{
return new TunnelListInfo
{
List = tunnelConfigTransfer.Config,
HashCode = _hashCode
HashCode = version
};
}
return new TunnelListInfo { HashCode = _hashCode };
return new TunnelListInfo { HashCode = version };
}
/// <summary>
/// 刷新隧道信息
@@ -145,7 +144,7 @@ namespace linker.plugins.tunnel
public sealed class TunnelListInfo
{
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> List { get; set; }
public uint HashCode { get; set; }
public ulong HashCode { get; set; }
}
}

View File

@@ -24,11 +24,8 @@ namespace linker.plugins.tunnel
private readonly TransportTcpPortMap transportTcpPortMap;
private readonly TransportUdpPortMap transportUdpPortMap;
private uint version = 0;
public uint ConfigVersion => version;
private ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> configs = new ConcurrentDictionary<string, TunnelTransportRouteLevelInfo>();
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> Config => configs;
public VersionManager Version { get; } = new VersionManager();
public ConcurrentDictionary<string, TunnelTransportRouteLevelInfo> Config { get; } = new ConcurrentDictionary<string, TunnelTransportRouteLevelInfo>();
public TunnelConfigTransfer(FileConfig config, RunningConfig running, ClientSignInState clientSignInState, MessengerSender messengerSender, RunningConfigTransfer runningConfigTransfer, ITunnelAdapter tunnelAdapter, TransportTcpPortMap transportTcpPortMap, TransportUdpPortMap transportUdpPortMap)
{
@@ -108,8 +105,8 @@ namespace linker.plugins.tunnel
/// <returns></returns>
public TunnelTransportRouteLevelInfo OnRemoteRouteLevel(TunnelTransportRouteLevelInfo tunnelTransportFileConfigInfo)
{
configs.AddOrUpdate(tunnelTransportFileConfigInfo.MachineId, tunnelTransportFileConfigInfo, (a, b) => tunnelTransportFileConfigInfo);
Interlocked.Increment(ref version);
Config.AddOrUpdate(tunnelTransportFileConfigInfo.MachineId, tunnelTransportFileConfigInfo, (a, b) => tunnelTransportFileConfigInfo);
Version.Add();
return GetLocalRouteLevel();
}
private void GetRemoteRouteLevel()
@@ -128,11 +125,11 @@ namespace linker.plugins.tunnel
List<TunnelTransportRouteLevelInfo> list = MemoryPackSerializer.Deserialize<List<TunnelTransportRouteLevelInfo>>(result.Result.Data.Span);
foreach (var item in list)
{
configs.AddOrUpdate(item.MachineId, item, (a, b) => item);
Config.AddOrUpdate(item.MachineId, item, (a, b) => item);
}
TunnelTransportRouteLevelInfo config = GetLocalRouteLevel();
configs.AddOrUpdate(config.MachineId, config, (a, b) => config);
Interlocked.Increment(ref version);
Config.AddOrUpdate(config.MachineId, config, (a, b) => config);
Version.Add();
}
});
}
@@ -145,7 +142,7 @@ namespace linker.plugins.tunnel
RouteLevelPlus = running.Data.Tunnel.RouteLevelPlus,
PortMapWan = running.Data.Tunnel.PortMapWan,
PortMapLan = running.Data.Tunnel.PortMapLan,
NeedReboot = reboot
NeedReboot = false
};
}
private void InitRouteLevel()
@@ -157,7 +154,6 @@ namespace linker.plugins.tunnel
}
bool reboot = false;
private void TestQuic()
{
if (OperatingSystem.IsWindows())
@@ -172,7 +168,6 @@ namespace linker.plugins.tunnel
File.Move("msquic.dll", "msquic.dll.temp", true);
File.Move("msquic-openssl.dll", "msquic.dll", true);
reboot = true;
Environment.Exit(1);
}
}

View File

@@ -46,17 +46,16 @@ namespace linker.plugins.tuntap
/// <returns></returns>
public TuntabListInfo Get(ApiControllerParamsInfo param)
{
uint hashCode = uint.Parse(param.Content);
uint _hashCode = tuntapTransfer.InfosVersion;
if (_hashCode != hashCode)
ulong hashCode = ulong.Parse(param.Content);
if (tuntapTransfer.Version.Eq(hashCode, out ulong version))
{
return new TuntabListInfo
{
List = tuntapTransfer.Infos,
HashCode = _hashCode
HashCode = version
};
}
return new TuntabListInfo { HashCode = _hashCode };
return new TuntabListInfo { HashCode = version };
}
/// <summary>
/// 刷新网卡信息
@@ -147,7 +146,7 @@ namespace linker.plugins.tuntap
public sealed class TuntabListInfo
{
public ConcurrentDictionary<string, TuntapInfo> List { get; set; }
public uint HashCode { get; set; }
public ulong HashCode { get; set; }
}
}
}

View File

@@ -12,6 +12,7 @@ using linker.plugins.client;
using linker.plugins.messenger;
using linker.plugins.tuntap.config;
using linker.tun;
using linker.tunnel.connection;
namespace linker.plugins.tuntap
{
@@ -25,16 +26,15 @@ namespace linker.plugins.tuntap
private readonly LinkerTunDeviceAdapter linkerTunDeviceAdapter;
private string deviceName = "linker";
private uint operating = 0;
private List<IPAddress> routeIps = new List<IPAddress>();
private uint infosVersion = 0;
public uint InfosVersion => infosVersion;
public VersionManager Version { get; } = new VersionManager();
private readonly ConcurrentDictionary<string, TuntapInfo> tuntapInfos = new ConcurrentDictionary<string, TuntapInfo>();
public ConcurrentDictionary<string, TuntapInfo> Infos => tuntapInfos;
public TuntapStatus Status => operating == 1 ? TuntapStatus.Operating : (TuntapStatus)(byte)linkerTunDeviceAdapter.Status;
private OperatingManager operatingManager = new OperatingManager();
public TuntapStatus Status => operatingManager.Operating ? TuntapStatus.Operating : (TuntapStatus)(byte)linkerTunDeviceAdapter.Status;
public TuntapTransfer(MessengerSender messengerSender, ClientSignInState clientSignInState, LinkerTunDeviceAdapter linkerTunDeviceAdapter, FileConfig config, TuntapProxy tuntapProxy, RunningConfig runningConfig)
{
@@ -59,6 +59,7 @@ namespace linker.plugins.tuntap
NetworkHelper.GetRouteLevel(config.Data.Client.Server, out routeIps);
NotifyConfig();
CheckTuntapStatusTask();
PingTask();
if (runningConfig.Data.Tuntap.Running)
{
Setup();
@@ -71,7 +72,7 @@ namespace linker.plugins.tuntap
/// </summary>
public void Setup()
{
if (Interlocked.CompareExchange(ref operating, 1, 0) == 1)
if (operatingManager.StartOperation() == false)
{
return;
}
@@ -111,7 +112,7 @@ namespace linker.plugins.tuntap
}
private void SetupAfter()
{
Interlocked.Exchange(ref operating, 0);
operatingManager.StopOperation();
NotifyConfig();
}
private void SetupSuccess()
@@ -127,7 +128,7 @@ namespace linker.plugins.tuntap
/// </summary>
public void Shutdown()
{
if (Interlocked.CompareExchange(ref operating, 1, 0) == 1)
if (operatingManager.StartOperation() == false)
{
return;
}
@@ -155,7 +156,7 @@ namespace linker.plugins.tuntap
}
private void ShutdownAfter()
{
Interlocked.Exchange(ref operating, 0);
operatingManager.StopOperation();
NotifyConfig();
}
private void ShutdownSuccess()
@@ -188,6 +189,8 @@ namespace linker.plugins.tuntap
runningConfig.Data.Tuntap.Masks = info.Masks;
runningConfig.Data.Tuntap.PrefixLength = info.PrefixLength;
runningConfig.Data.Tuntap.Gateway = info.Gateway;
runningConfig.Data.Tuntap.ShowDelay = info.ShowDelay;
runningConfig.Data.Tuntap.AutoConnect = info.AutoConnect;
runningConfig.Data.Tuntap.Upgrade = info.Upgrade;
runningConfig.Data.Tuntap.Forwards = info.Forwards;
runningConfig.Data.Update();
@@ -214,7 +217,7 @@ namespace linker.plugins.tuntap
{
DelRoute();
tuntapInfos.AddOrUpdate(info.MachineId, info, (a, b) => info);
Interlocked.Increment(ref infosVersion);
Version.Add();
AddRoute();
});
@@ -240,7 +243,7 @@ namespace linker.plugins.tuntap
}
AddRoute();
}
Interlocked.Increment(ref infosVersion);
Version.Add();
});
}
/// <summary>
@@ -260,9 +263,12 @@ namespace linker.plugins.tuntap
Error = linkerTunDeviceAdapter.Error,
Error1 = linkerTunDeviceAdapter.Error1,
SystemInfo = $"{System.Runtime.InteropServices.RuntimeInformation.OSDescription} {(string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")) == false ? "Docker" : "")}",
Gateway = runningConfig.Data.Tuntap.Gateway,
Upgrade = runningConfig.Data.Tuntap.Upgrade,
Forwards = runningConfig.Data.Tuntap.Forwards,
Switch = (runningConfig.Data.Tuntap.Gateway ? TuntapSwitch.Gateway : 0)
| (runningConfig.Data.Tuntap.Upgrade ? TuntapSwitch.Upgrade : 0)
| (runningConfig.Data.Tuntap.ShowDelay ? TuntapSwitch.ShowDelay : 0)
| (runningConfig.Data.Tuntap.AutoConnect ? TuntapSwitch.AutoConnect : 0)
};
if (runningConfig.Data.Tuntap.Masks.Length != runningConfig.Data.Tuntap.LanIPs.Length)
{
@@ -404,7 +410,7 @@ namespace linker.plugins.tuntap
await Task.Delay(15000).ConfigureAwait(false);
try
{
if (runningConfig.Data.Tuntap.Running && OperatingSystem.IsWindows() && operating == 0)
if (runningConfig.Data.Tuntap.Running && OperatingSystem.IsWindows() && operatingManager.Operating == false)
{
await CheckInterface().ConfigureAwait(false);
}
@@ -419,18 +425,64 @@ namespace linker.plugins.tuntap
{
NetworkInterface networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(c => c.Name == deviceName);
if (networkInterface == null || networkInterface.OperationalStatus != OperationalStatus.Up && operating == 0)
if (networkInterface == null || networkInterface.OperationalStatus != OperationalStatus.Up && operatingManager.Operating == false)
{
LoggerHelper.Instance.Error($"tuntap inerface {deviceName} is {networkInterface?.OperationalStatus ?? OperationalStatus.Unknown}, restarting");
Shutdown();
await Task.Delay(5000).ConfigureAwait(false);
networkInterface = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(c => c.Name == deviceName);
if (networkInterface == null || networkInterface.OperationalStatus != OperationalStatus.Up && operating == 0)
if (networkInterface == null || networkInterface.OperationalStatus != OperationalStatus.Up && operatingManager.Operating == false)
{
Setup();
}
}
}
private void PingTask()
{
Task.Run(async () =>
{
while (true)
{
if (Status == TuntapStatus.Running && runningConfig.Data.Tuntap.ShowDelay)
{
var items = tuntapInfos.Values.Where(c => c.IP != null && c.IP.Equals(IPAddress.Any) == false);
if (runningConfig.Data.Tuntap.AutoConnect == false)
{
var connections = tuntapProxy.GetConnections();
items = items.Where(c => (connections.TryGetValue(c.MachineId, out ITunnelConnection connection) && connection.Connected) || c.MachineId == config.Data.Client.Id);
}
var tasks = items.Select(c =>
{
Ping ping = new Ping();
return new PingTaskInfo
{
TuntapInfo = c,
Ping = ping,
Task = ping.SendPingAsync(c.IP, 1000)
};
});
await Task.WhenAll(tasks.Select(c => c.Task));
foreach (var item in tasks.Where(c => c.Task.Result != null))
{
item.TuntapInfo.Delay = item.Task.Result.Status == IPStatus.Success ? (int)item.Task.Result.RoundtripTime : -1;
item.Ping.Dispose();
}
Version.Add();
}
await Task.Delay(3000);
}
});
}
public sealed class PingTaskInfo
{
public TuntapInfo TuntapInfo { get; set; }
public Ping Ping { get; set; }
public Task<PingReply> Task { get; set; }
}
}
}

View File

@@ -4,15 +4,18 @@ using System.Net;
namespace linker.plugins.tuntap.config
{
public sealed class TuntapConfigInfo
[MemoryPackable]
public sealed partial class TuntapConfigInfo
{
/// <summary>
/// 网卡IP
/// </summary>
[MemoryPackAllowSerialize]
public IPAddress IP { get; set; } = IPAddress.Any;
/// <summary>
/// 局域网IP列表
/// </summary>
[MemoryPackAllowSerialize]
public IPAddress[] LanIPs { get; set; } = Array.Empty<IPAddress>();
/// <summary>
/// 局域网掩码列表与IP列表一一对应
@@ -33,9 +36,19 @@ namespace linker.plugins.tuntap.config
/// </summary>
public bool Gateway { get; set; }
/// <summary>
/// 显示延迟
/// </summary>
public bool ShowDelay { get; set; }
/// <summary>
/// 自动连接
/// </summary>
public bool AutoConnect { get; set; }
/// <summary>
/// 使用高级功能
/// </summary>
public bool Upgrade { get; set; }
/// <summary>
/// 端口转发列表
/// </summary>
@@ -103,6 +116,12 @@ namespace linker.plugins.tuntap.config
[MemoryPackAllowSerialize]
public IPAddress IP { get; set; }
/// <summary>
/// 前缀长度
/// </summary>
public byte PrefixLength { get; set; } = 24;
/// <summary>
/// 局域网IP
/// </summary>
@@ -115,11 +134,6 @@ namespace linker.plugins.tuntap.config
public int[] Masks { get; set; } = Array.Empty<int>();
/// <summary>
/// 前缀长度
/// </summary>
public byte PrefixLength { get; set; } = 24;
/// <summary>
/// 网卡安装错误
/// </summary>
@@ -132,18 +146,120 @@ namespace linker.plugins.tuntap.config
/// 系统信息
/// </summary>
public string SystemInfo { get; set; }
/// <summary>
/// 是否网关
/// </summary>
public bool Gateway { get; set; }
/// <summary>
/// 使用高级功能
/// </summary>
public bool Upgrade { get; set; }
/// <summary>
/// 端口转发列表
/// </summary>
public List<TuntapForwardInfo> Forwards { get; set; } = new List<TuntapForwardInfo>();
/// <summary>
/// 延迟ms
/// </summary>
public int Delay { get; set; } = -1;
/// <summary>
/// 开关多个bool集合
/// </summary>
public TuntapSwitch Switch { get; set; }
/// <summary>
/// 是否网关
/// </summary>
[MemoryPackIgnore]
public bool Gateway
{
get
{
return (Switch & TuntapSwitch.Gateway) == TuntapSwitch.Gateway;
}
set
{
if (value)
{
Switch |= TuntapSwitch.Gateway;
}
else
{
Switch &= ~TuntapSwitch.Gateway;
}
}
}
/// <summary>
/// 显示延迟
/// </summary>
[MemoryPackIgnore]
public bool ShowDelay
{
get
{
return (Switch & TuntapSwitch.ShowDelay) == TuntapSwitch.ShowDelay;
}
set
{
if (value)
{
Switch |= TuntapSwitch.ShowDelay;
}
else
{
Switch &= ~TuntapSwitch.ShowDelay;
}
}
}
/// <summary>
/// 自动连接
/// </summary>
[MemoryPackIgnore]
public bool AutoConnect
{
get
{
return (Switch & TuntapSwitch.AutoConnect) == TuntapSwitch.AutoConnect;
}
set
{
if (value)
{
Switch |= TuntapSwitch.AutoConnect;
}
else
{
Switch &= ~TuntapSwitch.AutoConnect;
}
}
}
/// <summary>
/// 使用高级功能
/// </summary>
[MemoryPackIgnore]
public bool Upgrade
{
get
{
return (Switch & TuntapSwitch.Upgrade) == TuntapSwitch.Upgrade;
}
set
{
if (value)
{
Switch |= TuntapSwitch.Upgrade;
}
else
{
Switch &= ~TuntapSwitch.Upgrade;
}
}
}
}
[Flags]
public enum TuntapSwitch
{
Gateway = 1,
ShowDelay = 2,
Upgrade = 4,
AutoConnect = 8,
}

View File

@@ -9,8 +9,6 @@ using System.Collections.Concurrent;
using linker.plugins.tuntap.config;
using linker.tun;
using System.Buffers.Binary;
using System.Net.Sockets;
using System.Net;
namespace linker.plugins.tuntap.proxy
{
@@ -27,8 +25,7 @@ namespace linker.plugins.tuntap.proxy
private readonly ConcurrentDictionary<string, ITunnelConnection> connections = new ConcurrentDictionary<string, ITunnelConnection>();
private readonly ConcurrentDictionary<uint, ITunnelConnection> ipConnections = new ConcurrentDictionary<uint, ITunnelConnection>();
SemaphoreSlim slimGlobal = new SemaphoreSlim(1);
private readonly ConcurrentDictionary<string, SemaphoreSlim> dicLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
private readonly OperatingMultipleManager operatingMultipleManager = new OperatingMultipleManager();
public TuntapProxy(TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, RunningConfig runningConfig, FileConfig config, LinkerTunDeviceAdapter linkerTunDeviceAdapter)
{
@@ -112,7 +109,6 @@ namespace linker.plugins.tuntap.proxy
}
}
/// <summary>
/// 设置IP等下有连接进来用IP匹配才能知道这个连接是要连谁
/// </summary>
@@ -179,23 +175,13 @@ namespace linker.plugins.tuntap.proxy
return connection;
}
await slimGlobal.WaitAsync().ConfigureAwait(false);
if (dicLocks.TryGetValue(machineId, out SemaphoreSlim slim) == false)
if(operatingMultipleManager.StartOperation(machineId) ==false)
{
slim = new SemaphoreSlim(1);
dicLocks.TryAdd(machineId, slim);
return null;
}
slimGlobal.Release();
await slim.WaitAsync().ConfigureAwait(false);
try
{
if (connections.TryGetValue(machineId, out connection) && connection.Connected)
{
return connection;
}
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"tuntap tunnel to {machineId}");
connection = await tunnelTransfer.ConnectAsync(machineId, "tuntap", TunnelProtocolType.None).ConfigureAwait(false);
@@ -210,7 +196,6 @@ namespace linker.plugins.tuntap.proxy
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "tuntap").ConfigureAwait(false);
if (connection != null)
{
//tunnelTransfer.StartBackground(machineId, "tuntap");
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"tuntap relay success,{connection.ToString()}");
}
}
@@ -224,7 +209,7 @@ namespace linker.plugins.tuntap.proxy
}
finally
{
slim.Release();
operatingMultipleManager.StopOperation(machineId);
}
return connection;
}