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(); } }
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); }
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); }
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()); }
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); }
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); }
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); } }
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; } }
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); } }