Added inbound part of sync. This also meant to remove the black/whitelisting as we did by now. A more scalable way to blacklist will follow.

dynamic-accesslists
erdgeist 18 years ago
parent b38104b986
commit 33774078ab

@ -56,6 +56,7 @@ struct http_data {
io_batch batch; io_batch batch;
}; };
unsigned char ip[4]; unsigned char ip[4];
int blessed;
}; };
/* Prototypes */ /* Prototypes */
@ -87,6 +88,7 @@ static void graceful( int s );
#define HTTPERROR_400 return httperror( s, "400 Invalid Request", "This server only understands GET." ) #define HTTPERROR_400 return httperror( s, "400 Invalid Request", "This server only understands GET." )
#define HTTPERROR_400_PARAM return httperror( s, "400 Invalid Request", "Invalid parameter" ) #define HTTPERROR_400_PARAM return httperror( s, "400 Invalid Request", "Invalid parameter" )
#define HTTPERROR_400_COMPACT return httperror( s, "400 Invalid Request", "This server only delivers compact results." ) #define HTTPERROR_400_COMPACT return httperror( s, "400 Invalid Request", "This server only delivers compact results." )
#define HTTPERROR_403_IP return httperror( s, "403 Access Denied", "Your ip address is not allowed to administrate this server." )
#define HTTPERROR_404 return httperror( s, "404 Not Found", "No such file or directory." ) #define HTTPERROR_404 return httperror( s, "404 Not Found", "No such file or directory." )
#define HTTPERROR_500 return httperror( s, "500 Internal Server Error", "A server error has occured. Please retry later." ) #define HTTPERROR_500 return httperror( s, "500 Internal Server Error", "A server error has occured. Please retry later." )
@ -173,6 +175,7 @@ static void senddata( const int64 s, char *buffer, size_t size ) {
} }
static void httpresponse( const int64 s, char *data ) { static void httpresponse( const int64 s, char *data ) {
struct http_data* h = io_getcookie( s );
char *c, *reply; char *c, *reply;
ot_peer peer; ot_peer peer;
ot_torrent *torrent; ot_torrent *torrent;
@ -198,11 +201,48 @@ static void httpresponse( const int64 s, char *data ) {
for( c = data+4; *c == '/'; ++c); for( c = data+4; *c == '/'; ++c);
switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) {
/******************************
* S Y N C *
******************************/
case 4: /* sync ? */ case 4: /* sync ? */
if( byte_diff( data, 4, "sync") ) HTTPERROR_404; if( byte_diff( data, 4, "sync") ) HTTPERROR_404;
if( !h->blessed ) HTTPERROR_403_IP;
mode = SYNC_OUT;
scanon = 1;
while( scanon ) {
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
case -2: scanon = 0; break; /* TERMINATOR */
case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break;
case 9:
if(byte_diff(data,9,"changeset")) {
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
continue;
}
/* ignore this, when we dont at least see "d4:syncdee" */
if( ( len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) < 10 ) HTTPERROR_400_PARAM;
if( add_changeset_to_tracker( (ot_byte*)data, len ) ) HTTPERROR_400_PARAM;
mode = SYNC_IN;
break;
}
}
if( mode == SYNC_OUT ) {
if( !( reply_size = return_changeset_for_tracker( &reply ) ) ) HTTPERROR_500; if( !( reply_size = return_changeset_for_tracker( &reply ) ) ) HTTPERROR_500;
return sendmallocdata( s, reply, reply_size ); return sendmallocdata( s, reply, reply_size );
}
/* Simple but proof for now */
reply = "OK";
reply_size = 2;
break;
/******************************
* S T A T S *
******************************/
case 5: /* stats ? */ case 5: /* stats ? */
if( byte_diff(data,5,"stats")) HTTPERROR_404; if( byte_diff(data,5,"stats")) HTTPERROR_404;
scanon = 1; scanon = 1;
@ -260,8 +300,11 @@ static void httpresponse( const int64 s, char *data ) {
if( !( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, mode ) ) ) HTTPERROR_500; if( !( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, mode ) ) ) HTTPERROR_500;
break; break;
} }
break; break;
/******************************
* S C R A P E *
******************************/
case 6: /* scrape ? */ case 6: /* scrape ? */
if( byte_diff( data, 6, "scrape") ) HTTPERROR_404; if( byte_diff( data, 6, "scrape") ) HTTPERROR_404;
@ -280,7 +323,7 @@ SCRAPE_WORKAROUND:
} }
/* ignore this, when we have less than 20 bytes */ /* ignore this, when we have less than 20 bytes */
if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM;
hash = (ot_hash*)data; /* Fall through intended */ hash = (ot_hash*)data;
break; break;
} }
} }
@ -297,6 +340,9 @@ SCRAPE_WORKAROUND:
ot_overall_tcp_successfulannounces++; ot_overall_tcp_successfulannounces++;
break; break;
/******************************
* A N N O U N C E *
******************************/
case 8: case 8:
if( byte_diff( data, 8, "announce" ) ) HTTPERROR_404; if( byte_diff( data, 8, "announce" ) ) HTTPERROR_404;
@ -384,7 +430,7 @@ ANNOUNCE_WORKAROUND:
remove_peer_from_torrent( hash, &peer ); remove_peer_from_torrent( hash, &peer );
reply_size = sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); reply_size = sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM );
} else { } else {
torrent = add_peer_to_torrent( hash, &peer ); torrent = add_peer_to_torrent( hash, &peer, 0 );
if( !torrent || !( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 1 ) ) ) HTTPERROR_500; if( !torrent || !( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 1 ) ) ) HTTPERROR_500;
} }
ot_overall_tcp_successfulannounces++; ot_overall_tcp_successfulannounces++;
@ -438,12 +484,6 @@ static void graceful( int s ) {
static void usage( char *name ) { static void usage( char *name ) {
fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]" fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]"
#ifdef WANT_CLOSED_TRACKER
" [-oc]"
#endif
#ifdef WANT_BLACKLIST
" [-bB]"
#endif
"\n", name ); "\n", name );
} }
@ -453,23 +493,6 @@ static void help( char *name ) {
"\t-p serverport\tspecify tcp port to bind to (default: 6969, you may specify more than one)\n" "\t-p serverport\tspecify tcp port to bind to (default: 6969, you may specify more than one)\n"
"\t-P serverport\tspecify udp port to bind to (default: 6969, you may specify more than one)\n" "\t-P serverport\tspecify udp port to bind to (default: 6969, you may specify more than one)\n"
"\t-d serverdir\tspecify directory containing white- or black listed torrent info_hashes (default: \".\")\n" "\t-d serverdir\tspecify directory containing white- or black listed torrent info_hashes (default: \".\")\n"
#ifdef WANT_CLOSED_TRACKER
"\t-o\t\tmake tracker an open tracker, e.g. do not check for white list (default: off)\n"
"\t-c\t\tmake tracker a closed tracker, e.g. check each announced torrent against white list (default: on)\n"
#endif
#ifdef WANT_BLACKLIST
"\t-b\t\tmake tracker check its black list, e.g. check each announced torrent against black list (default: on)\n"
"\t-B\t\tmake tracker check its black list, e.g. check each announced torrent against black list (default: off)\n"
#endif
#ifdef WANT_CLOSED_TRACKER
"\n* To white list a torrent, touch a file inside serverdir with info_hash hex string.\n"
#endif
#ifdef WANT_BLACKLIST
#ifndef WANT_CLOSED_TRACKER
"\n"
#endif
"* To white list a torrent, touch a file inside serverdir with info_hash hex string, preprended by '-'.\n"
#endif
"\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -i 10.1.1.23 -p 2710 -p 80\n" "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -i 10.1.1.23 -p 2710 -p 80\n"
); );
} }
@ -503,7 +526,7 @@ static void handle_read( const int64 clientsocket ) {
if( array_failed( &h->request ) ) if( array_failed( &h->request ) )
return httperror( clientsocket, "500 Server Error", "Request too long."); return httperror( clientsocket, "500 Server Error", "Request too long.");
if( array_bytes( &h->request ) > 8192 ) if( ( !h->blessed ) && ( array_bytes( &h->request ) > 8192 ) )
return httperror( clientsocket, "500 request too long", "You sent too much headers"); return httperror( clientsocket, "500 request too long", "You sent too much headers");
if( memchr( array_start( &h->request ), '\n', array_length( &h->request, 1 ) ) ) if( memchr( array_start( &h->request ), '\n', array_length( &h->request, 1 ) ) )
@ -626,7 +649,7 @@ static void handle_udp4( int64 serversocket ) {
outpacket[3] = outpacket[4] = 0; outpacket[3] = outpacket[4] = 0;
r = 20; r = 20;
} else { } else {
torrent = add_peer_to_torrent( hash, &peer ); torrent = add_peer_to_torrent( hash, &peer, 0 );
if( !torrent ) if( !torrent )
return; /* XXX maybe send error */ return; /* XXX maybe send error */
@ -719,14 +742,6 @@ int main( int argc, char **argv ) {
case 'P': ot_try_bind( serverip, (uint16)atol( optarg ), 0 ); break; case 'P': ot_try_bind( serverip, (uint16)atol( optarg ), 0 ); break;
case 'd': serverdir = optarg; break; case 'd': serverdir = optarg; break;
case 'h': help( argv[0] ); exit( 0 ); case 'h': help( argv[0] ); exit( 0 );
#ifdef WANT_CLOSED_TRACKER
case 'o': g_closedtracker = 0; break;
case 'c': g_closedtracker = 1; break;
#endif
#ifdef WANT_BLACKLIST
case 'b': g_check_blacklist = 1; break;
case 'B': g_check_blacklist = 0; break;
#endif
default: default:
case '?': usage( argv[0] ); exit( 1 ); case '?': usage( argv[0] ); exit( 1 );
} }

@ -19,26 +19,12 @@
#include "scan.h" #include "scan.h"
#include "byte.h" #include "byte.h"
#if defined( WANT_CLOSED_TRACKER ) || defined( WANT_BLACKLIST )
#include <sys/stat.h>
#endif
/* GLOBAL VARIABLES */ /* GLOBAL VARIABLES */
static ot_vector all_torrents[256]; static ot_vector all_torrents[256];
static ot_vector changeset; static ot_vector changeset;
size_t changeset_size = 0; size_t changeset_size = 0;
time_t last_clean_time = 0; time_t last_clean_time = 0;
#ifdef WANT_CLOSED_TRACKER
int g_closedtracker = 1;
static ot_torrent* const OT_TORRENT_NOT_ON_WHITELIST = (ot_torrent*)1;
#endif
#ifdef WANT_BLACKLIST
int g_check_blacklist = 1;
static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2;
#endif
/* Converter function from memory to human readable hex strings /* Converter function from memory to human readable hex strings
- definitely not thread safe!!! - definitely not thread safe!!!
*/ */
@ -162,25 +148,12 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
return 1; return 1;
} }
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) {
int exactmatch; int exactmatch;
ot_torrent *torrent; ot_torrent *torrent;
ot_peer *peer_dest; ot_peer *peer_dest;
ot_vector *torrents_list = &all_torrents[*hash[0]], *peer_pool; ot_vector *torrents_list = &all_torrents[*hash[0]], *peer_pool;
#if defined( WANT_CLOSED_TRACKER ) || defined( WANT_BLACKLIST ) int base_pool = 0;
struct stat dummy_sb;
char *fn = to_hex( (ot_byte*)hash );
#endif
#ifdef WANT_CLOSED_TRACKER
if( g_closedtracker && stat( fn, &dummy_sb ) )
return OT_TORRENT_NOT_ON_WHITELIST;
#endif
#ifdef WANT_BLACKLIST
if( g_check_blacklist && !stat( fn - 1, &dummy_sb ) )
return OT_TORRENT_ON_BLACKLIST;
#endif
torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
if( !torrent ) return NULL; if( !torrent ) return NULL;
@ -202,7 +175,16 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED; OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED;
if( from_changeset ) {
/* Check, whether peer already is in current pool, do nothing if so */
peer_pool = &torrent->peer_list->peers[0]; peer_pool = &torrent->peer_list->peers[0];
binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch );
if( exactmatch )
return torrent;
base_pool = 1;
}
peer_pool = &torrent->peer_list->peers[ base_pool ];
peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch ); peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
/* If we hadn't had a match in current pool, create peer there and /* If we hadn't had a match in current pool, create peer there and
@ -215,9 +197,9 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
torrent->peer_list->downloaded++; torrent->peer_list->downloaded++;
if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) if( OT_FLAG(peer) & PEER_FLAG_SEEDING )
torrent->peer_list->seed_count[0]++; torrent->peer_list->seed_count[ base_pool ]++;
for( i=1; i<OT_POOLS_COUNT; ++i ) { for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) {
switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) { switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) {
case 0: continue; case 0: continue;
case 2: torrent->peer_list->seed_count[i]--; case 2: torrent->peer_list->seed_count[i]--;
@ -226,9 +208,9 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
} }
} else { } else {
if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) )
torrent->peer_list->seed_count[0]--; torrent->peer_list->seed_count[ base_pool ]--;
if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) )
torrent->peer_list->seed_count[0]++; torrent->peer_list->seed_count[ base_pool ]++;
if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) ) if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) )
torrent->peer_list->downloaded++; torrent->peer_list->downloaded++;
if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED )
@ -250,22 +232,6 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply
char *r = reply; char *r = reply;
size_t peer_count, seed_count, index; size_t peer_count, seed_count, index;
#ifdef WANT_CLOSED_TRACKER
if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) {
const char * const notvalid = "d14:failure reason43:This torrent is not served by this tracker.e";
memmove( reply, notvalid, sizeof(notvalid));
return sizeof(notvalid);
}
#endif
#ifdef WANT_BLACKLIST
if( torrent == OT_TORRENT_ON_BLACKLIST ) {
const char * const blacklisted = "d14:failure reason29:This torrent is black listed.e";
memmove( reply, blacklisted, sizeof(blacklisted));
return sizeof(blacklisted);
}
#endif
for( peer_count = seed_count = index = 0; index < OT_POOLS_COUNT; ++index ) { for( peer_count = seed_count = index = 0; index < OT_POOLS_COUNT; ++index ) {
peer_count += torrent->peer_list->peers[index].size; peer_count += torrent->peer_list->peers[index].size;
seed_count += torrent->peer_list->seed_count[index]; seed_count += torrent->peer_list->seed_count[index];
@ -473,8 +439,48 @@ static void add_pool_to_changeset( ot_hash *hash, ot_peer *peers, size_t peer_co
changeset_size += r - sizeof( size_t ); changeset_size += r - sizeof( size_t );
} }
/* Import Changeset from an external authority
format: d4:syncd[..]ee
[..]: ( 20:01234567890abcdefghij16:XXXXYYYY )+
*/
int add_changeset_to_tracker( ot_byte *data, size_t len ) {
ot_hash *hash;
ot_byte *end = data + len;
size_t peer_count;
/* We do know, that the string is \n terminated, so it cant
overflow */
if( byte_diff( data, 8, "d4:syncd" ) ) return -1;
data += 8;
while( 1 ) {
if( byte_diff( data, 3, "20:" ) ) {
if( byte_diff( data, 2, "ee" ) )
return -1;
return 0;
}
data += 3;
hash = (ot_hash*)data;
data += sizeof( ot_hash );
/* Scan string length indicator */
data += ( len = scan_ulong( (char*)data, &peer_count ) );
/* If no long was scanned, it is not divisible by 8, it is not
followed by a colon or claims to need to much memory, we fail */
if( !len || !peer_count || ( peer_count & 7 ) || ( *data++ != ':' ) || ( data + peer_count > end ) )
return -1;
while( peer_count > 0 ) {
add_peer_to_torrent( hash, (ot_peer*)data, 1 );
data += 8; peer_count -= 8;
}
}
return 0;
}
/* Proposed output format /* Proposed output format
d4:syncd20:<info_hash>8*N:(xxxxyy)*Nee d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee
*/ */
size_t return_changeset_for_tracker( char **reply ) { size_t return_changeset_for_tracker( char **reply ) {
size_t i, r = 8; size_t i, r = 8;

@ -84,16 +84,10 @@ typedef struct {
int init_logic( const char * const serverdir ); int init_logic( const char * const serverdir );
void deinit_logic( void ); void deinit_logic( void );
#ifdef WANT_CLOSED_TRACKER enum { STATS_MRTG, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, SYNC_IN, SYNC_OUT };
extern int g_closedtracker;
#endif
#ifdef WANT_BLACKLIST
extern int g_check_blacklist;
#endif
enum { STATS_MRTG, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP };
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ); ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset );
int add_changeset_to_tracker( ot_byte *data, size_t len );
size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ); size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp );
size_t return_fullscrape_for_tracker( char **reply ); size_t return_fullscrape_for_tracker( char **reply );
size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply ); size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply );

Loading…
Cancel
Save