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 * - Think about mixed dns queries (.gnunet and .org)
26 * - The smaller FIXME issues all around
28 * @file gns/gnunet-service-gns.c
29 * @brief GNUnet GNS service
30 * @author Martin Schanzenbach
33 #include "gnunet_util_lib.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_dns_service.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_namestore_service.h"
39 #include "gnunet_gns_service.h"
42 /* Ignore for now not used anyway and probably never will */
43 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23
44 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24
47 * A result list for namestore queries
49 struct GNUNET_GNS_ResolverHandle
53 /* the request handle to reply to */
54 struct GNUNET_DNS_RequestHandle *request_handle;
56 /* has this query been answered? how many matches */
59 /* the authoritative zone to query */
60 GNUNET_HashCode *authority;
63 * we have an authority in namestore that
64 * may be able to resolve
68 struct GNUNET_DNSPARSER_Packet *packet;
70 struct GNUNET_DNSPARSER_Query *query;
75 * Our handle to the DNS handler library
77 struct GNUNET_DNS_Handle *dns_handle;
80 * Our handle to the DHT
82 struct GNUNET_DHT_Handle *dht_handle;
85 * Our zone's private key
87 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
90 * Our handle to the namestore service
92 struct GNUNET_NAMESTORE_Handle *namestore_handle;
94 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
97 * The configuration the GNS service is running with
99 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
102 * Our notification context.
104 static struct GNUNET_SERVER_NotificationContext *nc;
109 GNUNET_HashCode zone_hash;
112 * Our tld. Maybe get from config file
114 const char* gnunet_tld = ".gnunet";
117 * Useful for zone update for DHT put
119 static int num_public_records = 3600;
120 struct GNUNET_TIME_Relative dht_update_interval;
123 void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, uint32_t rd_count,
124 const struct GNUNET_NAMESTORE_RecordData *rd);
125 void resolve_name(struct GNUNET_GNS_ResolverHandle *query,
126 GNUNET_HashCode *zone);
129 * Task run during shutdown.
135 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
137 GNUNET_DNS_disconnect(dns_handle);
138 GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
139 GNUNET_DHT_disconnect(dht_handle);
143 on_namestore_record_put_result(void *cls,
147 if (GNUNET_NO == success)
149 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
152 else if (GNUNET_YES == success)
154 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
155 "records successfully put in namestore\n");
159 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
160 "Error putting records into namestore: %s\n", emsg);
164 * Function called when we get a result from the dht
167 * @param cls the query handle
168 * @param exp lifetime
169 * @param key the key the record was stored under
170 * @param get_path get path
171 * @param get_path_length get path length
172 * @param put_path put path
173 * @param put_path_length put path length
174 * @param type the block type
175 * @param size the size of the record
176 * @param data the record data
179 process_authority_dht_result(void* cls,
180 struct GNUNET_TIME_Absolute exp,
181 const GNUNET_HashCode * key,
182 const struct GNUNET_PeerIdentity *get_path,
183 unsigned int get_path_length,
184 const struct GNUNET_PeerIdentity *put_path,
185 unsigned int put_path_length,
186 enum GNUNET_BLOCK_Type type,
187 size_t size, const void *data)
189 struct GNUNET_GNS_ResolverHandle *rh;
190 uint32_t num_records;
193 struct GNUNET_CRYPTO_RsaSignature *signature;
194 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
197 GNUNET_HashCode zone, name_hash;
202 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
205 num_records = ntohl(*pos);
206 struct GNUNET_NAMESTORE_RecordData rd[num_records];
208 pos += sizeof(uint32_t);
210 for (i=0; i<num_records; i++)
212 namelen = ntohs(*pos);
213 pos += sizeof(uint16_t);
215 //name must be 0 terminated
219 rd[i].record_type = ntohl(*pos);
220 pos += sizeof(uint32_t);
222 rd[i].data_size = ntohl(*pos);
223 pos += sizeof(uint32_t);
226 pos += rd[i].data_size;
228 rd[i].expiration = GNUNET_TIME_absolute_ntoh(
229 *((struct GNUNET_TIME_AbsoluteNBO*)pos));
230 pos += sizeof(struct GNUNET_TIME_AbsoluteNBO);
232 rd[i].flags = ntohs(*pos);
233 pos += sizeof(uint16_t);
235 if (strcmp(name, rh->query->name) && rd[i].record_type == rh->query->type)
242 if ((((char*)data)-pos) <
243 (sizeof(struct GNUNET_CRYPTO_RsaSignature) +
244 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
246 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
247 "Cannot parse signature/key in DHT response. Corrupted or Missing");
251 signature = (struct GNUNET_CRYPTO_RsaSignature*)pos;
252 pos += sizeof(struct GNUNET_CRYPTO_RsaSignature);
254 public_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded*)pos;
255 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
256 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
259 GNUNET_NAMESTORE_record_put (namestore_handle,
266 &on_namestore_record_put_result, //cont
272 memcpy(rh->authority, &zone, sizeof(GNUNET_HashCode));
273 resolve_name(rh, rh->authority);
276 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No authority in records\n");
277 reply_to_dns(rh, 0, NULL);
281 * Start DHT lookup for a name -> PKEY (compare NS) record in
282 * query->authority's zone
284 * @param query the pending gns query
285 * @param name the name of the PKEY record
288 resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
290 enum GNUNET_GNS_RecordType rtype = GNUNET_GNS_RECORD_PKEY;
291 struct GNUNET_TIME_Relative timeout;
292 GNUNET_HashCode name_hash;
293 GNUNET_HashCode lookup_key;
295 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
296 GNUNET_CRYPTO_hash_xor(&name_hash, rh->authority, &lookup_key);
298 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
300 //FIXME how long to wait for results?
301 GNUNET_DHT_get_start(dht_handle, timeout,
302 GNUNET_BLOCK_TYPE_TEST, //FIXME todo
304 5, //Replication level FIXME
306 &rtype, //xquery FIXME this is bad
307 sizeof(GNUNET_GNS_RECORD_PKEY),
308 &process_authority_dht_result,
314 * Function called when we get a result from the dht
317 * @param cls the query handle
318 * @param exp lifetime
319 * @param key the key the record was stored under
320 * @param get_path get path
321 * @param get_path_length get path length
322 * @param put_path put path
323 * @param put_path_length put path length
324 * @param type the block type
325 * @param size the size of the record
326 * @param data the record data
329 process_name_dht_result(void* cls,
330 struct GNUNET_TIME_Absolute exp,
331 const GNUNET_HashCode * key,
332 const struct GNUNET_PeerIdentity *get_path,
333 unsigned int get_path_length,
334 const struct GNUNET_PeerIdentity *put_path,
335 unsigned int put_path_length,
336 enum GNUNET_BLOCK_Type type,
337 size_t size, const void *data)
339 struct GNUNET_GNS_ResolverHandle *rh;
340 uint32_t num_records;
343 struct GNUNET_CRYPTO_RsaSignature *signature;
344 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
347 GNUNET_HashCode zone, name_hash;
352 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
355 num_records = ntohl(*pos);
356 struct GNUNET_NAMESTORE_RecordData rd[num_records];
358 pos += sizeof(uint32_t);
360 for (i=0; i<num_records; i++)
362 namelen = ntohs(*pos);
363 pos += sizeof(uint16_t);
365 //name must be 0 terminated
369 rd[i].record_type = ntohl(*pos);
370 pos += sizeof(uint32_t);
372 rd[i].data_size = ntohl(*pos);
373 pos += sizeof(uint32_t);
376 pos += rd[i].data_size;
378 rd[i].expiration = GNUNET_TIME_absolute_ntoh(
379 *((struct GNUNET_TIME_AbsoluteNBO*)pos));
380 pos += sizeof(struct GNUNET_TIME_AbsoluteNBO);
382 rd[i].flags = ntohs(*pos);
383 pos += sizeof(uint16_t);
386 if (strcmp(name, rh->query->name) && rd[i].record_type == rh->query->type)
393 if ((((char*)data)-pos) <
394 (sizeof(struct GNUNET_CRYPTO_RsaSignature) +
395 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
397 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
398 "Cannot parse signature/key in DHT response. Corrupted or Missing");
402 signature = (struct GNUNET_CRYPTO_RsaSignature*)pos;
403 pos += sizeof(struct GNUNET_CRYPTO_RsaSignature);
405 public_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded*)pos;
407 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
408 GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
411 GNUNET_NAMESTORE_record_put (namestore_handle,
418 &on_namestore_record_put_result, //cont
422 reply_to_dns(rh, num_records, rd);
425 * data is a serialized GNS record of type
426 * Check if record type and name match in query and reply
432 * Start DHT lookup for a (name -> query->record_type) record in
433 * query->authority's zone
435 * @param query the pending gns query
436 * @param name the name to query record
439 resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
441 struct GNUNET_TIME_Relative timeout;
442 GNUNET_HashCode name_hash;
443 GNUNET_HashCode lookup_key;
445 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
446 GNUNET_CRYPTO_hash_xor(&name_hash, rh->authority, &lookup_key);
448 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
450 //FIXME how long to wait for results?
451 GNUNET_DHT_get_start(dht_handle, timeout,
452 GNUNET_BLOCK_TYPE_TEST, //FIXME todo
454 5, //Replication level FIXME
456 &rh->query->type, //xquery
457 sizeof(rh->query->type),
458 &process_name_dht_result,
465 resolve_name(struct GNUNET_GNS_ResolverHandle *query, GNUNET_HashCode *zone);
468 * This is a callback function that should give us only PKEY
469 * records. Used to query the namestore for the authority (PKEY)
472 * @param cls the pending query
473 * @param zone our zone hash
474 * @param name the name for which we need an authority
475 * @param record_type the type of record (PKEY)
476 * @param expiration expiration date of the record
477 * @param flags namestore record flags
478 * @param sig_loc the location of the record in the signature tree
479 * @param size the size of the record
480 * @param data the record data
483 process_authority_lookup(void* cls,
484 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
485 struct GNUNET_TIME_Absolute expiration,
487 unsigned int rd_count,
488 const struct GNUNET_NAMESTORE_RecordData *rd,
489 const struct GNUNET_CRYPTO_RsaSignature *signature)
491 struct GNUNET_GNS_ResolverHandle *rh;
492 struct GNUNET_TIME_Relative remaining_time;
493 GNUNET_HashCode zone;
495 rh = (struct GNUNET_GNS_ResolverHandle *)cls;
496 GNUNET_CRYPTO_hash(key, GNUNET_CRYPTO_RSA_KEY_LENGTH, &zone);
497 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
500 * No authority found in namestore.
505 * We did not find an authority in the namestore
506 * _IF_ the current authoritative zone is us we cannot resolve
507 * _ELSE_ we can still check the _expired_ dht
509 if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) &&
510 (remaining_time.rel_value == 0))
512 resolve_authority_dht(rh, name);
515 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Authority unknown\n");
516 reply_to_dns(rh, 0, NULL);
520 //Note only 1 pkey should have been returned.. anything else would be strange
522 * We found an authority that may be able to help us
526 for (i=0; i<rd_count;i++)
529 if (strcmp(name, rh->query->name) && rd[i].record_type
530 != GNUNET_GNS_RECORD_PKEY)
533 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
536 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
537 if (remaining_time.rel_value == 0)
539 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
540 "This dht entry is expired. Refreshing\n");
541 resolve_authority_dht(rh, name);
547 GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
548 GNUNET_HashCode *pkey_hash = GNUNET_malloc(sizeof(GNUNET_HashCode));
549 GNUNET_CRYPTO_hash(rd[i].data, GNUNET_CRYPTO_RSA_KEY_LENGTH, pkey_hash);
550 GNUNET_free_non_null(rh->authority);
551 rh->authority = pkey_hash;
552 resolve_name(rh, rh->authority);
561 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
562 "Authority lookup successful but no PKEY... never get here?\n");
563 reply_to_dns(rh, 0, NULL);
568 * Reply to client with the result from our lookup.
570 * @param answer the pending query used in the lookup
573 reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
574 const struct GNUNET_NAMESTORE_RecordData *rd)
580 struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
581 struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
582 struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
583 packet->answers = answer_records;
584 packet->additional_records = additional_records;
586 len = sizeof(struct GNUNET_DNSPARSER_Record*);
587 for (i=0; i < rd_count; i++)
589 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
590 "Adding type %d to DNS response\n", rd[i].record_type);
591 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Name: %s\n", rh->name);
592 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "QName: %s\n", rh->query->name);
593 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record %d/%d\n", i+1, rd_count);
594 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record len %d\n", rd[i].data_size);
595 if (rd[i].record_type == rh->query->type)
597 answer_records[i].name = rh->query->name;
598 answer_records[i].type = rd[i].record_type;
599 answer_records[i].data.raw.data_len = rd[i].data_size;
600 answer_records[i].data.raw.data = (char*)rd[i].data;
601 answer_records[i].expiration_time = rd[i].expiration;
602 answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
606 additional_records[i].name = rh->query->name;
607 additional_records[i].type = rd[i].record_type;
608 additional_records[i].data.raw.data_len = rd[i].data_size;
609 additional_records[i].data.raw.data = (char*)rd[i].data;
610 additional_records[i].expiration_time = rd[i].expiration;
611 additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
613 //GNUNET_free(i->record); DO this later!
616 packet->num_answers = rh->answered; //answer->num_records;
617 packet->num_additional_records = rd_count-(rh->answered);
619 if (NULL == rh->authority)
620 packet->flags.authoritative_answer = 1;
622 packet->flags.authoritative_answer = 0;
625 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
627 packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
629 packet->flags.query_or_response = 1;
631 //FIXME this is silently discarded
632 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
633 "Building DNS response\n");
634 ret = GNUNET_DNSPARSER_pack (packet,
635 1024, /* FIXME magic from dns redirector */
638 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
639 "Built DNS response! (ret=%d,len=%d)\n", ret, len);
640 if (ret == GNUNET_OK)
642 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
643 "Answering DNS request\n");
644 GNUNET_DNS_request_answer(rh->request_handle,
647 //GNUNET_free(answer);
648 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Answered DNS request\n");
649 //FIXME return code, free datastructures
653 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
654 "Error building DNS response! (ret=%d)", ret);
657 //FIXME into free_resolver(rh)
658 //GNUNET_DNSPARSER_free_packet(rh->packet);
659 //GNUNET_free(rh->name);
665 * Namestore calls this function if we have an entry for this name.
666 * (or data=null to indicate the lookup has finished)
668 * @param cls the pending query
669 * @param zone the zone of the lookup
670 * @param name the name looked up
671 * @param record_type the record type
672 * @param expiration lifetime of the record
673 * @param flags record flags
674 * @param sig_loc location of the record in the signature tree
675 * @param size the size of the record
676 * @param data the record data
679 process_authoritative_result(void* cls,
680 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
681 struct GNUNET_TIME_Absolute expiration,
682 const char *name, unsigned int rd_count,
683 const struct GNUNET_NAMESTORE_RecordData *rd,
684 const struct GNUNET_CRYPTO_RsaSignature *signature)
686 struct GNUNET_GNS_ResolverHandle *rh;
687 struct GNUNET_TIME_Relative remaining_time;
688 GNUNET_HashCode zone;
690 rh = (struct GNUNET_GNS_ResolverHandle *) cls;
691 GNUNET_CRYPTO_hash(key, GNUNET_CRYPTO_RSA_KEY_LENGTH, &zone);
692 remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
694 //FIXME Handle results in rd
699 * Lookup terminated and no results
700 * -> DHT Phase unless data is recent
702 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
703 "Namestore lookup for %s terminated without results\n", name);
706 * if this is not our zone we cannot rely on the namestore to be
707 * complete. -> Query DHT
709 if (!GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash))
711 if (remaining_time.rel_value == 0)
713 resolve_name_dht(rh, name);
718 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
719 "Record is still recent. No DHT lookup\n");
724 * Our zone and no result? Cannot resolve TT
726 GNUNET_assert(rh->answered == 0);
727 reply_to_dns(rh, 0, NULL); //answered should be 0
734 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
735 "Processing additional result %s from namestore\n", name);
737 for (i=0; i<rd_count;i++)
740 if (strcmp(name, rh->query->name) && rd[i].record_type != rh->query->type)
743 if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
746 //FIXME there is a catch here...
747 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
757 * consult dht if expired
759 if ((remaining_time.rel_value == 0) && (rh->answered == 0))
761 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
762 "This dht entry is old. Refreshing.\n");
763 resolve_name_dht(rh, name);
767 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Found %d answer(s) to query!\n",
770 reply_to_dns(rh, rd_count, rd);
775 * Determine if this name is canonical.
777 * a.b.gnunet = not canonical
780 * @param name the name to test
781 * @return 1 if canonical
784 is_canonical(char* name)
786 uint32_t len = strlen(name);
789 for (i=0; i<len; i++)
791 if (*(name+i) == '.')
798 * Move one level up in the domain hierarchy and return the
799 * passed top level domain.
800 * FIXME this needs a better name
802 * @param name the domain
805 char* pop_tld(char* name)
809 if (is_canonical(name))
812 for (len = strlen(name); len > 0; len--)
814 if (*(name+len) == '.')
821 name[len] = '\0'; //terminate string
828 * The first phase of resolution.
829 * First check if the name is canonical.
830 * If it is then try to resolve directly.
831 * If not then first have to resolve the authoritative entities.
833 * @param query the pending lookup
834 * @param zone the zone we are currently resolving in
837 resolve_name(struct GNUNET_GNS_ResolverHandle *rh, GNUNET_HashCode *zone)
839 if (is_canonical(rh->name))
841 //We only need to check this zone's ns
842 GNUNET_NAMESTORE_lookup_record(namestore_handle,
846 &process_authoritative_result,
851 //We have to resolve the authoritative entity
852 char *new_authority = pop_tld(rh->name);
853 GNUNET_NAMESTORE_lookup_record(namestore_handle,
856 GNUNET_GNS_RECORD_PKEY,
857 &process_authority_lookup,
863 * Entry point for name resolution
864 * Lookup local namestore of our zone.
866 * Setup a new query and try to resolve
868 * @param rh the request handle of the DNS request from a client
869 * @param p the DNS query packet we received
870 * @param name the name to look up
871 * @param id the id of the dns request (for the reply)
872 * @param type the record type to look for
875 start_resolution(struct GNUNET_DNS_RequestHandle *request,
876 struct GNUNET_DNSPARSER_Packet *p,
877 struct GNUNET_DNSPARSER_Query *q)
879 struct GNUNET_GNS_ResolverHandle *rh;
881 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting resolution for (%s)!\n",
884 rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
887 rh->authority = NULL;
889 //FIXME do not forget to free!!
890 rh->name = GNUNET_malloc(strlen(q->name)
891 - strlen(gnunet_tld) + 1);
893 strlen(q->name)-strlen(gnunet_tld) + 1);
894 memcpy(rh->name, q->name,
895 strlen(q->name)-strlen(gnunet_tld));
897 rh->request_handle = request;
899 //Start resolution in our zone
900 resolve_name(rh, &zone_hash);
904 * The DNS request handler
905 * Called for every incoming DNS request.
908 * @param rh request handle to user for reply
909 * @param request_length number of bytes in request
910 * @param request udp payload of the DNS request
913 handle_dns_request(void *cls,
914 struct GNUNET_DNS_RequestHandle *rh,
915 size_t request_length,
918 struct GNUNET_DNSPARSER_Packet *p;
921 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Hijacked a DNS request...processing\n");
922 p = GNUNET_DNSPARSER_parse (request, request_length);
926 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
927 "Received malformed DNS packet, leaving it untouched\n");
928 GNUNET_DNS_request_forward (rh);
933 * Check tld and decide if we or
934 * legacy dns is responsible
936 * FIXME now in theory there could be more than 1 query in the request
937 * but if this is case we get into trouble:
938 * either we query the GNS or the DNS. We cannot do both!
939 * So I suggest to either only allow a single query per request or
940 * only allow GNS or DNS requests.
941 * The way it is implemented here now is buggy and will lead to erratic
942 * behaviour (if multiple queries are present).
944 if (p->num_queries == 0)
946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947 "No Queries in DNS packet... forwarding\n");
948 GNUNET_DNS_request_forward (rh);
951 if (p->num_queries > 1)
953 //Note: We could also look for .gnunet
954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
955 ">1 queriy in DNS packet... odd. We only process #1\n");
959 tldoffset = p->queries[0].name + strlen(p->queries[0].name);
961 while ((*tldoffset) != '.')
964 if (0 == strcmp(tldoffset, gnunet_tld))
966 start_resolution(rh, p, p->queries);
971 * This request does not concern us. Forward to real DNS.
973 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
974 "Request for %s is forwarded to DNS\n", p->queries[0].name);
975 GNUNET_DNS_request_forward (rh);
981 * test function that stores some data in the namestore
984 put_some_records(void)
986 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Populating namestore\n");
987 /* put a few records into namestore */
988 char* ipA = "1.2.3.4";
989 char* ipB = "5.6.7.8";
990 struct GNUNET_CRYPTO_RsaPrivateKey *bob_key = GNUNET_CRYPTO_rsa_key_create (); struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob;
991 bob = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
993 GNUNET_CRYPTO_rsa_key_get_public (bob_key, bob);
995 GNUNET_HashCode *bob_zone = GNUNET_malloc(sizeof(GNUNET_HashCode));
997 GNUNET_CRYPTO_hash(bob, GNUNET_CRYPTO_RSA_KEY_LENGTH, bob_zone);
999 struct in_addr *alice = GNUNET_malloc(sizeof(struct in_addr));
1000 struct in_addr *bob_web = GNUNET_malloc(sizeof(struct in_addr));
1001 struct GNUNET_NAMESTORE_RecordData rda;
1002 struct GNUNET_NAMESTORE_RecordData rdb;
1003 struct GNUNET_NAMESTORE_RecordData rdb_web;
1005 GNUNET_assert(1 == inet_pton (AF_INET, ipA, alice));
1006 GNUNET_assert(1 == inet_pton (AF_INET, ipB, bob_web));
1008 rda.data_size = sizeof(struct in_addr);
1009 rdb_web.data_size = sizeof(struct in_addr);
1010 rdb.data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded);
1013 rdb_web.data = bob_web;
1014 rda.record_type = GNUNET_GNS_RECORD_TYPE_A;
1015 rdb_web.record_type = GNUNET_GNS_RECORD_TYPE_A;
1016 rdb.record_type = GNUNET_GNS_RECORD_PKEY;
1017 rdb_web.expiration = GNUNET_TIME_absolute_get_forever ();
1018 rda.expiration = GNUNET_TIME_absolute_get_forever ();
1019 rdb.expiration = GNUNET_TIME_absolute_get_forever ();
1021 //alice.gnunet A IN 1.2.3.4
1022 GNUNET_NAMESTORE_record_create (namestore_handle,
1029 //www.bob.gnunet A IN 5.6.7.8
1030 GNUNET_NAMESTORE_record_create (namestore_handle,
1036 GNUNET_NAMESTORE_record_put(namestore_handle,
1039 GNUNET_TIME_absolute_get_forever (),
1048 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1050 GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1054 * Function used to put all records successively into the DHT.
1056 * @param cls the closure (NULL)
1057 * @param zone our root zone hash
1058 * @param name the name of the record
1059 * @param record_type the type of the record
1060 * @param expiration lifetime of the record
1061 * @param flags flags of the record
1062 * @param sig_loc location of record in signature tree
1063 * @param size size of the record
1064 * @param record_data the record data
1067 put_gns_record(void *cls,
1068 const const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1069 struct GNUNET_TIME_Absolute expiration,
1071 unsigned int rd_count,
1072 const struct GNUNET_NAMESTORE_RecordData *rd,
1073 const struct GNUNET_CRYPTO_RsaSignature *signature)
1075 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Putting records into the DHT\n");
1076 struct GNUNET_TIME_Relative timeout;
1077 GNUNET_HashCode name_hash;
1078 GNUNET_HashCode xor_hash;
1080 if (NULL == name) //We're done
1082 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1086 * FIXME magic number 20 move to config file
1088 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
1089 GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1090 GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1091 GNUNET_DHT_put (dht_handle, &xor_hash,
1092 5, //replication level
1094 GNUNET_BLOCK_TYPE_TEST, //FIXME todo block plugin
1099 NULL, //FIXME continuation needed? success check? yes ofc
1100 NULL); //cls for cont
1102 num_public_records++;
1105 * Reschedule periodic put
1107 GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1108 &update_zone_dht_next,
1114 * Periodically iterate over our zone and store everything in dht
1117 * @param tc task context
1120 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1122 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Update zone!\n");
1123 dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1124 (3600/num_public_records));
1125 num_public_records = 0; //start counting again
1126 namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1128 GNUNET_NAMESTORE_RF_AUTHORITY,
1129 GNUNET_NAMESTORE_RF_PRIVATE,
1135 * Process GNS requests.
1137 * @param cls closure
1138 * @param server the initialized server
1139 * @param c configuration to use
1142 run (void *cls, struct GNUNET_SERVER_Handle *server,
1143 const struct GNUNET_CONFIGURATION_Handle *c)
1146 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Init GNS\n");
1147 zone_key = GNUNET_CRYPTO_rsa_key_create ();
1149 GNUNET_CRYPTO_hash(zone_key, GNUNET_CRYPTO_RSA_KEY_LENGTH,//FIXME is this ok?
1151 nc = GNUNET_SERVER_notification_context_create (server, 1);
1153 /* FIXME - do some config parsing
1154 * - Maybe only hijack dns if option is set (HIJACK_DNS=1)
1157 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1160 * Do gnunet dns init here
1162 dns_handle = GNUNET_DNS_connect(c,
1163 GNUNET_DNS_FLAG_PRE_RESOLUTION,
1164 &handle_dns_request, /* rh */
1165 NULL); /* Closure */
1167 if (NULL == dns_handle)
1169 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1170 "Failed to connect to the dnsservice!\n");
1174 * handle to our local namestore
1176 namestore_handle = GNUNET_NAMESTORE_connect(c);
1178 if (NULL == namestore_handle)
1180 //FIXME do error handling;
1181 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1182 "Failed to connect to the namestore!\n");
1188 dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1190 if (NULL == dht_handle)
1192 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1195 put_some_records(); //FIXME for testing
1198 * Schedule periodic put
1200 * We have roughly an hour for all records;
1202 dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1203 60); //FIXME from cfg
1204 //GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1205 // &update_zone_dht_start,
1207 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "GNS Init done!\n");
1213 * The main function for the GNS service.
1215 * @param argc number of arguments from the command line
1216 * @param argv command line arguments
1217 * @return 0 ok, 1 on error
1220 main (int argc, char *const *argv)
1226 GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1231 /* end of gnunet-service-gns.c */