summaryrefslogtreecommitdiff
path: root/src/gns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-08-22 07:28:58 +0000
committerChristian Grothoff <christian@grothoff.org>2013-08-22 07:28:58 +0000
commit35904869bbbecaac43611a0d7b4b78e7735a90bf (patch)
tree04b76dcab6a97a1c4d41fbfda81f46893db543d0 /src/gns
parentaa590fa228c0efd30c5d6523bb064b4d4421752e (diff)
downloadgnunet-35904869bbbecaac43611a0d7b4b78e7735a90bf.tar.gz
gnunet-35904869bbbecaac43611a0d7b4b78e7735a90bf.zip
-move shorten logic to its own file
Diffstat (limited to 'src/gns')
-rw-r--r--src/gns/Makefile.am1
-rw-r--r--src/gns/gnunet-service-gns.c5
-rw-r--r--src/gns/gnunet-service-gns_resolver.c537
-rw-r--r--src/gns/gnunet-service-gns_shorten.c568
-rw-r--r--src/gns/gnunet-service-gns_shorten.h66
5 files changed, 641 insertions, 536 deletions
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index 10177996e..c2e4264b5 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -129,6 +129,7 @@ w32nsp_resolve_LDADD = -lws2_32
129gnunet_service_gns_SOURCES = \ 129gnunet_service_gns_SOURCES = \
130 gnunet-service-gns.c \ 130 gnunet-service-gns.c \
131 gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \ 131 gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \
132 gnunet-service-gns_shorten.c gnunet-service-gns_shorten.h \
132 gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h 133 gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h
133gnunet_service_gns_LDADD = \ 134gnunet_service_gns_LDADD = \
134 -lm \ 135 -lm \
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
index 583a5131a..b21584350 100644
--- a/src/gns/gnunet-service-gns.c
+++ b/src/gns/gnunet-service-gns.c
@@ -34,6 +34,7 @@
34#include "gnunet_statistics_service.h" 34#include "gnunet_statistics_service.h"
35#include "gns.h" 35#include "gns.h"
36#include "gnunet-service-gns_resolver.h" 36#include "gnunet-service-gns_resolver.h"
37#include "gnunet-service-gns_shorten.h"
37#include "gnunet-service-gns_interceptor.h" 38#include "gnunet-service-gns_interceptor.h"
38#include "gnunet_protocols.h" 39#include "gnunet_protocols.h"
39 40
@@ -214,6 +215,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
214 215
215 GNS_interceptor_done (); 216 GNS_interceptor_done ();
216 GNS_resolver_done (); 217 GNS_resolver_done ();
218 GNS_shorten_done ();
217 if (NULL != statistics) 219 if (NULL != statistics)
218 { 220 {
219 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); 221 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
@@ -718,11 +720,10 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
718 return; 720 return;
719 } 721 }
720 } 722 }
721 /* FIXME: install client disconnect handle to clean up pending
722 lookups on client disconnect! */
723 GNS_resolver_init (namestore_handle, dht_handle, 723 GNS_resolver_init (namestore_handle, dht_handle,
724 c, 724 c,
725 max_parallel_bg_queries); 725 max_parallel_bg_queries);
726 GNS_shorten_init (namestore_handle, dht_handle);
726 GNUNET_SERVER_disconnect_notify (server, 727 GNUNET_SERVER_disconnect_notify (server,
727 &notify_client_disconnect, 728 &notify_client_disconnect,
728 NULL); 729 NULL);
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
index b131a4750..0fb6ffbd1 100644
--- a/src/gns/gnunet-service-gns_resolver.c
+++ b/src/gns/gnunet-service-gns_resolver.c
@@ -53,7 +53,6 @@
53 */ 53 */
54#include "platform.h" 54#include "platform.h"
55#include "gnunet_util_lib.h" 55#include "gnunet_util_lib.h"
56#include "gnunet_transport_service.h"
57#include "gnunet_dnsstub_lib.h" 56#include "gnunet_dnsstub_lib.h"
58#include "gnunet_dht_service.h" 57#include "gnunet_dht_service.h"
59#include "gnunet_namestore_service.h" 58#include "gnunet_namestore_service.h"
@@ -63,6 +62,7 @@
63#include "gnunet_gns_service.h" 62#include "gnunet_gns_service.h"
64#include "gns.h" 63#include "gns.h"
65#include "gnunet-service-gns_resolver.h" 64#include "gnunet-service-gns_resolver.h"
65#include "gnunet-service-gns_shorten.h"
66#include "gnunet_vpn_service.h" 66#include "gnunet_vpn_service.h"
67 67
68 68
@@ -159,53 +159,6 @@ struct AuthorityChain
159 159
160 160
161/** 161/**
162 * Resolution status indicator
163 */
164enum ResolutionStatus
165{
166 /**
167 * the name to lookup exists
168 */
169 RSL_RECORD_EXISTS = 1,
170
171 /**
172 * the name in the record expired
173 */
174 RSL_RECORD_EXPIRED = 2,
175
176 /**
177 * resolution timed out
178 */
179 RSL_TIMED_OUT = 4,
180
181 /**
182 * Found VPN delegation
183 */
184 RSL_DELEGATE_VPN = 8,
185
186 /**
187 * Found NS delegation
188 */
189 RSL_DELEGATE_NS = 16,
190
191 /**
192 * Found PKEY delegation
193 */
194 RSL_DELEGATE_PKEY = 32,
195
196 /**
197 * Found CNAME record
198 */
199 RSL_CNAME_FOUND = 64,
200
201 /**
202 * Found PKEY has been revoked
203 */
204 RSL_PKEY_REVOKED = 128
205};
206
207
208/**
209 * A result we got from DNS. 162 * A result we got from DNS.
210 */ 163 */
211struct DnsResult 164struct DnsResult
@@ -402,60 +355,6 @@ struct GNS_ResolverHandle
402 355
403 356
404/** 357/**
405 * Handle for a PSEU lookup used to shorten names.
406 */
407struct GetPseuAuthorityHandle
408{
409 /**
410 * DLL
411 */
412 struct GetPseuAuthorityHandle *next;
413
414 /**
415 * DLL
416 */
417 struct GetPseuAuthorityHandle *prev;
418
419 /**
420 * Private key of the (shorten) zone to store the resulting
421 * pseudonym in.
422 */
423 struct GNUNET_CRYPTO_EccPrivateKey shorten_zone_key;
424
425 /**
426 * Original label (used if no PSEU record is found).
427 */
428 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
429
430 /**
431 * Label we are currently trying out (during #perform_pseu_lookup).
432 */
433 char *current_label;
434
435 /**
436 * The zone for which we are trying to find the PSEU record.
437 */
438 struct GNUNET_CRYPTO_EccPublicKey target_zone;
439
440 /**
441 * Handle for DHT lookups. Should be NULL if no lookups are in progress
442 */
443 struct GNUNET_DHT_GetHandle *get_handle;
444
445 /**
446 * Handle to namestore request
447 */
448 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
449
450 /**
451 * Task to abort DHT lookup operation.
452 */
453 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
454
455};
456
457
458/**
459 * Our handle to the namestore service 358 * Our handle to the namestore service
460 */ 359 */
461static struct GNUNET_NAMESTORE_Handle *namestore_handle; 360static struct GNUNET_NAMESTORE_Handle *namestore_handle;
@@ -486,16 +385,6 @@ static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
486static unsigned long long max_allowed_background_queries; 385static unsigned long long max_allowed_background_queries;
487 386
488/** 387/**
489 * Head of PSEU/shorten operations list.
490 */
491struct GetPseuAuthorityHandle *gph_head;
492
493/**
494 * Tail of PSEU/shorten operations list.
495 */
496struct GetPseuAuthorityHandle *gph_tail;
497
498/**
499 * Head of resolver lookup list 388 * Head of resolver lookup list
500 */ 389 */
501static struct GNS_ResolverHandle *rlh_head; 390static struct GNS_ResolverHandle *rlh_head;
@@ -576,425 +465,6 @@ is_canonical (const char *name)
576} 465}
577 466
578 467
579/* ******************** Shortening logic ************************ */
580
581
582/**
583 * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
584 * pending activities.
585 *
586 * @param gph handle to terminate
587 */
588static void
589free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
590{
591 if (NULL != gph->get_handle)
592 {
593 GNUNET_DHT_get_stop (gph->get_handle);
594 gph->get_handle = NULL;
595 }
596 if (NULL != gph->namestore_task)
597 {
598 GNUNET_NAMESTORE_cancel (gph->namestore_task);
599 gph->namestore_task = NULL;
600 }
601 if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
602 {
603 GNUNET_SCHEDULER_cancel (gph->timeout_task);
604 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
605 }
606 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
607 GNUNET_free_non_null (gph->current_label);
608 GNUNET_free (gph);
609}
610
611
612/**
613 * Continuation for pkey record creation (shorten)
614 *
615 * @param cls a GetPseuAuthorityHandle
616 * @param success unused
617 * @param emsg unused
618 */
619static void
620create_pkey_cont (void* cls,
621 int32_t success,
622 const char *emsg)
623{
624 struct GetPseuAuthorityHandle* gph = cls;
625
626 gph->namestore_task = NULL;
627 free_get_pseu_authority_handle (gph);
628}
629
630
631/**
632 * Namestore calls this function if we have record for this name.
633 * (or with rd_count=0 to indicate no matches).
634 *
635 * @param cls the pending query
636 * @param rd_count the number of records with 'name'
637 * @param rd the record data
638 */
639static void
640process_pseu_lookup_ns (void *cls,
641 unsigned int rd_count,
642 const struct GNUNET_NAMESTORE_RecordData *rd);
643
644
645/**
646 * We obtained a result for our query to the shorten zone from
647 * the namestore. Try to decrypt.
648 *
649 * @param cls the handle to our shorten operation
650 * @param block resulting encrypted block
651 */
652static void
653process_pseu_block_ns (void *cls,
654 const struct GNUNET_NAMESTORE_Block *block)
655{
656 struct GetPseuAuthorityHandle *gph = cls;
657 struct GNUNET_CRYPTO_EccPublicKey pub;
658
659 gph->namestore_task = NULL;
660 if (NULL == block)
661 {
662 process_pseu_lookup_ns (gph, 0, NULL);
663 return;
664 }
665 GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
666 &pub);
667 if (GNUNET_OK !=
668 GNUNET_NAMESTORE_block_decrypt (block,
669 &pub,
670 gph->current_label,
671 &process_pseu_lookup_ns,
672 gph))
673 {
674 GNUNET_break (0);
675 free_get_pseu_authority_handle (gph);
676 return;
677 }
678}
679
680
681/**
682 * Lookup in the namestore for the shorten zone the given label.
683 *
684 * @param gph the handle to our shorten operation
685 * @param label the label to lookup
686 */
687static void
688perform_pseu_lookup (struct GetPseuAuthorityHandle *gph,
689 const char *label)
690{
691 struct GNUNET_CRYPTO_EccPublicKey pub;
692 struct GNUNET_HashCode query;
693
694 GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
695 &pub);
696 GNUNET_free_non_null (gph->current_label);
697 gph->current_label = GNUNET_strdup (label);
698 GNUNET_NAMESTORE_query_from_public_key (&pub,
699 label,
700 &query);
701 gph->namestore_task = GNUNET_NAMESTORE_lookup_block (namestore_handle,
702 &query,
703 &process_pseu_block_ns,
704 gph);
705}
706
707
708/**
709 * Namestore calls this function if we have record for this name.
710 * (or with rd_count=0 to indicate no matches).
711 *
712 * @param cls the pending query
713 * @param rd_count the number of records with 'name'
714 * @param rd the record data
715 */
716static void
717process_pseu_lookup_ns (void *cls,
718 unsigned int rd_count,
719 const struct GNUNET_NAMESTORE_RecordData *rd)
720{
721 struct GetPseuAuthorityHandle *gph = cls;
722 struct GNUNET_NAMESTORE_RecordData new_pkey;
723
724 gph->namestore_task = NULL;
725 if (rd_count > 0)
726 {
727 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
728 "Name `%s' already taken, cannot shorten.\n",
729 gph->current_label);
730 /* if this was not yet the original label, try one more
731 time, this time not using PSEU but the original label */
732 if (0 == strcmp (gph->current_label,
733 gph->label))
734 {
735 free_get_pseu_authority_handle (gph);
736 }
737 else
738 {
739 perform_pseu_lookup (gph, gph->label);
740 }
741 return;
742 }
743 /* name is available */
744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745 "Shortening `%s' to `%s'\n",
746 GNUNET_NAMESTORE_z2s (&gph->target_zone),
747 gph->current_label);
748 new_pkey.expiration_time = UINT64_MAX;
749 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
750 new_pkey.data = &gph->target_zone;
751 new_pkey.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
752 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
753 | GNUNET_NAMESTORE_RF_PRIVATE
754 | GNUNET_NAMESTORE_RF_PENDING;
755 gph->namestore_task
756 = GNUNET_NAMESTORE_records_store (namestore_handle,
757 &gph->shorten_zone_key,
758 gph->current_label,
759 1, &new_pkey,
760 &create_pkey_cont, gph);
761}
762
763
764/**
765 * Process result of a DHT lookup for a PSEU record.
766 *
767 * @param gph the handle to our shorten operation
768 * @param pseu the pseu result or NULL
769 */
770static void
771process_pseu_result (struct GetPseuAuthorityHandle* gph,
772 const char *pseu)
773{
774 if (NULL == pseu)
775 {
776 /* no PSEU found, try original label */
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778 "No PSEU found, trying original label `%s' instead.\n",
779 gph->label);
780 perform_pseu_lookup (gph, gph->label);
781 return;
782 }
783 /* check if 'pseu' is taken */
784 perform_pseu_lookup (gph, pseu);
785}
786
787
788/**
789 * Handle timeout for DHT request during shortening.
790 *
791 * @param cls the request handle as closure
792 * @param tc the task context
793 */
794static void
795handle_auth_discovery_timeout (void *cls,
796 const struct GNUNET_SCHEDULER_TaskContext *tc)
797{
798 struct GetPseuAuthorityHandle *gph = cls;
799
800 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
802 "DHT lookup for PSEU query timed out.\n");
803 GNUNET_DHT_get_stop (gph->get_handle);
804 gph->get_handle = NULL;
805 process_pseu_result (gph, NULL);
806}
807
808
809/**
810 * Handle decrypted records from DHT result.
811 *
812 * @param cls closure with our 'struct GetPseuAuthorityHandle'
813 * @param rd_count number of entries in 'rd' array
814 * @param rd array of records with data to store
815 */
816static void
817process_auth_records (void *cls,
818 unsigned int rd_count,
819 const struct GNUNET_NAMESTORE_RecordData *rd)
820{
821 struct GetPseuAuthorityHandle *gph = cls;
822 unsigned int i;
823
824 for (i=0; i < rd_count; i++)
825 {
826 if (GNUNET_NAMESTORE_TYPE_PSEU == rd[i].record_type)
827 {
828 /* found pseu */
829 process_pseu_result (gph,
830 (const char *) rd[i].data);
831 return;
832 }
833 }
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 "No PSEU record found in DHT reply.\n");
836 process_pseu_result (gph, NULL);
837}
838
839
840/**
841 * Function called when we find a PSEU entry in the DHT
842 *
843 * @param cls the request handle
844 * @param exp lifetime
845 * @param key the key the record was stored under
846 * @param get_path get path
847 * @param get_path_length get path length
848 * @param put_path put path
849 * @param put_path_length put path length
850 * @param type the block type
851 * @param size the size of the record
852 * @param data the record data
853 */
854static void
855process_auth_discovery_dht_result (void* cls,
856 struct GNUNET_TIME_Absolute exp,
857 const struct GNUNET_HashCode *key,
858 const struct GNUNET_PeerIdentity *get_path,
859 unsigned int get_path_length,
860 const struct GNUNET_PeerIdentity *put_path,
861 unsigned int put_path_length,
862 enum GNUNET_BLOCK_Type type,
863 size_t size,
864 const void *data)
865{
866 struct GetPseuAuthorityHandle *gph = cls;
867 const struct GNUNET_NAMESTORE_Block *block;
868
869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
870 "Got DHT result for PSEU request\n");
871 GNUNET_DHT_get_stop (gph->get_handle);
872 gph->get_handle = NULL;
873 GNUNET_SCHEDULER_cancel (gph->timeout_task);
874 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
875
876 if (NULL == data)
877 {
878 /* is this allowed!? */
879 GNUNET_break (0);
880 process_pseu_result (gph, NULL);
881 return;
882 }
883 if (size < sizeof (struct GNUNET_NAMESTORE_Block))
884 {
885 /* how did this pass DHT block validation!? */
886 GNUNET_break (0);
887 process_pseu_result (gph, NULL);
888 return;
889 }
890 block = data;
891 if (size !=
892 ntohs (block->purpose.size) +
893 sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
894 sizeof (struct GNUNET_CRYPTO_EccSignature))
895 {
896 /* how did this pass DHT block validation!? */
897 GNUNET_break (0);
898 process_pseu_result (gph, NULL);
899 return;
900 }
901 if (GNUNET_OK !=
902 GNUNET_NAMESTORE_block_decrypt (block,
903 &gph->target_zone,
904 GNUNET_GNS_TLD_PLUS,
905 &process_auth_records,
906 gph))
907 {
908 /* other peer encrypted invalid block, complain */
909 GNUNET_break_op (0);
910 process_pseu_result (gph, NULL);
911 return;
912 }
913}
914
915
916/**
917 * Callback called by namestore for a zone to name result. We're
918 * trying to see if a short name for a given zone already exists.
919 *
920 * @param cls the closure
921 * @param zone_key the zone we queried
922 * @param name the name found or NULL
923 * @param rd_len number of records for the name
924 * @param rd the record data (PKEY) for the name
925 */
926static void
927process_zone_to_name_discover (void *cls,
928 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
929 const char *name,
930 unsigned int rd_len,
931 const struct GNUNET_NAMESTORE_RecordData *rd)
932{
933 struct GetPseuAuthorityHandle* gph = cls;
934 struct GNUNET_HashCode lookup_key;
935
936 gph->namestore_task = NULL;
937 if (0 != rd_len)
938 {
939 /* we found a match in our own zone */
940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
941 "Shortening aborted, name `%s' already reserved for the zone\n",
942 name);
943 free_get_pseu_authority_handle (gph);
944 return;
945 }
946 /* record does not yet exist, go into DHT to find PSEU record */
947 GNUNET_NAMESTORE_query_from_public_key (&gph->target_zone,
948 GNUNET_GNS_TLD_PLUS,
949 &lookup_key);
950 gph->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
951 &handle_auth_discovery_timeout,
952 gph);
953 gph->get_handle = GNUNET_DHT_get_start (dht_handle,
954 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
955 &lookup_key,
956 DHT_GNS_REPLICATION_LEVEL,
957 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
958 NULL, 0,
959 &process_auth_discovery_dht_result,
960 gph);
961}
962
963
964/**
965 * Start shortening algorithm, try to allocate a nice short
966 * canonical name for @a pub in @a shorten_zone, using
967 * @a original_label as one possible suggestion.
968 *
969 * @param original_label original label for the zone
970 * @param pub public key of the zone to shorten
971 * @param shorten_zone private key of the target zone for the new record
972 */
973static void
974start_shorten (const char *original_label,
975 const struct GNUNET_CRYPTO_EccPublicKey *pub,
976 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone)
977{
978 struct GetPseuAuthorityHandle *gph;
979
980 if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
981 {
982 GNUNET_break (0);
983 return;
984 }
985 gph = GNUNET_new (struct GetPseuAuthorityHandle);
986 gph->shorten_zone_key = *shorten_zone;
987 gph->target_zone = *pub;
988 strcpy (gph->label, original_label);
989 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
990 /* first, check if we *already* have a record for this zone */
991 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
992 shorten_zone,
993 pub,
994 &process_zone_to_name_discover,
995 gph);
996}
997
998 468
999/* ************************** Resolution **************************** */ 469/* ************************** Resolution **************************** */
1000 470
@@ -2394,15 +1864,14 @@ GNS_resolver_done ()
2394 rh->proc (rh->proc_cls, 0, NULL); 1864 rh->proc (rh->proc_cls, 0, NULL);
2395 GNS_resolver_lookup_cancel (rh); 1865 GNS_resolver_lookup_cancel (rh);
2396 } 1866 }
2397 /* abort active shorten operations */
2398 while (NULL != gph_head)
2399 free_get_pseu_authority_handle (gph_head);
2400 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap); 1867 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2401 dht_lookup_heap = NULL; 1868 dht_lookup_heap = NULL;
2402 GNUNET_DNSSTUB_stop (dns_handle); 1869 GNUNET_DNSSTUB_stop (dns_handle);
2403 dns_handle = NULL; 1870 dns_handle = NULL;
2404 GNUNET_VPN_disconnect (vpn_handle); 1871 GNUNET_VPN_disconnect (vpn_handle);
2405 vpn_handle = NULL; 1872 vpn_handle = NULL;
1873 dht_handle = NULL;
1874 namestore_handle = NULL;
2406} 1875}
2407 1876
2408 1877
diff --git a/src/gns/gnunet-service-gns_shorten.c b/src/gns/gnunet-service-gns_shorten.c
new file mode 100644
index 000000000..6f27a7234
--- /dev/null
+++ b/src/gns/gnunet-service-gns_shorten.c
@@ -0,0 +1,568 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011-2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file gns/gnunet-service-gns_shorten.c
23 * @brief GNUnet GNS shortening logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_namestore_service.h"
31#include "gnunet_resolver_service.h"
32#include "gnunet_gns_service.h"
33#include "gns.h"
34#include "gnunet-service-gns_shorten.h"
35#include "gnunet_vpn_service.h"
36
37
38/**
39 * Default DHT timeout for lookups.
40 */
41#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
42
43/**
44 * DHT replication level
45 */
46#define DHT_GNS_REPLICATION_LEVEL 5
47
48
49/**
50 * Handle for a PSEU lookup used to shorten names.
51 */
52struct GetPseuAuthorityHandle
53{
54 /**
55 * DLL
56 */
57 struct GetPseuAuthorityHandle *next;
58
59 /**
60 * DLL
61 */
62 struct GetPseuAuthorityHandle *prev;
63
64 /**
65 * Private key of the (shorten) zone to store the resulting
66 * pseudonym in.
67 */
68 struct GNUNET_CRYPTO_EccPrivateKey shorten_zone_key;
69
70 /**
71 * Original label (used if no PSEU record is found).
72 */
73 char label[GNUNET_DNSPARSER_MAX_LABEL_LENGTH + 1];
74
75 /**
76 * Label we are currently trying out (during #perform_pseu_lookup).
77 */
78 char *current_label;
79
80 /**
81 * The zone for which we are trying to find the PSEU record.
82 */
83 struct GNUNET_CRYPTO_EccPublicKey target_zone;
84
85 /**
86 * Handle for DHT lookups. Should be NULL if no lookups are in progress
87 */
88 struct GNUNET_DHT_GetHandle *get_handle;
89
90 /**
91 * Handle to namestore request
92 */
93 struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
94
95 /**
96 * Task to abort DHT lookup operation.
97 */
98 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
99
100};
101
102
103/**
104 * Head of PSEU/shorten operations list.
105 */
106static struct GetPseuAuthorityHandle *gph_head;
107
108/**
109 * Tail of PSEU/shorten operations list.
110 */
111static struct GetPseuAuthorityHandle *gph_tail;
112
113/**
114 * Our handle to the namestore service
115 */
116static struct GNUNET_NAMESTORE_Handle *namestore_handle;
117
118/**
119 * Resolver handle to the dht
120 */
121static struct GNUNET_DHT_Handle *dht_handle;
122
123/**
124 * Cleanup a 'struct GetPseuAuthorityHandle', terminating all
125 * pending activities.
126 *
127 * @param gph handle to terminate
128 */
129static void
130free_get_pseu_authority_handle (struct GetPseuAuthorityHandle *gph)
131{
132 if (NULL != gph->get_handle)
133 {
134 GNUNET_DHT_get_stop (gph->get_handle);
135 gph->get_handle = NULL;
136 }
137 if (NULL != gph->namestore_task)
138 {
139 GNUNET_NAMESTORE_cancel (gph->namestore_task);
140 gph->namestore_task = NULL;
141 }
142 if (GNUNET_SCHEDULER_NO_TASK != gph->timeout_task)
143 {
144 GNUNET_SCHEDULER_cancel (gph->timeout_task);
145 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
146 }
147 GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
148 GNUNET_free_non_null (gph->current_label);
149 GNUNET_free (gph);
150}
151
152
153/**
154 * Continuation for pkey record creation (shorten)
155 *
156 * @param cls a GetPseuAuthorityHandle
157 * @param success unused
158 * @param emsg unused
159 */
160static void
161create_pkey_cont (void* cls,
162 int32_t success,
163 const char *emsg)
164{
165 struct GetPseuAuthorityHandle* gph = cls;
166
167 gph->namestore_task = NULL;
168 free_get_pseu_authority_handle (gph);
169}
170
171
172/**
173 * Namestore calls this function if we have record for this name.
174 * (or with rd_count=0 to indicate no matches).
175 *
176 * @param cls the pending query
177 * @param rd_count the number of records with 'name'
178 * @param rd the record data
179 */
180static void
181process_pseu_lookup_ns (void *cls,
182 unsigned int rd_count,
183 const struct GNUNET_NAMESTORE_RecordData *rd);
184
185
186/**
187 * We obtained a result for our query to the shorten zone from
188 * the namestore. Try to decrypt.
189 *
190 * @param cls the handle to our shorten operation
191 * @param block resulting encrypted block
192 */
193static void
194process_pseu_block_ns (void *cls,
195 const struct GNUNET_NAMESTORE_Block *block)
196{
197 struct GetPseuAuthorityHandle *gph = cls;
198 struct GNUNET_CRYPTO_EccPublicKey pub;
199
200 gph->namestore_task = NULL;
201 if (NULL == block)
202 {
203 process_pseu_lookup_ns (gph, 0, NULL);
204 return;
205 }
206 GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
207 &pub);
208 if (GNUNET_OK !=
209 GNUNET_NAMESTORE_block_decrypt (block,
210 &pub,
211 gph->current_label,
212 &process_pseu_lookup_ns,
213 gph))
214 {
215 GNUNET_break (0);
216 free_get_pseu_authority_handle (gph);
217 return;
218 }
219}
220
221
222/**
223 * Lookup in the namestore for the shorten zone the given label.
224 *
225 * @param gph the handle to our shorten operation
226 * @param label the label to lookup
227 */
228static void
229perform_pseu_lookup (struct GetPseuAuthorityHandle *gph,
230 const char *label)
231{
232 struct GNUNET_CRYPTO_EccPublicKey pub;
233 struct GNUNET_HashCode query;
234
235 GNUNET_CRYPTO_ecc_key_get_public (&gph->shorten_zone_key,
236 &pub);
237 GNUNET_free_non_null (gph->current_label);
238 gph->current_label = GNUNET_strdup (label);
239 GNUNET_NAMESTORE_query_from_public_key (&pub,
240 label,
241 &query);
242 gph->namestore_task = GNUNET_NAMESTORE_lookup_block (namestore_handle,
243 &query,
244 &process_pseu_block_ns,
245 gph);
246}
247
248
249/**
250 * Namestore calls this function if we have record for this name.
251 * (or with rd_count=0 to indicate no matches).
252 *
253 * @param cls the pending query
254 * @param rd_count the number of records with 'name'
255 * @param rd the record data
256 */
257static void
258process_pseu_lookup_ns (void *cls,
259 unsigned int rd_count,
260 const struct GNUNET_NAMESTORE_RecordData *rd)
261{
262 struct GetPseuAuthorityHandle *gph = cls;
263 struct GNUNET_NAMESTORE_RecordData new_pkey;
264
265 gph->namestore_task = NULL;
266 if (rd_count > 0)
267 {
268 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
269 "Name `%s' already taken, cannot shorten.\n",
270 gph->current_label);
271 /* if this was not yet the original label, try one more
272 time, this time not using PSEU but the original label */
273 if (0 == strcmp (gph->current_label,
274 gph->label))
275 {
276 free_get_pseu_authority_handle (gph);
277 }
278 else
279 {
280 perform_pseu_lookup (gph, gph->label);
281 }
282 return;
283 }
284 /* name is available */
285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286 "Shortening `%s' to `%s'\n",
287 GNUNET_NAMESTORE_z2s (&gph->target_zone),
288 gph->current_label);
289 new_pkey.expiration_time = UINT64_MAX;
290 new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
291 new_pkey.data = &gph->target_zone;
292 new_pkey.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
293 new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
294 | GNUNET_NAMESTORE_RF_PRIVATE
295 | GNUNET_NAMESTORE_RF_PENDING;
296 gph->namestore_task
297 = GNUNET_NAMESTORE_records_store (namestore_handle,
298 &gph->shorten_zone_key,
299 gph->current_label,
300 1, &new_pkey,
301 &create_pkey_cont, gph);
302}
303
304
305/**
306 * Process result of a DHT lookup for a PSEU record.
307 *
308 * @param gph the handle to our shorten operation
309 * @param pseu the pseu result or NULL
310 */
311static void
312process_pseu_result (struct GetPseuAuthorityHandle* gph,
313 const char *pseu)
314{
315 if (NULL == pseu)
316 {
317 /* no PSEU found, try original label */
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 "No PSEU found, trying original label `%s' instead.\n",
320 gph->label);
321 perform_pseu_lookup (gph, gph->label);
322 return;
323 }
324 /* check if 'pseu' is taken */
325 perform_pseu_lookup (gph, pseu);
326}
327
328
329/**
330 * Handle timeout for DHT request during shortening.
331 *
332 * @param cls the request handle as closure
333 * @param tc the task context
334 */
335static void
336handle_auth_discovery_timeout (void *cls,
337 const struct GNUNET_SCHEDULER_TaskContext *tc)
338{
339 struct GetPseuAuthorityHandle *gph = cls;
340
341 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "DHT lookup for PSEU query timed out.\n");
344 GNUNET_DHT_get_stop (gph->get_handle);
345 gph->get_handle = NULL;
346 process_pseu_result (gph, NULL);
347}
348
349
350/**
351 * Handle decrypted records from DHT result.
352 *
353 * @param cls closure with our 'struct GetPseuAuthorityHandle'
354 * @param rd_count number of entries in 'rd' array
355 * @param rd array of records with data to store
356 */
357static void
358process_auth_records (void *cls,
359 unsigned int rd_count,
360 const struct GNUNET_NAMESTORE_RecordData *rd)
361{
362 struct GetPseuAuthorityHandle *gph = cls;
363 unsigned int i;
364
365 for (i=0; i < rd_count; i++)
366 {
367 if (GNUNET_NAMESTORE_TYPE_PSEU == rd[i].record_type)
368 {
369 /* found pseu */
370 process_pseu_result (gph,
371 (const char *) rd[i].data);
372 return;
373 }
374 }
375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376 "No PSEU record found in DHT reply.\n");
377 process_pseu_result (gph, NULL);
378}
379
380
381/**
382 * Function called when we find a PSEU entry in the DHT
383 *
384 * @param cls the request handle
385 * @param exp lifetime
386 * @param key the key the record was stored under
387 * @param get_path get path
388 * @param get_path_length get path length
389 * @param put_path put path
390 * @param put_path_length put path length
391 * @param type the block type
392 * @param size the size of the record
393 * @param data the record data
394 */
395static void
396process_auth_discovery_dht_result (void* cls,
397 struct GNUNET_TIME_Absolute exp,
398 const struct GNUNET_HashCode *key,
399 const struct GNUNET_PeerIdentity *get_path,
400 unsigned int get_path_length,
401 const struct GNUNET_PeerIdentity *put_path,
402 unsigned int put_path_length,
403 enum GNUNET_BLOCK_Type type,
404 size_t size,
405 const void *data)
406{
407 struct GetPseuAuthorityHandle *gph = cls;
408 const struct GNUNET_NAMESTORE_Block *block;
409
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411 "Got DHT result for PSEU request\n");
412 GNUNET_DHT_get_stop (gph->get_handle);
413 gph->get_handle = NULL;
414 GNUNET_SCHEDULER_cancel (gph->timeout_task);
415 gph->timeout_task = GNUNET_SCHEDULER_NO_TASK;
416
417 if (NULL == data)
418 {
419 /* is this allowed!? */
420 GNUNET_break (0);
421 process_pseu_result (gph, NULL);
422 return;
423 }
424 if (size < sizeof (struct GNUNET_NAMESTORE_Block))
425 {
426 /* how did this pass DHT block validation!? */
427 GNUNET_break (0);
428 process_pseu_result (gph, NULL);
429 return;
430 }
431 block = data;
432 if (size !=
433 ntohs (block->purpose.size) +
434 sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
435 sizeof (struct GNUNET_CRYPTO_EccSignature))
436 {
437 /* how did this pass DHT block validation!? */
438 GNUNET_break (0);
439 process_pseu_result (gph, NULL);
440 return;
441 }
442 if (GNUNET_OK !=
443 GNUNET_NAMESTORE_block_decrypt (block,
444 &gph->target_zone,
445 GNUNET_GNS_TLD_PLUS,
446 &process_auth_records,
447 gph))
448 {
449 /* other peer encrypted invalid block, complain */
450 GNUNET_break_op (0);
451 process_pseu_result (gph, NULL);
452 return;
453 }
454}
455
456
457/**
458 * Callback called by namestore for a zone to name result. We're
459 * trying to see if a short name for a given zone already exists.
460 *
461 * @param cls the closure
462 * @param zone_key the zone we queried
463 * @param name the name found or NULL
464 * @param rd_len number of records for the name
465 * @param rd the record data (PKEY) for the name
466 */
467static void
468process_zone_to_name_discover (void *cls,
469 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
470 const char *name,
471 unsigned int rd_len,
472 const struct GNUNET_NAMESTORE_RecordData *rd)
473{
474 struct GetPseuAuthorityHandle* gph = cls;
475 struct GNUNET_HashCode lookup_key;
476
477 gph->namestore_task = NULL;
478 if (0 != rd_len)
479 {
480 /* we found a match in our own zone */
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
482 "Shortening aborted, name `%s' already reserved for the zone\n",
483 name);
484 free_get_pseu_authority_handle (gph);
485 return;
486 }
487 /* record does not yet exist, go into DHT to find PSEU record */
488 GNUNET_NAMESTORE_query_from_public_key (&gph->target_zone,
489 GNUNET_GNS_TLD_PLUS,
490 &lookup_key);
491 gph->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
492 &handle_auth_discovery_timeout,
493 gph);
494 gph->get_handle = GNUNET_DHT_get_start (dht_handle,
495 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
496 &lookup_key,
497 DHT_GNS_REPLICATION_LEVEL,
498 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
499 NULL, 0,
500 &process_auth_discovery_dht_result,
501 gph);
502}
503
504
505/**
506 * Start shortening algorithm, try to allocate a nice short
507 * canonical name for @a pub in @a shorten_zone, using
508 * @a original_label as one possible suggestion.
509 *
510 * @param original_label original label for the zone
511 * @param pub public key of the zone to shorten
512 * @param shorten_zone private key of the target zone for the new record
513 */
514void
515GNS_shorten_start (const char *original_label,
516 const struct GNUNET_CRYPTO_EccPublicKey *pub,
517 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone)
518{
519 struct GetPseuAuthorityHandle *gph;
520
521 if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
522 {
523 GNUNET_break (0);
524 return;
525 }
526 gph = GNUNET_new (struct GetPseuAuthorityHandle);
527 gph->shorten_zone_key = *shorten_zone;
528 gph->target_zone = *pub;
529 strcpy (gph->label, original_label);
530 GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
531 /* first, check if we *already* have a record for this zone */
532 gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
533 shorten_zone,
534 pub,
535 &process_zone_to_name_discover,
536 gph);
537}
538
539
540/**
541 * Initialize the shortening subsystem
542 *
543 * @param nh the namestore handle
544 * @param dht the dht handle
545 */
546void
547GNS_shorten_init (struct GNUNET_NAMESTORE_Handle *nh,
548 struct GNUNET_DHT_Handle *dht)
549{
550 namestore_handle = nh;
551 dht_handle = dht;
552}
553
554
555/**
556 * Shutdown shortening.
557 */
558void
559GNS_shorten_done ()
560{
561 /* abort active shorten operations */
562 while (NULL != gph_head)
563 free_get_pseu_authority_handle (gph_head);
564 dht_handle = NULL;
565 namestore_handle = NULL;
566}
567
568/* end of gnunet-service-gns_shorten.c */
diff --git a/src/gns/gnunet-service-gns_shorten.h b/src/gns/gnunet-service-gns_shorten.h
new file mode 100644
index 000000000..d71100a88
--- /dev/null
+++ b/src/gns/gnunet-service-gns_shorten.h
@@ -0,0 +1,66 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009-2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file gns/gnunet-service-gns_shorten.h
22 * @brief GNUnet GNS shortening API
23 * @author Martin Schanzenbach
24 */
25#ifndef GNS_SHORTEN_H
26#define GNS_SHORTEN_H
27#include "gns.h"
28#include "gnunet_dht_service.h"
29#include "gnunet_namestore_service.h"
30
31
32/**
33 * Initialize the shorten subsystem.
34 * MUST be called before #GNS_shorten_start.
35 *
36 * @param nh handle to the namestore
37 * @param dht handle to the dht
38 */
39void
40GNS_shorten_init (struct GNUNET_NAMESTORE_Handle *nh,
41 struct GNUNET_DHT_Handle *dht);
42
43
44/**
45 * Cleanup shorten: Terminate pending lookups
46 */
47void
48GNS_shorten_done (void);
49
50
51/**
52 * Start shortening algorithm, try to allocate a nice short
53 * canonical name for @a pub in @a shorten_zone, using
54 * @a original_label as one possible suggestion.
55 *
56 * @param original_label original label for the zone
57 * @param pub public key of the zone to shorten
58 * @param shorten_zone private key of the target zone for the new record
59 */
60void
61GNS_shorten_start (const char *original_label,
62 const struct GNUNET_CRYPTO_EccPublicKey *pub,
63 const struct GNUNET_CRYPTO_EccPrivateKey *shorten_zone);
64
65
66#endif