diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-04-10 15:10:08 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-04-10 15:10:21 +0200 |
commit | 2c3ed5fda45b21ce7e3038324d785cb13ffd0edb (patch) | |
tree | 7fc0611fc98c81d91b0ebaa7c776fd2d056bb7c6 /src/namestore/gnunet-zoneimport.c | |
parent | de72aeb9ffa09576f7df749ef5ef2cf3391adec2 (diff) | |
download | gnunet-2c3ed5fda45b21ce7e3038324d785cb13ffd0edb.tar.gz gnunet-2c3ed5fda45b21ce7e3038324d785cb13ffd0edb.zip |
more work on zoneimport tool, lacks CNAME but otherwise largely complete, except untested
Diffstat (limited to 'src/namestore/gnunet-zoneimport.c')
-rw-r--r-- | src/namestore/gnunet-zoneimport.c | 328 |
1 files changed, 294 insertions, 34 deletions
diff --git a/src/namestore/gnunet-zoneimport.c b/src/namestore/gnunet-zoneimport.c index 33c20953b..f2e5c7ba8 100644 --- a/src/namestore/gnunet-zoneimport.c +++ b/src/namestore/gnunet-zoneimport.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <gnunet_dnsparser_lib.h> | 28 | #include <gnunet_dnsparser_lib.h> |
29 | #include <gnunet_gnsrecord_lib.h> | 29 | #include <gnunet_gnsrecord_lib.h> |
30 | #include <gnunet_namestore_plugin.h> | 30 | #include <gnunet_namestore_plugin.h> |
31 | #include <gnunet_identity_service.h> | ||
31 | 32 | ||
32 | 33 | ||
33 | /** | 34 | /** |
@@ -91,14 +92,14 @@ struct Request | |||
91 | void *raw; | 92 | void *raw; |
92 | 93 | ||
93 | /** | 94 | /** |
94 | * Number of bytes in @e raw. | 95 | * Hostname we are resolving. |
95 | */ | 96 | */ |
96 | size_t raw_len; | 97 | char *hostname; |
97 | 98 | ||
98 | /** | 99 | /** |
99 | * Hostname we are resolving. | 100 | * Label (without TLD) which we are resolving. |
100 | */ | 101 | */ |
101 | char *hostname; | 102 | char *label; |
102 | 103 | ||
103 | /** | 104 | /** |
104 | * Answer we got back and are currently parsing, or NULL | 105 | * Answer we got back and are currently parsing, or NULL |
@@ -111,7 +112,12 @@ struct Request | |||
111 | * for this name expire? At this point, we need to re-fetch | 112 | * for this name expire? At this point, we need to re-fetch |
112 | * the record. | 113 | * the record. |
113 | */ | 114 | */ |
114 | struct GNUNET_TIME_Absolute expires__; | 115 | struct GNUNET_TIME_Absolute expires; |
116 | |||
117 | /** | ||
118 | * Number of bytes in @e raw. | ||
119 | */ | ||
120 | size_t raw_len; | ||
115 | 121 | ||
116 | /** | 122 | /** |
117 | * When did we last issue this request? | 123 | * When did we last issue this request? |
@@ -130,6 +136,12 @@ struct Request | |||
130 | uint16_t id; | 136 | uint16_t id; |
131 | }; | 137 | }; |
132 | 138 | ||
139 | |||
140 | /** | ||
141 | * Handle to the identity service. | ||
142 | */ | ||
143 | static struct GNUNET_IDENTITY_Handle *id; | ||
144 | |||
133 | /** | 145 | /** |
134 | * Namestore plugin. | 146 | * Namestore plugin. |
135 | */ | 147 | */ |
@@ -187,6 +199,21 @@ static char *dns_server; | |||
187 | */ | 199 | */ |
188 | static char *db_lib_name; | 200 | static char *db_lib_name; |
189 | 201 | ||
202 | /** | ||
203 | * Which zone are we importing into? | ||
204 | */ | ||
205 | static struct GNUNET_CRYPTO_EcdsaPrivateKey zone; | ||
206 | |||
207 | /** | ||
208 | * Which zone should records be imported into? | ||
209 | */ | ||
210 | static char *zone_name; | ||
211 | |||
212 | /** | ||
213 | * Did we find #zone_name and initialize #zone? | ||
214 | */ | ||
215 | static int zone_found; | ||
216 | |||
190 | 217 | ||
191 | /** | 218 | /** |
192 | * Maximum number of queries pending at the same time. | 219 | * Maximum number of queries pending at the same time. |
@@ -251,7 +278,35 @@ for_all_records (const struct GNUNET_DNSPARSER_Packet *p, | |||
251 | rs); | 278 | rs); |
252 | } | 279 | } |
253 | } | 280 | } |
254 | 281 | ||
282 | |||
283 | /** | ||
284 | * Insert @a req into DLL sorted by next fetch time. | ||
285 | * | ||
286 | * @param req request to insert into #req_head / #req_tail DLL | ||
287 | */ | ||
288 | static void | ||
289 | insert_sorted (struct Request *req) | ||
290 | { | ||
291 | struct Request *prev; | ||
292 | |||
293 | prev = NULL; | ||
294 | /* NOTE: this linear-time loop may actually be our | ||
295 | main burner of CPU time for large zones, to be | ||
296 | revisited if CPU utilization turns out to be an | ||
297 | issue! */ | ||
298 | for (struct Request *pos = req_head; | ||
299 | ( (NULL != pos) && | ||
300 | (NULL != pos->next) && | ||
301 | (pos->expires.abs_value_us <= req->expires.abs_value_us) ); | ||
302 | pos = pos->next) | ||
303 | prev = pos; | ||
304 | GNUNET_CONTAINER_DLL_insert_after (req_head, | ||
305 | req_tail, | ||
306 | prev, | ||
307 | req); | ||
308 | } | ||
309 | |||
255 | 310 | ||
256 | /** | 311 | /** |
257 | * Add record to the GNS record set for @a req. | 312 | * Add record to the GNS record set for @a req. |
@@ -573,7 +628,9 @@ process_result (void *cls, | |||
573 | size_t dns_len) | 628 | size_t dns_len) |
574 | { | 629 | { |
575 | struct Request *req = cls; | 630 | struct Request *req = cls; |
631 | struct Record *rec; | ||
576 | struct GNUNET_DNSPARSER_Packet *p; | 632 | struct GNUNET_DNSPARSER_Packet *p; |
633 | unsigned int rd_count; | ||
577 | 634 | ||
578 | (void) rs; | 635 | (void) rs; |
579 | if (NULL == dns) | 636 | if (NULL == dns) |
@@ -618,26 +675,68 @@ process_result (void *cls, | |||
618 | if (req->issue_num > MAX_RETRIES) | 675 | if (req->issue_num > MAX_RETRIES) |
619 | { | 676 | { |
620 | failures++; | 677 | failures++; |
621 | GNUNET_free (req->hostname); | 678 | insert_sorted (req); |
622 | GNUNET_free (req->raw); | ||
623 | GNUNET_free (req); | ||
624 | return; | 679 | return; |
625 | } | 680 | } |
626 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | 681 | insert_sorted (req); |
627 | req_tail, | ||
628 | req); | ||
629 | return; | 682 | return; |
630 | } | 683 | } |
684 | /* Free old/legacy records */ | ||
685 | while (NULL != (rec = req->rec_head)) | ||
686 | { | ||
687 | GNUNET_CONTAINER_DLL_remove (req->rec_head, | ||
688 | req->rec_tail, | ||
689 | rec); | ||
690 | GNUNET_free (rec); | ||
691 | } | ||
692 | /* import new records */ | ||
693 | req->issue_num = 0; /* success, reset counter! */ | ||
631 | req->p = p; | 694 | req->p = p; |
632 | for_all_records (p, | 695 | for_all_records (p, |
633 | &process_record, | 696 | &process_record, |
634 | req); | 697 | req); |
635 | req->p = NULL; | 698 | req->p = NULL; |
636 | // FIXME: update database! | ||
637 | GNUNET_DNSPARSER_free_packet (p); | 699 | GNUNET_DNSPARSER_free_packet (p); |
638 | GNUNET_free (req->hostname); | 700 | /* count records found, determine minimum expiration time */ |
639 | GNUNET_free (req->raw); | 701 | req->expires = GNUNET_TIME_UNIT_FOREVER_ABS; |
640 | GNUNET_free (req); | 702 | rd_count = 0; |
703 | for (rec = req->rec_head; NULL != rec; rec = rec->next) | ||
704 | { | ||
705 | struct GNUNET_TIME_Absolute at; | ||
706 | |||
707 | at.abs_value_us = rec->grd.expiration_time; | ||
708 | req->expires = GNUNET_TIME_absolute_min (req->expires, | ||
709 | at); | ||
710 | rd_count++; | ||
711 | } | ||
712 | /* Instead of going for SOA, simplified for now to look each | ||
713 | day in case we got an empty response */ | ||
714 | if (0 == rd_count) | ||
715 | req->expires | ||
716 | = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS); | ||
717 | /* convert records to namestore import format */ | ||
718 | { | ||
719 | struct GNUNET_GNSRECORD_Data rd[rd_count]; | ||
720 | unsigned int off; | ||
721 | |||
722 | /* convert linked list into array */ | ||
723 | for (rec = req->rec_head, off = 0; | ||
724 | NULL != rec; | ||
725 | rec =rec->next, off++) | ||
726 | rd[off] = rec->grd; | ||
727 | if (GNUNET_OK != | ||
728 | ns->store_records (ns->cls, | ||
729 | &zone, | ||
730 | req->label, | ||
731 | rd_count, | ||
732 | rd)) | ||
733 | { | ||
734 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
735 | "Failed to store zone data for `%s'\n", | ||
736 | req->hostname); | ||
737 | } | ||
738 | } | ||
739 | insert_sorted (req); | ||
641 | } | 740 | } |
642 | 741 | ||
643 | 742 | ||
@@ -715,6 +814,11 @@ static void | |||
715 | do_shutdown (void *cls) | 814 | do_shutdown (void *cls) |
716 | { | 815 | { |
717 | (void) cls; | 816 | (void) cls; |
817 | if (NULL != id) | ||
818 | { | ||
819 | GNUNET_IDENTITY_disconnect (id); | ||
820 | id = NULL; | ||
821 | } | ||
718 | if (NULL != t) | 822 | if (NULL != t) |
719 | { | 823 | { |
720 | GNUNET_SCHEDULER_cancel (t); | 824 | GNUNET_SCHEDULER_cancel (t); |
@@ -734,6 +838,43 @@ do_shutdown (void *cls) | |||
734 | 838 | ||
735 | 839 | ||
736 | /** | 840 | /** |
841 | * Function called for each matching record. | ||
842 | * | ||
843 | * @param cls `struct Request *` | ||
844 | * @param zone_key private key of the zone | ||
845 | * @param label name that is being mapped (at most 255 characters long) | ||
846 | * @param rd_count number of entries in @a rd array | ||
847 | * @param rd array of records with data to store | ||
848 | */ | ||
849 | static void | ||
850 | import_records (void *cls, | ||
851 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key, | ||
852 | const char *label, | ||
853 | unsigned int rd_count, | ||
854 | const struct GNUNET_GNSRECORD_Data *rd) | ||
855 | { | ||
856 | struct Request *req = cls; | ||
857 | |||
858 | GNUNET_break (0 == memcmp (private_key, | ||
859 | &zone, | ||
860 | sizeof (zone))); | ||
861 | GNUNET_break (0 == strcasecmp (label, | ||
862 | req->label)); | ||
863 | for (unsigned int i=0;i<rd_count;i++) | ||
864 | { | ||
865 | struct GNUNET_TIME_Absolute at; | ||
866 | |||
867 | at.abs_value_us = rd->expiration_time; | ||
868 | add_record (req, | ||
869 | rd->record_type, | ||
870 | at, | ||
871 | rd->data, | ||
872 | rd->data_size); | ||
873 | } | ||
874 | } | ||
875 | |||
876 | |||
877 | /** | ||
737 | * Add @a hostname to the list of requests to be made. | 878 | * Add @a hostname to the list of requests to be made. |
738 | * | 879 | * |
739 | * @param hostname name to resolve | 880 | * @param hostname name to resolve |
@@ -746,6 +887,7 @@ queue (const char *hostname) | |||
746 | struct Request *req; | 887 | struct Request *req; |
747 | char *raw; | 888 | char *raw; |
748 | size_t raw_size; | 889 | size_t raw_size; |
890 | const char *dot; | ||
749 | 891 | ||
750 | if (GNUNET_OK != | 892 | if (GNUNET_OK != |
751 | GNUNET_DNSPARSER_check_name (hostname)) | 893 | GNUNET_DNSPARSER_check_name (hostname)) |
@@ -755,6 +897,15 @@ queue (const char *hostname) | |||
755 | hostname); | 897 | hostname); |
756 | return; | 898 | return; |
757 | } | 899 | } |
900 | dot = strrchr (hostname, | ||
901 | (unsigned char) '.'); | ||
902 | if (NULL == dot) | ||
903 | { | ||
904 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
905 | "Refusing invalid hostname `%s' (lacks '.')\n", | ||
906 | hostname); | ||
907 | return; | ||
908 | } | ||
758 | q.name = (char *) hostname; | 909 | q.name = (char *) hostname; |
759 | q.type = GNUNET_DNSPARSER_TYPE_NS; | 910 | q.type = GNUNET_DNSPARSER_TYPE_NS; |
760 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; | 911 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; |
@@ -780,16 +931,128 @@ queue (const char *hostname) | |||
780 | } | 931 | } |
781 | 932 | ||
782 | req = GNUNET_new (struct Request); | 933 | req = GNUNET_new (struct Request); |
783 | req->hostname = strdup (hostname); | 934 | req->hostname = GNUNET_strdup (hostname); |
784 | req->raw = raw; | 935 | req->raw = raw; |
785 | req->raw_len = raw_size; | 936 | req->raw_len = raw_size; |
786 | req->id = p.id; | 937 | req->id = p.id; |
787 | /* FIXME: import data from namestore! */ | 938 | req->label = GNUNET_strndup (hostname, |
939 | dot - hostname); | ||
940 | if (NULL != strchr (req->label, | ||
941 | (unsigned char) '.')) | ||
942 | { | ||
943 | GNUNET_free (req->hostname); | ||
944 | GNUNET_free (req->label); | ||
945 | GNUNET_free (req); | ||
946 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
947 | "Label contained a `.', invalid hostname `%s'\n", | ||
948 | hostname); | ||
949 | return; | ||
950 | } | ||
951 | if (GNUNET_OK != | ||
952 | ns->lookup_records (ns->cls, | ||
953 | &zone, | ||
954 | req->label, | ||
955 | &import_records, | ||
956 | req)) | ||
957 | { | ||
958 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
959 | "Failed to load data from namestore for `%s'\n", | ||
960 | req->label); | ||
961 | } | ||
962 | insert_sorted (req); | ||
963 | } | ||
964 | |||
965 | |||
966 | /** | ||
967 | * Begin processing hostnames from stdin. | ||
968 | * | ||
969 | * @param cls NULL | ||
970 | */ | ||
971 | static void | ||
972 | process_stdin (void *cls) | ||
973 | { | ||
974 | char hn[256]; | ||
788 | 975 | ||
789 | /* FIXME: insert sorted by record expiration time */ | 976 | (void) cls; |
790 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | 977 | t = NULL; |
791 | req_tail, | 978 | GNUNET_IDENTITY_disconnect (id); |
792 | req); | 979 | id = NULL; |
980 | while (NULL != | ||
981 | fgets (hn, | ||
982 | sizeof (hn), | ||
983 | stdin)) | ||
984 | { | ||
985 | if (strlen(hn) > 0) | ||
986 | hn[strlen(hn)-1] = '\0'; /* eat newline */ | ||
987 | queue (hn); | ||
988 | } | ||
989 | t = GNUNET_SCHEDULER_add_now (&process_queue, | ||
990 | NULL); | ||
991 | } | ||
992 | |||
993 | |||
994 | /** | ||
995 | * Method called to inform about the egos of this peer. | ||
996 | * | ||
997 | * When used with #GNUNET_IDENTITY_connect, this function is | ||
998 | * initially called for all egos and then again whenever a | ||
999 | * ego's name changes or if it is deleted. At the end of | ||
1000 | * the initial pass over all egos, the function is once called | ||
1001 | * with 'NULL' for @a ego. That does NOT mean that the callback won't | ||
1002 | * be invoked in the future or that there was an error. | ||
1003 | * | ||
1004 | * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get, | ||
1005 | * this function is only called ONCE, and 'NULL' being passed in | ||
1006 | * @a ego does indicate an error (i.e. name is taken or no default | ||
1007 | * value is known). If @a ego is non-NULL and if '*ctx' | ||
1008 | * is set in those callbacks, the value WILL be passed to a subsequent | ||
1009 | * call to the identity callback of #GNUNET_IDENTITY_connect (if | ||
1010 | * that one was not NULL). | ||
1011 | * | ||
1012 | * When an identity is renamed, this function is called with the | ||
1013 | * (known) @a ego but the NEW @a name. | ||
1014 | * | ||
1015 | * When an identity is deleted, this function is called with the | ||
1016 | * (known) ego and "NULL" for the @a name. In this case, | ||
1017 | * the @a ego is henceforth invalid (and the @a ctx should also be | ||
1018 | * cleaned up). | ||
1019 | * | ||
1020 | * @param cls closure | ||
1021 | * @param ego ego handle | ||
1022 | * @param ctx context for application to store data for this ego | ||
1023 | * (during the lifetime of this process, initially NULL) | ||
1024 | * @param name name assigned by the user for this ego, | ||
1025 | * NULL if the user just deleted the ego and it | ||
1026 | * must thus no longer be used | ||
1027 | */ | ||
1028 | static void | ||
1029 | identity_cb (void *cls, | ||
1030 | struct GNUNET_IDENTITY_Ego *ego, | ||
1031 | void **ctx, | ||
1032 | const char *name) | ||
1033 | { | ||
1034 | (void) cls; | ||
1035 | (void) ctx; | ||
1036 | if (NULL == ego) | ||
1037 | { | ||
1038 | if (zone_found) | ||
1039 | t = GNUNET_SCHEDULER_add_now (&process_stdin, | ||
1040 | NULL); | ||
1041 | else | ||
1042 | { | ||
1043 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1044 | "Specified zone not found\n"); | ||
1045 | GNUNET_SCHEDULER_shutdown (); | ||
1046 | return; | ||
1047 | } | ||
1048 | } | ||
1049 | if ( (NULL != name) && | ||
1050 | (0 == strcasecmp (name, | ||
1051 | zone_name)) ) | ||
1052 | { | ||
1053 | zone_found = GNUNET_YES; | ||
1054 | zone = *GNUNET_IDENTITY_ego_get_private_key (ego); | ||
1055 | } | ||
793 | } | 1056 | } |
794 | 1057 | ||
795 | 1058 | ||
@@ -808,7 +1071,6 @@ run (void *cls, | |||
808 | const char *cfgfile, | 1071 | const char *cfgfile, |
809 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 1072 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
810 | { | 1073 | { |
811 | char hn[256]; | ||
812 | char *database; | 1074 | char *database; |
813 | 1075 | ||
814 | (void) cls; | 1076 | (void) cls; |
@@ -835,19 +1097,11 @@ run (void *cls, | |||
835 | ns = GNUNET_PLUGIN_load (db_lib_name, | 1097 | ns = GNUNET_PLUGIN_load (db_lib_name, |
836 | (void *) cfg); | 1098 | (void *) cfg); |
837 | GNUNET_free (database); | 1099 | GNUNET_free (database); |
838 | while (NULL != | 1100 | id = GNUNET_IDENTITY_connect (cfg, |
839 | fgets (hn, | 1101 | &identity_cb, |
840 | sizeof (hn), | 1102 | NULL); |
841 | stdin)) | ||
842 | { | ||
843 | if (strlen(hn) > 0) | ||
844 | hn[strlen(hn)-1] = '\0'; /* eat newline */ | ||
845 | queue (hn); | ||
846 | } | ||
847 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, | 1103 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, |
848 | NULL); | 1104 | NULL); |
849 | t = GNUNET_SCHEDULER_add_now (&process_queue, | ||
850 | NULL); | ||
851 | } | 1105 | } |
852 | 1106 | ||
853 | 1107 | ||
@@ -869,6 +1123,12 @@ main (int argc, | |||
869 | "IP", | 1123 | "IP", |
870 | "which DNS server should be used", | 1124 | "which DNS server should be used", |
871 | &dns_server)), | 1125 | &dns_server)), |
1126 | GNUNET_GETOPT_option_mandatory | ||
1127 | (GNUNET_GETOPT_option_string ('i', | ||
1128 | "identity", | ||
1129 | "ZONENAME", | ||
1130 | "which GNS zone should we import data into", | ||
1131 | &zone_name)), | ||
872 | GNUNET_GETOPT_OPTION_END | 1132 | GNUNET_GETOPT_OPTION_END |
873 | }; | 1133 | }; |
874 | 1134 | ||