示例#1
0
static void
gotError( tr_peerIo  * io,
          short        what,
          void       * vhandshake )
{
    int errcode = errno;
    tr_handshake * handshake = vhandshake;

    if( io->utp_socket && !io->isIncoming && handshake->state == AWAITING_YB ) {
        /* This peer probably doesn't speak uTP. */
        tr_torrent *tor =
            tr_peerIoHasTorrentHash( io ) ?
            tr_torrentFindFromHash( handshake->session,
                                    tr_peerIoGetTorrentHash( io ) ) :
            NULL;
        /* Don't mark a peer as non-uTP unless it's really a connect failure. */
        if( tor && ( errcode == ETIMEDOUT || errcode == ECONNREFUSED ) ) {
            tr_torrentLock( tor );
            tr_peerMgrSetUtpFailed( tor,
                                    tr_peerIoGetAddress( io, NULL ),
                                    TRUE );
            tr_torrentUnlock( tor );
        }

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

    /* if the error happened while we were sending a public key, we might
     * have encountered a peer that doesn't do encryption... reconnect and
     * try a plaintext handshake */
    if( ( ( handshake->state == AWAITING_YB )
        || ( handshake->state == AWAITING_VC ) )
      && ( handshake->encryptionMode != TR_ENCRYPTION_REQUIRED )
      && ( !tr_peerIoReconnect( handshake->io ) ) )
    {
        uint8_t msg[HANDSHAKE_SIZE];

        dbgmsg( handshake, "handshake failed, trying plaintext..." );
        buildHandshakeMessage( handshake, msg );
        handshake->haveSentBitTorrentHandshake = 1;
        setReadState( handshake, AWAITING_HANDSHAKE );
        tr_peerIoWriteBytes( handshake->io, msg, sizeof( msg ), FALSE );
    }
    else
    {
        dbgmsg( handshake, "libevent got an error what==%d, errno=%d (%s)",
               (int)what, errno, tr_strerror( errno ) );
        tr_handshakeDone( handshake, FALSE );
    }
}
示例#2
0
static int
readYa( tr_handshake *    handshake,
        struct evbuffer * inbuf )
{
    uint8_t        ya[KEY_LEN];
    uint8_t *      walk, outbuf[KEY_LEN + PadB_MAXLEN];
    const uint8_t *myKey, *secret;
    int            len;

    dbgmsg( handshake, "in readYa... need %d, have %zu",
            KEY_LEN, evbuffer_get_length( inbuf ) );
    if( evbuffer_get_length( inbuf ) < KEY_LEN )
        return READ_LATER;

    /* read the incoming peer's public key */
    evbuffer_remove( inbuf, ya, KEY_LEN );
    secret = tr_cryptoComputeSecret( handshake->crypto, ya );
    memcpy( handshake->mySecret, secret, KEY_LEN );
    tr_sha1( handshake->myReq1, "req1", 4, secret, KEY_LEN, NULL );

    dbgmsg( handshake, "sending B->A: Diffie Hellman Yb, PadB" );
    /* send our public key to the peer */
    walk = outbuf;
    myKey = tr_cryptoGetMyPublicKey( handshake->crypto, &len );
    memcpy( walk, myKey, len );
    walk += len;
    len = tr_cryptoRandInt( PadB_MAXLEN );
    tr_cryptoRandBuf( walk, len );
    walk += len;

    setReadState( handshake, AWAITING_PAD_A );
    tr_peerIoWriteBytes( handshake->io, outbuf, walk - outbuf, FALSE );
    return READ_NOW;
}
示例#3
0
void
tr_peerIoWriteUint32( tr_peerIo        * io,
                      struct evbuffer  * outbuf,
                      uint32_t           writeme )
{
    const uint32_t tmp = htonl( writeme );
    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof( uint32_t ) );
}
示例#4
0
tr_handshake*
tr_handshakeNew (tr_peerIo           * io,
                 tr_encryption_mode    encryptionMode,
                 handshakeDoneCB       doneCB,
                 void                * doneUserData)
{
  tr_handshake * handshake;
  tr_session * session = tr_peerIoGetSession (io);

  handshake = tr_new0 (tr_handshake, 1);
  handshake->io = io;
  handshake->crypto = tr_peerIoGetCrypto (io);
  handshake->encryptionMode = encryptionMode;
  handshake->doneCB = doneCB;
  handshake->doneUserData = doneUserData;
  handshake->session = session;
  handshake->timeout_timer = evtimer_new (session->event_base, handshakeTimeout, handshake);
  tr_timerAdd (handshake->timeout_timer, HANDSHAKE_TIMEOUT_SEC, 0);

  tr_peerIoRef (io); /* balanced by the unref in tr_handshakeFree */
  tr_peerIoSetIOFuncs (handshake->io, canRead, NULL, gotError, handshake);
  tr_peerIoSetEncryption (io, PEER_ENCRYPTION_NONE);

  if (tr_peerIoIsIncoming (handshake->io))
    {
      setReadState (handshake, AWAITING_HANDSHAKE);
    }
  else if (encryptionMode != TR_CLEAR_PREFERRED)
    {
      sendYa (handshake);
    }
  else
    {
      uint8_t msg[HANDSHAKE_SIZE];
      buildHandshakeMessage (handshake, msg);

      handshake->haveSentBitTorrentHandshake = 1;
      setReadState (handshake, AWAITING_HANDSHAKE);
      tr_peerIoWriteBytes (handshake->io, msg, sizeof (msg), false);
    }

  return handshake;
}
示例#5
0
/* 1 A->B: Diffie Hellman Ya, PadA */
static void
sendYa( tr_handshake * handshake )
{
    int               len;
    const uint8_t *   public_key;
    char              outbuf[ KEY_LEN + PadA_MAXLEN ], *walk=outbuf;

    /* add our public key (Ya) */
    public_key = tr_cryptoGetMyPublicKey( handshake->crypto, &len );
    assert( len == KEY_LEN );
    assert( public_key );
    memcpy( walk, public_key, len );
    walk += len;

    /* add some bullshit padding */
    len = tr_cryptoRandInt( PadA_MAXLEN );
    tr_cryptoRandBuf( walk, len );
    walk += len;

    /* send it */
    setReadState( handshake, AWAITING_YB );
    tr_peerIoWriteBytes( handshake->io, outbuf, walk - outbuf, FALSE );
}
示例#6
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;
}