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, 3)
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_LOOKUP 23
49 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
50 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
51 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
56 struct AuthorityChain *prev;
58 struct AuthorityChain *next;
62 /* (local) name of the authority */
65 /* was the ns entry fresh */
69 struct GNUNET_GNS_ResolverHandle;
71 typedef void (*ResolutionResultProcessor) (void *cls,
72 struct GNUNET_GNS_ResolverHandle *rh,
74 const struct GNUNET_NAMESTORE_RecordData *rd);
83 * Handle to a currenty pending resolution
85 struct GNUNET_GNS_ResolverHandle
87 /* The name to resolve */
92 /* has this query been answered? how many matches */
95 /* the authoritative zone to query */
96 GNUNET_HashCode authority;
98 /* the name of the authoritative zone to query */
102 * we have an authority in namestore that
103 * may be able to resolve
107 /* a handle for dht lookups. should be NULL if no lookups are in progress */
108 struct GNUNET_DHT_GetHandle *get_handle;
110 /* timeout task for dht lookups */
111 GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
113 ResolutionResultProcessor proc;
117 struct AuthorityChain *authority_chain_head;
118 struct AuthorityChain *authority_chain_tail;
120 enum ResolutionStatus status;
125 * Handle to a record lookup
127 struct RecordLookupHandle
129 /* the record type to look up */
130 enum GNUNET_GNS_RecordType record_type;
132 /* the name to look up */
135 /* Method to call on resolution result */
136 ResolutionResultProcessor proc;
138 /* closure to pass to proc */
143 struct ClientShortenHandle
145 struct GNUNET_SERVER_Client *client;
152 struct ClientLookupHandle
154 struct GNUNET_SERVER_Client *client;
157 char* name; //Needed?
160 struct InterceptLookupHandle
162 /* the request handle to reply to */
163 struct GNUNET_DNS_RequestHandle *request_handle;
165 /* the dns parser packet received */
166 struct GNUNET_DNSPARSER_Packet *packet;
168 /* the query parsed from the packet */
170 struct GNUNET_DNSPARSER_Query *query;
174 * Our handle to the DNS handler library
176 struct GNUNET_DNS_Handle *dns_handle;
179 * Our handle to the DHT
181 struct GNUNET_DHT_Handle *dht_handle;
184 * Our zone's private key
186 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
189 * Our handle to the namestore service
190 * FIXME maybe need a second handle for iteration
192 struct GNUNET_NAMESTORE_Handle *namestore_handle;
195 * Handle to iterate over our authoritative zone in namestore
197 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
200 * The configuration the GNS service is running with
202 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
205 * Our notification context.
207 static struct GNUNET_SERVER_NotificationContext *nc;
212 GNUNET_HashCode zone_hash;
215 * Our tld. Maybe get from config file
217 const char* gnunet_tld = ".gnunet";
220 * Useful for zone update for DHT put
222 static int num_public_records = 3600;
223 struct GNUNET_TIME_Relative dht_update_interval;
224 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
226 //static void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
229 * Reply to client with the result from our lookup.
231 * @param rh the request handle of the lookup
232 * @param rd_count the number of records to return
233 * @param rd the record data
236 reply_to_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
237 const struct GNUNET_NAMESTORE_RecordData *rd)
243 struct InterceptLookupHandle* ilh = (struct InterceptLookupHandle*)cls;
244 struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
245 struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
246 struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
247 packet->answers = answer_records;
248 packet->additional_records = additional_records;
251 * Put records in the DNS packet and modify it
254 len = sizeof(struct GNUNET_DNSPARSER_Record*);
255 for (i=0; i < rd_count; i++)
258 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
259 "Adding type %d to DNS response\n", rd[i].record_type);
260 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
261 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", ilh->query->name);
262 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
263 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
265 if (rd[i].record_type == ilh->query->type)
267 answer_records[i].name = ilh->query->name;
268 answer_records[i].type = rd[i].record_type;
269 answer_records[i].data.raw.data_len = rd[i].data_size;
270 answer_records[i].data.raw.data = (char*)rd[i].data;
271 answer_records[i].expiration_time = rd[i].expiration;
272 answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
276 additional_records[i].name = ilh->query->name;
277 additional_records[i].type = rd[i].record_type;
278 additional_records[i].data.raw.data_len = rd[i].data_size;
279 additional_records[i].data.raw.data = (char*)rd[i].data;
280 additional_records[i].expiration_time = rd[i].expiration;
281 additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
285 packet->num_answers = rh->answered;
286 packet->num_additional_records = rd_count-(rh->answered);
288 if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
289 packet->flags.authoritative_answer = 1;
291 packet->flags.authoritative_answer = 0;
294 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
296 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
298 packet->flags.query_or_response = 1;
304 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
305 "Building DNS response\n");
306 ret = GNUNET_DNSPARSER_pack (packet,
307 1024, /* FIXME magic from dns redirector */
310 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
311 "Built DNS response! (ret=%d,len=%d)\n", ret, len);
312 if (ret == GNUNET_OK)
314 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
315 "Answering DNS request\n");
316 GNUNET_DNS_request_answer(ilh->request_handle,
319 //GNUNET_free(answer);
320 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
324 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
325 "Error building DNS response! (ret=%d)", ret);
329 GNUNET_free(rh->name);
330 GNUNET_free(rh->proc_cls);
337 * Task run during shutdown.
343 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
345 /* Kill zone task for it may make the scheduler hang */
346 if (zone_update_taskid)
347 GNUNET_SCHEDULER_cancel(zone_update_taskid);
349 GNUNET_DNS_disconnect(dns_handle);
350 GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
351 GNUNET_DHT_disconnect(dht_handle);
355 * Callback when record data is put into namestore
357 * @param cls the closure
358 * @param success GNUNET_OK on success
359 * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
362 on_namestore_record_put_result(void *cls,
366 if (GNUNET_NO == success)
368 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
371 else if (GNUNET_YES == success)
373 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
374 "records successfully put in namestore\n");
378 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
379 "Error putting records into namestore: %s\n", emsg);
383 * Handle timeout for DHT requests
385 * @param cls the request handle as closure
386 * @param tc the task context
389 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
391 struct GNUNET_GNS_ResolverHandle *rh = cls;
393 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
394 "dht lookup for query %s timed out.\n",
397 GNUNET_DHT_get_stop (rh->get_handle);
398 rh->proc(rh->proc_cls, rh, 0, NULL);
404 * Function called when we get a result from the dht
407 * @param cls the request handle
408 * @param exp lifetime
409 * @param key the key the record was stored under
410 * @param get_path get path
411 * @param get_path_length get path length
412 * @param put_path put path
413 * @param put_path_length put path length
414 * @param type the block type
415 * @param size the size of the record
416 * @param data the record data
419 process_record_dht_result(void* cls,
420 struct GNUNET_TIME_Absolute exp,
421 const GNUNET_HashCode * key,
422 const struct GNUNET_PeerIdentity *get_path,
423 unsigned int get_path_length,
424 const struct GNUNET_PeerIdentity *put_path,
425 unsigned int put_path_length,
426 enum GNUNET_BLOCK_Type type,
427 size_t size, const void *data)
429 struct GNUNET_GNS_ResolverHandle *rh;
430 struct RecordLookupHandle *rlh;
431 struct GNSNameRecordBlock *nrb;
432 uint32_t num_records;
434 char* rd_data = (char*)data;
438 GNUNET_HashCode zone, name_hash;
439 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
444 //FIXME maybe check expiration here, check block type
446 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
447 rlh = (struct RecordLookupHandle *) rh->proc_cls;
448 nrb = (struct GNSNameRecordBlock*)data;
450 /* stop lookup and timeout task */
451 GNUNET_DHT_get_stop (rh->get_handle);
452 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
454 rh->get_handle = NULL;
455 name = (char*)&nrb[1];
456 num_records = ntohl(nrb->rd_count);
458 struct GNUNET_NAMESTORE_RecordData rd[num_records];
460 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
461 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
463 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
468 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
472 for (i=0; i<num_records; i++)
474 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
475 "Got name: %s (wanted %s)\n", name, rh->name);
476 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
479 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
480 "Got data length: %d\n", rd[i].data_size);
481 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
482 "Got flag %d\n", rd[i].flags);
484 if ((strcmp(name, rh->name) == 0) &&
485 (rd[i].record_type == rlh->record_type))
492 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
493 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
496 * FIXME check pubkey against existing key in namestore?
497 * https://gnunet.org/bugs/view.php?id=2179
500 /* Save to namestore */
501 GNUNET_NAMESTORE_record_put (namestore_handle,
508 &on_namestore_record_put_result, //cont
512 rh->proc(rh->proc_cls, rh, num_records, rd);
514 rh->proc(rh->proc_cls, rh, 0, NULL);
521 * Start DHT lookup for a (name -> query->record_type) record in
522 * rh->authority's zone
524 * @param rh the pending gns query context
525 * @param name the name to query record
528 resolve_record_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
531 GNUNET_HashCode name_hash;
532 GNUNET_HashCode lookup_key;
533 struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
534 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
536 GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
537 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
538 GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
540 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
541 "starting dht lookup for %s with key: %s\n",
542 rh->name, (char*)&lookup_key_string);
544 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
545 &dht_lookup_timeout, rh);
547 xquery = htonl(rlh->record_type);
548 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
549 DHT_OPERATION_TIMEOUT,
550 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
552 DHT_GNS_REPLICATION_LEVEL,
556 &process_record_dht_result,
563 * Namestore calls this function if we have record for this name.
564 * (or with rd_count=0 to indicate no matches)
566 * @param cls the pending query
567 * @param key the key of the zone we did the lookup
568 * @param expiration expiration date of the namestore entry
569 * @param name the name for which we need an authority
570 * @param rd_count the number of records with 'name'
571 * @param rd the record data
572 * @param signature the signature of the authority for the record data
575 process_record_lookup_ns(void* cls,
576 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
577 struct GNUNET_TIME_Absolute expiration,
578 const char *name, unsigned int rd_count,
579 const struct GNUNET_NAMESTORE_RecordData *rd,
580 const struct GNUNET_CRYPTO_RsaSignature *signature)
582 struct GNUNET_GNS_ResolverHandle *rh;
583 struct RecordLookupHandle *rlh;
584 struct GNUNET_TIME_Relative remaining_time;
585 GNUNET_HashCode zone;
587 rh = (struct GNUNET_GNS_ResolverHandle *) cls;
588 rlh = (struct RecordLookupHandle *)rh->proc_cls;
589 GNUNET_CRYPTO_hash(key,
590 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
592 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
598 rh->status |= EXISTS;
601 if (remaining_time.rel_value == 0)
603 rh->status |= EXPIRED;
609 * Lookup terminated and no results
611 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
612 "Namestore lookup for %s terminated without results\n", name);
616 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
617 "Record %s unknown in namestore\n",
620 * Our zone and no result? Cannot resolve TT
622 rh->proc(rh->proc_cls, rh, 0, NULL);
629 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
630 "Processing additional result %s from namestore\n", name);
632 for (i=0; i<rd_count;i++)
635 if (rd[i].record_type != rlh->record_type)
638 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
641 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
652 if (rh->answered == 0)
654 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
655 "No answers found. This is odd!\n");
656 rh->proc(rh->proc_cls, rh, 0, NULL);
660 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
663 rh->proc(rh->proc_cls, rh, rd_count, rd);
668 * The final phase of resolution.
669 * This is a name that is canonical and we do not have a delegation.
671 * @param rh the pending lookup
674 resolve_record_from_ns(struct GNUNET_GNS_ResolverHandle *rh)
676 struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
678 * Try to resolve this record in our namestore.
679 * The name to resolve is now in rh->authority_name
680 * since we tried to resolve it to an authority
683 GNUNET_NAMESTORE_lookup_record(namestore_handle,
687 &process_record_lookup_ns,
694 * Handle timeout for DHT requests
696 * @param cls the request handle as closure
697 * @param tc the task context
700 dht_authority_lookup_timeout(void *cls,
701 const struct GNUNET_SCHEDULER_TaskContext *tc)
703 struct GNUNET_GNS_ResolverHandle *rh = cls;
705 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
706 "dht lookup for query %s timed out.\n",
709 GNUNET_DHT_get_stop (rh->get_handle);
710 if (strcmp(rh->name, "") == 0)
713 * promote authority back to name and try to resolve record
715 strcpy(rh->name, rh->authority_name);
717 rh->proc(rh->proc_cls, rh, 0, NULL);
721 static void resolve_delegation_from_dht(struct GNUNET_GNS_ResolverHandle *rh);
724 * Function called when we get a result from the dht
725 * for our query. Recursively tries to resolve PKEYs
728 * @param cls the request handle
729 * @param exp lifetime
730 * @param key the key the record was stored under
731 * @param get_path get path
732 * @param get_path_length get path length
733 * @param put_path put path
734 * @param put_path_length put path length
735 * @param type the block type
736 * @param size the size of the record
737 * @param data the record data
740 process_authority_dht_result(void* cls,
741 struct GNUNET_TIME_Absolute exp,
742 const GNUNET_HashCode * key,
743 const struct GNUNET_PeerIdentity *get_path,
744 unsigned int get_path_length,
745 const struct GNUNET_PeerIdentity *put_path,
746 unsigned int put_path_length,
747 enum GNUNET_BLOCK_Type type,
748 size_t size, const void *data)
750 struct GNUNET_GNS_ResolverHandle *rh;
751 struct GNSNameRecordBlock *nrb;
752 uint32_t num_records;
754 char* rd_data = (char*) data;
757 GNUNET_HashCode zone, name_hash;
762 //FIXME check expiration?
764 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
765 nrb = (struct GNSNameRecordBlock*)data;
767 /* stop dht lookup and timeout task */
768 GNUNET_DHT_get_stop (rh->get_handle);
769 GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
771 rh->get_handle = NULL;
772 num_records = ntohl(nrb->rd_count);
773 name = (char*)&nrb[1];
775 struct GNUNET_NAMESTORE_RecordData rd[num_records];
777 rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
778 rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
780 if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
785 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
789 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
790 "Got name: %s (wanted %s)\n", name, rh->authority_name);
791 for (i=0; i<num_records; i++)
794 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
795 "Got name: %s (wanted %s)\n", name, rh->authority_name);
796 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
797 "Got type: %d (wanted %d)\n",
798 rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
799 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
800 "Got data length: %d\n", rd[i].data_size);
801 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
802 "Got flag %d\n", rd[i].flags);
804 if ((strcmp(name, rh->authority_name) == 0) &&
805 (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
807 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
809 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
810 struct AuthorityChain *auth =
811 GNUNET_malloc(sizeof(struct AuthorityChain));
812 auth->zone = rh->authority;
813 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
814 memset(auth->name, 0, strlen(rh->authority_name)+1);
815 strcpy(auth->name, rh->authority_name);
816 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
817 rh->authority_chain_tail,
824 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
825 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
827 /* Save to namestore */
828 if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
830 GNUNET_NAMESTORE_record_put (namestore_handle,
837 &on_namestore_record_put_result, //cont
846 if (strcmp(rh->name, "") == 0)
847 rh->proc(rh->proc_cls, rh, 0, NULL);
849 resolve_delegation_from_dht(rh);
854 * should never get here unless false dht key/put
855 * block plugin should handle this
858 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup error!\n");
864 * Process DHT lookup result for record.
866 * @param cls the closure
867 * @param rh resolver handle
868 * @param rd_count number of results (always 0)
869 * @param rd record data (always NULL)
872 process_record_result_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
873 unsigned int rd_count,
874 const struct GNUNET_NAMESTORE_RecordData *rd)
876 struct RecordLookupHandle* rlh;
877 rlh = (struct RecordLookupHandle*)cls;
880 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
881 "No records for %s found in DHT. Aborting\n",
883 /* give up, cannot resolve */
884 rlh->proc(rlh->proc_cls, rh, 0, NULL);
885 //reply_to_dns(NULL, rh, 0, NULL);
889 /* results found yay */
890 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
891 "Record resolved from namestore!");
892 rlh->proc(rlh->proc_cls, rh, rd_count, rd);
893 //reply_to_dns(NULL, rh, rd_count, rd);
899 * Process namestore lookup result for record.
901 * @param cls the closure
902 * @param rh resolver handle
903 * @param rd_count number of results (always 0)
904 * @param rd record data (always NULL)
907 process_record_result_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
908 unsigned int rd_count,
909 const struct GNUNET_NAMESTORE_RecordData *rd)
911 struct RecordLookupHandle* rlh;
912 rlh = (struct RecordLookupHandle*) cls;
915 /* ns entry expired. try dht */
916 if (rh->status & (EXPIRED | !EXISTS))
918 rh->proc = &process_record_result_dht;
919 resolve_record_from_dht(rh);
922 /* give up, cannot resolve */
923 rlh->proc(rlh->proc_cls, rh, 0, NULL);
924 //reply_to_dns(NULL, rh, 0, NULL);
928 /* results found yay */
929 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
930 "Record resolved from namestore!");
931 rlh->proc(rlh->proc_cls, rh, rd_count, rd);
932 //reply_to_dns(NULL, rh, rd_count, rd);
938 * Determine if this name is canonical.
940 * a.b.gnunet = not canonical
943 * @param name the name to test
944 * @return 1 if canonical
947 is_canonical(char* name)
949 uint32_t len = strlen(name);
952 for (i=0; i<len; i++)
954 if (*(name+i) == '.')
961 * Move one level up in the domain hierarchy and return the
962 * passed top level domain.
964 * @param name the domain
965 * @param dest the destination where the tld will be put
968 pop_tld(char* name, char* dest)
972 if (is_canonical(name))
979 for (len = strlen(name); len > 0; len--)
981 if (*(name+len) == '.')
991 strcpy(dest, (name+len+1));
995 * DHT resolution for delegation finished. Processing result.
997 * @param cls the closure
998 * @param rh resolver handle
999 * @param rd_count number of results (always 0)
1000 * @param rd record data (always NULL)
1003 process_dht_delegation_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1004 unsigned int rd_count,
1005 const struct GNUNET_NAMESTORE_RecordData *rd)
1007 struct RecordLookupHandle* rlh;
1008 rlh = (struct RecordLookupHandle*) cls;
1010 if (strcmp(rh->name, "") == 0)
1012 /* We resolved full name for delegation. resolving record */
1013 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1014 "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1015 rh->proc = &process_record_result_ns;
1016 resolve_record_from_ns(rh);
1021 * we still have some left
1023 if (is_canonical(rh->name))
1025 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1026 "Resolving canonical record %s in ns\n", rh->name);
1027 rh->proc = &process_record_result_ns;
1028 resolve_record_from_ns(rh);
1031 /* give up, cannot resolve */
1032 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1033 "Cannot fully resolve delegation for %s via DHT!\n",
1035 rlh->proc(rlh->proc_cls, rh, 0, NULL);
1036 //reply_to_dns(NULL, rh, 0, NULL);
1041 * Start DHT lookup for a name -> PKEY (compare NS) record in
1042 * rh->authority's zone
1044 * @param rh the pending gns query
1045 * @param name the name of the PKEY record
1048 resolve_delegation_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
1051 GNUNET_HashCode name_hash;
1052 GNUNET_HashCode lookup_key;
1054 GNUNET_CRYPTO_hash(rh->authority_name,
1055 strlen(rh->authority_name),
1057 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1059 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1060 &dht_authority_lookup_timeout,
1063 xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1065 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1066 DHT_OPERATION_TIMEOUT,
1067 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1069 DHT_GNS_REPLICATION_LEVEL,
1073 &process_authority_dht_result,
1080 * Namestore resolution for delegation finished. Processing result.
1082 * @param cls the closure
1083 * @param rh resolver handle
1084 * @param rd_count number of results (always 0)
1085 * @param rd record data (always NULL)
1088 process_ns_delegation_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1089 unsigned int rd_count,
1090 const struct GNUNET_NAMESTORE_RecordData *rd)
1092 struct RecordLookupHandle* rlh;
1093 rlh = (struct RecordLookupHandle*) cls;
1095 if (strcmp(rh->name, "") == 0)
1097 /* We resolved full name for delegation. resolving record */
1098 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1099 "Resolved full name for delegation. resolving record ''\n");
1100 rh->proc = &process_record_result_ns;
1101 resolve_record_from_ns(rh);
1106 * we still have some left
1107 * check if ns entry is fresh
1109 if (rh->status & (EXISTS | !EXPIRED))
1111 if (is_canonical(rh->name))
1113 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1114 "Resolving canonical record %s\n", rh->name);
1115 rh->proc = &process_record_result_ns;
1116 resolve_record_from_ns(rh);
1120 /* give up, cannot resolve */
1121 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1122 "Cannot fully resolve delegation for %s!\n",
1124 rlh->proc(rlh->proc_cls, rh, 0, NULL);
1125 //reply_to_dns(NULL, rh, 0, NULL);
1130 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1131 "Trying to resolve delegation for %s via DHT\n",
1133 rh->proc = &process_dht_delegation_dns;
1134 resolve_delegation_from_dht(rh);
1138 static void resolve_delegation_from_ns(struct GNUNET_GNS_ResolverHandle *rh);
1141 * This is a callback function that should give us only PKEY
1142 * records. Used to query the namestore for the authority (PKEY)
1143 * for 'name'. It will recursively try to resolve the
1144 * authority for a given name from the namestore.
1146 * @param cls the pending query
1147 * @param key the key of the zone we did the lookup
1148 * @param expiration expiration date of the record data set in the namestore
1149 * @param name the name for which we need an authority
1150 * @param rd_count the number of records with 'name'
1151 * @param rd the record data
1152 * @param signature the signature of the authority for the record data
1155 process_authority_lookup_ns(void* cls,
1156 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1157 struct GNUNET_TIME_Absolute expiration,
1159 unsigned int rd_count,
1160 const struct GNUNET_NAMESTORE_RecordData *rd,
1161 const struct GNUNET_CRYPTO_RsaSignature *signature)
1163 struct GNUNET_GNS_ResolverHandle *rh;
1164 struct GNUNET_TIME_Relative remaining_time;
1165 GNUNET_HashCode zone;
1168 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1171 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1172 GNUNET_CRYPTO_hash(key,
1173 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1175 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1181 rh->status |= EXISTS;
1184 if (remaining_time.rel_value == 0)
1186 rh->status |= EXPIRED;
1190 * No authority found in namestore.
1195 * We did not find an authority in the namestore
1200 * Promote this authority back to a name maybe it is
1203 if (strcmp(rh->name, "") == 0)
1205 /* simply promote back */
1206 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1207 "Promoting %s back to name\n", rh->authority_name);
1208 strcpy(rh->name, rh->authority_name);
1212 /* add back to existing name */
1213 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1214 "Adding %s back to %s\n",
1215 rh->authority_name, rh->name);
1216 new_name = GNUNET_malloc(strlen(rh->name)
1217 + strlen(rh->authority_name) + 2);
1218 memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1219 strcpy(new_name, rh->name);
1220 strcpy(new_name+strlen(new_name)+1, ".");
1221 strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1222 GNUNET_free(rh->name);
1223 rh->name = new_name;
1225 rh->proc(rh->proc_cls, rh, 0, NULL);
1229 //Note only 1 pkey should have been returned.. anything else would be strange
1231 * We found an authority that may be able to help us
1232 * move on with query
1235 for (i=0; i<rd_count;i++)
1238 if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1241 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1244 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1245 if (remaining_time.rel_value == 0)
1247 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1248 "This dht entry is expired.\n");
1249 rh->authority_chain_head->fresh = 0;
1250 rh->proc(rh->proc_cls, rh, 0, NULL);
1258 * Resolve rest of query with new authority
1260 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1261 memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1262 struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1263 auth->zone = rh->authority;
1264 auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1265 memset(auth->name, 0, strlen(rh->authority_name)+1);
1266 strcpy(auth->name, rh->authority_name);
1267 GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1268 rh->authority_chain_tail,
1272 * We are done with PKEY resolution if name is empty
1273 * else resolve again with new authority
1275 if (strcmp(rh->name, "") == 0)
1276 rh->proc(rh->proc_cls, rh, 0, NULL);
1278 resolve_delegation_from_ns(rh);
1285 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1286 "Authority lookup successful but no PKEY... never get here\n");
1287 rh->proc(rh->proc_cls, rh, 0, NULL);
1292 * Resolve the delegation chain for the request
1294 * @param rh the resolver handle
1297 resolve_delegation_from_ns(struct GNUNET_GNS_ResolverHandle *rh)
1300 pop_tld(rh->name, rh->authority_name);
1301 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1304 GNUNET_GNS_RECORD_PKEY,
1305 &process_authority_lookup_ns,
1311 * Entry point for name resolution
1312 * Setup a new query and try to resolve
1314 * @param request the request handle of the DNS request from a client
1315 * @param p the DNS query packet we received
1316 * @param q the DNS query we received parsed from p
1319 start_resolution_from_dns(struct GNUNET_DNS_RequestHandle *request,
1320 struct GNUNET_DNSPARSER_Packet *p,
1321 struct GNUNET_DNSPARSER_Query *q)
1323 struct GNUNET_GNS_ResolverHandle *rh;
1324 struct RecordLookupHandle* rlh;
1325 struct InterceptLookupHandle* ilh;
1327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1328 "Starting resolution for %s (type=%d)!\n",
1331 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1332 rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1333 ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle));
1336 ilh->request_handle = request;
1338 rh->authority = zone_hash;
1340 rlh->record_type = q->type;
1341 rlh->name = q->name;
1342 rlh->proc = &reply_to_dns;
1343 rlh->proc_cls = ilh;
1347 rh->authority = zone_hash;
1348 rh->name = GNUNET_malloc(strlen(q->name)
1349 - strlen(gnunet_tld) + 1);
1351 strlen(q->name)-strlen(gnunet_tld) + 1);
1352 memcpy(rh->name, q->name,
1353 strlen(q->name)-strlen(gnunet_tld));
1355 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1357 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1358 rh->authority_chain_tail = rh->authority_chain_head;
1359 rh->authority_chain_head->zone = zone_hash;
1361 /* Start resolution in our zone */
1362 rh->proc = &process_ns_delegation_dns;
1363 resolve_delegation_from_ns(rh);
1367 * The DNS request handler
1368 * Called for every incoming DNS request.
1370 * @param cls closure
1371 * @param rh request handle to user for reply
1372 * @param request_length number of bytes in request
1373 * @param request udp payload of the DNS request
1376 handle_dns_request(void *cls,
1377 struct GNUNET_DNS_RequestHandle *rh,
1378 size_t request_length,
1379 const char *request)
1381 struct GNUNET_DNSPARSER_Packet *p;
1384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1385 p = GNUNET_DNSPARSER_parse (request, request_length);
1389 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1390 "Received malformed DNS packet, leaving it untouched\n");
1391 GNUNET_DNS_request_forward (rh);
1396 * Check tld and decide if we or
1397 * legacy dns is responsible
1399 * FIXME now in theory there could be more than 1 query in the request
1400 * but if this is case we get into trouble:
1401 * either we query the GNS or the DNS. We cannot do both!
1402 * So I suggest to either only allow a single query per request or
1403 * only allow GNS or DNS requests.
1404 * The way it is implemented here now is buggy and will lead to erratic
1405 * behaviour (if multiple queries are present).
1407 if (p->num_queries == 0)
1409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1410 "No Queries in DNS packet... forwarding\n");
1411 GNUNET_DNS_request_forward (rh);
1414 if (p->num_queries > 1)
1416 /* Note: We could also look for .gnunet */
1417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1418 ">1 queriy in DNS packet... odd. We only process #1\n");
1425 tldoffset = p->queries[0].name + strlen(p->queries[0].name);
1427 while ((*tldoffset) != '.')
1430 if (0 == strcmp(tldoffset, gnunet_tld))
1432 start_resolution_from_dns(rh, p, p->queries);
1437 * This request does not concern us. Forward to real DNS.
1439 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1440 "Request for %s is forwarded to DNS\n", p->queries[0].name);
1441 GNUNET_DNS_request_forward (rh);
1447 * Method called periodicattluy that triggers
1448 * iteration over root zone
1450 * @param cls closure
1451 * @param tc task context
1454 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1456 GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1460 * Continuation for DHT put
1462 * @param cls closure
1463 * @param tc task context
1466 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1468 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1473 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1476 * Function used to put all records successively into the DHT.
1478 * @param cls the closure (NULL)
1479 * @param key the public key of the authority (ours)
1480 * @param expiration lifetime of the namestore entry
1481 * @param name the name of the records
1482 * @param rd_count the number of records in data
1483 * @param rd the record data
1484 * @param signature the signature for the record data
1487 put_gns_record(void *cls,
1488 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1489 struct GNUNET_TIME_Absolute expiration,
1491 unsigned int rd_count,
1492 const struct GNUNET_NAMESTORE_RecordData *rd,
1493 const struct GNUNET_CRYPTO_RsaSignature *signature)
1496 struct GNSNameRecordBlock *nrb;
1497 GNUNET_HashCode name_hash;
1498 GNUNET_HashCode xor_hash;
1499 struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1500 uint32_t rd_payload_length;
1501 char* nrb_data = NULL;
1506 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1507 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1508 zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1513 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1514 "Putting records for %s into the DHT\n", name);
1516 rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1518 nrb = GNUNET_malloc(rd_payload_length + strlen(name) + 1
1519 + sizeof(struct GNSNameRecordBlock));
1521 if (signature != NULL)
1522 nrb->signature = *signature;
1524 nrb->public_key = *key;
1526 nrb->rd_count = htonl(rd_count);
1528 memset(&nrb[1], 0, strlen(name) + 1);
1529 memcpy(&nrb[1], name, strlen(name));
1531 nrb_data = (char*)&nrb[1];
1532 nrb_data += strlen(name) + 1;
1534 rd_payload_length += sizeof(struct GNSNameRecordBlock) +
1537 if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
1542 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
1549 * calculate DHT key: H(name) xor H(pubkey)
1551 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1552 GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1553 GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1554 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1555 "putting records for %s under key: %s with size %d\n",
1556 name, (char*)&xor_hash_string, rd_payload_length);
1558 GNUNET_DHT_put (dht_handle, &xor_hash,
1559 DHT_GNS_REPLICATION_LEVEL,
1561 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1565 DHT_OPERATION_TIMEOUT,
1567 NULL); //cls for cont
1569 num_public_records++;
1572 * Reschedule periodic put
1574 zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1575 &update_zone_dht_next,
1581 * Periodically iterate over our zone and store everything in dht
1584 * @param tc task context
1587 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1589 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1590 if (0 == num_public_records)
1592 dht_update_interval = GNUNET_TIME_relative_multiply(
1593 GNUNET_TIME_UNIT_SECONDS,
1598 dht_update_interval = GNUNET_TIME_relative_multiply(
1599 GNUNET_TIME_UNIT_SECONDS,
1600 (3600/num_public_records));
1602 num_public_records = 0; //start counting again
1603 namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1605 GNUNET_NAMESTORE_RF_AUTHORITY,
1606 GNUNET_NAMESTORE_RF_PRIVATE,
1612 static void send_shorten_response(const char* name,
1613 struct ClientShortenHandle *csh);
1615 process_shorten_pseu_lookup_ns(void *cls,
1616 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1617 struct GNUNET_TIME_Absolute expire,
1619 unsigned int rd_len,
1620 const struct GNUNET_NAMESTORE_RecordData *rd,
1621 const struct GNUNET_CRYPTO_RsaSignature *signature)
1623 struct GNUNET_GNS_ResolverHandle *rh =
1624 (struct GNUNET_GNS_ResolverHandle *)cls;
1625 struct GNUNET_TIME_Relative remaining_time;
1632 rh->status |= EXISTS;
1635 if (remaining_time.rel_value == 0)
1637 rh->status |= EXPIRED;
1640 rh->proc(cls, rh, rd_len, rd);
1645 * Start DHT lookup for a PSEUdonym record in
1646 * rh->authority's zone
1648 * @param rh the pending gns query
1649 * @param name the name of the PKEY record
1652 resolve_pseu_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
1655 GNUNET_HashCode name_hash;
1656 GNUNET_HashCode lookup_key;
1659 GNUNET_CRYPTO_hash("",
1663 GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1665 rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1666 &dht_lookup_timeout,
1669 xquery = htonl(GNUNET_GNS_RECORD_PSEU);
1671 rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1672 DHT_OPERATION_TIMEOUT,
1673 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1675 DHT_GNS_REPLICATION_LEVEL,
1679 &process_authority_dht_result,
1686 handle_shorten_pseu_ns_result(void* cls,
1687 struct GNUNET_GNS_ResolverHandle *rh,
1689 const struct GNUNET_NAMESTORE_RecordData *rd);
1692 handle_shorten_zone_to_name(void *cls,
1693 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1694 struct GNUNET_TIME_Absolute expire,
1696 unsigned int rd_len,
1697 const struct GNUNET_NAMESTORE_RecordData *rd,
1698 const struct GNUNET_CRYPTO_RsaSignature *signature)
1700 struct GNUNET_GNS_ResolverHandle *rh =
1701 (struct GNUNET_GNS_ResolverHandle *)cls;
1702 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) rh->proc_cls;
1706 /* we found a match in our own zone */
1709 result = GNUNET_malloc(strlen(rh->name) + strlen(name) + 1);
1710 memset(result, 0, strlen(rh->name) + strlen(name) + 1);
1711 memcpy(result, rh->name, strlen(rh->name));
1712 memcpy(result+strlen(rh->name)+1, name, strlen(name));
1714 send_shorten_response(result, csh);
1716 GNUNET_free(result);
1721 * Nothing in our zone
1722 * check PSEU for this authority in namestore
1724 rh->proc = &handle_shorten_pseu_ns_result;
1725 GNUNET_NAMESTORE_lookup_record(namestore_handle,
1726 &rh->authority_chain_head->zone,
1728 GNUNET_GNS_RECORD_PSEU,
1729 &process_shorten_pseu_lookup_ns,
1735 * Process result from namestore delegation lookup
1736 * for shorten operation
1738 * @param cls the client shorten handle
1739 * @param rh the resolver handle
1740 * @param rd_count number of results (0)
1741 * @param rd data (NULL)
1744 handle_shorten_pseu_dht_result(void* cls,
1745 struct GNUNET_GNS_ResolverHandle *rh,
1747 const struct GNUNET_NAMESTORE_RecordData *rd)
1749 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1750 struct AuthorityChain *auth_chain;
1761 for (i=0; i < rd_len; i++)
1763 if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1767 pseu = (char*) rd[i].data;
1768 result = GNUNET_malloc(strlen(rh->name) + strlen(pseu) + 1);
1769 memset(result, 0, strlen(rh->name) + strlen(pseu) + 1);
1770 memcpy(result, rh->name, strlen(rh->name));
1771 memcpy(result+strlen(rh->name)+1, pseu, strlen(pseu));
1773 send_shorten_response(result, csh);
1775 GNUNET_free(result);
1781 * continue with next authority
1784 auth_chain = rh->authority_chain_head;
1786 if ((auth_chain->next->next == NULL) &&
1787 GNUNET_CRYPTO_hash_cmp(&auth_chain->next->zone, &zone_hash) == 0)
1792 result = GNUNET_malloc(strlen(rh->name) + strlen(auth_chain->name) + 2);
1793 memset(result, 0, strlen(rh->name) + strlen(auth_chain->name) + 2);
1794 strcpy(result, rh->name);
1795 strcpy(result+strlen(rh->name)+1, ".");
1796 strcpy(result+strlen(rh->name)+2, auth_chain->name);
1797 send_shorten_response(result, csh);
1803 * Continue with next authority
1805 new_name = GNUNET_malloc(strlen(rh->name)+
1806 strlen(auth_chain->name) + 2);
1807 memset(new_name, 0, strlen(rh->name)+
1808 strlen(auth_chain->name) + 2);
1809 strcpy(new_name, rh->name);
1810 strcpy(new_name+strlen(rh->name)+1, ".");
1811 strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
1812 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1813 rh->authority_chain_tail,
1815 GNUNET_free(auth_chain->name);
1816 GNUNET_free(auth_chain);
1817 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1819 &rh->authority_chain_head->zone,
1820 &handle_shorten_zone_to_name,
1828 * Process result from namestore PSEU lookup
1829 * for shorten operation
1830 * FIXME do we need to check for own zone here?
1832 * @param cls the client shorten handle
1833 * @param rh the resolver handle
1834 * @param rd_count number of results (0 if none found)
1835 * @param rd data (NULL if none found)
1838 handle_shorten_pseu_ns_result(void* cls,
1839 struct GNUNET_GNS_ResolverHandle *rh,
1841 const struct GNUNET_NAMESTORE_RecordData *rd)
1843 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1844 struct AuthorityChain *auth_chain;
1855 for (i=0; i < rd_len; i++)
1857 if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1861 pseu = (char*) rd[i].data;
1862 result = GNUNET_malloc(strlen(rh->name) + strlen(pseu) + 1);
1863 memset(result, 0, strlen(rh->name) + strlen(pseu) + 1);
1864 memcpy(result, rh->name, strlen(rh->name));
1865 memcpy(result+strlen(rh->name)+1, pseu, strlen(pseu));
1867 send_shorten_response(result, csh);
1869 GNUNET_free(result);
1874 * No PSEU found. Ask DHT if expired.
1875 * Else contunue with next authority
1877 if (rh->status & (EXISTS | !EXPIRED))
1882 auth_chain = rh->authority_chain_head;
1883 new_name = GNUNET_malloc(strlen(rh->name)+
1884 strlen(auth_chain->name) + 2);
1885 memset(new_name, 0, strlen(rh->name)+
1886 strlen(auth_chain->name) + 2);
1887 strcpy(new_name, rh->name);
1888 strcpy(new_name+strlen(rh->name)+1, ".");
1889 strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
1891 GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1892 rh->authority_chain_tail,
1895 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1897 &rh->authority_chain_head->zone,
1898 &handle_shorten_zone_to_name,
1906 rh->authority = rh->authority_chain_head->zone;
1907 rh->proc = &handle_shorten_pseu_dht_result;
1908 resolve_pseu_from_dht(rh);
1915 * Process result from namestore delegation lookup
1916 * for shorten operation
1918 * @param cls the client shorten handle
1919 * @param rh the resolver handle
1920 * @param rd_count number of results (0)
1921 * @param rd data (NULL)
1924 handle_shorten_delegation_result(void* cls,
1925 struct GNUNET_GNS_ResolverHandle *rh,
1927 const struct GNUNET_NAMESTORE_RecordData *rd)
1929 struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1930 struct AuthorityChain *auth_chain;
1933 * At this point rh->name contains the part of the name
1934 * that we do not have a PKEY in our namestore to resolve.
1935 * The authority chain in the resolver handle is now
1936 * useful to backtrack if needed
1939 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1940 "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1942 if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1946 * This is our zone append .gnunet unless name is empty
1947 * (it shouldn't be, usually FIXME what happens if we
1948 * shorten to our zone to a "" record??)
1950 send_shorten_response(rh->name, csh); //FIXME +.gnunet!
1954 csh->offset++; //FIXME needed?
1955 auth_chain = rh->authority_chain_head;
1956 /* backtrack authorities for pseu */
1957 GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1960 &handle_shorten_zone_to_name,
1965 typedef void (*ShortenResponseProc) (void* cls, const char* name);
1968 * Shorten a given name
1970 * @param name the name to shorten
1971 * @param proc the processor to call when finished
1972 * @praram cls the closure to the processor
1975 shorten_name(char* name, struct ClientShortenHandle* csh)
1978 struct GNUNET_GNS_ResolverHandle *rh;
1980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1981 "Starting resolution for %s (type=%d)!\n",
1982 name, GNUNET_GNS_RECORD_PKEY);
1984 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1985 rh->authority = zone_hash;
1987 rh->name = GNUNET_malloc(strlen(name)
1988 - strlen(gnunet_tld) + 1);
1990 strlen(name)-strlen(gnunet_tld) + 1);
1991 memcpy(rh->name, name,
1992 strlen(name)-strlen(gnunet_tld));
1994 csh->name = GNUNET_malloc(strlen(name)
1995 - strlen(gnunet_tld) + 1);
1997 strlen(name)-strlen(gnunet_tld) + 1);
1998 memcpy(rh->name, name,
1999 strlen(name)-strlen(gnunet_tld));
2001 rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
2003 rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2004 rh->authority_chain_tail = rh->authority_chain_head;
2005 rh->authority_chain_head->zone = zone_hash;
2006 rh->proc = &handle_shorten_delegation_result;
2007 rh->proc_cls = (void*)csh;
2009 /* Start delegation resolution in our namestore */
2010 resolve_delegation_from_ns(rh);
2015 * Send shorten response back to client
2016 * FIXME this is without .gnunet!
2018 * @param cls the client handle in closure
2019 * @param name the shortened name result or NULL if cannot be shortened
2022 send_shorten_response(const char* name, struct ClientShortenHandle *csh)
2024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n",
2026 struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
2033 rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage *)
2036 rmsg->unique_id = csh->unique_id;
2037 rmsg->key = csh->key;
2038 rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
2040 htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
2043 strcpy((char*)&rmsg[1], name);
2045 GNUNET_SERVER_notification_context_unicast (nc, csh->client,
2046 (const struct GNUNET_MessageHeader *) rmsg,
2049 GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
2052 //GNUNET_free(rmsg);
2057 * Handle a shorten message from the api
2059 * @param cls the closure
2060 * @param client the client
2061 * @param message the message
2063 static void handle_shorten(void *cls,
2064 struct GNUNET_SERVER_Client * client,
2065 const struct GNUNET_MessageHeader * message)
2067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
2069 size_t msg_size = 0;
2070 struct ClientShortenHandle *csh;
2072 if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
2074 GNUNET_break_op (0);
2075 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2079 GNUNET_SERVER_notification_context_add (nc, client);
2080 GNUNET_SERVER_client_keep (client);
2082 struct GNUNET_GNS_ClientShortenMessage *sh_msg =
2083 (struct GNUNET_GNS_ClientShortenMessage *) message;
2085 msg_size = ntohs(message->size);
2087 if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2089 GNUNET_break_op (0);
2090 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2094 csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
2095 csh->client = client;
2096 csh->unique_id = sh_msg->unique_id;
2097 csh->key = sh_msg->key;
2099 //Offset in original name
2103 shorten_name((char*)&sh_msg[1], csh);
2111 handle_lookup(void *cls,
2112 struct GNUNET_SERVER_Client * client,
2113 const struct GNUNET_MessageHeader * message)
2118 * Process GNS requests.
2120 * @param cls closure)
2121 * @param server the initialized server
2122 * @param c configuration to use
2125 run (void *cls, struct GNUNET_SERVER_Handle *server,
2126 const struct GNUNET_CONFIGURATION_Handle *c)
2129 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
2132 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
2134 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2135 {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
2136 {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0}
2139 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
2140 "ZONEKEY", &keyfile))
2142 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2143 "No private key for root zone specified%s!\n", keyfile);
2144 GNUNET_SCHEDULER_shutdown(0);
2148 zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2149 GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
2151 GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2156 GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
2159 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2160 "DNS hijacking enabled... connecting to service.\n");
2162 * Do gnunet dns init here
2164 dns_handle = GNUNET_DNS_connect(c,
2165 GNUNET_DNS_FLAG_PRE_RESOLUTION,
2166 &handle_dns_request, /* rh */
2167 NULL); /* Closure */
2168 if (NULL == dns_handle)
2170 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2171 "Failed to connect to the dnsservice!\n");
2178 * handle to our local namestore
2180 namestore_handle = GNUNET_NAMESTORE_connect(c);
2182 if (NULL == namestore_handle)
2184 //FIXME do error handling;
2185 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2186 "Failed to connect to the namestore!\n");
2187 GNUNET_SCHEDULER_shutdown(0);
2194 dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
2196 if (NULL == dht_handle)
2198 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
2201 //put_some_records(); //FIXME for testing
2204 * Schedule periodic put
2206 * We have roughly an hour for all records;
2208 dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
2210 //zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
2212 GNUNET_SERVER_add_handlers (server, handlers);
2215 //GNUNET_SERVER_disconnect_notify (server,
2216 // &client_disconnect_notification,
2219 nc = GNUNET_SERVER_notification_context_create (server, 1);
2221 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
2227 * The main function for the GNS service.
2229 * @param argc number of arguments from the command line
2230 * @param argv command line arguments
2231 * @return 0 ok, 1 on error
2234 main (int argc, char *const *argv)
2240 GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
2245 /* end of gnunet-service-gns.c */