Esempio n. 1
0
        private async Task <RfbProtocolVersion> NegotiateProtocolVersionAsync(ITransport transport, CancellationToken cancellationToken = default)
        {
            // Read maximum supported server protocol version
            RfbProtocolVersion serverProtocolVersion = await ReadProtocolVersionAsync(transport, cancellationToken).ConfigureAwait(false);

            // Select used protocol version
            RfbProtocolVersion clientProtocolVersion;

            if (serverProtocolVersion == RfbProtocolVersion.Unknown)
            {
                clientProtocolVersion = RfbProtocolVersions.LatestSupported;
                _logger.LogDebug("Supported server protocol version is unknown, too new? Trying latest protocol version {clientProtocolVersion}.",
                                 clientProtocolVersion.ToReadableString());
            }
            else if (serverProtocolVersion > RfbProtocolVersions.LatestSupported)
            {
                clientProtocolVersion = RfbProtocolVersions.LatestSupported;
                _logger.LogDebug("Supported server protocol version {serverProtocolVersion} is too new. Requesting latest version supported by the client.",
                                 serverProtocolVersion.ToReadableString());
            }
            else
            {
                clientProtocolVersion = serverProtocolVersion;
                _logger.LogDebug("Server supports protocol version {serverProtocolVersion}. Choosing that as the highest one that's supported by both sides.",
                                 serverProtocolVersion.ToReadableString());
            }

            // Send selected protocol version
            await SendProtocolVersionAsync(transport, clientProtocolVersion, cancellationToken).ConfigureAwait(false);

            return(clientProtocolVersion);
        }
Esempio n. 2
0
        /// <inheritdoc />
        public async Task <ITransport?> DoHandshakeAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            _logger.LogDebug("Doing protocol handshake...");

            ITransport currentTransport = _context.Transport ?? throw new InvalidOperationException("Cannot do handshake before a transport has been created.");

            // Negotiate the protocol version that both sides will use
            RfbProtocolVersion protocolVersion = await NegotiateProtocolVersionAsync(currentTransport, cancellationToken).ConfigureAwait(false);

            _state.ProtocolVersion = protocolVersion;

            // Negotiate which security type will be used
            ISecurityType usedSecurityType = await NegotiateSecurityTypeAsync(currentTransport, cancellationToken).ConfigureAwait(false);

            _state.UsedSecurityType = usedSecurityType;

            // Execute authentication
            _logger.LogDebug("Negotiated security type: {name}({id}). Authenticating...", usedSecurityType.Name, usedSecurityType.Id);
            AuthenticationResult authenticationResult = await usedSecurityType
                                                        .AuthenticateAsync(_context.Connection.Parameters.AuthenticationHandler, cancellationToken).ConfigureAwait(false);

            // When a tunnel was built, use that transport for further communication
            if (authenticationResult.TunnelTransport != null)
            {
                currentTransport = authenticationResult.TunnelTransport;
            }

            if (authenticationResult.ExpectSecurityResult)
            {
                // Read the security result
                ReadOnlyMemory <byte> securityResultBytes = await currentTransport.Stream.ReadAllAsync(4, cancellationToken).ConfigureAwait(false);

                uint securityResult = BinaryPrimitives.ReadUInt32BigEndian(securityResultBytes.Span);

                // Authentication failed?
                if (securityResult > 0)
                {
                    // From version 3.8 onwards the server sends a reason
                    if (protocolVersion >= RfbProtocolVersion.RFB_3_8)
                    {
                        string reason = await ReadFailureReasonAsync(currentTransport, cancellationToken).ConfigureAwait(false);

                        throw new HandshakeFailedException($"Authentication failed: {reason}");
                    }

                    // There is no reason
                    throw new HandshakeFailedException("Authentication failed" + (securityResult == 2 ? " because of too many attempts." : "."));
                }
            }

            return(authenticationResult.TunnelTransport);
        }
Esempio n. 3
0
        private async Task SendProtocolVersionAsync(ITransport transport, RfbProtocolVersion protocolVersion, CancellationToken cancellationToken = default)
        {
            _logger.LogDebug("Sending protocol version {protocolVersion}...", protocolVersion.ToReadableString());

            string protocolVersionString = protocolVersion.GetStringRepresentation() + '\n';

            byte[] bytes = Encoding.ASCII.GetBytes(protocolVersionString);
            Debug.Assert(bytes.Length == 12, "bytes.Length == 12");

            await transport.Stream.WriteAsync(bytes, cancellationToken).ConfigureAwait(false);
        }
Esempio n. 4
0
        private async Task <RfbProtocolVersion> ReadProtocolVersionAsync(ITransport transport, CancellationToken cancellationToken = default)
        {
            _logger.LogDebug("Reading protocol version...");

            // The protocol version info always consists of 12 bytes
            ReadOnlyMemory <byte> bytes = await transport.Stream.ReadAllAsync(12, cancellationToken).ConfigureAwait(false);

            string protocolVersionString = Encoding.ASCII.GetString(bytes.Span).TrimEnd('\n');

            RfbProtocolVersion protocolVersion = RfbProtocolVersions.GetFromStringRepresentation(protocolVersionString);

            if (protocolVersion == RfbProtocolVersion.Unknown)
            {
                _logger.LogWarning("Unknown protocol version {protocolVersionString}.", protocolVersionString);
            }

            return(protocolVersion);
        }
 /// <summary>
 /// Sets the value of the <seealso cref="RfbConnection.ProtocolVersion"/> property on the <see cref="RfbConnection"/> object.
 /// </summary>
 /// <param name="protocolVersion">The new protocol version value.</param>
 public void SetProtocolVersion(RfbProtocolVersion protocolVersion) => _connection.ProtocolVersion = protocolVersion;
Esempio n. 6
0
 /// <summary>
 /// Returns the string representation of a given protocol version.
 /// </summary>
 /// <param name="protocolVersion">The protocol version.</param>
 /// <returns>The string representation defined by the protocol.</returns>
 public static string GetStringRepresentation(this RfbProtocolVersion protocolVersion)
 => protocolVersion switch
 {