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:
parent
008025c9c9
commit
a9e5fff2e6
3 changed files with 73 additions and 45 deletions
|
@ -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) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue