mirror of
git://erdgeist.org/opentracker
synced 2025-02-22 09:01:29 +08:00
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.
This commit is contained in:
parent
b38104b986
commit
33774078ab
@ -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 );
|
||||
}
|
||||
|
110
trackerlogic.c
110
trackerlogic.c
@ -19,26 +19,12 @@
|
||||
#include "scan.h"
|
||||
#include "byte.h"
|
||||
|
||||
#if defined( WANT_CLOSED_TRACKER ) || defined( WANT_BLACKLIST )
|
||||
#include <sys/stat.h>
|
||||
#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; 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 ) ) {
|
||||
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:<info_hash>8*N:(xxxxyy)*Nee
|
||||
d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee
|
||||
*/
|
||||
size_t return_changeset_for_tracker( char **reply ) {
|
||||
size_t i, r = 8;
|
||||
|
@ -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, SYNC_IN, SYNC_OUT };
|
||||
|
||||
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_fullscrape_for_tracker( char **reply );
|
||||
size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply );
|
||||
|
Loading…
x
Reference in New Issue
Block a user