#include <stdlib.h> /* free */
#include <string.h>
+#include <libgen.h> /* basename */
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
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
return b;
}
+const char*
+_tr_blocklistGetFilename( const tr_blocklist * b )
+{
+ return b->filename;
+}
+
void
_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;
}
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 )
++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 );
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
{
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 ) );
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 );
}
/* 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;
{
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;
****
***/
+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 *
/* 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 );
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 );
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;
+ }
}
}
}
***/
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 )
-{
- return _tr_blocklistHasAddress( handle->blocklist, addr );
+tr_sessionIsAddressBlocked( const tr_session * session,
+ const struct in_addr * addr )
+{
+ tr_list * l;
+ for( l=session->blocklists; l; l=l->next )
+ if( _tr_blocklistHasAddress( l->data, addr ) )
+ return TRUE;
+ return FALSE;
}
/***
{
unsigned int isPortSet : 1;
unsigned int isPexEnabled : 1;
+ unsigned int isBlocklistEnabled : 1;
unsigned int isProxyEnabled : 1;
unsigned int isProxyAuthEnabled : 1;
unsigned int isClosed : 1;
struct tr_ratecontrol * upload;
struct tr_ratecontrol * download;
- struct tr_blocklist * blocklist;
+ struct tr_list * blocklists;
struct tr_peerMgr * peerMgr;
struct tr_shared * shared;
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 * );
*
* 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);
/** @} */
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( )))
****
***/
+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).
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 );