This commit is contained in:
snltty
2024-04-21 08:56:46 +08:00
parent 08c37367bb
commit 035a4a1b0c
29 changed files with 627 additions and 114 deletions

View File

@@ -3,9 +3,4 @@
<PropertyGroup> <PropertyGroup>
<_LastSelectedProfileId>D:\desktop\cmonitor\cmonitor.viewer.server.win\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId> <_LastSelectedProfileId>D:\desktop\cmonitor\cmonitor.viewer.server.win\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project> </Project>

View File

@@ -13,18 +13,18 @@
</div> </div>
<div class="body flex flex-1"> <div class="body flex flex-1">
<div class="private"> <div class="private">
<CheckBoxWrap ref="privateProcess" :data="state.privateProcess" :items="state.privateProcessItems" label="Name" text="Name" title="私有程序组"></CheckBoxWrap> <CheckBoxWrap v-if="state.showCheck" ref="privateProcess" :data="state.privateProcess" :items="state.privateProcessItems" label="Name" text="Name" title="私有程序组"></CheckBoxWrap>
</div> </div>
<div class="flex-1"></div> <div class="flex-1"></div>
<div class="public"> <div class="public">
<CheckBoxWrap ref="publicProcess" :data="state.publicProcess" :items="state.publicProcessItems" label="Name" text="Name" title="公共程序组"></CheckBoxWrap> <CheckBoxWrap v-if="state.showCheck" ref="publicProcess" :data="state.publicProcess" :items="state.publicProcessItems" label="Name" text="Name" title="公共程序组"></CheckBoxWrap>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { computed, reactive, ref, watch } from 'vue'; import { computed, nextTick, reactive, ref, watch } from 'vue';
import CheckBoxWrap from '../../../boxs/CheckBoxWrap.vue' import CheckBoxWrap from '../../../boxs/CheckBoxWrap.vue'
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { updateRule } from '../../../../../apis/hijack' import { updateRule } from '../../../../../apis/hijack'
@@ -78,6 +78,18 @@ export default {
}, 300); }, 300);
} }
}); });
watch(()=>state.privateProcessItems,()=>{
state.showCheck = false;
nextTick(()=>{
state.showCheck = true;
})
});
watch(()=>state.publicProcessItems,()=>{
state.showCheck = false;
nextTick(()=>{
state.showCheck = true;
})
});
const privateProcess = ref(null); const privateProcess = ref(null);
const publicProcess = ref(null); const publicProcess = ref(null);

View File

@@ -101,7 +101,7 @@ namespace cmonitor.config
{ {
PluginNames = value.ToList().Concat(new List<string> PluginNames = value.ToList().Concat(new List<string>
{ {
"client","server","api","web","plugins.signin", "client","server","api","web","serializes","plugins.signin",
"plugins.watch","plugins.devices","plugins.report", "plugins.watch","plugins.devices","plugins.report",
"plugins.share","plugins.rule","plugins.modes", "plugins.share","plugins.rule","plugins.modes",
}).Select(c => $".{c}.").ToArray(); }).Select(c => $".{c}.").ToArray();

View File

@@ -7,6 +7,7 @@ using common.libs.winapis;
using System.Text; using System.Text;
using System.Buffers.Binary; using System.Buffers.Binary;
using common.libs; using common.libs;
using common.libs.extends;
namespace cmonitor.plugins.hijack.report.hijack namespace cmonitor.plugins.hijack.report.hijack
{ {
@@ -256,7 +257,6 @@ namespace cmonitor.plugins.hijack.report.hijack
IPHostEntry entry = await Dns.GetHostEntryAsync(domain); IPHostEntry entry = await Dns.GetHostEntryAsync(domain);
foreach (IPAddress item in entry.AddressList) foreach (IPAddress item in entry.AddressList)
{ {
if (domainIPs.ContainsKey(item) == false) if (domainIPs.ContainsKey(item) == false)
domainIPs[item] = AllowType.Denied; domainIPs[item] = AllowType.Denied;
} }
@@ -372,7 +372,7 @@ namespace cmonitor.plugins.hijack.report.hijack
ushort type = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(index)); ushort type = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(index));
index += 2; //type index += 2; //type
if (type != 1) if (type != 1 && type != 28)
{ {
return null; //不是A查询 return null; //不是A查询
} }
@@ -391,7 +391,7 @@ namespace cmonitor.plugins.hijack.report.hijack
int dataLength = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(index)); int dataLength = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(index));
index += 2; index += 2;
if (type == 1) //是A回应其它的不要 if (type == 1 || type == 28) //是A回应其它的不要
{ {
ips[i] = new IPAddress(span.Slice(index, dataLength)); ips[i] = new IPAddress(span.Slice(index, dataLength));
} }
@@ -423,7 +423,6 @@ namespace cmonitor.plugins.hijack.report.hijack
if (ip != null && domainIPs.TryGetValue(ip, out type)) if (ip != null && domainIPs.TryGetValue(ip, out type))
{ {
if (type == AllowType.Denied && domainKill) if (type == AllowType.Denied && domainKill)
{ {
try try

View File

@@ -18,7 +18,7 @@ namespace cmonitor.plugins.share.report
public ShareReport(Config config, ShareMemory shareMemory) public ShareReport(Config config, ShareMemory shareMemory)
{ {
#if RELEASE #if RELEASE
if (config.Common.BlueProtect && OperatingSystem.IsWindows()) //if (config.Data.Common.BlueProtect && OperatingSystem.IsWindows())
{ {
//ProcessBlueProtection.Protect(); //ProcessBlueProtection.Protect();
//SystemEvents.SessionEnding += SystemEvents_SessionEnding; //SystemEvents.SessionEnding += SystemEvents_SessionEnding;

View File

@@ -1,9 +1,12 @@
using cmonitor.config; using cmonitor.config;
using cmonitor.plugins.tunnel.compact; using cmonitor.plugins.tunnel.compact;
using cmonitor.plugins.tunnel.messenger;
using cmonitor.plugins.tunnel.server; using cmonitor.plugins.tunnel.server;
using cmonitor.plugins.tunnel.transport;
using cmonitor.startup; using cmonitor.startup;
using common.libs; using common.libs;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Reflection; using System.Reflection;
namespace cmonitor.plugins.tunnel namespace cmonitor.plugins.tunnel
@@ -14,11 +17,22 @@ namespace cmonitor.plugins.tunnel
{ {
serviceCollection.AddSingleton<CompactTransfer>(); serviceCollection.AddSingleton<CompactTransfer>();
serviceCollection.AddSingleton<CompactSelfHost>(); serviceCollection.AddSingleton<CompactSelfHost>();
serviceCollection.AddSingleton<TunnelClientMessenger>();
serviceCollection.AddSingleton<TunnelBindServer>();
serviceCollection.AddSingleton<ITransport, TransportTcpNutssb>();
Logger.Instance.Info($"tunnel route level getting.");
config.Data.Client.Tunnel.RouteLevel = NetworkHelper.GetRouteLevel(out List<IPAddress> ips);
Logger.Instance.Info($"tunnel route level:{config.Data.Client.Tunnel.RouteLevel}");
} }
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies) public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{ {
serviceCollection.AddSingleton<TunnelServer>(); serviceCollection.AddSingleton<TunnelServer>();
serviceCollection.AddSingleton<TunnelServerMessenger>();
} }
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies) public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)

View File

@@ -1,4 +1,6 @@
using common.libs.extends; using cmonitor.plugins.tunnel.server;
using common.libs.extends;
using MemoryPack;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
@@ -8,7 +10,7 @@ namespace cmonitor.plugins.tunnel.compact
{ {
public string Type => "self"; public string Type => "self";
public async Task<CompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server) public async Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server)
{ {
Socket socket = new Socket(server.AddressFamily, SocketType.Stream, ProtocolType.Tcp); Socket socket = new Socket(server.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Reuse(true); socket.Reuse(true);
@@ -17,47 +19,31 @@ namespace cmonitor.plugins.tunnel.compact
byte[] bytes = new byte[20]; byte[] bytes = new byte[20];
int length = await socket.ReceiveAsync(bytes.AsMemory(), SocketFlags.None); int length = await socket.ReceiveAsync(bytes.AsMemory(), SocketFlags.None);
if (length == 0) return null; if (length == 0)
{
return null;
}
return new CompactIPEndPoint { Local = socket.LocalEndPoint as IPEndPoint, Remote = ReadData(bytes) }; TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(bytes.AsSpan(0,length));
return new TunnelCompactIPEndPoint { Local = socket.LocalEndPoint as IPEndPoint, Remote = tunnelExternalIPInfo.ExternalIP };
} }
public async Task<CompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server) public async Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server)
{ {
using UdpClient udpClient = new UdpClient(); using UdpClient udpClient = new UdpClient();
udpClient.Client.Reuse(true); udpClient.Client.Reuse(true);
await udpClient.SendAsync(new byte[1] { 0 }, server); await udpClient.SendAsync(new byte[1] { 0 }, server);
var result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromSeconds(5)); var result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromSeconds(5));
if (result.Buffer.Length == 0) return null; if (result.Buffer.Length == 0)
return new CompactIPEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = ReadData(result.Buffer) };
}
private IPEndPoint ReadData(byte[] bytes)
{
int index = 0;
AddressFamily family = (AddressFamily)bytes[index];
index++;
int ipLength = family switch
{ {
AddressFamily.InterNetwork => 4, return null;
AddressFamily.InterNetworkV6 => 16,
_ => 0,
};
if (ipLength > 0)
{
IPAddress ip = new IPAddress(bytes.AsSpan(0, ipLength));
index += ipLength;
ushort port = bytes.AsSpan(index).ToUInt16();
IPEndPoint iPEndPoint = new IPEndPoint(ip, port);
return iPEndPoint;
} }
return null; TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(result.Buffer);
return new TunnelCompactIPEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = tunnelExternalIPInfo.ExternalIP };
} }
} }
} }

View File

@@ -31,9 +31,9 @@ namespace cmonitor.plugins.tunnel.compact
Logger.Instance.Warning($"load tunnel compacts:{string.Join(",", compacts.Select(c => c.Type))}"); Logger.Instance.Warning($"load tunnel compacts:{string.Join(",", compacts.Select(c => c.Type))}");
} }
public async Task<CompactIPEndPoint[]> GetExternalIPAsync(ProtocolType protocolType) public async Task<TunnelCompactIPEndPoint[]> GetExternalIPAsync(ProtocolType protocolType)
{ {
CompactIPEndPoint[] endpoints = new CompactIPEndPoint[config.Data.Client.Tunnel.Servers.Length]; TunnelCompactIPEndPoint[] endpoints = new TunnelCompactIPEndPoint[config.Data.Client.Tunnel.Servers.Length];
for (int i = 0; i < config.Data.Client.Tunnel.Servers.Length; i++) for (int i = 0; i < config.Data.Client.Tunnel.Servers.Length; i++)
{ {
@@ -46,12 +46,12 @@ namespace cmonitor.plugins.tunnel.compact
IPEndPoint server = NetworkHelper.GetEndPoint(item.Host, 3478); IPEndPoint server = NetworkHelper.GetEndPoint(item.Host, 3478);
if (protocolType == ProtocolType.Tcp) if (protocolType == ProtocolType.Tcp)
{ {
CompactIPEndPoint externalIP = await compact.GetTcpExternalIPAsync(server); TunnelCompactIPEndPoint externalIP = await compact.GetTcpExternalIPAsync(server);
endpoints[i] = externalIP; endpoints[i] = externalIP;
} }
else if (protocolType == ProtocolType.Udp) else if (protocolType == ProtocolType.Udp)
{ {
CompactIPEndPoint externalIP = await compact.GetUdpExternalIPAsync(server); TunnelCompactIPEndPoint externalIP = await compact.GetUdpExternalIPAsync(server);
endpoints[i] = externalIP; endpoints[i] = externalIP;
} }
} }

View File

@@ -5,11 +5,11 @@ namespace cmonitor.plugins.tunnel.compact
public interface ICompact public interface ICompact
{ {
public string Type { get; } public string Type { get; }
public Task<CompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server); public Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server);
public Task<CompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server); public Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server);
} }
public sealed class CompactIPEndPoint public sealed class TunnelCompactIPEndPoint
{ {
public IPEndPoint Local { get; set; } public IPEndPoint Local { get; set; }
public IPEndPoint Remote { get; set; } public IPEndPoint Remote { get; set; }

View File

@@ -1,4 +1,6 @@
namespace cmonitor.config using System.Text.Json.Serialization;
namespace cmonitor.config
{ {
public partial class ConfigClientInfo public partial class ConfigClientInfo
{ {
@@ -15,6 +17,9 @@
{ {
new TunnelCompactInfo { Type="self", Host="127.0.0.1:1804" } new TunnelCompactInfo { Type="self", Host="127.0.0.1:1804" }
}; };
[JsonIgnore]
public int RouteLevel { get; set; }
} }
public sealed class TunnelConfigServerInfo public sealed class TunnelConfigServerInfo

View File

@@ -1,12 +1,66 @@
using cmonitor.server; using cmonitor.config;
using cmonitor.plugins.signin.messenger;
using cmonitor.plugins.tunnel.transport;
using cmonitor.server;
using MemoryPack;
using System.Buffers;
namespace cmonitor.plugins.tunnel.messenger namespace cmonitor.plugins.tunnel.messenger
{ {
public sealed class TunnelMessenger : IMessenger public sealed class TunnelClientMessenger : IMessenger
{ {
public TunnelMessenger() private readonly ITransport transport;
private readonly Config config;
public TunnelClientMessenger(ITransport transport, Config config)
{ {
this.transport = transport;
this.config = config;
}
[MessengerId((ushort)TunnelMessengerIds.Begin)]
public async Task Begin(IConnection connection)
{
TunnelTransportInfo tunnelTransportInfo = MemoryPackSerializer.Deserialize<TunnelTransportInfo>(connection.ReceiveRequestWrap.Payload.Span);
tunnelTransportInfo.RouteLevel = config.Data.Client.Tunnel.RouteLevel;
TunnelTransportInfo info = await transport.OnBegin(tunnelTransportInfo);
connection.Write(MemoryPackSerializer.Serialize(info));
}
}
public sealed class TunnelServerMessenger : IMessenger
{
private readonly MessengerSender messengerSender;
private readonly SignCaching signCaching;
public TunnelServerMessenger(MessengerSender messengerSender, SignCaching signCaching)
{
this.messengerSender = messengerSender;
this.signCaching = signCaching;
}
[MessengerId((ushort)TunnelMessengerIds.BeginForward)]
public async Task BeginForward(IConnection connection)
{
TunnelTransportInfo tunnelTransportInfo = MemoryPackSerializer.Deserialize<TunnelTransportInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.Get(tunnelTransportInfo.ToMachineName, out SignCacheInfo cache))
{
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = cache.Connection,
MessengerId = (ushort)TunnelMessengerIds.Begin,
Payload = connection.ReceiveRequestWrap.Payload
});
if (resp.Code == MessageResponeCodes.OK)
{
byte[] bytes = ArrayPool<byte>.Shared.Rent(resp.Data.Length);
resp.Data.CopyTo(bytes);
connection.Write(bytes.AsMemory(0, resp.Data.Length));
ArrayPool<byte>.Shared.Return(bytes);
}
}
} }
} }
} }

View File

@@ -3,7 +3,10 @@
public enum TunnelMessengerIds : ushort public enum TunnelMessengerIds : ushort
{ {
Update = 2000, Update = 2000,
Begin = 2001,
BeginForward = 2002,
Reverse = 2003,
ReverseForward = 2004,
None = 2001 None = 2001
} }
} }

View File

@@ -0,0 +1,117 @@
using common.libs;
using common.libs.extends;
using System.Net;
using System.Net.Sockets;
namespace cmonitor.plugins.tunnel.server
{
public sealed class TunnelBindServer
{
private SocketAsyncEventArgs acceptEventArg;
private Socket socket;
private UdpClient socketUdp;
public Action<object, Socket> OnTcpConnected { get; set; } = (state, socket) => { };
public Action<object, UdpClient> OnUdpConnected { get; set; } = (state, udpClient) => { };
public void Bind(IPEndPoint local, object state)
{
try
{
socket = new Socket(local.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.IPv6Only(local.AddressFamily, false);
socket.ReuseBind(local);
socket.Listen(int.MaxValue);
acceptEventArg = new SocketAsyncEventArgs
{
UserToken = new AsyncUserToken
{
SourceSocket = socket,
State = state
},
SocketFlags = SocketFlags.None,
};
acceptEventArg.Completed += IO_Completed;
StartAccept(acceptEventArg);
socketUdp = new UdpClient();
socketUdp.Client.ReuseBind(local);
socketUdp.Client.EnableBroadcast = true;
socketUdp.Client.WindowsUdpBug();
IAsyncResult result = socketUdp.BeginReceive(ReceiveCallbackUdp, state);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
}
private void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
acceptEventArg.AcceptSocket = null;
AsyncUserToken token = (AsyncUserToken)acceptEventArg.UserToken;
try
{
if (token.SourceSocket.AcceptAsync(acceptEventArg) == false)
{
ProcessAccept(acceptEventArg);
}
}
catch (Exception)
{
token.Clear();
}
}
private void IO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
ProcessAccept(e);
break;
default:
break;
}
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
if (e.AcceptSocket != null)
{
AsyncUserToken token = e.UserToken as AsyncUserToken;
OnTcpConnected(token.State, e.AcceptSocket);
StartAccept(e);
}
}
private void ReceiveCallbackUdp(IAsyncResult result)
{
try
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
byte[] _ = socketUdp.EndReceive(result, ref ep);
OnUdpConnected(result.AsyncState, socketUdp);
}
catch (Exception)
{
}
}
public sealed class AsyncUserToken
{
public Socket SourceSocket { get; set; }
public object State { get; set; }
public void Clear()
{
SourceSocket?.SafeClose();
SourceSocket = null;
GC.Collect();
}
}
}
}

View File

@@ -1,6 +1,6 @@
using common.libs; using common.libs;
using common.libs.extends; using common.libs.extends;
using System.Buffers; using MemoryPack;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
@@ -88,20 +88,10 @@ namespace cmonitor.plugins.tunnel.server
if (token.SourceSocket != null) if (token.SourceSocket != null)
{ {
IPEndPoint ep = token.SourceSocket.RemoteEndPoint as IPEndPoint; IPEndPoint ep = token.SourceSocket.RemoteEndPoint as IPEndPoint;
Memory<byte> memory = MemoryPackSerializer.Serialize(new TunnelExternalIPInfo { ExternalIP = ep });
byte[] bytes = ArrayPool<byte>.Shared.Rent(20); await token.SourceSocket.SendAsync(memory);
int index = 0;
bytes[index] = (byte)ep.Address.AddressFamily;
index++;
ep.Address.TryWriteBytes(bytes.AsSpan(index), out int bytesWritten);
index += bytesWritten;
((ushort)ep.Port).ToBytes(bytes.AsMemory(index));
index += 2;
await token.SourceSocket.SendAsync(bytes.AsMemory(0, index));
ArrayPool<byte>.Shared.Return(bytes);
} }
} }
@@ -112,20 +102,9 @@ namespace cmonitor.plugins.tunnel.server
IPEndPoint ep = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort); IPEndPoint ep = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
byte[] _ = socketUdp.EndReceive(result, ref ep); byte[] _ = socketUdp.EndReceive(result, ref ep);
Memory<byte> memory = MemoryPackSerializer.Serialize(new TunnelExternalIPInfo { ExternalIP = ep });
byte[] bytes = ArrayPool<byte>.Shared.Rent(20); await socketUdp.SendAsync(memory, ep);
int index = 0;
bytes[index] = (byte)ep.Address.AddressFamily;
index++;
ep.Address.TryWriteBytes(bytes.AsSpan(index), out int bytesWritten);
index += bytesWritten;
((ushort)ep.Port).ToBytes(bytes.AsMemory(index));
index += 2;
await socketUdp.SendAsync(bytes.AsMemory(0, index), ep);
ArrayPool<byte>.Shared.Return(bytes);
result = socketUdp.BeginReceive(ReceiveCallbackUdp, null); result = socketUdp.BeginReceive(ReceiveCallbackUdp, null);
} }
@@ -147,6 +126,7 @@ namespace cmonitor.plugins.tunnel.server
public void Stop() public void Stop()
{ {
CloseClientSocket(acceptEventArg); CloseClientSocket(acceptEventArg);
socketUdp?.Close();
} }
} }
@@ -162,4 +142,11 @@ namespace cmonitor.plugins.tunnel.server
GC.Collect(); GC.Collect();
} }
} }
[MemoryPackable]
public sealed partial class TunnelExternalIPInfo
{
[MemoryPackAllowSerialize]
public IPEndPoint ExternalIP { get; set; }
}
} }

View File

@@ -1,10 +1,43 @@
using System.Net; using MemoryPack;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
namespace cmonitor.plugins.tunnel.transport namespace cmonitor.plugins.tunnel.transport
{ {
public interface ITransport public interface ITransport
{ {
public Task<Socket> ConnectAsync(IPEndPoint local, IPEndPoint remote); public string Name { get; }
public ProtocolType TypeFlag { get; }
public Func<TunnelTransportInfo, Task<TunnelTransportInfo>> SendBegin { get; set; }
public Action<TransportState> OnConnected { get; set; }
public Task<Socket> ConnectAsync(string fromMachineName, string toMachineName);
public Task<TunnelTransportInfo> OnBegin(TunnelTransportInfo tunnelTransportNoticeInfo);
public Task OnReverse(TunnelTransportInfo tunnelTransportNoticeInfo);
} }
[MemoryPackable]
public sealed partial class TunnelTransportInfo
{
[MemoryPackAllowSerialize]
public IPEndPoint FromLocal { get; set; }
[MemoryPackAllowSerialize]
public IPEndPoint FromRemote { get; set; }
public string FromMachineName { get; set; }
public string ToMachineName { get; set; }
public ProtocolType TypeFlag { get; set; }
public int RouteLevel { get; set; }
}
public sealed class TransportState
{
public string FromMachineName { get; set; }
public ProtocolType TypeFlag { get; set; }
public object ConnectedObject { get; set; }
}
} }

View File

@@ -0,0 +1,160 @@
using cmonitor.plugins.tunnel.compact;
using cmonitor.plugins.tunnel.server;
using common.libs;
using common.libs.extends;
using System.Net;
using System.Net.Sockets;
namespace cmonitor.plugins.tunnel.transport
{
public sealed class TransportTcpNutssb : ITransport
{
private readonly TunnelBindServer tunnelBindServer;
private readonly CompactTransfer compactTransfer;
public Action<TransportState> OnConnected { get; set; } = (state) => { };
public Func<TunnelTransportInfo, Task<TunnelTransportInfo>> SendBegin { get; set; }
public string Name => "TcpNutssb";
public ProtocolType TypeFlag => ProtocolType.Tcp;
public TransportTcpNutssb(TunnelBindServer tunnelBindServer, CompactTransfer compactTransfer)
{
this.tunnelBindServer = tunnelBindServer;
tunnelBindServer.OnTcpConnected += OnTcpConnected;
this.compactTransfer = compactTransfer;
}
public async Task<Socket> ConnectAsync(string fromMachineName, string toMachineName)
{
//获取自己的外网IP
TunnelCompactIPEndPoint[] ips = await compactTransfer.GetExternalIPAsync(TypeFlag);
if (ips.Length == 0)
{
return null;
}
//告诉对方,我要连你,你需要给我发送一下 低TTL并且对方要返回它的外网地址过来给我去连接
TunnelTransportInfo tunnelTransportInfo = new TunnelTransportInfo
{
FromMachineName = fromMachineName,
ToMachineName = toMachineName,
FromLocal = ips[0].Local,
FromRemote = ips[0].Remote,
};
TunnelTransportInfo remoteInfo = await SendBegin(tunnelTransportInfo);
//要连接哪些IP
IPEndPoint[] eps = new IPEndPoint[] {
new IPEndPoint(remoteInfo.FromLocal.Address,remoteInfo.FromLocal.Port),
new IPEndPoint(remoteInfo.FromLocal.Address,remoteInfo.FromRemote.Port),
new IPEndPoint(remoteInfo.FromLocal.Address,remoteInfo.FromRemote.Port+1),
new IPEndPoint(remoteInfo.FromRemote.Address,remoteInfo.FromRemote.Port),
new IPEndPoint(remoteInfo.FromRemote.Address,remoteInfo.FromRemote.Port+1),
};
//过滤掉不支持IPV6的情况去尝试连接
IEnumerable<IAsyncResult> results = eps.Where(c => NotIPv6Support(c.Address) == false).Select(ip =>
{
using Socket targetSocket = new(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
targetSocket.IPv6Only(ip.Address.AddressFamily, false);
targetSocket.ReuseBind(new IPEndPoint(ip.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.FromLocal.Port));
IAsyncResult result = targetSocket.BeginConnect(ip, null, targetSocket);
return result;
}
catch (Exception)
{
}
return null;
});
//检查一下是否连接成功
for (int i = 0; i < 10; i++)
{
IAsyncResult result = results.FirstOrDefault(c => c.IsCompleted);
if (result != null)
{
return result.AsyncState as Socket;
}
await Task.Delay(10);
}
return null;
}
public async Task<TunnelTransportInfo> OnBegin(TunnelTransportInfo tunnelTransportInfo)
{
//获取自己的外网IP
TunnelCompactIPEndPoint[] ips = await compactTransfer.GetExternalIPAsync(ProtocolType.Tcp);
if (ips.Length == 0)
{
return null;
}
//监听,等对方来连
TunnelTransportInfo info = new TunnelTransportInfo
{
ToMachineName = tunnelTransportInfo.FromMachineName,
FromMachineName = tunnelTransportInfo.ToMachineName,
FromLocal = ips[0].Local,
FromRemote = ips[0].Remote,
RouteLevel = tunnelTransportInfo.RouteLevel
};
TransportTcpNutssbState state = new TransportTcpNutssbState { FromMachineName = tunnelTransportInfo.FromMachineName };
tunnelBindServer.Bind(info.FromLocal, state);
//给对方发送TTL消息
IPEndPoint[] eps = new IPEndPoint[] {
new IPEndPoint(tunnelTransportInfo.FromLocal.Address,tunnelTransportInfo.FromLocal.Port),
new IPEndPoint(tunnelTransportInfo.FromLocal.Address,tunnelTransportInfo.FromRemote.Port),
new IPEndPoint(tunnelTransportInfo.FromLocal.Address,tunnelTransportInfo.FromRemote.Port+1),
new IPEndPoint(tunnelTransportInfo.FromRemote.Address,tunnelTransportInfo.FromRemote.Port),
new IPEndPoint(tunnelTransportInfo.FromRemote.Address,tunnelTransportInfo.FromRemote.Port+1),
};
//过滤掉不支持IPV6的情况
IEnumerable<Socket> sockets = eps.Where(c => NotIPv6Support(c.Address) == false).Select(ip =>
{
using Socket targetSocket = new(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
targetSocket.IPv6Only(ip.Address.AddressFamily, false);
targetSocket.Ttl = (short)(info.RouteLevel);
targetSocket.ReuseBind(new IPEndPoint(ip.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, info.FromLocal.Port));
_ = targetSocket.ConnectAsync(ip);
return targetSocket;
}
catch (Exception)
{
}
return null;
});
foreach (Socket item in sockets.Where(c => c != null && c.Connected == false))
{
item.SafeClose();
}
return info;
}
public async Task OnReverse(TunnelTransportInfo tunnelTransportInfo)
{
}
private void OnTcpConnected(object state, Socket socket)
{
if (state is TransportTcpNutssbState _state)
{
OnConnected(new TransportState { FromMachineName = _state.FromMachineName, TypeFlag = ProtocolType.Tcp, ConnectedObject = socket });
}
}
private bool NotIPv6Support(IPAddress ip)
{
return ip.AddressFamily == AddressFamily.InterNetworkV6 && (NetworkHelper.IPv6Support == false);
}
public sealed class TransportTcpNutssbState
{
public string FromMachineName { get; set; }
}
}
}

View File

@@ -53,7 +53,7 @@ namespace cmonitor.plugins.viewer.messenger
public async Task ProxyFromServer(IConnection connection) public async Task ProxyFromServer(IConnection connection)
{ {
ViewerProxyInfo proxy = MemoryPackSerializer.Deserialize<ViewerProxyInfo>(connection.ReceiveRequestWrap.Payload.Span); ViewerProxyInfo proxy = MemoryPackSerializer.Deserialize<ViewerProxyInfo>(connection.ReceiveRequestWrap.Payload.Span);
proxy.ProxyEP = $"{clientSignInState.Connection.Address.Address}:{config.Data.Client.Viewer.ProxyPort}"; proxy.ProxyEP = new System.Net.IPEndPoint(clientSignInState.Connection.Address.Address,config.Data.Client.Viewer.ProxyPort);
proxy.TargetEP = runningConfig.Data.Viewer.ConnectEP; proxy.TargetEP = runningConfig.Data.Viewer.ConnectEP;
await viewerProxyClient.Connect(proxy); await viewerProxyClient.Connect(proxy);
} }

View File

@@ -248,22 +248,13 @@ namespace cmonitor.plugins.viewer.proxy
Socket targetSocket = null; Socket targetSocket = null;
try try
{ {
if (IPEndPoint.TryParse(viewerProxyInfo.ProxyEP, out IPEndPoint proxyEP) == false) proxySocket = new Socket(viewerProxyInfo.ProxyEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
{
return;
}
if (IPEndPoint.TryParse(viewerProxyInfo.TargetEP, out IPEndPoint targetEP) == false)
{
return;
}
proxySocket = new Socket(proxyEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
proxySocket.KeepAlive(); proxySocket.KeepAlive();
await proxySocket.ConnectAsync(proxyEP); await proxySocket.ConnectAsync(viewerProxyInfo.ProxyEP);
targetSocket = new Socket(targetEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); targetSocket = new Socket(viewerProxyInfo.TargetEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
targetSocket.KeepAlive(); targetSocket.KeepAlive();
await targetSocket.ConnectAsync(targetEP); await targetSocket.ConnectAsync(viewerProxyInfo.TargetEP);
int length = responseBytes.Length + 4; int length = responseBytes.Length + 4;
byte[] data = ArrayPool<byte>.Shared.Rent(length); byte[] data = ArrayPool<byte>.Shared.Rent(length);
@@ -428,9 +419,11 @@ namespace cmonitor.plugins.viewer.proxy
public string ViewerMachine { get; set; } public string ViewerMachine { get; set; }
public string ProxyEP { get; set; } [MemoryPackAllowSerialize]
public IPEndPoint ProxyEP { get; set; }
public string TargetEP { get; set; } [MemoryPackAllowSerialize]
public IPEndPoint TargetEP { get; set; }
} }
public sealed class ConnectServerCache public sealed class ConnectServerCache

View File

@@ -35,7 +35,7 @@ namespace cmonitor.plugins.viewer.proxy
Payload = MemoryPackSerializer.Serialize(new ViewerProxyInfo Payload = MemoryPackSerializer.Serialize(new ViewerProxyInfo
{ {
ConnectId = connectId, ConnectId = connectId,
ProxyEP = $"{clientSignInState.Connection.LocalAddress.Address}:{LocalEndpoint.Port}", ProxyEP = new System.Net.IPEndPoint(clientSignInState.Connection.LocalAddress.Address, LocalEndpoint.Port),
ViewerMachine = runningConfig.Data.Viewer.ServerMachine ViewerMachine = runningConfig.Data.Viewer.ServerMachine
}) })
}); });

View File

@@ -31,7 +31,7 @@ namespace cmonitor.plugins.viewer.proxy
Payload = MemoryPackSerializer.Serialize(new ViewerProxyInfo Payload = MemoryPackSerializer.Serialize(new ViewerProxyInfo
{ {
ConnectId = connectId, ConnectId = connectId,
ProxyEP = string.Empty, ProxyEP = null,
ViewerMachine = string.Empty ViewerMachine = string.Empty
}) })
}); });

View File

@@ -10,9 +10,9 @@ namespace cmonitor.plugins.viewer.report
public void Open(bool value, ParamInfo info); public void Open(bool value, ParamInfo info);
public string GetConnectString(); public string GetConnectString();
public void SetConnectString(string connectStr); public void SetConnectString(string connectStr);
public string GetConnectEP(string connectStr) public IPEndPoint GetConnectEP(string connectStr)
{ {
return string.Empty; return null;
} }
} }
@@ -50,7 +50,8 @@ namespace cmonitor.plugins.viewer.report
/// 比如 B 是共享服务端A是共享客户端 /// 比如 B 是共享服务端A是共享客户端
/// 当连不上时会需要代理由B去连接A或者B去连接服务器形成通道那B这边还需要手动连接共享服务就用这个去连 /// 当连不上时会需要代理由B去连接A或者B去连接服务器形成通道那B这边还需要手动连接共享服务就用这个去连
/// </summary> /// </summary>
public string ConnectEP { get; set; } = string.Empty; [MemoryPackAllowSerialize]
public IPEndPoint ConnectEP { get; set; }
} }
public enum ViewerMode : byte public enum ViewerMode : byte

View File

@@ -16,9 +16,9 @@ namespace cmonitor.plugins.viewer.report
} }
public string GetConnectEP(string connectStr) public IPEndPoint GetConnectEP(string connectStr)
{ {
return string.Empty; return null;
} }
} }
} }

View File

@@ -16,9 +16,9 @@ namespace cmonitor.plugins.viewer.report
} }
public string GetConnectEP(string connectStr) public IPEndPoint GetConnectEP(string connectStr)
{ {
return string.Empty; return null;
} }
} }
} }

View File

@@ -179,7 +179,7 @@ namespace cmonitor.plugins.viewer.report
} }
private void UpdateConnectEP() private void UpdateConnectEP()
{ {
string connectEP = viewer.GetConnectEP(runningConfig.Data.Viewer.ConnectStr); IPEndPoint connectEP = viewer.GetConnectEP(runningConfig.Data.Viewer.ConnectStr);
runningConfig.Data.Viewer.ConnectEP = connectEP; runningConfig.Data.Viewer.ConnectEP = connectEP;
runningConfig.Data.Update(); runningConfig.Data.Update();
} }

View File

@@ -35,7 +35,7 @@ namespace cmonitor.plugins.viewer.report
Registry.SetValue("HKEY_CURRENT_USER\\SOFTWARE\\Cmonitor", "viewerConnectStr", connectStr); Registry.SetValue("HKEY_CURRENT_USER\\SOFTWARE\\Cmonitor", "viewerConnectStr", connectStr);
} }
public string GetConnectEP(string connectStr) public IPEndPoint GetConnectEP(string connectStr)
{ {
try try
{ {
@@ -48,13 +48,13 @@ namespace cmonitor.plugins.viewer.report
var p = node.Attributes["P"].Value; var p = node.Attributes["P"].Value;
var n = node.Attributes["N"].Value; var n = node.Attributes["N"].Value;
return $"{n}:{p}"; return new IPEndPoint(IPAddress.Parse(n),int.Parse(p));
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Instance.Error(ex); Logger.Instance.Error(ex);
} }
return string.Empty; return null;
} }
} }
} }

View File

@@ -0,0 +1,50 @@
using common.libs.extends;
using MemoryPack;
using System.Net;
namespace cmonitor.serializes
{
public sealed class IPEndPointFormatter : MemoryPackFormatter<IPEndPoint>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref IPEndPoint value)
{
if (value == null)
{
writer.WriteNullCollectionHeader();
return;
}
Memory<byte> memory = new byte[20];
Span<byte> span = memory.Span;
int index = 1;
value.Address.TryWriteBytes(span.Slice(index), out int bytesWritten);
index += bytesWritten;
span[0] = (byte)bytesWritten;
ushort port = (ushort)value.Port;
port.ToBytes(memory.Slice(index));
index += 2;
writer.WriteCollectionHeader(index + 4);
writer.WriteSpan(span.Slice(0, index));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref IPEndPoint value)
{
if (!reader.TryReadCollectionHeader(out int len))
{
value = null;
return;
}
Span<byte> span = Array.Empty<byte>();
reader.ReadSpan(ref span);
int length = span[4];
value = new IPEndPoint(new IPAddress(span.Slice(4 + 1, length)), span.Slice(4 + 1 + length).ToUInt16());
}
}
}

View File

@@ -0,0 +1,30 @@
using cmonitor.config;
using cmonitor.startup;
using MemoryPack;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace cmonitor.serializes
{
public sealed class SerializeStartup : IStartup
{
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
MemoryPackFormatterProvider.Register(new IPEndPointFormatter());
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
MemoryPackFormatterProvider.Register(new IPEndPointFormatter());
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
}
}

View File

@@ -16,6 +16,8 @@ namespace cmonitor.startup
types = types.Where(c => config.Data.Common.PluginNames.Any(d => c.FullName.Contains(d))); types = types.Where(c => config.Data.Common.PluginNames.Any(d => c.FullName.Contains(d)));
} }
startups = types.Select(c => Activator.CreateInstance(c) as IStartup).ToList(); startups = types.Select(c => Activator.CreateInstance(c) as IStartup).ToList();
Logger.Instance.Warning($"load startup : {string.Join(",", types.Select(c=>c.Name))}");
} }
public static void Add(ServiceCollection serviceCollection, Config config, Assembly[] assemblies) public static void Add(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)

View File

@@ -1,7 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text;
namespace common.libs namespace common.libs
{ {
@@ -46,6 +49,75 @@ namespace common.libs
return new IPEndPoint(ip, port); return new IPEndPoint(ip, port);
} }
public static ushort GetRouteLevel(out List<IPAddress> ips)
{
ips = new List<IPAddress>();
try
{
List<string> starts = new() { "10.", "100.", "192.168.", "172." };
var list = GetTraceRoute("www.baidu.com").ToList();
for (ushort i = 0; i < list.Count(); i++)
{
string ip = list.ElementAt(i).ToString();
if (ip.StartsWith(starts[0], StringComparison.Ordinal) || ip.StartsWith(starts[1], StringComparison.Ordinal) || ip.StartsWith(starts[2], StringComparison.Ordinal) || ip.StartsWith(starts[3], StringComparison.Ordinal))
{
if (ip.StartsWith(starts[2], StringComparison.Ordinal) == false)
ips.Add(list.ElementAt(i));
}
else
{
return i;
}
}
}
catch (Exception)
{
}
return 0;
}
public static IEnumerable<IPAddress> GetTraceRoute(string hostNameOrAddress)
{
return GetTraceRoute(hostNameOrAddress, 1);
}
private static IEnumerable<IPAddress> GetTraceRoute(string hostNameOrAddress, int ttl)
{
Ping pinger = new();
// 创建PingOptions对象
PingOptions pingerOptions = new(ttl, true);
int timeout = 100;
byte[] buffer = Encoding.ASCII.GetBytes("11");
// 创建PingReply对象
// 发送ping命令
PingReply reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions);
// 处理返回结果
List<IPAddress> result = new();
if (reply.Status == IPStatus.Success)
{
result.Add(reply.Address);
}
else if (reply.Status == IPStatus.TtlExpired || reply.Status == IPStatus.TimedOut)
{
//增加当前这个访问地址
if (reply.Status == IPStatus.TtlExpired)
{
result.Add(reply.Address);
}
if (ttl <= 10)
{
//递归访问下一个地址
IEnumerable<IPAddress> tempResult = GetTraceRoute(hostNameOrAddress, ttl + 1);
result.AddRange(tempResult);
}
}
else
{
//失败
}
return result;
}
#if DISABLE_IPV6 || (!UNITY_EDITOR && ENABLE_IL2CPP && !UNITY_2018_3_OR_NEWER) #if DISABLE_IPV6 || (!UNITY_EDITOR && ENABLE_IL2CPP && !UNITY_2018_3_OR_NEWER)
public static bool IPv6Support = false; public static bool IPv6Support = false;