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 } }
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; }
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(); }
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 } }
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(); } }
/// <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; } }