private void EndCheckEncryption(IAsyncResult result)
        {
            PeerId id = (PeerId)result.AsyncState;

            byte[] initialData;
            try
            {
                EncryptorFactory.EndCheckEncryption(result, out initialData);
                if (initialData != null && initialData.Length > 0)
                {
                    throw new EncryptionException("unhandled initial data");
                }

                EncryptionTypes e = engine.Settings.AllowedEncryption;
                if (id.Encryptor is RC4 && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Full) ||
                    id.Encryptor is RC4Header && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Header) ||
                    id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(e, EncryptionTypes.PlainText))
                {
                    CleanupSocket(id, id.Encryptor.GetType().Name + " encryption is not enabled");
                }
                else
                {
                    // Create a handshake message to send to the peer
                    HandshakeMessage handshake = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100);
                    SendMessage(id, handshake, this.handshakeSentCallback);
                }
            }
            catch
            {
                id.Peer.Encryption &= ~EncryptionTypes.RC4Full;
                id.Peer.Encryption &= ~EncryptionTypes.RC4Header;
                CleanupSocket(id, "Failed encryptor check");
            }
        }
Example #2
0
 internal EngineSettings(
     IList <EncryptionType> allowedEncryption, bool allowHaveSuppression, bool allowLocalPeerDiscovery, bool allowPortForwarding,
     bool autoSaveLoadDhtCache, bool autoSaveLoadFastResume, bool autoSaveLoadMagnetLinkMetadata, string cacheDirectory,
     TimeSpan connectionTimeout, IPEndPoint dhtEndPoint, int diskCacheBytes, FastResumeMode fastResumeMode, IPEndPoint listenEndPoint,
     int maximumConnections, int maximumDiskReadRate, int maximumDiskWriteRate, int maximumDownloadSpeed, int maximumHalfOpenConnections,
     int maximumOpenFiles, int maximumUploadSpeed, IPEndPoint reportedAddress, bool usePartialFiles)
 {
     // Make sure this is immutable now
     AllowedEncryption              = EncryptionTypes.MakeReadOnly(allowedEncryption);
     AllowHaveSuppression           = allowHaveSuppression;
     AllowLocalPeerDiscovery        = allowLocalPeerDiscovery;
     AllowPortForwarding            = allowPortForwarding;
     AutoSaveLoadDhtCache           = autoSaveLoadDhtCache;
     AutoSaveLoadFastResume         = autoSaveLoadFastResume;
     AutoSaveLoadMagnetLinkMetadata = autoSaveLoadMagnetLinkMetadata;
     DhtEndPoint                = dhtEndPoint;
     DiskCacheBytes             = diskCacheBytes;
     CacheDirectory             = cacheDirectory;
     ConnectionTimeout          = connectionTimeout;
     FastResumeMode             = fastResumeMode;
     ListenEndPoint             = listenEndPoint;
     MaximumConnections         = maximumConnections;
     MaximumDiskReadRate        = maximumDiskReadRate;
     MaximumDiskWriteRate       = maximumDiskWriteRate;
     MaximumDownloadSpeed       = maximumDownloadSpeed;
     MaximumHalfOpenConnections = maximumHalfOpenConnections;
     MaximumOpenFiles           = maximumOpenFiles;
     MaximumUploadSpeed         = maximumUploadSpeed;
     ReportedAddress            = reportedAddress;
     UsePartialFiles            = usePartialFiles;
 }
        public void RemoveFromEmptyList()
        {
            var result = EncryptionTypes.Remove(new List <EncryptionType> (), EncryptionType.PlainText);

            Assert.IsEmpty(result);
            Assert.Throws <NotSupportedException> (() => result.Add(EncryptionType.PlainText));
        }
        public void GetPreferredEncryption()
        {
            var result = EncryptionTypes.GetPreferredEncryption(
                new[] { EncryptionType.PlainText },
                new[] { EncryptionType.RC4Header });

            Assert.IsEmpty(result);

            result = EncryptionTypes.GetPreferredEncryption(
                new[] { EncryptionType.PlainText, EncryptionType.RC4Header },
                new[] { EncryptionType.RC4Header });

            Assert.AreEqual(EncryptionType.RC4Header, result.Single());

            result = EncryptionTypes.GetPreferredEncryption(
                new[] { EncryptionType.PlainText, EncryptionType.RC4Header, EncryptionType.RC4Full },
                new[] { EncryptionType.RC4Full });

            Assert.AreEqual(EncryptionType.RC4Full, result.Single());

            result = EncryptionTypes.GetPreferredEncryption(
                new[] { EncryptionType.PlainText, EncryptionType.RC4Header },
                new[] { EncryptionType.RC4Full, EncryptionType.PlainText, EncryptionType.RC4Header });

            Assert.AreEqual(EncryptionType.PlainText, result.Single());
        }
        async void ConnectionReceived(object?sender, PeerConnectionEventArgs e)
        {
            await ClientEngine.MainLoop;
            var peer = new Peer("", e.Connection.Uri, EncryptionTypes.All);

            try {
                if (Engine.ConnectionManager.ShouldBanPeer(peer))
                {
                    e.Connection.Dispose();
                    return;
                }
                if (!e.Connection.IsIncoming)
                {
                    var manager = Engine.Torrents.FirstOrDefault(t => t.InfoHashes.Contains(e.InfoHash !)) !;
                    var id      = new PeerId(peer, e.Connection, new BitField(manager.Bitfield.Length).SetAll(false));
                    id.LastMessageSent.Restart();
                    id.LastMessageReceived.Restart();

                    Engine.ConnectionManager.ProcessNewOutgoingConnection(manager, id);
                    return;
                }

                logger.Info(e.Connection, "ConnectionReceived");

                var supportedEncryptions = EncryptionTypes.GetSupportedEncryption(peer.AllowedEncryption, Engine.Settings.AllowedEncryption);
                EncryptorFactory.EncryptorResult result = await EncryptorFactory.CheckIncomingConnectionAsync(e.Connection, supportedEncryptions, SKeys, Engine.Factories);

                if (!await HandleHandshake(peer, e.Connection, result.Handshake !, result.Decryptor, result.Encryptor))
                {
                    e.Connection.Dispose();
                }
            } catch {
                e.Connection.Dispose();
            }
        }
Example #6
0
 public EngineSettings(string savePath, int listenPort, int maximumConnections, int maximumHalfOpenConnections, int maximumDownloadSpeed, int maximumUploadSpeed, EncryptionTypes allowedEncryption)
     : this(savePath, listenPort, maximumConnections, maximumHalfOpenConnections)
 {
     MaximumDownloadSpeed = maximumDownloadSpeed;
     MaximumUploadSpeed   = maximumUploadSpeed;
     AllowedEncryption    = allowedEncryption;
 }
Example #7
0
        async void ConnectionReceived(object sender, NewConnectionEventArgs e)
        {
            await ClientEngine.MainLoop;

            try {
                if (Engine.ConnectionManager.ShouldBanPeer(e.Peer))
                {
                    e.Connection.Dispose();
                    return;
                }

                if (!e.Connection.IsIncoming)
                {
                    var id = new PeerId(e.Peer, e.Connection, e.TorrentManager.Bitfield?.Clone().SetAll(false));
                    id.LastMessageSent.Restart();
                    id.LastMessageReceived.Restart();

                    Engine.ConnectionManager.ProcessNewOutgoingConnection(e.TorrentManager, id);
                    return;
                }

                logger.Info(e.Connection, "ConnectionReceived");

                var supportedEncryptions = EncryptionTypes.GetSupportedEncryption(e.Peer.AllowedEncryption, Engine.Settings.AllowedEncryption);
                EncryptorFactory.EncryptorResult result = await EncryptorFactory.CheckIncomingConnectionAsync(e.Connection, supportedEncryptions, SKeys);

                if (!await HandleHandshake(e.Peer, e.Connection, result.Handshake, result.Decryptor, result.Encryptor))
                {
                    e.Connection.Dispose();
                }
            } catch {
                e.Connection.Dispose();
            }
        }
Example #8
0
 public EngineSettings(string defaultSavePath, int listenPort, int globalMaxConnections, int globalHalfOpenConnections, int globalMaxDownloadSpeed, int globalMaxUploadSpeed, EncryptionTypes allowedEncryption)
 {
     this.globalMaxConnections         = globalMaxConnections;
     this.globalMaxDownloadSpeed       = globalMaxDownloadSpeed;
     this.globalMaxUploadSpeed         = globalMaxUploadSpeed;
     this.globalMaxHalfOpenConnections = globalHalfOpenConnections;
     this.listenPort        = listenPort;
     this.allowedEncryption = allowedEncryption;
     this.savePath          = defaultSavePath;
 }
Example #9
0
        private void Handshake(EncryptionTypes encryptionA, EncryptionTypes encryptionB, bool addInitial)
        {
            HandshakeMessage m = new HandshakeMessage(rig.Torrent.InfoHash, "12345123451234512345", VersionInfo.ProtocolStringV100);

            byte[] handshake = m.Encode();

            PeerAEncryption a = new PeerAEncryption(rig.Torrent.InfoHash, encryptionA);

            if (addInitial)
            {
                a.AddPayload(handshake);
            }

            PeerBEncryption b = new PeerBEncryption(new InfoHash[] { rig.Torrent.InfoHash }, encryptionB);

            var resultA = a.HandshakeAsync(conn.Outgoing);
            var resultB = b.HandshakeAsync(conn.Incoming);

            if (!Task.WhenAll(resultA, resultB).Wait(5000))
            {
                Assert.Fail("Could not handshake");
            }


            HandshakeMessage d = new HandshakeMessage();

            if (!addInitial)
            {
                a.Encrypt(handshake, 0, handshake.Length);
                b.Decrypt(handshake, 0, handshake.Length);
                d.Decode(handshake, 0, handshake.Length);
            }
            else
            {
                d.Decode(b.InitialData, 0, b.InitialData.Length);
            }
            Assert.AreEqual(m, d);


            if (encryptionA == EncryptionTypes.RC4Full || encryptionB == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
                Assert.IsTrue(b.Encryptor is RC4);
            }
            else if (encryptionA == EncryptionTypes.RC4Header || encryptionB == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
                Assert.IsTrue(b.Encryptor is RC4Header);
            }
            else if (encryptionA == EncryptionTypes.PlainText || encryptionB == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is PlainTextEncryption);
                Assert.IsTrue(b.Encryptor is PlainTextEncryption);
            }
        }
Example #10
0
        public async Task InitiateTransfer(CustomConnection connection, EncryptionTypes allowedEncryption)
        {
            PeerId id = new PeerId(new Peer("", connection.Uri), rig.Manager);

            id.Peer.Encryption = allowedEncryption;
            id.Connection      = connection;

            var data = await EncryptorFactory.CheckEncryptionAsync(id, 68, new InfoHash[] { id.TorrentManager.InfoHash });

            decryptor = id.Decryptor;
            encryptor = id.Encryptor;
            TestHandshake(data, connection);
        }
Example #11
0
        private void PeerATest(EncryptionTypes encryption, bool addInitial)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            rig.Engine.StartAll();

            HandshakeMessage message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);

            byte[]          buffer = message.Encode();
            PeerAEncryption a      = new PeerAEncryption(rig.Manager.InfoHash, encryption);

            if (addInitial)
            {
                a.AddPayload(buffer);
            }

            rig.AddConnection(conn.Incoming);
            IAsyncResult result = a.BeginHandshake(conn.Outgoing, null, null);

            if (!result.AsyncWaitHandle.WaitOne(4000, true))
            {
                Assert.Fail("Handshake timed out");
            }
            a.EndHandshake(result);

            if (!addInitial)
            {
                a.Encryptor.Encrypt(buffer);
                conn.Outgoing.EndSend(conn.Outgoing.BeginSend(buffer, 0, buffer.Length, null, null));
            }

            int received = conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));

            Assert.AreEqual(68, received, "Recived handshake");

            a.Decryptor.Decrypt(buffer);
            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);

            if (encryption == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
            }
            else if (encryption == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
            }
            else if (encryption == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
            }
        }
        private async void EndCheckEncryption(PeerId id, byte[] initialData)
        {
            try
            {
                if (initialData != null && initialData.Length > 0)
                {
                    throw new EncryptionException("unhandled initial data");
                }

                EncryptionTypes e = engine.Settings.AllowedEncryption;
                if (id.Encryptor is RC4 && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Full) ||
                    id.Encryptor is RC4Header && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Header) ||
                    id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(e, EncryptionTypes.PlainText))
                {
                    CleanupSocket(id, id.Encryptor.GetType().Name + " encryption is not enabled");
                }
                else
                {
                    // Create a handshake message to send to the peer
                    var handshake = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100);
                    await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, handshake, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor);

                    // Receive their handshake
                    handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor);

                    handshake.Handle(id);

                    // If there are any pending messages, send them otherwise set the queue
                    // processing as finished.
                    if (id.QueueLength > 0)
                    {
                        ProcessQueue(id);
                    }
                    else
                    {
                        id.ProcessingQueue = false;
                    }

                    ReceiveMessagesAsync(id.Connection, id.Decryptor, id.TorrentManager.DownloadLimiter, id.Monitor, id.TorrentManager, id);
                    // Alert the engine that there is a new usable connection
                    id.TorrentManager.HandlePeerConnected(id, Direction.Outgoing);
                }
            }
            catch
            {
                id.Peer.Encryption &= ~EncryptionTypes.RC4Full;
                id.Peer.Encryption &= ~EncryptionTypes.RC4Header;
                CleanupSocket(id, "Failed encryptor check");
            }
        }
Example #13
0
 public async Task InitiateTransfer(CustomConnection connection, EncryptionTypes allowedEncryption)
 {
     EncryptorFactory.EncryptorResult result;
     if (connection.IsIncoming)
     {
         result = await EncryptorFactory.CheckIncomingConnectionAsync(connection, allowedEncryption, rig.Engine.Settings, HandshakeMessage.HandshakeLength, new [] { rig.Manager.InfoHash });
     }
     else
     {
         result = await EncryptorFactory.CheckOutgoingConnectionAsync(connection, allowedEncryption, rig.Engine.Settings, rig.Manager.InfoHash);
     }
     decryptor = result.Decryptor;
     encryptor = result.Encryptor;
     TestHandshake(result.InitialData, connection);
 }
Example #14
0
        public Peer(string peerId, Uri connectionUri, EncryptionTypes encryption)
        {
            if (peerId == null)
            {
                throw new ArgumentNullException("peerId");
            }
            if (connectionUri == null)
            {
                throw new ArgumentNullException("connectionUri");
            }

            this.connectionUri = connectionUri;
            this.encryption    = encryption;
            this.peerId        = peerId;
        }
        public void GetSupported()
        {
            var result = EncryptionTypes.GetSupportedEncryption(
                new[] { EncryptionType.RC4Full, EncryptionType.PlainText },
                new[] { EncryptionType.PlainText });

            Assert.AreEqual(EncryptionType.PlainText, result.Single());

            result = EncryptionTypes.GetSupportedEncryption(
                new[] { EncryptionType.PlainText },
                new[] { EncryptionType.RC4Full, EncryptionType.PlainText });
            Assert.AreEqual(EncryptionType.PlainText, result.Single());

            result = EncryptionTypes.GetSupportedEncryption(
                new[] { EncryptionType.PlainText, EncryptionType.RC4Full, EncryptionType.RC4Header },
                new[] { EncryptionType.RC4Full, EncryptionType.PlainText });
            Assert.AreEqual(EncryptionType.RC4Full, result.First());
            Assert.AreEqual(EncryptionType.PlainText, result.Last());
        }
Example #16
0
 internal EngineSettings(IList <EncryptionType> allowedEncryption, bool allowHaveSuppression, bool allowLocalPeerDiscovery, bool allowPortForwarding, TimeSpan connectionTimeout, int dhtPort, int listenPort, int maximumConnections, int maximumDiskReadRate, int maximumDiskWriteRate, int maximumDownloadSpeed, int maximumHalfOpenConnections, int maximumOpenFiles, int maximumUploadSpeed, IPEndPoint reportedAddress, string savePath)
 {
     // Make sure this is immutable now
     AllowedEncryption       = EncryptionTypes.MakeReadOnly(allowedEncryption);
     AllowHaveSuppression    = allowHaveSuppression;
     AllowLocalPeerDiscovery = allowLocalPeerDiscovery;
     AllowPortForwarding     = allowPortForwarding;
     DhtPort                    = dhtPort;
     ConnectionTimeout          = connectionTimeout;
     ListenPort                 = listenPort;
     MaximumConnections         = maximumConnections;
     MaximumDiskReadRate        = maximumDiskReadRate;
     MaximumDiskWriteRate       = maximumDiskWriteRate;
     MaximumDownloadSpeed       = maximumDownloadSpeed;
     MaximumHalfOpenConnections = maximumHalfOpenConnections;
     MaximumOpenFiles           = maximumOpenFiles;
     MaximumUploadSpeed         = maximumUploadSpeed;
     ReportedAddress            = reportedAddress;
     SavePath                   = savePath;
 }
        // TODO onDropped!
        #endregion


        #region Methods

        internal void OnTick()
        {
            if (!Manager.Settings.AllowPeerExchange)
            {
                return;
            }

            int len = (addedPeers.Count <= MAX_PEERS) ? addedPeers.Count : MAX_PEERS;

            byte[] added     = new byte[len * 6];
            byte[] addedDotF = new byte[len];
            for (int i = 0; i < len; i++)
            {
                addedPeers[i].CompactPeer(added.AsSpan(i * 6, 6));
                if (EncryptionTypes.SupportsRC4(addedPeers[i].AllowedEncryption))
                {
                    addedDotF[i] = 0x01;
                }
                else
                {
                    addedDotF[i] = 0x00;
                }

                addedDotF[i] |= (byte)(addedPeers[i].IsSeeder ? 0x02 : 0x00);
            }
            addedPeers.RemoveRange(0, len);

            len = Math.Min(MAX_PEERS - len, droppedPeers.Count);

            byte[] dropped = new byte[len * 6];
            for (int i = 0; i < len; i++)
            {
                droppedPeers[i].CompactPeer(dropped.AsSpan(i * 6, 6));
            }

            droppedPeers.RemoveRange(0, len);

            (var message, var releaser) = PeerMessage.Rent <PeerExchangeMessage> ();
            message.Initialize(id.ExtensionSupports, new ReadOnlyMemory <byte> (added), new ReadOnlyMemory <byte> (addedDotF), new ReadOnlyMemory <byte> (dropped));
            id.MessageQueue.Enqueue(message, releaser);
        }
Example #18
0
        // TODO onDropped!
        #endregion


        #region Methods

        internal void OnTick()
        {
            if (!Manager.Settings.AllowPeerExchange)
            {
                return;
            }

            int len = (addedPeers.Count <= MAX_PEERS) ? addedPeers.Count : MAX_PEERS;

            byte[] added     = new byte[len * 6];
            byte[] addedDotF = new byte[len];
            for (int i = 0; i < len; i++)
            {
                addedPeers[i].CompactPeer(added, i * 6);
                if (EncryptionTypes.SupportsRC4(addedPeers[i].AllowedEncryption))
                {
                    addedDotF[i] = 0x01;
                }
                else
                {
                    addedDotF[i] = 0x00;
                }

                addedDotF[i] |= (byte)(addedPeers[i].IsSeeder ? 0x02 : 0x00);
            }
            addedPeers.RemoveRange(0, len);

            len = Math.Min(MAX_PEERS - len, droppedPeers.Count);

            byte[] dropped = new byte[len * 6];
            for (int i = 0; i < len; i++)
            {
                droppedPeers[i].CompactPeer(dropped, i * 6);
            }

            droppedPeers.RemoveRange(0, len);
            id.MessageQueue.Enqueue(new PeerExchangeMessage(id, added, addedDotF, dropped));
        }
Example #19
0
        private void PeerBTest(EncryptionTypes encryption)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            rig.Engine.StartAll();
            rig.AddConnection(conn.Outgoing);

            PeerBEncryption a      = new PeerBEncryption(new InfoHash[] { rig.Manager.InfoHash }, EncryptionTypes.All);
            IAsyncResult    result = a.BeginHandshake(conn.Incoming, null, null);

            if (!result.AsyncWaitHandle.WaitOne(4000, true))
            {
                Assert.Fail("Handshake timed out");
            }
            a.EndHandshake(result);

            HandshakeMessage message = new HandshakeMessage();

            byte[] buffer = new byte[68];

            conn.Incoming.EndReceive(conn.Incoming.BeginReceive(buffer, 0, buffer.Length, null, null));

            a.Decryptor.Decrypt(buffer);
            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);
            if (encryption == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
            }
            else if (encryption == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
            }
            else if (encryption == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
            }
        }
Example #20
0
        internal async void ProcessNewOutgoingConnection(TorrentManager manager, PeerId id)
        {
            // If we have too many open connections, close the connection
            if (OpenConnections > MaxOpenConnections)
            {
                CleanupSocket(manager, id);
                return;
            }

            manager.Peers.ActivePeers.Add(id.Peer);
            manager.Peers.ConnectedPeers.Add(id);
            Interlocked.Increment(ref openConnections);

            try {
                // Create a handshake message to send to the peer
                var handshake           = new HandshakeMessage(manager.InfoHash, LocalPeerId, VersionInfo.ProtocolStringV100);
                var preferredEncryption = EncryptionTypes.GetPreferredEncryption(id.Peer.AllowedEncryption, Settings.AllowedEncryption);
                EncryptorFactory.EncryptorResult result = await EncryptorFactory.CheckOutgoingConnectionAsync(id.Connection, preferredEncryption, manager.InfoHash, handshake);

                id.Decryptor = result.Decryptor;
                id.Encryptor = result.Encryptor;
            } catch {
                // If an exception is thrown it's because we tried to establish an encrypted connection and something went wrong
                if (id.Peer.AllowedEncryption.Contains(EncryptionType.PlainText))
                {
                    id.Peer.AllowedEncryption = EncryptionTypes.PlainText;
                }
                else
                {
                    id.Peer.AllowedEncryption = EncryptionTypes.None;
                }

                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.EncryptionNegiotiationFailed, manager));
                CleanupSocket(manager, id);

                // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If
                // the peer was re-added, then we should try to reconnect to it immediately to try an
                // unencrypted connection.
                if (manager.Peers.AvailablePeers.Remove(id.Peer))
                {
                    ConnectToPeer(manager, id.Peer);
                }
                return;
            }

            try {
                // Receive their handshake
                HandshakeMessage handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor);

                manager.Mode.HandleMessage(id, handshake);
            } catch {
                // If we choose plaintext and it resulted in the connection being closed, remove it from the list.
                id.Peer.AllowedEncryption = EncryptionTypes.Remove(id.Peer.AllowedEncryption, id.EncryptionType);

                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.HandshakeFailed, manager));
                CleanupSocket(manager, id);

                // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If
                // the peer was re-added, then we should try to reconnect to it immediately to try an
                // encrypted connection, assuming the previous connection was unencrypted and it failed.
                if (manager.Peers.AvailablePeers.Remove(id.Peer))
                {
                    ConnectToPeer(manager, id.Peer);
                }

                return;
            }

            try {
                if (id.BitField.Length != manager.Bitfield.Length)
                {
                    throw new TorrentException($"The peer's bitfield was of length {id.BitField.Length} but the TorrentManager's bitfield was of length {manager.Bitfield.Length}.");
                }

                manager.HandlePeerConnected(id);
                id.MessageQueue.SetReady();
                TryProcessQueue(manager, id);

                ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id);

                id.WhenConnected.Restart();
                id.LastBlockReceived.Restart();
            } catch {
                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.Unknown, manager));
                CleanupSocket(manager, id);
                return;
            }
        }
Example #21
0
 public Peer(BEncodedString peerId, Uri connectionUri, EncryptionTypes allowedEncryption)
 {
     PeerId            = peerId ?? throw new ArgumentNullException(nameof(peerId));
     ConnectionUri     = connectionUri ?? throw new ArgumentNullException(nameof(connectionUri));
     AllowedEncryption = allowedEncryption;
 }
Example #22
0
        private void Handshake(EncryptionTypes encryptionA, EncryptionTypes encryptionB, bool addInitial)
        {
            bool doneA = false;
            bool doneB = false;

            HandshakeMessage m = new HandshakeMessage(rig.Torrent.InfoHash, "12345123451234512345", VersionInfo.ProtocolStringV100);

            byte[] handshake = m.Encode();

            PeerAEncryption a = new PeerAEncryption(rig.Torrent.InfoHash, encryptionA);

            if (addInitial)
            {
                a.AddPayload(handshake);
            }

            PeerBEncryption b = new PeerBEncryption(new InfoHash[] { rig.Torrent.InfoHash }, encryptionB);

            IAsyncResult resultA = a.BeginHandshake(conn.Outgoing, null, null);
            IAsyncResult resultB = b.BeginHandshake(conn.Incoming, null, null);

            WaitHandle[] handles = new WaitHandle[] { resultA.AsyncWaitHandle, resultB.AsyncWaitHandle };
            int          count   = 1000;

            while (!WaitHandle.WaitAll(handles, 5, true))
            {
                if (!doneA && (doneA = resultA.IsCompleted))
                {
                    a.EndHandshake(resultA);
                }
                if (!doneB && (doneB = resultB.IsCompleted))
                {
                    b.EndHandshake(resultB);
                }

                if (count-- == 0)
                {
                    Assert.Fail("Could not handshake");
                }
            }
            if (!doneA)
            {
                a.EndHandshake(resultA);
            }
            if (!doneB)
            {
                b.EndHandshake(resultB);
            }

            HandshakeMessage d = new HandshakeMessage();

            if (!addInitial)
            {
                a.Encrypt(handshake, 0, handshake.Length);
                b.Decrypt(handshake, 0, handshake.Length);
                d.Decode(handshake, 0, handshake.Length);
            }
            else
            {
                d.Decode(b.InitialData, 0, b.InitialData.Length);
            }
            Assert.AreEqual(m, d);


            if (encryptionA == EncryptionTypes.RC4Full || encryptionB == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
                Assert.IsTrue(b.Encryptor is RC4);
            }
            else if (encryptionA == EncryptionTypes.RC4Header || encryptionB == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
                Assert.IsTrue(b.Encryptor is RC4Header);
            }
            else if (encryptionA == EncryptionTypes.PlainText || encryptionB == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is PlainTextEncryption);
                Assert.IsTrue(b.Encryptor is PlainTextEncryption);
            }
        }