An open and free bittorrent tracker https://erdgeist.org/gitweb/opentracker
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
9.6 KiB

13 years ago
14 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
  1. /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
  2. It is considered beerware. Prost. Skol. Cheers or whatever.
  3. $id$ */
  4. /* System */
  5. #include <pthread.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include <signal.h>
  10. #include <unistd.h>
  11. /* Libowfat */
  12. #include "byte.h"
  13. #include "scan.h"
  14. #include "ip6.h"
  15. #include "mmap.h"
  16. /* Opentracker */
  17. #include "trackerlogic.h"
  18. #include "ot_accesslist.h"
  19. #include "ot_vector.h"
  20. /* GLOBAL VARIABLES */
  21. #ifdef WANT_ACCESSLIST
  22. char *g_accesslist_filename;
  23. static ot_hash *g_accesslist;
  24. static size_t g_accesslist_size;
  25. static pthread_mutex_t g_accesslist_mutex;
  26. static int vector_compare_hash(const void *hash1, const void *hash2 ) {
  27. return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE );
  28. }
  29. /* Read initial access list */
  30. static void accesslist_readfile( void ) {
  31. ot_hash *info_hash, *accesslist_new = NULL;
  32. char *map, *map_end, *read_offs;
  33. size_t maplen;
  34. if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) {
  35. char *wd = getcwd( NULL, 0 );
  36. fprintf( stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).\nPWD: %s\n", g_accesslist_filename, wd );
  37. free( wd );
  38. return;
  39. }
  40. /* You need at least 41 bytes to pass an info_hash, make enough room
  41. for the maximum amount of them */
  42. info_hash = accesslist_new = malloc( ( maplen / 41 ) * 20 );
  43. if( !accesslist_new ) {
  44. fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 );
  45. return;
  46. }
  47. /* No use to scan if there's not enough room for another full info_hash */
  48. map_end = map + maplen - 40;
  49. read_offs = map;
  50. /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */
  51. while( read_offs <= map_end ) {
  52. int i;
  53. for( i=0; i<(int)sizeof(ot_hash); ++i ) {
  54. int eger1 = scan_fromhex( read_offs[ 2*i ] );
  55. int eger2 = scan_fromhex( read_offs[ 1 + 2*i ] );
  56. if( eger1 < 0 || eger2 < 0 )
  57. break;
  58. (*info_hash)[i] = eger1 * 16 + eger2;
  59. }
  60. if( i == sizeof(ot_hash) ) {
  61. read_offs += 40;
  62. /* Append accesslist to accesslist vector */
  63. if( read_offs == map_end || scan_fromhex( *read_offs ) < 0 )
  64. ++info_hash;
  65. }
  66. /* Find start of next line */
  67. while( read_offs <= map_end && *(read_offs++) != '\n' );
  68. }
  69. #ifdef _DEBUG
  70. fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new) );
  71. #endif
  72. mmap_unmap( map, maplen);
  73. qsort( accesslist_new, info_hash - accesslist_new, sizeof( *info_hash ), vector_compare_hash );
  74. /* Now exchange the accesslist vector in the least race condition prone way */
  75. pthread_mutex_lock(&g_accesslist_mutex);
  76. free( g_accesslist );
  77. g_accesslist = accesslist_new;
  78. g_accesslist_size = info_hash - accesslist_new;
  79. pthread_mutex_unlock(&g_accesslist_mutex);
  80. }
  81. int accesslist_hashisvalid( ot_hash hash ) {
  82. void *exactmatch;
  83. /* Lock should hardly ever be contended */
  84. pthread_mutex_lock(&g_accesslist_mutex);
  85. exactmatch = bsearch( hash, g_accesslist, g_accesslist_size, OT_HASH_COMPARE_SIZE, vector_compare_hash );
  86. pthread_mutex_unlock(&g_accesslist_mutex);
  87. #ifdef WANT_ACCESSLIST_BLACK
  88. return exactmatch == NULL;
  89. #else
  90. return exactmatch != NULL;
  91. #endif
  92. }
  93. static void * accesslist_worker( void * args ) {
  94. int sig;
  95. sigset_t signal_mask;
  96. sigemptyset(&signal_mask);
  97. sigaddset(&signal_mask, SIGHUP);
  98. (void)args;
  99. while( 1 ) {
  100. /* Initial attempt to read accesslist */
  101. accesslist_readfile( );
  102. /* Wait for signals */
  103. while( sigwait (&signal_mask, &sig) != 0 && sig != SIGHUP );
  104. }
  105. return NULL;
  106. }
  107. static pthread_t thread_id;
  108. void accesslist_init( ) {
  109. pthread_mutex_init(&g_accesslist_mutex, NULL);
  110. pthread_create( &thread_id, NULL, accesslist_worker, NULL );
  111. }
  112. void accesslist_deinit( void ) {
  113. pthread_cancel( thread_id );
  114. pthread_mutex_destroy(&g_accesslist_mutex);
  115. free( g_accesslist );
  116. g_accesslist = 0;
  117. g_accesslist_size = 0;
  118. }
  119. #endif
  120. int address_in_net( const ot_ip6 address, const ot_net *net ) {
  121. int bits = net->bits;
  122. int result = memcmp( address, &net->address, bits >> 3 );
  123. if( !result && ( bits & 7 ) )
  124. result = ( ( 0x7f00 >> ( bits & 7 ) ) & address[bits>>3] ) - net->address[bits>>3];
  125. return result == 0;
  126. }
  127. void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value, const size_t member_size ) {
  128. size_t i;
  129. int exactmatch;
  130. /* Caller must have a concept of ot_net in it's member */
  131. if( member_size < sizeof(ot_net) )
  132. return 0;
  133. /* Check each net in vector for overlap */
  134. uint8_t *member = ((uint8_t*)vector->data);
  135. for( i=0; i<vector->size; ++i ) {
  136. if( address_in_net( *(ot_ip6*)member, net ) ||
  137. address_in_net( net->address, (ot_net*)member ) )
  138. return 0;
  139. member += member_size;
  140. }
  141. member = vector_find_or_insert( vector, (void*)net, member_size, sizeof(ot_net), &exactmatch );
  142. if( member ) {
  143. memcpy( member, net, sizeof(ot_net));
  144. memcpy( member + sizeof(ot_net), value, member_size - sizeof(ot_net));
  145. }
  146. return member;
  147. }
  148. /* Takes a vector filled with { ot_net net, uint8_t[x] value };
  149. Returns value associated with the net, or NULL if not found */
  150. void *get_value_for_net( const ot_ip6 address, const ot_vector *vector, const size_t member_size ) {
  151. int exactmatch;
  152. /* This binary search will return a pointer to the first non-containing network... */
  153. ot_net *net = binary_search( address, vector->data, vector->size, member_size, sizeof(ot_ip6), &exactmatch );
  154. if( !net )
  155. return NULL;
  156. /* ... so we'll need to move back one step unless we've exactly hit the first address in network */
  157. if( !exactmatch && ( (void*)net > vector->data ) )
  158. --net;
  159. if( !address_in_net( address, net ) )
  160. return NULL;
  161. return (void*)net;
  162. }
  163. #ifdef WANT_FULLLOG_NETWORKS
  164. static ot_vector g_lognets_list;
  165. ot_log *g_logchain_first, *g_logchain_last;
  166. static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER;
  167. void loglist_add_network( const ot_net *net ) {
  168. pthread_mutex_lock(&g_lognets_list_mutex);
  169. set_value_for_net( net, &g_lognets_list, NULL, sizeof(ot_net));
  170. pthread_mutex_unlock(&g_lognets_list_mutex);
  171. }
  172. void loglist_reset( ) {
  173. pthread_mutex_lock(&g_lognets_list_mutex);
  174. free( g_lognets_list.data );
  175. g_lognets_list.data = 0;
  176. g_lognets_list.size = g_lognets_list.space = 0;
  177. pthread_mutex_unlock(&g_lognets_list_mutex);
  178. }
  179. int loglist_check_address( const ot_ip6 address ) {
  180. int result;
  181. pthread_mutex_lock(&g_lognets_list_mutex);
  182. result = ( NULL != get_value_for_net( address, &g_lognets_list, sizeof(ot_net)) );
  183. pthread_mutex_unlock(&g_lognets_list_mutex);
  184. return result;
  185. }
  186. #endif
  187. #ifdef WANT_IP_FROM_PROXY
  188. typedef struct {
  189. ot_net *proxy;
  190. ot_vector networks;
  191. } ot_proxymap;
  192. static ot_vector g_proxies_list;
  193. static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER;
  194. int proxylist_add_network( const ot_net *proxy, const ot_net *net ) {
  195. ot_proxymap *map;
  196. int exactmatch, result = 1;
  197. pthread_mutex_lock(&g_proxies_list_mutex);
  198. /* If we have a direct hit, use and extend the vector there */
  199. map = binary_search( proxy, g_proxies_list.data, g_proxies_list.size, sizeof(ot_proxymap), sizeof(ot_net), &exactmatch );
  200. if( !map || !exactmatch ) {
  201. /* else see, if we've got overlapping networks
  202. and get a new empty vector if not */
  203. ot_vector empty;
  204. memset( &empty, 0, sizeof( ot_vector ) );
  205. map = set_value_for_net( proxy, &g_proxies_list, &empty, sizeof(ot_proxymap));
  206. }
  207. if( map && set_value_for_net( net, &map->networks, NULL, sizeof(ot_net) ) )
  208. result = 1;
  209. pthread_mutex_unlock(&g_proxies_list_mutex);
  210. return result;
  211. }
  212. int proxylist_check_proxy( const ot_ip6 proxy, const ot_ip6 address ) {
  213. int result = 0;
  214. ot_proxymap *map;
  215. pthread_mutex_lock(&g_proxies_list_mutex);
  216. if( ( map = get_value_for_net( proxy, &g_proxies_list, sizeof(ot_proxymap) ) ) )
  217. if( !address || get_value_for_net( address, &map->networks, sizeof(ot_net) ) )
  218. result = 1;
  219. pthread_mutex_unlock(&g_proxies_list_mutex);
  220. return result;
  221. }
  222. #endif
  223. static ot_ip6 g_adminip_addresses[OT_ADMINIP_MAX];
  224. static ot_permissions g_adminip_permissions[OT_ADMINIP_MAX];
  225. static unsigned int g_adminip_count = 0;
  226. int accesslist_blessip( ot_ip6 ip, ot_permissions permissions ) {
  227. if( g_adminip_count >= OT_ADMINIP_MAX )
  228. return -1;
  229. memcpy(g_adminip_addresses + g_adminip_count,ip,sizeof(ot_ip6));
  230. g_adminip_permissions[ g_adminip_count++ ] = permissions;
  231. #ifdef _DEBUG
  232. {
  233. char _debug[512];
  234. int off = snprintf( _debug, sizeof(_debug), "Blessing ip address " );
  235. off += fmt_ip6c(_debug+off, ip );
  236. if( permissions & OT_PERMISSION_MAY_STAT ) off += snprintf( _debug+off, 512-off, " may_fetch_stats" );
  237. if( permissions & OT_PERMISSION_MAY_LIVESYNC ) off += snprintf( _debug+off, 512-off, " may_sync_live" );
  238. if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) off += snprintf( _debug+off, 512-off, " may_fetch_fullscrapes" );
  239. if( permissions & OT_PERMISSION_MAY_PROXY ) off += snprintf( _debug+off, 512-off, " may_proxy" );
  240. if( !permissions ) off += snprintf( _debug+off, sizeof(_debug)-off, " nothing\n" );
  241. _debug[off++] = '.';
  242. write( 2, _debug, off );
  243. }
  244. #endif
  245. return 0;
  246. }
  247. int accesslist_isblessed( ot_ip6 ip, ot_permissions permissions ) {
  248. unsigned int i;
  249. for( i=0; i<g_adminip_count; ++i )
  250. if( !memcmp( g_adminip_addresses + i, ip, sizeof(ot_ip6)) && ( g_adminip_permissions[ i ] & permissions ) )
  251. return 1;
  252. return 0;
  253. }
  254. const char *g_version_accesslist_c = "$Source: /home/cvsroot/opentracker/ot_accesslist.c,v $: $Revision: 1.31 $\n";