Igor/CG: various minor updates to man pages
[oweals/gnunet.git] / src / gns / gnunet-service-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  *
23  * TODO:
24  *    - Write xquery and block plugin
25  *    - Think about mixed dns queries (.gnunet and .org)
26  *    - The smaller FIXME issues all around
27  *
28  * @file gns/gnunet-service-gns.c
29  * @brief GNUnet GNS service
30  * @author Martin Schanzenbach
31  */
32 #include "platform.h"
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"
40 #include "gns.h"
41
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
45
46 /**
47  * A result list for namestore queries
48  */
49 struct GNUNET_GNS_ResolverHandle
50 {
51   char *name;
52
53   /* the request handle to reply to */
54   struct GNUNET_DNS_RequestHandle *request_handle;
55
56   /* has this query been answered? how many matches */
57   int answered;
58
59   /* the authoritative zone to query */
60   GNUNET_HashCode *authority;
61
62   /**
63    * we have an authority in namestore that
64    * may be able to resolve
65    */
66   int authority_found;
67
68   struct GNUNET_DNSPARSER_Packet *packet;
69
70   struct GNUNET_DNSPARSER_Query *query;
71 };
72
73
74 /**
75  * Our handle to the DNS handler library
76  */
77 struct GNUNET_DNS_Handle *dns_handle;
78
79 /**
80  * Our handle to the DHT
81  */
82 struct GNUNET_DHT_Handle *dht_handle;
83
84 /**
85  * Our zone's private key
86  */
87 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
88
89 /**
90  * Our handle to the namestore service
91  */
92 struct GNUNET_NAMESTORE_Handle *namestore_handle;
93
94 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
95
96 /**
97  * The configuration the GNS service is running with
98  */
99 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
100
101 /**
102  * Our notification context.
103  */
104 static struct GNUNET_SERVER_NotificationContext *nc;
105
106 /**
107  * Our zone hash
108  */
109 GNUNET_HashCode zone_hash;
110
111 /**
112  * Our tld. Maybe get from config file
113  */
114 const char* gnunet_tld = ".gnunet";
115
116 /**
117  * Useful for zone update for DHT put
118  */
119 static int num_public_records =  3600;
120 struct GNUNET_TIME_Relative dht_update_interval;
121
122
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);
127
128 /**
129  * Task run during shutdown.
130  *
131  * @param cls unused
132  * @param tc unused
133  */
134 static void
135 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
136 {
137   GNUNET_DNS_disconnect(dns_handle);
138   GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
139   GNUNET_DHT_disconnect(dht_handle);
140 }
141
142 void
143 on_namestore_record_put_result(void *cls,
144                                int32_t success,
145                                const char *emsg)
146 {
147   if (GNUNET_NO == success)
148   {
149     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
150     return;
151   }
152   else if (GNUNET_YES == success)
153   {
154     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
155                "records successfully put in namestore\n");
156     return;
157   }
158
159   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
160              "Error putting records into namestore: %s\n", emsg);
161 }
162
163 /**
164  * Function called when we get a result from the dht
165  * for our query
166  *
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
177  */
178 void
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)
188 {
189   struct GNUNET_GNS_ResolverHandle *rh;
190   uint32_t num_records;
191   uint16_t namelen;
192   char* name = NULL;
193   struct GNUNET_CRYPTO_RsaSignature *signature;
194   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
195   int i;
196   char* pos;
197   GNUNET_HashCode zone, name_hash;
198
199   if (data == NULL)
200     return;
201   
202   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
203   pos = (char*)data;
204   
205   num_records = ntohl(*pos);
206   struct GNUNET_NAMESTORE_RecordData rd[num_records];
207
208   pos += sizeof(uint32_t);
209   
210   for (i=0; i<num_records; i++)
211   {
212     namelen = ntohs(*pos);
213     pos += sizeof(uint16_t);
214     
215     //name must be 0 terminated
216     name = pos;
217     pos += namelen;
218   
219     rd[i].record_type = ntohl(*pos);
220     pos += sizeof(uint32_t);
221   
222     rd[i].data_size = ntohl(*pos);
223     pos += sizeof(uint32_t);
224   
225     rd[i].data = pos;
226     pos += rd[i].data_size;
227
228     rd[i].expiration = GNUNET_TIME_absolute_ntoh(
229                               *((struct GNUNET_TIME_AbsoluteNBO*)pos));
230     pos += sizeof(struct GNUNET_TIME_AbsoluteNBO);
231
232     rd[i].flags = ntohs(*pos);
233     pos += sizeof(uint16_t);
234     
235     if (strcmp(name, rh->query->name) && rd[i].record_type == rh->query->type)
236     {
237       rh->answered = 1;
238     }
239
240   }
241
242   if ((((char*)data)-pos) < 
243       (sizeof(struct GNUNET_CRYPTO_RsaSignature) +
244        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
245   {
246     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
247             "Cannot parse signature/key in DHT response. Corrupted or Missing");
248     return;
249   }
250
251   signature = (struct GNUNET_CRYPTO_RsaSignature*)pos;
252   pos += sizeof(struct GNUNET_CRYPTO_RsaSignature);
253   
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);
257
258   //Save to namestore
259   GNUNET_NAMESTORE_record_put (namestore_handle,
260                                public_key,
261                                name,
262                                exp,
263                                num_records,
264                                rd,
265                                signature,
266                                &on_namestore_record_put_result, //cont
267                                NULL); //cls
268   
269   if (rh->answered)
270   {
271     rh->answered = 0;
272     memcpy(rh->authority, &zone, sizeof(GNUNET_HashCode));
273     resolve_name(rh, rh->authority);
274     return;
275   }
276   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No authority in records\n");
277   reply_to_dns(rh, 0, NULL);
278 }
279
280 /**
281  * Start DHT lookup for a name -> PKEY (compare NS) record in
282  * query->authority's zone
283  *
284  * @param query the pending gns query
285  * @param name the name of the PKEY record
286  */
287 void
288 resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
289 {
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;
294
295   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
296   GNUNET_CRYPTO_hash_xor(&name_hash, rh->authority, &lookup_key);
297
298   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
299   
300   //FIXME how long to wait for results?
301   GNUNET_DHT_get_start(dht_handle, timeout,
302                        GNUNET_BLOCK_TYPE_TEST, //FIXME todo
303                        &lookup_key,
304                        5, //Replication level FIXME
305                        GNUNET_DHT_RO_NONE,
306                        &rtype, //xquery FIXME this is bad
307                        sizeof(GNUNET_GNS_RECORD_PKEY),
308                        &process_authority_dht_result,
309                        rh);
310
311 }
312
313 /**
314  * Function called when we get a result from the dht
315  * for our query
316  *
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
327  */
328 void
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)
338 {
339   struct GNUNET_GNS_ResolverHandle *rh;
340   uint32_t num_records;
341   uint16_t namelen;
342   char* name = NULL;
343   struct GNUNET_CRYPTO_RsaSignature *signature;
344   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
345   int i;
346   char* pos;
347   GNUNET_HashCode zone, name_hash;
348
349   if (data == NULL)
350     return;
351   
352   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
353   pos = (char*)data;
354   
355   num_records = ntohl(*pos);
356   struct GNUNET_NAMESTORE_RecordData rd[num_records];
357
358   pos += sizeof(uint32_t);
359   
360   for (i=0; i<num_records; i++)
361   {
362     namelen = ntohs(*pos);
363     pos += sizeof(uint16_t);
364     
365     //name must be 0 terminated
366     name = pos;
367     pos += namelen;
368   
369     rd[i].record_type = ntohl(*pos);
370     pos += sizeof(uint32_t);
371   
372     rd[i].data_size = ntohl(*pos);
373     pos += sizeof(uint32_t);
374   
375     rd[i].data = pos;
376     pos += rd[i].data_size;
377
378     rd[i].expiration = GNUNET_TIME_absolute_ntoh(
379                               *((struct GNUNET_TIME_AbsoluteNBO*)pos));
380     pos += sizeof(struct GNUNET_TIME_AbsoluteNBO);
381
382     rd[i].flags = ntohs(*pos);
383     pos += sizeof(uint16_t);
384     //FIXME class?
385     //
386     if (strcmp(name, rh->query->name) && rd[i].record_type == rh->query->type)
387     {
388       rh->answered++;
389     }
390
391   }
392
393   if ((((char*)data)-pos) < 
394       (sizeof(struct GNUNET_CRYPTO_RsaSignature) +
395        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
396   {
397     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
398             "Cannot parse signature/key in DHT response. Corrupted or Missing");
399     return;
400   }
401
402   signature = (struct GNUNET_CRYPTO_RsaSignature*)pos;
403   pos += sizeof(struct GNUNET_CRYPTO_RsaSignature);
404   
405   public_key = (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded*)pos;
406
407   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
408   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
409
410   //Save to namestore
411   GNUNET_NAMESTORE_record_put (namestore_handle,
412                                public_key,
413                                name,
414                                exp,
415                                num_records,
416                                rd,
417                                signature,
418                                &on_namestore_record_put_result, //cont
419                                NULL); //cls
420   
421   if (rh->answered)
422     reply_to_dns(rh, num_records, rd);
423
424   /**
425    * data is a serialized GNS record of type
426    * Check if record type and name match in query and reply
427    * to dns!
428    */
429 }
430
431 /**
432  * Start DHT lookup for a (name -> query->record_type) record in
433  * query->authority's zone
434  *
435  * @param query the pending gns query
436  * @param name the name to query record
437  */
438 void
439 resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
440 {
441   struct GNUNET_TIME_Relative timeout;
442   GNUNET_HashCode name_hash;
443   GNUNET_HashCode lookup_key;
444
445   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
446   GNUNET_CRYPTO_hash_xor(&name_hash, rh->authority, &lookup_key);
447
448   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
449   
450   //FIXME how long to wait for results?
451   GNUNET_DHT_get_start(dht_handle, timeout,
452                        GNUNET_BLOCK_TYPE_TEST, //FIXME todo
453                        &lookup_key,
454                        5, //Replication level FIXME
455                        GNUNET_DHT_RO_NONE,
456                        &rh->query->type, //xquery
457                        sizeof(rh->query->type),
458                        &process_name_dht_result,
459                        rh);
460
461 }
462
463 //Prototype
464 void
465 resolve_name(struct GNUNET_GNS_ResolverHandle *query, GNUNET_HashCode *zone);
466
467 /**
468  * This is a callback function that should give us only PKEY
469  * records. Used to query the namestore for the authority (PKEY)
470  * for 'name'
471  *
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
481  */
482 void
483 process_authority_lookup(void* cls,
484                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
485                    struct GNUNET_TIME_Absolute expiration,
486                    const char *name,
487                    unsigned int rd_count,
488                    const struct GNUNET_NAMESTORE_RecordData *rd,
489                    const struct GNUNET_CRYPTO_RsaSignature *signature)
490 {
491   struct GNUNET_GNS_ResolverHandle *rh;
492   struct GNUNET_TIME_Relative remaining_time;
493   GNUNET_HashCode zone;
494
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);
498   
499   /**
500    * No authority found in namestore.
501    */
502   if (rd_count == 0)
503   {
504     /**
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
508      */
509     if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) &&
510         (remaining_time.rel_value == 0))
511     {
512       resolve_authority_dht(rh, name);
513       return;
514     }
515     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Authority unknown\n");
516     reply_to_dns(rh, 0, NULL);
517     return;
518   }
519
520   //Note only 1 pkey should have been returned.. anything else would be strange
521   /**
522    * We found an authority that may be able to help us
523    * move on with query
524    */
525   int i;
526   for (i=0; i<rd_count;i++)
527   {
528   
529     if (strcmp(name, rh->query->name) && rd[i].record_type
530         != GNUNET_GNS_RECORD_PKEY)
531       continue;
532     
533       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
534           == 0)
535       {
536         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
537         if (remaining_time.rel_value == 0)
538         {
539           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
540                      "This dht entry is expired. Refreshing\n");
541           resolve_authority_dht(rh, name);
542         }
543
544         continue;
545       }
546
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);
553       return;
554       
555   }
556     
557   /**
558    * no answers found
559    */
560   
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);
564 }
565
566
567 /**
568  * Reply to client with the result from our lookup.
569  *
570  * @param answer the pending query used in the lookup
571  */
572 void
573 reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
574              const struct GNUNET_NAMESTORE_RecordData *rd)
575 {
576   int i;
577   size_t len;
578   int ret;
579   char *buf;
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;
585   
586   len = sizeof(struct GNUNET_DNSPARSER_Record*);
587   for (i=0; i < rd_count; i++)
588   {
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)
596     {
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
603     }
604     else
605     {
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
612     }
613     //GNUNET_free(i->record); DO this later!
614   }
615   
616   packet->num_answers = rh->answered; //answer->num_records;
617   packet->num_additional_records = rd_count-(rh->answered);
618   
619   if (NULL == rh->authority)
620     packet->flags.authoritative_answer = 1;
621   else
622    packet->flags.authoritative_answer = 0;
623
624   if (rd == NULL)
625     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
626   else
627     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
628   
629   packet->flags.query_or_response = 1;
630
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 */
636                                &buf,
637                                &len);
638   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
639              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
640   if (ret == GNUNET_OK)
641   {
642     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
643                "Answering DNS request\n");
644     GNUNET_DNS_request_answer(rh->request_handle,
645                               len,
646                               buf);
647     //GNUNET_free(answer);
648     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Answered DNS request\n");
649     //FIXME return code, free datastructures
650   }
651   else
652   {
653     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
654                "Error building DNS response! (ret=%d)", ret);
655   }
656
657   //FIXME into free_resolver(rh)
658   //GNUNET_DNSPARSER_free_packet(rh->packet);
659   //GNUNET_free(rh->name);
660   //GNUNET_free(rh);
661 }
662
663
664 /**
665  * Namestore calls this function if we have an entry for this name.
666  * (or data=null to indicate the lookup has finished)
667  *
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
677  */
678 static void
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)
685 {
686   struct GNUNET_GNS_ResolverHandle *rh;
687   struct GNUNET_TIME_Relative remaining_time;
688   GNUNET_HashCode zone;
689
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);
693
694   //FIXME Handle results in rd
695
696   if (rd_count == 0)
697   {
698     /**
699      * Lookup terminated and no results
700      * -> DHT Phase unless data is recent
701      */
702     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
703                "Namestore lookup for %s terminated without results\n", name);
704     
705     /**
706      * if this is not our zone we cannot rely on the namestore to be
707      * complete. -> Query DHT
708      */
709     if (!GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash))
710     {
711       if (remaining_time.rel_value == 0)
712       {
713         resolve_name_dht(rh, name);
714         return;
715       }
716       else
717       {
718         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
719                    "Record is still recent. No DHT lookup\n");
720       }
721     }
722
723     /**
724      * Our zone and no result? Cannot resolve TT
725      */
726     GNUNET_assert(rh->answered == 0);
727     reply_to_dns(rh, 0, NULL); //answered should be 0
728     return;
729
730   }
731   else
732   {
733     
734     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
735                "Processing additional result %s from namestore\n", name);
736     int i;
737     for (i=0; i<rd_count;i++)
738     {
739       
740       if (strcmp(name, rh->query->name) && rd[i].record_type != rh->query->type)
741         continue;
742       
743       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
744           == 0)
745       {
746         //FIXME there is a catch here...
747         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
748         continue;
749       }
750       
751       rh->answered++;
752       
753     }
754     
755     /**
756      * no answers found
757      * consult dht if expired
758      */
759     if ((remaining_time.rel_value == 0) && (rh->answered == 0))
760     {
761       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
762                  "This dht entry is old. Refreshing.\n");
763       resolve_name_dht(rh, name);
764       return;
765     }
766     
767     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Found %d answer(s) to query!\n",
768                rh->answered);
769
770     reply_to_dns(rh, rd_count, rd);
771   }
772 }
773
774 /**
775  * Determine if this name is canonical.
776  * i.e.
777  * a.b.gnunet  = not canonical
778  * a           = canonical
779  *
780  * @param name the name to test
781  * @return 1 if canonical
782  */
783 int
784 is_canonical(char* name)
785 {
786   uint32_t len = strlen(name);
787   int i;
788
789   for (i=0; i<len; i++)
790   {
791     if (*(name+i) == '.')
792       return 0;
793   }
794   return 1;
795 }
796
797 /**
798  * Move one level up in the domain hierarchy and return the
799  * passed top level domain.
800  * FIXME this needs a better name
801  *
802  * @param name the domain
803  * @return the tld
804  */
805 char* pop_tld(char* name)
806 {
807   uint32_t len;
808
809   if (is_canonical(name))
810     return NULL;
811
812   for (len = strlen(name); len > 0; len--)
813   {
814     if (*(name+len) == '.')
815       break;
816   }
817
818   if (len == 0)
819     return NULL; //Error
820
821   name[len] = '\0'; //terminate string
822
823   return (name+len+1);
824 }
825
826
827 /**
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.
832  *
833  * @param query the pending lookup
834  * @param zone the zone we are currently resolving in
835  */
836 void
837 resolve_name(struct GNUNET_GNS_ResolverHandle *rh, GNUNET_HashCode *zone)
838 {
839   if (is_canonical(rh->name))
840   {
841     //We only need to check this zone's ns
842     GNUNET_NAMESTORE_lookup_record(namestore_handle,
843                                zone,
844                                rh->name,
845                                rh->query->type,
846                                &process_authoritative_result,
847                                rh);
848   }
849   else
850   {
851     //We have to resolve the authoritative entity
852     char *new_authority = pop_tld(rh->name);
853     GNUNET_NAMESTORE_lookup_record(namestore_handle,
854                                  zone,
855                                  new_authority,
856                                  GNUNET_GNS_RECORD_PKEY,
857                                  &process_authority_lookup,
858                                  rh);
859   }
860 }
861
862 /**
863  * Entry point for name resolution
864  * Lookup local namestore of our zone.
865  *
866  * Setup a new query and try to resolve
867  *
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
873  */
874 void
875 start_resolution(struct GNUNET_DNS_RequestHandle *request,
876                  struct GNUNET_DNSPARSER_Packet *p,
877                  struct GNUNET_DNSPARSER_Query *q)
878 {
879   struct GNUNET_GNS_ResolverHandle *rh;
880   
881   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting resolution for (%s)!\n",
882               q->name);
883   
884   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
885   rh->packet = p;
886   rh->query = q;
887   rh->authority = NULL;
888   
889   //FIXME do not forget to free!!
890   rh->name = GNUNET_malloc(strlen(q->name)
891                               - strlen(gnunet_tld) + 1);
892   memset(rh->name, 0,
893          strlen(q->name)-strlen(gnunet_tld) + 1);
894   memcpy(rh->name, q->name,
895          strlen(q->name)-strlen(gnunet_tld));
896
897   rh->request_handle = request;
898
899   //Start resolution in our zone
900   resolve_name(rh, &zone_hash);
901 }
902
903 /**
904  * The DNS request handler
905  * Called for every incoming DNS request.
906  *
907  * @param cls closure
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
911  */
912 void
913 handle_dns_request(void *cls,
914                    struct GNUNET_DNS_RequestHandle *rh,
915                    size_t request_length,
916                    const char *request)
917 {
918   struct GNUNET_DNSPARSER_Packet *p;
919   char *tldoffset;
920
921   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Hijacked a DNS request...processing\n");
922   p = GNUNET_DNSPARSER_parse (request, request_length);
923   
924   if (NULL == p)
925   {
926     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
927                 "Received malformed DNS packet, leaving it untouched\n");
928     GNUNET_DNS_request_forward (rh);
929     return;
930   }
931   
932   /**
933    * Check tld and decide if we or
934    * legacy dns is responsible
935    *
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).
943    */
944   if (p->num_queries == 0)
945   {
946     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947                 "No Queries in DNS packet... forwarding\n");
948     GNUNET_DNS_request_forward (rh);
949   }
950
951   if (p->num_queries > 1)
952   {
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");
956   }
957
958
959   tldoffset = p->queries[0].name + strlen(p->queries[0].name);
960
961   while ((*tldoffset) != '.')
962     tldoffset--;
963   
964   if (0 == strcmp(tldoffset, gnunet_tld))
965   {
966     start_resolution(rh, p, p->queries);
967   }
968   else
969   {
970     /**
971      * This request does not concern us. Forward to real DNS.
972      */
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);
976   }
977
978 }
979
980 /**
981  * test function that stores some data in the namestore
982  */
983 void
984 put_some_records(void)
985 {
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));
992
993   GNUNET_CRYPTO_rsa_key_get_public (bob_key, bob);
994
995   GNUNET_HashCode *bob_zone = GNUNET_malloc(sizeof(GNUNET_HashCode));
996
997   GNUNET_CRYPTO_hash(bob, GNUNET_CRYPTO_RSA_KEY_LENGTH, bob_zone);
998
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;
1004
1005   GNUNET_assert(1 == inet_pton (AF_INET, ipA, alice));
1006   GNUNET_assert(1 == inet_pton (AF_INET, ipB, bob_web));
1007
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);
1011   rda.data = alice;
1012   rdb.data = bob;
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 ();
1020   
1021   //alice.gnunet A IN 1.2.3.4
1022   GNUNET_NAMESTORE_record_create (namestore_handle,
1023                                zone_key,
1024                                "alice",
1025                                &rda,
1026                                NULL,
1027                                NULL);
1028
1029   //www.bob.gnunet A IN 5.6.7.8
1030   GNUNET_NAMESTORE_record_create (namestore_handle,
1031                                zone_key,
1032                                "bob",
1033                                &rdb,
1034                                NULL,
1035                                NULL);
1036   GNUNET_NAMESTORE_record_put(namestore_handle,
1037                               bob,
1038                               "www",
1039                               GNUNET_TIME_absolute_get_forever (),
1040                               1,
1041                               &rdb_web,
1042                               NULL, //Signature
1043                               NULL, //Cont
1044                               NULL); //cls
1045 }
1046
1047 void
1048 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1049 {
1050   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1051 }
1052
1053 /**
1054  * Function used to put all records successively into the DHT.
1055  *
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
1065  */
1066 void
1067 put_gns_record(void *cls,
1068                 const const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1069                 struct GNUNET_TIME_Absolute expiration,
1070                 const char *name,
1071                 unsigned int rd_count,
1072                 const struct GNUNET_NAMESTORE_RecordData *rd,
1073                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1074 {
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;
1079
1080   if (NULL == name) //We're done
1081   {
1082     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1083     return;
1084   }
1085   /**
1086    * FIXME magic number 20 move to config file
1087    */
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
1093                   GNUNET_DHT_RO_NONE,
1094                   GNUNET_BLOCK_TYPE_TEST, //FIXME todo block plugin
1095                   rd->data_size,
1096                   rd->data,
1097                   expiration,
1098                   timeout,
1099                   NULL, //FIXME continuation needed? success check? yes ofc
1100                   NULL); //cls for cont
1101   
1102   num_public_records++;
1103
1104   /**
1105    * Reschedule periodic put
1106    */
1107   GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1108                                 &update_zone_dht_next,
1109                                 NULL);
1110
1111 }
1112
1113 /**
1114  * Periodically iterate over our zone and store everything in dht
1115  *
1116  * @param cls NULL
1117  * @param tc task context
1118  */
1119 static void
1120 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1121 {
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,
1127                                                           &zone_hash,
1128                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1129                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1130                                                           &put_gns_record,
1131                                                           NULL);
1132 }
1133
1134 /**
1135  * Process GNS requests.
1136  *
1137  * @param cls closure
1138  * @param server the initialized server
1139  * @param c configuration to use
1140  */
1141 static void
1142 run (void *cls, struct GNUNET_SERVER_Handle *server,
1143      const struct GNUNET_CONFIGURATION_Handle *c)
1144 {
1145   
1146   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Init GNS\n");
1147   zone_key = GNUNET_CRYPTO_rsa_key_create ();
1148
1149   GNUNET_CRYPTO_hash(zone_key, GNUNET_CRYPTO_RSA_KEY_LENGTH,//FIXME is this ok?
1150                      &zone_hash);
1151   nc = GNUNET_SERVER_notification_context_create (server, 1);
1152
1153   /* FIXME - do some config parsing 
1154    *       - Maybe only hijack dns if option is set (HIJACK_DNS=1)
1155    */
1156
1157   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1158                                 NULL);
1159   /**
1160    * Do gnunet dns init here
1161    */
1162   dns_handle = GNUNET_DNS_connect(c,
1163                                   GNUNET_DNS_FLAG_PRE_RESOLUTION,
1164                                   &handle_dns_request, /* rh */
1165                                   NULL); /* Closure */
1166
1167   if (NULL == dns_handle)
1168   {
1169     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1170                "Failed to connect to the dnsservice!\n");
1171   }
1172
1173   /**
1174    * handle to our local namestore
1175    */
1176   namestore_handle = GNUNET_NAMESTORE_connect(c);
1177
1178   if (NULL == namestore_handle)
1179   {
1180     //FIXME do error handling;
1181     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1182                "Failed to connect to the namestore!\n");
1183   }
1184
1185   /**
1186    * handle to the dht
1187    */
1188   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1189
1190   if (NULL == dht_handle)
1191   {
1192     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1193   }
1194
1195   put_some_records(); //FIXME for testing
1196   
1197   /**
1198    * Schedule periodic put
1199    * for our records
1200    * We have roughly an hour for all records;
1201    */
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,
1206   //                              NULL);
1207   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "GNS Init done!\n");
1208
1209 }
1210
1211
1212 /**
1213  * The main function for the GNS service.
1214  *
1215  * @param argc number of arguments from the command line
1216  * @param argv command line arguments
1217  * @return 0 ok, 1 on error
1218  */
1219 int
1220 main (int argc, char *const *argv)
1221 {
1222   int ret;
1223
1224   ret =
1225       (GNUNET_OK ==
1226        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1227                            NULL)) ? 0 : 1;
1228   return ret;
1229 }
1230
1231 /* end of gnunet-service-gns.c */