summaryrefslogtreecommitdiff
path: root/ot_accesslist.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_accesslist.c')
-rw-r--r--ot_accesslist.c506
1 files changed, 364 insertions, 142 deletions
diff --git a/ot_accesslist.c b/ot_accesslist.c
index 3154e7f..4b88c40 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -5,121 +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;
34#ifdef WANT_DYNAMIC_ACCESSLIST
35char *g_accesslist_pipe_add = NULL;
36char *g_accesslist_pipe_delete = NULL;
37#endif
28static pthread_mutex_t g_accesslist_mutex; 38static pthread_mutex_t g_accesslist_mutex;
29 39
30typedef struct { 40/* Accesslists are lock free linked lists. We can not make them locking, because every announce
31 ot_hash *list; 41 would try to acquire the mutex, making it the most contested mutex in the whole of opentracker,
32 size_t size; 42 basically creating a central performance choke point.
33} ot_accesslist; 43
34ot_accesslist * g_accesslist = NULL; 44 The idea is that updating the list heads happens under the g_accesslist_mutex guard and is
35ot_accesslist * g_accesslist_old = NULL; 45 done atomically, while consumers might potentially still hold pointers deeper inside the list.
36 46
37static int vector_compare_hash(const void *hash1, const void *hash2 ) { 47 Consumers (for now only via accesslist_hashisvalid) will always fetch the list head pointer
38 return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); 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 }
39} 100}
40 101
41/* Read initial access list */ 102/* Read initial access list */
42static void accesslist_readfile( void ) { 103static void accesslist_readfile(void) {
43 ot_accesslist * accesslist_new = malloc(sizeof(ot_accesslist)); 104 ot_accesslist *accesslist_new;
44 ot_hash *info_hash; 105 ot_hash *info_hash;
45 const char *map, *map_end, *read_offs; 106 const char *map, *map_end, *read_offs;
46 size_t maplen; 107 size_t maplen;
47 108
48 if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) { 109 if ((map = mmap_read(g_accesslist_filename, &maplen)) == NULL) {
49 char *wd = getcwd( NULL, 0 ); 110 char *wd = getcwd(NULL, 0);
50 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 ); 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);
51 free( wd ); 112 free(wd);
52 return; 113 return;
53 } 114 }
54 115
55 /* 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
56 for the maximum amount of them */ 117 for the maximum amount of them */
57 accesslist_new->size = 0; 118 accesslist_new = accesslist_make(g_accesslist, maplen / 41);
58 info_hash = accesslist_new->list = malloc( ( maplen / 41 ) * 20 ); 119 if (!accesslist_new) {
59 if( !accesslist_new->list ) { 120 fprintf(stderr, "Warning: Not enough memory to allocate %zd bytes for accesslist buffer. May succeed later.\n", (maplen / 41) * 20);
60 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);
61 mmap_unmap( map, maplen);
62 free(accesslist_new);
63 return; 122 return;
64 } 123 }
124 info_hash = accesslist_new->list;
65 125
66 /* 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 */
67 map_end = map + maplen - 40; 127 map_end = map + maplen - 40;
68 read_offs = map; 128 read_offs = map;
69 129
70 /* 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:].*" */
71 while( read_offs <= map_end ) { 131 while (read_offs <= map_end) {
72 int i; 132 int i;
73 for( i=0; i<(int)sizeof(ot_hash); ++i ) { 133 for (i = 0; i < (int)sizeof(ot_hash); ++i) {
74 int eger1 = scan_fromhex( read_offs[ 2*i ] ); 134 int eger1 = scan_fromhex((unsigned char)read_offs[2 * i]);
75 int eger2 = scan_fromhex( read_offs[ 1 + 2*i ] ); 135 int eger2 = scan_fromhex((unsigned char)read_offs[1 + 2 * i]);
76 if( eger1 < 0 || eger2 < 0 ) 136 if (eger1 < 0 || eger2 < 0)
77 break; 137 break;
78 (*info_hash)[i] = eger1 * 16 + eger2; 138 (*info_hash)[i] = (uint8_t)(eger1 * 16 + eger2);
79 } 139 }
80 140
81 if( i == sizeof(ot_hash) ) { 141 if (i == sizeof(ot_hash)) {
82 read_offs += 40; 142 read_offs += 40;
83 143
84 /* Append accesslist to accesslist vector */ 144 /* Append accesslist to accesslist vector */
85 if( read_offs == map_end || scan_fromhex( *read_offs ) < 0 ) 145 if (read_offs == map_end || scan_fromhex((unsigned char)*read_offs) < 0)
86 ++info_hash; 146 ++info_hash;
87 } 147 }
88 148
89 /* Find start of next line */ 149 /* Find start of next line */
90 while( read_offs <= map_end && *(read_offs++) != '\n' ); 150 while (read_offs <= map_end && *(read_offs++) != '\n')
151 ;
91 } 152 }
92#ifdef _DEBUG 153#ifdef _DEBUG
93 fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list) ); 154 fprintf(stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new->list));
94#endif 155#endif
95 156
96 mmap_unmap( map, maplen); 157 mmap_unmap(map, maplen);
97 158
98 qsort( accesslist_new->list, info_hash - accesslist_new->list, sizeof( *info_hash ), vector_compare_hash ); 159 qsort(accesslist_new->list, info_hash - accesslist_new->list, sizeof(*info_hash), vector_compare_hash);
99 accesslist_new->size = info_hash - accesslist_new->list; 160 accesslist_new->size = info_hash - accesslist_new->list;
100 161
101 /* 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 */
102 pthread_mutex_lock(&g_accesslist_mutex); 163 pthread_mutex_lock(&g_accesslist_mutex);
164 accesslist_new->next = g_accesslist;
165 g_accesslist = accesslist_new; /* Only now set a new list */
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
103 175
104 if (g_accesslist_old) { 176 accesslist_clean(g_accesslist);
105 free(g_accesslist_old->list);
106 free(g_accesslist_old);
107 }
108
109 g_accesslist_old = g_accesslist; /* Keep a copy for later free */
110 g_accesslist = accesslist_new; /* Only now set a new list */
111 177
112 pthread_mutex_unlock(&g_accesslist_mutex); 178 pthread_mutex_unlock(&g_accesslist_mutex);
113} 179}
114 180
115int accesslist_hashisvalid( ot_hash hash ) { 181int accesslist_hashisvalid(ot_hash hash) {
116 /* Get working copy of current access list */ 182 /* Get working copy of current access list */
117 ot_accesslist * accesslist = g_accesslist; 183 ot_accesslist *accesslist = g_accesslist;
118 184#ifdef WANT_DYNAMIC_ACCESSLIST
119 void * exactmatch = NULL; 185 ot_accesslist *accesslist_add, *accesslist_delete;
186#endif
187 void *exactmatch = NULL;
120 188
121 if (accesslist) 189 if (accesslist)
122 exactmatch = bsearch( hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); 190 exactmatch = bsearch(hash, accesslist->list, accesslist->size, OT_HASH_COMPARE_SIZE, vector_compare_hash);
191
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
123 203
124#ifdef WANT_ACCESSLIST_BLACK 204#ifdef WANT_ACCESSLIST_BLACK
125 return exactmatch == NULL; 205 return exactmatch == NULL;
@@ -128,79 +208,210 @@ int accesslist_hashisvalid( ot_hash hash ) {
128#endif 208#endif
129} 209}
130 210
131static void * accesslist_worker( void * args ) { 211static void *accesslist_worker(void *args) {
132 int sig; 212 int sig;
133 sigset_t signal_mask; 213 sigset_t signal_mask;
134 214
135 sigemptyset(&signal_mask); 215 sigemptyset(&signal_mask);
136 sigaddset(&signal_mask, SIGHUP); 216 sigaddset(&signal_mask, SIGHUP);
137 217
138 (void)args; 218 (void)args;
139 219
140 while( 1 ) { 220 while (1) {
221 if (!g_opentracker_running)
222 return NULL;
141 223
142 /* Initial attempt to read accesslist */ 224 /* Initial attempt to read accesslist */
143 accesslist_readfile( ); 225 accesslist_readfile();
144 226
145 /* Wait for signals */ 227 /* Wait for signals */
146 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);
147 } 330 }
148 return NULL; 331 return NULL;
149} 332}
150 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
151static pthread_t thread_id; 344static pthread_t thread_id;
152void accesslist_init( ) { 345void accesslist_init() {
153 pthread_mutex_init(&g_accesslist_mutex, NULL); 346 pthread_mutex_init(&g_accesslist_mutex, NULL);
154 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
155} 354}
156 355
157void accesslist_deinit( void ) { 356void accesslist_deinit(void) {
158 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);
159 pthread_mutex_destroy(&g_accesslist_mutex); 371 pthread_mutex_destroy(&g_accesslist_mutex);
372}
160 373
161 if (g_accesslist_old) { 374void accesslist_cleanup(void) {
162 free(g_accesslist_old->list); 375 pthread_mutex_lock(&g_accesslist_mutex);
163 free(g_accesslist_old);
164 g_accesslist_old = 0;
165 }
166 376
167 if (g_accesslist) { 377 accesslist_clean(g_accesslist);
168 free(g_accesslist->list); 378#if WANT_DYNAMIC_ACCESSLIST
169 free(g_accesslist); 379 accesslist_clean(g_accesslist_add);
170 g_accesslist = 0; 380 accesslist_clean(g_accesslist_delete);
171 } 381#endif
382
383 pthread_mutex_unlock(&g_accesslist_mutex);
172} 384}
173#endif 385#endif
174 386
175int address_in_net( const ot_ip6 address, const ot_net *net ) { 387int address_in_net(const ot_ip6 address, const ot_net *net) {
176 int bits = net->bits; 388 int bits = net->bits, checkbits = (0x7f00 >> (bits & 7));
177 int result = memcmp( address, &net->address, bits >> 3 ); 389 int result = memcmp(address, &net->address, bits >> 3);
178 if( !result && ( bits & 7 ) ) 390 if (!result && (bits & 7))
179 result = ( ( 0x7f00 >> ( bits & 7 ) ) & address[bits>>3] ) - net->address[bits>>3]; 391 result = (checkbits & address[bits >> 3]) - (checkbits & net->address[bits >> 3]);
180 return result == 0; 392 return result == 0;
181} 393}
182 394
183void *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) {
184 size_t i; 396 size_t i;
185 int exactmatch; 397 int exactmatch;
186 398
187 /* 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 */
188 if( member_size < sizeof(ot_net) ) 400 if (member_size < sizeof(ot_net))
189 return 0; 401 return 0;
190 402
191 /* Check each net in vector for overlap */ 403 /* Check each net in vector for overlap */
192 uint8_t *member = ((uint8_t*)vector->data); 404 uint8_t *member = ((uint8_t *)vector->data);
193 for( i=0; i<vector->size; ++i ) { 405 for (i = 0; i < vector->size; ++i) {
194 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))
195 address_in_net( net->address, (ot_net*)member ) )
196 return 0; 407 return 0;
197 member += member_size; 408 member += member_size;
198 } 409 }
199 410
200 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);
201 if( member ) { 412 if (member) {
202 memcpy( member, net, sizeof(ot_net)); 413 memcpy(member, net, sizeof(ot_net));
203 memcpy( member + sizeof(ot_net), value, member_size - sizeof(ot_net)); 414 memcpy(member + sizeof(ot_net), value, member_size - sizeof(ot_net));
204 } 415 }
205 416
206 return member; 417 return member;
@@ -208,43 +419,43 @@ void *set_value_for_net( const ot_net *net, ot_vector *vector, const void *value
208 419
209/* 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 };
210 Returns value associated with the net, or NULL if not found */ 421 Returns value associated with the net, or NULL if not found */
211void *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) {
212 int exactmatch; 423 int exactmatch;
213 /* 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... */
214 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);
215 if( !net ) 426 if (!net)
216 return NULL; 427 return NULL;
217 /* ... 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 */
218 if( !exactmatch && ( (void*)net > vector->data ) ) 429 if (!exactmatch && ((void *)net > vector->data))
219 --net; 430 --net;
220 if( !address_in_net( address, net ) ) 431 if (!address_in_net(address, net))
221 return NULL; 432 return NULL;
222 return (void*)net; 433 return (void *)net;
223} 434}
224 435
225#ifdef WANT_FULLLOG_NETWORKS 436#ifdef WANT_FULLLOG_NETWORKS
226static ot_vector g_lognets_list; 437static ot_vector g_lognets_list;
227ot_log *g_logchain_first, *g_logchain_last; 438ot_log *g_logchain_first, *g_logchain_last;
228
229static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER; 439static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER;
230void loglist_add_network( const ot_net *net ) { 440
441void loglist_add_network(const ot_net *net) {
231 pthread_mutex_lock(&g_lognets_list_mutex); 442 pthread_mutex_lock(&g_lognets_list_mutex);
232 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));
233 pthread_mutex_unlock(&g_lognets_list_mutex); 444 pthread_mutex_unlock(&g_lognets_list_mutex);
234} 445}
235 446
236void loglist_reset( ) { 447void loglist_reset() {
237 pthread_mutex_lock(&g_lognets_list_mutex); 448 pthread_mutex_lock(&g_lognets_list_mutex);
238 free( g_lognets_list.data ); 449 free(g_lognets_list.data);
239 g_lognets_list.data = 0; 450 g_lognets_list.data = 0;
240 g_lognets_list.size = g_lognets_list.space = 0; 451 g_lognets_list.size = g_lognets_list.space = 0;
241 pthread_mutex_unlock(&g_lognets_list_mutex); 452 pthread_mutex_unlock(&g_lognets_list_mutex);
242} 453}
243 454
244int loglist_check_address( const ot_ip6 address ) { 455int loglist_check_address(const ot_ip6 address) {
245 int result; 456 int result;
246 pthread_mutex_lock(&g_lognets_list_mutex); 457 pthread_mutex_lock(&g_lognets_list_mutex);
247 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)));
248 pthread_mutex_unlock(&g_lognets_list_mutex); 459 pthread_mutex_unlock(&g_lognets_list_mutex);
249 return result; 460 return result;
250} 461}
@@ -252,44 +463,44 @@ int loglist_check_address( const ot_ip6 address ) {
252 463
253#ifdef WANT_IP_FROM_PROXY 464#ifdef WANT_IP_FROM_PROXY
254typedef struct { 465typedef struct {
255 ot_net *proxy; 466 ot_net *proxy;
256 ot_vector networks; 467 ot_vector networks;
257} ot_proxymap; 468} ot_proxymap;
258 469
259static ot_vector g_proxies_list; 470static ot_vector g_proxies_list;
260static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER; 471static pthread_mutex_t g_proxies_list_mutex = PTHREAD_MUTEX_INITIALIZER;
261 472
262int proxylist_add_network( const ot_net *proxy, const ot_net *net ) { 473int proxylist_add_network(const ot_net *proxy, const ot_net *net) {
263 ot_proxymap *map; 474 ot_proxymap *map;
264 int exactmatch, result = 1; 475 int exactmatch, result = 1;
265 pthread_mutex_lock(&g_proxies_list_mutex); 476 pthread_mutex_lock(&g_proxies_list_mutex);
266 477
267 /* 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 */
268 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);
269 480
270 if( !map || !exactmatch ) { 481 if (!map || !exactmatch) {
271 /* else see, if we've got overlapping networks 482 /* else see, if we've got overlapping networks
272 and get a new empty vector if not */ 483 and get a new empty vector if not */
273 ot_vector empty; 484 ot_vector empty;
274 memset( &empty, 0, sizeof( ot_vector ) ); 485 memset(&empty, 0, sizeof(ot_vector));
275 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));
276 } 487 }
277 488
278 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)))
279 result = 1; 490 result = 1;
280 491
281 pthread_mutex_unlock(&g_proxies_list_mutex); 492 pthread_mutex_unlock(&g_proxies_list_mutex);
282 return result; 493 return result;
283} 494}
284 495
285int proxylist_check_proxy( const ot_ip6 proxy, const ot_ip6 address ) { 496int proxylist_check_proxy(const ot_ip6 proxy, const ot_ip6 address) {
286 int result = 0; 497 int result = 0;
287 ot_proxymap *map; 498 ot_proxymap *map;
288 499
289 pthread_mutex_lock(&g_proxies_list_mutex); 500 pthread_mutex_lock(&g_proxies_list_mutex);
290 501
291 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))))
292 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)))
293 result = 1; 504 result = 1;
294 505
295 pthread_mutex_unlock(&g_proxies_list_mutex); 506 pthread_mutex_unlock(&g_proxies_list_mutex);
@@ -298,42 +509,53 @@ int proxylist_check_proxy( const ot_ip6 proxy, const ot_ip6 address ) {
298 509
299#endif 510#endif
300 511
301static ot_ip6 g_adminip_addresses[OT_ADMINIP_MAX]; 512static ot_net g_admin_nets[OT_ADMINIP_MAX];
302static ot_permissions g_adminip_permissions[OT_ADMINIP_MAX]; 513static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX];
303static unsigned int g_adminip_count = 0; 514static unsigned int g_admin_nets_count = 0;
304 515
305int accesslist_blessip( ot_ip6 ip, ot_permissions permissions ) { 516int accesslist_bless_net(ot_net *net, ot_permissions permissions) {
306 if( g_adminip_count >= OT_ADMINIP_MAX ) 517 if (g_admin_nets_count >= OT_ADMINIP_MAX)
307 return -1; 518 return -1;
308 519
309 memcpy(g_adminip_addresses + g_adminip_count,ip,sizeof(ot_ip6)); 520 memcpy(g_admin_nets + g_admin_nets_count, net, sizeof(ot_net));
310 g_adminip_permissions[ g_adminip_count++ ] = permissions; 521 g_admin_nets_permissions[g_admin_nets_count++] = permissions;
311 522
312#ifdef _DEBUG 523#ifdef _DEBUG
313 { 524 {
314 char _debug[512]; 525 char _debug[512];
315 int off = snprintf( _debug, sizeof(_debug), "Blessing ip address " ); 526 int off = snprintf(_debug, sizeof(_debug), "Blessing ip net ");
316 off += fmt_ip6c(_debug+off, ip ); 527 off += fmt_ip6c(_debug + off, net->address);
317 528 if (net->bits < 128) {
318 if( permissions & OT_PERMISSION_MAY_STAT ) off += snprintf( _debug+off, 512-off, " may_fetch_stats" ); 529 _debug[off++] = '/';
319 if( permissions & OT_PERMISSION_MAY_LIVESYNC ) off += snprintf( _debug+off, 512-off, " may_sync_live" ); 530 if (ip6_isv4mapped(net->address))
320 if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) off += snprintf( _debug+off, 512-off, " may_fetch_fullscrapes" ); 531 off += fmt_long(_debug + off, net->bits - 96);
321 if( permissions & OT_PERMISSION_MAY_PROXY ) off += snprintf( _debug+off, 512-off, " may_proxy" ); 532 else
322 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");
323 _debug[off++] = '.'; 546 _debug[off++] = '.';
324 write( 2, _debug, off ); 547 _debug[off++] = '\n';
548 (void)write(2, _debug, off);
325 } 549 }
326#endif 550#endif
327 551
328 return 0; 552 return 0;
329} 553}
330 554
331int accesslist_isblessed( ot_ip6 ip, ot_permissions permissions ) { 555int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) {
332 unsigned int i; 556 unsigned int i;
333 for( i=0; i<g_adminip_count; ++i ) 557 for (i = 0; i < g_admin_nets_count; ++i)
334 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))
335 return 1; 559 return 1;
336 return 0; 560 return 0;
337} 561}
338
339const char *g_version_accesslist_c = "$Source$: $Revision$\n";