コード例 #1
0
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;
}
コード例 #2
0
ファイル: handshake.c プロジェクト: dreamcat4/transmission
static int
readPeerId( tr_handshake    * handshake,
            struct evbuffer * inbuf )
{
    tr_bool peerIsGood;
    char client[128];
    tr_torrent * tor;
    const uint8_t * tor_peer_id;
    uint8_t peer_id[PEER_ID_LEN];

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

    /* peer id */
    tr_peerIoReadBytes( handshake->io, inbuf, peer_id, PEER_ID_LEN );
    tr_peerIoSetPeersId( handshake->io, peer_id );
    handshake->havePeerID = TRUE;
    tr_clientForId( client, sizeof( client ), peer_id );
    dbgmsg( handshake, "peer-id is [%s] ... isIncoming is %d", client,
            tr_peerIoIsIncoming( handshake->io ) );

    /* if we've somehow connected to ourselves, don't keep the connection */
    tor = tr_torrentFindFromHash( handshake->session, tr_peerIoGetTorrentHash( handshake->io ) );
    tor_peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );
    peerIsGood = memcmp( peer_id, tor_peer_id, PEER_ID_LEN ) != 0;
    dbgmsg( handshake, "isPeerGood == %d", (int)peerIsGood );
    return tr_handshakeDone( handshake, peerIsGood );
}
コード例 #3
0
static int
readPeerId (tr_handshake    * handshake,
            struct evbuffer * inbuf)
{
  bool connected_to_self;
  char client[128];
  uint8_t peer_id[PEER_ID_LEN];
  tr_torrent * tor;

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

  /* peer id */
  tr_peerIoReadBytes (handshake->io, inbuf, peer_id, PEER_ID_LEN);
  tr_peerIoSetPeersId (handshake->io, peer_id);
  handshake->havePeerID = true;
  tr_clientForId (client, sizeof (client), peer_id);
  dbgmsg (handshake, "peer-id is [%s] ... isIncoming is %d", client,
          tr_peerIoIsIncoming (handshake->io));

  /* if we've somehow connected to ourselves, don't keep the connection */
  tor = tr_torrentFindFromHash (handshake->session, tr_peerIoGetTorrentHash (handshake->io));
  connected_to_self = (tor != NULL) && !memcmp (peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN);

  return tr_handshakeDone (handshake, !connected_to_self);
}
コード例 #4
0
ファイル: peer-io.c プロジェクト: miracle2k/transmission
void tr_peerIoReadUint32( tr_peerIo        * io,
                          struct evbuffer  * inbuf,
                          uint32_t         * setme )
{
    uint32_t tmp;
    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof( uint32_t ) );
    *setme = ntohl( tmp );
}
コード例 #5
0
ファイル: peer-io.c プロジェクト: miracle2k/transmission
void
tr_peerIoDrain( tr_peerIo       * io,
                struct evbuffer * inbuf,
                size_t            byteCount )
{
    void * buf = tr_sessionGetBuffer( io->session );
    const size_t buflen = SESSION_BUFFER_SIZE;

    while( byteCount > 0 )
    {
        const size_t thisPass = MIN( byteCount, buflen );
        tr_peerIoReadBytes( io, inbuf, buf, thisPass );
        byteCount -= thisPass;
    }

    tr_sessionReleaseBuffer( io->session );
}
コード例 #6
0
ファイル: handshake.c プロジェクト: dreamcat4/transmission
static int
readPadD( tr_handshake *    handshake,
          struct evbuffer * inbuf )
{
    const size_t needlen = handshake->pad_d_len;
    uint8_t *    tmp;

    dbgmsg( handshake, "pad d: need %zu, got %zu",
            needlen, evbuffer_get_length( inbuf ) );
    if( evbuffer_get_length( inbuf ) < needlen )
        return READ_LATER;

    tmp = tr_new( uint8_t, needlen );
    tr_peerIoReadBytes( handshake->io, inbuf, tmp, needlen );
    tr_free( tmp );

    tr_peerIoSetEncryption( handshake->io, handshake->crypto_select );

    setState( handshake, AWAITING_HANDSHAKE );
    return READ_NOW;
}
コード例 #7
0
static int
readPadC (tr_handshake    * handshake,
          struct evbuffer * inbuf)
{
  char * padc;
  uint16_t ia_len;
  const size_t needlen = handshake->pad_c_len + sizeof (uint16_t);

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

  /* read the throwaway padc */
  padc = tr_new (char, handshake->pad_c_len);
  tr_peerIoReadBytes (handshake->io, inbuf, padc, handshake->pad_c_len);
  tr_free (padc);

  /* read ia_len */
  tr_peerIoReadUint16 (handshake->io, inbuf, &ia_len);
  dbgmsg (handshake, "ia_len is %d", (int)ia_len);
  handshake->ia_len = ia_len;
  setState (handshake, AWAITING_IA);
  return READ_NOW;
}
コード例 #8
0
ファイル: handshake.c プロジェクト: dreamcat4/transmission
static int
readCryptoProvide( tr_handshake *    handshake,
                   struct evbuffer * inbuf )
{
    /* HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide,
      len(PadC)) */

    int          i;
    uint8_t      vc_in[VC_LENGTH];
    uint8_t      req2[SHA_DIGEST_LENGTH];
    uint8_t      req3[SHA_DIGEST_LENGTH];
    uint8_t      obfuscatedTorrentHash[SHA_DIGEST_LENGTH];
    uint16_t     padc_len = 0;
    uint32_t     crypto_provide = 0;
    const size_t needlen = SHA_DIGEST_LENGTH /* HASH('req1',s) */
                           + SHA_DIGEST_LENGTH /* HASH('req2', SKEY) xor
                                                 HASH('req3', S) */
                           + VC_LENGTH
                           + sizeof( crypto_provide )
                           + sizeof( padc_len );
    tr_torrent * tor = NULL;

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

    /* TODO: confirm they sent HASH('req1',S) here? */
    evbuffer_drain( inbuf, SHA_DIGEST_LENGTH );

    /* This next piece is HASH('req2', SKEY) xor HASH('req3', S) ...
     * we can get the first half of that (the obufscatedTorrentHash)
     * by building the latter and xor'ing it with what the peer sent us */
    dbgmsg( handshake, "reading obfuscated torrent hash..." );
    evbuffer_remove( inbuf, req2, SHA_DIGEST_LENGTH );
    tr_sha1( req3, "req3", 4, handshake->mySecret, KEY_LEN, NULL );
    for( i = 0; i < SHA_DIGEST_LENGTH; ++i )
        obfuscatedTorrentHash[i] = req2[i] ^ req3[i];
    if(( tor = tr_torrentFindFromObfuscatedHash( handshake->session, obfuscatedTorrentHash )))
    {
        const tr_bool clientIsSeed = tr_torrentIsSeed( tor );
        const tr_bool peerIsSeed = tr_peerMgrPeerIsSeed( tor, tr_peerIoGetAddress( handshake->io, NULL ) );
        dbgmsg( handshake, "got INCOMING connection's encrypted handshake for torrent [%s]",
                tr_torrentName( tor ) );
        tr_peerIoSetTorrentHash( handshake->io, tor->info.hash );

        if( clientIsSeed && peerIsSeed )
        {
            dbgmsg( handshake, "another seed tried to reconnect to us!" );
            return tr_handshakeDone( handshake, FALSE );
        }
    }
    else
    {
        dbgmsg( handshake, "can't find that torrent..." );
        return tr_handshakeDone( handshake, FALSE );
    }

    /* next part: ENCRYPT(VC, crypto_provide, len(PadC), */

    tr_cryptoDecryptInit( handshake->crypto );

    tr_peerIoReadBytes( handshake->io, inbuf, vc_in, VC_LENGTH );

    tr_peerIoReadUint32( handshake->io, inbuf, &crypto_provide );
    handshake->crypto_provide = crypto_provide;
    dbgmsg( handshake, "crypto_provide is %d", (int)crypto_provide );

    tr_peerIoReadUint16( handshake->io, inbuf, &padc_len );
    dbgmsg( handshake, "padc is %d", (int)padc_len );
    handshake->pad_c_len = padc_len;
    setState( handshake, AWAITING_PAD_C );
    return READ_NOW;
}
コード例 #9
0
ファイル: handshake.c プロジェクト: dreamcat4/transmission
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;
}