(libT) allow custom blocklists... now all you need to do is place a file in the blocklists/ folder and Transmission will automatically use it the next time it starts.
This commit is contained in:
parent
d2459fa2af
commit
f0229ed8ad
|
@ -14,6 +14,7 @@
|
|||
#include <stdlib.h> /* free */
|
||||
#include <string.h>
|
||||
|
||||
#include <libgen.h> /* basename */
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -89,7 +90,14 @@ blocklistLoad( tr_blocklist * b )
|
|||
b->byteCount = st.st_size;
|
||||
b->ruleCount = st.st_size / sizeof( struct tr_ip_range );
|
||||
b->fd = fd;
|
||||
tr_inf( _( "Blocklist contains %'u entries" ), (unsigned int)b->ruleCount );
|
||||
|
||||
{
|
||||
char * name;
|
||||
char buf[MAX_PATH_LENGTH];
|
||||
tr_strlcpy( buf, b->filename, sizeof( buf ) );
|
||||
name = basename( buf );
|
||||
tr_inf( _( "Blocklist \"%s\" contains %'u entries" ), name, (unsigned int)b->ruleCount );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -133,6 +141,12 @@ _tr_blocklistNew( const char * filename, int isEnabled )
|
|||
return b;
|
||||
}
|
||||
|
||||
const char*
|
||||
_tr_blocklistGetFilename( const tr_blocklist * b )
|
||||
{
|
||||
return b->filename;
|
||||
}
|
||||
|
||||
void
|
||||
_tr_blocklistFree( tr_blocklist * b )
|
||||
{
|
||||
|
@ -142,9 +156,16 @@ _tr_blocklistFree( tr_blocklist * b )
|
|||
}
|
||||
|
||||
int
|
||||
_tr_blocklistGetRuleCount( tr_blocklist * b )
|
||||
_tr_blocklistExists( const tr_blocklist * b )
|
||||
{
|
||||
blocklistEnsureLoaded( b );
|
||||
struct stat st;
|
||||
return !stat( b->filename, &st );
|
||||
}
|
||||
|
||||
int
|
||||
_tr_blocklistGetRuleCount( const tr_blocklist * b )
|
||||
{
|
||||
blocklistEnsureLoaded( (tr_blocklist*)b );
|
||||
|
||||
return b->ruleCount;
|
||||
}
|
||||
|
@ -185,13 +206,6 @@ _tr_blocklistHasAddress( tr_blocklist * b, const struct in_addr * addr )
|
|||
return range != NULL;
|
||||
}
|
||||
|
||||
int
|
||||
_tr_blocklistExists( const tr_blocklist * b )
|
||||
{
|
||||
struct stat st;
|
||||
return !stat( b->filename, &st );
|
||||
}
|
||||
|
||||
int
|
||||
_tr_blocklistSetContent( tr_blocklist * b,
|
||||
const char * filename )
|
||||
|
@ -255,7 +269,14 @@ _tr_blocklistSetContent( tr_blocklist * b,
|
|||
++lineCount;
|
||||
}
|
||||
|
||||
tr_inf( _( "Blocklist updated with %'d entries" ), lineCount );
|
||||
{
|
||||
char * name;
|
||||
char buf[MAX_PATH_LENGTH];
|
||||
tr_strlcpy( buf, b->filename, sizeof( buf ) );
|
||||
name = basename( buf );
|
||||
tr_inf( _( "Blocklist \"%s\" updated with %'d entries" ), name, lineCount );
|
||||
}
|
||||
|
||||
|
||||
fclose( out );
|
||||
fclose( in );
|
||||
|
|
|
@ -17,12 +17,13 @@ struct in_addr;
|
|||
typedef struct tr_blocklist tr_blocklist;
|
||||
|
||||
tr_blocklist* _tr_blocklistNew ( const char * filename, int isEnabled );
|
||||
void _tr_blocklistFree ( tr_blocklist * b );
|
||||
int _tr_blocklistGetRuleCount( tr_blocklist * b );
|
||||
int _tr_blocklistIsEnabled ( tr_blocklist * b );
|
||||
void _tr_blocklistSetEnabled ( tr_blocklist * b, int isEnabled );
|
||||
int _tr_blocklistHasAddress ( tr_blocklist * b, const struct in_addr * addr );
|
||||
int _tr_blocklistExists ( const tr_blocklist * b );
|
||||
int _tr_blocklistSetContent ( tr_blocklist * b, const char * filename );
|
||||
int _tr_blocklistExists ( const tr_blocklist * );
|
||||
const char* _tr_blocklistGetFilename ( const tr_blocklist * );
|
||||
int _tr_blocklistGetRuleCount( const tr_blocklist * );
|
||||
void _tr_blocklistFree ( tr_blocklist * );
|
||||
int _tr_blocklistIsEnabled ( tr_blocklist * );
|
||||
void _tr_blocklistSetEnabled ( tr_blocklist *, int isEnabled );
|
||||
int _tr_blocklistHasAddress ( tr_blocklist *, const struct in_addr * addr );
|
||||
int _tr_blocklistSetContent ( tr_blocklist *, const char * filename );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1015,7 +1015,7 @@ tr_peerMgrAddIncoming( tr_peerMgr * manager,
|
|||
{
|
||||
managerLock( manager );
|
||||
|
||||
if( tr_blocklistHasAddress( manager->handle, addr ) )
|
||||
if( tr_sessionIsAddressBlocked( manager->handle, addr ) )
|
||||
{
|
||||
tr_dbg( "Banned IP address \"%s\" tried to connect to us",
|
||||
inet_ntoa( *addr ) );
|
||||
|
@ -1053,7 +1053,7 @@ tr_peerMgrAddPex( tr_peerMgr * manager,
|
|||
managerLock( manager );
|
||||
|
||||
t = getExistingTorrent( manager, torrentHash );
|
||||
if( !tr_blocklistHasAddress( t->manager->handle, &pex->in_addr ) )
|
||||
if( !tr_sessionIsAddressBlocked( t->manager->handle, &pex->in_addr ) )
|
||||
ensureAtomExists( t, &pex->in_addr, pex->port, pex->flags, from );
|
||||
|
||||
managerUnlock( manager );
|
||||
|
@ -1799,7 +1799,7 @@ getPeerCandidates( Torrent * t, int * setmeSize )
|
|||
}
|
||||
|
||||
/* Don't connect to peers in our blocklist */
|
||||
if( tr_blocklistHasAddress( t->manager->handle, &atom->addr ) )
|
||||
if( tr_sessionIsAddressBlocked( t->manager->handle, &atom->addr ) )
|
||||
continue;
|
||||
|
||||
ret[retCount++] = atom;
|
||||
|
|
|
@ -30,7 +30,7 @@ testWildcard( const char * in, const char * expected )
|
|||
{
|
||||
int ok;
|
||||
char * str = cidrize( in );
|
||||
fprintf( stderr, "in [%s] out [%s] should be [%s]\n", in, str, expected );
|
||||
/* fprintf( stderr, "in [%s] out [%s] should be [%s]\n", in, str, expected ); */
|
||||
ok = expected ? !strcmp( expected, str ) : !str;
|
||||
tr_free( str );
|
||||
return ok;
|
||||
|
|
|
@ -116,6 +116,71 @@ tr_sessionSetEncryption( tr_session * session, tr_encryption_mode mode )
|
|||
****
|
||||
***/
|
||||
|
||||
static void
|
||||
loadBlocklists( tr_session * session )
|
||||
{
|
||||
int binCount = 0;
|
||||
int newCount = 0;
|
||||
struct stat sb;
|
||||
char dirname[MAX_PATH_LENGTH];
|
||||
DIR * odir = NULL;
|
||||
tr_list * list = NULL;
|
||||
const int isEnabled = session->isBlocklistEnabled;
|
||||
|
||||
/* walk through the directory and find blocklists */
|
||||
tr_buildPath( dirname, sizeof( dirname ), session->configDir, "blocklists", NULL );
|
||||
if( !stat( dirname, &sb ) && S_ISDIR( sb.st_mode ) && (( odir = opendir( dirname ))))
|
||||
{
|
||||
struct dirent *d;
|
||||
for( d=readdir( odir ); d; d=readdir( odir ) )
|
||||
{
|
||||
char filename[MAX_PATH_LENGTH];
|
||||
|
||||
if( !d->d_name || d->d_name[0]=='.' ) /* skip dotfiles, ., and .. */
|
||||
continue;
|
||||
|
||||
tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
|
||||
|
||||
if( tr_stringEndsWith( filename, ".bin" ) )
|
||||
{
|
||||
/* if we don't already have this blocklist, add it */
|
||||
if( !tr_list_find( list, filename, (TrListCompareFunc)strcmp ) )
|
||||
{
|
||||
tr_list_append( &list, _tr_blocklistNew( filename, isEnabled ) );
|
||||
++binCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* strip out the file suffix, if there is one, and add ".bin" instead */
|
||||
tr_blocklist * b;
|
||||
const char * dot = strrchr( d->d_name, '.' );
|
||||
const int len = dot ? dot - d->d_name : (int)strlen( d->d_name );
|
||||
char tmp[MAX_PATH_LENGTH];
|
||||
snprintf( tmp, sizeof( tmp ),
|
||||
"%s%c%*.*s.bin", dirname, TR_PATH_DELIMITER, len, len, d->d_name );
|
||||
b = _tr_blocklistNew( tmp, isEnabled );
|
||||
_tr_blocklistSetContent( b, filename );
|
||||
tr_list_append( &list, b );
|
||||
++newCount;
|
||||
}
|
||||
}
|
||||
|
||||
closedir( odir );
|
||||
}
|
||||
|
||||
session->blocklists = list;
|
||||
|
||||
if( binCount )
|
||||
tr_dbg( "Found %d blocklists in \"%s\"", binCount, dirname );
|
||||
if( newCount )
|
||||
tr_dbg( "Found %d new blocklists in \"%s\"", newCount, dirname );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static void metainfoLookupRescan( tr_handle * h );
|
||||
|
||||
tr_handle *
|
||||
|
@ -206,8 +271,8 @@ tr_sessionInitFull( const char * configDir,
|
|||
/* initialize the blocklist */
|
||||
tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists", NULL );
|
||||
tr_mkdirp( filename, 0777 );
|
||||
tr_buildPath( filename, sizeof( filename ), h->configDir, "blocklists", "level1.bin", NULL );
|
||||
h->blocklist = _tr_blocklistNew( filename, isBlocklistEnabled );
|
||||
h->isBlocklistEnabled = isBlocklistEnabled;
|
||||
loadBlocklists( h );
|
||||
|
||||
tr_statsInit( h );
|
||||
|
||||
|
@ -485,8 +550,7 @@ tr_sessionClose( tr_handle * h )
|
|||
while( !h->isClosed && !deadlineReached( deadline ) )
|
||||
tr_wait( 100 );
|
||||
|
||||
_tr_blocklistFree( h->blocklist );
|
||||
h->blocklist = NULL;
|
||||
tr_list_free( &h->blocklists, (TrListForeachFunc)_tr_blocklistFree );
|
||||
tr_webClose( &h->web );
|
||||
|
||||
tr_eventClose( h );
|
||||
|
@ -535,11 +599,14 @@ tr_sessionLoadTorrents ( tr_handle * h,
|
|||
tr_torrent * tor;
|
||||
char filename[MAX_PATH_LENGTH];
|
||||
tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
|
||||
tr_ctorSetMetainfoFromFile( ctor, filename );
|
||||
tor = tr_torrentNew( h, ctor, NULL );
|
||||
if( tor ) {
|
||||
tr_list_append( &list, tor );
|
||||
n++;
|
||||
if( tr_stringEndsWith( filename, ".torrent" ) )
|
||||
{
|
||||
tr_ctorSetMetainfoFromFile( ctor, filename );
|
||||
tor = tr_torrentNew( h, ctor, NULL );
|
||||
if( tor ) {
|
||||
tr_list_append( &list, tor );
|
||||
++n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -600,39 +667,66 @@ tr_sessionIsPortForwardingEnabled( const tr_handle * h )
|
|||
***/
|
||||
|
||||
int
|
||||
tr_blocklistGetRuleCount( tr_handle * handle )
|
||||
tr_blocklistGetRuleCount( const tr_session * session )
|
||||
{
|
||||
return _tr_blocklistGetRuleCount( handle->blocklist );
|
||||
int n = 0;
|
||||
tr_list * l;
|
||||
for( l=session->blocklists; l; l=l->next )
|
||||
n += _tr_blocklistGetRuleCount( l->data );
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
tr_blocklistIsEnabled( const tr_handle * handle )
|
||||
tr_blocklistIsEnabled( const tr_session * session )
|
||||
{
|
||||
return _tr_blocklistIsEnabled( handle->blocklist );
|
||||
return session->isBlocklistEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
tr_blocklistSetEnabled( tr_handle * handle, int isEnabled )
|
||||
tr_blocklistSetEnabled( tr_session * session, int isEnabled )
|
||||
{
|
||||
_tr_blocklistSetEnabled( handle->blocklist, isEnabled );
|
||||
tr_list * l;
|
||||
session->isBlocklistEnabled = isEnabled ? 1 : 0;
|
||||
for( l=session->blocklists; l; l=l->next )
|
||||
_tr_blocklistSetEnabled( l->data, isEnabled );
|
||||
}
|
||||
|
||||
int
|
||||
tr_blocklistExists( const tr_handle * handle )
|
||||
tr_blocklistExists( const tr_session * session )
|
||||
{
|
||||
return _tr_blocklistExists( handle->blocklist );
|
||||
return session->blocklists != NULL;
|
||||
}
|
||||
|
||||
int
|
||||
tr_blocklistSetContent( tr_handle * handle, const char * filename )
|
||||
tr_blocklistSetContent( tr_session * session, const char * contentFilename )
|
||||
{
|
||||
return _tr_blocklistSetContent( handle->blocklist, filename );
|
||||
tr_list * l;
|
||||
tr_blocklist * b;
|
||||
const char * defaultName = "level1.bin";
|
||||
|
||||
for( b=NULL, l=session->blocklists; !b && l; l=l->next )
|
||||
if( tr_stringEndsWith( _tr_blocklistGetFilename( l->data ), defaultName ) )
|
||||
b = l->data;
|
||||
|
||||
if( !b ) {
|
||||
char filename[MAX_PATH_LENGTH];
|
||||
tr_buildPath( filename, sizeof( filename ), session->configDir, "blocklists", defaultName, NULL );
|
||||
b = _tr_blocklistNew( filename, session->isBlocklistEnabled );
|
||||
tr_list_append( &session->blocklists, b );
|
||||
}
|
||||
|
||||
return _tr_blocklistSetContent( b, contentFilename );
|
||||
}
|
||||
|
||||
int
|
||||
tr_blocklistHasAddress( tr_handle * handle, const struct in_addr * addr )
|
||||
tr_sessionIsAddressBlocked( const tr_session * session,
|
||||
const struct in_addr * addr )
|
||||
{
|
||||
return _tr_blocklistHasAddress( handle->blocklist, addr );
|
||||
tr_list * l;
|
||||
for( l=session->blocklists; l; l=l->next )
|
||||
if( _tr_blocklistHasAddress( l->data, addr ) )
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
@ -51,6 +51,7 @@ struct tr_handle
|
|||
{
|
||||
unsigned int isPortSet : 1;
|
||||
unsigned int isPexEnabled : 1;
|
||||
unsigned int isBlocklistEnabled : 1;
|
||||
unsigned int isProxyEnabled : 1;
|
||||
unsigned int isProxyAuthEnabled : 1;
|
||||
unsigned int isClosed : 1;
|
||||
|
@ -80,7 +81,7 @@ struct tr_handle
|
|||
struct tr_ratecontrol * upload;
|
||||
struct tr_ratecontrol * download;
|
||||
|
||||
struct tr_blocklist * blocklist;
|
||||
struct tr_list * blocklists;
|
||||
struct tr_peerMgr * peerMgr;
|
||||
struct tr_shared * shared;
|
||||
|
||||
|
@ -106,6 +107,12 @@ void tr_sessionSetTorrentFile( tr_session * session,
|
|||
const char * hashString,
|
||||
const char * filename );
|
||||
|
||||
struct in_addr;
|
||||
|
||||
int tr_sessionIsAddressBlocked( const tr_session * session,
|
||||
const struct in_addr * addr );
|
||||
|
||||
|
||||
void tr_globalLock ( tr_session * );
|
||||
void tr_globalUnlock ( tr_session * );
|
||||
int tr_globalIsLocked ( const tr_session * );
|
||||
|
|
|
@ -605,22 +605,18 @@ void tr_freeMessageList( tr_msg_list * freeme );
|
|||
*
|
||||
* Passing NULL for a filename will clear the blocklist.
|
||||
*/
|
||||
int tr_blocklistSetContent( tr_handle * handle,
|
||||
const char * filename );
|
||||
int tr_blocklistSetContent ( tr_session * session,
|
||||
const char * filename );
|
||||
|
||||
int tr_blocklistGetRuleCount( tr_handle * handle );
|
||||
int tr_blocklistGetRuleCount ( const tr_session * session );
|
||||
|
||||
int tr_blocklistExists( const tr_handle * handle );
|
||||
int tr_blocklistExists ( const tr_session * session );
|
||||
|
||||
int tr_blocklistIsEnabled( const tr_handle * handle );
|
||||
int tr_blocklistIsEnabled ( const tr_session * session );
|
||||
|
||||
void tr_blocklistSetEnabled( tr_handle * handle,
|
||||
int isEnabled );
|
||||
void tr_blocklistSetEnabled ( tr_session * session,
|
||||
int isEnabled );
|
||||
|
||||
struct in_addr;
|
||||
|
||||
int tr_blocklistHasAddress( tr_handle * handle,
|
||||
const struct in_addr * addr);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -93,6 +93,13 @@ main( void )
|
|||
tr_free( in );
|
||||
tr_free( out );
|
||||
|
||||
/* tr_stringEndsWith */
|
||||
check( tr_stringEndsWith( "the", "the" ) );
|
||||
check( tr_stringEndsWith( "dress", "dress" ) );
|
||||
check( tr_stringEndsWith( "address", "dress" ) );
|
||||
check( !tr_stringEndsWith( "foo.bin", "gfoo.bin" ) );
|
||||
check( !tr_stringEndsWith( "xyz", "xyw" ) );
|
||||
|
||||
/* simple bitfield tests */
|
||||
for( l=0; l<NUM_LOOPS; ++l )
|
||||
if(( i = test_bitfields( )))
|
||||
|
|
|
@ -921,6 +921,14 @@ tr_wait( uint64_t delay_milliseconds )
|
|||
****
|
||||
***/
|
||||
|
||||
int
|
||||
tr_stringEndsWith( const char * str, const char * end )
|
||||
{
|
||||
const size_t slen = strlen( str );
|
||||
const size_t elen = strlen( end );
|
||||
return slen>=elen && !memcmp( &str[slen-elen], end, elen );
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
|
|
|
@ -197,7 +197,7 @@ char* tr_base64_decode( const void * input, int inlen, int *outlen ) TR_GNUC_MAL
|
|||
|
||||
size_t tr_strlcpy( char * dst, const char * src, size_t siz );
|
||||
|
||||
|
||||
int tr_stringEndsWith( const char * string, const char * end );
|
||||
|
||||
const char* tr_strerror( int );
|
||||
|
||||
|
|
Loading…
Reference in New Issue