private void EndCheckEncryption(IAsyncResult result)
        {
            var id = (PeerId) result.AsyncState;
            try
            {
                byte[] initialData;
                EncryptorFactory.EndCheckEncryption(result, out initialData);

                if (initialData != null && initialData.Length == HandshakeMessage.HandshakeLength)
                {
                    var message = new HandshakeMessage();
                    message.Decode(initialData, 0, initialData.Length);
                    handleHandshake(id, message);
                }
                else if (initialData.Length > 0)
                {
                    throw new Exception("Argh. I can't handle this scenario. It also shouldn't happen. Ever.");
                }
                else
                {
                    PeerIO.EnqueueReceiveHandshake(id.Connection, id.Decryptor, handshakeReceivedCallback, id);
                }
            }
            catch
            {
                id.Connection.Dispose();
            }
        }
Exemplo n.º 2
0
        public void EncryptorFactoryPeerAPlain()
        {
            rig.Engine.StartAll();

            rig.AddConnection(conn.Incoming);

            HandshakeMessage message = new HandshakeMessage(rig.Manager.Torrent.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);
            byte[] buffer = message.Encode();

            conn.Outgoing.EndSend(conn.Outgoing.BeginSend(buffer, 0, buffer.Length, null, null));
            conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));

            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);
        }
Exemplo n.º 3
0
        static void HandshakeReceived (bool successful, int transferred, object state)
        {
            var data = (ReceiveMessageState) state;
            PeerMessage message = null;

            if (successful) {
                data.Decryptor.Decrypt (data.Buffer, 0, transferred);
                message = new HandshakeMessage ();
                message.Decode (data.Buffer, 0, transferred);
            }

            data.Callback (successful, message, data.State);
            ClientEngine.BufferManager.FreeBuffer (data.Buffer);
            receiveCache.Enqueue (data);
        }
Exemplo n.º 4
0
        public void TestHandshake(byte[] buffer, CustomConnection connection)
        {
            // 1) Send local handshake
            SendMessage(
                new HandshakeMessage(rig.Manager.Torrent.infoHash, new string('g', 20), VersionInfo.ProtocolStringV100,
                    true, false), connection);

            // 2) Receive remote handshake
            if (buffer == null || buffer.Length == 0)
            {
                buffer = new byte[68];
                Receive(connection, buffer, 0, 68);
                decryptor.Decrypt(buffer);
            }

            var handshake = new HandshakeMessage();
            handshake.Decode(buffer, 0, buffer.Length);
            Assert.Equal(rig.Engine.PeerId, handshake.PeerId);
            Assert.Equal(VersionInfo.ProtocolStringV100, handshake.ProtocolString);
            Assert.Equal(ClientEngine.SupportsFastPeer, handshake.SupportsFastPeer);
            Assert.Equal(ClientEngine.SupportsExtended, handshake.SupportsExtendedMessaging);

            // 2) Send local bitfield
            SendMessage(new BitfieldMessage(rig.Manager.Bitfield), connection);

            // 3) Receive remote bitfield - have none
            var message = ReceiveMessage(connection);
            Assert.True(message is HaveNoneMessage || message is BitfieldMessage, "HaveNone");

            // 4) Send a few allowed fast
            SendMessage(new AllowedFastMessage(1), connection);
            SendMessage(new AllowedFastMessage(2), connection);
            SendMessage(new AllowedFastMessage(3), connection);
            SendMessage(new AllowedFastMessage(0), connection);

            // 5) Receive a few allowed fast
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
            ReceiveMessage(connection);
        }
        private void PeerATest(EncryptionTypes encryption, bool addInitial)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            rig.Engine.StartAll();

            var message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB",
                VersionInfo.ProtocolStringV100);
            var buffer = message.Encode();
            var a = new PeerAEncryption(rig.Manager.InfoHash, encryption);
            if (addInitial)
                a.AddPayload(buffer);

            rig.AddConnection(conn.Incoming);
            var result = a.BeginHandshake(conn.Outgoing, null, null);
            if (!result.AsyncWaitHandle.WaitOne(4000, true))
                Assert.True(false, "Handshake timed out");
            a.EndHandshake(result);

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

            var received = conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));
            Assert.Equal(68, received);

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

            if (encryption == EncryptionTypes.RC4Full)
                Assert.True(a.Encryptor is RC4);
            else if (encryption == EncryptionTypes.RC4Header)
                Assert.True(a.Encryptor is RC4Header);
            else if (encryption == EncryptionTypes.PlainText)
                Assert.True(a.Encryptor is RC4Header);
        }
        private void handleHandshake(PeerId id, HandshakeMessage message)
        {
            TorrentManager man = null;
            try
            {
                if (message.ProtocolString != VersionInfo.ProtocolStringV100)
                    throw new ProtocolException("Invalid protocol string in handshake");
            }
            catch (Exception ex)
            {
                Logger.Log(id.Connection, ex.Message);
                id.Connection.Dispose();
                return;
            }

            ClientEngine.MainLoop.QueueWait(delegate
            {
                for (var i = 0; i < Engine.Torrents.Count; i++)
                    if (message.infoHash == Engine.Torrents[i].InfoHash)
                        man = Engine.Torrents[i];
            });

            //FIXME: #warning FIXME: Don't stop the message loop until Dispose() and track all incoming connections
            if (man == null) // We're not hosting that torrent
            {
                Logger.Log(id.Connection, "ListenManager - Handshake requested nonexistant torrent");
                id.Connection.Dispose();
                return;
            }
            if (man.State == TorrentState.Stopped)
            {
                Logger.Log(id.Connection, "ListenManager - Handshake requested for torrent which is not running");
                id.Connection.Dispose();
                return;
            }
            if (!man.Mode.CanAcceptConnections)
            {
                Logger.Log(id.Connection, "ListenManager - Current mode does not support connections");
                id.Connection.Dispose();
                return;
            }

            id.Peer.PeerId = message.PeerId;
            id.TorrentManager = man;

            // If the handshake was parsed properly without encryption, then it definitely was not encrypted. If this is not allowed, abort
            if (id.Encryptor is PlainTextEncryption &&
                !Toolbox.HasEncryption(Engine.Settings.AllowedEncryption, EncryptionTypes.PlainText) &&
                ClientEngine.SupportsEncryption)
            {
                Logger.Log(id.Connection, "ListenManager - Encryption is required but was not active");
                id.Connection.Dispose();
                return;
            }

            message.Handle(id);
            Logger.Log(id.Connection, "ListenManager - Handshake successful handled");

            id.ClientApp = new Software(message.PeerId);

            message = new HandshakeMessage(id.TorrentManager.InfoHash, Engine.PeerId, VersionInfo.ProtocolStringV100);
            var callback = Engine.ConnectionManager.incomingConnectionAcceptedCallback;
            PeerIO.EnqueueSendMessage(id.Connection, id.Encryptor, message, id.TorrentManager.UploadLimiter,
                id.Monitor, id.TorrentManager.Monitor, callback, id);
        }
        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");
            }
        }
        public void HandshakeEncoding()
        {
            var infohash = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 12, 15, 12, 52};
            var length =
                new HandshakeMessage(new InfoHash(infohash), "12312312345645645678", VersionInfo.ProtocolStringV100,
                    false, false).Encode(buffer, offset);

            Console.WriteLine(BitConverter.ToString(buffer, offset, length));
            var peerId = Encoding.ASCII.GetBytes("12312312345645645678");
            var protocolVersion = Encoding.ASCII.GetBytes(VersionInfo.ProtocolStringV100);
            Assert.Equal(19, buffer[offset]);
            Assert.True(Toolbox.ByteMatch(protocolVersion, 0, buffer, offset + 1, 19), "2");
            Assert.True(Toolbox.ByteMatch(new byte[8], 0, buffer, offset + 20, 8), "3");
            Assert.True(Toolbox.ByteMatch(infohash, 0, buffer, offset + 28, 20), "4");
            Assert.True(Toolbox.ByteMatch(peerId, 0, buffer, offset + 48, 20), "5");
            Assert.Equal(length, 68);

            length =
                new HandshakeMessage(new InfoHash(infohash), "12312312345645645678", VersionInfo.ProtocolStringV100,
                    true, false).Encode(buffer, offset);
            Assert.Equal(BitConverter.ToString(buffer, offset, length),
                "13-42-69-74-54-6F-72-72-65-6E-74-20-70-72-6F-74-6F-63-6F-6C-00-00-00-00-00-00-00-04-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F-00-0C-0F-0C-34-31-32-33-31-32-33-31-32-33-34-35-36-34-35-36-34-35-36-37-38");
        }
 public void HandshakeDecoding()
 {
     var infohash = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 12, 15, 12, 52};
     var orig = new HandshakeMessage(new InfoHash(infohash), "12312312345645645678",
         VersionInfo.ProtocolStringV100);
     orig.Encode(buffer, offset);
     var dec = new HandshakeMessage();
     dec.Decode(buffer, offset, 68);
     Assert.True(orig.Equals(dec));
     Assert.Equal(orig.Encode(), dec.Encode());
 }
Exemplo n.º 10
0
        protected virtual void HandleHandshakeMessage(PeerId id, HandshakeMessage message)
        {
            if (!message.ProtocolString.Equals(VersionInfo.ProtocolStringV100))
            {
                Logger.Log(id.Connection, "HandShake.Handle - Invalid protocol in handshake: {0}", message.ProtocolString);
                throw new ProtocolException("Invalid protocol string");
            }

            // If we got the peer as a "compact" peer, then the peerid will be empty. In this case
            // we just copy the one that is in the handshake. 
            if (string.IsNullOrEmpty(id.Peer.PeerId))
                id.Peer.PeerId = message.PeerId;

            // If the infohash doesn't match, dump the connection
            if (message.InfoHash != id.TorrentManager.InfoHash)
            {
                Logger.Log(id.Connection, "HandShake.Handle - Invalid infohash");
                throw new TorrentException("Invalid infohash. Not tracking this torrent");
            }

            // If the peer id's don't match, dump the connection. This is due to peers faking usually
            if (id.Peer.PeerId != message.PeerId)
            {
                Logger.Log(id.Connection, "HandShake.Handle - Invalid peerid");
                throw new TorrentException("Supplied PeerID didn't match the one the tracker gave us");
            }

            // Attempt to parse the application that the peer is using
            id.ClientApp = new Software(message.PeerId);
            id.SupportsFastPeer = message.SupportsFastPeer;
            id.SupportsLTMessages = message.SupportsExtendedMessaging;

            // If they support fast peers, create their list of allowed pieces that they can request off me
            if (id.SupportsFastPeer && id.TorrentManager != null && id.TorrentManager.HasMetadata)
                id.AmAllowedFastPieces = AllowedFastAlgorithm.Calculate(id.AddressBytes, id.TorrentManager.InfoHash, (uint)id.TorrentManager.Torrent.Pieces.Count);
        }
Exemplo n.º 11
0
        private void PeerBTest(EncryptionTypes encryption)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            rig.Engine.StartAll();
            rig.AddConnection(conn.Outgoing);

            PeerBEncryption a = new PeerBEncryption(new byte[][] { rig.Manager.Torrent.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);
        }
Exemplo n.º 12
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 byte[][] { 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);
            }
        }
Exemplo n.º 13
0
        private static void HandshakeReceived(bool succeeded, int count, object state)
        {
            EncryptorAsyncResult result = (EncryptorAsyncResult)state;
            IConnection connection = result.Id.Connection;

            try
            {
                if (!succeeded)
                    throw new EncryptionException("Couldn't receive the handshake");

                result.Available += count;
                if (count < result.Buffer.Length)
                {
                    NetworkIO.EnqueueReceive(connection, result.Buffer, result.Available, result.Buffer.Length - result.Available,
                                    HandshakeReceivedCallback, result);
                    return;
                }

                HandshakeMessage message = new HandshakeMessage();
                message.Decode(result.Buffer, 0, result.Buffer.Length);
                bool valid = message.ProtocolString == VersionInfo.ProtocolStringV100;
                EncryptionTypes usable = CheckRC4(result.Id);

                bool canUseRC4 = Toolbox.HasEncryption(usable, EncryptionTypes.RC4Header) || Toolbox.HasEncryption(usable, EncryptionTypes.RC4Full);
                // If encryption is disabled and we received an invalid handshake - abort!
                if (valid)
                {
                    result.InitialData = result.Buffer;
                    result.Complete();
                    return;
                }
                if (!canUseRC4 && !valid)
                {
                    result.Complete(new EncryptionException("Invalid handshake received and no decryption works"));
                    return;
                }
                if (canUseRC4)
                {
                    // The data we just received was part of an encrypted handshake and was *not* the BitTorrent handshake
                    result.EncSocket = new PeerBEncryption(result.SKeys, EncryptionTypes.All);
                    result.EncSocket.BeginHandshake(connection, result.Buffer, 0, result.Buffer.Length, CompletedEncryptedHandshakeCallback, result);
                }
                else
                {
                    result.Complete();
                }
            }
            catch (Exception ex)
            {
                result.Complete(ex);
                return;
            }
        }
Exemplo n.º 14
0
        private void PeerHandshakeReceived(bool succeeded, int count, object state)
        {
            PeerId id = (PeerId)state;
            string reason = null;
            bool cleanUp = false;
            PeerMessage msg;

            try
            {
                // If the connection is closed, just return
                if (!succeeded)
                {
                    CleanupSocket(id, "Handshaking failed");
                    return;
                }
                // Decode the handshake and handle it
                id.Decryptor.Decrypt(id.recieveBuffer.Array, id.recieveBuffer.Offset, count);
                msg = new HandshakeMessage();
                msg.Decode(id.recieveBuffer, 0, count);
                msg.Handle(id);

                Logger.Log(id.Connection, "ConnectionManager - Handshake recieved");
                if (id.SupportsFastPeer && ClientEngine.SupportsFastPeer)
                {
                    if (id.TorrentManager.Bitfield.AllFalse || id.TorrentManager.IsInitialSeeding)
                        msg = new HaveNoneMessage();

                    else if (id.TorrentManager.Bitfield.AllTrue)
                        msg = new HaveAllMessage();

                    else
                        msg = new BitfieldMessage(id.TorrentManager.Bitfield);
                }
                else if (id.TorrentManager.IsInitialSeeding)
                {
                    BitField btfld = new BitField(id.TorrentManager.Bitfield.Length);
                    btfld.SetAll(false);
                    msg = new BitfieldMessage(btfld);
                }
                else
                {
                    msg = new BitfieldMessage(id.TorrentManager.Bitfield);
                }

                if (id.SupportsLTMessages && ClientEngine.SupportsExtended)
                {
                    MessageBundle bundle = new MessageBundle();
                    bundle.Messages.Add(new ExtendedHandshakeMessage());
                    bundle.Messages.Add(msg);
                    msg = bundle;
                }

                //ClientEngine.BufferManager.FreeBuffer(ref id.recieveBuffer);
                SendMessage(id, msg, this.bitfieldSentCallback);
            }
            catch (TorrentException)
            {
                Logger.Log(id.Connection, "ConnectionManager - Couldn't decode the message");
                reason = "Couldn't decode handshake";
                cleanUp = true;
                return;
            }
            finally
            {
                if (cleanUp)
                    CleanupSocket(id, reason);
            }
        }