diff --git a/cmonitor.web.client/src/views/servers/Transports.vue b/cmonitor.web.client/src/views/servers/Transports.vue
index fda4b100..80c508bb 100644
--- a/cmonitor.web.client/src/views/servers/Transports.vue
+++ b/cmonitor.web.client/src/views/servers/Transports.vue
@@ -9,6 +9,11 @@
+
+
+
+
+
diff --git a/cmonitor/client/ClientSignInTransfer.cs b/cmonitor/client/ClientSignInTransfer.cs
index e26e1175..435e92fa 100644
--- a/cmonitor/client/ClientSignInTransfer.cs
+++ b/cmonitor/client/ClientSignInTransfer.cs
@@ -28,16 +28,15 @@ namespace cmonitor.client
this.messengerSender = messengerSender;
this.signInArgsTransfer = signInArgsTransfer;
- SignInTask();
+ //SignInTask();
}
- private void SignInTask()
+ public void SignInTask()
{
Task.Run(async () =>
{
while (true)
{
-
if (clientSignInState.Connected == false)
{
try
diff --git a/cmonitor/client/ClientStartup.cs b/cmonitor/client/ClientStartup.cs
index 16555811..25d37211 100644
--- a/cmonitor/client/ClientStartup.cs
+++ b/cmonitor/client/ClientStartup.cs
@@ -49,7 +49,7 @@ namespace cmonitor.client
if (string.IsNullOrWhiteSpace(config.Data.Client.Server) && config.Data.Client.Servers.Length > 0)
config.Data.Client.Server = config.Data.Client.Servers.FirstOrDefault().Host;
ClientSignInTransfer clientTransfer = serviceProvider.GetService();
-
+ clientTransfer.SignInTask();
}
diff --git a/cmonitor/client/tunnel/TunnelConnectionMsQuic.cs b/cmonitor/client/tunnel/TunnelConnectionMsQuic.cs
index 609fb728..a2eb978d 100644
--- a/cmonitor/client/tunnel/TunnelConnectionMsQuic.cs
+++ b/cmonitor/client/tunnel/TunnelConnectionMsQuic.cs
@@ -6,6 +6,7 @@ using System.Net.Quic;
using System.Net;
using System.Text;
using System.Text.Json.Serialization;
+using System.Net.Sockets;
namespace cmonitor.client.tunnel
{
@@ -32,6 +33,11 @@ namespace cmonitor.client.tunnel
[JsonIgnore]
public QuicConnection Connection { get; init; }
+ [JsonIgnore]
+ public UdpClient LocalUdp { get; init; }
+ [JsonIgnore]
+ public UdpClient remoteUdp { get; init; }
+
private ITunnelConnectionReceiveCallback callback;
private CancellationTokenSource cancellationTokenSource;
@@ -256,6 +262,9 @@ namespace cmonitor.client.tunnel
Connection?.CloseAsync(0x0a);
Connection?.DisposeAsync();
+
+ LocalUdp?.Close();
+ remoteUdp?.Close();
}
public override string ToString()
diff --git a/cmonitor/plugins/tunnel/TunnelTransfer.cs b/cmonitor/plugins/tunnel/TunnelTransfer.cs
index 91b97710..d00ae221 100644
--- a/cmonitor/plugins/tunnel/TunnelTransfer.cs
+++ b/cmonitor/plugins/tunnel/TunnelTransfer.cs
@@ -10,6 +10,7 @@ using common.libs.extends;
using MemoryPack;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
+using System.Net;
using System.Reflection;
namespace cmonitor.plugins.tunnel
@@ -59,7 +60,7 @@ namespace cmonitor.plugins.tunnel
//拼接,再去重,因为有可能有新的
config.Data.Client.Tunnel.TunnelTransports = config.Data.Client.Tunnel.TunnelTransports
- .Concat(transports.Select(c => new TunnelTransportItemInfo { Disabled = c.Disabled, Label = c.Label, Name = c.Name, ProtocolType = c.ProtocolType.ToString() }))
+ .Concat(transports.Select(c => new TunnelTransportItemInfo { Reverse = true, Disabled = false, Label = c.Label, Name = c.Name, ProtocolType = c.ProtocolType.ToString() }))
.Distinct(new TunnelTransportItemInfoEqualityComparer())
.ToList();
@@ -91,6 +92,7 @@ namespace cmonitor.plugins.tunnel
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)TunnelMessengerIds.ConfigForward,
+ Timeout = 3000,
Payload = MemoryPackSerializer.Serialize(config)
}).ContinueWith((result) =>
{
@@ -157,7 +159,8 @@ namespace cmonitor.plugins.tunnel
* 所以,我们需要在第一次正向连接失败后再尝试反向连接,因为间隔了一定时间,最大程度避免了连续端口污染
*/
TunnelTransportInfo tunnelTransportInfo = null;
- for (int i = 0; i <= 0; i++)
+ int times = transportItem.Reverse ? 1 : 0;
+ for (int i = 0; i <= times; i++)
{
try
{
@@ -197,7 +200,7 @@ namespace cmonitor.plugins.tunnel
}
catch (Exception ex)
{
- if(Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
+ if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Error(ex);
}
@@ -243,7 +246,7 @@ namespace cmonitor.plugins.tunnel
private async Task GetLocalInfo()
{
- TunnelCompactIPEndPoint ip = await compactTransfer.GetExternalIPAsync();
+ TunnelCompactIPEndPoint ip = await compactTransfer.GetExternalIPAsync(clientSignInState.Connection?.LocalAddress.Address ?? IPAddress.Any);
if (ip != null)
{
return new TunnelTransportExternalIPInfo
diff --git a/cmonitor/plugins/tunnel/compact/TunnelCompactSelfHost.cs b/cmonitor/plugins/tunnel/compact/TunnelCompactSelfHost.cs
index dbe2dce2..85e5ce1d 100644
--- a/cmonitor/plugins/tunnel/compact/TunnelCompactSelfHost.cs
+++ b/cmonitor/plugins/tunnel/compact/TunnelCompactSelfHost.cs
@@ -11,21 +11,17 @@ namespace cmonitor.plugins.tunnel.compact
public string Name => "默认";
public TunnelCompactType Type => TunnelCompactType.Self;
- public static UdpClient udpClient;
-
public TunnelCompactSelfHost()
{
}
public async Task GetExternalIPAsync(IPEndPoint server)
{
- udpClient = new UdpClient(AddressFamily.InterNetwork);
- //udpClient.Client.IPv6Only(AddressFamily.InterNetworkV6, false);
- udpClient.Client.Reuse(true);
- udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, new Random().Next(10000, 50000)));
-
+ UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork);
+ udpClient.Client.Reuse();
+ udpClient.Client.WindowsUdpBug();
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < 5; i++)
{
try
{
@@ -54,22 +50,6 @@ namespace cmonitor.plugins.tunnel.compact
}
}
- Task.Run(async () =>
- {
- while (true)
- {
- try
- {
- UdpReceiveResult result = await udpClient.ReceiveAsync();
- Logger.Instance.Error(Encoding.UTF8.GetString(result.Buffer));
- }
- catch (Exception ex)
- {
- Logger.Instance.Error(ex);
- }
- }
- });
-
return null;
}
}
diff --git a/cmonitor/plugins/tunnel/compact/TunnelCompactTransfer.cs b/cmonitor/plugins/tunnel/compact/TunnelCompactTransfer.cs
index 4051363a..f23f8c53 100644
--- a/cmonitor/plugins/tunnel/compact/TunnelCompactTransfer.cs
+++ b/cmonitor/plugins/tunnel/compact/TunnelCompactTransfer.cs
@@ -41,7 +41,7 @@ namespace cmonitor.plugins.tunnel.compact
config.Save();
}
- public async Task GetExternalIPAsync()
+ public async Task GetExternalIPAsync(IPAddress localIP)
{
for (int i = 0; i < config.Data.Client.Tunnel.Servers.Length; i++)
{
@@ -61,7 +61,11 @@ namespace cmonitor.plugins.tunnel.compact
Logger.Instance.Warning($"get domain ip time:{sw.ElapsedMilliseconds}ms");
}
TunnelCompactIPEndPoint externalIP = await compact.GetExternalIPAsync(server);
- if (externalIP != null) return externalIP;
+ if (externalIP != null)
+ {
+ externalIP.Local.Address = localIP;
+ return externalIP;
+ }
}
catch (Exception ex)
{
diff --git a/cmonitor/plugins/tunnel/messenger/TunnelMessenger.cs b/cmonitor/plugins/tunnel/messenger/TunnelMessenger.cs
index 29b2f2d4..e6024e0d 100644
--- a/cmonitor/plugins/tunnel/messenger/TunnelMessenger.cs
+++ b/cmonitor/plugins/tunnel/messenger/TunnelMessenger.cs
@@ -114,7 +114,8 @@ namespace cmonitor.plugins.tunnel.messenger
{
Connection = cache.Connection,
MessengerId = (ushort)TunnelMessengerIds.Info,
- Payload = connection.ReceiveRequestWrap.Payload
+ Payload = connection.ReceiveRequestWrap.Payload,
+ Timeout = 3000,
});
if (resp.Code == MessageResponeCodes.OK && resp.Data.Span.Length > 0)
{
@@ -131,7 +132,7 @@ namespace cmonitor.plugins.tunnel.messenger
if (signCaching.Get(tunnelTransportInfo.Remote.MachineName, out SignCacheInfo cache) && signCaching.Get(connection.Name, out SignCacheInfo cache1) && cache.GroupId == cache1.GroupId)
{
- await messengerSender.SendReply(new MessageRequestWrap
+ await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = cache.Connection,
MessengerId = (ushort)TunnelMessengerIds.Begin,
@@ -204,6 +205,7 @@ namespace cmonitor.plugins.tunnel.messenger
{
Connection = item.Connection,
MessengerId = (ushort)TunnelMessengerIds.Config,
+ Timeout = 3000,
Payload = connection.ReceiveRequestWrap.Payload
}));
}
diff --git a/cmonitor/plugins/tunnel/transport/ITunnelTransport.cs b/cmonitor/plugins/tunnel/transport/ITunnelTransport.cs
index 91757e1c..8fc3217a 100644
--- a/cmonitor/plugins/tunnel/transport/ITunnelTransport.cs
+++ b/cmonitor/plugins/tunnel/transport/ITunnelTransport.cs
@@ -8,7 +8,6 @@ namespace cmonitor.plugins.tunnel.transport
{
public string Name { get; }
public string Label { get; }
- public bool Disabled { get; }
public TunnelProtocolType ProtocolType { get; }
///
@@ -93,6 +92,7 @@ namespace cmonitor.plugins.tunnel.transport
public string ProtocolType { get; set; }
public bool Disabled { get; set; }
+ public bool Reverse { get; set; }
}
public sealed class TunnelTransportItemInfoEqualityComparer : IEqualityComparer
{
diff --git a/cmonitor/plugins/tunnel/transport/TransportMsQuic.cs b/cmonitor/plugins/tunnel/transport/TransportMsQuic.cs
index f3c6cb14..a671f1ac 100644
--- a/cmonitor/plugins/tunnel/transport/TransportMsQuic.cs
+++ b/cmonitor/plugins/tunnel/transport/TransportMsQuic.cs
@@ -18,9 +18,7 @@ namespace cmonitor.plugins.tunnel.transport
{
public string Name => "msquic";
- public string Label => "UDP,MsQuic";
-
- public bool Disabled => false;
+ public string Label => "UDP over MsQuic,win11+、linux";
public TunnelProtocolType ProtocolType => TunnelProtocolType.Quic;
@@ -30,6 +28,10 @@ namespace cmonitor.plugins.tunnel.transport
public Action OnConnected { get; set; } = (state) => { };
+ private ConcurrentDictionary stateDic = new ConcurrentDictionary();
+ private byte[] authBytes = Encoding.UTF8.GetBytes("snltty.ttl");
+ private byte[] endBytes = Encoding.UTF8.GetBytes("snltty.end");
+ private IPEndPoint quicListenEP = null;
private X509Certificate serverCertificate;
public TransportMsQuic(Config config)
@@ -44,10 +46,9 @@ namespace cmonitor.plugins.tunnel.transport
Logger.Instance.Error($"file {path} not found");
Environment.Exit(0);
}
+ _ = QuicStart();
}
-
-
public async Task ConnectAsync(TunnelTransportInfo tunnelTransportInfo)
{
if (OperatingSystem.IsWindows() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
@@ -78,8 +79,9 @@ namespace cmonitor.plugins.tunnel.transport
{
//反向连接
TunnelTransportInfo tunnelTransportInfo1 = tunnelTransportInfo.ToJsonFormat().DeJson();
+ _ = BindListen(tunnelTransportInfo1.Local.Local, quicListenEP, tunnelTransportInfo1);
+ await Task.Delay(50);
BindAndTTL(tunnelTransportInfo1);
- _ = QuicStart(tunnelTransportInfo1.Local.Local, tunnelTransportInfo1);
if (await OnSendConnectBegin(tunnelTransportInfo1) == false)
{
return null;
@@ -101,18 +103,17 @@ namespace cmonitor.plugins.tunnel.transport
{
if (QuicListener.IsSupported == false)
{
- //OnSendConnectFail(tunnelTransportInfo);
- //return;
+ OnSendConnectFail(tunnelTransportInfo);
+ return;
}
}
Task.Run(async () =>
{
if (tunnelTransportInfo.Direction == TunnelDirection.Forward)
{
- BindAndTTL(tunnelTransportInfo);
- Logger.Instance.Error($"ttl");
+ _ = BindListen(tunnelTransportInfo.Local.Local, quicListenEP, tunnelTransportInfo);
await Task.Delay(50);
- _ = QuicStart(tunnelTransportInfo.Local.Local, tunnelTransportInfo);
+ BindAndTTL(tunnelTransportInfo);
}
else
{
@@ -131,16 +132,109 @@ namespace cmonitor.plugins.tunnel.transport
});
}
+ private (UdpClient, UdpClient) BindListen(IPEndPoint local, TaskCompletionSource tcs)
+ {
+ UdpClient udpClient = new UdpClient(local.AddressFamily);
+ udpClient.Client.ReuseBind(local);
+ udpClient.Client.WindowsUdpBug();
+ IAsyncResult result = udpClient.BeginReceive((IAsyncResult result) =>
+ {
+ try
+ {
+ IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
+ byte[] bytes = udpClient.EndReceive(result, ref ep);
+ udpClient.Send(endBytes, ep);
+ tcs.SetResult(ep);
+ }
+ catch (Exception)
+ {
+ }
+ }, null);
+
+ UdpClient udpClient6 = new UdpClient(AddressFamily.InterNetworkV6);
+ udpClient6.Client.ReuseBind(new IPEndPoint(IPAddress.IPv6Any, local.Port));
+ udpClient6.Client.WindowsUdpBug();
+ IAsyncResult result6 = udpClient6.BeginReceive((IAsyncResult result) =>
+ {
+ try
+ {
+ IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
+ byte[] bytes = udpClient6.EndReceive(result, ref ep);
+ udpClient6.Send(endBytes, ep);
+ tcs.SetResult(ep);
+ }
+ catch (Exception)
+ {
+ }
+ }, null);
+
+
+ return (udpClient, udpClient6);
+ }
+ private UdpClient BindListen(UdpClient remoteUdp, IPEndPoint remoteEP)
+ {
+ UdpClient localUdp = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
+ localUdp.Client.WindowsUdpBug();
+
+ ListenAsyncToken token = new ListenAsyncToken
+ {
+ LocalUdp = remoteUdp,
+ Received = false,
+ RemoteUdp = localUdp,
+ };
+ remoteUdp.BeginReceive(ListenConnectCallback, token);
+
+ localUdp.BeginReceive(ListenConnectCallback, new ListenAsyncToken
+ {
+ LocalUdp = localUdp,
+ Received = false,
+ RemoteUdp = remoteUdp,
+ RemoteEP = remoteEP,
+ State = token
+ });
+
+ return localUdp;
+ }
+ private void ListenConnectCallback(IAsyncResult result)
+ {
+ ListenAsyncToken token = result.AsyncState as ListenAsyncToken;
+ try
+ {
+ byte[] bytes = token.LocalUdp.EndReceive(result, ref token.tempEP);
+ if (token.Received == false)
+ {
+ if (token.State is ListenAsyncToken targetToken)
+ {
+ targetToken.RemoteEP = token.tempEP;
+ }
+ }
+ token.Received = true;
+
+ token.RemoteUdp.Send(bytes, token.RemoteEP);
+
+ token.LocalUdp.BeginReceive(ListenConnectCallback, token);
+
+ }
+ catch (Exception)
+ {
+ try
+ {
+ token.LocalUdp.Close();
+ token.RemoteUdp.Close();
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
private async Task ConnectForward(TunnelTransportInfo tunnelTransportInfo)
{
//要连接哪些IP
IPAddress[] localIps = tunnelTransportInfo.Remote.LocalIps.Where(c => c.Equals(tunnelTransportInfo.Remote.Local.Address) == false).ToArray();
List eps = new List();
- eps.AddRange(new List{
- new IPEndPoint(tunnelTransportInfo.Remote.Remote.Address,tunnelTransportInfo.Remote.Remote.Port),
- new IPEndPoint(tunnelTransportInfo.Remote.Remote.Address,tunnelTransportInfo.Remote.Remote.Port+1),
- });
+
//先尝试内网ipv4
foreach (IPAddress item in localIps.Where(c => c.AddressFamily == AddressFamily.InterNetwork))
{
@@ -149,7 +243,10 @@ namespace cmonitor.plugins.tunnel.transport
eps.Add(new IPEndPoint(item, tunnelTransportInfo.Remote.Remote.Port + 1));
}
//在尝试外网
-
+ eps.AddRange(new List{
+ new IPEndPoint(tunnelTransportInfo.Remote.Remote.Address,tunnelTransportInfo.Remote.Remote.Port),
+ new IPEndPoint(tunnelTransportInfo.Remote.Remote.Address,tunnelTransportInfo.Remote.Remote.Port+1),
+ });
//再尝试IPV6
foreach (IPAddress item in localIps.Where(c => c.AddressFamily == AddressFamily.InterNetworkV6))
{
@@ -163,62 +260,28 @@ namespace cmonitor.plugins.tunnel.transport
Logger.Instance.Warning($"{Name} connect to {tunnelTransportInfo.Remote.MachineName} {string.Join("\r\n", eps.Select(c => c.ToString()))}");
}
- //IPEndPoint local = new IPEndPoint(IPAddress.Any, tunnelTransportInfo.Local.Local.Port);
- //UdpClient udpClient = new UdpClient(local);
- //udpClient.Client.ReuseBind(local);
+ IPEndPoint local = new IPEndPoint(tunnelTransportInfo.Local.Local.Address, tunnelTransportInfo.Local.Local.Port);
+ TaskCompletionSource taskCompletionSource = new TaskCompletionSource();
+ //接收远端数据,收到了就是成功了
+ (UdpClient remoteUdp, UdpClient remoteUdp6) = BindListen(local, taskCompletionSource);
foreach (IPEndPoint ep in eps.Where(c => NetworkHelper.NotIPv6Support(c.Address) == false))
{
- //QuicConnection connection = null;
-
-
-
try
{
-
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Warning($"{Name} connect to {tunnelTransportInfo.Remote.MachineName} {ep}");
}
- TunnelCompactSelfHost.udpClient.Send(Encoding.UTF8.GetBytes("snltty.ttl"), ep);
- TunnelCompactSelfHost.udpClient.Send(Encoding.UTF8.GetBytes("snltty.end"), ep);
- /*
- connection = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
+ if (ep.AddressFamily == AddressFamily.InterNetwork)
{
- RemoteEndPoint = ep,
- LocalEndPoint = new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port),
- DefaultCloseErrorCode = 0x0a,
- DefaultStreamErrorCode = 0x0b,
- IdleTimeout = TimeSpan.FromMilliseconds(15000),
- ClientAuthenticationOptions = new SslClientAuthenticationOptions
- {
- ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
- EnabledSslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13,
- RemoteCertificateValidationCallback = (sender, certificate, chain, errors) =>
- {
- return true;
- }
- }
- }).AsTask().WaitAsync(TimeSpan.FromMilliseconds(ep.Address.Equals(tunnelTransportInfo.Remote.Remote.Address) ? 500 : 100));
-
-
- QuicStream quicStream = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
-
- return new TunnelConnectionMsQuic
+ remoteUdp.Send(authBytes, ep);
+ }
+ else
{
- Stream = quicStream,
- Connection = connection,
- IPEndPoint = ep,
- TransactionId = tunnelTransportInfo.TransactionId,
- RemoteMachineName = tunnelTransportInfo.Remote.MachineName,
- TransportName = Name,
- Direction = tunnelTransportInfo.Direction,
- ProtocolType = ProtocolType,
- Type = TunnelType.P2P,
- Mode = TunnelMode.Client,
- Label = string.Empty,
- };
- */
+ remoteUdp6.Send(authBytes, ep);
+ }
+ await Task.Delay(50);
}
catch (Exception ex)
{
@@ -226,43 +289,233 @@ namespace cmonitor.plugins.tunnel.transport
{
Logger.Instance.Error(ex.Message);
}
- //Logger.Instance.Warning($"{Name} wait 1000");
- //await Task.Delay(1000);
}
}
+
+ try
+ {
+ IPEndPoint remoteEP = await taskCompletionSource.Task.WaitAsync(TimeSpan.FromMilliseconds(500));
+ //绑定一个udp,用来给QUIC链接
+ UdpClient localUdp = BindListen(remoteEP.AddressFamily == AddressFamily.InterNetwork ? remoteUdp : remoteUdp6, remoteEP);
+
+ QuicConnection connection = connection = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
+ {
+ RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, (localUdp.Client.LocalEndPoint as IPEndPoint).Port),
+ LocalEndPoint = new IPEndPoint(IPAddress.Any, 0),
+ DefaultCloseErrorCode = 0x0a,
+ DefaultStreamErrorCode = 0x0b,
+ IdleTimeout = TimeSpan.FromMilliseconds(15000),
+ ClientAuthenticationOptions = new SslClientAuthenticationOptions
+ {
+ ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
+ EnabledSslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13,
+ RemoteCertificateValidationCallback = (sender, certificate, chain, errors) =>
+ {
+ return true;
+ }
+ }
+ }).AsTask().WaitAsync(TimeSpan.FromMilliseconds(5000));
+ QuicStream quicStream = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
+ return new TunnelConnectionMsQuic
+ {
+ LocalUdp = localUdp,
+ remoteUdp = remoteUdp,
+ Stream = quicStream,
+ Connection = connection,
+ IPEndPoint = remoteEP,
+ TransactionId = tunnelTransportInfo.TransactionId,
+ RemoteMachineName = tunnelTransportInfo.Remote.MachineName,
+ TransportName = Name,
+ Direction = tunnelTransportInfo.Direction,
+ ProtocolType = ProtocolType,
+ Type = TunnelType.P2P,
+ Mode = TunnelMode.Client,
+ Label = string.Empty,
+ };
+ }
+ catch (Exception ex)
+ {
+ if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
+ {
+ Logger.Instance.Error(ex);
+ }
+ }
+ try
+ {
+ remoteUdp.Close();
+ }
+ catch (Exception)
+ {
+ }
return null;
}
+
+
+ private async Task BindListen(IPEndPoint local, IPEndPoint targetEP, TunnelTransportInfo state)
+ {
+ UdpClient udpClient = new UdpClient(local.AddressFamily);
+ UdpClient udpClient6 = new UdpClient(AddressFamily.InterNetworkV6);
+
+ try
+ {
+ udpClient.Client.ReuseBind(local);
+ udpClient.Client.WindowsUdpBug();
+ ListenAsyncToken token = new ListenAsyncToken
+ {
+ Step = ListenStep.Auth,
+ LocalUdp = udpClient,
+ RemoteEP = targetEP,
+ Tcs = new TaskCompletionSource(),
+ State = state
+ };
+ udpClient.BeginReceive(ListenReceiveCallback, token);
+
+
+ udpClient6.Client.ReuseBind(new IPEndPoint(IPAddress.IPv6Any, local.Port));
+ udpClient6.Client.WindowsUdpBug();
+ ListenAsyncToken token6 = new ListenAsyncToken
+ {
+ Step = ListenStep.Auth,
+ LocalUdp = udpClient6,
+ RemoteEP = targetEP,
+ Tcs = token.Tcs,
+ State = state
+ };
+ udpClient6.BeginReceive(ListenReceiveCallback, token6);
+
+ bool result = await token.Tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(30000));
+ }
+ catch (Exception ex)
+ {
+ udpClient.Close();
+ udpClient6.Close();
+ if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
+ {
+ Logger.Instance.Error(ex);
+ }
+ }
+ }
+ private void ListenReceiveCallback(IAsyncResult result)
+ {
+ ListenAsyncToken token = result.AsyncState as ListenAsyncToken;
+ try
+ {
+
+ byte[] bytes = token.LocalUdp.EndReceive(result, ref token.tempEP);
+ if (token.Step == ListenStep.Auth)
+ {
+ if (bytes.Length == endBytes.Length && bytes.AsSpan().SequenceEqual(endBytes))
+ {
+ token.Step = ListenStep.Forward;
+ }
+ else
+ {
+ token.LocalUdp.Send(bytes, token.tempEP);
+ }
+ if (token.Tcs != null && token.Tcs.Task.IsCompleted == false)
+ {
+ token.Tcs.SetResult(true);
+ }
+ }
+ else
+ {
+ if (token.RemoteUdp == null)
+ {
+ token.RemoteUdp = new UdpClient();
+ token.RemoteUdp.Client.WindowsUdpBug();
+ }
+ if (token.Received == false)
+ {
+ token.RemoteUdp.Send(bytes, token.RemoteEP);
+ token.Received = true;
+ token.RealRemoteEP = token.tempEP;
+ stateDic.AddOrUpdate((token.RemoteUdp.Client.LocalEndPoint as IPEndPoint).Port, token, (a, b) => token);
+ token.RemoteUdp.BeginReceive(ListenReceiveCallback, new ListenAsyncToken
+ {
+ LocalUdp = token.RemoteUdp,
+ Step = ListenStep.Forward,
+ RemoteEP = token.tempEP,
+ RemoteUdp = token.LocalUdp,
+ RealRemoteEP = token.tempEP,
+ Received = true,
+ }) ;
+ }
+ else
+ {
+ token.RemoteUdp.Send(bytes, token.RemoteEP);
+ }
+ }
+ token.LocalUdp.BeginReceive(ListenReceiveCallback, token);
+ }
+ catch (Exception ex)
+ {
+ if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
+ {
+ Logger.Instance.Error(ex);
+ }
+ try
+ {
+ stateDic.TryRemove((token.RemoteUdp.Client.LocalEndPoint as IPEndPoint).Port, out _);
+ token.LocalUdp?.Close();
+ token.RemoteUdp?.Close();
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
private void BindAndTTL(TunnelTransportInfo tunnelTransportInfo)
{
//给对方发送TTL消息
IPAddress[] localIps = tunnelTransportInfo.Remote.LocalIps.Where(c => c.Equals(tunnelTransportInfo.Remote.Local.Address) == false).ToArray();
List eps = new List();
+
foreach (IPAddress item in localIps)
{
eps.Add(new IPEndPoint(item, tunnelTransportInfo.Remote.Local.Port));
eps.Add(new IPEndPoint(item, tunnelTransportInfo.Remote.Remote.Port));
eps.Add(new IPEndPoint(item, tunnelTransportInfo.Remote.Remote.Port + 1));
}
+
eps.AddRange(new List{
new IPEndPoint(tunnelTransportInfo.Remote.Remote.Address,tunnelTransportInfo.Remote.Remote.Port),
new IPEndPoint(tunnelTransportInfo.Remote.Remote.Address,tunnelTransportInfo.Remote.Remote.Port+1),
});
+
+ IPEndPoint local = new IPEndPoint(tunnelTransportInfo.Local.Local.Address, tunnelTransportInfo.Local.Local.Port);
foreach (var ip in eps.Where(c => NetworkHelper.NotIPv6Support(c.Address) == false))
{
try
{
-
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Warning($"{Name} ttl to {tunnelTransportInfo.Remote.MachineName} {ip}");
}
- TunnelCompactSelfHost.udpClient.Send(Encoding.UTF8.GetBytes(tunnelTransportInfo.Remote.MachineName), ip);
+
+ if (ip.AddressFamily == AddressFamily.InterNetwork)
+ {
+ Socket socket = new Socket(local.AddressFamily, SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
+ socket.WindowsUdpBug();
+ socket.ReuseBind(local);
+ socket.Ttl = (short)(tunnelTransportInfo.Local.RouteLevel);
+ _ = socket.SendToAsync(new byte[0], SocketFlags.None, ip);
+ socket.SafeClose();
+ }
+ else
+ {
+ Socket socket = new Socket(ip.AddressFamily, SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
+ socket.WindowsUdpBug();
+ socket.ReuseBind(new IPEndPoint(IPAddress.IPv6Any, local.Port));
+ socket.Ttl = 2;
+ _ = socket.SendToAsync(new byte[0], SocketFlags.None, ip);
+ socket.SafeClose();
+ }
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
- Logger.Instance.Error(ex);
+ Logger.Instance.Error(ex.Message);
}
}
finally
@@ -308,14 +561,17 @@ namespace cmonitor.plugins.tunnel.transport
}
- private async Task OnUdpConnected(TunnelTransportInfo state, QuicConnection quicConnection, QuicStream stream)
+ private async Task OnUdpConnected(object _state, UdpClient localUdp, UdpClient remoteUdp,IPEndPoint remoteEP, QuicConnection quicConnection, QuicStream stream)
{
+ TunnelTransportInfo state = _state as TunnelTransportInfo;
if (state.TransportName == Name)
{
try
{
TunnelConnectionMsQuic result = new TunnelConnectionMsQuic
{
+ LocalUdp = localUdp,
+ remoteUdp = remoteUdp,
RemoteMachineName = state.Remote.MachineName,
Direction = state.Direction,
ProtocolType = TunnelProtocolType.Quic,
@@ -325,7 +581,7 @@ namespace cmonitor.plugins.tunnel.transport
Mode = TunnelMode.Server,
TransactionId = state.TransactionId,
TransportName = state.TransportName,
- IPEndPoint = quicConnection.RemoteEndPoint,
+ IPEndPoint = remoteEP,
Label = string.Empty,
};
if (reverseDic.TryRemove(state.Remote.MachineName, out TaskCompletionSource tcs))
@@ -346,17 +602,8 @@ namespace cmonitor.plugins.tunnel.transport
await Task.CompletedTask;
}
- private async Task QuicStart(IPEndPoint local, TunnelTransportInfo info)
+ private async Task QuicStart()
{
- return;
- UdpClient udpClient = new UdpClient(local);
- while (true)
- {
- UdpReceiveResult result = await udpClient.ReceiveAsync();
- Console.WriteLine(Encoding.UTF8.GetString(result.Buffer));
- }
-
- return;
if (OperatingSystem.IsWindows() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
if (QuicListener.IsSupported == false) return;
@@ -365,7 +612,7 @@ namespace cmonitor.plugins.tunnel.transport
{
ApplicationProtocols = new List { SslApplicationProtocol.Http3 },
ListenBacklog = int.MaxValue,
- ListenEndPoint = local,
+ ListenEndPoint = new IPEndPoint(IPAddress.Any, 0),
ConnectionOptionsCallback = (connection, hello, token) =>
{
return ValueTask.FromResult(new QuicServerConnectionOptions
@@ -384,22 +631,54 @@ namespace cmonitor.plugins.tunnel.transport
});
}
});
-
- try
+ quicListenEP = new IPEndPoint(IPAddress.Loopback, listener.LocalEndPoint.Port);
+ while (true)
{
- QuicConnection quicConnection = await listener.AcceptConnectionAsync().AsTask().WaitAsync(TimeSpan.FromMilliseconds(30000));
- QuicStream quicStream = await quicConnection.AcceptInboundStreamAsync().AsTask().WaitAsync(TimeSpan.FromMilliseconds(2000));
- await OnUdpConnected(info, quicConnection, quicStream);
- }
- catch (Exception ex)
- {
- if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
+ try
{
- Logger.Instance.Error(ex);
+ QuicConnection quicConnection = await listener.AcceptConnectionAsync();
+ QuicStream quicStream = await quicConnection.AcceptInboundStreamAsync();
+
+ if (stateDic.TryRemove(quicConnection.RemoteEndPoint.Port, out ListenAsyncToken token))
+ {
+ await OnUdpConnected(token.State, token.LocalUdp, token.RemoteUdp, token.RealRemoteEP, quicConnection, quicStream);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
+ {
+ Logger.Instance.Error(ex);
+ }
}
}
- await listener.DisposeAsync();
}
}
+
+
+ sealed class ListenAsyncToken
+ {
+ public ListenStep Step { get; set; }
+ public UdpClient LocalUdp { get; set; }
+ public IPEndPoint tempEP = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
+
+ public UdpClient RemoteUdp { get; set; }
+ public IPEndPoint RemoteEP { get; set; }
+ public IPEndPoint RealRemoteEP { get; set; }
+
+ public TaskCompletionSource Tcs { get; set; }
+
+ public object State { get; set; }
+
+ public bool Received { get; set; }
+ }
+
+ enum ListenStep : byte
+ {
+ Auth = 0,
+ Forward = 1
+ }
}
+
+
}
diff --git a/cmonitor/plugins/tunnel/transport/TransportTcpNutssb.cs b/cmonitor/plugins/tunnel/transport/TransportTcpNutssb.cs
index 0e9da0e2..737518e7 100644
--- a/cmonitor/plugins/tunnel/transport/TransportTcpNutssb.cs
+++ b/cmonitor/plugins/tunnel/transport/TransportTcpNutssb.cs
@@ -15,7 +15,6 @@ namespace cmonitor.plugins.tunnel.transport
{
public string Name => "TcpNutssb";
public string Label => "TCP、低TTL";
- public bool Disabled => true;
public TunnelProtocolType ProtocolType => TunnelProtocolType.Tcp;
private X509Certificate serverCertificate;
diff --git a/cmonitor/plugins/tuntap/TuntapTransfer.cs b/cmonitor/plugins/tuntap/TuntapTransfer.cs
index 11a6a37e..a83bff32 100644
--- a/cmonitor/plugins/tuntap/TuntapTransfer.cs
+++ b/cmonitor/plugins/tuntap/TuntapTransfer.cs
@@ -124,18 +124,21 @@ namespace cmonitor.plugins.tuntap
///
public void OnUpdate(TuntapInfo info)
{
- config.Data.Client.Tuntap.IP = info.IP;
- config.Data.Client.Tuntap.LanIPs = info.LanIPs;
- config.Save();
- if (Status == TuntapStatus.Running)
+ Task.Run(() =>
{
- Stop();
- Run();
- }
- else
- {
- OnChange();
- }
+ config.Data.Client.Tuntap.IP = info.IP;
+ config.Data.Client.Tuntap.LanIPs = info.LanIPs;
+ config.Save();
+ if (Status == TuntapStatus.Running)
+ {
+ Stop();
+ Run();
+ }
+ else
+ {
+ OnChange();
+ }
+ });
}
///
/// 更新远程主机信息
@@ -158,13 +161,20 @@ namespace cmonitor.plugins.tuntap
{
GetRemoteInfo().ContinueWith((result) =>
{
- DelRoute();
- foreach (var item in result.Result)
+ if(result.Result == null)
{
- tuntapInfos.AddOrUpdate(item.MachineName, item, (a, b) => item);
+ OnChange();
+ }
+ else
+ {
+ DelRoute();
+ foreach (var item in result.Result)
+ {
+ tuntapInfos.AddOrUpdate(item.MachineName, item, (a, b) => item);
+ }
+ Interlocked.Increment(ref infosVersion);
+ AddRoute();
}
- Interlocked.Increment(ref infosVersion);
- AddRoute();
});
}
@@ -179,7 +189,8 @@ namespace cmonitor.plugins.tuntap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)TuntapMessengerIds.ConfigForward,
- Payload = MemoryPackSerializer.Serialize(info)
+ Payload = MemoryPackSerializer.Serialize(info),
+ Timeout = 3000
});
if (resp.Code != MessageResponeCodes.OK)
{
diff --git a/cmonitor/plugins/tuntap/messenger/TuntapMessenger.cs b/cmonitor/plugins/tuntap/messenger/TuntapMessenger.cs
index 7a84db02..c113a04d 100644
--- a/cmonitor/plugins/tuntap/messenger/TuntapMessenger.cs
+++ b/cmonitor/plugins/tuntap/messenger/TuntapMessenger.cs
@@ -117,7 +117,8 @@ namespace cmonitor.plugins.tuntap.messenger
{
Connection = item.Connection,
MessengerId = (ushort)TuntapMessengerIds.Config,
- Payload = connection.ReceiveRequestWrap.Payload
+ Payload = connection.ReceiveRequestWrap.Payload,
+ Timeout = 1000,
}));
}
diff --git a/cmonitor/server/MessengerSender.cs b/cmonitor/server/MessengerSender.cs
index f6b72624..2fc6f9a0 100644
--- a/cmonitor/server/MessengerSender.cs
+++ b/cmonitor/server/MessengerSender.cs
@@ -1,5 +1,6 @@
using common.libs;
using System.Collections.Concurrent;
+using System.Diagnostics;
namespace cmonitor.server
{
@@ -69,6 +70,7 @@ namespace cmonitor.server
}
byte[] bytes = msg.ToArray(out int length);
+ var sw = new Stopwatch();
bool res = await msg.Connection.SendAsync(bytes.AsMemory(0, length)).ConfigureAwait(false);
msg.Return(bytes);
return res;