diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2022-02-05 00:50:38 +0100 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2022-02-05 15:38:39 +0100 |
commit | ee865f851ca4b173da8d00e87a0ad446efc8037e (patch) | |
tree | 92a627afa5799d78df0fd5b09a711ca3b89a8b6b /src/zonemaster | |
parent | 65f9e37ce036acdfab29b25b9b6f69de1b126962 (diff) | |
download | gnunet-ee865f851ca4b173da8d00e87a0ad446efc8037e.tar.gz gnunet-ee865f851ca4b173da8d00e87a0ad446efc8037e.zip |
GNS: Implement Tombstone logic
GNS: Namestore zonemaster record store processing
ZONEMASTER: Do not publish records if tombstone expires in the future
NAMESTORE: Purge old tombstones.
Diffstat (limited to 'src/zonemaster')
-rw-r--r-- | src/zonemaster/gnunet-service-zonemaster.c | 179 |
1 files changed, 164 insertions, 15 deletions
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c index 9ff1a97b8..e478ceeab 100644 --- a/src/zonemaster/gnunet-service-zonemaster.c +++ b/src/zonemaster/gnunet-service-zonemaster.c | |||
@@ -90,6 +90,29 @@ | |||
90 | */ | 90 | */ |
91 | #define DHT_GNS_REPLICATION_LEVEL 5 | 91 | #define DHT_GNS_REPLICATION_LEVEL 5 |
92 | 92 | ||
93 | /** | ||
94 | * Handle for tombston updates which are executed for each published | ||
95 | * record set. | ||
96 | */ | ||
97 | struct TombstoneActivity | ||
98 | { | ||
99 | /** | ||
100 | * Kept in a DLL. | ||
101 | */ | ||
102 | struct TombstoneActivity *next; | ||
103 | |||
104 | /** | ||
105 | * Kept in a DLL. | ||
106 | */ | ||
107 | struct TombstoneActivity *prev; | ||
108 | |||
109 | /** | ||
110 | * Handle for the store operation. | ||
111 | */ | ||
112 | struct GNUNET_NAMESTORE_QueueEntry *ns_qe; | ||
113 | |||
114 | }; | ||
115 | |||
93 | 116 | ||
94 | /** | 117 | /** |
95 | * Handle for DHT PUT activity triggered from the namestore monitor. | 118 | * Handle for DHT PUT activity triggered from the namestore monitor. |
@@ -149,6 +172,16 @@ static struct DhtPutActivity *it_head; | |||
149 | static struct DhtPutActivity *it_tail; | 172 | static struct DhtPutActivity *it_tail; |
150 | 173 | ||
151 | /** | 174 | /** |
175 | * Head of the tombstone operations | ||
176 | */ | ||
177 | static struct TombstoneActivity *ta_head; | ||
178 | |||
179 | /** | ||
180 | * Tail of the tombstone operations | ||
181 | */ | ||
182 | static struct TombstoneActivity *ta_tail; | ||
183 | |||
184 | /** | ||
152 | * Number of entries in the DHT queue #it_head. | 185 | * Number of entries in the DHT queue #it_head. |
153 | */ | 186 | */ |
154 | static unsigned int dht_queue_length; | 187 | static unsigned int dht_queue_length; |
@@ -248,6 +281,7 @@ static void | |||
248 | shutdown_task (void *cls) | 281 | shutdown_task (void *cls) |
249 | { | 282 | { |
250 | struct DhtPutActivity *ma; | 283 | struct DhtPutActivity *ma; |
284 | struct TombstoneActivity *ta; | ||
251 | 285 | ||
252 | (void) cls; | 286 | (void) cls; |
253 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 287 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -262,6 +296,14 @@ shutdown_task (void *cls) | |||
262 | dht_queue_length--; | 296 | dht_queue_length--; |
263 | GNUNET_free (ma); | 297 | GNUNET_free (ma); |
264 | } | 298 | } |
299 | while (NULL != (ta = ta_head)) | ||
300 | { | ||
301 | GNUNET_NAMESTORE_cancel (ta->ns_qe); | ||
302 | GNUNET_CONTAINER_DLL_remove (ta_head, | ||
303 | ta_tail, | ||
304 | ta); | ||
305 | GNUNET_free (ta); | ||
306 | } | ||
265 | if (NULL != statistics) | 307 | if (NULL != statistics) |
266 | { | 308 | { |
267 | GNUNET_STATISTICS_destroy (statistics, | 309 | GNUNET_STATISTICS_destroy (statistics, |
@@ -535,22 +577,33 @@ dht_put_continuation (void *cls) | |||
535 | * @param rd input records | 577 | * @param rd input records |
536 | * @param rd_count size of the @a rd and @a rd_public arrays | 578 | * @param rd_count size of the @a rd and @a rd_public arrays |
537 | * @param rd_public where to write the converted records | 579 | * @param rd_public where to write the converted records |
580 | * @param expire the expiration of the block | ||
538 | * @return number of records written to @a rd_public | 581 | * @return number of records written to @a rd_public |
539 | */ | 582 | */ |
540 | static unsigned int | 583 | static unsigned int |
541 | convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, | 584 | convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, |
542 | unsigned int rd_count, | 585 | unsigned int rd_count, |
543 | struct GNUNET_GNSRECORD_Data *rd_public) | 586 | struct GNUNET_GNSRECORD_Data *rd_public, |
587 | struct GNUNET_TIME_Absolute *expiry) | ||
544 | { | 588 | { |
589 | const struct GNUNET_GNSRECORD_TombstoneRecord *tombstone; | ||
590 | struct GNUNET_TIME_Absolute expiry_tombstone; | ||
545 | struct GNUNET_TIME_Absolute now; | 591 | struct GNUNET_TIME_Absolute now; |
546 | unsigned int rd_public_count; | 592 | unsigned int rd_public_count; |
547 | 593 | ||
548 | rd_public_count = 0; | 594 | rd_public_count = 0; |
595 | tombstone = NULL; | ||
549 | now = GNUNET_TIME_absolute_get (); | 596 | now = GNUNET_TIME_absolute_get (); |
550 | for (unsigned int i = 0; i < rd_count; i++) | 597 | for (unsigned int i = 0; i < rd_count; i++) |
551 | { | 598 | { |
552 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) | 599 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) |
553 | continue; | 600 | continue; |
601 | /* Should always be private but just to be sure */ | ||
602 | if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type) | ||
603 | { | ||
604 | tombstone = rd[i].data; | ||
605 | continue; | ||
606 | } | ||
554 | if ((0 == (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) && | 607 | if ((0 == (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) && |
555 | (rd[i].expiration_time < now.abs_value_us)) | 608 | (rd[i].expiration_time < now.abs_value_us)) |
556 | continue; /* record already expired, skip it */ | 609 | continue; /* record already expired, skip it */ |
@@ -568,6 +621,21 @@ convert_records_for_export (const struct GNUNET_GNSRECORD_Data *rd, | |||
568 | rd_public[rd_public_count].flags |= GNUNET_GNSRECORD_RF_CRITICAL; | 621 | rd_public[rd_public_count].flags |= GNUNET_GNSRECORD_RF_CRITICAL; |
569 | rd_public_count++; | 622 | rd_public_count++; |
570 | } | 623 | } |
624 | |||
625 | *expiry = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count, | ||
626 | rd_public); | ||
627 | |||
628 | /* We need to check if the tombstone has an expiration in the fututre | ||
629 | * which would mean there was a block published under this label | ||
630 | * previously that is still valid. In this case we MUST NOT publish this | ||
631 | * block | ||
632 | */ | ||
633 | if (NULL != tombstone) | ||
634 | { | ||
635 | expiry_tombstone = GNUNET_TIME_absolute_ntoh (tombstone->time_of_death); | ||
636 | if (GNUNET_TIME_absolute_cmp (*expiry,<=,expiry_tombstone)) | ||
637 | return 0; | ||
638 | } | ||
571 | return rd_public_count; | 639 | return rd_public_count; |
572 | } | 640 | } |
573 | 641 | ||
@@ -587,30 +655,28 @@ perform_dht_put (const struct GNUNET_IDENTITY_PrivateKey *key, | |||
587 | const char *label, | 655 | const char *label, |
588 | const struct GNUNET_GNSRECORD_Data *rd_public, | 656 | const struct GNUNET_GNSRECORD_Data *rd_public, |
589 | unsigned int rd_public_count, | 657 | unsigned int rd_public_count, |
658 | const struct GNUNET_TIME_Absolute expire, | ||
590 | struct DhtPutActivity *ma) | 659 | struct DhtPutActivity *ma) |
591 | { | 660 | { |
592 | struct GNUNET_GNSRECORD_Block *block; | 661 | struct GNUNET_GNSRECORD_Block *block; |
593 | struct GNUNET_HashCode query; | 662 | struct GNUNET_HashCode query; |
594 | struct GNUNET_TIME_Absolute expire; | ||
595 | size_t block_size; | 663 | size_t block_size; |
596 | struct GNUNET_DHT_PutHandle *ret; | 664 | struct GNUNET_DHT_PutHandle *ret; |
597 | 665 | ||
598 | expire = GNUNET_GNSRECORD_record_get_expiration_time (rd_public_count, | ||
599 | rd_public); | ||
600 | if (cache_keys) | 666 | if (cache_keys) |
601 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create2 (key, | 667 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create2 (key, |
602 | expire, | 668 | expire, |
603 | label, | 669 | label, |
604 | rd_public, | 670 | rd_public, |
605 | rd_public_count, | 671 | rd_public_count, |
606 | &block)); | 672 | &block)); |
607 | else | 673 | else |
608 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create (key, | 674 | GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create (key, |
609 | expire, | 675 | expire, |
610 | label, | 676 | label, |
611 | rd_public, | 677 | rd_public, |
612 | rd_public_count, | 678 | rd_public_count, |
613 | &block)); | 679 | &block)); |
614 | if (NULL == block) | 680 | if (NULL == block) |
615 | { | 681 | { |
616 | GNUNET_break (0); | 682 | GNUNET_break (0); |
@@ -717,6 +783,74 @@ zone_iteration_finished (void *cls) | |||
717 | } | 783 | } |
718 | } | 784 | } |
719 | 785 | ||
786 | static void | ||
787 | ts_store_cont (void *cls, int32_t success, const char *emsg) | ||
788 | { | ||
789 | struct TombstoneActivity *ta = cls; | ||
790 | |||
791 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
792 | "Tombstone update complete\n"); | ||
793 | GNUNET_CONTAINER_DLL_remove (ta_head, | ||
794 | ta_tail, | ||
795 | ta); | ||
796 | GNUNET_free (ta); | ||
797 | |||
798 | } | ||
799 | |||
800 | /** | ||
801 | * Update tombstone records. | ||
802 | * | ||
803 | * @param key key of the zone | ||
804 | * @param label label to store under | ||
805 | * @param rd_public public record data | ||
806 | * @param rd_public_count number of records in @a rd_public | ||
807 | * @param expire the expiration time for the tombstone | ||
808 | * @param ta handle for the put operation | ||
809 | * @return Namestore queue entry, NULL on error | ||
810 | */ | ||
811 | static struct GNUNET_NAMESTORE_QueueEntry * | ||
812 | touch_tombstone (const struct GNUNET_IDENTITY_PrivateKey *key, | ||
813 | const char *label, | ||
814 | const struct GNUNET_GNSRECORD_Data *rd_original, | ||
815 | unsigned int rd_count_original, | ||
816 | const struct GNUNET_TIME_Absolute expire, | ||
817 | struct TombstoneActivity *ta) | ||
818 | { | ||
819 | struct GNUNET_TIME_AbsoluteNBO exp_nbo; | ||
820 | struct GNUNET_GNSRECORD_Data rd[rd_count_original + 1]; | ||
821 | int tombstone_exists = GNUNET_NO; | ||
822 | unsigned int rd_count; | ||
823 | |||
824 | exp_nbo = GNUNET_TIME_absolute_hton (expire); | ||
825 | for (rd_count = 0; rd_count < rd_count_original; rd_count++) | ||
826 | { | ||
827 | memcpy (&rd[rd_count], &rd_original[rd_count], | ||
828 | sizeof (struct GNUNET_GNSRECORD_Data)); | ||
829 | if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[rd_count].record_type) | ||
830 | { | ||
831 | rd[rd_count].data = &exp_nbo; | ||
832 | tombstone_exists = GNUNET_YES; | ||
833 | } | ||
834 | } | ||
835 | if (GNUNET_NO == tombstone_exists) | ||
836 | { | ||
837 | rd[rd_count].data = &exp_nbo; | ||
838 | rd[rd_count].data_size = sizeof (exp_nbo); | ||
839 | rd[rd_count].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE; | ||
840 | rd[rd_count].flags = GNUNET_GNSRECORD_RF_PRIVATE; | ||
841 | rd[rd_count].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; | ||
842 | rd_count++; | ||
843 | } | ||
844 | return GNUNET_NAMESTORE_records_store_ (namestore_handle, | ||
845 | key, | ||
846 | label, | ||
847 | rd_count, | ||
848 | rd, | ||
849 | GNUNET_YES, | ||
850 | &ts_store_cont, | ||
851 | ta); | ||
852 | } | ||
853 | |||
720 | 854 | ||
721 | /** | 855 | /** |
722 | * Function used to put all records successively into the DHT. | 856 | * Function used to put all records successively into the DHT. |
@@ -737,12 +871,15 @@ put_gns_record (void *cls, | |||
737 | struct GNUNET_GNSRECORD_Data rd_public[rd_count]; | 871 | struct GNUNET_GNSRECORD_Data rd_public[rd_count]; |
738 | unsigned int rd_public_count; | 872 | unsigned int rd_public_count; |
739 | struct DhtPutActivity *ma; | 873 | struct DhtPutActivity *ma; |
874 | struct TombstoneActivity *ta; | ||
875 | struct GNUNET_TIME_Absolute expire; | ||
740 | 876 | ||
741 | (void) cls; | 877 | (void) cls; |
742 | ns_iteration_left--; | 878 | ns_iteration_left--; |
743 | rd_public_count = convert_records_for_export (rd, | 879 | rd_public_count = convert_records_for_export (rd, |
744 | rd_count, | 880 | rd_count, |
745 | rd_public); | 881 | rd_public, |
882 | &expire); | ||
746 | if (0 == rd_public_count) | 883 | if (0 == rd_public_count) |
747 | { | 884 | { |
748 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 885 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -753,13 +890,25 @@ put_gns_record (void *cls, | |||
753 | /* We got a set of records to publish */ | 890 | /* We got a set of records to publish */ |
754 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 891 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
755 | "Starting DHT PUT\n"); | 892 | "Starting DHT PUT\n"); |
893 | |||
756 | ma = GNUNET_new (struct DhtPutActivity); | 894 | ma = GNUNET_new (struct DhtPutActivity); |
757 | ma->start_date = GNUNET_TIME_absolute_get (); | 895 | ma->start_date = GNUNET_TIME_absolute_get (); |
758 | ma->ph = perform_dht_put (key, | 896 | ma->ph = perform_dht_put (key, |
759 | label, | 897 | label, |
760 | rd_public, | 898 | rd_public, |
761 | rd_public_count, | 899 | rd_public_count, |
900 | expire, | ||
762 | ma); | 901 | ma); |
902 | ta = GNUNET_new (struct TombstoneActivity); | ||
903 | ta->ns_qe = touch_tombstone (key, | ||
904 | label, | ||
905 | rd, | ||
906 | rd_count, | ||
907 | expire, | ||
908 | ta); | ||
909 | GNUNET_CONTAINER_DLL_insert_tail (ta_head, | ||
910 | ta_tail, | ||
911 | ta); | ||
763 | put_cnt++; | 912 | put_cnt++; |
764 | if (0 == put_cnt % DELTA_INTERVAL) | 913 | if (0 == put_cnt % DELTA_INTERVAL) |
765 | update_velocity (DELTA_INTERVAL); | 914 | update_velocity (DELTA_INTERVAL); |