void Initialize_TcpDecrypt_Crumb() { if (null == _tcp_decrypt_crumb) { _tcp_decrypt_crumb = SmartBuffer.Rent(LEN_TCP_MAX_CHUNK + LEN_TCP_OVERHEAD_PER_CHUNK + 100); } }
public virtual SmartBuffer EncryptUdp(ReadOnlyMemory <byte> plain) { if (plain.IsEmpty) { _logger?.LogInformation($"ShadowosocksAeadCipher EncryptUdp plain.IsEmpty."); return(null); } var cipherPacket = SmartBuffer.Rent(1500 + LEN_TAG + _keySize_SaltSize.Item2); var cipherPacketStream = new MemoryWriter(cipherPacket.Memory); byte[] salt = new byte[_keySize_SaltSize.Item2], key = new byte[_keySize_SaltSize.Item1]; RandomNumberGenerator.Fill(salt); DeriveSubKey(_masterKeyBytes, salt, SubkeyInfoBytes, key, key.Length); //[encrypted payload][tag] using (var payload = this.EncryptChunk(plain, key.AsSpan(), _nonceZero.AsSpan())) { cipherPacketStream.Write(salt.AsMemory()); cipherPacketStream.Write(payload.SignificantMemory); cipherPacket.SignificantLength = cipherPacketStream.Position; //[salt][encrypted payload][tag] } return(cipherPacket); }
protected override SmartBuffer EncryptChunk(ReadOnlyMemory <byte> raw, ReadOnlySpan <byte> key, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> add = default) { AesGcm aes = null; if (!_cipherPool.TryPop(out aes)) { aes = new AesGcm(key); } SmartBuffer cipherPacket = SmartBuffer.Rent(raw.Length + LEN_TAG); var cipherSpan = cipherPacket.Memory.Span; try { aes.Encrypt(nonce, raw.Span, cipherSpan.Slice(0, raw.Length), cipherSpan.Slice(raw.Length, LEN_TAG), add); cipherPacket.SignificantLength = raw.Length + LEN_TAG; } catch (Exception ex) { cipherPacket.SignificantLength = 0; _logger?.LogError(ex, "AeadAesGcm EncryptChunk failed."); } finally { _cipherPool.Push(aes); } return(cipherPacket); }
protected override SmartBuffer DecryptChunk(ReadOnlyMemory <byte> cipher, ReadOnlySpan <byte> key, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> add = default) { AesGcm aes = null; if (!_cipherPool.TryPop(out aes)) { aes = new AesGcm(key); } SmartBuffer plainPacket = SmartBuffer.Rent(cipher.Length); var plainSpan = plainPacket.Memory.Span; try { aes.Decrypt(nonce, cipher.Span.Slice(0, cipher.Length - LEN_TAG), cipher.Span.Slice(cipher.Length - LEN_TAG), plainSpan.Slice(0, cipher.Length - LEN_TAG), add); plainPacket.SignificantLength = cipher.Length - LEN_TAG; } catch (Exception ex) { plainPacket.SignificantLength = 0; _logger?.LogError(ex, "AeadAesGcm DecryptChunk failed."); } finally { _cipherPool.Push(aes); } return(plainPacket); }
/// <summary> /// /// </summary> /// <param name="cipher">[Cipher][Tag]</param> /// <param name="key"></param> /// <param name="nonce"></param> /// <param name="aad"></param> /// <returns>[Plain]</returns> protected override SmartBuffer DecryptChunk(ReadOnlyMemory <byte> cipher, ReadOnlySpan <byte> key, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> aad = default) { var rt = SmartBuffer.Rent(cipher.Length - LEN_TAG); var aead = this.CreateCipher(key, nonce, aad); using (MemoryStream src = MemoryStreamManager.GetStream(), work = MemoryStreamManager.GetStream()) { cipher.Slice(0, cipher.Length - LEN_TAG).CopyToStream(src); src.Position = 0; try { aead.Decrypt(src, src, work, cipher.Slice(cipher.Length - LEN_TAG).Span); src.Position = 0; rt.SignificantLength += rt.Memory.CopyFromStream(src); } catch (Exception ex) { Console.WriteLine($"AeadChaChaPoly1305 DecryptChunk failed. {ex.Message}"); _logger?.LogWarning($"AeadChaChaPoly1305 DecryptChunk failed. {ex.Message}"); rt.SignificantLength = 0; } return(rt); } }
/// <summary> /// Read the client. /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> public async ValueTask <ReadResult> Read(CancellationToken cancellationToken) { var received = SmartBuffer.Rent(_bufferSize); received.SignificantLength = await Client.ReadAsync(received.Memory, cancellationToken); _logger?.LogInformation($"PipeReader Received {received.SignificantLength} bytes from [{Client.EndPoint.ToString()}]."); if (0 >= received.SignificantLength) { received.Dispose(); return(new ReadResult(Failed, null, received.SignificantLength)); } if (FilterEnabled && FilterChain.Count > 0) { var result = ExecuteFilter(received.SignificantMemory, cancellationToken); received.Dispose(); received = result.Buffer; if (!result.Continue) { received?.Dispose(); return(new ReadResult(BrokeByFilter, null, 0)); } } int read = null != received ? received.SignificantLength : 0; _logger?.LogInformation($"{read} bytes left after [OnReading] filtering."); return(new ReadResult(Succeeded, received, read)); }
public virtual SmartBuffer EncryptTcp(ReadOnlyMemory <byte> plain) { if (plain.IsEmpty) { _logger?.LogInformation($"ShadowosocksAeadCipher EncryptTcp plain.IsEmpty."); return(null); } int cipherLen = CalcTcpCipherStreamLength(plain.Length); SmartBuffer cihperBuffer = SmartBuffer.Rent(cipherLen); var cipherStream = new MemoryWriter(cihperBuffer.Memory); if (!_tcpCtx加密.HaveSalt()) { _tcpCtx加密.NewSalt(); cipherStream.Write(_tcpCtx加密.Salt.AsMemory()); _logger?.LogInformation($"ShadowosocksAeadCipher EncryptTcp new salt wrote. { _tcpCtx加密.Salt.ToHexString()}"); DeriveSubKey(_masterKeyBytes, _tcpCtx加密.Salt, SubkeyInfoBytes, _tcpCtx加密.Key, _tcpCtx加密.Key.Length); _logger?.LogInformation($"ShadowosocksAeadCipher EncryptTcp new subkey {_tcpCtx加密.Key.ToHexString()}."); } int remain = plain.Length; int chunkLen = 0, encrypted = 0; do { chunkLen = Math.Min(remain, LEN_TCP_MAX_CHUNK); //payload length. { byte[] payloadLenBytes = BitConverter.GetBytes((ushort)(System.Net.IPAddress.HostToNetworkOrder((short)chunkLen))); _logger?.LogInformation($"ShadowosocksAeadCipher EncryptTcp chunklen={chunkLen}, payloadLenBytes={payloadLenBytes.ToHexString()}."); using (var payloadLenC = this.EncryptChunk(payloadLenBytes, _tcpCtx加密.Key, _tcpCtx加密.Nonce)) { //[encrypted payload length][length tag] cipherStream.Write(payloadLenC.Memory.Slice(0, payloadLenC.SignificantLength)); _tcpCtx加密.IncreaseNonce(); } } //payload. { var payload = plain.Slice(plain.Length - remain, chunkLen); using (var payloadC = this.EncryptChunk(payload, _tcpCtx加密.Key, _tcpCtx加密.Nonce)) { //[encrypted payload][payload tag] cipherStream.Write(payloadC.Memory.Slice(0, payloadC.SignificantLength)); _tcpCtx加密.IncreaseNonce(); } } //------------------------------- encrypted += chunkLen; _logger?.LogInformation($"ShadowosocksAeadCipher EncryptTcp encrypted {encrypted} bytes."); remain -= chunkLen; } while (remain > 0); cihperBuffer.SignificantLength = cipherStream.Position; return(cihperBuffer); }
public override ClientFilterResult AfterReading(ClientFilterContext ctx) { _logger?.LogInformation($"TestPipeFilter AfterReading data={ctx.Memory.ToArray().ToHexString()}"); var newBuff = SmartBuffer.Rent(ctx.Memory.Length - 4); ctx.Memory.Slice(4).CopyTo(newBuff.Memory); newBuff.SignificantLength = ctx.Memory.Length - 4; return(new ClientFilterResult(ctx.Client, newBuff, true)); }
public override ClientFilterResult BeforeWriting(ClientFilterContext ctx) { _logger?.LogInformation($"TestPipeFilter BeforeWriting data={ctx.Memory.ToArray().ToHexString()}"); var newBuff = SmartBuffer.Rent(ctx.Memory.Length + 4); var p = newBuff.Memory.Span; p[0] = 0x12; p[1] = 0x34; p[4] = 0xAB; p[3] = 0xCD; ctx.Memory.CopyTo(newBuff.Memory.Slice(4)); newBuff.SignificantLength = ctx.Memory.Length + 4; return(new ClientFilterResult(ctx.Client, newBuff, true)); }
public override ClientFilterResult BeforeWriting(ClientFilterContext ctx) { SmartBuffer toTarget = SmartBuffer.Rent(ctx.Memory.Length); if (ShadowsocksAddress.TryResolveLength(ctx.Memory, out int targetAddrLen)) { ctx.Memory.Slice(targetAddrLen).CopyTo(toTarget.Memory); toTarget.SignificantLength = ctx.Memory.Length - targetAddrLen; return(new ClientFilterResult(ctx.Client, toTarget, true)); } else { return(new ClientFilterResult(ctx.Client, toTarget, false)); } }
public ShadowosocksAeadCipher(string password, ValueTuple <int, int> key_salt_size, ILogger logger = null) : base(password) { _keySize_SaltSize = key_salt_size; _logger = logger; _hkdf = new HkdfBytesGenerator(new Sha1Digest()); _masterKeyBytes = MasterKeyGenerator.PasswordToKey(password, _keySize_SaltSize.Item1); _logger?.LogInformation($"ShadowosocksAeadCipher ctor " + $"_keySize_SaltSize={_keySize_SaltSize.Item1},{_keySize_SaltSize.Item2}"); _tcpCtx加密 = new TcpCipherContext(_keySize_SaltSize.Item1, _keySize_SaltSize.Item2); _tcpCtx解密 = new TcpCipherContext(_keySize_SaltSize.Item1, _keySize_SaltSize.Item2); _tcp_decrypt_crumb = SmartBuffer.Rent(LEN_TCP_OVERHEAD_PER_CHUNK * 2); }
public override ClientFilterResult BeforeWriting(ClientFilterContext ctx) { if (!ctx.Memory.IsEmpty) { SmartBuffer toRemote = SmartBuffer.Rent(1500); ctx.Memory.Slice(3).CopyTo(toRemote.Memory); toRemote.SignificantLength = ctx.Memory.Length - 3; return(new ClientFilterResult(ctx.Client, toRemote, true)); } else { _logger?.LogError($"LocalUdpRelayPackingFilter BeforeWriting filterContext.Memory.IsEmpty"); } return(new ClientFilterResult(this.Client, null, false)); }
public void TestMemoryPool1() { var buf1 = SmartBuffer.Rent(16); System.Security.Cryptography.RandomNumberGenerator.Fill(buf1.Memory.Span); Trace.TraceInformation(BitConverter.ToString(buf1.Memory.ToArray()).Replace("-", "")); buf1.Dispose(); var buf2 = SmartBuffer.Rent(10); Trace.TraceInformation(BitConverter.ToString(buf2.Memory.ToArray()).Replace("-", "")); buf2.Dispose(); var buf3 = SmartBuffer.Rent(20); Trace.TraceInformation(BitConverter.ToString(buf3.Memory.ToArray()).Replace("-", "")); buf3.Dispose(); }
public override ClientFilterResult AfterReading(ClientFilterContext ctx) { if (!ctx.Memory.IsEmpty) { SmartBuffer toApplication = SmartBuffer.Rent(1500); ctx.Memory.CopyTo(toApplication.Memory.Slice(2 + 1)); var p = toApplication.Memory.Span; p.Slice(0, 3).Fill(0x0); toApplication.SignificantLength = ctx.Memory.Length + 2 + 1; return(new ClientFilterResult(ctx.Client, toApplication, true)); } else { _logger?.LogError($"LocalUdpRelayPackingFilter AfterReading filterContext.Memory.IsEmpty"); } return(new ClientFilterResult(this.Client, null, false)); }
protected override SmartBuffer EncryptChunk(ReadOnlyMemory <byte> raw, ReadOnlySpan <byte> key, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> aad = default) { using (var aes = new AesGcm(key)) { SmartBuffer cipherPacket = SmartBuffer.Rent(raw.Length + LEN_TAG); var cipherSpan = cipherPacket.Memory.Span; try { aes.Encrypt(nonce, raw.Span, cipherSpan.Slice(0, raw.Length), cipherSpan.Slice(raw.Length, LEN_TAG), aad); cipherPacket.SignificantLength = raw.Length + LEN_TAG; } catch (Exception ex) { cipherPacket.SignificantLength = 0; _logger?.LogWarning($"AeadAesGcm EncryptChunk failed. {ex.Message}"); } return(cipherPacket); } }
protected override SmartBuffer DecryptChunk(ReadOnlyMemory <byte> cipher, ReadOnlySpan <byte> key, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> aad = default) { using (var aes = new AesGcm(key)) { SmartBuffer plainPacket = SmartBuffer.Rent(cipher.Length); var plainSpan = plainPacket.Memory.Span; try { aes.Decrypt(nonce, cipher.Span.Slice(0, cipher.Length - LEN_TAG), cipher.Span.Slice(cipher.Length - LEN_TAG), plainSpan.Slice(0, cipher.Length - LEN_TAG), aad); plainPacket.SignificantLength = cipher.Length - LEN_TAG; } catch (Exception ex) { plainPacket.SignificantLength = 0; _logger?.LogWarning($"AeadAesGcm DecryptChunk failed. {ex.Message}"); } return(plainPacket); } }
public override ClientFilterResult AfterReading(ClientFilterContext ctx) { SmartBuffer toSsLocal = SmartBuffer.Rent(1500);//TODO what if exceeds 1500? fragments or not? if (ShadowsocksAddress.TrySerailizeTo( (byte)(AddressFamily.InterNetworkV6 == ctx.Client.EndPoint.AddressFamily ? 0x4 : 0x1), ctx.Client.EndPoint.Address.GetAddressBytes(), (ushort)ctx.Client.EndPoint.Port, toSsLocal.Memory, out int written)) { toSsLocal.SignificantLength = written; int payloadToCopy = Math.Min(toSsLocal.FreeSpace, ctx.Memory.Length); ctx.Memory.Slice(0, payloadToCopy).CopyTo(toSsLocal.FreeMemory); toSsLocal.SignificantLength += payloadToCopy; return(new ClientFilterResult(ctx.Client, toSsLocal, true));; } return(new ClientFilterResult(ctx.Client, null, false));; }
/// <summary> /// /// </summary> /// <param name="raw">[Plain]</param> /// <param name="key"></param> /// <param name="nonce"></param> /// <param name="aad"></param> /// <returns>[Cipher][Tag]</returns> protected override SmartBuffer EncryptChunk(ReadOnlyMemory <byte> raw, ReadOnlySpan <byte> key, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> aad = default) { var aead = this.CreateCipher(key, nonce, aad); using (MemoryStream src = MemoryStreamManager.GetStream(), work = MemoryStreamManager.GetStream()) { raw.CopyToStream(src); src.Position = 0; var tag = aead.Encrypt(src, src, work); src.Position = 0; var rt = SmartBuffer.Rent((int)raw.Length + tag.Length); rt.SignificantLength = rt.Memory.CopyFromStream(src); tag.AsMemory().CopyTo(rt.FreeMemory); rt.SignificantLength += tag.Length; return(rt); } }
async Task <bool> Handshake(IClient client, CancellationToken cancellationToken) { using (var request = SmartBuffer.Rent(300)) { request.SignificantLength = await client.ReadAsync(request.Memory, cancellationToken); if (2 < request.SignificantLength) { if (request.Memory.Span[0] != 0x5)//accept socks5 only. { await client.WriteAsync(NegotiationResponse.HandshakeReject, cancellationToken); client.Close(); return(false); } else { return(2 == await client.WriteAsync(NegotiationResponse.HandshakeAccept, cancellationToken)); } } client.Close(); return(false); } }
/* * # shadowsocks UDP Request (before encrypted) # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ # # shadowsocks UDP Response (before encrypted) # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ */ public async Task HandleUdp(IClient client, CancellationToken cancellationToken = default) { if (null == client) { return; } using (SmartBuffer localRequestCipher = SmartBuffer.Rent(1500)) { localRequestCipher.SignificantLength = await client.ReadAsync(localRequestCipher.Memory, cancellationToken);//A. read a packet if (0 == localRequestCipher.SignificantLength) { _logger?.LogWarning($"HandleUdp an empty udp packet received, client=[{client.EndPoint.ToString()}]"); client.Close(); return; } var cipher = _remoteServerConfig.CreateCipher(_logger); using (var localReqest = cipher.DecryptUdp(localRequestCipher.SignificanMemory)) //B. decrypt { if (null == localReqest || 0 == localReqest.SignificantLength) //decrypt failed, available options: 1.leave it. 2.close connection. 3.add to blocklist. { _logger?.LogWarning($"HandleUdp decrypt failed, client=[{client.EndPoint.ToString()}]"); client.Close();//->local pipe broken-> local pipe close. return; } IPAddress targetIP = IPAddress.Any; //TODO target address check if (ShadowsocksAddress.TryResolve(localReqest.SignificanMemory, out ShadowsocksAddress ssaddr)) //C. resolve target address { if (0x3 == ssaddr.ATYP) //a domain name { var ips = await _dnsCache.ResolveHost(Encoding.UTF8.GetString(ssaddr.Address.ToArray())); if (ips != null && ips.Length > 0) { targetIP = ips[0]; } } else { targetIP = new IPAddress(ssaddr.Address.Span); } if (IPAddress.Any != targetIP)//D. target addr resolved. { IPEndPoint targetEndPoint = new IPEndPoint(targetIP, ssaddr.Port); var targetClient = await UdpClient1.ConnectAsync(targetEndPoint, _logger);//E. connect to target if (null == targetClient) { _logger?.LogInformation($"HandleUdp unable to connect target [{targetEndPoint.ToString()}]. client=[{client.EndPoint.ToString()}]"); client.Close(); return; } await targetClient.WriteAsync(localReqest.Memory.Slice(ssaddr.RawMemory.Length), cancellationToken); //F. send payload . PipeUdp(client, targetClient, cipher, cancellationToken); //G. piping } else//resolve target address failed. { _logger?.LogWarning($"HandleUdp invalid target addr. client=[{client.EndPoint.ToString()}]"); client.Close(); return; } } else { _logger?.LogWarning($"HandleUdp resolve target addr failed. client=[{client.EndPoint.ToString()}]"); client.Close(); return; } } }//end using }
async Task PipeB2A(CancellationToken cancellationToken) { SmartBuffer buffer = SmartBuffer.Rent(_bufferSize);//read buff buffer.SignificantLength = await ClientB.ReadAsync(buffer.Memory, cancellationToken); if (buffer.SignificantLength > 0) { if (_filtersB.Count > 0) { bool locked = false; try { DoFilter_Lock(ref locked); PipeFilterResult filterResult = DoFilter_AfterReading(ref buffer, _filtersB, cancellationToken); if (!filterResult.Continue || cancellationToken.IsCancellationRequested) { ReportBroken(); return; } else { buffer = filterResult.Buffer; } DoFilter_UnLock(ref locked); } finally { DoFilter_UnLock(ref locked); } }//end FilterB if (_filtersA.Count > 0) { bool locked = false; try { DoFilter_Lock(ref locked); PipeFilterResult filterResult = DoFilter_BeforeWriting(ref buffer, _filtersA, cancellationToken); if (!filterResult.Continue || cancellationToken.IsCancellationRequested) { ReportBroken(); return; } else { buffer = filterResult.Buffer; } DoFilter_UnLock(ref locked); } finally { DoFilter_UnLock(ref locked); } }//end FilterA int written = await ClientA.WriteAsync(buffer.Memory, cancellationToken);//Pipe _logger?.LogInformation($"DefaultPipe Pipe B to A {written} bytes."); if (written < 0) { ClientA.Close(); buffer.Dispose(); ReportBroken(); return; } } else if (0 == buffer.SignificantLength) { _logger?.LogInformation($"DefaultPipe read = 0."); } else//<0 { _logger?.LogInformation($"DefaultPipe error, read={buffer.SignificantLength}."); ClientB.Close(); ReportBroken(); return; } buffer.Dispose();//free memory. if (!cancellationToken.IsCancellationRequested) { await PipeB2A(cancellationToken);//continue. } }
async Task PipeA2B(CancellationToken cancellationToken) { //using (var received = SmartBuffer.Rent(_bufferSize)) var received = SmartBuffer.Rent(_bufferSize); while (!cancellationToken.IsCancellationRequested) { received.SignificantLength = await ClientA.ReadAsync(received.Memory, cancellationToken); _logger.LogInformation($"Received {received.SignificantLength} bytes from [{ClientA.EndPoint.ToString()}]."); if (0 >= received.SignificantLength) { ReportBroken(PipeBrokenCause.Exception); return; } if (_filtersA.Count > 0) { var result = ExecuteFilter_AfterReading(ClientA, received, _filtersA, cancellationToken); received.Dispose(); received = result.Buffer; if (!result.Continue) { _logger.LogInformation($"Ripe broke by filterA [{ClientA.EndPoint.ToString()}]."); received?.Dispose(); ReportBroken(PipeBrokenCause.FilterBreak); return; } } if (_filtersB.Count > 0) { var result = ExecuteFilter_BeforeWriting(ClientB, received, _filtersB, cancellationToken); received.Dispose(); received = result.Buffer; if (!result.Continue) { _logger.LogInformation($"Ripe broke by filterB [{ClientB.EndPoint.ToString()}]."); received?.Dispose(); ReportBroken(PipeBrokenCause.FilterBreak); return; } } if (null != received && received.SignificantLength > 0) { _logger?.LogInformation($"{received.SignificantLength} bytes left after filtering."); int written = await ClientB.WriteAsync(received.SignificanMemory, cancellationToken); _logger?.LogInformation($"Pipe [{ClientA.EndPoint.ToString()}] => [{ClientB.EndPoint.ToString()}] {written} bytes."); if (0 >= written) { received?.Dispose(); ReportBroken(PipeBrokenCause.Exception); return; } ReportPiping(new PipingEventArgs { Bytes = written, Origin = ClientA.EndPoint, Destination = ClientB.EndPoint }); } //continue piping }//end while received?.Dispose(); ReportBroken(PipeBrokenCause.Cancelled); }
public async Task HandleHttp(IClient client, CancellationToken cancellationToken) { if (null == client) { return; } using (SmartBuffer clientRequest = SmartBuffer.Rent(2048)) { clientRequest.SignificantLength = await client.ReadAsync(clientRequest.Memory, cancellationToken); if (10 >= clientRequest.SignificantLength) { goto GOODBYE503; } if (HttpProxyHeaderResolver.TryResolve(clientRequest.SignificantMemory, out HttpProxyHeaderResolver.Verb httpVerb, out Uri targetHost, out byte[] normalHttpRequestHeader)) { //_logger?.LogInformation($"HttpRoxyServer Verb={httpVerb.ToString()}."); var server = _serverLoader.Load(null); if (null == server) { _logger?.LogInformation($"HttpRoxyServer Proxy server not found."); goto GOODBYE503; } var serverAddr = await server.GetIPEndPoint(); if (null == serverAddr) { _logger?.LogInformation($"HttpRoxyServer Unable to get proxy server address."); goto GOODBYE503; } var relayClient = await TcpClient1.ConnectAsync(serverAddr, _logger); //A. connect ss-remote if (null == relayClient) //unable to connect ss-remote { _logger?.LogInformation($"HttpRoxyServer Unable to connect ss-remote:[{serverAddr.ToString()}]"); goto GOODBYE503; } using (var relayRequst = SmartBuffer.Rent(HttpProxyHeaderResolver.Verb.CONNECT == httpVerb ? 300 : normalHttpRequestHeader.Length + 300)) { if (ShadowsocksAddress.TryParse(targetHost, out Tuple <byte, ushort, byte[]> ssaddr))//B. construct sssaddr { //_logger?.LogInformation($"HttpRoxyServer ATYP={ssaddr.Item1}, port={ssaddr.Item2}"); ShadowsocksAddress.TrySerailizeTo(ssaddr.Item1, ssaddr.Item3, ssaddr.Item2, relayRequst.Memory, out int written); relayRequst.SignificantLength = written; if (HttpProxyHeaderResolver.Verb.CONNECT != httpVerb) { normalHttpRequestHeader.CopyTo(relayRequst.FreeMemory); relayRequst.SignificantLength += normalHttpRequestHeader.Length; } var cipher = server.CreateCipher(_logger); DefaultPipe pipe = new DefaultPipe(client, relayClient, Defaults.ReceiveBufferSize, _logger); Cipher.TcpCipherFilter cipherFilter = new Cipher.TcpCipherFilter(relayClient, cipher, _logger); pipe.ApplyClientFilter(cipherFilter); var writeResult = await pipe.Writer[relayClient].Write(relayRequst.SignificantMemory, cancellationToken);//C. send target addr (& http header) to ss-remote. _logger?.LogInformation($"Send target addr {writeResult.Written} bytes. {writeResult.Result}."); if (HttpProxyHeaderResolver.Verb.CONNECT == httpVerb) { await client.WriteAsync(RESPONSE_200_Connection_Established, cancellationToken); } PipeClient(pipe, cancellationToken);//D. start piping. return; } else { _logger?.LogInformation($"HttpRoxyServer parse host URL failed."); goto GOODBYE503; } } }
public async Task HandleTcp(IClient client, CancellationToken cancellationToken) { if (null == client) { return; } if (!await Handshake(client, cancellationToken)) { return; } //Handshake using (SmartBuffer request = SmartBuffer.Rent(300), response = SmartBuffer.Rent(300)) { request.SignificantLength = await client.ReadAsync(request.Memory, cancellationToken); if (5 >= request.SignificantLength) { client.Close(); return; } #region socks5 /* +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ | | Where: | | o VER protocol version: X'05' | o CMD | o CONNECT X'01' | o BIND X'02' | o UDP ASSOCIATE X'03' | o RSV RESERVED | o ATYP address type of following address | o IP V4 address: X'01' | o DOMAINNAME: X'03' | o IP V6 address: X'04' | o DST.ADDR desired destination address | o DST.PORT desired destination port in network octet | order | | +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ | | Where: | | o VER protocol version: X'05' | o REP Reply field: | o X'00' succeeded | o X'01' general SOCKS server failure | o X'02' connection not allowed by ruleset | o X'03' Network unreachable | o X'04' Host unreachable | o X'05' Connection refused | o X'06' TTL expired | o X'07' Command not supported | o X'08' Address type not supported | o X'09' to X'FF' unassigned | o RSV RESERVED | o ATYP address type of following address | o IP V4 address: X'01' | o DOMAINNAME: X'03' | o IP V6 address: X'04' | o BND.ADDR server bound address | o BND.PORT server bound port in network octet order */ #endregion switch (request.Memory.Span[1]) { case 0x1: //connect //TODO validate addr { var server = _serverLoader.Load(null); if (null == server) { _logger?.LogInformation($"proxy server not found."); client.Close(); break; } var serverAddr = await server.GetIPEndPoint(); if (null == serverAddr) { _logger?.LogInformation($"unable to get proxy server address."); client.Close(); break; } var relayClient = await TcpClient1.ConnectAsync(serverAddr, _logger); //A. connect ss-remote if (null == relayClient) //unable to connect ss-remote { _logger?.LogInformation($"unable to connect ss-remote:[{serverAddr.ToString()}]"); await client.WriteAsync(NegotiationResponse.CommandConnectFailed, cancellationToken); client.Close(); break; } var clientRequest = request; if (ShadowsocksAddress.TryResolve(clientRequest.Memory.Slice(3), out ShadowsocksAddress ssaddr)) //B.resove target addr. { var cipher = server.CreateCipher(_logger); using (var targetAddrCipher = cipher.EncryptTcp(ssaddr.RawMemory)) { int sent = await relayClient.WriteAsync(targetAddrCipher.SignificanMemory, cancellationToken); //C. send target addr to ss-remote. _logger?.LogInformation($"Send target addr {sent}={targetAddrCipher.SignificantLength}."); await client.WriteAsync(NegotiationResponse.CommandConnectOK, cancellationToken); //D. notify client to send data. PipeTcp(client, relayClient, cipher, cancellationToken); //E. start piping. } } else { _logger?.LogWarning("resolve target addr failed."); client.Close(); } } break; case 0x2: //bind { request.SignificanMemory.CopyTo(response.Memory); response.Memory.Span[1] = 0x7; await client.WriteAsync(response.Memory.Slice(0, request.SignificantLength), cancellationToken); client.Close(); } break; case 0x3: //udp assoc { if (ShadowsocksAddress.TrySerailizeTo( (byte)(AddressFamily.InterNetworkV6 == client.LocalEndPoint.AddressFamily ? 0x4 : 0x1), client.LocalEndPoint.Address.GetAddressBytes(), (ushort)client.LocalEndPoint.Port, response.Memory, out int written)) { response.SignificantLength = written; await client.WriteAsync(response.SignificanMemory, cancellationToken); } //TODO client.Closing += this.Client_Closing; } break; default: break; } } }
/// <summary> /// /// </summary> /// <param name="cipher"></param> /// <returns>plain. null if decrypt failed.</returns> public virtual SmartBuffer DecryptTcp(ReadOnlyMemory <byte> cipher) { if (cipher.IsEmpty) { _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp plain.IsEmpty."); return(null); } bool decrypteFailed = false; #region crumb if (null != _tcp_decrypt_crumb && _tcp_decrypt_crumb.SignificantLength > 0)//have crumb left lasttime. { _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp crumb {_tcp_decrypt_crumb.SignificantLength} bytes found."); using (var combCipher = SmartBuffer.Rent(cipher.Length + _tcp_decrypt_crumb.SignificantLength)) { //combine crumb var combCipherStream = new MemoryWriter(combCipher.Memory); combCipherStream.Write(_tcp_decrypt_crumb.SignificantMemory); combCipherStream.Write(cipher); combCipher.SignificantLength = cipher.Length + _tcp_decrypt_crumb.SignificantLength; _tcp_decrypt_crumb.SignificantLength = 0; _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp combined crumb + new cipher = {combCipher.SignificantLength} bytes."); return(DecryptTcp(combCipher.SignificantMemory)); } } if (cipher.Length <= LEN_TCP_OVERHEAD_PER_CHUNK)//still an incomplete chunk. { Initialize_TcpDecrypt_Crumb(); cipher.CopyTo(_tcp_decrypt_crumb.Memory); _tcp_decrypt_crumb.SignificantLength = cipher.Length; _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp save crumb {_tcp_decrypt_crumb.SignificantLength} bytes."); return(null); } #endregion var cipherStreamReader = new ReadOnlyMemoryReader(cipher); if (!_tcpCtx解密.HaveSalt()) { _tcpCtx解密.SetSalt(cipherStreamReader.Read(_tcpCtx解密.Salt.Length)); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp salt read. {_tcpCtx解密.Salt.ToHexString()}"); DeriveSubKey(_masterKeyBytes, _tcpCtx解密.Salt, SubkeyInfoBytes, _tcpCtx解密.Key, _tcpCtx解密.Key.Length); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp new subkey. {_tcpCtx解密.Key.ToHexString()}"); } var plainBuffer = SmartBuffer.Rent(cipher.Length);//enough var plainStream = new MemoryWriter(plainBuffer.Memory); int remain = cipher.Length; do { const int LEN_AND_LENTAG = LEN_TCP_PAYLOADLEN_LENGTH + LEN_TAG; ushort payloadLen = 0; //payloadlen { var arrPayloadLen = cipherStreamReader.Read(LEN_AND_LENTAG); using (var len = this.DecryptChunk(arrPayloadLen, _tcpCtx解密.Key, _tcpCtx解密.Nonce)) { _tcpCtx解密.IncreaseNonce(); if (null == len || 0 >= len.SignificantLength) { decrypteFailed = true;//TODO close client or not break; } var payloadLenBytes = len.SignificantMemory; _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp payloadLenBytes ={payloadLenBytes.ToArray().ToHexString()}."); // payloadLen = (ushort)System.Net.IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(payloadLenBytes.Span)); BinaryPrimitives.TryReadUInt16BigEndian(payloadLenBytes.Span, out payloadLen); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp decrypted payloadLen={payloadLen}."); } if (payloadLen <= 0) { decrypteFailed = true; _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp something weird happened."); break; } if (!decrypteFailed && payloadLen + LEN_TAG > (cipherStreamReader.Length - cipherStreamReader.Position)) { Initialize_TcpDecrypt_Crumb(); cipher.Slice(cipherStreamReader.Position - LEN_AND_LENTAG).CopyTo(_tcp_decrypt_crumb.Memory); _tcp_decrypt_crumb.SignificantLength = (cipherStreamReader.Length - cipherStreamReader.Position + LEN_AND_LENTAG); remain = 0; _tcpCtx解密.DecreaseNonce(); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp save incomplete chunk {_tcp_decrypt_crumb.SignificantLength} bytes."); break; } } //payload { var arrPayload = cipherStreamReader.Read(payloadLen + LEN_TAG); using (var payload = this.DecryptChunk(arrPayload, _tcpCtx解密.Key, _tcpCtx解密.Nonce)) { _tcpCtx解密.IncreaseNonce(); if (0 >= payload.SignificantLength) { decrypteFailed = true; break; } plainStream.Write(payload.SignificantMemory); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp decrypted payload {payload.SignificantLength} bytes."); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp decrypted plain= " + $"{payload.SignificantMemory.ToArray().ToHexString()}"); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp decrypted plain.UTF8= " + $"{Encoding.UTF8.GetString(payload.SignificantMemory.ToArray())}\r\n"); } } //----- _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp one chunk decrypted."); remain = cipherStreamReader.Length - cipherStreamReader.Position; } while (remain > LEN_TCP_OVERHEAD_PER_CHUNK); if (!decrypteFailed && 0 < remain && remain <= LEN_TCP_OVERHEAD_PER_CHUNK)//crumb { Initialize_TcpDecrypt_Crumb(); _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp save incomplete chunk {_tcp_decrypt_crumb.SignificantLength} bytes."); cipher.Slice(cipher.Length - remain, remain).CopyTo(_tcp_decrypt_crumb.Memory); _tcp_decrypt_crumb.SignificantLength += remain;//_decrypt_crumb must be empty. //TODO not thread-safe. } if (decrypteFailed && null != _tcp_decrypt_crumb) { _tcp_decrypt_crumb.Erase(); } plainBuffer.SignificantLength = decrypteFailed ? 0 : plainStream.Position; _logger?.LogInformation($"ShadowosocksAeadCipher DecryptTcp {plainBuffer.SignificantLength} bytes got, will return."); return(plainBuffer); }
public async Task HandleTcp(IClient client, CancellationToken cancellationToken = default) { if (null == client) { return; } using (SmartBuffer localRequestCipher = SmartBuffer.Rent(Defaults.ReceiveBufferSize)) { localRequestCipher.SignificantLength = await client.ReadAsync(localRequestCipher.Memory, cancellationToken);//A. Receive target addr. //decrypt var cipher = _remoteServerConfig.CreateCipher(_logger); using (var localReqestPlain = cipher.DecryptTcp(localRequestCipher.SignificanMemory)) { if (0 == localRequestCipher.SignificantLength) { //decrypt failed, available options: 1.leave it. 2.close connection. 3.add to blocklist. _logger?.LogWarning($"Decrypt target addr failed, client=[{client.EndPoint.ToString()}]"); client.Close();//->local pipe broken-> local pipe close. return; } IPAddress targetIP = IPAddress.Any; //TODO target address check if (ShadowsocksAddress.TryResolve(localReqestPlain.Memory, out ShadowsocksAddress ssaddr)) //B. Resolve target addr. { if (0x3 == ssaddr.ATYP) //a domain name { var ips = await _dnsCache.ResolveHost(Encoding.UTF8.GetString(ssaddr.Address.ToArray())); if (ips != null && ips.Length > 0) { targetIP = ips[0]; } } else//IPv4/v6 { targetIP = new IPAddress(ssaddr.Address.Span); } if (IPAddress.Any == targetIP)//a empty IP. { _logger?.LogWarning($"Invalid target addr. client=[{client.EndPoint.ToString()}]"); client.Close(); return; } IPEndPoint ipeTarget = new IPEndPoint(targetIP, ssaddr.Port); _logger.LogInformation($"Resolved target address:[{ipeTarget.ToString()}]"); _logger.LogInformation($"Connecting to [{ipeTarget.ToString()}]..."); var targetClient = await TcpClient1.ConnectAsync(ipeTarget, _logger); //C. Connect target if (null == targetClient) //connect target failed. { _logger?.LogInformation($"Unable to connect target [{ipeTarget.ToString()}]. client=[{client.EndPoint.ToString()}]"); client.Close(); return; } _logger.LogInformation($"Connected to [{ipeTarget.ToString()}]"); if (localReqestPlain.Memory.Length > ssaddr.RawMemory.Length)//have some payload { _logger.LogInformation($"Writing payload before piping..."); await targetClient.WriteAsync(localReqestPlain.SignificanMemory.Slice(ssaddr.RawMemory.Length)); } _logger.LogInformation($"Start piping..."); PipeTcp(client, targetClient, cipher, cancellationToken);//D. start piping. } else//invalid socks5 addr { _logger?.LogWarning($"StandardRemoteSocks5Handler HandleTcp resolve target addr failed. client=[{client.EndPoint.ToString()}]"); client.Close(); return; } } } await Task.CompletedTask; }