diff --git a/opentracker.c b/opentracker.c index 7be1421..0ddce0c 100644 --- a/opentracker.c +++ b/opentracker.c @@ -56,6 +56,7 @@ struct http_data { io_batch batch; }; unsigned char ip[4]; + int blessed; }; /* 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_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_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_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 ) { + struct http_data* h = io_getcookie( s ); char *c, *reply; ot_peer peer; ot_torrent *torrent; @@ -198,11 +201,48 @@ static void httpresponse( const int64 s, char *data ) { for( c = data+4; *c == '/'; ++c); switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { + +/****************************** + * S Y N C * + ******************************/ case 4: /* sync ? */ if( byte_diff( data, 4, "sync") ) HTTPERROR_404; - if( !( reply_size = return_changeset_for_tracker( &reply ) ) ) HTTPERROR_500; - return sendmallocdata( s, reply, reply_size ); + 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; + 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 ? */ if( byte_diff(data,5,"stats")) HTTPERROR_404; 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; break; } - break; + +/****************************** + * S C R A P E * + ******************************/ case 6: /* scrape ? */ if( byte_diff( data, 6, "scrape") ) HTTPERROR_404; @@ -280,7 +323,7 @@ SCRAPE_WORKAROUND: } /* ignore this, when we have less than 20 bytes */ 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; } } @@ -297,6 +340,9 @@ SCRAPE_WORKAROUND: ot_overall_tcp_successfulannounces++; break; +/****************************** + * A N N O U N C E * + ******************************/ case 8: if( byte_diff( data, 8, "announce" ) ) HTTPERROR_404; @@ -384,7 +430,7 @@ ANNOUNCE_WORKAROUND: 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 ); } 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; } ot_overall_tcp_successfulannounces++; @@ -438,12 +484,6 @@ static void graceful( int s ) { static void usage( char *name ) { fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]" -#ifdef WANT_CLOSED_TRACKER - " [-oc]" -#endif -#ifdef WANT_BLACKLIST - " [-bB]" -#endif "\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 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" -#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" ); } @@ -503,7 +526,7 @@ static void handle_read( const int64 clientsocket ) { if( array_failed( &h->request ) ) 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"); 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; r = 20; } else { - torrent = add_peer_to_torrent( hash, &peer ); + torrent = add_peer_to_torrent( hash, &peer, 0 ); if( !torrent ) 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 'd': serverdir = optarg; break; 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: case '?': usage( argv[0] ); exit( 1 ); } diff --git a/trackerlogic.c b/trackerlogic.c index d2d279e..5bda0df 100644 --- a/trackerlogic.c +++ b/trackerlogic.c @@ -19,26 +19,12 @@ #include "scan.h" #include "byte.h" -#if defined( WANT_CLOSED_TRACKER ) || defined( WANT_BLACKLIST ) -#include -#endif - /* GLOBAL VARIABLES */ static ot_vector all_torrents[256]; static ot_vector changeset; size_t changeset_size = 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 - definitely not thread safe!!! */ @@ -162,25 +148,12 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { return 1; } -ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { - int exactmatch; +ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) { + int exactmatch; ot_torrent *torrent; ot_peer *peer_dest; ot_vector *torrents_list = &all_torrents[*hash[0]], *peer_pool; -#if defined( WANT_CLOSED_TRACKER ) || defined( WANT_BLACKLIST ) - 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 + int base_pool = 0; torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); 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 ) OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED; - peer_pool = &torrent->peer_list->peers[0]; + if( from_changeset ) { + /* Check, whether peer already is in current pool, do nothing if so */ + 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 ); /* 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++; if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) - torrent->peer_list->seed_count[0]++; + torrent->peer_list->seed_count[ base_pool ]++; - for( i=1; ipeer_list->peers[i], peer, 0 ) ) { case 0: continue; 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 { 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 ) ) - 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 ) ) torrent->peer_list->downloaded++; 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; 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 ) { peer_count += torrent->peer_list->peers[index].size; 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 ); } +/* 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 - d4:syncd20:8*N:(xxxxyy)*Nee + d4:syncd20:8*N:(xxxxyyyy)*Nee */ size_t return_changeset_for_tracker( char **reply ) { size_t i, r = 8; diff --git a/trackerlogic.h b/trackerlogic.h index dfd5047..4fa48eb 100644 --- a/trackerlogic.h +++ b/trackerlogic.h @@ -84,16 +84,10 @@ typedef struct { int init_logic( const char * const serverdir ); void deinit_logic( void ); -#ifdef WANT_CLOSED_TRACKER -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 }; +enum { STATS_MRTG, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, SYNC_IN, SYNC_OUT }; -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_fullscrape_for_tracker( char **reply ); size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply );