2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
24 * - Write xquery and block plugin
25 * - The smaller FIXME issues all around
27 * @file gns/gnunet-service-gns.c
28 * @brief GNUnet GNS service
29 * @author Martin Schanzenbach
32 #include "gnunet_util_lib.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_dht_service.h"
37 #include "gnunet_namestore_service.h"
38 #include "gnunet_gns_service.h"
39 #include "block_gns.h"
42 #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
43 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44 #define DHT_GNS_REPLICATION_LEVEL 5
45 #define MAX_DNS_LABEL_LENGTH 63
47 /* Ignore for now not used anyway and probably never will */
48 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23
49 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24
52 * Handle to a currenty pending resolution
54 struct GNUNET_GNS_ResolverHandle
56 /* The name to resolve */
59 /* the request handle to reply to */
60 struct GNUNET_DNS_RequestHandle *request_handle;
62 /* the dns parser packet received */
63 struct GNUNET_DNSPARSER_Packet *packet;
65 /* the query parsed from the packet */
67 struct GNUNET_DNSPARSER_Query *query;
69 /* has this query been answered? how many matches */
72 /* the authoritative zone to query */
73 GNUNET_HashCode authority;
75 /* the name of the authoritative zone to query */
79 * we have an authority in namestore that
80 * may be able to resolve
84 /* a handle for dht lookups. should be NULL if no lookups are in progress */
85 struct GNUNET_DHT_GetHandle *get_handle;
87 /* timeout task for dht lookups */
88 GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
94 * Our handle to the DNS handler library
96 struct GNUNET_DNS_Handle *dns_handle;
99 * Our handle to the DHT
101 struct GNUNET_DHT_Handle *dht_handle;
104 * Our zone's private key
106 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
109 * Our handle to the namestore service
110 * FIXME maybe need a second handle for iteration
112 struct GNUNET_NAMESTORE_Handle *namestore_handle;
115 * Handle to iterate over our authoritative zone in namestore
117 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
120 * The configuration the GNS service is running with
122 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
125 * Our notification context.
127 static struct GNUNET_SERVER_NotificationContext *nc;
132 GNUNET_HashCode zone_hash;
135 * Our tld. Maybe get from config file
137 const char* gnunet_tld = ".gnunet";
140 * Useful for zone update for DHT put
142 static int num_public_records = 3600;
143 struct GNUNET_TIME_Relative dht_update_interval;
144 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
146 static void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
149 * Reply to client with the result from our lookup.
151 * @param rh the request handle of the lookup
152 * @param rd_count the number of records to return
153 * @param rd the record data
156 reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
157 const struct GNUNET_NAMESTORE_RecordData *rd)
163 struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
164 struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
165 struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
166 packet->answers = answer_records;
167 packet->additional_records = additional_records;
170 * Put records in the DNS packet and modify it
173 len = sizeof(struct GNUNET_DNSPARSER_Record*);
174 for (i=0; i < rd_count; i++)
177 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
178 "Adding type %d to DNS response\n", rd[i].record_type);
179 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
180 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name);
181 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
182 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
184 if (rd[i].record_type == rh->query->type)
186 answer_records[i].name = rh->query->name;
187 answer_records[i].type = rd[i].record_type;
188 answer_records[i].data.raw.data_len = rd[i].data_size;
189 answer_records[i].data.raw.data = (char*)rd[i].data;
190 answer_records[i].expiration_time = rd[i].expiration;
191 answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
195 additional_records[i].name = rh->query->name;
196 additional_records[i].type = rd[i].record_type;
197 additional_records[i].data.raw.data_len = rd[i].data_size;
198 additional_records[i].data.raw.data = (char*)rd[i].data;
199 additional_records[i].expiration_time = rd[i].expiration;
200 additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
204 packet->num_answers = rh->answered;
205 packet->num_additional_records = rd_count-(rh->answered);
207 if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
208 packet->flags.authoritative_answer = 1;
210 packet->flags.authoritative_answer = 0;
213 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
215 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
217 packet->flags.query_or_response = 1;
223 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
224 "Building DNS response\n");
225 ret = GNUNET_DNSPARSER_pack (packet,
226 1024, /* FIXME magic from dns redirector */
229 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
230 "Built DNS response! (ret=%d,len=%d)\n", ret, len);
231 if (ret == GNUNET_OK)
233 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
234 "Answering DNS request\n");
235 GNUNET_DNS_request_answer(rh->request_handle,
238 //GNUNET_free(answer);
239 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
243 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
244 "Error building DNS response! (ret=%d)", ret);
247 GNUNET_free(rh->name);
253 * Task run during shutdown.
259 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
261 /* Kill zone task for it may make the scheduler hang */
262 if (zone_update_taskid)
263 GNUNET_SCHEDULER_cancel(zone_update_taskid);
265 GNUNET_DNS_disconnect(dns_handle);
266 GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
267 GNUNET_DHT_disconnect(dht_handle);
271 * Callback when record data is put into namestore
273 * @param cls the closure
274 * @param success GNUNET_OK on success
275 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
278 on_namestore_record_put_result(void *cls,
282 if (GNUNET_NO == success)
284 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
287 else if (GNUNET_YES == success)
289 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
290 "records successfully put in namestore\n");
294 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
295 "Error putting records into namestore: %s\n", emsg);
299 * Handle timeout for DHT requests
301 * @param cls the request handle as closure
302 * @param tc the task context
305 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
307 struct GNUNET_GNS_ResolverHandle *rh = cls;
309 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
310 "dht lookup for query %s (type=%d) timed out.\n",
311 rh->name, rh->query->type);
313 GNUNET_DHT_get_stop (rh->get_handle);
314 reply_to_dns(rh, 0, NULL);
320 * Function called when we get a result from the dht
323 * @param cls the request handle
324 * @param exp lifetime
325 * @param key the key the record was stored under
326 * @param get_path get path
327 * @param get_path_length get path length
328 * @param put_path put path
329 * @param put_path_length put path length
330 * @param type the block type
331 * @param size the size of the record
332 * @param data the record data
335 process_record_dht_result(void* cls,
336 struct GNUNET_TIME_Absolute exp,
337 const GNUNET_HashCode * key,
338 const struct GNUNET_PeerIdentity *get_path,
339 unsigned int get_path_length,
340 const struct GNUNET_PeerIdentity *put_path,
341 unsigned int put_path_length,
342 enum GNUNET_BLOCK_Type type,
343 size_t size, const void *data)
345 struct GNUNET_GNS_ResolverHandle *rh;
346 struct GNSNameRecordBlock *nrb;
347 uint32_t num_records;
349 char* rd_data = (char*)data;
353 GNUNET_HashCode zone, name_hash;
354 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
359 //FIXME maybe check expiration here, check block type
361 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
362 nrb = (struct GNSNameRecordBlock*)data;
364 /* stop lookup and timeout task */
365 GNUNET_DHT_get_stop (rh->get_handle);
366 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
368 rh->get_handle = NULL;
369 name = (char*)&nrb[1];
370 num_records = ntohl(nrb->rd_count);
372 struct GNUNET_NAMESTORE_RecordData rd[num_records];
374 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
375 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
377 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
382 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
386 for (i=0; i<num_records; i++)
388 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
389 "Got name: %s (wanted %s)\n", name, rh->name);
390 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
391 "Got type: %d (wanted %d)\n",
392 rd[i].record_type, rh->query->type);
393 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
394 "Got data length: %d\n", rd[i].data_size);
395 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
396 "Got flag %d\n", rd[i].flags);
398 if ((strcmp(name, rh->name) == 0) &&
399 (rd[i].record_type == rh->query->type))
406 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
407 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
410 * FIXME check pubkey against existing key in namestore?
411 * https://gnunet.org/bugs/view.php?id=2179
414 /* Save to namestore */
415 GNUNET_NAMESTORE_record_put (namestore_handle,
422 &on_namestore_record_put_result, //cont
426 reply_to_dns(rh, num_records, rd);
428 reply_to_dns(rh, 0, NULL);
435 * Start DHT lookup for a (name -> query->record_type) record in
436 * query->authority's zone
438 * @param rh the pending gns query context
439 * @param name the name to query record
442 resolve_record_dht(struct GNUNET_GNS_ResolverHandle *rh)
445 GNUNET_HashCode name_hash;
446 GNUNET_HashCode lookup_key;
447 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
449 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
450 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
451 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
453 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
454 "starting dht lookup for %s with key: %s\n",
455 rh->name, (char*)&lookup_key_string);
457 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
458 &dht_lookup_timeout, rh);
460 xquery = htonl(rh->query->type);
461 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
462 DHT_OPERATION_TIMEOUT,
463 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
465 DHT_GNS_REPLICATION_LEVEL,
469 &process_record_dht_result,
476 * Namestore calls this function if we have record for this name.
477 * (or with rd_count=0 to indicate no matches)
479 * @param cls the pending query
480 * @param key the key of the zone we did the lookup
481 * @param expiration expiration date of the namestore entry
482 * @param name the name for which we need an authority
483 * @param rd_count the number of records with 'name'
484 * @param rd the record data
485 * @param signature the signature of the authority for the record data
488 process_record_lookup(void* cls,
489 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
490 struct GNUNET_TIME_Absolute expiration,
491 const char *name, unsigned int rd_count,
492 const struct GNUNET_NAMESTORE_RecordData *rd,
493 const struct GNUNET_CRYPTO_RsaSignature *signature)
495 struct GNUNET_GNS_ResolverHandle *rh;
496 struct GNUNET_TIME_Relative remaining_time;
497 GNUNET_HashCode zone;
499 rh = (struct GNUNET_GNS_ResolverHandle *) cls;
500 GNUNET_CRYPTO_hash(key,
501 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
503 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
508 * Lookup terminated and no results
509 * -> DHT Phase unless data is recent
511 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
512 "Namestore lookup for %s terminated without results\n", name);
515 * Not our root and no record found. Try dht if expired
517 if ((0 != GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) &&
518 (remaining_time.rel_value != 0))
520 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
521 "Record %s unknown in namestore, trying dht\n",
523 resolve_record_dht(rh);
528 * Our zone and no result? Cannot resolve TT
530 GNUNET_assert(rh->answered == 0);
531 reply_to_dns(rh, 0, NULL);
538 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
539 "Processing additional result %s from namestore\n", name);
541 for (i=0; i<rd_count;i++)
544 if (rd[i].record_type != rh->query->type)
547 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
550 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
561 if (rh->answered == 0)
563 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
564 "No answers found. This is odd!\n");
565 reply_to_dns(rh, 0, NULL);
569 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
572 reply_to_dns(rh, rd_count, rd);
578 * The final phase of resolution.
579 * This is a name that is canonical and we do not have a delegation.
581 * @param rh the pending lookup
584 resolve_record(struct GNUNET_GNS_ResolverHandle *rh)
588 * Try to resolve this record in our namestore.
589 * The name to resolve is now in rh->authority_name
590 * since we tried to resolve it to an authority
593 GNUNET_NAMESTORE_lookup_record(namestore_handle,
597 &process_record_lookup,
604 * Handle timeout for DHT requests
606 * @param cls the request handle as closure
607 * @param tc the task context
610 dht_authority_lookup_timeout(void *cls,
611 const struct GNUNET_SCHEDULER_TaskContext *tc)
613 struct GNUNET_GNS_ResolverHandle *rh = cls;
615 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
616 "dht lookup for query %s (type=%d) timed out.\n",
617 rh->name, rh->query->type);
619 if (strcmp(rh->name, "") == 0)
622 * promote authority back to name and try to resolve record
624 strcpy(rh->name, rh->authority_name);
629 GNUNET_DHT_get_stop (rh->get_handle);
630 reply_to_dns(rh, 0, NULL);
636 * Function called when we get a result from the dht
639 * @param cls the request handle
640 * @param exp lifetime
641 * @param key the key the record was stored under
642 * @param get_path get path
643 * @param get_path_length get path length
644 * @param put_path put path
645 * @param put_path_length put path length
646 * @param type the block type
647 * @param size the size of the record
648 * @param data the record data
651 process_authority_dht_result(void* cls,
652 struct GNUNET_TIME_Absolute exp,
653 const GNUNET_HashCode * key,
654 const struct GNUNET_PeerIdentity *get_path,
655 unsigned int get_path_length,
656 const struct GNUNET_PeerIdentity *put_path,
657 unsigned int put_path_length,
658 enum GNUNET_BLOCK_Type type,
659 size_t size, const void *data)
661 struct GNUNET_GNS_ResolverHandle *rh;
662 struct GNSNameRecordBlock *nrb;
663 uint32_t num_records;
665 char* rd_data = (char*) data;
668 GNUNET_HashCode zone, name_hash;
673 //FIXME check expiration?
675 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
676 nrb = (struct GNSNameRecordBlock*)data;
678 /* stop dht lookup and timeout task */
679 GNUNET_DHT_get_stop (rh->get_handle);
680 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
682 rh->get_handle = NULL;
683 num_records = ntohl(nrb->rd_count);
684 name = (char*)&nrb[1];
686 struct GNUNET_NAMESTORE_RecordData rd[num_records];
688 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
689 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
691 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
696 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
700 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
701 "Got name: %s (wanted %s)\n", name, rh->authority_name);
702 for (i=0; i<num_records; i++)
705 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
706 "Got name: %s (wanted %s)\n", name, rh->authority_name);
707 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
708 "Got type: %d (wanted %d)\n",
709 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
710 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
711 "Got data length: %d\n", rd[i].data_size);
712 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
713 "Got flag %d\n", rd[i].flags);
715 if ((strcmp(name, rh->authority_name) == 0) &&
716 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
718 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
721 (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *)rd[i].data,
729 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
730 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
732 /* Save to namestore */
733 if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
735 GNUNET_NAMESTORE_record_put (namestore_handle,
742 &on_namestore_record_put_result, //cont
751 if (strcmp(rh->name, "") == 0)
759 if (strcmp(rh->name, "") == 0)
761 /* promote authority back to name */
762 strcpy(rh->name, rh->authority_name);
766 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n");
767 reply_to_dns(rh, 0, NULL);
771 * Start DHT lookup for a name -> PKEY (compare NS) record in
772 * query->authority's zone
774 * @param rh the pending gns query
775 * @param name the name of the PKEY record
778 resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh)
781 GNUNET_HashCode name_hash;
782 GNUNET_HashCode lookup_key;
784 GNUNET_CRYPTO_hash(rh->authority_name,
785 strlen(rh->authority_name),
787 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
789 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
790 &dht_authority_lookup_timeout,
793 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
794 //FIXME how long to wait for results?
795 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
796 DHT_OPERATION_TIMEOUT,
797 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
799 DHT_GNS_REPLICATION_LEVEL,
803 &process_authority_dht_result,
809 * This is a callback function that should give us only PKEY
810 * records. Used to query the namestore for the authority (PKEY)
813 * @param cls the pending query
814 * @param key the key of the zone we did the lookup
815 * @param expiration expiration date of the record data set in the namestore
816 * @param name the name for which we need an authority
817 * @param rd_count the number of records with 'name'
818 * @param rd the record data
819 * @param signature the signature of the authority for the record data
822 process_authority_lookup(void* cls,
823 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
824 struct GNUNET_TIME_Absolute expiration,
826 unsigned int rd_count,
827 const struct GNUNET_NAMESTORE_RecordData *rd,
828 const struct GNUNET_CRYPTO_RsaSignature *signature)
830 struct GNUNET_GNS_ResolverHandle *rh;
831 struct GNUNET_TIME_Relative remaining_time;
832 GNUNET_HashCode zone;
834 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
837 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
838 GNUNET_CRYPTO_hash(key,
839 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
841 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
844 * No authority found in namestore.
849 * We did not find an authority in the namestore
850 * _IF_ the current authoritative zone is us we cannot resolve
851 * _ELSE_ we can still check the _expired_ dht
855 * No PKEY in our root. Try to resolve actual type in our zone
856 * if name is canonical. Else we cannot resolve.
858 if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
860 if (strcmp(rh->name, "") == 0)
863 * Promote this authority back to a name
865 strcpy(rh->name, rh->authority_name);
871 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
872 "Authority %s unknown in namestore, cannot resolve\n",
875 reply_to_dns(rh, 0, NULL);
880 * Not our root and no PKEY found. Try dht if expired
881 * FIXME only do when expired?
883 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "AAAA %d\n", remaining_time.rel_value);
884 if ((0 != GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)))
886 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
887 "Authority %s unknown in namestore, trying dht\n",
889 resolve_authority_dht(rh);
894 * Not our root and not expired or no records. Cannot resolve
896 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority %s unknown\n",
898 reply_to_dns(rh, 0, NULL);
902 //Note only 1 pkey should have been returned.. anything else would be strange
904 * We found an authority that may be able to help us
908 for (i=0; i<rd_count;i++)
911 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
914 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
917 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
918 if (remaining_time.rel_value == 0)
920 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
921 "This dht entry is expired. Refreshing\n");
922 resolve_authority_dht(rh);
930 * Resolve rest of query with new authority
932 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
933 GNUNET_CRYPTO_hash(rd[i].data,
934 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
936 if (strcmp(rh->name, "") == 0)
946 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
947 "Authority lookup successful but no PKEY... never get here\n");
948 reply_to_dns(rh, 0, NULL);
953 * Determine if this name is canonical.
955 * a.b.gnunet = not canonical
958 * @param name the name to test
959 * @return 1 if canonical
962 is_canonical(char* name)
964 uint32_t len = strlen(name);
967 for (i=0; i<len; i++)
969 if (*(name+i) == '.')
976 * Move one level up in the domain hierarchy and return the
977 * passed top level domain.
979 * @param name the domain
980 * @param dest the destination where the tld will be put
983 pop_tld(char* name, char* dest)
987 if (is_canonical(name))
994 for (len = strlen(name); len > 0; len--)
996 if (*(name+len) == '.')
1006 strcpy(dest, (name+len+1));
1011 * The first phase of resolution.
1012 * First check if the name is canonical.
1013 * If it is then try to resolve directly.
1014 * If not then we first have to resolve the authoritative entities.
1016 * @param rh the pending lookup
1019 resolve_name(struct GNUNET_GNS_ResolverHandle *rh)
1023 * Try to resolve this name to a delegation.
1025 pop_tld(rh->name, rh->authority_name);
1026 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1029 GNUNET_GNS_RECORD_PKEY,
1030 &process_authority_lookup,
1036 * Entry point for name resolution
1037 * Setup a new query and try to resolve
1039 * @param request the request handle of the DNS request from a client
1040 * @param p the DNS query packet we received
1041 * @param q the DNS query we received parsed from p
1044 start_resolution(struct GNUNET_DNS_RequestHandle *request,
1045 struct GNUNET_DNSPARSER_Packet *p,
1046 struct GNUNET_DNSPARSER_Query *q)
1048 struct GNUNET_GNS_ResolverHandle *rh;
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Starting resolution for %s (type=%d)!\n",
1054 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1057 rh->authority = zone_hash;
1059 rh->name = GNUNET_malloc(strlen(q->name)
1060 - strlen(gnunet_tld) + 1);
1062 strlen(q->name)-strlen(gnunet_tld) + 1);
1063 memcpy(rh->name, q->name,
1064 strlen(q->name)-strlen(gnunet_tld));
1066 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1068 rh->request_handle = request;
1070 /* Start resolution in our zone */
1075 * The DNS request handler
1076 * Called for every incoming DNS request.
1078 * @param cls closure
1079 * @param rh request handle to user for reply
1080 * @param request_length number of bytes in request
1081 * @param request udp payload of the DNS request
1084 handle_dns_request(void *cls,
1085 struct GNUNET_DNS_RequestHandle *rh,
1086 size_t request_length,
1087 const char *request)
1089 struct GNUNET_DNSPARSER_Packet *p;
1092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1093 p = GNUNET_DNSPARSER_parse (request, request_length);
1097 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1098 "Received malformed DNS packet, leaving it untouched\n");
1099 GNUNET_DNS_request_forward (rh);
1104 * Check tld and decide if we or
1105 * legacy dns is responsible
1107 * FIXME now in theory there could be more than 1 query in the request
1108 * but if this is case we get into trouble:
1109 * either we query the GNS or the DNS. We cannot do both!
1110 * So I suggest to either only allow a single query per request or
1111 * only allow GNS or DNS requests.
1112 * The way it is implemented here now is buggy and will lead to erratic
1113 * behaviour (if multiple queries are present).
1115 if (p->num_queries == 0)
1117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1118 "No Queries in DNS packet... forwarding\n");
1119 GNUNET_DNS_request_forward (rh);
1122 if (p->num_queries > 1)
1124 /* Note: We could also look for .gnunet */
1125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1126 ">1 queriy in DNS packet... odd. We only process #1\n");
1133 tldoffset = p->queries[0].name + strlen(p->queries[0].name);
1135 while ((*tldoffset) != '.')
1138 if (0 == strcmp(tldoffset, gnunet_tld))
1140 start_resolution(rh, p, p->queries);
1145 * This request does not concern us. Forward to real DNS.
1147 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1148 "Request for %s is forwarded to DNS\n", p->queries[0].name);
1149 GNUNET_DNS_request_forward (rh);
1155 * Method called periodicattluy that triggers
1156 * iteration over root zone
1158 * @param cls closure
1159 * @param tc task context
1162 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1164 GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1168 * Continuation for DHT put
1170 * @param cls closure
1171 * @param tc task context
1174 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1176 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1181 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1184 * Function used to put all records successively into the DHT.
1186 * @param cls the closure (NULL)
1187 * @param key the public key of the authority (ours)
1188 * @param expiration lifetime of the namestore entry
1189 * @param name the name of the records
1190 * @param rd_count the number of records in data
1191 * @param rd the record data
1192 * @param signature the signature for the record data
1195 put_gns_record(void *cls,
1196 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1197 struct GNUNET_TIME_Absolute expiration,
1199 unsigned int rd_count,
1200 const struct GNUNET_NAMESTORE_RecordData *rd,
1201 const struct GNUNET_CRYPTO_RsaSignature *signature)
1204 struct GNSNameRecordBlock *nrb;
1205 GNUNET_HashCode name_hash;
1206 GNUNET_HashCode xor_hash;
1207 struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1208 uint32_t rd_payload_length;
1209 char* nrb_data = NULL;
1214 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1215 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1216 zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1221 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1222 "Putting records for %s into the DHT\n", name);
1224 rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1226 nrb = GNUNET_malloc(rd_payload_length + strlen(name) + 1
1227 + sizeof(struct GNSNameRecordBlock));
1229 if (signature != NULL)
1230 nrb->signature = *signature;
1232 nrb->public_key = *key;
1234 nrb->rd_count = htonl(rd_count);
1236 memset(&nrb[1], 0, strlen(name) + 1);
1237 memcpy(&nrb[1], name, strlen(name));
1239 nrb_data = (char*)&nrb[1];
1240 nrb_data += strlen(name) + 1;
1242 rd_payload_length += sizeof(struct GNSNameRecordBlock) +
1245 if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
1250 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
1257 * calculate DHT key: H(name) xor H(pubkey)
1259 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1260 GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1261 GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1262 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1263 "putting records for %s under key: %s with size %d\n",
1264 name, (char*)&xor_hash_string, rd_payload_length);
1266 GNUNET_DHT_put (dht_handle, &xor_hash,
1267 DHT_GNS_REPLICATION_LEVEL,
1269 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1273 DHT_OPERATION_TIMEOUT,
1275 NULL); //cls for cont
1277 num_public_records++;
1280 * Reschedule periodic put
1282 zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1283 &update_zone_dht_next,
1289 * Periodically iterate over our zone and store everything in dht
1292 * @param tc task context
1295 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1297 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1298 if (0 == num_public_records)
1300 dht_update_interval = GNUNET_TIME_relative_multiply(
1301 GNUNET_TIME_UNIT_SECONDS,
1306 dht_update_interval = GNUNET_TIME_relative_multiply(
1307 GNUNET_TIME_UNIT_SECONDS,
1308 (3600/num_public_records));
1310 num_public_records = 0; //start counting again
1311 namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1313 GNUNET_NAMESTORE_RF_AUTHORITY,
1314 GNUNET_NAMESTORE_RF_PRIVATE,
1320 * Process GNS requests.
1322 * @param cls closure
1323 * @param server the initialized server
1324 * @param c configuration to use
1327 run (void *cls, struct GNUNET_SERVER_Handle *server,
1328 const struct GNUNET_CONFIGURATION_Handle *c)
1331 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
1334 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
1336 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
1337 "ZONEKEY", &keyfile))
1339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1340 "No private key for root zone specified%s!\n", keyfile);
1341 GNUNET_SCHEDULER_shutdown(0);
1345 zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1346 GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
1348 GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1351 nc = GNUNET_SERVER_notification_context_create (server, 1);
1353 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1357 GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1360 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1361 "DNS hijacking enabled... connecting to service.\n");
1363 * Do gnunet dns init here
1365 dns_handle = GNUNET_DNS_connect(c,
1366 GNUNET_DNS_FLAG_PRE_RESOLUTION,
1367 &handle_dns_request, /* rh */
1368 NULL); /* Closure */
1369 if (NULL == dns_handle)
1371 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1372 "Failed to connect to the dnsservice!\n");
1379 * handle to our local namestore
1381 namestore_handle = GNUNET_NAMESTORE_connect(c);
1383 if (NULL == namestore_handle)
1385 //FIXME do error handling;
1386 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1387 "Failed to connect to the namestore!\n");
1388 GNUNET_SCHEDULER_shutdown(0);
1395 dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1397 if (NULL == dht_handle)
1399 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1402 //put_some_records(); //FIXME for testing
1405 * Schedule periodic put
1407 * We have roughly an hour for all records;
1409 dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1411 //zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1417 * The main function for the GNS service.
1419 * @param argc number of arguments from the command line
1420 * @param argv command line arguments
1421 * @return 0 ok, 1 on error
1424 main (int argc, char *const *argv)
1430 GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1435 /* end of gnunet-service-gns.c */