public async ValueTask AttachAsync(IPeerContext peerContext)
        {
            PeerContext    = peerContext as ExamplePeerContext ?? throw new ArgumentException("Expected ExamplePeerContext", nameof(peerContext));
            _messageWriter = PeerContext.GetMessageWriter();

            await OnPeerAttachedAsync().ConfigureAwait(false);
        }
Example #2
0
 public PrepareExtensionProtocolHandshakeContext(BDictionary handshakeContent,
                                                 IPeerContext peerContext,
                                                 Action <IExtensionProtocolMessage> sendMessage)
     : base(peerContext, sendMessage)
 {
     HandshakeContent = handshakeContent;
 }
Example #3
0
        /// <summary>
        /// Check if the client is allowed to connect based on certain criteria.
        /// </summary>
        /// <returns>When criteria is met returns <c>true</c>, to allow connection.</returns>
        private bool EnsurePeerCanConnect(ConnectionContext connection, IPeerContext peerContext)
        {
            if (_serverPeerConnectionGuards == null)
            {
                return(false);
            }

            ServerPeerConnectionGuardResult?result = (
                from guard in _serverPeerConnectionGuards
                let guardResult = guard.Check(peerContext)
                                  where guardResult.IsDenied
                                  select guardResult
                )
                                                     .DefaultIfEmpty(ServerPeerConnectionGuardResult.Success)
                                                     .FirstOrDefault();

            if (result == null)
            {
                return(true);             // no guards
            }
            if (result.IsDenied)
            {
                _logger.LogDebug("Connection from client '{ConnectingPeerEndPoint}' was rejected because of {ClientDisconnectedReason} and will be closed.", connection.RemoteEndPoint, result.DenyReason);
                connection.Abort(new ConnectionAbortedException(result.DenyReason));
                _eventBus.Publish(new PeerConnectionRejected(peerContext, result.DenyReason));
                return(false);
            }

            return(true);
        }
Example #4
0
        public void SetPeerContext(IPeerContext peerContext)
        {
            _networkPeerContext = peerContext as NetworkPeerContext ?? throw new ArgumentException("Expected NetworkPeerContext", nameof(peerContext));;
            _deserializationContext.SetInitiator(_networkPeerContext.Direction == PeerConnectionDirection.Outbound);

            LightningEndpoint?lightningEndpoint = null;

            if (peerContext.Direction == PeerConnectionDirection.Outbound)
            {
                OutgoingConnectionEndPoint endpoint = peerContext.Features.Get <OutgoingConnectionEndPoint>();

                if (endpoint == null || !endpoint.Items.TryGetValue(nameof(LightningEndpoint), out object?res))
                {
                    _logger.LogError("Remote connection was not found ");
                    throw new ApplicationException("Initiator connection must have a public key of the remote node");
                }

                if (res == null)
                {
                    _logger.LogError("Remote connection type is invalid");
                    throw new ApplicationException("Remote connection type is invalid");
                }

                lightningEndpoint = (LightningEndpoint)res;
            }

            _handshakeProtocol = new HandshakeWithNoiseProtocol(_nodeContext, lightningEndpoint?.NodePubKey, _handshakeProcessor);
            _networkPeerContext.SetHandshakeProtocol(_handshakeProtocol);
        }
Example #5
0
 public ExtensionProtocolMessageReceivedContext(IExtensionProtocolMessage message,
                                                IPeerContext peerContext,
                                                Action <IExtensionProtocolMessage> sendMessage)
     : base(peerContext, sendMessage)
 {
     Message = message;
 }
Example #6
0
        public virtual IPeerContext CreateOutgoingPeerContext(string peerId, EndPoint localEndPoint, OutgoingConnectionEndPoint outgoingConnectionEndPoint, INetworkMessageWriter messageWriter)
        {
            IPeerContext peerContext = Create(PeerConnectionDirection.Outbound, peerId, localEndPoint, outgoingConnectionEndPoint.EndPoint, messageWriter);

            peerContext.Features.Set(outgoingConnectionEndPoint);

            return(peerContext);
        }
Example #7
0
        public override async Task OnConnectedAsync(ConnectionContext connection)
        {
            if (connection is null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            using IDisposable loggerScope = _logger.BeginScope("Peer {PeerId} connected to server {ServerEndpoint}", connection.ConnectionId, connection.LocalEndPoint);

            ProtocolReader reader = connection.CreateReader();
            INetworkProtocolMessageSerializer protocol = _serviceProvider.GetRequiredService <INetworkProtocolMessageSerializer>();

            using IPeerContext peerContext = _peerContextFactory.CreateIncomingPeerContext(connection.ConnectionId,
                                                                                           connection.LocalEndPoint !.AsIPEndPoint().EnsureIPv6(),
                                                                                           connection.RemoteEndPoint !.AsIPEndPoint().EnsureIPv6(),
                                                                                           new NetworkMessageWriter(protocol, connection.CreateWriter()));

            using CancellationTokenRegistration cancellationRegistration = peerContext.ConnectionCancellationTokenSource.Token.Register(() =>
            {
                connection.Abort(new ConnectionAbortedException("Requested by PeerContext"));
            });

            connection.Features.Set(peerContext);
            protocol.SetPeerContext(peerContext);

            if (EnsurePeerCanConnect(connection, peerContext))
            {
                _eventBus.Publish(new PeerConnected(peerContext));

                await _networkMessageProcessorFactory.StartProcessorsAsync(peerContext).ConfigureAwait(false);

                while (true)
                {
                    try
                    {
                        ProtocolReadResult <INetworkMessage> result = await reader.ReadAsync(protocol).ConfigureAwait(false);

                        if (result.IsCompleted)
                        {
                            break;
                        }

                        await ProcessMessageAsync(result.Message, peerContext, connection.ConnectionClosed).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogDebug(ex, "Unexpected connection terminated because of {DisconnectionReason}.", ex.Message);
                        break;
                    }
                    finally
                    {
                        reader.Advance();
                    }
                }

                return;
            }
        }
        internal override string?TryGetDenyReason(IPeerContext peerContext)
        {
            if (_peerAddressBook.IsBanned(peerContext))
            {
                return("Inbound connection refused: peer is banned.");
            }

            return(null);
        }
Example #9
0
        public void OnPeerConnected(IPeerContext context)
        {
            foreach (var messageId in MessageIds)
            {
                context.RegisterMessageHandler(messageId);
            }

            context.Peer.SendMessage(new BitfieldMessage(new Bitfield(context.Metainfo.Pieces.Count, context.DataHandler.CompletedPieces)));
        }
        internal override string?TryGetDenyReason(IPeerContext peerContext)
        {
            if (!settings.AllowLoopbackConnection && IPAddress.IsLoopback(peerContext.RemoteEndPoint.Address))
            {
                return($"Loopback peer connection not allowed (set {nameof(settings.AllowLoopbackConnection)} to true to allow such kind of connections).");
            }

            return(null);
        }
Example #11
0
        internal override string TryGetDenyReason(IPeerContext peerContext)
        {
            if (this.serverPeerStats.ConnectedInboundPeersCount >= this.settings.MaxInboundConnections)
            {
                return("Inbound connection refused: max connection threshold reached.");
            }

            return(null);
        }
Example #12
0
        public BitcoinNetworkProtocolMessageSerializer(ILogger <BitcoinNetworkProtocolMessageSerializer> logger, INetworkDefinition chainDefinition, INetworkMessageSerializerManager networkMessageSerializerManager)
        {
            _logger          = logger;
            _chainDefinition = chainDefinition;
            _networkMessageSerializerManager = networkMessageSerializerManager;
            _deserializationContext          = new DeserializationContext(chainDefinition.MagicBytes);

            _peerContext = null !; //initialized by SetPeerContext
        }
        public void Serialize(INetworkMessage message, int protocolVersion, IPeerContext peerContext, IBufferWriter <byte> output)
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            Serialize((TMessageType)message, protocolVersion, (TPeerContext)peerContext, output);
        }
Example #14
0
 private void SendMessage(IPeerContext peerContext, Action <BinaryWriter> constructMessage)
 {
     using (var ms = new MemoryStream())
     {
         BinaryWriter writer = new BigEndianBinaryWriter(ms);
         constructMessage(writer);
         writer.Flush();
         peerContext.SendMessage(ExtensionProtocolMessageId, ms.ToArray());
     }
 }
        internal override string?TryGetDenyReason(IPeerContext peerContext)
        {
            //TODO implement ban check, bitcoin core ref: https://github.com/bitcoin/bitcoin/blob/e8e79958a7b2a0bf1b02adcce9f4d811eac37dfc/src/net.cpp#L984-L993
            //if (peer is banned)
            //{
            //   return "Current peer is banned.";
            //}

            return(null);
        }
        public bool TrySerialize(INetworkMessage message, int protocolVersion, IPeerContext peerContext, IBufferWriter <byte> output)
        {
            if (_serializers.TryGetValue(message.Command, out INetworkMessageSerializer? serializer))
            {
                serializer.Serialize(message, protocolVersion, peerContext, output);
                return(true);
            }

            return(false);
        }
Example #17
0
        public void SetPeerContext(IPeerContext peerContext)
        {
            // we know it's an ExamplePeerContext in our example.
            _peerContext = (ExamplePeerContext)peerContext;

            if (_peerContext.MyExtraInformation != null)
            {
                _logger.LogDebug("I'm ExampleNetworkProtocolMessageSerializer and I know that I've some information for you: {AdditionalInformation}", _peerContext.MyExtraInformation);
            }
        }
        private async Task ProcessMessageAsync(INetworkMessage message, IPeerContext peerContext, CancellationToken cancellation)
        {
            using IDisposable logScope = _logger.BeginScope("Processing message '{Command}'", message.Command);

            if (!(message is UnknownMessage))
            {
                await _networkMessageProcessorFactory.ProcessMessageAsync(message, peerContext, cancellation).ConfigureAwait(false);

                _eventBus.Publish(new PeerMessageReceived(peerContext, message));
            }
        }
 public int GetScore(IPeerContext peerContext)
 {
     if (!_connectedPeers.TryGetValue(peerContext.PeerId, out PeerScore? score))
     {
         _logger.LogWarning("Peer {PeerId} not found, returning neutral score.", peerContext.PeerId);
         return(0);
     }
     else
     {
         return(score.Score);
     }
 }
 public void AddBonus(IPeerContext peerContext, uint bonus, string reason)
 {
     if (!_connectedPeers.TryGetValue(peerContext.PeerId, out PeerScore? score))
     {
         _logger.LogWarning("Cannot attribute positive points to the peer {PeerId} because the peer isn't connected.", peerContext.PeerId);
     }
     else
     {
         _logger.LogDebug("Peer {PeerId} got a bonus {PeerBonus}: {MisbehaveReason}.", peerContext.PeerId, bonus, reason);
         score.UpdateScore((int)bonus);
     }
 }
        public ServerPeerConnectionGuardResult Check(IPeerContext peerContext)
        {
            string denyReason = this.TryGetDenyReason(peerContext);

            if (!string.IsNullOrEmpty(denyReason))
            {
                this.logger.LogDebug("Peer connection guard not passed: {denyReason}", denyReason);
                return(ServerPeerConnectionGuardResult.Deny(denyReason));
            }

            return(ServerPeerConnectionGuardResult.Allow());
        }
Example #22
0
        internal override string?TryGetDenyReason(IPeerContext peerContext)
        {
            if (_peerStats.ConnectedInboundPeersCount >= settings.MaxInboundConnections)
            {
                /// TODO: try to evict eventual bad connection to let a space for this connection
                /// ref: https://github.com/bitcoin/bitcoin/blob/e8e79958a7b2a0bf1b02adcce9f4d811eac37dfc/src/net.cpp#L995-L1003
                /// I'd consider another approach: accept a connection that exceed the maximum allowed connection, try to handshake
                /// and if successful then decide either if evict one connect and keep this, or drop the connection attempt
                return("Inbound connection refused: max connection threshold reached.");
            }

            return(null);
        }
Example #23
0
        private void SendExtensionMessage(IPeerContext peerContext, IExtensionProtocolMessage message)
        {
            var peerMessageIds = peerContext.GetValue <Dictionary <string, byte> >(ExtensionProtocolMessageIds);

            if (!peerMessageIds.TryGetValue(message.MessageType, out byte messageType))
            {
                throw new InvalidOperationException($"Peer does not support message type {message.MessageType}");
            }

            SendMessage(peerContext, writer =>
            {
                writer.Write(messageType);
                writer.Write(message.Serialize());
            });
        }
Example #24
0
        internal override string?TryGetDenyReason(IPeerContext peerContext)
        {
            if (_initialBlockDownloadState.IsDownloadingBlocks())
            {
                bool clientIsWhiteListed = settings.Listeners
                                           .Any(binding => binding.IsWhitelistingEndpoint && binding.Matches(peerContext.LocalEndPoint));

                if (!clientIsWhiteListed)
                {
                    return("Node is in IBD and the peer is not white-listed.");
                }
            }

            return(null);
        }
        void IModule.OnPeerConnected(IPeerContext context)
        {
            // Check for extension protocol support
            bool supportsExtensionProtocol = (context.Peer.ReservedBytes[5] & 0x10) != 0;

            if (!supportsExtensionProtocol)
            {
                return;
            }

            // Register to receive extension protocol messages
            context.RegisterMessageHandler(ExtensionProtocolMessageId);

            // Send handshake message
            var handshake = new ExtensionProtocolHandshake
            {
                MessageIds = _supportedMessages,
                Client     = "TorrentCore 0.1", // todo
            };

            var handshakeDict = handshake.Serialize();

            var prepareHandshakeContext =
                new PrepareExtensionProtocolHandshakeContext(
                    handshakeDict,
                    context,
                    msg => SendExtensionMessage(context, msg));

            foreach (var handler in _registeredHandlers)
            {
                handler.PrepareExtensionProtocolHandshake(prepareHandshakeContext);
            }

            SendMessage(context, writer =>
            {
                writer.Write((byte)0);
                writer.Flush();
                handshakeDict.EncodeTo(writer.BaseStream);
            });
        }
        /// <summary>
        /// Attaches known processors to specified peer.
        /// </summary>
        /// <param name="peerContext">The peer context.</param>
        public async Task StartProcessorsAsync(IPeerContext peerContext)
        {
            if (peerContext is null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(peerContext));
            }

            IEnumerable <INetworkMessageProcessor> processors = _serviceProvider.GetService <IEnumerable <INetworkMessageProcessor> >() !;

            foreach (INetworkMessageProcessor processor in processors)
            {
                // skip processors that aren't enabled
                if (!processor.Enabled)
                {
                    continue;
                }

                peerContext.AttachNetworkMessageProcessor(processor);
                await processor.AttachAsync(peerContext).ConfigureAwait(false);
            }

            peerContext.Features.Set(new PeerNetworkMessageProcessorContainer(_serviceProvider.GetRequiredService <ILogger <PeerNetworkMessageProcessorContainer> >(), processors));
        }
        public void Misbehave(IPeerContext peerContext, uint penality, string reason)
        {
            if (penality == 0)
            {
                return;
            }

            if (!_connectedPeers.TryGetValue(peerContext.PeerId, out PeerScore? score))
            {
                _logger.LogWarning("Cannot attribute bad behavior to the peer {PeerId} because the peer isn't connected.", peerContext.PeerId);
                // did we have to add it to banned peers anyway?
                return;
            }

            _logger.LogDebug("Peer {PeerId} misbehave: {MisbehaveReason}.", peerContext.PeerId, reason);
            int currentResult = score.UpdateScore(-(int)penality);

            if (currentResult < _connectivitySettings.BanScore)
            {
                //if threshold of bad behavior has been exceeded, this peer need to be banned
                _logger.LogDebug("Peer {RemoteEndPoint} BAN threshold exceeded.", peerContext.RemoteEndPoint);
                _peerAddressBook.Ban(peerContext, DateTimeOffset.UtcNow + TimeSpan.FromSeconds(_connectivitySettings.MisbehavingBanTime), "Peer Misbehaving");
            }
        }
 public async ValueTask ProcessMessageAsync(INetworkMessage message, IPeerContext peerContext, CancellationToken cancellation)
 {
     await peerContext.Features.Get <PeerNetworkMessageProcessorContainer>().ProcessMessageAsync(message, cancellation).ConfigureAwait(false);
 }
 internal void SetPeerContext(IPeerContext peerContext)
 {
     this.peerContext = peerContext;
 }
Example #30
0
        internal override void Completed(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext, OperationCompletedEventArgs oce)
        {
            ClientConst.OperationResult operationResult = oce.Result;

            if (operationResult == ClientConst.OperationResult.Successful)
            {
                Logger.GetLog().Info("接続を維持しています(接続数: " + peerContext.Connections + ")。");

                mediatorContext.State = new ConnectedState();
            }
            else if (operationResult == ClientConst.OperationResult.Restartable)
            {
                Logger.GetLog().Info("IPアドレスが変化しているため、再接続します。");

                peerContext.DisconnectAll();

                Logger.GetLog().Info("ピア接続をすべて切断しました(接続数: " + peerContext.Connections + ")");

                mediatorContext.State = new DisconnectedState();

                bool result = mediatorContext.Connect();
                if (!result)
                {
                    mediatorContext.State = new ConnectedState();
                }
            }
            else if (operationResult == ClientConst.OperationResult.Retryable)
            {
                // FIXME: 暫定。本当はすぐに再試行したい
                Logger.GetLog().Info("接続維持に失敗しました。再試行可能なエラーです。");

                mediatorContext.State = new ConnectedState();
            }
            else
            {
                throw new NotSupportedException();
            }
        }