* fix the `req->length == (uint32_t)( ((block)==((msgs->torrent)->blockCount-1))' bug.

* there seems to be a pattern for peers that were (intentionally?) giving incomplete data to trigger the bug above.  when a peer does this, give them a strike on its three-strikes-and-you're-banned count
This commit is contained in:
Charles Kerr 2007-11-13 05:36:43 +00:00
parent 008025c9c9
commit a9e5fff2e6
3 changed files with 73 additions and 45 deletions

View File

@ -812,6 +812,20 @@ broadcastGotBlock( Torrent * t, uint32_t index, uint32_t offset, uint32_t length
tr_free( peers );
}
static void
addStrike( Torrent * t, tr_peer * peer )
{
tordbg( t, "increasing peer %s strike count to %d", tr_peerIoAddrStr(&peer->in_addr,peer->port), peer->strikes+1 );
if( ++peer->strikes >= MAX_BAD_PIECES_PER_PEER )
{
struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
atom->myflags |= MYFLAG_BANNED;
peer->doPurge = 1;
tordbg( t, "banning peer %s", tr_peerIoAddrStr(&atom->addr,atom->port) );
}
}
static void
msgsCallbackFunc( void * vpeer, void * vevent, void * vt )
{
@ -855,6 +869,11 @@ msgsCallbackFunc( void * vpeer, void * vevent, void * vt )
broadcastGotBlock( t, e->pieceIndex, e->offset, e->length );
break;
case TR_PEERMSG_GOT_ASSERT_ERROR:
addStrike( t, peer );
peer->doPurge = 1;
break;
case TR_PEERMSG_GOT_ERROR:
peer->doPurge = 1;
break;
@ -1069,24 +1088,14 @@ tr_peerMgrSetBlame( tr_peerMgr * manager,
peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
for( i=0; i<peerCount; ++i )
{
struct peer_atom * atom;
tr_peer * peer;
peer = peers[i];
if( !tr_bitfieldHas( peer->blame, pieceIndex ) )
continue;
++peer->strikes;
tordbg( t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
tr_peerIoAddrStr(&peer->in_addr,peer->port),
pieceIndex, (int)peer->strikes );
if( peer->strikes < MAX_BAD_PIECES_PER_PEER )
continue;
atom = getExistingAtom( t, &peer->in_addr );
atom->myflags |= MYFLAG_BANNED;
peer->doPurge = 1;
tordbg( t, "banning peer %s due to corrupt data", tr_peerIoAddrStr(&atom->addr,atom->port) );
tr_peer * peer = peers[i];
if( tr_bitfieldHas( peer->blame, pieceIndex ) )
{
tordbg( t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
tr_peerIoAddrStr(&peer->in_addr,peer->port),
pieceIndex, (int)peer->strikes+1 );
addStrike( t, peer );
}
}
}
}

View File

@ -250,6 +250,14 @@ publish( tr_peermsgs * msgs, tr_peermsgs_event * e )
tr_publisherPublish( msgs->publisher, msgs->info, e );
}
static void
fireGotAssertError( tr_peermsgs * msgs )
{
tr_peermsgs_event e = blankEvent;
e.eventType = TR_PEERMSG_GOT_ASSERT_ERROR;
publish( msgs, &e );
}
static void
fireGotError( tr_peermsgs * msgs )
{
@ -968,12 +976,13 @@ messageLengthIsCorrect( const tr_peermsgs * msg, uint8_t id, uint32_t len )
}
}
static void
static int
clientGotBlock( tr_peermsgs * msgs, const uint8_t * block, const struct peer_request * req );
static int
readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf )
{
int ret;
uint8_t id;
uint32_t ui32;
uint32_t msglen = msgs->incomingMessageLength;
@ -985,8 +994,6 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf )
tr_peerIoReadUint8( msgs->io, inbuf, &id );
dbgmsg( msgs, "got BT id %d, len %d, buffer size is %d", (int)id, (int)msglen, (int)EVBUFFER_LENGTH(inbuf) );
assert( messageLengthIsCorrect( msgs, id, msglen ) );
if( !messageLengthIsCorrect( msgs, id, msglen ) )
{
dbgmsg( msgs, "bad packet - BT message #%d with a length of %d", (int)id, (int)msglen );
@ -995,7 +1002,7 @@ assert( messageLengthIsCorrect( msgs, id, msglen ) );
}
--msglen;
ret = 0;
switch( id )
{
case BT_CHOKE:
@ -1073,7 +1080,7 @@ assert( messageLengthIsCorrect( msgs, id, msglen ) );
block = tr_new( uint8_t, req.length );
tr_peerIoReadBytes( msgs->io, inbuf, block, req.length );
dbgmsg( msgs, "got a Block %u:%u->%u", req.index, req.offset, req.length );
clientGotBlock( msgs, block, &req );
ret = clientGotBlock( msgs, block, &req );
tr_free( block );
break;
}
@ -1134,14 +1141,27 @@ assert( 0 );
break;
}
dbgmsg( msgs, "startBufLen was %d, msglen was %d, current inbuf len is %d", (int)startBufLen, (int)(msglen+1), (int)EVBUFFER_LENGTH(inbuf) );
assert( msglen + 1 == msgs->incomingMessageLength );
assert( EVBUFFER_LENGTH(inbuf) == startBufLen - msgs->incomingMessageLength );
msgs->incomingMessageLength = -1;
msgs->state = AWAITING_BT_LENGTH;
return READ_AGAIN;
if( ret == (int)TR_ERROR_ASSERT )
{
fireGotAssertError( msgs );
return READ_DONE;
}
else if( ret == TR_OK )
{
assert( msglen + 1 == msgs->incomingMessageLength );
assert( EVBUFFER_LENGTH(inbuf) == startBufLen - msgs->incomingMessageLength );
msgs->incomingMessageLength = -1;
msgs->state = AWAITING_BT_LENGTH;
return READ_AGAIN;
}
else
{
fireGotError( msgs );
return READ_DONE;
}
}
static void
@ -1219,7 +1239,7 @@ addPeerToBlamefield( tr_peermsgs * msgs, uint32_t index )
tr_bitfieldAdd( msgs->info->blame, index );
}
static void
static int
clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_request * req )
{
int i;
@ -1229,8 +1249,13 @@ clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_requ
assert( msgs != NULL );
assert( req != NULL );
assert( req->length > 0 );
assert( req->length == (uint32_t)tr_torBlockCountBytes( msgs->torrent, block ) );
if( req->length != (uint32_t)tr_torBlockCountBytes( msgs->torrent, block ) )
{
dbgmsg( msgs, "wrong block size -- expected %u, got %d",
tr_torBlockCountBytes( msgs->torrent, block ), req->length );
return TR_ERROR_ASSERT;
}
/* save the block */
dbgmsg( msgs, "got block %u:%u->%u", req->index, req->offset, req->length );
@ -1243,7 +1268,7 @@ clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_requ
if( myreq == NULL ) {
clientGotUnwantedBlock( msgs, req );
dbgmsg( msgs, "we didn't ask for this message..." );
return;
return 0;
}
dbgmsg( msgs, "got block %u:%u->%u (turnaround time %d secs)",
@ -1259,7 +1284,7 @@ clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_requ
if( tr_cpBlockIsComplete( tor->completion, block ) ) {
dbgmsg( msgs, "we have this block already..." );
clientGotUnwantedBlock( msgs, req );
return;
return 0;
}
/**
@ -1270,16 +1295,7 @@ clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_requ
clientGotBytes( msgs, req->length );
i = tr_ioWrite( tor, req->index, req->offset, req->length, data );
if( i )
return;
#warning this sanity check is here to help track down the excess corrupt data bug, but is expensive and should be removed before the next release
{
uint8_t * check = tr_new( uint8_t, req->length );
const int val = tr_ioRead( tor, req->index, req->offset, req->length, check );
assert( !val );
assert( !memcmp( check, data, req->length ) );
tr_free( check );
}
return 0;
tr_cpBlockAdd( tor->completion, block );
@ -1296,11 +1312,13 @@ clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_requ
if( tr_ioHash( tor, req->index ) )
{
gotBadPiece( msgs, req->index );
return;
return 0;
}
fireClientHave( msgs, req->index );
}
return 0;
}
static ReadState

View File

@ -65,6 +65,7 @@ typedef enum
TR_PEERMSG_CLIENT_BLOCK,
TR_PEERMSG_PEER_PROGRESS,
TR_PEERMSG_GOT_ERROR,
TR_PEERMSG_GOT_ASSERT_ERROR,
TR_PEERMSG_CANCEL,
TR_PEERMSG_NEED_REQ
}