1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-19 18:25:38 +00:00

* 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 ); 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 static void
msgsCallbackFunc( void * vpeer, void * vevent, void * vt ) 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 ); broadcastGotBlock( t, e->pieceIndex, e->offset, e->length );
break; break;
case TR_PEERMSG_GOT_ASSERT_ERROR:
addStrike( t, peer );
peer->doPurge = 1;
break;
case TR_PEERMSG_GOT_ERROR: case TR_PEERMSG_GOT_ERROR:
peer->doPurge = 1; peer->doPurge = 1;
break; break;
@ -1069,24 +1088,14 @@ tr_peerMgrSetBlame( tr_peerMgr * manager,
peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount ); peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
for( i=0; i<peerCount; ++i ) for( i=0; i<peerCount; ++i )
{ {
struct peer_atom * atom; tr_peer * peer = peers[i];
tr_peer * peer; if( tr_bitfieldHas( peer->blame, pieceIndex ) )
{
peer = peers[i]; tordbg( t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
if( !tr_bitfieldHas( peer->blame, pieceIndex ) ) tr_peerIoAddrStr(&peer->in_addr,peer->port),
continue; pieceIndex, (int)peer->strikes+1 );
addStrike( t, peer );
++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) );
} }
} }
} }

View file

@ -250,6 +250,14 @@ publish( tr_peermsgs * msgs, tr_peermsgs_event * e )
tr_publisherPublish( msgs->publisher, msgs->info, 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 static void
fireGotError( tr_peermsgs * msgs ) 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 ); clientGotBlock( tr_peermsgs * msgs, const uint8_t * block, const struct peer_request * req );
static int static int
readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf ) readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf )
{ {
int ret;
uint8_t id; uint8_t id;
uint32_t ui32; uint32_t ui32;
uint32_t msglen = msgs->incomingMessageLength; uint32_t msglen = msgs->incomingMessageLength;
@ -985,8 +994,6 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf )
tr_peerIoReadUint8( msgs->io, inbuf, &id ); 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) ); 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 ) ) if( !messageLengthIsCorrect( msgs, id, msglen ) )
{ {
dbgmsg( msgs, "bad packet - BT message #%d with a length of %d", (int)id, (int)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; --msglen;
ret = 0;
switch( id ) switch( id )
{ {
case BT_CHOKE: case BT_CHOKE:
@ -1073,7 +1080,7 @@ assert( messageLengthIsCorrect( msgs, id, msglen ) );
block = tr_new( uint8_t, req.length ); block = tr_new( uint8_t, req.length );
tr_peerIoReadBytes( msgs->io, inbuf, block, req.length ); tr_peerIoReadBytes( msgs->io, inbuf, block, req.length );
dbgmsg( msgs, "got a Block %u:%u->%u", req.index, req.offset, 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 ); tr_free( block );
break; break;
} }
@ -1134,14 +1141,27 @@ assert( 0 );
break; break;
} }
dbgmsg( msgs, "startBufLen was %d, msglen was %d, current inbuf len is %d", (int)startBufLen, (int)(msglen+1), (int)EVBUFFER_LENGTH(inbuf) ); 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; if( ret == (int)TR_ERROR_ASSERT )
msgs->state = AWAITING_BT_LENGTH; {
return READ_AGAIN; 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 static void
@ -1219,7 +1239,7 @@ addPeerToBlamefield( tr_peermsgs * msgs, uint32_t index )
tr_bitfieldAdd( msgs->info->blame, index ); tr_bitfieldAdd( msgs->info->blame, index );
} }
static void static int
clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_request * req ) clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_request * req )
{ {
int i; int i;
@ -1229,8 +1249,13 @@ clientGotBlock( tr_peermsgs * msgs, const uint8_t * data, const struct peer_requ
assert( msgs != NULL ); assert( msgs != NULL );
assert( req != 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 */ /* save the block */
dbgmsg( msgs, "got block %u:%u->%u", req->index, req->offset, req->length ); 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 ) { if( myreq == NULL ) {
clientGotUnwantedBlock( msgs, req ); clientGotUnwantedBlock( msgs, req );
dbgmsg( msgs, "we didn't ask for this message..." ); dbgmsg( msgs, "we didn't ask for this message..." );
return; return 0;
} }
dbgmsg( msgs, "got block %u:%u->%u (turnaround time %d secs)", 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 ) ) { if( tr_cpBlockIsComplete( tor->completion, block ) ) {
dbgmsg( msgs, "we have this block already..." ); dbgmsg( msgs, "we have this block already..." );
clientGotUnwantedBlock( msgs, req ); 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 ); clientGotBytes( msgs, req->length );
i = tr_ioWrite( tor, req->index, req->offset, req->length, data ); i = tr_ioWrite( tor, req->index, req->offset, req->length, data );
if( i ) if( i )
return; return 0;
#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 );
}
tr_cpBlockAdd( tor->completion, block ); 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 ) ) if( tr_ioHash( tor, req->index ) )
{ {
gotBadPiece( msgs, req->index ); gotBadPiece( msgs, req->index );
return; return 0;
} }
fireClientHave( msgs, req->index ); fireClientHave( msgs, req->index );
} }
return 0;
} }
static ReadState static ReadState

View file

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