public void NegotiateSecurityIncorrectPasswordTest()
        {
            using (var stream = new TestStream())
            {
                // Have the client send authentication method 'Password', which is what the server expects
                VncStream clientStream = new VncStream(stream.Input);
                clientStream.SendByte((byte)AuthenticationMethod.Password);
                clientStream.Send(new byte[16]); // An empty response
                stream.Input.Position = 0;

                var session = new VncServerSession();
                session.Connect(stream, null, startThread: false);

                Assert.False(session.NegotiateSecurity(new AuthenticationMethod[] { AuthenticationMethod.Password }));

                VncStream serverStream = new VncStream(stream.Output);
                stream.Output.Position = 0;

                // Server will have offered 1 authentication method, and failed to authenticate
                // the client
                Assert.Equal(1, serverStream.ReceiveByte());                                   // 1 authentication method offered
                Assert.Equal((byte)AuthenticationMethod.Password, serverStream.ReceiveByte()); // The authentication method offered
                Assert.NotEqual(0u, serverStream.ReceiveUInt32BE());                           // Challenge, part 1
                Assert.NotEqual(0u, serverStream.ReceiveUInt32BE());                           // Challenge, part 2
                Assert.NotEqual(0u, serverStream.ReceiveUInt32BE());                           // Challenge, part 3
                Assert.NotEqual(0u, serverStream.ReceiveUInt32BE());                           // Challenge, part 4
                Assert.Equal(1u, serverStream.ReceiveUInt32BE());                              // Authentication failed
                Assert.Equal("Failed to authenticate", serverStream.ReceiveString());          // Error message

                Assert.Equal(stream.Output.Length, stream.Output.Position);
                Assert.Equal(stream.Input.Length, stream.Input.Position);
            }
        }
        void NegotiateDesktop()
        {
            byte shareDesktopSetting = _c.ReceiveByte();//是否同意分享屏幕
            bool shareDesktop        = shareDesktopSetting != 0;

            var e = new CreatingDesktopEventArgs(shareDesktop);

            OnCreatingDesktop(e);

            var fbSource = _fbSource;

            Framebuffer = fbSource != null?fbSource.Capture() : null;

            VncStream.Require(Framebuffer != null,
                              "No framebuffer. Make sure you've called SetFramebufferSource. It can be set to a VncFramebuffer.",
                              VncFailureReason.SanityCheckFailed);
            _clientPixelFormat = Framebuffer.PixelFormat;
            _clientWidth       = Framebuffer.Width; _clientHeight = Framebuffer.Height;
            _fbuAutoCache      = null;

            _c.SendUInt16BE((ushort)Framebuffer.Width);
            _c.SendUInt16BE((ushort)Framebuffer.Height);
            var pixelFormat = new byte[VncPixelFormat.Size];

            Framebuffer.PixelFormat.Encode(pixelFormat, 0);
            _c.Send(pixelFormat);
            _c.SendString(Framebuffer.Name, true);
        }
        public void HandleSetEncodingsTest(bool forceConnect, VncEncoding expectedEncoding)
        {
            using (var stream = new TestStream())
            {
                // Have the client send a list of supported encodings, including
                // Raw and zlib
                VncStream clientStream = new VncStream(stream.Input);
                clientStream.SendByte(0);
                clientStream.SendUInt16BE(2); // 2 encodings are supported
                clientStream.SendUInt32BE((uint)VncEncoding.Raw);
                clientStream.SendUInt32BE((uint)VncEncoding.Zlib);
                stream.Input.Position = 0;

                var session = new VncServerSession();
                session.Connect(stream, null, startThread: false, forceConnected: forceConnect);

                session.HandleSetEncodings();

                // The server should not have written any output, but switched
                // to zlib encoding
                VncStream serverStream = new VncStream(stream.Output);
                Assert.Equal(0, serverStream.Stream.Length);
                stream.Output.Position = 0;

                Assert.Equal(expectedEncoding, session.Encoder.Encoding);
            }
        }
        public void NegotiateSecurityInvalidMethodTest()
        {
            using (var stream = new TestStream())
            {
                // Have the client send authentication method 'None', while we only accept 'Password'
                VncStream clientStream = new VncStream(stream.Input);
                clientStream.SendByte((byte)AuthenticationMethod.None);
                stream.Input.Position = 0;

                var session = new VncServerSession();
                session.Connect(stream, null, startThread: false);

                Assert.False(session.NegotiateSecurity(new AuthenticationMethod[] { AuthenticationMethod.Password }));

                VncStream serverStream = new VncStream(stream.Output);
                stream.Output.Position = 0;

                // Server will have offered 1 authentication method, and disconnected when the client
                // accepted an invalid authentication method.
                Assert.Equal(1, serverStream.ReceiveByte());                                   // 1 authentication method offered
                Assert.Equal((byte)AuthenticationMethod.Password, serverStream.ReceiveByte()); // The authentication method offered
                Assert.Equal(1u, serverStream.ReceiveUInt32BE());                              // authentication failed
                Assert.Equal("Invalid authentication method.", serverStream.ReceiveString());  // error message
            }
        }
Exemple #5
0
        private void NegotiateDesktop()
        {
            this.logger?.Log(LogLevel.Info, () => "Negotiating desktop settings");

            byte shareDesktopSetting = this.c.ReceiveByte();
            bool shareDesktop        = shareDesktopSetting != 0;

            var e = new CreatingDesktopEventArgs(shareDesktop);

            this.OnCreatingDesktop(e);

            var fbSource = this.fbSource;

            this.Framebuffer = fbSource != null?fbSource.Capture() : null;

            VncStream.Require(
                this.Framebuffer != null,
                "No framebuffer. Make sure you've called SetFramebufferSource. It can be set to a VncFramebuffer.",
                VncFailureReason.SanityCheckFailed);
            this.clientPixelFormat = this.Framebuffer.PixelFormat;
            this.clientWidth       = this.Framebuffer.Width;
            this.clientHeight      = this.Framebuffer.Height;
            this.fbuAutoCache      = null;

            this.c.SendUInt16BE((ushort)this.Framebuffer.Width);
            this.c.SendUInt16BE((ushort)this.Framebuffer.Height);
            var pixelFormat = new byte[VncPixelFormat.Size];

            this.Framebuffer.PixelFormat.Encode(pixelFormat, 0);
            this.c.Send(pixelFormat);
            this.c.SendString(this.Framebuffer.Name, true);

            this.logger?.Log(LogLevel.Info, () => $"The desktop {this.Framebuffer.Name} has initialized with pixel format {this.clientPixelFormat}; the screen size is {this.clientWidth}x{this.clientHeight}");
        }
        void HandleSetEncodings()
        {
            _c.Receive(1);

            int encodingCount  = _c.ReceiveUInt16BE(); VncStream.SanityCheck(encodingCount <= 0x1ff);
            var clientEncoding = new VncEncoding[encodingCount];

            for (int i = 0; i < clientEncoding.Length; i++)
            {
                uint encoding = _c.ReceiveUInt32BE();
                clientEncoding[i] = (VncEncoding)encoding;
            }
            _clientEncoding = clientEncoding;
        }
Exemple #7
0
        private void NegotiateSecurity(AuthenticationMethod[] methods)
        {
            this.logger?.Log(LogLevel.Info, () => "Negotiating security");

            this.c.SendByte((byte)methods.Length);
            VncStream.Require(
                methods.Length > 0,
                "Client is not allowed in.",
                VncFailureReason.NoSupportedAuthenticationMethods);
            foreach (var method in methods)
            {
                this.c.SendByte((byte)method);
            }

            var selectedMethod = (AuthenticationMethod)this.c.ReceiveByte();

            VncStream.Require(
                methods.Contains(selectedMethod),
                "Invalid authentication method.",
                VncFailureReason.UnrecognizedProtocolElement);

            bool success = true;

            if (selectedMethod == AuthenticationMethod.Password)
            {
                var challenge = this.passwordChallenge.GenerateChallenge();
                using (new Utility.AutoClear(challenge))
                {
                    this.c.Send(challenge);

                    var response = this.c.Receive(16);
                    using (new Utility.AutoClear(response))
                    {
                        var e = new PasswordProvidedEventArgs(this.passwordChallenge, challenge, response);
                        this.OnPasswordProvided(e);
                        success = e.IsAuthenticated;
                    }
                }
            }

            this.c.SendUInt32BE(success ? 0 : (uint)1);
            VncStream.Require(
                success,
                "Failed to authenticate.",
                VncFailureReason.AuthenticationFailed);

            this.logger?.Log(LogLevel.Info, () => "The user authenticated successfully.");
            this.securityNegotiated = true;
        }
        void NegotiateSecurity(AuthenticationMethod[] methods)
        {
            _c.SendByte((byte)methods.Length);
            //验证密码
            VncStream.Require(methods.Length > 0,
                              "Client is not allowed in.",
                              VncFailureReason.NoSupportedAuthenticationMethods);
            foreach (var method in methods)
            {
                _c.SendByte((byte)method);
            }

            var selectedMethod = (AuthenticationMethod)_c.ReceiveByte();

            VncStream.Require(methods.Contains(selectedMethod),
                              "Invalid authentication method.",
                              VncFailureReason.UnrecognizedProtocolElement);

            bool success = true;

            if (selectedMethod == AuthenticationMethod.Password)
            {
                var challenge = VncPasswordChallenge.GenerateChallenge();
                using (new Utility.AutoClear(challenge))
                {
                    _c.Send(challenge);

                    var response = _c.Receive(16);
                    using (new Utility.AutoClear(response))
                    {
                        var e = new PasswordProvidedEventArgs(challenge, response);
                        OnPasswordProvided(e);
                        success = e.IsAuthenticated;
                    }
                }
            }

            _c.SendUInt32BE(success ? 0 : (uint)1);

            if (!success)
            {
                _c.SendString("Password authentication failed!", true);
            }

            VncStream.Require(success,
                              "Failed to authenticate.",
                              VncFailureReason.AuthenticationFailed);
        }
        public void NegotiateSecurityNoSecurityTypesTest()
        {
            using (var stream = new TestStream())
            {
                var session = new VncServerSession();
                session.Connect(stream, null, startThread: false);

                Assert.False(session.NegotiateSecurity(Array.Empty <AuthenticationMethod>()));

                VncStream serverStream = new VncStream(stream.Output);
                stream.Output.Position = 0;

                // Server should have sent a zero-length array, and a message explaining
                // the disconnect reason
                Assert.Equal(0, serverStream.ReceiveByte());
                Assert.Equal("The server and client could not agree on any authentication method.", serverStream.ReceiveString());
            }
        }
        public void NegotiateVersionNot38Test(string version)
        {
            using (var stream = new TestStream())
            {
                // Mimick the client negotiating RFB 3.8
                VncStream clientStream = new VncStream(stream.Input);
                clientStream.SendString(version);
                stream.Input.Position = 0;

                VncServerSession session = new VncServerSession();
                session.Connect(stream, null, startThread: false);

                Assert.True(session.NegotiateVersion(out AuthenticationMethod[] methods));
                Assert.Empty(methods);

                stream.Output.Position = 0;

                Assert.Equal(Encoding.UTF8.GetBytes("RFB 003.008\n"), ((MemoryStream)stream.Output).ToArray());
            }
        }
        internal void HandleSetEncodings()
        {
            this.c.Receive(1);

            int encodingCount = this.c.ReceiveUInt16BE();

            VncStream.SanityCheck(encodingCount <= 0x1ff);
            this.clientEncoding.Clear();

            this.logger?.Log(LogLevel.Info, () => "The client supports {0} encodings:", null, encodingCount);

            for (int i = 0; i < encodingCount; i++)
            {
                var encoding = (VncEncoding)this.c.ReceiveUInt32BE();
                this.clientEncoding.Add(encoding);

                this.logger?.Log(LogLevel.Info, () => "- {0}", null, encoding);
            }

            this.InitFramebufferEncoder();
        }
Exemple #12
0
        internal void HandleSetEncodings()
        {
            this.c.Receive(1);

            int encodingCount = this.c.ReceiveUInt16BE();

            VncStream.SanityCheck(encodingCount <= 0x1ff);
            this.clientEncoding.Clear();

            this.logger?.LogInformation($"The client supports {encodingCount} encodings:");

            for (int i = 0; i < encodingCount; i++)
            {
                var encoding = (VncEncoding)this.c.ReceiveUInt32BE();
                this.clientEncoding.Add(encoding);

                this.logger?.LogInformation($"- {encoding}");
            }

            this.InitFramebufferEncoder();
        }
        public void NegotiateVersionBoth38Test(VncServerSessionOptions sessionOptions, AuthenticationMethod expectedAuthenticationMethod)
        {
            using (var stream = new TestStream())
            {
                // Mimick the client negotiating RFB 3.8
                VncStream clientStream = new VncStream(stream.Input);
                clientStream.SendString("RFB 003.008\n");
                stream.Input.Position = 0;

                VncServerSession session = new VncServerSession();
                session.Connect(stream, sessionOptions, startThread: false);

                Assert.True(session.NegotiateVersion(out AuthenticationMethod[] methods));

                Assert.Collection(
                    methods,
                    (m) => Assert.Equal(expectedAuthenticationMethod, m));

                stream.Output.Position = 0;

                Assert.Equal(Encoding.UTF8.GetBytes("RFB 003.008\n"), ((MemoryStream)stream.Output).ToArray());
            }
        }
        public void GetChallengeResponseTest()
        {
            VncPasswordChallenge challenger = new VncPasswordChallenge();

            var challenge = new byte[]
            {
                0x71, 0x43, 0x19, 0xf2, 0xb3, 0xf6, 0xac, 0xcf,
                0x8c, 0x10, 0xc0, 0x06, 0x6e, 0x73, 0xb1, 0xd9
            };

            var password      = "******".ToCharArray();
            var passwordBytes = VncStream.EncodeString(password, 0, password.Length);
            var response      = new byte[16];

            challenger.GetChallengeResponse(challenge, passwordBytes, response);

            var expectedResponse = new byte[]
            {
                0x71, 0xb3, 0x6f, 0xa2, 0x44, 0x5a, 0xee, 0x4f,
                0x08, 0x70, 0x21, 0x69, 0x6e, 0x32, 0x87, 0x8e
            };

            Assert.Equal(expectedResponse, response);
        }
        public void NegotiateSecuritySuccessTest()
        {
            using (var stream = new TestStream())
            {
                // Have the client send authentication method 'None', which is what the server expects
                VncStream clientStream = new VncStream(stream.Input);
                clientStream.SendByte((byte)AuthenticationMethod.None);
                stream.Input.Position = 0;

                var session = new VncServerSession();
                session.Connect(stream, null, startThread: false);

                Assert.True(session.NegotiateSecurity(new AuthenticationMethod[] { AuthenticationMethod.None }));

                VncStream serverStream = new VncStream(stream.Output);
                stream.Output.Position = 0;

                // Server will have offered 1 authentication method, and successfully authenticated
                // the client
                Assert.Equal(1, serverStream.ReceiveByte());                               // 1 authentication method offered
                Assert.Equal((byte)AuthenticationMethod.None, serverStream.ReceiveByte()); // The authentication method offered
                Assert.Equal(0u, serverStream.ReceiveUInt32BE());                          // authentication succeeded
            }
        }
Exemple #16
0
        private void ThreadMain()
        {
            this.requester = new Utility.PeriodicThread();

            try
            {
                this.InitFramebufferEncoder();

                AuthenticationMethod[] methods;
                this.NegotiateVersion(out methods);
                this.NegotiateSecurity(methods);
                this.NegotiateDesktop();
                this.NegotiateEncodings();

                this.requester.Start(() => this.FramebufferSendChanges(), () => this.MaxUpdateRate, false);

                this.IsConnected = true;
                this.logger?.Log(LogLevel.Info, () => "The client has connected successfully");

                this.OnConnected();

                while (true)
                {
                    var command = (VncMessageType)this.c.ReceiveByte();

                    this.logger?.Log(LogLevel.Info, () => $"Received the {command} command.");

                    switch (command)
                    {
                    case VncMessageType.SetPixelFormat:
                        this.HandleSetPixelFormat();
                        break;

                    case VncMessageType.SetEncodings:
                        this.HandleSetEncodings();
                        break;

                    case VncMessageType.FrameBufferUpdateRequest:
                        this.HandleFramebufferUpdateRequest();
                        break;

                    case VncMessageType.KeyEvent:
                        this.HandleKeyEvent();
                        break;

                    case VncMessageType.PointerEvent:
                        this.HandlePointerEvent();
                        break;

                    case VncMessageType.ClientCutText:
                        this.HandleReceiveClipboardData();
                        break;

                    default:
                        VncStream.Require(
                            false,
                            "Unsupported command.",
                            VncFailureReason.UnrecognizedProtocolElement);

                        break;
                    }
                }
            }
            catch (Exception exception)
            {
                this.logger?.Log(LogLevel.Error, () => $"VNC server session stopped due to: {exception.Message}");
            }

            this.requester.Stop();

            this.c.Stream = null;
            if (this.IsConnected)
            {
                this.IsConnected = false;
                this.OnClosed();
            }
            else
            {
                this.OnConnectionFailed();
            }
        }
        public void SetDesktopSizeTest()
        {
            var framebuffer1 = new VncFramebuffer("test-1", 100, 200, VncPixelFormat.RGB32);
            var framebuffer2 = new VncFramebuffer("test-2", 200, 400, VncPixelFormat.RGB32);
            var framebuffer  = framebuffer1;

            var framebufferSourceMock = new Mock <IVncFramebufferSource>(MockBehavior.Strict);

            framebufferSourceMock
            .Setup(m => m.SetDesktopSize(200, 300))
            .Returns(ExtendedDesktopSizeStatus.Success)
            .Callback(() => { framebuffer = framebuffer2; });

            framebufferSourceMock
            .Setup(m => m.Capture())
            .Returns(() => framebuffer);

            using (var stream = new TestStream())
            {
                VncStream clientStream = new VncStream(stream.Input);

                // Negotiating the dessktop size
                clientStream.SendByte(0); // share desktop setting

                // Send a SetDesktopSize request
                clientStream.SendByte((byte)VncMessageType.SetDesktopSize);
                clientStream.SendByte(0);       // padding
                clientStream.SendUInt16BE(200); // width
                clientStream.SendUInt16BE(300); // height
                clientStream.SendByte(1);       // number of screens
                clientStream.SendByte(0);       // padding
                clientStream.SendUInt32BE(1);   // screen id
                clientStream.SendUInt16BE(0);   // x position
                clientStream.SendUInt16BE(0);   // x position
                clientStream.SendUInt16BE(200); // width
                clientStream.SendUInt16BE(300); // height
                clientStream.SendUInt32BE(0);   // flags

                stream.Input.Position = 0;

                var session = new VncServerSession();
                session.SetFramebufferSource(framebufferSourceMock.Object);
                session.Connect(stream, null, startThread: false);

                // Negotiate the desktop
                session.NegotiateDesktop();
                Assert.Equal(VncPixelFormat.RGB32, session.ClientPixelFormat);

                // Handle the SetDesktopSize request
                session.HandleMessage();

                VncStream serverStream = new VncStream(stream.Output);
                stream.Output.Position = 0;

                // Desktop negotiation result
                Assert.Equal(100, serverStream.ReceiveUInt16BE());
                Assert.Equal(200, serverStream.ReceiveUInt16BE());
                var format = serverStream.Receive(16);
                Assert.Equal("test-1", serverStream.ReceiveString());

                // SetDesktopSize result
                Assert.Equal(0, serverStream.ReceiveUInt16BE());                                         // Update rectangle request
                Assert.Equal(1, serverStream.ReceiveUInt16BE());                                         // 1 rectangle;

                Assert.Equal((ushort)ExtendedDesktopSizeReason.Client, serverStream.ReceiveUInt16BE());  // x
                Assert.Equal((ushort)ExtendedDesktopSizeStatus.Success, serverStream.ReceiveUInt16BE()); // y
                Assert.Equal(100, serverStream.ReceiveUInt16BE());                                       // width
                Assert.Equal(200, serverStream.ReceiveUInt16BE());                                       // height

                Assert.Equal((int)VncEncoding.ExtendedDesktopSize, (int)serverStream.ReceiveUInt32BE()); // encoding

                Assert.Equal(1u, serverStream.ReceiveByte());                                            // Number of screens
                serverStream.Receive(3);                                                                 // Padding
                Assert.Equal(0u, serverStream.ReceiveUInt32BE());                                        // screen ID
                Assert.Equal(0u, serverStream.ReceiveUInt16BE());                                        // x-position
                Assert.Equal(0u, serverStream.ReceiveUInt16BE());                                        // y-position
                Assert.Equal(100u, serverStream.ReceiveUInt16BE());                                      // width
                Assert.Equal(200u, serverStream.ReceiveUInt16BE());                                      // height
                Assert.Equal(0u, serverStream.ReceiveUInt32BE());                                        // flags

                Assert.Equal(stream.Output.Length, stream.Output.Position);
                Assert.Equal(stream.Input.Length, stream.Input.Position);
            }
        }
        void ThreadMain()
        {
            _requester = new Utility.PeriodicThread();

            try
            {
                InitFramebufferEncoder();

                AuthenticationMethod[] methods;
                NegotiateVersion(out methods);
                NegotiateSecurity(methods);
                NegotiateDesktop();//绘画的桌面
                NegotiateEncodings();

                _requester.Start(FramebufferSendChanges, () => MaxUpdateRate, false);

                IsConnected = true; OnConnected();

                while (true)
                {
                    var command = _c.ReceiveByte();

                    switch (command)
                    {
                    case 0:
                        HandleSetPixelFormat();
                        break;

                    case 2:
                        HandleSetEncodings();
                        break;

                    case 3:
                        HandleFramebufferUpdateRequest();
                        break;

                    case 4:
                        HandleKeyEvent();
                        break;

                    case 5:
                        HandlePointerEvent();
                        break;

                    case 6:
                        HandleReceiveClipboardData();
                        break;

                    default:
                        VncStream.Require(false, "Unsupported command.",
                                          VncFailureReason.UnrecognizedProtocolElement);
                        break;
                    }
                }
            }
            catch (ObjectDisposedException ex)
            {
            }
            catch (IOException ex)
            {
            }
            catch (VncException ex)
            {
                //Vnc错误
            }

            _requester.Stop();

            _c.Stream = null;
            if (IsConnected)
            {
                IsConnected = false; OnClosed();
            }
            else
            {
                OnConnectionFailed();
            }
        }
Exemple #19
0
        /// <summary>
        /// Reads the next client message and handles it.
        /// </summary>
        /// <remarks>
        /// The <see cref="VncServerSession"/> starts a main thread which read and processes messages.
        /// You don't normally need to call this method yourself; but it can be usefull when writing
        /// unit tests.
        /// </remarks>
        public void HandleMessage()
        {
            var command = (VncMessageType)this.c.ReceiveByte();

            // If the same command is sent repeatedly (e.g. FramebufferUpdateRequest), suppress repeated requests
            if (this.previousCommand != command || this.commandCount >= 25)
            {
                if (this.commandCount > 0)
                {
                    this.logger?.LogInformation($"Suppressed {this.commandCount} notifications of the {command} command at the Info level.");
                }

                this.logger?.LogInformation($"Received the {command} command.");
                this.commandCount = 0;
            }
            else
            {
                this.logger?.LogDebug($"Received the {command} command");
                this.commandCount++;
            }

            this.previousCommand = command;

            switch (command)
            {
            case VncMessageType.SetPixelFormat:
                this.HandleSetPixelFormat();
                break;

            case VncMessageType.SetEncodings:
                this.HandleSetEncodings();
                break;

            case VncMessageType.FrameBufferUpdateRequest:
                this.HandleFramebufferUpdateRequest();
                break;

            case VncMessageType.KeyEvent:
                this.HandleKeyEvent();
                break;

            case VncMessageType.PointerEvent:
                this.HandlePointerEvent();
                break;

            case VncMessageType.ClientCutText:
                this.HandleReceiveClipboardData();
                break;

            case VncMessageType.SetDesktopSize:
                this.HandleSetDesktopSize();
                break;

            default:
                VncStream.Require(
                    false,
                    "Unsupported command.",
                    VncFailureReason.UnrecognizedProtocolElement);

                break;
            }
        }