Пример #1
0
 void Initialize_TcpDecrypt_Crumb()
 {
     if (null == _tcp_decrypt_crumb)
     {
         _tcp_decrypt_crumb = SmartBuffer.Rent(LEN_TCP_MAX_CHUNK + LEN_TCP_OVERHEAD_PER_CHUNK + 100);
     }
 }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        /// <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);
            }
        }
Пример #6
0
        /// <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);
        }
Пример #8
0
        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));
        }
Пример #9
0
        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));
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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));
        }
Пример #13
0
        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();
        }
Пример #14
0
        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));
        }
Пример #15
0
 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);
     }
 }
Пример #16
0
        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));;
        }
Пример #18
0
        /// <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
        }
Пример #21
0
        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.
            }
        }
Пример #22
0
        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);
        }
Пример #23
0
        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;
                }
            }
        }
Пример #25
0
        /// <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;
        }