summaryrefslogtreecommitdiff
path: root/ot_accesslist.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_accesslist.c')
-rw-r--r--ot_accesslist.c494
1 files changed, 371 insertions, 123 deletions
diff --git a/ot_accesslist.c b/ot_accesslist.c
index cdb964d..4b88c40 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -5,104 +5,201 @@
5 5
6/* System */ 6/* System */
7#include <pthread.h> 7#include <pthread.h>
8#include <signal.h>
9#include <stdio.h>
8#include <stdlib.h> 10#include <stdlib.h>
9#include <string.h> 11#include <string.h>
10#include <stdio.h>
11#include <signal.h>
12#include <unistd.h> 12#include <unistd.h>
13#ifdef WANT_DYNAMIC_ACCESSLIST
14#include <errno.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#endif
13 18
14/* Libowfat */ 19/* Libowfat */
15#include "byte.h" 20#include "byte.h"
16#include "scan.h" 21#include "fmt.h"
17#include "ip6.h" 22#include "ip6.h"
18#include "mmap.h" 23#include "mmap.h"
24#include "scan.h"
19 25
20/* Opentracker */ 26/* Opentracker */
21#include "trackerlogic.h"
22#include "ot_accesslist.h" 27#include "ot_accesslist.h"
23#include "ot_vector.h" 28#include "ot_vector.h"
29#include "trackerlogic.h"
24 30
25/* GLOBAL VARIABLES */ 31/* GLOBAL VARIABLES */
26#ifdef WANT_ACCESSLIST 32#ifdef WANT_ACCESSLIST
27 char *g_accesslist_filename; 33char *g_accesslist_filename = NULL;
28static ot_hash *g_accesslist; 34#ifdef WANT_DYNAMIC_ACCESSLIST
29static size_t g_accesslist_size; 35char *g_accesslist_pipe_add = NULL;
36char *g_accesslist_pipe_delete = NULL;
37#endif
30static pthread_mutex_t g_accesslist_mutex; 38static pthread_mutex_t g_accesslist_mutex;
31 39
32static int vector_compare_hash(const void *hash1, const void *hash2 ) { 40/* Accesslists are lock free linked lists. We can not make them locking, because every announce
33 return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); 41 would try to acquire the mutex, making it the most contested mutex in the whole of opentracker,
42 basically creating a central performance choke point.
43
44 The idea is that updating the list heads happens under the g_accesslist_mutex guard and is
45 done atomically, while consumers might potentially still hold pointers deeper inside the list.
46
47 Consumers (for now only via accesslist_hashisvalid) will always fetch the list head pointer
48 that is guaranteed to live for at least five minutes. This should be many orders of magnitudes
49 more than how long it will be needed by the bsearch done on the list. */
50struct ot_accesslist;
51typedef struct ot_accesslist ot_accesslist;
52struct ot_accesslist {
53 ot_hash *list;
54 size_t size;
55 ot_time base;
56 ot_accesslist *next;
57};
58static ot_accesslist *_Atomic g_accesslist = NULL;
59#ifdef WANT_DYNAMIC_ACCESSLIST
60static ot_accesslist *_Atomic g_accesslist_add = NULL;
61static ot_accesslist *_Atomic g_accesslist_delete = NULL;
62#endif
63
64/* Helpers to work on access lists */
65static int vector_compare_hash(const void *hash1, const void *hash2) { return memcmp(hash1, hash2, OT_HASH_COMPARE_SIZE); }
66
67static ot_accesslist *accesslist_free(ot_accesslist *accesslist) {
68 while (accesslist) {
69 ot_accesslist *this_accesslist = accesslist;
70 accesslist = this_accesslist->next;
71 free(this_accesslist->list);
72 free(this_accesslist);
73 }
74 return NULL;
75}
76
77static ot_accesslist *accesslist_make(ot_accesslist *next, size_t size) {
78 ot_accesslist *accesslist_new = malloc(sizeof(ot_accesslist));
79 if (accesslist_new) {
80 accesslist_new->list = size ? malloc(sizeof(ot_hash) * size) : NULL;
81 accesslist_new->size = size;
82 accesslist_new->base = g_now_minutes;
83 accesslist_new->next = next;
84 if (size && !accesslist_new->list) {
85 free(accesslist_new);
86 accesslist_new = NULL;
87 }
88 }
89 return accesslist_new;
90}
91
92/* This must be called with g_accesslist_mutex held.
93 This will never delete head, because that might still be in use. */
94static void accesslist_clean(ot_accesslist *accesslist) {
95 while (accesslist && accesslist->next) {
96 if (accesslist->next->base + 5 < g_now_minutes)
97 accesslist->next = accesslist_free(accesslist->next);
98 accesslist = accesslist->next;
99 }
34} 100}
35 101
36/* Read initial access list */ 102/* Read initial access list */
37static void accesslist_readfile( void ) { 103static void accesslist_readfile(void) {
38 ot_hash *info_hash, *accesslist_new = NULL; 104 ot_accesslist *accesslist_new;
39 char *map, *map_end, *read_offs; 105 ot_hash *info_hash;
40 size_t maplen; 106 const char *map, *map_end, *read_offs;
41 107 size_t maplen;
42 if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) { 108
43 char *wd = getcwd( NULL, 0 ); 109 if ((map = mmap_read(g_accesslist_filename, &maplen)) == NULL) {
44 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 ); 110 char *wd = getcwd(NULL, 0);
45 free( wd ); 111 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);
112 free(wd);
46 return; 113 return;
47 } 114 }
48 115
49 /* You need at least 41 bytes to pass an info_hash, make enough room 116 /* You need at least 41 bytes to pass an info_hash, make enough room
50 for the maximum amount of them */ 117 for the maximum amount of them */
51 info_hash = accesslist_new = malloc( ( maplen / 41 ) * 20 ); 118 accesslist_new = accesslist_make(g_accesslist, maplen / 41);
52 if( !accesslist_new ) { 119 if (!accesslist_new) {
53 fprintf( stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", ( maplen / 41 ) * 20 ); 120 fprintf(stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", (maplen / 41) * 20);
121 mmap_unmap(map, maplen);
54 return; 122 return;
55 } 123 }
124 info_hash = accesslist_new->list;
56 125
57 /* No use to scan if there's not enough room for another full info_hash */ 126 /* No use to scan if there's not enough room for another full info_hash */
58 map_end = map + maplen - 40; 127 map_end = map + maplen - 40;
59 read_offs = map; 128 read_offs = map;
60 129
61 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */ 130 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */
62 while( read_offs <= map_end ) { 131 while (read_offs <= map_end) {
63 int i; 132 int i;
64 for( i=0; i<(int)sizeof(ot_hash); ++i ) { 133 for (i = 0; i < (int)sizeof(ot_hash); ++i) {
65 int eger1 = scan_fromhex( read_offs[ 2*i ] ); 134 int eger1 = scan_fromhex((unsigned char)read_offs[2 * i]);
66 int eger2 = scan_fromhex( read_offs[ 1 + 2*i ] ); 135 int eger2 = scan_fromhex((unsigned char)read_offs[1 + 2 * i]);
67 if( eger1 < 0 || eger2 < 0 ) 136 if (eger1 < 0 || eger2 < 0)
68 break; 137 break;
69 (*info_hash)[i] = eger1 * 16 + eger2; 138 (*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
70 } 139 }
71 140
72 if( i == sizeof(ot_hash) ) { 141 if (i == sizeof(ot_hash)) {
73 read_offs += 40; 142 read_offs += 40;
74 143
75 /* Append accesslist to accesslist vector */ 144 /* Append accesslist to accesslist vector */
76 if( read_offs == map_end || scan_fromhex( *read_offs ) < 0 ) 145 if (read_offs == map_end || scan_fromhex((unsigned char)*read_offs) < 0)
77 ++info_hash; 146 ++info_hash;
78 } 147 }
79 148
80 /* Find start of next line */ 149 /* Find start of next line */
81 while( read_offs <= map_end && *(read_offs++) != '\n' ); 150 while (read_offs <= map_end && *(read_offs++) != '\n')
151 ;
82 } 152 }
83#ifdef _DEBUG 153#ifdef _DEBUG
84 fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new) ); 154 fprintf(stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list));
85#endif 155#endif
86 156
87 mmap_unmap( map, maplen); 157 mmap_unmap(map, maplen);
88 158
89 qsort( accesslist_new, info_hash - accesslist_new, sizeof( *info_hash ), vector_compare_hash ); 159 qsort(accesslist_new->list, info_hash - accesslist_new->list, sizeof(*info_hash), vector_compare_hash);
160 accesslist_new->size = info_hash - accesslist_new->list;
90 161
91 /* Now exchange the accesslist vector in the least race condition prone way */ 162 /* Now exchange the accesslist vector in the least race condition prone way */
92 pthread_mutex_lock(&g_accesslist_mutex); 163 pthread_mutex_lock(&g_accesslist_mutex);
93 free( g_accesslist ); 164 accesslist_new->next = g_accesslist;
94 g_accesslist = accesslist_new; 165 g_accesslist = accesslist_new; /* Only now set a new list */
95 g_accesslist_size = info_hash - accesslist_new; 166
167#ifdef WANT_DYNAMIC_ACCESSLIST
168 /* If we have dynamic accesslists, reloading a new one will always void the add/delete lists.
169 Insert empty ones at the list head */
170 if (g_accesslist_add && (accesslist_new = accesslist_make(g_accesslist_add, 0)) != NULL)
171 g_accesslist_add = accesslist_new;
172 if (g_accesslist_delete && (accesslist_new = accesslist_make(g_accesslist_delete, 0)) != NULL)
173 g_accesslist_delete = accesslist_new;
174#endif
175
176 accesslist_clean(g_accesslist);
177
96 pthread_mutex_unlock(&g_accesslist_mutex); 178 pthread_mutex_unlock(&g_accesslist_mutex);
97} 179}
98 180
99int accesslist_hashisvalid( ot_hash hash ) { 181int accesslist_hashisvalid(ot_hash hash) {
100 void *exactmatch; 182 /* Get working copy of current access list */
183 ot_accesslist *accesslist = g_accesslist;
184#ifdef WANT_DYNAMIC_ACCESSLIST
185 ot_accesslist *accesslist_add, *accesslist_delete;
186#endif
187 void *exactmatch = NULL;
101 188
102 /* Lock should hardly ever be contended */ 189 if (accesslist)
103 pthread_mutex_lock(&g_accesslist_mutex); 190 exactmatch = bsearch(hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
104 exactmatch = bsearch( hash, g_accesslist, g_accesslist_size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); 191
105 pthread_mutex_unlock(&g_accesslist_mutex); 192#ifdef WANT_DYNAMIC_ACCESSLIST
193 /* If we had no match on the main list, scan the list of dynamically added hashes */
194 accesslist_add = g_accesslist_add;
195 if ((exactmatch == NULL) && accesslist_add)
196 exactmatch = bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
197
198 /* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */
199 accesslist_delete = g_accesslist_delete;
200 if ((exactmatch != NULL) && accesslist_delete && bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash))
201 exactmatch = NULL;
202#endif
106 203
107#ifdef WANT_ACCESSLIST_BLACK 204#ifdef WANT_ACCESSLIST_BLACK
108 return exactmatch == NULL; 205 return exactmatch == NULL;
@@ -111,70 +208,210 @@ int accesslist_hashisvalid( ot_hash hash ) {
111#endif 208#endif
112} 209}
113 210
114static void * accesslist_worker( void * args ) { 211static void *accesslist_worker(void *args) {
115 int sig; 212 int sig;
116 sigset_t signal_mask; 213 sigset_t signal_mask;
117 214
118 sigemptyset(&signal_mask); 215 sigemptyset(&signal_mask);
119 sigaddset(&signal_mask, SIGHUP); 216 sigaddset(&signal_mask, SIGHUP);
120 217
121 (void)args; 218 (void)args;
122 219
123 while( 1 ) { 220 while (1) {
221 if (!g_opentracker_running)
222 return NULL;
124 223
125 /* Initial attempt to read accesslist */ 224 /* Initial attempt to read accesslist */
126 accesslist_readfile( ); 225 accesslist_readfile();
127 226
128 /* Wait for signals */ 227 /* Wait for signals */
129 while( sigwait (&signal_mask, &sig) != 0 && sig != SIGHUP ); 228 while (sigwait(&signal_mask, &sig) != 0 && sig != SIGHUP)
229 ;
230 }
231 return NULL;
232}
233
234#ifdef WANT_DYNAMIC_ACCESSLIST
235static pthread_t thread_adder_id, thread_deleter_id;
236static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic *adding_to, ot_accesslist *_Atomic *removing_from) {
237 struct stat st;
238
239 if (!stat(fifoname, &st)) {
240 if (!S_ISFIFO(st.st_mode)) {
241 fprintf(stderr, "Error when starting dynamic accesslists: Found Non-FIFO file at %s.\nPlease remove it and restart opentracker.\n", fifoname);
242 return NULL;
243 }
244 } else {
245 int error = mkfifo(fifoname, 0755);
246 if (error && error != EEXIST) {
247 fprintf(stderr, "Error when starting dynamic accesslists: Couldn't create FIFO at %s, error: %s\n", fifoname, strerror(errno));
248 return NULL;
249 }
250 }
251
252 while (g_opentracker_running) {
253 FILE *fifo = fopen(fifoname, "r");
254 char *line = NULL;
255 size_t linecap = 0;
256 ssize_t linelen;
257
258 if (!fifo) {
259 fprintf(stderr, "Error when reading dynamic accesslists: Couldn't open FIFO at %s, error: %s\n", fifoname, strerror(errno));
260 return NULL;
261 }
262
263 while ((linelen = getline(&line, &linecap, fifo)) > 0) {
264 ot_hash info_hash;
265 int i;
266
267 printf("Got line %*s", (int)linelen, line);
268 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*"
269 If there's not enough characters for an info_hash in the line, skip it. */
270 if (linelen < 41)
271 continue;
272
273 for (i = 0; i < (int)sizeof(ot_hash); ++i) {
274 int eger1 = scan_fromhex((unsigned char)line[2 * i]);
275 int eger2 = scan_fromhex((unsigned char)line[1 + 2 * i]);
276 if (eger1 < 0 || eger2 < 0)
277 break;
278 ((uint8_t *)info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
279 }
280 printf("parsed info_hash %20s\n", info_hash);
281 if (i != sizeof(ot_hash))
282 continue;
283
284 /* From now on we modify g_accesslist_add and g_accesslist_delete, so prevent the
285 other worker threads from doing the same */
286 pthread_mutex_lock(&g_accesslist_mutex);
287
288 /* If the info hash is in the removing_from list, create a new head without that entry */
289 if (*removing_from && (*removing_from)->list) {
290 ot_hash *exactmatch = bsearch(info_hash, (*removing_from)->list, (*removing_from)->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
291 if (exactmatch) {
292 ptrdiff_t off = exactmatch - (*removing_from)->list;
293 ot_accesslist *accesslist_new = accesslist_make(*removing_from, (*removing_from)->size - 1);
294 if (accesslist_new) {
295 memcpy(accesslist_new->list, (*removing_from)->list, sizeof(ot_hash) * off);
296 memcpy(accesslist_new->list + off, (*removing_from)->list + off + 1, (*removing_from)->size - off - 1);
297 *removing_from = accesslist_new;
298 }
299 }
300 }
301
302 /* Simple case: there's no adding_to list yet, create one with one member */
303 if (!*adding_to) {
304 ot_accesslist *accesslist_new = accesslist_make(NULL, 1);
305 if (accesslist_new) {
306 memcpy(accesslist_new->list, info_hash, sizeof(ot_hash));
307 *adding_to = accesslist_new;
308 }
309 } else {
310 int exactmatch = 0;
311 ot_hash *insert_point = binary_search(info_hash, (*adding_to)->list, (*adding_to)->size, OT_HASH_COMPARE_SIZE, sizeof(ot_hash), &exactmatch);
312
313 /* Only if the info hash is not in the adding_to list, create a new head with that entry */
314 if (!exactmatch) {
315 ot_accesslist *accesslist_new = accesslist_make(*adding_to, (*adding_to)->size + 1);
316 ptrdiff_t off = insert_point - (*adding_to)->list;
317 if (accesslist_new) {
318 memcpy(accesslist_new->list, (*adding_to)->list, sizeof(ot_hash) * off);
319 memcpy(accesslist_new->list + off, info_hash, sizeof(info_hash));
320 memcpy(accesslist_new->list + off + 1, (*adding_to)->list + off, (*adding_to)->size - off);
321 *adding_to = accesslist_new;
322 }
323 }
324 }
325
326 pthread_mutex_unlock(&g_accesslist_mutex);
327 }
328
329 fclose(fifo);
130 } 330 }
131 return NULL; 331 return NULL;
132} 332}
133 333
334static void *accesslist_adder_worker(void *args) {
335 (void)args;
336 return accesslist_adddel_worker(g_accesslist_pipe_add, &g_accesslist_add, &g_accesslist_delete);
337}
338static void *accesslist_deleter_worker(void *args) {
339 (void)args;
340 return accesslist_adddel_worker(g_accesslist_pipe_delete, &g_accesslist_delete, &g_accesslist_add);
341}
342#endif
343
134static pthread_t thread_id; 344static pthread_t thread_id;
135void accesslist_init( ) { 345void accesslist_init() {
136 pthread_mutex_init(&g_accesslist_mutex, NULL); 346 pthread_mutex_init(&g_accesslist_mutex, NULL);
137 pthread_create( &thread_id, NULL, accesslist_worker, NULL ); 347 pthread_create(&thread_id, NULL, accesslist_worker, NULL);
348#ifdef WANT_DYNAMIC_ACCESSLIST
349 if (g_accesslist_pipe_add)
350 pthread_create(&thread_adder_id, NULL, accesslist_adder_worker, NULL);
351 if (g_accesslist_pipe_delete)
352 pthread_create(&thread_deleter_id, NULL, accesslist_deleter_worker, NULL);
353#endif
138} 354}
139 355
140void accesslist_deinit( void ) { 356void accesslist_deinit(void) {
141 pthread_cancel( thread_id ); 357 /* Wake up sleeping worker */
358 pthread_kill(thread_id, SIGHUP);
359
360 pthread_mutex_lock(&g_accesslist_mutex);
361
362 g_accesslist = accesslist_free(g_accesslist);
363
364#ifdef WANT_DYNAMIC_ACCESSLIST
365 g_accesslist_add = accesslist_free(g_accesslist_add);
366 g_accesslist_delete = accesslist_free(g_accesslist_delete);
367#endif
368
369 pthread_mutex_unlock(&g_accesslist_mutex);
370 pthread_cancel(thread_id);
142 pthread_mutex_destroy(&g_accesslist_mutex); 371 pthread_mutex_destroy(&g_accesslist_mutex);
143 free( g_accesslist ); 372}
144 g_accesslist = 0; 373
145 g_accesslist_size = 0; 374void accesslist_cleanup(void) {
375 pthread_mutex_lock(&g_accesslist_mutex);
376
377 accesslist_clean(g_accesslist);
378#if WANT_DYNAMIC_ACCESSLIST
379 accesslist_clean(g_accesslist_add);
380 accesslist_clean(g_accesslist_delete);
381#endif
382
383 pthread_mutex_unlock(&g_accesslist_mutex);
146} 384}
147#endif 385#endif
148 386
149int address_in_net( const ot_ip6 address, const ot_net *net ) { 387int address_in_net(const ot_ip6 address, const ot_net *net) {
150 int bits = net->bits; 388 int bits = net->bits, checkbits = (0x7f00 >> (bits & 7));
151 int result = memcmp( address, &net->address, bits >> 3 ); 389 int result = memcmp(address, &net->address, bits >> 3);
152 if( !result && ( bits & 7 ) ) 390 if (!result && (bits & 7))
153 result = ( ( 0x7f00 >> ( bits & 7 ) ) & address[bits>>3] ) - net->address[bits>>3]; 391 result = (checkbits & address[bits >> 3]) - (checkbits & net->address[bits >> 3]);
154 return result == 0; 392 return result == 0;
155} 393}
156 394
157void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value, const size_t member_size ) { 395void *set_value_for_net(const ot_net *net, ot_vector *vector, const void *value, const size_t member_size) {
158 size_t i; 396 size_t i;
159 int exactmatch; 397 int exactmatch;
160 398
161 /* Caller must have a concept of ot_net in it's member */ 399 /* Caller must have a concept of ot_net in it's member */
162 if( member_size < sizeof(ot_net) ) 400 if (member_size < sizeof(ot_net))
163 return 0; 401 return 0;
164 402
165 /* Check each net in vector for overlap */ 403 /* Check each net in vector for overlap */
166 uint8_t *member = ((uint8_t*)vector->data); 404 uint8_t *member = ((uint8_t *)vector->data);
167 for( i=0; i<vector->size; ++i ) { 405 for (i = 0; i < vector->size; ++i) {
168 if( address_in_net( *(ot_ip6*)member, net ) || 406 if (address_in_net(*(ot_ip6 *)member, net) || address_in_net(net->address, (ot_net *)member))
169 address_in_net( net->address, (ot_net*)member ) )
170 return 0; 407 return 0;
171 member += member_size; 408 member += member_size;
172 } 409 }
173 410
174 member = vector_find_or_insert( vector, (void*)net, member_size, sizeof(ot_net), &exactmatch ); 411 member = vector_find_or_insert(vector, (void *)net, member_size, sizeof(ot_net), &exactmatch);
175 if( member ) { 412 if (member) {
176 memcpy( member, net, sizeof(ot_net)); 413 memcpy(member, net, sizeof(ot_net));
177 memcpy( member + sizeof(ot_net), value, member_size - sizeof(ot_net)); 414 memcpy(member + sizeof(ot_net), value, member_size - sizeof(ot_net));
178 } 415 }
179 416
180 return member; 417 return member;
@@ -182,43 +419,43 @@ void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value
182 419
183/* Takes a vector filled with { ot_net net, uint8_t[x] value }; 420/* Takes a vector filled with { ot_net net, uint8_t[x] value };
184 Returns value associated with the net, or NULL if not found */ 421 Returns value associated with the net, or NULL if not found */
185void *get_value_for_net( const ot_ip6 address, const ot_vector *vector, const size_t member_size ) { 422void *get_value_for_net(const ot_ip6 address, const ot_vector *vector, const size_t member_size) {
186 int exactmatch; 423 int exactmatch;
187 /* This binary search will return a pointer to the first non-containing network... */ 424 /* This binary search will return a pointer to the first non-containing network... */
188 ot_net *net = binary_search( address, vector->data, vector->size, member_size, sizeof(ot_ip6), &exactmatch ); 425 ot_net *net = binary_search(address, vector->data, vector->size, member_size, sizeof(ot_ip6), &exactmatch);
189 if( !net ) 426 if (!net)
190 return NULL; 427 return NULL;
191 /* ... so we'll need to move back one step unless we've exactly hit the first address in network */ 428 /* ... so we'll need to move back one step unless we've exactly hit the first address in network */
192 if( !exactmatch && ( (void*)net > vector->data ) ) 429 if (!exactmatch && ((void *)net > vector->data))
193 --net; 430 --net;
194 if( !address_in_net( address, net ) ) 431 if (!address_in_net(address, net))
195 return NULL; 432 return NULL;
196 return (void*)net; 433 return (void *)net;
197} 434}
198 435
199#ifdef WANT_FULLLOG_NETWORKS 436#ifdef WANT_FULLLOG_NETWORKS
200static ot_vector g_lognets_list; 437static ot_vector g_lognets_list;
201ot_log *g_logchain_first, *g_logchain_last; 438ot_log *g_logchain_first, *g_logchain_last;
202
203static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER; 439static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER;
204void loglist_add_network( const ot_net *net ) { 440
441void loglist_add_network(const ot_net *net) {
205 pthread_mutex_lock(&g_lognets_list_mutex); 442 pthread_mutex_lock(&g_lognets_list_mutex);
206 set_value_for_net( net, &g_lognets_list, NULL, sizeof(ot_net)); 443 set_value_for_net(net, &g_lognets_list, NULL, sizeof(ot_net));
207 pthread_mutex_unlock(&g_lognets_list_mutex); 444 pthread_mutex_unlock(&g_lognets_list_mutex);
208} 445}
209 446
210void loglist_reset( ) { 447void loglist_reset() {
211 pthread_mutex_lock(&g_lognets_list_mutex); 448 pthread_mutex_lock(&g_lognets_list_mutex);
212 free( g_lognets_list.data ); 449 free(g_lognets_list.data);
213 g_lognets_list.data = 0; 450 g_lognets_list.data = 0;
214 g_lognets_list.size = g_lognets_list.space = 0; 451 g_lognets_list.size = g_lognets_list.space = 0;
215 pthread_mutex_unlock(&g_lognets_list_mutex); 452 pthread_mutex_unlock(&g_lognets_list_mutex);
216} 453}
217 454
218int loglist_check_address( const ot_ip6 address ) { 455int loglist_check_address(const ot_ip6 address) {
219 int result; 456 int result;
220 pthread_mutex_lock(&g_lognets_list_mutex); 457 pthread_mutex_lock(&g_lognets_list_mutex);
221 result = ( NULL != get_value_for_net( address, &g_lognets_list, sizeof(ot_net)) ); 458 result = (NULL != get_value_for_net(address, &g_lognets_list, sizeof(ot_net)));
222 pthread_mutex_unlock(&g_lognets_list_mutex); 459 pthread_mutex_unlock(&g_lognets_list_mutex);
223 return result; 460 return result;
224} 461}
@@ -226,44 +463,44 @@ int loglist_check_address( const ot_ip6 address ) {
226 463
227#ifdef WANT_IP_FROM_PROXY 464#ifdef WANT_IP_FROM_PROXY
228typedef struct { 465typedef struct {
229 ot_net *proxy; 466 ot_net *proxy;
230 ot_vector networks; 467 ot_vector networks;
231} ot_proxymap; 468} ot_proxymap;
232 469
233static ot_vector g_proxies_list; 470static ot_vector g_proxies_list;
234static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER; 471static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER;
235 472
236int proxylist_add_network( const ot_net *proxy, const ot_net *net ) { 473int proxylist_add_network(const ot_net *proxy, const ot_net *net) {
237 ot_proxymap *map; 474 ot_proxymap *map;
238 int exactmatch, result = 1; 475 int exactmatch, result = 1;
239 pthread_mutex_lock(&g_proxies_list_mutex); 476 pthread_mutex_lock(&g_proxies_list_mutex);
240 477
241 /* If we have a direct hit, use and extend the vector there */ 478 /* If we have a direct hit, use and extend the vector there */
242 map = binary_search( proxy, g_proxies_list.data, g_proxies_list.size, sizeof(ot_proxymap), sizeof(ot_net), &exactmatch ); 479 map = binary_search(proxy, g_proxies_list.data, g_proxies_list.size, sizeof(ot_proxymap), sizeof(ot_net), &exactmatch);
243 480
244 if( !map || !exactmatch ) { 481 if (!map || !exactmatch) {
245 /* else see, if we've got overlapping networks 482 /* else see, if we've got overlapping networks
246 and get a new empty vector if not */ 483 and get a new empty vector if not */
247 ot_vector empty; 484 ot_vector empty;
248 memset( &empty, 0, sizeof( ot_vector ) ); 485 memset(&empty, 0, sizeof(ot_vector));
249 map = set_value_for_net( proxy, &g_proxies_list, &empty, sizeof(ot_proxymap)); 486 map = set_value_for_net(proxy, &g_proxies_list, &empty, sizeof(ot_proxymap));
250 } 487 }
251 488
252 if( map && set_value_for_net( net, &map->networks, NULL, sizeof(ot_net) ) ) 489 if (map && set_value_for_net(net, &map->networks, NULL, sizeof(ot_net)))
253 result = 1; 490 result = 1;
254 491
255 pthread_mutex_unlock(&g_proxies_list_mutex); 492 pthread_mutex_unlock(&g_proxies_list_mutex);
256 return result; 493 return result;
257} 494}
258 495
259int proxylist_check_proxy( const ot_ip6 proxy, const ot_ip6 address ) { 496int proxylist_check_proxy(const ot_ip6 proxy, const ot_ip6 address) {
260 int result = 0; 497 int result = 0;
261 ot_proxymap *map; 498 ot_proxymap *map;
262 499
263 pthread_mutex_lock(&g_proxies_list_mutex); 500 pthread_mutex_lock(&g_proxies_list_mutex);
264 501
265 if( ( map = get_value_for_net( proxy, &g_proxies_list, sizeof(ot_proxymap) ) ) ) 502 if ((map = get_value_for_net(proxy, &g_proxies_list, sizeof(ot_proxymap))))
266 if( !address || get_value_for_net( address, &map->networks, sizeof(ot_net) ) ) 503 if (!address || get_value_for_net(address, &map->networks, sizeof(ot_net)))
267 result = 1; 504 result = 1;
268 505
269 pthread_mutex_unlock(&g_proxies_list_mutex); 506 pthread_mutex_unlock(&g_proxies_list_mutex);
@@ -272,42 +509,53 @@ int proxylist_check_proxy( const ot_ip6 proxy, const ot_ip6 address ) {
272 509
273#endif 510#endif
274 511
275static ot_ip6 g_adminip_addresses[OT_ADMINIP_MAX]; 512static ot_net g_admin_nets[OT_ADMINIP_MAX];
276static ot_permissions g_adminip_permissions[OT_ADMINIP_MAX]; 513static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX];
277static unsigned int g_adminip_count = 0; 514static unsigned int g_admin_nets_count = 0;
278 515
279int accesslist_blessip( ot_ip6 ip, ot_permissions permissions ) { 516int accesslist_bless_net(ot_net *net, ot_permissions permissions) {
280 if( g_adminip_count >= OT_ADMINIP_MAX ) 517 if (g_admin_nets_count >= OT_ADMINIP_MAX)
281 return -1; 518 return -1;
282 519
283 memcpy(g_adminip_addresses + g_adminip_count,ip,sizeof(ot_ip6)); 520 memcpy(g_admin_nets + g_admin_nets_count, net, sizeof(ot_net));
284 g_adminip_permissions[ g_adminip_count++ ] = permissions; 521 g_admin_nets_permissions[g_admin_nets_count++] = permissions;
285 522
286#ifdef _DEBUG 523#ifdef _DEBUG
287 { 524 {
288 char _debug[512]; 525 char _debug[512];
289 int off = snprintf( _debug, sizeof(_debug), "Blessing ip address " ); 526 int off = snprintf(_debug, sizeof(_debug), "Blessing ip net ");
290 off += fmt_ip6c(_debug+off, ip ); 527 off += fmt_ip6c(_debug + off, net->address);
291 528 if (net->bits < 128) {
292 if( permissions & OT_PERMISSION_MAY_STAT ) off += snprintf( _debug+off, 512-off, " may_fetch_stats" ); 529 _debug[off++] = '/';
293 if( permissions & OT_PERMISSION_MAY_LIVESYNC ) off += snprintf( _debug+off, 512-off, " may_sync_live" ); 530 if (ip6_isv4mapped(net->address))
294 if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) off += snprintf( _debug+off, 512-off, " may_fetch_fullscrapes" ); 531 off += fmt_long(_debug + off, net->bits - 96);
295 if( permissions & OT_PERMISSION_MAY_PROXY ) off += snprintf( _debug+off, 512-off, " may_proxy" ); 532 else
296 if( !permissions ) off += snprintf( _debug+off, sizeof(_debug)-off, " nothing\n" ); 533 off += fmt_long(_debug + off, net->bits);
534 }
535
536 if (permissions & OT_PERMISSION_MAY_STAT)
537 off += snprintf(_debug + off, 512 - off, " may_fetch_stats");
538 if (permissions & OT_PERMISSION_MAY_LIVESYNC)
539 off += snprintf(_debug + off, 512 - off, " may_sync_live");
540 if (permissions & OT_PERMISSION_MAY_FULLSCRAPE)
541 off += snprintf(_debug + off, 512 - off, " may_fetch_fullscrapes");
542 if (permissions & OT_PERMISSION_MAY_PROXY)
543 off += snprintf(_debug + off, 512 - off, " may_proxy");
544 if (!permissions)
545 off += snprintf(_debug + off, sizeof(_debug) - off, " nothing");
297 _debug[off++] = '.'; 546 _debug[off++] = '.';
298 write( 2, _debug, off ); 547 _debug[off++] = '\n';
548 (void)write(2, _debug, off);
299 } 549 }
300#endif 550#endif
301 551
302 return 0; 552 return 0;
303} 553}
304 554
305int accesslist_isblessed( ot_ip6 ip, ot_permissions permissions ) { 555int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) {
306 unsigned int i; 556 unsigned int i;
307 for( i=0; i<g_adminip_count; ++i ) 557 for (i = 0; i < g_admin_nets_count; ++i)
308 if( !memcmp( g_adminip_addresses + i, ip, sizeof(ot_ip6)) && ( g_adminip_permissions[ i ] & permissions ) ) 558 if (address_in_net(ip, g_admin_nets + i) && (g_admin_nets_permissions[i] & permissions))
309 return 1; 559 return 1;
310 return 0; 560 return 0;
311} 561}
312
313const char *g_version_accesslist_c = "$Source$: $Revision$\n";