static int
parseHandshake (tr_handshake *    handshake,
                struct evbuffer * inbuf)
{
  uint8_t name[HANDSHAKE_NAME_LEN];
  uint8_t reserved[HANDSHAKE_FLAGS_LEN];
  uint8_t hash[SHA_DIGEST_LENGTH];
  tr_torrent * tor;
  uint8_t peer_id[PEER_ID_LEN];

  dbgmsg (handshake, "payload: need %d, got %zu",
          HANDSHAKE_SIZE, evbuffer_get_length (inbuf));

  if (evbuffer_get_length (inbuf) < HANDSHAKE_SIZE)
    return READ_LATER;

  /* confirm the protocol */
  tr_peerIoReadBytes (handshake->io, inbuf, name, HANDSHAKE_NAME_LEN);
  if (memcmp (name, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN))
    return HANDSHAKE_ENCRYPTION_WRONG;

  /* read the reserved bytes */
  tr_peerIoReadBytes (handshake->io, inbuf, reserved, HANDSHAKE_FLAGS_LEN);

  /* torrent hash */
  tr_peerIoReadBytes (handshake->io, inbuf, hash, sizeof (hash));
  assert (tr_peerIoHasTorrentHash (handshake->io));
  if (!tr_torrentExists (handshake->session, hash)
      || memcmp (hash, tr_peerIoGetTorrentHash (handshake->io), SHA_DIGEST_LENGTH))
    {
      dbgmsg (handshake, "peer returned the wrong hash. wtf?");
      return HANDSHAKE_BAD_TORRENT;
    }

  /* peer_id */
  tr_peerIoReadBytes (handshake->io, inbuf, peer_id, sizeof (peer_id));
  tr_peerIoSetPeersId (handshake->io, peer_id);

  /* peer id */
  handshake->havePeerID = true;
  dbgmsg (handshake, "peer-id is [%*.*s]", PEER_ID_LEN, PEER_ID_LEN, peer_id);

  tor = tr_torrentFindFromHash (handshake->session, hash);
  if (!memcmp (peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN))
    {
      dbgmsg (handshake, "streuth!  we've connected to ourselves.");
      return HANDSHAKE_PEER_IS_SELF;
    }

  /**
  *** Extensions
  **/

  tr_peerIoEnableDHT  (handshake->io, HANDSHAKE_HAS_DHT    (reserved));
  tr_peerIoEnableLTEP (handshake->io, HANDSHAKE_HAS_LTEP    (reserved));
  tr_peerIoEnableFEXT (handshake->io, HANDSHAKE_HAS_FASTEXT (reserved));

  return HANDSHAKE_OK;
}
Exemple #2
0
static int
readHandshake( tr_handshake *    handshake,
               struct evbuffer * inbuf )
{
    uint8_t   pstrlen;
    uint8_t * pstr;
    uint8_t   reserved[HANDSHAKE_FLAGS_LEN];
    uint8_t   hash[SHA_DIGEST_LENGTH];

    dbgmsg( handshake, "payload: need %d, got %zu",
            INCOMING_HANDSHAKE_LEN, evbuffer_get_length( inbuf ) );

    if( evbuffer_get_length( inbuf ) < INCOMING_HANDSHAKE_LEN )
        return READ_LATER;

    handshake->haveReadAnythingFromPeer = TRUE;

    pstrlen = evbuffer_pullup( inbuf, 1 )[0]; /* peek, don't read. We may be
                                                 handing inbuf to AWAITING_YA */

    if( pstrlen == 19 ) /* unencrypted */
    {
        tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_NONE );

        if( handshake->encryptionMode == TR_ENCRYPTION_REQUIRED )
        {
            dbgmsg( handshake,
                    "peer is unencrypted, and we're disallowing that" );
            return tr_handshakeDone( handshake, FALSE );
        }
    }
    else /* encrypted or corrupt */
    {
        tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_RC4 );

        if( tr_peerIoIsIncoming( handshake->io ) )
        {
            dbgmsg( handshake,
                    "I think peer is sending us an encrypted handshake..." );
            setState( handshake, AWAITING_YA );
            return READ_NOW;
        }
        tr_cryptoDecrypt( handshake->crypto, 1, &pstrlen, &pstrlen );

        if( pstrlen != 19 )
        {
            dbgmsg( handshake,
                    "I think peer has sent us a corrupt handshake..." );
            return tr_handshakeDone( handshake, FALSE );
        }
    }

    evbuffer_drain( inbuf, 1 );

    /* pstr (BitTorrent) */
    pstr = tr_new( uint8_t, pstrlen + 1 );
    tr_peerIoReadBytes( handshake->io, inbuf, pstr, pstrlen );
    pstr[pstrlen] = '\0';
    if( strcmp( (char*)pstr, "BitTorrent protocol" ) )
    {
        tr_free( pstr );
        return tr_handshakeDone( handshake, FALSE );
    }
    tr_free( pstr );

    /* reserved bytes */
    tr_peerIoReadBytes( handshake->io, inbuf, reserved, sizeof( reserved ) );

    /**
    *** Extensions
    **/

    tr_peerIoEnableLTEP( handshake->io, HANDSHAKE_HAS_LTEP( reserved ) );

    tr_peerIoEnableFEXT( handshake->io, HANDSHAKE_HAS_FASTEXT( reserved ) );

    tr_peerIoEnableDHT( handshake->io, HANDSHAKE_HAS_DHT( reserved ) );

    /* torrent hash */
    tr_peerIoReadBytes( handshake->io, inbuf, hash, sizeof( hash ) );
    if( tr_peerIoIsIncoming( handshake->io ) )
    {
        if( !tr_torrentExists( handshake->session, hash ) )
        {
            dbgmsg( handshake, "peer is trying to connect to us for a torrent we don't have." );
            return tr_handshakeDone( handshake, FALSE );
        }
        else
        {
            assert( !tr_peerIoHasTorrentHash( handshake->io ) );
            tr_peerIoSetTorrentHash( handshake->io, hash );
        }
    }
    else /* outgoing */
    {
        assert( tr_peerIoHasTorrentHash( handshake->io ) );
        if( memcmp( hash, tr_peerIoGetTorrentHash( handshake->io ),
                    SHA_DIGEST_LENGTH ) )
        {
            dbgmsg( handshake, "peer returned the wrong hash. wtf?" );
            return tr_handshakeDone( handshake, FALSE );
        }
    }

    /**
    ***  If it's an incoming message, we need to send a response handshake
    **/

    if( !handshake->haveSentBitTorrentHandshake )
    {
        uint8_t msg[HANDSHAKE_SIZE];
        buildHandshakeMessage( handshake, msg );
        tr_peerIoWriteBytes( handshake->io, msg, sizeof( msg ), FALSE );
        handshake->haveSentBitTorrentHandshake = 1;
    }

    setReadState( handshake, AWAITING_PEER_ID );
    return READ_NOW;
}