Example #1
0
        public unsafe Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            var tcs = new TaskCompletionSource <object>();

            void packetHandler(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs e)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    var buffer = e.GetDataReader().DetachBuffer();
                    var ptr    = ((IBufferByteAccess)buffer).GetBuffer();
                    localAdapter.WritePacketToLocal(new Span <byte>(ptr.ToPointer(), (int)buffer.Length), cancellationToken);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                }
            }

            udpReceivedHandler = packetHandler;
            cancellationToken.Register(() =>
            {
                tcs.TrySetCanceled();
                var socket = datagramSocket;
                if (socket != null)
                {
                    socket.MessageReceived -= packetHandler;
                }
            });
            return(tcs.Task);
        }
        public unsafe virtual Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            var outDataBuffer = new byte[sendBufferLen + 66];
            var tcs           = new TaskCompletionSource <object>();

            void packetHandler(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs e)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    var buffer     = e.GetDataReader().DetachBuffer();
                    var ptr        = ((IBufferByteAccess)buffer).GetBuffer().ToPointer();
                    var cryptor    = ShadowsocksFactory.GlobalCryptorFactory.CreateCryptor();
                    var decDataLen = Decrypt(new ReadOnlySpan <byte>(ptr, (int)buffer.Length), outDataBuffer, cryptor);
                    // TODO: support IPv6/domain name address type
                    if (decDataLen < 7 || outDataBuffer[0] != 1)
                    {
                        return;
                    }

                    var headerLen = Destination.Destination.TryParseSocks5StyleAddress(outDataBuffer.AsSpan(0, (int)decDataLen), out _, TransportProtocol.Udp);
                    if (headerLen <= 0)
                    {
                        return;
                    }
                    localAdapter.WritePacketToLocal(outDataBuffer.AsSpan(headerLen, (int)decDataLen - headerLen), cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                }
            }

            udpReceivedHandler = packetHandler;
            cancellationToken.Register(() =>
            {
                tcs.TrySetCanceled();
                var socket = udpClient;
                if (socket != null)
                {
                    socket.MessageReceived -= packetHandler;
                }
            });
            return(tcs.Task);
        }
Example #3
0
        public async ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            if (allowInsecure)
            {
                socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
                socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.WrongUsage);
                socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);
                socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
                socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
            }
            var dev         = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter;
            var connectTask = socket.ConnectAsync(server, port, SocketProtectionLevel.Tls12, dev).AsTask(cancellationToken).ConfigureAwait(false);
            // TODO: custom certificate, server name

            var destination    = localAdapter.Destination;
            var firstBuf       = Array.Empty <byte>();
            var firstBufCancel = new CancellationTokenSource(500);

            try
            {
                if (await outboundChan.WaitToReadAsync(firstBufCancel.Token).ConfigureAwait(false))
                {
                    outboundChan.TryRead(out firstBuf);
                }
            }
            catch (OperationCanceledException) { }
            finally
            {
                firstBufCancel.Dispose();
            }
            int firstBufLen = firstBuf.Length;

            byte[] requestPayload = sendArrayPool.Rent(destination.Host.Size + firstBufLen + 65);
            try
            {
                var headerLen = FillTrojanRequest(requestPayload, destination);
                firstBuf.CopyTo(requestPayload.AsSpan(headerLen));

                await connectTask;
                inputStream  = socket.InputStream;
                outputStream = socket.OutputStream;
                _            = outputStream.WriteAsync(requestPayload.AsBuffer(0, firstBuf.Length + headerLen)).AsTask(cancellationToken);
            }
            finally
            {
                sendArrayPool.Return(requestPayload);
            }
        }
Example #4
0
        public async override ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            this.localAdapter = localAdapter;

            var greeting = await outboundChan.ReadAsync().ConfigureAwait(false);

            if (greeting.Length < 3 || greeting[0] != 5 || greeting[2] != 0)
            {
                throw BadGreetingException;
            }
            await WritePacketToLocal(ServerChoicePayload);

            var request = await outboundChan.ReadAsync().ConfigureAwait(false);

            Destination = ParseDestinationFromRequest(request);
            if (Destination.TransportProtocol == TransportProtocol.Udp)
            {
                throw UnknownTypeException;
            }
            await WritePacketToLocal(DummyResponsePayload);

            await base.Init(outboundChan, localAdapter, cancellationToken).ConfigureAwait(false);
        }
Example #5
0
        public async ValueTask Init(ChannelReader <byte[]> channel, ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            var dev  = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter;
            var port = localAdapter.Destination.Port;

            switch (localAdapter.Destination.TransportProtocol)
            {
            case Destination.TransportProtocol.Tcp:
                streamSocket = new StreamSocket();
                await streamSocket.ConnectAsync((HostName)localAdapter.Destination, port.ToString(), SocketProtectionLevel.PlainSocket, dev).AsTask(cancellationToken).ConfigureAwait(false);

                break;

            case Destination.TransportProtocol.Udp:
                datagramSocket = new DatagramSocket();
                datagramSocket.MessageReceived += DatagramSocket_MessageReceived;
                await datagramSocket.BindServiceNameAsync(string.Empty, dev).AsTask(cancellationToken).ConfigureAwait(false);

                await datagramSocket.ConnectAsync((HostName)localAdapter.Destination, port.ToString()).AsTask(cancellationToken).ConfigureAwait(false);

                break;
            }
        }
        public async ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            var          destination = localAdapter.Destination;
            IAsyncAction connectTask;
            var          dev = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter;

            switch (destination.TransportProtocol)
            {
            case TransportProtocol.Tcp:
                client = new StreamSocket();
                client.Control.NoDelay = true;
                connectTask            = client.ConnectAsync(new HostName(server), serviceName, SocketProtectionLevel.PlainSocket, dev);
                tcpInputStream         = client.InputStream;
                break;

            case TransportProtocol.Udp:
                cryptor = null;
                // Shadowsocks does not require a handshake for UDP transport
                udpClient = new DatagramSocket();
                // MessageReceived must be subscribed at this point
                udpClient.MessageReceived += UdpClient_MessageReceived;
                await udpClient.BindServiceNameAsync(string.Empty, dev).AsTask(cancellationToken).ConfigureAwait(false);

                udpOutputStream = await udpClient.GetOutputStreamAsync(new HostName(server), serviceName).AsTask(cancellationToken).ConfigureAwait(false);

                return;

            default:
                throw new NotImplementedException("Unknown transport protocol");
            }

            byte[] firstBuf       = Array.Empty <byte>();
            var    firstBufCancel = new CancellationTokenSource(500);

            try
            {
                if (await outboundChan.WaitToReadAsync(firstBufCancel.Token).ConfigureAwait(false))
                {
                    outboundChan.TryRead(out firstBuf);
                }
            }
            catch (OperationCanceledException) { }
            finally
            {
                firstBufCancel.Dispose();
            }
            int firstBufLen       = firstBuf.Length;
            int requestPayloadLen = firstBufLen + destination.Host.Size + 4;
            // Later will be reused to store dec iv
            var requestPayload = sendArrayPool.Rent(Math.Max(requestPayloadLen, (int)cryptor.IvLen));
            var headerLen      = destination.FillSocks5StyleAddress(requestPayload);

            firstBuf.CopyTo(requestPayload.AsSpan(headerLen));
            var encryptedFirstSeg    = sendArrayPool.Rent(requestPayloadLen + 66);       // Reserve space for IV or salt + 2 * tag + size
            var ivLen                = Encrypt(Array.Empty <byte>(), encryptedFirstSeg); // Fill IV/salt first
            var encryptedFirstSegLen = ivLen + Encrypt(requestPayload.AsSpan(0, headerLen + firstBufLen), encryptedFirstSeg.AsSpan((int)ivLen));

            try
            {
                await connectTask.AsTask(cancellationToken).ConfigureAwait(false);
            }
            catch (Exception)
            {
                sendArrayPool.Return(requestPayload);
                sendArrayPool.Return(encryptedFirstSeg, true);
                throw;
            }
            try
            {
                // Recv iv first, then GetRecvBufSizeHint will not bother with iv stuff
                receiveIvTask = ReceiveIv(requestPayload, cancellationToken);
                _             = client.OutputStream.WriteAsync(encryptedFirstSeg.AsBuffer(0, (int)encryptedFirstSegLen)).AsTask(cancellationToken);
            }
            finally
            {
                sendArrayPool.Return(encryptedFirstSeg, true);
            }
        }
Example #7
0
        public async Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            const int RECV_BUFFER_LEN = 2048;

            byte[] buf = new byte[RECV_BUFFER_LEN];
            var    stream = inputStream.AsStreamForRead();
            int    offset = 0, unconsumedLen = 0;

            while (!cancellationToken.IsCancellationRequested)
            {
                int parseResult = Destination.Destination.TryParseSocks5StyleAddress(buf.AsSpan(offset, unconsumedLen), out _, TransportProtocol.Udp);
                unconsumedLen -= parseResult;
                while (parseResult == 0 || unconsumedLen < 4) // Need more data as address header + len + crlf
                {
                    var readLen = await stream.ReadAsync(buf, offset, RECV_BUFFER_LEN - offset).ConfigureAwait(false);

                    offset        += readLen;
                    unconsumedLen += readLen;
                    if (readLen == 0)
                    {
                        goto END;
                    }
                    if (parseResult == 0)
                    {
                        parseResult    = Destination.Destination.TryParseSocks5StyleAddress(buf.AsSpan(0, unconsumedLen), out _, TransportProtocol.Udp);
                        unconsumedLen -= parseResult;
                    }
                }

                // buf now contains a valid address header, check payload length and CRLF
                ushort len = (ushort)(buf[parseResult] << 8 | buf[parseResult + 1]);
                if (buf[parseResult + 2] != 0x0D || buf[parseResult + 3] != 0x0A)
                {
                    if (DebugLogger.LogNeeded())
                    {
                        DebugLogger.Log("Received a malformed Trojan UDP response");
                    }
                    break;
                }
                unconsumedLen -= 4;
                while (unconsumedLen < len)
                {
                    var readLen = await stream.ReadAsync(buf, offset, RECV_BUFFER_LEN - offset).ConfigureAwait(false);

                    offset        += readLen;
                    unconsumedLen += readLen;
                    if (readLen == 0)
                    {
                        goto END;
                    }
                }
                await localAdapter.WritePacketToLocal(buf.AsSpan(offset - len, len), cancellationToken).ConfigureAwait(false);

                unconsumedLen -= len;
                if (unconsumedLen > 0)
                {
                    Array.Copy(buf, parseResult + len, buf, 0, unconsumedLen);
                }
                offset = unconsumedLen;
            }
END:
            ;
        }
Example #8
0
        public unsafe override Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            var outDataBuffer = new byte[sendBufferLen + 66];
            var tcs           = new TaskCompletionSource <object>();

            void packetHandler(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs e)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    var cryptor = ShadowsocksFactory.GlobalCryptorFactory.CreateCryptor();
                    var buffer  = e.GetDataReader().DetachBuffer();
                    var ptr     = ((IBufferByteAccess)buffer).GetBuffer();
                    var ivLen   = (int)cryptor.IvLen;
                    if (buffer.Length < ivLen + TAG_SIZE + 7)
                    {
                        return;
                    }

                    int decDataLen;
                    try
                    {
                        decDataLen = Decrypt(
                            new ReadOnlySpan <byte>(ptr.ToPointer(), (int)(buffer.Length - TAG_SIZE)),
                            new ReadOnlySpan <byte>((void *)(ptr.ToInt64() + buffer.Length - TAG_SIZE), TAG_SIZE),
                            outDataBuffer, cryptor);
                    }
                    catch (AeadOperationException ex)
                    {
                        if (DebugLogger.LogNeeded())
                        {
                            DebugLogger.Log($"Error decrypting a UDP packet from {localAdapter.Destination}: {ex}");
                        }
                        throw;
                    }
                    // TODO: support IPv6/domain name address type
                    if (decDataLen < 7 || outDataBuffer[0] != 1)
                    {
                        return;
                    }

                    var headerLen = Destination.Destination.TryParseSocks5StyleAddress(outDataBuffer.AsSpan(0, decDataLen), out _, TransportProtocol.Udp);
                    if (headerLen <= 0)
                    {
                        return;
                    }
                    localAdapter.WritePacketToLocal(outDataBuffer.AsSpan(headerLen, decDataLen - headerLen), cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                }
            }

            udpReceivedHandler = packetHandler;
            cancellationToken.Register(() =>
            {
                tcs.TrySetCanceled();
                var socket = udpClient;
                if (socket != null)
                {
                    socket.MessageReceived -= packetHandler;
                }
            });
            return(tcs.Task);
        }
Example #9
0
        public async ValueTask Init(ChannelReader <byte[]> outboundChan, ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
        {
            if (localAdapter.Destination.TransportProtocol == TransportProtocol.Udp)
            {
                throw UdpNotSupportedException;
            }
            var dev         = NetworkInformation.GetInternetConnectionProfile().NetworkAdapter;
            var connectTask = socket.ConnectAsync(new HostName(server), port.ToString(), SocketProtectionLevel.PlainSocket, dev).AsTask(cancellationToken).ConfigureAwait(false);

            var destination    = localAdapter.Destination;
            var dstPort        = destination.Port;
            var dstPortStrSize = CountDigit(dstPort);
            var dstHostStrSize = destination.Host.Size;
            int headerLen      = HEADER1.Length + dstHostStrSize + 1 + dstPortStrSize + HEADER2.Length;
            var firstSeg       = sendArrayPool.Rent(headerLen);

            try
            {
                HEADER1.CopyTo(firstSeg, 0);
                destination.Host.CopyTo(firstSeg.AsSpan(HEADER1.Length));
                firstSeg[HEADER1.Length + dstHostStrSize] = (byte)':';
                while (dstPortStrSize-- > 0)
                {
                    firstSeg[HEADER1.Length + dstHostStrSize + 1 + dstPortStrSize] = (byte)(dstPort % 10 + '0');
                    dstPort /= 10;
                }
                HEADER2.CopyTo(firstSeg, headerLen - HEADER2.Length);

                // Connect and perform handshake
                await connectTask;
                inputStream  = socket.InputStream;
                outputStream = socket.OutputStream;
                await outputStream.WriteAsync(firstSeg.AsBuffer(0, headerLen)).AsTask(cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                sendArrayPool.Return(firstSeg);
            }
            var responseBuf = sendArrayPool.Rent(HEAD_BUFFER_LEN);

            try
            {
                var resBuf = await inputStream.ReadAsync(responseBuf.AsBuffer(), HEAD_BUFFER_LEN, InputStreamOptions.Partial).AsTask(cancellationToken).ConfigureAwait(false);

                uint responseLen = resBuf.Length;
                if (responseLen < 14)
                {
                    throw new InvalidOperationException("Remote response too short");
                }
                if ((responseBuf[9] == (byte)'2') && (responseBuf[10] == (byte)'0') && (responseBuf[11] == (byte)'0'))
                {
                    // 200 objk
                }
                else
                {
                    var code = 100 * (responseBuf[9] - '0') + 10 * (responseBuf[10] - '0') + responseBuf[11] - '0';
                    throw new InvalidOperationException("Remote status code: " + code.ToString());
                }
                bool foundHeader = false;
                for (int headerStart = 12; headerStart < responseLen - 3; headerStart++)
                {
                    if (responseBuf[headerStart] == '\r')
                    {
                        if (responseBuf[headerStart + 1] == '\n')
                        {
                            if (responseBuf[headerStart + 2] == '\r')
                            {
                                if (responseBuf[headerStart + 3] == '\n')
                                {
                                    foundHeader = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                if (!foundHeader)
                {
                    throw new InvalidOperationException("Unrecognized remote header: " + Encoding.UTF8.GetString(responseBuf, 0, (int)responseLen));
                }
            }
            finally
            {
                sendArrayPool.Return(responseBuf);
            }
            // Initial data?
        }
Example #10
0
 public Task StartRecvPacket(ILocalAdapter localAdapter, CancellationToken cancellationToken = default)
 {
     return(Task.CompletedTask);
 }