aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--doc/man/gnunet-nat.110
-rw-r--r--doc/structure.dot5
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/gns/gns.conf.in4
-rw-r--r--src/gns/gnunet-service-gns.c647
-rw-r--r--src/gns/gnunet-service-gns_reverser.c5
-rw-r--r--src/vpn/vpn.conf.in2
-rw-r--r--src/zonemaster/Makefile.am35
-rw-r--r--src/zonemaster/gnunet-service-zonemaster.c773
-rw-r--r--src/zonemaster/zonemaster.conf.in25
11 files changed, 857 insertions, 653 deletions
diff --git a/configure.ac b/configure.ac
index faf058849..c41bcc4b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1641,6 +1641,8 @@ src/util/Makefile
1641src/util/resolver.conf 1641src/util/resolver.conf
1642src/vpn/Makefile 1642src/vpn/Makefile
1643src/vpn/vpn.conf 1643src/vpn/vpn.conf
1644src/zonemaster/Makefile
1645src/zonemaster/zonemaster.conf
1644src/rest/Makefile 1646src/rest/Makefile
1645src/identity-provider/Makefile 1647src/identity-provider/Makefile
1646pkgconfig/Makefile 1648pkgconfig/Makefile
diff --git a/doc/man/gnunet-nat.1 b/doc/man/gnunet-nat.1
index 5bdbb21eb..a834a1d96 100644
--- a/doc/man/gnunet-nat.1
+++ b/doc/man/gnunet-nat.1
@@ -81,13 +81,15 @@ We are bound to "127.0.0.1:8080" on UDP and want to obtain all applicable IP add
81 81
82\fBICMP-based NAT traversal:\fR 82\fBICMP-based NAT traversal:\fR
83 83
84Watch for connection reversal request: 84Watch for connection reversal request (you must be bound to NAT range or to wildcard, 0.0.0.0), only works for IPv4:
85 85
86 # gnunet-nat FIXME 86 # gnunet-nat -Wt -i 192.168.178.12:8080
87 87
88Initiate connection reversal request: 88Initiate connection reversal request from peer at external IPv4 address 1.2.3.4 while we are running ourselves at 2.3.4.5:8080 (must use IPv4 addresses):
89 89
90 # gnunet-nat FIXME 90 # gnunet-nat -t -r 1.2.3.4:8080 -i 2.3.4.5:8080
91
92 # gnunet-nat -t -r 1.2.3.4:8080 -i 0.0.0.0:8080 ### TEST THIS!
91 93
92\fBManual hole punching:\fR 94\fBManual hole punching:\fR
93 95
diff --git a/doc/structure.dot b/doc/structure.dot
index 2a30c7c17..e244d20b8 100644
--- a/doc/structure.dot
+++ b/doc/structure.dot
@@ -41,8 +41,9 @@ splines = true;
41 dv -> ats; 41 dv -> ats;
42 dns -> tun; 42 dns -> tun;
43 dns -> dnsstub; 43 dns -> dnsstub;
44 gns [shape=house]; 44 zonemaster [shape=house];
45 gns -> namestore; 45 zonemaster -> namestore;
46 zonemaster -> dht;
46 gns -> dns; 47 gns -> dns;
47 gns -> dht; 48 gns -> dht;
48 gns -> block [style=dotted,color=blue]; 49 gns -> block [style=dotted,color=blue];
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 80aab7123..56af200ff 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -245,6 +245,7 @@ src/nat/gnunet-nat.c
245src/nat/gnunet-nat-server.c 245src/nat/gnunet-nat-server.c
246src/nat/gnunet-service-nat.c 246src/nat/gnunet-service-nat.c
247src/nat/gnunet-service-nat_helper.c 247src/nat/gnunet-service-nat_helper.c
248src/nat/gnunet-service-nat_mini.c
248src/nat/gnunet-service-nat_stun.c 249src/nat/gnunet-service-nat_stun.c
249src/nat/nat_api.c 250src/nat/nat_api.c
250src/nat/nat_api_stun.c 251src/nat/nat_api_stun.c
@@ -489,6 +490,7 @@ src/vpn/gnunet-helper-vpn-windows.c
489src/vpn/gnunet-service-vpn.c 490src/vpn/gnunet-service-vpn.c
490src/vpn/gnunet-vpn.c 491src/vpn/gnunet-vpn.c
491src/vpn/vpn_api.c 492src/vpn/vpn_api.c
493src/zonemaster/gnunet-service-zonemaster.c
492src/fs/fs_api.h 494src/fs/fs_api.h
493src/include/gnunet_common.h 495src/include/gnunet_common.h
494src/include/gnunet_mq_lib.h 496src/include/gnunet_mq_lib.h
diff --git a/src/gns/gns.conf.in b/src/gns/gns.conf.in
index bf59cac15..b34246cef 100644
--- a/src/gns/gns.conf.in
+++ b/src/gns/gns.conf.in
@@ -5,7 +5,6 @@ HOSTNAME = localhost
5BINARY = gnunet-service-gns 5BINARY = gnunet-service-gns
6UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-gns.sock 6UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-gns.sock
7@JAVAPORT@PORT = 2102 7@JAVAPORT@PORT = 2102
8USER_SERVICE = YES
9 8
10# Do we require users that want to access GNS to run this process 9# Do we require users that want to access GNS to run this process
11# (usually not a good idea) 10# (usually not a good idea)
@@ -17,9 +16,6 @@ UNIX_MATCH_GID = YES
17# How many queries is GNS allowed to perform in the background at the same time? 16# How many queries is GNS allowed to perform in the background at the same time?
18MAX_PARALLEL_BACKGROUND_QUERIES = 1000 17MAX_PARALLEL_BACKGROUND_QUERIES = 1000
19 18
20# How frequently do we try to publish our full zone?
21ZONE_PUBLISH_TIME_WINDOW = 4 h
22
23# Using caching or always ask DHT 19# Using caching or always ask DHT
24# USE_CACHE = YES 20# USE_CACHE = YES
25 21
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index 3e718dac8..7c1dfaba2 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -40,43 +40,6 @@
40#include "gnunet-service-gns_interceptor.h" 40#include "gnunet-service-gns_interceptor.h"
41#include "gnunet_protocols.h" 41#include "gnunet_protocols.h"
42 42
43/**
44 * The initial interval in milliseconds btween puts in
45 * a zone iteration
46 */
47#define INITIAL_PUT_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
48
49/**
50 * The lower bound for the zone iteration interval
51 */
52#define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
53
54/**
55 * The upper bound for the zone iteration interval
56 */
57#define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
58
59/**
60 * The default put interval for the zone iteration. In case
61 * no option is found
62 */
63#define DEFAULT_ZONE_PUBLISH_TIME_WINDOW GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
64
65/**
66 * The factor the current zone iteration interval is divided by for each
67 * additional new record
68 */
69#define LATE_ITERATION_SPEEDUP_FACTOR 2
70
71/**
72 * How long until a DHT PUT attempt should time out?
73 */
74#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
75
76/**
77 * What replication level do we use for DHT PUT operations?
78 */
79#define DHT_GNS_REPLICATION_LEVEL 5
80 43
81/** 44/**
82 * GnsClient prototype 45 * GnsClient prototype
@@ -146,36 +109,14 @@ struct GnsClient
146 109
147 110
148/** 111/**
149 * Handle for DHT PUT activity triggered from the namestore monitor.
150 */
151struct MonitorActivity
152{
153 /**
154 * Kept in a DLL.
155 */
156 struct MonitorActivity *next;
157
158 /**
159 * Kept in a DLL.
160 */
161 struct MonitorActivity *prev;
162
163 /**
164 * Handle for the DHT PUT operation.
165 */
166 struct GNUNET_DHT_PutHandle *ph;
167};
168
169
170/**
171 * Our handle to the DHT 112 * Our handle to the DHT
172 */ 113 */
173static struct GNUNET_DHT_Handle *dht_handle; 114static struct GNUNET_DHT_Handle *dht_handle;
174 115
175/** 116/**
176 * Active DHT put operation (or NULL) 117 * Our handle to the namecache service
177 */ 118 */
178static struct GNUNET_DHT_PutHandle *active_put; 119static struct GNUNET_NAMECACHE_Handle *namecache_handle;
179 120
180/** 121/**
181 * Our handle to the namestore service 122 * Our handle to the namestore service
@@ -183,11 +124,6 @@ static struct GNUNET_DHT_PutHandle *active_put;
183static struct GNUNET_NAMESTORE_Handle *namestore_handle; 124static struct GNUNET_NAMESTORE_Handle *namestore_handle;
184 125
185/** 126/**
186 * Our handle to the namecache service
187 */
188static struct GNUNET_NAMECACHE_Handle *namecache_handle;
189
190/**
191 * Our handle to the identity service 127 * Our handle to the identity service
192 */ 128 */
193static struct GNUNET_IDENTITY_Handle *identity_handle; 129static struct GNUNET_IDENTITY_Handle *identity_handle;
@@ -199,68 +135,6 @@ static struct GNUNET_IDENTITY_Handle *identity_handle;
199static struct GNUNET_IDENTITY_Operation *identity_op; 135static struct GNUNET_IDENTITY_Operation *identity_op;
200 136
201/** 137/**
202 * Handle to iterate over our authoritative zone in namestore
203 */
204static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
205
206/**
207 * Handle to monitor namestore changes to instant propagation.
208 */
209static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
210
211/**
212 * Head of monitor activities; kept in a DLL.
213 */
214static struct MonitorActivity *ma_head;
215
216/**
217 * Tail of monitor activities; kept in a DLL.
218 */
219static struct MonitorActivity *ma_tail;
220
221/**
222 * Useful for zone update for DHT put
223 */
224static unsigned long long num_public_records;
225
226/**
227 * Last seen record count
228 */
229static unsigned long long last_num_public_records;
230
231/**
232 * Minimum relative expiration time of records seem during the current
233 * zone iteration.
234 */
235static struct GNUNET_TIME_Relative min_relative_record_time;
236
237/**
238 * Zone iteration PUT interval.
239 */
240static struct GNUNET_TIME_Relative put_interval;
241
242/**
243 * Default time window for zone iteration
244 */
245static struct GNUNET_TIME_Relative zone_publish_time_window_default;
246
247/**
248 * Time window for zone iteration, adjusted based on relative record
249 * expiration times in our zone.
250 */
251static struct GNUNET_TIME_Relative zone_publish_time_window;
252
253/**
254 * zone publish task
255 */
256static struct GNUNET_SCHEDULER_Task *zone_publish_task;
257
258/**
259 * #GNUNET_YES if zone has never been published before
260 */
261static int first_zone_iteration;
262
263/**
264 * #GNUNET_YES if ipv6 is supported 138 * #GNUNET_YES if ipv6 is supported
265 */ 139 */
266static int v6_enabled; 140static int v6_enabled;
@@ -285,8 +159,6 @@ static struct GNUNET_STATISTICS_Handle *statistics;
285static void 159static void
286shutdown_task (void *cls) 160shutdown_task (void *cls)
287{ 161{
288 struct MonitorActivity *ma;
289
290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291 "Shutting down!\n"); 163 "Shutting down!\n");
292 GNS_interceptor_done (); 164 GNS_interceptor_done ();
@@ -303,35 +175,12 @@ shutdown_task (void *cls)
303 GNS_resolver_done (); 175 GNS_resolver_done ();
304 GNS_reverse_done (); 176 GNS_reverse_done ();
305 GNS_shorten_done (); 177 GNS_shorten_done ();
306 while (NULL != (ma = ma_head))
307 {
308 GNUNET_DHT_put_cancel (ma->ph);
309 GNUNET_CONTAINER_DLL_remove (ma_head,
310 ma_tail,
311 ma);
312 GNUNET_free (ma);
313 }
314 if (NULL != statistics) 178 if (NULL != statistics)
315 { 179 {
316 GNUNET_STATISTICS_destroy (statistics, 180 GNUNET_STATISTICS_destroy (statistics,
317 GNUNET_NO); 181 GNUNET_NO);
318 statistics = NULL; 182 statistics = NULL;
319 } 183 }
320 if (NULL != zone_publish_task)
321 {
322 GNUNET_SCHEDULER_cancel (zone_publish_task);
323 zone_publish_task = NULL;
324 }
325 if (NULL != namestore_iter)
326 {
327 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
328 namestore_iter = NULL;
329 }
330 if (NULL != zmon)
331 {
332 GNUNET_NAMESTORE_zone_monitor_stop (zmon);
333 zmon = NULL;
334 }
335 if (NULL != namestore_handle) 184 if (NULL != namestore_handle)
336 { 185 {
337 GNUNET_NAMESTORE_disconnect (namestore_handle); 186 GNUNET_NAMESTORE_disconnect (namestore_handle);
@@ -342,11 +191,6 @@ shutdown_task (void *cls)
342 GNUNET_NAMECACHE_disconnect (namecache_handle); 191 GNUNET_NAMECACHE_disconnect (namecache_handle);
343 namecache_handle = NULL; 192 namecache_handle = NULL;
344 } 193 }
345 if (NULL != active_put)
346 {
347 GNUNET_DHT_put_cancel (active_put);
348 active_put = NULL;
349 }
350 if (NULL != dht_handle) 194 if (NULL != dht_handle)
351 { 195 {
352 GNUNET_DHT_disconnect (dht_handle); 196 GNUNET_DHT_disconnect (dht_handle);
@@ -354,6 +198,7 @@ shutdown_task (void *cls)
354 } 198 }
355} 199}
356 200
201
357/** 202/**
358 * Called whenever a client is disconnected. 203 * Called whenever a client is disconnected.
359 * 204 *
@@ -413,408 +258,6 @@ client_connect_cb (void *cls,
413 258
414 259
415/** 260/**
416 * Method called periodically that triggers iteration over authoritative records
417 *
418 * @param cls closure
419 */
420static void
421publish_zone_dht_next (void *cls)
422{
423 zone_publish_task = NULL;
424 GNUNET_assert (NULL != namestore_iter);
425 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
426}
427
428
429/**
430 * Periodically iterate over our zone and store everything in dht
431 *
432 * @param cls NULL
433 */
434static void
435publish_zone_dht_start (void *cls);
436
437
438/**
439 * Continuation called from DHT once the PUT operation is done.
440 *
441 * @param cls closure, NULL if called from regular iteration,
442 * `struct MonitorActivity` if called from #handle_monitor_event.
443 * @param success #GNUNET_OK on success
444 */
445static void
446dht_put_continuation (void *cls,
447 int success)
448{
449 struct MonitorActivity *ma = cls;
450 struct GNUNET_TIME_Relative next_put_interval;
451
452 num_public_records++;
453 if (NULL == ma)
454 {
455 active_put = NULL;
456 if ( (num_public_records > last_num_public_records) &&
457 (GNUNET_NO == first_zone_iteration) )
458 {
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Last record count was lower than current record count. Reducing interval.\n");
461 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
462 num_public_records);
463 next_put_interval = GNUNET_TIME_relative_divide (put_interval,
464 LATE_ITERATION_SPEEDUP_FACTOR);
465 }
466 else
467 next_put_interval = put_interval;
468 next_put_interval = GNUNET_TIME_relative_min (next_put_interval,
469 MAXIMUM_ZONE_ITERATION_INTERVAL);
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471 "PUT complete, next PUT in %s!\n",
472 GNUNET_STRINGS_relative_time_to_string (next_put_interval,
473 GNUNET_YES));
474
475 GNUNET_STATISTICS_set (statistics,
476 "Current zone iteration interval (ms)",
477 next_put_interval.rel_value_us / 1000LL,
478 GNUNET_NO);
479 GNUNET_assert (NULL == zone_publish_task);
480 zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
481 &publish_zone_dht_next,
482 NULL);
483 }
484 else
485 {
486 GNUNET_CONTAINER_DLL_remove (ma_head,
487 ma_tail,
488 ma);
489 GNUNET_free (ma);
490 }
491}
492
493
494/**
495 * Convert namestore records from the internal format to that
496 * suitable for publication (removes private records, converts
497 * to absolute expiration time).
498 *
499 * @param rd input records
500 * @param rd_count size of the @a rd and @a rd_public arrays
501 * @param rd_public where to write the converted records
502 * @return number of records written to @a rd_public
503 */
504static unsigned int
505convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
506 unsigned int rd_count,
507 struct GNUNET_GNSRECORD_Data *rd_public)
508{
509 struct GNUNET_TIME_Absolute now;
510 unsigned int rd_public_count;
511 unsigned int i;
512
513 rd_public_count = 0;
514 now = GNUNET_TIME_absolute_get ();
515 for (i=0;i<rd_count;i++)
516 if (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
517 {
518 rd_public[rd_public_count] = rd[i];
519 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
520 {
521 /* GNUNET_GNSRECORD_block_create will convert to absolute time;
522 we just need to adjust our iteration frequency */
523 min_relative_record_time.rel_value_us =
524 GNUNET_MIN (rd_public[rd_public_count].expiration_time,
525 min_relative_record_time.rel_value_us);
526 }
527 else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
528 {
529 /* record already expired, skip it */
530 continue;
531 }
532 rd_public_count++;
533 }
534 return rd_public_count;
535}
536
537
538/**
539 * Store GNS records in the DHT.
540 *
541 * @param key key of the zone
542 * @param label label to store under
543 * @param rd_public public record data
544 * @param rd_public_count number of records in @a rd_public
545 * @param pc_arg closure argument to pass to the #dht_put_continuation
546 * @return DHT PUT handle, NULL on error
547 */
548static struct GNUNET_DHT_PutHandle *
549perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
550 const char *label,
551 const struct GNUNET_GNSRECORD_Data *rd_public,
552 unsigned int rd_public_count,
553 void *pc_arg)
554{
555 struct GNUNET_GNSRECORD_Block *block;
556 struct GNUNET_HashCode query;
557 struct GNUNET_TIME_Absolute expire;
558 size_t block_size;
559 struct GNUNET_DHT_PutHandle *ret;
560
561 expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
562 rd_public);
563 block = GNUNET_GNSRECORD_block_create (key,
564 expire,
565 label,
566 rd_public,
567 rd_public_count);
568 if (NULL == block)
569 return NULL; /* whoops */
570 block_size = ntohl (block->purpose.size)
571 + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
572 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
573 GNUNET_GNSRECORD_query_from_private_key (key,
574 label,
575 &query);
576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577 "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
578 rd_public_count,
579 label,
580 GNUNET_STRINGS_absolute_time_to_string (expire),
581 GNUNET_h2s (&query));
582 ret = GNUNET_DHT_put (dht_handle,
583 &query,
584 DHT_GNS_REPLICATION_LEVEL,
585 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
586 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
587 block_size,
588 block,
589 expire,
590 &dht_put_continuation,
591 pc_arg);
592 GNUNET_free (block);
593 return ret;
594}
595
596
597/**
598 * We encountered an error in our zone iteration.
599 */
600static void
601zone_iteration_error (void *cls)
602{
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "Got disconnected from namestore database, retrying.\n");
605 namestore_iter = NULL;
606 /* We end up here on error/disconnect/shutdown, so potentially
607 while a zone publish task or a DHT put is still running; hence
608 we need to cancel those. */
609 if (NULL != zone_publish_task)
610 {
611 GNUNET_SCHEDULER_cancel (zone_publish_task);
612 zone_publish_task = NULL;
613 }
614 if (NULL != active_put)
615 {
616 GNUNET_DHT_put_cancel (active_put);
617 active_put = NULL;
618 }
619 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
620 NULL);
621}
622
623
624/**
625 * Zone iteration is completed.
626 */
627static void
628zone_iteration_finished (void *cls)
629{
630 /* we're done with one iteration, calculate when to do the next one */
631 namestore_iter = NULL;
632 last_num_public_records = num_public_records;
633 first_zone_iteration = GNUNET_NO;
634 if (0 == num_public_records)
635 {
636 /**
637 * If no records are known (startup) or none present
638 * we can safely set the interval to the value for a single
639 * record
640 */
641 put_interval = zone_publish_time_window;
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
643 "No records in namestore database.\n");
644 }
645 else
646 {
647 /* If records are present, next publication is based on the minimum
648 * relative expiration time of the records published divided by 4
649 */
650 zone_publish_time_window
651 = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide (min_relative_record_time, 4),
652 zone_publish_time_window_default);
653 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
654 num_public_records);
655 }
656 /* reset for next iteration */
657 min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
658 put_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
659 put_interval);
660 put_interval = GNUNET_TIME_relative_min (put_interval,
661 MAXIMUM_ZONE_ITERATION_INTERVAL);
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Zone iteration finished. Adjusted zone iteration interval to %s\n",
664 GNUNET_STRINGS_relative_time_to_string (put_interval,
665 GNUNET_YES));
666 GNUNET_STATISTICS_set (statistics,
667 "Current zone iteration interval (in ms)",
668 put_interval.rel_value_us / 1000LL,
669 GNUNET_NO);
670 GNUNET_STATISTICS_update (statistics,
671 "Number of zone iterations",
672 1,
673 GNUNET_NO);
674 GNUNET_STATISTICS_set (statistics,
675 "Number of public records in DHT",
676 last_num_public_records,
677 GNUNET_NO);
678 GNUNET_assert (NULL == zone_publish_task);
679 if (0 == num_public_records)
680 zone_publish_task = GNUNET_SCHEDULER_add_delayed (put_interval,
681 &publish_zone_dht_start,
682 NULL);
683 else
684 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
685 NULL);
686}
687
688
689/**
690 * Function used to put all records successively into the DHT.
691 *
692 * @param cls the closure (NULL)
693 * @param key the private key of the authority (ours)
694 * @param label the name of the records, NULL once the iteration is done
695 * @param rd_count the number of records in @a rd
696 * @param rd the record data
697 */
698static void
699put_gns_record (void *cls,
700 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
701 const char *label,
702 unsigned int rd_count,
703 const struct GNUNET_GNSRECORD_Data *rd)
704{
705 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
706 unsigned int rd_public_count;
707
708 rd_public_count = convert_records_for_export (rd,
709 rd_count,
710 rd_public);
711
712 if (0 == rd_public_count)
713 {
714 GNUNET_assert (NULL == zone_publish_task);
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "Record set empty, moving to next record set\n");
717 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
718 NULL);
719 return;
720 }
721 /* We got a set of records to publish */
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "Starting DHT PUT\n");
724 active_put = perform_dht_put (key,
725 label,
726 rd_public,
727 rd_public_count,
728 NULL);
729 if (NULL == active_put)
730 {
731 GNUNET_break (0);
732 dht_put_continuation (NULL, GNUNET_NO);
733 }
734}
735
736
737/**
738 * Periodically iterate over all zones and store everything in DHT
739 *
740 * @param cls NULL
741 */
742static void
743publish_zone_dht_start (void *cls)
744{
745 zone_publish_task = NULL;
746
747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
748 "Starting DHT zone update!\n");
749 /* start counting again */
750 num_public_records = 0;
751 GNUNET_assert (NULL == namestore_iter);
752 namestore_iter
753 = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
754 NULL, /* All zones */
755 &zone_iteration_error,
756 NULL,
757 &put_gns_record,
758 NULL,
759 &zone_iteration_finished,
760 NULL);
761}
762
763
764/**
765 * Process a record that was stored in the namestore
766 * (invoked by the monitor).
767 *
768 * @param cls closure, NULL
769 * @param zone private key of the zone; NULL on disconnect
770 * @param label label of the records; NULL on disconnect
771 * @param rd_count number of entries in @a rd array, 0 if label was deleted
772 * @param rd array of records with data to store
773 */
774static void
775handle_monitor_event (void *cls,
776 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
777 const char *label,
778 unsigned int rd_count,
779 const struct GNUNET_GNSRECORD_Data *rd)
780{
781 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
782 unsigned int rd_public_count;
783 struct MonitorActivity *ma;
784
785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
786 "Received %u records for label `%s' via namestore monitor\n",
787 rd_count,
788 label);
789 /* filter out records that are not public, and convert to
790 absolute expiration time. */
791 rd_public_count = convert_records_for_export (rd,
792 rd_count,
793 rd_public);
794 if (0 == rd_public_count)
795 return; /* nothing to do */
796 ma = GNUNET_new (struct MonitorActivity);
797 ma->ph = perform_dht_put (zone,
798 label,
799 rd,
800 rd_count,
801 ma);
802 if (NULL == ma->ph)
803 {
804 /* PUT failed, do not remember operation */
805 GNUNET_free (ma);
806 return;
807 }
808 GNUNET_CONTAINER_DLL_insert (ma_head,
809 ma_tail,
810 ma);
811}
812
813
814/* END DHT ZONE PROPAGATION */
815
816
817/**
818 * Reply to client with the result from our lookup. 261 * Reply to client with the result from our lookup.
819 * 262 *
820 * @param cls the closure (our client lookup handle) 263 * @param cls the closure (our client lookup handle)
@@ -1020,49 +463,6 @@ handle_rev_lookup (void *cls,
1020 463
1021 464
1022/** 465/**
1023 * The zone monitor is now in SYNC with the current state of the
1024 * name store. Start to perform periodic iterations.
1025 *
1026 * @param cls NULL
1027 */
1028static void
1029monitor_sync_event (void *cls)
1030{
1031 GNUNET_assert (NULL == zone_publish_task);
1032 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
1033 NULL);
1034}
1035
1036
1037/**
1038 * The zone monitor is now in SYNC with the current state of the
1039 * name store. Start to perform periodic iterations.
1040 *
1041 * @param cls NULL
1042 */
1043static void
1044handle_monitor_error (void *cls)
1045{
1046 if (NULL != zone_publish_task)
1047 {
1048 GNUNET_SCHEDULER_cancel (zone_publish_task);
1049 zone_publish_task = NULL;
1050 }
1051 if (NULL != namestore_iter)
1052 {
1053 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1054 namestore_iter = NULL;
1055 }
1056 if (NULL != active_put)
1057 {
1058 GNUNET_DHT_put_cancel (active_put);
1059 active_put = NULL;
1060 }
1061 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
1062 NULL);
1063}
1064
1065/**
1066 * Method called to inform about the ego to be used for the master zone 466 * Method called to inform about the ego to be used for the master zone
1067 * for DNS interceptions. 467 * for DNS interceptions.
1068 * 468 *
@@ -1107,7 +507,6 @@ identity_reverse_cb (void *cls,
1107} 507}
1108 508
1109 509
1110
1111/** 510/**
1112 * Method called to inform about the ego to be used for the master zone 511 * Method called to inform about the ego to be used for the master zone
1113 * for DNS interceptions. 512 * for DNS interceptions.
@@ -1178,8 +577,7 @@ run (void *cls,
1178 unsigned long long max_parallel_bg_queries = 0; 577 unsigned long long max_parallel_bg_queries = 0;
1179 578
1180 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6); 579 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
1181 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET); 580 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
1182 min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
1183 namestore_handle = GNUNET_NAMESTORE_connect (c); 581 namestore_handle = GNUNET_NAMESTORE_connect (c);
1184 if (NULL == namestore_handle) 582 if (NULL == namestore_handle)
1185 { 583 {
@@ -1188,7 +586,7 @@ run (void *cls,
1188 GNUNET_SCHEDULER_shutdown (); 586 GNUNET_SCHEDULER_shutdown ();
1189 return; 587 return;
1190 } 588 }
1191 namecache_handle = GNUNET_NAMECACHE_connect (c); 589 namecache_handle = GNUNET_NAMECACHE_connect (c);
1192 if (NULL == namecache_handle) 590 if (NULL == namecache_handle)
1193 { 591 {
1194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1197,29 +595,6 @@ run (void *cls,
1197 return; 595 return;
1198 } 596 }
1199 597
1200 put_interval = INITIAL_PUT_INTERVAL;
1201 zone_publish_time_window_default = DEFAULT_ZONE_PUBLISH_TIME_WINDOW;
1202 if (GNUNET_OK ==
1203 GNUNET_CONFIGURATION_get_value_time (c, "gns",
1204 "ZONE_PUBLISH_TIME_WINDOW",
1205 &zone_publish_time_window_default))
1206 {
1207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1208 "Time window for zone iteration: %s\n",
1209 GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window,
1210 GNUNET_YES));
1211 }
1212 zone_publish_time_window = zone_publish_time_window_default;
1213 if (GNUNET_OK ==
1214 GNUNET_CONFIGURATION_get_value_number (c, "gns",
1215 "MAX_PARALLEL_BACKGROUND_QUERIES",
1216 &max_parallel_bg_queries))
1217 {
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Number of allowed parallel background queries: %llu\n",
1220 max_parallel_bg_queries);
1221 }
1222
1223 dht_handle = GNUNET_DHT_connect (c, 598 dht_handle = GNUNET_DHT_connect (c,
1224 (unsigned int) max_parallel_bg_queries); 599 (unsigned int) max_parallel_bg_queries);
1225 if (NULL == dht_handle) 600 if (NULL == dht_handle)
@@ -1254,19 +629,7 @@ run (void *cls,
1254 GNS_shorten_init (namestore_handle, 629 GNS_shorten_init (namestore_handle,
1255 namecache_handle, 630 namecache_handle,
1256 dht_handle); 631 dht_handle);
1257 /* Schedule periodic put for our records. */
1258 first_zone_iteration = GNUNET_YES;
1259 statistics = GNUNET_STATISTICS_create ("gns", c); 632 statistics = GNUNET_STATISTICS_create ("gns", c);
1260 zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
1261 NULL,
1262 GNUNET_NO,
1263 &handle_monitor_error,
1264 NULL,
1265 &handle_monitor_event,
1266 NULL,
1267 &monitor_sync_event,
1268 NULL);
1269 GNUNET_break (NULL != zmon);
1270 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); 633 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1271} 634}
1272 635
diff --git a/src/gns/gnunet-service-gns_reverser.c b/src/gns/gnunet-service-gns_reverser.c
index 931dc6809..b5b8b31b7 100644
--- a/src/gns/gnunet-service-gns_reverser.c
+++ b/src/gns/gnunet-service-gns_reverser.c
@@ -394,6 +394,7 @@ handle_gns_result_iter (void *cls,
394 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith); 394 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
395} 395}
396 396
397
397static void 398static void
398next_it (void *cls) 399next_it (void *cls)
399{ 400{
@@ -402,6 +403,7 @@ next_it (void *cls)
402 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter); 403 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
403} 404}
404 405
406
405static void 407static void
406iterator_cb (void *cls, 408iterator_cb (void *cls,
407 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, 409 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
@@ -487,6 +489,7 @@ store_reverse (void *cls,
487 GNUNET_free (ith); 489 GNUNET_free (ith);
488} 490}
489 491
492
490static void 493static void
491finished_cb (void *cls) 494finished_cb (void *cls)
492{ 495{
@@ -522,6 +525,7 @@ finished_cb (void *cls)
522 525
523} 526}
524 527
528
525static void 529static void
526it_error (void *cls) 530it_error (void *cls)
527{ 531{
@@ -529,6 +533,7 @@ it_error (void *cls)
529 "Error iterating for REVERSE\n"); 533 "Error iterating for REVERSE\n");
530} 534}
531 535
536
532static void 537static void
533check_reverse_records (void *cls) 538check_reverse_records (void *cls)
534{ 539{
diff --git a/src/vpn/vpn.conf.in b/src/vpn/vpn.conf.in
index 000300084..585131554 100644
--- a/src/vpn/vpn.conf.in
+++ b/src/vpn/vpn.conf.in
@@ -6,7 +6,7 @@ BINARY = gnunet-service-vpn
6ACCEPT_FROM = 127.0.0.1; 6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1; 7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-vpn.sock 8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-vpn.sock
9UNIX_MATCH_UID = YES 9UNIX_MATCH_UID = NO
10UNIX_MATCH_GID = YES 10UNIX_MATCH_GID = YES
11 11
12IPV6ADDR = 1234::1 12IPV6ADDR = 1234::1
diff --git a/src/zonemaster/Makefile.am b/src/zonemaster/Makefile.am
new file mode 100644
index 000000000..21f986498
--- /dev/null
+++ b/src/zonemaster/Makefile.am
@@ -0,0 +1,35 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
11 zonemaster.conf
12
13if MINGW
14 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
15endif
16
17if USE_COVERAGE
18 AM_CFLAGS = --coverage -O0
19 XLIBS = -lgcov
20endif
21
22libexec_PROGRAMS = \
23 gnunet-service-zonemaster
24
25gnunet_service_zonemaster_SOURCES = \
26 gnunet-service-zonemaster.c
27
28gnunet_service_zonemaster_LDADD = \
29 $(top_builddir)/src/dht/libgnunetdht.la \
30 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
31 $(top_builddir)/src/statistics/libgnunetstatistics.la \
32 $(top_builddir)/src/util/libgnunetutil.la \
33 $(top_builddir)/src/namestore/libgnunetnamestore.la \
34 $(GN_LIBINTL)
35
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c
new file mode 100644
index 000000000..d61eb723f
--- /dev/null
+++ b/src/zonemaster/gnunet-service-zonemaster.c
@@ -0,0 +1,773 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file zonemaster/gnunet-service-zonemaster.c
23 * @brief publish records from namestore to GNUnet name system
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_dnsparser_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_namestore_service.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_namestore_plugin.h"
33#include "gnunet_signatures.h"
34
35
36#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
37
38
39
40/**
41 * The initial interval in milliseconds btween puts in
42 * a zone iteration
43 */
44#define INITIAL_PUT_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
45
46/**
47 * The lower bound for the zone iteration interval
48 */
49#define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
50
51/**
52 * The upper bound for the zone iteration interval
53 */
54#define MAXIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
55
56/**
57 * The default put interval for the zone iteration. In case
58 * no option is found
59 */
60#define DEFAULT_ZONE_PUBLISH_TIME_WINDOW GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
61
62/**
63 * The factor the current zone iteration interval is divided by for each
64 * additional new record
65 */
66#define LATE_ITERATION_SPEEDUP_FACTOR 2
67
68/**
69 * How long until a DHT PUT attempt should time out?
70 */
71#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
72
73/**
74 * What replication level do we use for DHT PUT operations?
75 */
76#define DHT_GNS_REPLICATION_LEVEL 5
77
78
79/**
80 * Handle for DHT PUT activity triggered from the namestore monitor.
81 */
82struct MonitorActivity
83{
84 /**
85 * Kept in a DLL.
86 */
87 struct MonitorActivity *next;
88
89 /**
90 * Kept in a DLL.
91 */
92 struct MonitorActivity *prev;
93
94 /**
95 * Handle for the DHT PUT operation.
96 */
97 struct GNUNET_DHT_PutHandle *ph;
98};
99
100
101/**
102 * Handle to the statistics service
103 */
104static struct GNUNET_STATISTICS_Handle *statistics;
105
106/**
107 * Our handle to the DHT
108 */
109static struct GNUNET_DHT_Handle *dht_handle;
110
111/**
112 * Active DHT put operation (or NULL)
113 */
114static struct GNUNET_DHT_PutHandle *active_put;
115
116/**
117 * Our handle to the namestore service
118 */
119static struct GNUNET_NAMESTORE_Handle *namestore_handle;
120
121/**
122 * Handle to iterate over our authoritative zone in namestore
123 */
124static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
125
126/**
127 * Handle to monitor namestore changes to instant propagation.
128 */
129static struct GNUNET_NAMESTORE_ZoneMonitor *zmon;
130
131/**
132 * Head of monitor activities; kept in a DLL.
133 */
134static struct MonitorActivity *ma_head;
135
136/**
137 * Tail of monitor activities; kept in a DLL.
138 */
139static struct MonitorActivity *ma_tail;
140
141/**
142 * Useful for zone update for DHT put
143 */
144static unsigned long long num_public_records;
145
146/**
147 * Last seen record count
148 */
149static unsigned long long last_num_public_records;
150
151/**
152 * Minimum relative expiration time of records seem during the current
153 * zone iteration.
154 */
155static struct GNUNET_TIME_Relative min_relative_record_time;
156
157/**
158 * Zone iteration PUT interval.
159 */
160static struct GNUNET_TIME_Relative put_interval;
161
162/**
163 * Default time window for zone iteration
164 */
165static struct GNUNET_TIME_Relative zone_publish_time_window_default;
166
167/**
168 * Time window for zone iteration, adjusted based on relative record
169 * expiration times in our zone.
170 */
171static struct GNUNET_TIME_Relative zone_publish_time_window;
172
173/**
174 * zone publish task
175 */
176static struct GNUNET_SCHEDULER_Task *zone_publish_task;
177
178/**
179 * #GNUNET_YES if zone has never been published before
180 */
181static int first_zone_iteration;
182
183/**
184 * Task run during shutdown.
185 *
186 * @param cls unused
187 * @param tc unused
188 */
189static void
190shutdown_task (void *cls)
191{
192 struct MonitorActivity *ma;
193
194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
195 "Shutting down!\n");
196 while (NULL != (ma = ma_head))
197 {
198 GNUNET_DHT_put_cancel (ma->ph);
199 GNUNET_CONTAINER_DLL_remove (ma_head,
200 ma_tail,
201 ma);
202 GNUNET_free (ma);
203 }
204 if (NULL != statistics)
205 {
206 GNUNET_STATISTICS_destroy (statistics,
207 GNUNET_NO);
208 statistics = NULL;
209 }
210 if (NULL != zone_publish_task)
211 {
212 GNUNET_SCHEDULER_cancel (zone_publish_task);
213 zone_publish_task = NULL;
214 }
215 if (NULL != namestore_iter)
216 {
217 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
218 namestore_iter = NULL;
219 }
220 if (NULL != zmon)
221 {
222 GNUNET_NAMESTORE_zone_monitor_stop (zmon);
223 zmon = NULL;
224 }
225 if (NULL != namestore_handle)
226 {
227 GNUNET_NAMESTORE_disconnect (namestore_handle);
228 namestore_handle = NULL;
229 }
230 if (NULL != active_put)
231 {
232 GNUNET_DHT_put_cancel (active_put);
233 active_put = NULL;
234 }
235 if (NULL != dht_handle)
236 {
237 GNUNET_DHT_disconnect (dht_handle);
238 dht_handle = NULL;
239 }
240}
241
242
243/**
244 * Method called periodically that triggers iteration over authoritative records
245 *
246 * @param cls closure
247 */
248static void
249publish_zone_dht_next (void *cls)
250{
251 zone_publish_task = NULL;
252 GNUNET_assert (NULL != namestore_iter);
253 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
254}
255
256
257/**
258 * Periodically iterate over our zone and store everything in dht
259 *
260 * @param cls NULL
261 */
262static void
263publish_zone_dht_start (void *cls);
264
265
266/**
267 * Continuation called from DHT once the PUT operation is done.
268 *
269 * @param cls closure, NULL if called from regular iteration,
270 * `struct MonitorActivity` if called from #handle_monitor_event.
271 * @param success #GNUNET_OK on success
272 */
273static void
274dht_put_continuation (void *cls,
275 int success)
276{
277 struct MonitorActivity *ma = cls;
278 struct GNUNET_TIME_Relative next_put_interval;
279
280 num_public_records++;
281 if (NULL == ma)
282 {
283 active_put = NULL;
284 if ( (num_public_records > last_num_public_records) &&
285 (GNUNET_NO == first_zone_iteration) )
286 {
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Last record count was lower than current record count. Reducing interval.\n");
289 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
290 num_public_records);
291 next_put_interval = GNUNET_TIME_relative_divide (put_interval,
292 LATE_ITERATION_SPEEDUP_FACTOR);
293 }
294 else
295 next_put_interval = put_interval;
296 next_put_interval = GNUNET_TIME_relative_min (next_put_interval,
297 MAXIMUM_ZONE_ITERATION_INTERVAL);
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "PUT complete, next PUT in %s!\n",
300 GNUNET_STRINGS_relative_time_to_string (next_put_interval,
301 GNUNET_YES));
302
303 GNUNET_STATISTICS_set (statistics,
304 "Current zone iteration interval (ms)",
305 next_put_interval.rel_value_us / 1000LL,
306 GNUNET_NO);
307 GNUNET_assert (NULL == zone_publish_task);
308 zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
309 &publish_zone_dht_next,
310 NULL);
311 }
312 else
313 {
314 GNUNET_CONTAINER_DLL_remove (ma_head,
315 ma_tail,
316 ma);
317 GNUNET_free (ma);
318 }
319}
320
321
322/**
323 * Convert namestore records from the internal format to that
324 * suitable for publication (removes private records, converts
325 * to absolute expiration time).
326 *
327 * @param rd input records
328 * @param rd_count size of the @a rd and @a rd_public arrays
329 * @param rd_public where to write the converted records
330 * @return number of records written to @a rd_public
331 */
332static unsigned int
333convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd,
334 unsigned int rd_count,
335 struct GNUNET_GNSRECORD_Data *rd_public)
336{
337 struct GNUNET_TIME_Absolute now;
338 unsigned int rd_public_count;
339 unsigned int i;
340
341 rd_public_count = 0;
342 now = GNUNET_TIME_absolute_get ();
343 for (i=0;i<rd_count;i++)
344 if (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))
345 {
346 rd_public[rd_public_count] = rd[i];
347 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
348 {
349 /* GNUNET_GNSRECORD_block_create will convert to absolute time;
350 we just need to adjust our iteration frequency */
351 min_relative_record_time.rel_value_us =
352 GNUNET_MIN (rd_public[rd_public_count].expiration_time,
353 min_relative_record_time.rel_value_us);
354 }
355 else if (rd_public[rd_public_count].expiration_time < now.abs_value_us)
356 {
357 /* record already expired, skip it */
358 continue;
359 }
360 rd_public_count++;
361 }
362 return rd_public_count;
363}
364
365
366/**
367 * Store GNS records in the DHT.
368 *
369 * @param key key of the zone
370 * @param label label to store under
371 * @param rd_public public record data
372 * @param rd_public_count number of records in @a rd_public
373 * @param pc_arg closure argument to pass to the #dht_put_continuation
374 * @return DHT PUT handle, NULL on error
375 */
376static struct GNUNET_DHT_PutHandle *
377perform_dht_put (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
378 const char *label,
379 const struct GNUNET_GNSRECORD_Data *rd_public,
380 unsigned int rd_public_count,
381 void *pc_arg)
382{
383 struct GNUNET_GNSRECORD_Block *block;
384 struct GNUNET_HashCode query;
385 struct GNUNET_TIME_Absolute expire;
386 size_t block_size;
387 struct GNUNET_DHT_PutHandle *ret;
388
389 expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count,
390 rd_public);
391 block = GNUNET_GNSRECORD_block_create (key,
392 expire,
393 label,
394 rd_public,
395 rd_public_count);
396 if (NULL == block)
397 return NULL; /* whoops */
398 block_size = ntohl (block->purpose.size)
399 + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)
400 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
401 GNUNET_GNSRECORD_query_from_private_key (key,
402 label,
403 &query);
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405 "Storing %u record(s) for label `%s' in DHT with expiration `%s' under key %s\n",
406 rd_public_count,
407 label,
408 GNUNET_STRINGS_absolute_time_to_string (expire),
409 GNUNET_h2s (&query));
410 ret = GNUNET_DHT_put (dht_handle,
411 &query,
412 DHT_GNS_REPLICATION_LEVEL,
413 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
414 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
415 block_size,
416 block,
417 expire,
418 &dht_put_continuation,
419 pc_arg);
420 GNUNET_free (block);
421 return ret;
422}
423
424
425/**
426 * We encountered an error in our zone iteration.
427 */
428static void
429zone_iteration_error (void *cls)
430{
431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432 "Got disconnected from namestore database, retrying.\n");
433 namestore_iter = NULL;
434 /* We end up here on error/disconnect/shutdown, so potentially
435 while a zone publish task or a DHT put is still running; hence
436 we need to cancel those. */
437 if (NULL != zone_publish_task)
438 {
439 GNUNET_SCHEDULER_cancel (zone_publish_task);
440 zone_publish_task = NULL;
441 }
442 if (NULL != active_put)
443 {
444 GNUNET_DHT_put_cancel (active_put);
445 active_put = NULL;
446 }
447 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
448 NULL);
449}
450
451
452/**
453 * Zone iteration is completed.
454 */
455static void
456zone_iteration_finished (void *cls)
457{
458 /* we're done with one iteration, calculate when to do the next one */
459 namestore_iter = NULL;
460 last_num_public_records = num_public_records;
461 first_zone_iteration = GNUNET_NO;
462 if (0 == num_public_records)
463 {
464 /**
465 * If no records are known (startup) or none present
466 * we can safely set the interval to the value for a single
467 * record
468 */
469 put_interval = zone_publish_time_window;
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
471 "No records in namestore database.\n");
472 }
473 else
474 {
475 /* If records are present, next publication is based on the minimum
476 * relative expiration time of the records published divided by 4
477 */
478 zone_publish_time_window
479 = GNUNET_TIME_relative_min (GNUNET_TIME_relative_divide (min_relative_record_time, 4),
480 zone_publish_time_window_default);
481 put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
482 num_public_records);
483 }
484 /* reset for next iteration */
485 min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
486 put_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
487 put_interval);
488 put_interval = GNUNET_TIME_relative_min (put_interval,
489 MAXIMUM_ZONE_ITERATION_INTERVAL);
490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
491 "Zone iteration finished. Adjusted zone iteration interval to %s\n",
492 GNUNET_STRINGS_relative_time_to_string (put_interval,
493 GNUNET_YES));
494 GNUNET_STATISTICS_set (statistics,
495 "Current zone iteration interval (in ms)",
496 put_interval.rel_value_us / 1000LL,
497 GNUNET_NO);
498 GNUNET_STATISTICS_update (statistics,
499 "Number of zone iterations",
500 1,
501 GNUNET_NO);
502 GNUNET_STATISTICS_set (statistics,
503 "Number of public records in DHT",
504 last_num_public_records,
505 GNUNET_NO);
506 GNUNET_assert (NULL == zone_publish_task);
507 if (0 == num_public_records)
508 zone_publish_task = GNUNET_SCHEDULER_add_delayed (put_interval,
509 &publish_zone_dht_start,
510 NULL);
511 else
512 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
513 NULL);
514}
515
516
517/**
518 * Function used to put all records successively into the DHT.
519 *
520 * @param cls the closure (NULL)
521 * @param key the private key of the authority (ours)
522 * @param label the name of the records, NULL once the iteration is done
523 * @param rd_count the number of records in @a rd
524 * @param rd the record data
525 */
526static void
527put_gns_record (void *cls,
528 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
529 const char *label,
530 unsigned int rd_count,
531 const struct GNUNET_GNSRECORD_Data *rd)
532{
533 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
534 unsigned int rd_public_count;
535
536 rd_public_count = convert_records_for_export (rd,
537 rd_count,
538 rd_public);
539
540 if (0 == rd_public_count)
541 {
542 GNUNET_assert (NULL == zone_publish_task);
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Record set empty, moving to next record set\n");
545 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
546 NULL);
547 return;
548 }
549 /* We got a set of records to publish */
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Starting DHT PUT\n");
552 active_put = perform_dht_put (key,
553 label,
554 rd_public,
555 rd_public_count,
556 NULL);
557 if (NULL == active_put)
558 {
559 GNUNET_break (0);
560 dht_put_continuation (NULL, GNUNET_NO);
561 }
562}
563
564
565/**
566 * Periodically iterate over all zones and store everything in DHT
567 *
568 * @param cls NULL
569 */
570static void
571publish_zone_dht_start (void *cls)
572{
573 zone_publish_task = NULL;
574
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576 "Starting DHT zone update!\n");
577 /* start counting again */
578 num_public_records = 0;
579 GNUNET_assert (NULL == namestore_iter);
580 namestore_iter
581 = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
582 NULL, /* All zones */
583 &zone_iteration_error,
584 NULL,
585 &put_gns_record,
586 NULL,
587 &zone_iteration_finished,
588 NULL);
589}
590
591
592/**
593 * Process a record that was stored in the namestore
594 * (invoked by the monitor).
595 *
596 * @param cls closure, NULL
597 * @param zone private key of the zone; NULL on disconnect
598 * @param label label of the records; NULL on disconnect
599 * @param rd_count number of entries in @a rd array, 0 if label was deleted
600 * @param rd array of records with data to store
601 */
602static void
603handle_monitor_event (void *cls,
604 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
605 const char *label,
606 unsigned int rd_count,
607 const struct GNUNET_GNSRECORD_Data *rd)
608{
609 struct GNUNET_GNSRECORD_Data rd_public[rd_count];
610 unsigned int rd_public_count;
611 struct MonitorActivity *ma;
612
613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614 "Received %u records for label `%s' via namestore monitor\n",
615 rd_count,
616 label);
617 /* filter out records that are not public, and convert to
618 absolute expiration time. */
619 rd_public_count = convert_records_for_export (rd,
620 rd_count,
621 rd_public);
622 if (0 == rd_public_count)
623 return; /* nothing to do */
624 ma = GNUNET_new (struct MonitorActivity);
625 ma->ph = perform_dht_put (zone,
626 label,
627 rd,
628 rd_count,
629 ma);
630 if (NULL == ma->ph)
631 {
632 /* PUT failed, do not remember operation */
633 GNUNET_free (ma);
634 return;
635 }
636 GNUNET_CONTAINER_DLL_insert (ma_head,
637 ma_tail,
638 ma);
639}
640
641
642/**
643 * The zone monitor is now in SYNC with the current state of the
644 * name store. Start to perform periodic iterations.
645 *
646 * @param cls NULL
647 */
648static void
649monitor_sync_event (void *cls)
650{
651 GNUNET_assert (NULL == zone_publish_task);
652 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
653 NULL);
654}
655
656
657/**
658 * The zone monitor is now in SYNC with the current state of the
659 * name store. Start to perform periodic iterations.
660 *
661 * @param cls NULL
662 */
663static void
664handle_monitor_error (void *cls)
665{
666 if (NULL != zone_publish_task)
667 {
668 GNUNET_SCHEDULER_cancel (zone_publish_task);
669 zone_publish_task = NULL;
670 }
671 if (NULL != namestore_iter)
672 {
673 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
674 namestore_iter = NULL;
675 }
676 if (NULL != active_put)
677 {
678 GNUNET_DHT_put_cancel (active_put);
679 active_put = NULL;
680 }
681 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
682 NULL);
683}
684
685
686/**
687 * Performe zonemaster duties: watch namestore, publish records.
688 *
689 * @param cls closure
690 * @param server the initialized server
691 * @param c configuration to use
692 */
693static void
694run (void *cls,
695 const struct GNUNET_CONFIGURATION_Handle *c,
696 struct GNUNET_SERVICE_Handle *service)
697{
698 unsigned long long max_parallel_bg_queries = 0;
699
700 min_relative_record_time = GNUNET_TIME_UNIT_FOREVER_REL;
701 namestore_handle = GNUNET_NAMESTORE_connect (c);
702 if (NULL == namestore_handle)
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
705 _("Failed to connect to the namestore!\n"));
706 GNUNET_SCHEDULER_shutdown ();
707 return;
708 }
709
710 put_interval = INITIAL_PUT_INTERVAL;
711 zone_publish_time_window_default = DEFAULT_ZONE_PUBLISH_TIME_WINDOW;
712 if (GNUNET_OK ==
713 GNUNET_CONFIGURATION_get_value_time (c, "gns",
714 "ZONE_PUBLISH_TIME_WINDOW",
715 &zone_publish_time_window_default))
716 {
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "Time window for zone iteration: %s\n",
719 GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window,
720 GNUNET_YES));
721 }
722 zone_publish_time_window = zone_publish_time_window_default;
723 if (GNUNET_OK ==
724 GNUNET_CONFIGURATION_get_value_number (c, "gns",
725 "MAX_PARALLEL_BACKGROUND_QUERIES",
726 &max_parallel_bg_queries))
727 {
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Number of allowed parallel background queries: %llu\n",
730 max_parallel_bg_queries);
731 }
732
733 dht_handle = GNUNET_DHT_connect (c,
734 (unsigned int) max_parallel_bg_queries);
735 if (NULL == dht_handle)
736 {
737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
738 _("Could not connect to DHT!\n"));
739 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
740 return;
741 }
742
743 /* Schedule periodic put for our records. */
744 first_zone_iteration = GNUNET_YES;\
745 statistics = GNUNET_STATISTICS_create ("zonemaster", c);
746 zmon = GNUNET_NAMESTORE_zone_monitor_start (c,
747 NULL,
748 GNUNET_NO,
749 &handle_monitor_error,
750 NULL,
751 &handle_monitor_event,
752 NULL,
753 &monitor_sync_event,
754 NULL);
755 GNUNET_break (NULL != zmon);
756 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
757}
758
759
760/**
761 * Define "main" method using service macro.
762 */
763GNUNET_SERVICE_MAIN
764("zonemaster",
765 GNUNET_SERVICE_OPTION_NONE,
766 &run,
767 NULL,
768 NULL,
769 NULL,
770 GNUNET_MQ_handler_end());
771
772
773/* end of gnunet-service-zonemaster.c */
diff --git a/src/zonemaster/zonemaster.conf.in b/src/zonemaster/zonemaster.conf.in
new file mode 100644
index 000000000..dda0c7ec4
--- /dev/null
+++ b/src/zonemaster/zonemaster.conf.in
@@ -0,0 +1,25 @@
1[gns]
2AUTOSTART = @AUTOSTART@
3FORCESTART = YES
4HOSTNAME = localhost
5BINARY = gnunet-service-zonemaster
6UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-zonemaster.sock
7@JAVAPORT@PORT = 2123
8
9# Do we require users that want to access GNS to run this process
10# (usually not a good idea)
11UNIX_MATCH_UID = NO
12
13# Do we require users that want to access GNS to be in the 'gnunet' group?
14UNIX_MATCH_GID = NO
15
16# How many queries is GNS allowed to perform in the background at the same time?
17MAX_PARALLEL_BACKGROUND_QUERIES = 1000
18
19# How frequently do we try to publish our full zone?
20ZONE_PUBLISH_TIME_WINDOW = 4 h
21
22# Using caching or always ask DHT
23# USE_CACHE = YES
24
25# PREFIX = valgrind --leak-check=full --track-origins=yes