Exemple #1
0
        public async Task <IClusterNode> CreateAndConnectAsync(HostEndpoint endPoint, CancellationToken cancellationToken = default)
        {
            var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(endPoint.Host, endPoint.Port.GetValueOrDefault(), cancellationToken).ConfigureAwait(false);

            var clusterNode = new ClusterNode(_clusterContext, _connectionPoolFactory, _logger,
                                              _transcoder, _circuitBreaker, _saslMechanismFactory, _redactor, ipEndPoint)
            {
                BootstrapEndpoint = endPoint
            };

            //ensure server calls are made to set the state
            await clusterNode.InitializeAsync().ConfigureAwait(false);

            return(clusterNode);
        }
Exemple #2
0
        private async Task <IList <IPEndPoint> > GetIpEndPointsAsync(BucketConfig config, CancellationToken cancellationToken)
        {
            var ipEndPoints = new List <IPEndPoint>();

            foreach (var node in config.GetNodes().Where(p => p.IsKvNode))
            {
                var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(node, cancellationToken);

                if (ipEndPoint == null)
                {
                    throw new InvalidOperationException("IP endpoint lookup failed.");
                }

                ipEndPoints.Add(ipEndPoint);
            }

            return(ipEndPoints);
        }
        public async Task <IClusterNode> CreateAndConnectAsync(HostEndpoint endPoint, BucketType bucketType, NodeAdapter?nodeAdapter, CancellationToken cancellationToken = default)
        {
            var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(endPoint.Host, endPoint.Port.GetValueOrDefault(), cancellationToken).ConfigureAwait(false);

            //for recording k/v latencies per request
            var valueRecorder = _meter.ValueRecorder(OuterRequestSpans.ServiceSpan.Kv.Name);

            var clusterNode = new ClusterNode(_clusterContext, _connectionPoolFactory, _logger,
                                              _operationBuilderPool, _circuitBreaker, _saslMechanismFactory, _redactor, ipEndPoint, bucketType,
                                              nodeAdapter, _tracer, valueRecorder)
            {
                BootstrapEndpoint = endPoint
            };

            //ensure server calls are made to set the state
            await clusterNode.InitializeAsync().ConfigureAwait(false);

            return(clusterNode);
        }
Exemple #4
0
        private async Task <IList <IPEndPoint> > GetIpEndPointsAsync(BucketConfig config, CancellationToken cancellationToken)
        {
            var ipEndPoints = new List <IPEndPoint>();

            foreach (var node in config.GetNodes().Where(p => p.IsKvNode))
            {
                //log any alternate address mapping
                _logger.LogInformation(node.ToString());

                var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(node, cancellationToken).ConfigureAwait(false);

                if (ipEndPoint == null)
                {
                    throw new InvalidOperationException("IP endpoint lookup failed.");
                }

                ipEndPoints.Add(ipEndPoint);
            }

            return(ipEndPoints);
        }
Exemple #5
0
        private async IAsyncEnumerable <IPEndPoint> GetIpEndPointsAsync(IEnumerable <string> serverList,
                                                                        [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            foreach (var server in serverList)
            {
                var(hostName, port) = HostEndpoint.Parse(server);
                if (port == null)
                {
                    // Should not happen with data from BucketConfig
                    ThrowHelper.ThrowInvalidOperationException("Server list is missing port numbers.");
                }

                var ipEndPoint = await _ipEndPointService.GetIpEndPointAsync(hostName, port.Value, cancellationToken)
                                 .ConfigureAwait(false);

                if (ipEndPoint == null)
                {
                    ThrowHelper.ThrowArgumentException($"Unable to resolve '{server}'.", nameof(serverList));
                }

                yield return(ipEndPoint);
            }
        }
Exemple #6
0
        public async Task <IConnection> CreateAndConnectAsync(HostEndpointWithPort hostEndpoint,
                                                              CancellationToken cancellationToken = default)
        {
            if (_clusterOptions.IsCapella && !_clusterOptions.EffectiveEnableTls)
            {
                _multiplexLogger.LogWarning("TLS is required when connecting to Couchbase Capella. Please enable TLS by prefixing the connection string with \"couchbases://\" (note the final 's').");
            }

            var endPoint = await _ipEndPointService.GetIpEndPointAsync(hostEndpoint.Host, hostEndpoint.Port, cancellationToken)
                           .ConfigureAwait(false);

            if (endPoint is null)
            {
                throw new ConnectException($"Unable to resolve host '{hostEndpoint}'.");
            }

            var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                var connectTask = socket.ConnectAsync(endPoint);

                var whichTask = await Task
                                .WhenAny(connectTask, Task.Delay(_clusterOptions.KvConnectTimeout, cancellationToken))
                                .ConfigureAwait(false);

                if (whichTask != connectTask)
                {
                    // Was a timeout
                    const int connectionTimedOut = 10060;
                    throw new SocketException(connectionTimedOut);
                }
            }
            catch
            {
                socket.Dispose();
                throw;
            }

#if NETCOREAPP3_0_OR_GREATER
            _multiplexLogger.LogDebug("Setting TCP Keep-Alives using SocketOptions - enable keep-alives {EnableTcpKeepAlives}, time {TcpKeepAliveTime}, interval {TcpKeepAliveInterval}.",
                                      _clusterOptions.EnableTcpKeepAlives, _clusterOptions.TcpKeepAliveTime, _clusterOptions.TcpKeepAliveInterval);

            if (!socket.TryEnableKeepAlives(_clusterOptions.EnableTcpKeepAlives,
                                            (int)_clusterOptions.TcpKeepAliveTime.TotalSeconds,
                                            (int)_clusterOptions.TcpKeepAliveInterval.TotalSeconds, out string setKeepAliveMessage)
                )
            {
                _multiplexLogger.LogWarning(setKeepAliveMessage);
            }
#else
            _multiplexLogger.LogDebug(
                "Setting TCP Keep-Alives using Socket.IOControl on {endpoint} - enable tcp keep-alives {EnableTcpKeepAlives}, time {TcpKeepAliveTime}, interval {TcpKeepAliveInterval}",
                endPoint, _clusterOptions.EnableTcpKeepAlives, _clusterOptions.TcpKeepAliveTime,
                _clusterOptions.TcpKeepAliveInterval);

            if (!socket.TrySetKeepAlives(_clusterOptions.EnableTcpKeepAlives,
                                         (uint)_clusterOptions.TcpKeepAliveTime.TotalMilliseconds,
                                         (uint)_clusterOptions.TcpKeepAliveInterval.TotalMilliseconds, out var setKeepAliveMessage)
                )
            {
                _multiplexLogger.LogWarning(setKeepAliveMessage);
            }
#endif

            if (_clusterOptions.EffectiveEnableTls)
            {
                //Check if were using x509 auth, if so fetch the certificates
                X509Certificate2Collection?certs = null;
                if (_clusterOptions.X509CertificateFactory != null)
                {
                    certs = _clusterOptions.X509CertificateFactory.GetCertificates();
                    if (certs == null || certs.Count == 0)
                    {
                        throw new AuthenticationException(
                                  "No certificates matching the X509FindType and specified FindValue were found in the Certificate Store.");
                    }

                    if (_sslLogger.IsEnabled(LogLevel.Debug))
                    {
                        foreach (var cert in certs)
                        {
                            _sslLogger.LogDebug("Cert sent {cert.FriendlyName} - Thumbprint {cert.Thumbprint}",
                                                cert.FriendlyName, cert.Thumbprint);
                        }

                        _sslLogger.LogDebug("Sending {certs.Count} certificates to the server.", certs.Count);
                    }
                }

                //The endpoint we are connecting to
                var targetHost = _clusterOptions.ForceIpAsTargetHost
                    ? endPoint.Address.ToString()
                    : hostEndpoint.Host;

                //create the sslstream with appropriate authentication
                RemoteCertificateValidationCallback?certValidationCallback = _clusterOptions.KvCertificateCallbackValidation;
                if (certValidationCallback == null)
                {
                    certValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
                    {
                        if (_clusterOptions.KvIgnoreRemoteCertificateNameMismatch &&
                            CertificateFactory.ValidatorWithIgnoreNameMismatch(sender, certificate, chain, sslPolicyErrors))
                        {
                            return(true);
                        }

                        return(CertificateFactory.ValidateWithDefaultCertificates(sender, certificate, chain, sslPolicyErrors));
                    };
                }

                var sslStream = new SslStream(new NetworkStream(socket, true), false,
                                              certValidationCallback);

#if !NETCOREAPP3_1_OR_GREATER
                await sslStream.AuthenticateAsClientAsync(targetHost, certs,
                                                          _clusterOptions.EnabledSslProtocols,
                                                          _clusterOptions.EnableCertificateRevocation)
                .ConfigureAwait(false);
#else
                SslClientAuthenticationOptions sslOptions = new SslClientAuthenticationOptions()
                {
                    TargetHost                     = targetHost,
                    ClientCertificates             = certs,
                    EnabledSslProtocols            = _clusterOptions.EnabledSslProtocols,
                    CertificateRevocationCheckMode = _clusterOptions.EnableCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck
                };
                if (_clusterOptions.EnabledTlsCipherSuites != null && _clusterOptions.EnabledTlsCipherSuites.Count > 0)
                {
                    sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(_clusterOptions.EnabledTlsCipherSuites);
                }

                await sslStream.AuthenticateAsClientAsync(sslOptions)
                .ConfigureAwait(false);
#endif

                var isSecure = sslStream.IsAuthenticated && sslStream.IsSigned && sslStream.IsEncrypted;
                _sslLogger.LogDebug("IsAuthenticated {0} on {1}", sslStream.IsAuthenticated, targetHost);
                _sslLogger.LogDebug("IsSigned {0} on {1}", sslStream.IsSigned, targetHost);
                _sslLogger.LogDebug("IsEncrypted {0} on {1}", sslStream.IsEncrypted, targetHost);

                //punt if we cannot successfully authenticate
                if (!isSecure)
                {
                    throw new AuthenticationException($"The SSL/TLS connection could not be authenticated on [{targetHost}].");
                }

                return(new SslConnection(sslStream, socket.LocalEndPoint !, socket.RemoteEndPoint !,
                                         _sslLogger, _multiplexLogger));
            }

            return(new MultiplexingConnection(socket, _multiplexLogger));
        }