using linker.tunnel.connection; using linker.libs; using linker.libs.extends; using System.Buffers; using System.Net; using System.Net.Sockets; namespace linker.messenger.forward.proxy { public partial class ForwardProxy { private readonly NumberSpace ns = new NumberSpace(); private void Start(IPEndPoint ep, byte bufferSize) { StartTcp(ep, bufferSize); StartUdp(new IPEndPoint(ep.Address, LocalEndpoint.Port), bufferSize); } /// /// 根据不同的消息类型做不同的事情 /// /// /// private async Task ReadConnectionPack(AsyncUserTunnelToken token) { switch (token.Proxy.Step) { case ProxyStep.Request: ConnectBind(token); break; case ProxyStep.Forward: { if (token.Proxy.Protocol == ProxyProtocol.Tcp) { await SendToSocketTcp(token).ConfigureAwait(false); } else { await SendToSocketUdp(token).ConfigureAwait(false); } } break; case ProxyStep.Receive: ReceiveSocket(token); break; case ProxyStep.Close: CloseSocket(token); break; default: break; } } private void Stop() { StopTcp(); StopUdp(); } private void Stop(int port) { StopTcp(port); StopUdp(port); } } public enum ProxyStep : byte { Request = 1, Forward = 2, Receive = 3, Pause = 4, Close = 5, } public enum ProxyProtocol : byte { Tcp = 0, Udp = 1 } public enum ProxyDirection : byte { Forward = 0, Reverse = 1 } public sealed class ProxyInfo { public ulong ConnectId { get; set; } public ProxyStep Step { get; set; } = ProxyStep.Request; public ProxyProtocol Protocol { get; set; } = ProxyProtocol.Tcp; public ProxyDirection Direction { get; set; } = ProxyDirection.Forward; public byte BufferSize { get; set; } = 3; public ushort Port { get; set; } public IPEndPoint SourceEP { get; set; } public IPEndPoint TargetEP { get; set; } public byte Rsv { get; set; } public ReadOnlyMemory Data { get; set; } public byte[] ToBytes(out int length) { int sourceLength = SourceEP == null ? 0 : (SourceEP.AddressFamily == AddressFamily.InterNetwork ? 4 : 16) + 2; int targetLength = TargetEP == null ? 0 : (TargetEP.AddressFamily == AddressFamily.InterNetwork ? 4 : 16) + 2; length = 4 + 8 + 1 + 1 + 2 + 1 + sourceLength + 1 + targetLength + Data.Length; byte[] bytes = ArrayPool.Shared.Rent(length); Memory memory = bytes.AsMemory(); int index = 0; (length - 4).ToBytes(memory); index += 4; ConnectId.ToBytes(memory.Slice(index)); index += 8; bytes[index] = (byte)(((byte)Step << 4) | ((byte)Protocol << 2) | (byte)Direction); index += 1; bytes[index] = BufferSize; index += 1; Port.ToBytes(memory.Slice(index)); index += 2; bytes[index] = (byte)sourceLength; index += 1; if (sourceLength > 0) { SourceEP.Address.TryWriteBytes(memory.Slice(index).Span, out int writeLength); index += writeLength; ((ushort)SourceEP.Port).ToBytes(memory.Slice(index)); index += 2; } bytes[index] = (byte)targetLength; index += 1; if (targetLength > 0) { TargetEP.Address.TryWriteBytes(memory.Slice(index).Span, out int writeLength); index += writeLength; ((ushort)TargetEP.Port).ToBytes(memory.Slice(index)); index += 2; } Data.CopyTo(memory.Slice(index)); return bytes; } public void Return(byte[] bytes) { ArrayPool.Shared.Return(bytes); } public void DeBytes(ReadOnlyMemory memory) { int index = 0; ReadOnlySpan span = memory.Span; ConnectId = memory.Slice(index).ToUInt64(); index += 8; Step = (ProxyStep)(span[index] >> 4); Protocol = (ProxyProtocol)((span[index] & 0b1100) >> 2); Direction = (ProxyDirection)(span[index] & 0b0011); index++; BufferSize = span[index]; index++; Port = memory.Slice(index).ToUInt16(); index += 2; byte sourceLength = span[index]; index += 1; if (sourceLength > 0) { IPAddress ip = new IPAddress(span.Slice(index, sourceLength - 2)); index += sourceLength; ushort port = span.Slice(index - 2).ToUInt16(); SourceEP = new IPEndPoint(ip, port); } byte targetLength = span[index]; index += 1; if (targetLength > 0) { IPAddress ip = new IPAddress(span.Slice(index, targetLength - 2)); index += targetLength; ushort port = span.Slice(index - 2).ToUInt16(); TargetEP = new IPEndPoint(ip, port); } Data = memory.Slice(index); } } public sealed class AsyncUserTunnelToken { public ITunnelConnection Connection { get; set; } public ProxyInfo Proxy { get; set; } public void Clear() { GC.Collect(); } public ConnectId GetTcpConnectId() { return new ConnectId(Proxy.ConnectId, Connection.RemoteMachineId.GetHashCode(), Connection.TransactionId.GetHashCode(), (byte)Proxy.Direction); } public ConnectIdUdp GetUdpConnectId() { return new ConnectIdUdp(Proxy.SourceEP, Connection.RemoteMachineId.GetHashCode(), Connection.TransactionId.GetHashCode()); } } }