-some more config handling for tests
[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  *    - The smaller FIXME issues all around
26  *
27  * @file gns/gnunet-service-gns.c
28  * @brief GNUnet GNS service
29  * @author Martin Schanzenbach
30  */
31 #include "platform.h"
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"
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   /* The name to resolve */
52   char *name;
53
54   /* the request handle to reply to */
55   struct GNUNET_DNS_RequestHandle *request_handle;
56   
57   /* the dns parser packet received */
58   struct GNUNET_DNSPARSER_Packet *packet;
59   
60   /* the query parsed from the packet */
61
62   struct GNUNET_DNSPARSER_Query *query;
63   
64   /* has this query been answered? how many matches */
65   int answered;
66
67   /* the authoritative zone to query */
68   GNUNET_HashCode authority;
69
70   /**
71    * we have an authority in namestore that
72    * may be able to resolve
73    */
74   int authority_found;
75
76   /* a handle for dht lookups. should be NULL if no lookups are in progress */
77   struct GNUNET_DHT_GetHandle *get_handle;
78
79 };
80
81
82 /**
83  * Our handle to the DNS handler library
84  */
85 struct GNUNET_DNS_Handle *dns_handle;
86
87 /**
88  * Our handle to the DHT
89  */
90 struct GNUNET_DHT_Handle *dht_handle;
91
92 /**
93  * Our zone's private key
94  */
95 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
96
97 /**
98  * Our handle to the namestore service
99  * FIXME maybe need a second handle for iteration
100  */
101 struct GNUNET_NAMESTORE_Handle *namestore_handle;
102
103 /**
104  * Handle to iterate over our authoritative zone in namestore
105  */
106 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
107
108 /**
109  * The configuration the GNS service is running with
110  */
111 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
112
113 /**
114  * Our notification context.
115  */
116 static struct GNUNET_SERVER_NotificationContext *nc;
117
118 /**
119  * Our zone hash
120  */
121 GNUNET_HashCode zone_hash;
122
123 /**
124  * Our tld. Maybe get from config file
125  */
126 const char* gnunet_tld = ".gnunet";
127
128 /**
129  * Useful for zone update for DHT put
130  */
131 static int num_public_records =  3600;
132 struct GNUNET_TIME_Relative dht_update_interval;
133 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
134
135 //Prototypes
136 void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, uint32_t rd_count,
137                   const struct GNUNET_NAMESTORE_RecordData *rd);
138 void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
139
140 /**
141  * Task run during shutdown.
142  *
143  * @param cls unused
144  * @param tc unused
145  */
146 static void
147 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
148 {
149   //Kill zone task for it may make the scheduler hang
150   GNUNET_SCHEDULER_cancel(zone_update_taskid);
151   GNUNET_DNS_disconnect(dns_handle);
152   GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
153   GNUNET_DHT_disconnect(dht_handle);
154 }
155
156 /**
157  * Callback when record data is put into namestore
158  *
159  * @param cls the closure
160  * @param success GNUNET_OK on success
161  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
162  */
163 void
164 on_namestore_record_put_result(void *cls,
165                                int32_t success,
166                                const char *emsg)
167 {
168   if (GNUNET_NO == success)
169   {
170     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
171     return;
172   }
173   else if (GNUNET_YES == success)
174   {
175     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
176                "records successfully put in namestore\n");
177     return;
178   }
179
180   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
181              "Error putting records into namestore: %s\n", emsg);
182 }
183
184 /**
185  * Function called when we get a result from the dht
186  * for our query
187  *
188  * @param cls the request handle
189  * @param exp lifetime
190  * @param key the key the record was stored under
191  * @param get_path get path
192  * @param get_path_length get path length
193  * @param put_path put path
194  * @param put_path_length put path length
195  * @param type the block type
196  * @param size the size of the record
197  * @param data the record data
198  */
199 void
200 process_authority_dht_result(void* cls,
201                  struct GNUNET_TIME_Absolute exp,
202                  const GNUNET_HashCode * key,
203                  const struct GNUNET_PeerIdentity *get_path,
204                  unsigned int get_path_length,
205                  const struct GNUNET_PeerIdentity *put_path,
206                  unsigned int put_path_length,
207                  enum GNUNET_BLOCK_Type type,
208                  size_t size, const void *data)
209 {
210   struct GNUNET_GNS_ResolverHandle *rh;
211   struct GNSNameRecordBlock *nrb;
212   struct GNSRecordBlock *rb;
213   uint32_t num_records;
214   char* name = NULL;
215   int i;
216   GNUNET_HashCode zone, name_hash;
217   
218   if (data == NULL)
219     return;
220   
221   //FIXME check expiration?
222   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
223   nrb = (struct GNSNameRecordBlock*)data;
224   
225   GNUNET_DHT_get_stop (rh->get_handle);
226   rh->get_handle = NULL;
227   num_records = ntohl(nrb->rd_count);
228   struct GNUNET_NAMESTORE_RecordData rd[num_records];
229   name = (char*)&nrb[1];
230   rb = (struct GNSRecordBlock *)(&nrb[1] + strlen(name) + 1);
231
232   for (i=0; i<num_records; i++)
233   {
234   
235     rd[i].record_type = ntohl(rb->type);
236     rd[i].data_size = ntohl(rb->data_length);
237     rd[i].data = &rb[1];
238     rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration);
239     rd[i].flags = ntohs(rb->flags);
240     
241     if (strcmp(name, rh->query->name) &&
242         (rd[i].record_type == rh->query->type))
243     {
244       rh->answered = 1;
245     }
246
247   }
248
249   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
250   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
251
252   //Save to namestore
253   GNUNET_NAMESTORE_record_put (namestore_handle,
254                                &nrb->public_key,
255                                name,
256                                exp,
257                                num_records,
258                                rd,
259                                &nrb->signature,
260                                &on_namestore_record_put_result, //cont
261                                NULL); //cls
262   
263   if (rh->answered)
264   {
265     rh->answered = 0;
266     rh->authority = zone;
267     resolve_name(rh);
268     return;
269   }
270   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No authority in records\n");
271   reply_to_dns(rh, 0, NULL);
272 }
273
274 /**
275  * Start DHT lookup for a name -> PKEY (compare NS) record in
276  * query->authority's zone
277  *
278  * @param rh the pending gns query
279  * @param name the name of the PKEY record
280  */
281 void
282 resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
283 {
284   uint32_t xquery;
285   struct GNUNET_TIME_Relative timeout;
286   GNUNET_HashCode name_hash;
287   GNUNET_HashCode lookup_key;
288
289   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
290   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
291
292   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
293   
294   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
295   //FIXME how long to wait for results?
296   rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout,
297                        GNUNET_BLOCK_TYPE_TEST, //FIXME todo
298                        &lookup_key,
299                        5, //Replication level FIXME
300                        GNUNET_DHT_RO_NONE,
301                        &xquery, //xquery FIXME is this bad?
302                        sizeof(GNUNET_GNS_RECORD_PKEY),
303                        &process_authority_dht_result,
304                        rh);
305
306 }
307
308 /**
309  * Function called when we get a result from the dht
310  * for our query
311  *
312  * @param cls the request handle
313  * @param exp lifetime
314  * @param key the key the record was stored under
315  * @param get_path get path
316  * @param get_path_length get path length
317  * @param put_path put path
318  * @param put_path_length put path length
319  * @param type the block type
320  * @param size the size of the record
321  * @param data the record data
322  */
323 void
324 process_name_dht_result(void* cls,
325                  struct GNUNET_TIME_Absolute exp,
326                  const GNUNET_HashCode * key,
327                  const struct GNUNET_PeerIdentity *get_path,
328                  unsigned int get_path_length,
329                  const struct GNUNET_PeerIdentity *put_path,
330                  unsigned int put_path_length,
331                  enum GNUNET_BLOCK_Type type,
332                  size_t size, const void *data)
333 {
334   struct GNUNET_GNS_ResolverHandle *rh;
335   struct GNSNameRecordBlock *nrb;
336   struct GNSRecordBlock *rb;
337   uint32_t num_records;
338   char* name = NULL;
339   int i;
340   GNUNET_HashCode zone, name_hash;
341
342   if (data == NULL)
343     return;
344
345   //FIXME maybe check expiration here, check block type
346   
347   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
348   nrb = (struct GNSNameRecordBlock*)data;
349
350   GNUNET_DHT_get_stop (rh->get_handle);
351   rh->get_handle = NULL;
352   num_records = ntohl(nrb->rd_count);
353   struct GNUNET_NAMESTORE_RecordData rd[num_records];
354
355   name = (char*)&nrb[1];
356   rb = (struct GNSRecordBlock*)(&nrb[1] + strlen(name) + 1);
357   
358   for (i=0; i<num_records; i++)
359   {
360     rd[i].record_type = ntohl(rb->type);
361     rd[i].data_size = ntohl(rb->data_length);
362     rd[i].data = (char*)&rb[1];
363     rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration);
364     rd[i].flags = ntohs(rb->flags);
365     //FIXME class?
366     if (strcmp(name, rh->query->name) &&
367        (rd[i].record_type == rh->query->type))
368     {
369       rh->answered++;
370     }
371
372   }
373
374   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
375   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
376   
377   //FIXME check pubkey against existing key in namestore?
378   //https://gnunet.org/bugs/view.php?id=2179
379
380   //Save to namestore
381   GNUNET_NAMESTORE_record_put (namestore_handle,
382                                &nrb->public_key,
383                                name,
384                                exp,
385                                num_records,
386                                rd,
387                                &nrb->signature,
388                                &on_namestore_record_put_result, //cont
389                                NULL); //cls
390   
391   if (rh->answered)
392     reply_to_dns(rh, num_records, rd);
393   else
394     reply_to_dns(rh, 0, NULL);
395
396 }
397
398 /**
399  * Start DHT lookup for a (name -> query->record_type) record in
400  * query->authority's zone
401  *
402  * @param rh the pending gns query context
403  * @param name the name to query record
404  */
405 void
406 resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
407 {
408   uint32_t xquery;
409   struct GNUNET_TIME_Relative timeout;
410   GNUNET_HashCode name_hash;
411   GNUNET_HashCode lookup_key;
412
413   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
414   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
415   
416
417   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
418   
419   xquery = htonl(rh->query->type);
420   //FIXME how long to wait for results?
421   rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout,
422                        GNUNET_BLOCK_TYPE_TEST, //FIXME todo
423                        &lookup_key,
424                        5, //Replication level FIXME
425                        GNUNET_DHT_RO_NONE,
426                        &xquery, //xquery FIXME is this bad?
427                        sizeof(rh->query->type),
428                        &process_name_dht_result,
429                        rh);
430
431 }
432
433 //Prototype
434 void
435 resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
436
437 /**
438  * This is a callback function that should give us only PKEY
439  * records. Used to query the namestore for the authority (PKEY)
440  * for 'name'
441  *
442  * @param cls the pending query
443  * @param key the key of the zone we did the lookup
444  * @param expiration expiration date of the record data set in the namestore
445  * @param name the name for which we need an authority
446  * @param rd_count the number of records with 'name'
447  * @param rd the record data
448  * @param signature the signature of the authority for the record data
449  */
450 void
451 process_authority_lookup(void* cls,
452                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
453                    struct GNUNET_TIME_Absolute expiration,
454                    const char *name,
455                    unsigned int rd_count,
456                    const struct GNUNET_NAMESTORE_RecordData *rd,
457                    const struct GNUNET_CRYPTO_RsaSignature *signature)
458 {
459   struct GNUNET_GNS_ResolverHandle *rh;
460   struct GNUNET_TIME_Relative remaining_time;
461   GNUNET_HashCode zone;
462
463   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
464   GNUNET_CRYPTO_hash(key, GNUNET_CRYPTO_RSA_KEY_LENGTH, &zone);
465   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
466   
467   /**
468    * No authority found in namestore.
469    */
470   if (rd_count == 0)
471   {
472     /**
473      * We did not find an authority in the namestore
474      * _IF_ the current authoritative zone is us we cannot resolve
475      * _ELSE_ we can still check the _expired_ dht
476      */
477     if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) &&
478         (remaining_time.rel_value == 0))
479     {
480       resolve_authority_dht(rh, name);
481       return;
482     }
483     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Authority unknown\n");
484     reply_to_dns(rh, 0, NULL);
485     return;
486   }
487
488   //Note only 1 pkey should have been returned.. anything else would be strange
489   /**
490    * We found an authority that may be able to help us
491    * move on with query
492    */
493   int i;
494   for (i=0; i<rd_count;i++)
495   {
496   
497     if (strcmp(name, rh->query->name) && rd[i].record_type
498         != GNUNET_GNS_RECORD_PKEY)
499       continue;
500     
501       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
502           == 0)
503       {
504         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
505         if (remaining_time.rel_value == 0)
506         {
507           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
508                      "This dht entry is expired. Refreshing\n");
509           resolve_authority_dht(rh, name);
510         }
511
512         continue;
513       }
514
515       GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
516       GNUNET_CRYPTO_hash(rd[i].data, GNUNET_CRYPTO_RSA_KEY_LENGTH,
517                          &rh->authority);
518       resolve_name(rh);
519       return;
520       
521   }
522     
523   /**
524    * no answers found
525    */
526   
527   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
528              "Authority lookup successful but no PKEY... never get here?\n");
529   reply_to_dns(rh, 0, NULL);
530 }
531
532
533 /**
534  * Reply to client with the result from our lookup.
535  *
536  * @param rh the request handle of the lookup
537  * @param rd_count the number of records to return
538  * @param rd the record data
539  */
540 void
541 reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
542              const struct GNUNET_NAMESTORE_RecordData *rd)
543 {
544   int i;
545   size_t len;
546   int ret;
547   char *buf;
548   struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
549   struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
550   struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
551   packet->answers = answer_records;
552   packet->additional_records = additional_records;
553   
554   len = sizeof(struct GNUNET_DNSPARSER_Record*);
555   for (i=0; i < rd_count; i++)
556   {
557     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
558                "Adding type %d to DNS response\n", rd[i].record_type);
559     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Name: %s\n", rh->name);
560     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "QName: %s\n", rh->query->name);
561     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record %d/%d\n", i+1, rd_count);
562     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record len %d\n", rd[i].data_size);
563     if (rd[i].record_type == rh->query->type)
564     {
565       answer_records[i].name = rh->query->name;
566       answer_records[i].type = rd[i].record_type;
567       answer_records[i].data.raw.data_len = rd[i].data_size;
568       answer_records[i].data.raw.data = (char*)rd[i].data;
569       answer_records[i].expiration_time = rd[i].expiration;
570       answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
571     }
572     else
573     {
574       additional_records[i].name = rh->query->name;
575       additional_records[i].type = rd[i].record_type;
576       additional_records[i].data.raw.data_len = rd[i].data_size;
577       additional_records[i].data.raw.data = (char*)rd[i].data;
578       additional_records[i].expiration_time = rd[i].expiration;
579       additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
580     }
581     //GNUNET_free(i->record); DO this later!
582   }
583   
584   packet->num_answers = rh->answered; //answer->num_records;
585   packet->num_additional_records = rd_count-(rh->answered);
586   
587   if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
588     packet->flags.authoritative_answer = 1;
589   else
590    packet->flags.authoritative_answer = 0;
591
592   if (rd == NULL)
593     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
594   else
595     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
596   
597   packet->flags.query_or_response = 1;
598
599   //FIXME this is silently discarded
600   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
601              "Building DNS response\n");
602   ret = GNUNET_DNSPARSER_pack (packet,
603                                1024, /* FIXME magic from dns redirector */
604                                &buf,
605                                &len);
606   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
607              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
608   if (ret == GNUNET_OK)
609   {
610     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
611                "Answering DNS request\n");
612     GNUNET_DNS_request_answer(rh->request_handle,
613                               len,
614                               buf);
615     //GNUNET_free(answer);
616     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Answered DNS request\n");
617     //FIXME return code, free datastructures
618   }
619   else
620   {
621     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
622                "Error building DNS response! (ret=%d)", ret);
623   }
624
625   //FIXME into free_resolver(rh)
626   GNUNET_free(rh->name);
627   GNUNET_free(rh);
628 }
629
630
631 /**
632  * Namestore calls this function if we have an entry for this name.
633  * (or data=null to indicate the lookup has finished
634  *
635  * @param cls the pending query
636  * @param key the key of the zone we did the lookup
637  * @param expiration expiration date of the namestore entry
638  * @param name the name for which we need an authority
639  * @param rd_count the number of records with 'name'
640  * @param rd the record data
641  * @param signature the signature of the authority for the record data
642  */
643 static void
644 process_authoritative_result(void* cls,
645                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
646                   struct GNUNET_TIME_Absolute expiration,
647                   const char *name, unsigned int rd_count,
648                   const struct GNUNET_NAMESTORE_RecordData *rd,
649                   const struct GNUNET_CRYPTO_RsaSignature *signature)
650 {
651   struct GNUNET_GNS_ResolverHandle *rh;
652   struct GNUNET_TIME_Relative remaining_time;
653   GNUNET_HashCode zone;
654
655   rh = (struct GNUNET_GNS_ResolverHandle *) cls;
656   GNUNET_CRYPTO_hash(key, GNUNET_CRYPTO_RSA_KEY_LENGTH, &zone);
657   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
658
659   //FIXME Handle results in rd
660
661   if (rd_count == 0)
662   {
663     /**
664      * Lookup terminated and no results
665      * -> DHT Phase unless data is recent
666      */
667     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
668                "Namestore lookup for %s terminated without results\n", name);
669     
670     /**
671      * if this is not our zone we cannot rely on the namestore to be
672      * complete. -> Query DHT
673      */
674     if (!GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash))
675     {
676       if (remaining_time.rel_value == 0)
677       {
678         resolve_name_dht(rh, name);
679         return;
680       }
681       else
682       {
683         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
684                    "Record is still recent. No DHT lookup\n");
685       }
686     }
687
688     /**
689      * Our zone and no result? Cannot resolve TT
690      */
691     GNUNET_assert(rh->answered == 0);
692     reply_to_dns(rh, 0, NULL); //answered should be 0
693     return;
694
695   }
696   else
697   {
698     
699     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
700                "Processing additional result %s from namestore\n", name);
701     int i;
702     for (i=0; i<rd_count;i++)
703     {
704       
705       if (strcmp(name, rh->query->name) && rd[i].record_type != rh->query->type)
706         continue;
707       
708       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
709           == 0)
710       {
711         //FIXME there is a catch here...
712         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
713         continue;
714       }
715       
716       rh->answered++;
717       
718     }
719     
720     /**
721      * no answers found
722      * consult dht if expired
723      */
724     if ((remaining_time.rel_value == 0) && (rh->answered == 0))
725     {
726       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
727                  "This dht entry is old. Refreshing.\n");
728       resolve_name_dht(rh, name);
729       return;
730     }
731     
732     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Found %d answer(s) to query!\n",
733                rh->answered);
734
735     reply_to_dns(rh, rd_count, rd);
736   }
737 }
738
739 /**
740  * Determine if this name is canonical.
741  * i.e.
742  * a.b.gnunet  = not canonical
743  * a           = canonical
744  *
745  * @param name the name to test
746  * @return 1 if canonical
747  */
748 int
749 is_canonical(char* name)
750 {
751   uint32_t len = strlen(name);
752   int i;
753
754   for (i=0; i<len; i++)
755   {
756     if (*(name+i) == '.')
757       return 0;
758   }
759   return 1;
760 }
761
762 /**
763  * Move one level up in the domain hierarchy and return the
764  * passed top level domain.
765  *
766  * @param name the domain
767  * @return the tld
768  */
769 char* pop_tld(char* name)
770 {
771   uint32_t len;
772
773   if (is_canonical(name))
774     return NULL;
775
776   for (len = strlen(name); len > 0; len--)
777   {
778     if (*(name+len) == '.')
779       break;
780   }
781
782   if (len == 0)
783     return NULL; //Error
784
785   name[len] = '\0'; //terminate string
786
787   return (name+len+1);
788 }
789
790
791 /**
792  * The first phase of resolution.
793  * First check if the name is canonical.
794  * If it is then try to resolve directly.
795  * If not then first have to resolve the authoritative entities.
796  *
797  * @param rh the pending lookup
798  * @param zone the zone we are currently resolving in
799  */
800 void
801 resolve_name(struct GNUNET_GNS_ResolverHandle *rh)
802 {
803   if (is_canonical(rh->name))
804   {
805     //We only need to check this zone's ns
806     GNUNET_NAMESTORE_lookup_record(namestore_handle,
807                                &rh->authority,
808                                rh->name,
809                                rh->query->type,
810                                &process_authoritative_result,
811                                rh);
812   }
813   else
814   {
815     //We have to resolve the authoritative entity
816     char *new_authority = pop_tld(rh->name);
817     GNUNET_NAMESTORE_lookup_record(namestore_handle,
818                                  &rh->authority,
819                                  new_authority,
820                                  GNUNET_GNS_RECORD_PKEY,
821                                  &process_authority_lookup,
822                                  rh);
823   }
824 }
825
826 /**
827  * Entry point for name resolution
828  * Lookup local namestore of our zone.
829  *
830  * Setup a new query and try to resolve
831  *
832  * @param request the request handle of the DNS request from a client
833  * @param p the DNS query packet we received
834  * @param q the DNS query we received parsed from p
835  */
836 void
837 start_resolution(struct GNUNET_DNS_RequestHandle *request,
838                  struct GNUNET_DNSPARSER_Packet *p,
839                  struct GNUNET_DNSPARSER_Query *q)
840 {
841   struct GNUNET_GNS_ResolverHandle *rh;
842   
843   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting resolution for (%s)!\n",
844               q->name);
845   
846   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
847   rh->packet = p;
848   rh->query = q;
849   rh->authority = zone_hash;
850   
851   //FIXME do not forget to free!!
852   rh->name = GNUNET_malloc(strlen(q->name)
853                               - strlen(gnunet_tld) + 1);
854   memset(rh->name, 0,
855          strlen(q->name)-strlen(gnunet_tld) + 1);
856   memcpy(rh->name, q->name,
857          strlen(q->name)-strlen(gnunet_tld));
858
859   rh->request_handle = request;
860
861   //Start resolution in our zone
862   resolve_name(rh);
863 }
864
865 /**
866  * The DNS request handler
867  * Called for every incoming DNS request.
868  *
869  * @param cls closure
870  * @param rh request handle to user for reply
871  * @param request_length number of bytes in request
872  * @param request udp payload of the DNS request
873  */
874 void
875 handle_dns_request(void *cls,
876                    struct GNUNET_DNS_RequestHandle *rh,
877                    size_t request_length,
878                    const char *request)
879 {
880   struct GNUNET_DNSPARSER_Packet *p;
881   char *tldoffset;
882
883   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Hijacked a DNS request...processing\n");
884   p = GNUNET_DNSPARSER_parse (request, request_length);
885   
886   if (NULL == p)
887   {
888     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
889                 "Received malformed DNS packet, leaving it untouched\n");
890     GNUNET_DNS_request_forward (rh);
891     return;
892   }
893   
894   /**
895    * Check tld and decide if we or
896    * legacy dns is responsible
897    *
898    * FIXME now in theory there could be more than 1 query in the request
899    * but if this is case we get into trouble:
900    * either we query the GNS or the DNS. We cannot do both!
901    * So I suggest to either only allow a single query per request or
902    * only allow GNS or DNS requests.
903    * The way it is implemented here now is buggy and will lead to erratic
904    * behaviour (if multiple queries are present).
905    */
906   if (p->num_queries == 0)
907   {
908     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909                 "No Queries in DNS packet... forwarding\n");
910     GNUNET_DNS_request_forward (rh);
911   }
912
913   if (p->num_queries > 1)
914   {
915     //Note: We could also look for .gnunet
916     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
917                 ">1 queriy in DNS packet... odd. We only process #1\n");
918   }
919
920
921   tldoffset = p->queries[0].name + strlen(p->queries[0].name);
922
923   while ((*tldoffset) != '.')
924     tldoffset--;
925   
926   if (0 == strcmp(tldoffset, gnunet_tld))
927   {
928     start_resolution(rh, p, p->queries);
929   }
930   else
931   {
932     /**
933      * This request does not concern us. Forward to real DNS.
934      */
935     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
936                "Request for %s is forwarded to DNS\n", p->queries[0].name);
937     GNUNET_DNS_request_forward (rh);
938   }
939
940 }
941
942 /**
943  * test function that stores some data in the namestore
944  */
945 void
946 put_some_records(void)
947 {
948   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Populating namestore\n");
949   /* put a few records into namestore */
950   char* ipA = "1.2.3.4";
951   char* ipB = "5.6.7.8";
952   struct GNUNET_CRYPTO_RsaPrivateKey *bob_key = GNUNET_CRYPTO_rsa_key_create ();  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob;
953   bob = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
954
955   GNUNET_CRYPTO_rsa_key_get_public (bob_key, bob);
956
957   GNUNET_HashCode *bob_zone = GNUNET_malloc(sizeof(GNUNET_HashCode));
958
959   GNUNET_CRYPTO_hash(bob, GNUNET_CRYPTO_RSA_KEY_LENGTH, bob_zone);
960
961   struct in_addr *alice = GNUNET_malloc(sizeof(struct in_addr));
962   struct in_addr *bob_web = GNUNET_malloc(sizeof(struct in_addr));
963   struct GNUNET_NAMESTORE_RecordData rda;
964   struct GNUNET_NAMESTORE_RecordData rdb;
965   struct GNUNET_NAMESTORE_RecordData rdb_web;
966
967   GNUNET_assert(1 == inet_pton (AF_INET, ipA, alice));
968   GNUNET_assert(1 == inet_pton (AF_INET, ipB, bob_web));
969
970   rda.data_size = sizeof(struct in_addr);
971   rdb_web.data_size = sizeof(struct in_addr);
972   rdb.data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded);
973   rda.data = alice;
974   rdb.data = bob;
975   rdb_web.data = bob_web;
976   rda.record_type = GNUNET_GNS_RECORD_TYPE_A;
977   rdb_web.record_type = GNUNET_GNS_RECORD_TYPE_A;
978   rdb.record_type = GNUNET_GNS_RECORD_PKEY;
979   rdb_web.expiration = GNUNET_TIME_absolute_get_forever ();
980   rda.expiration = GNUNET_TIME_absolute_get_forever ();
981   rdb.expiration = GNUNET_TIME_absolute_get_forever ();
982   
983   //alice.gnunet A IN 1.2.3.4
984   GNUNET_NAMESTORE_record_create (namestore_handle,
985                                zone_key,
986                                "alice",
987                                &rda,
988                                NULL,
989                                NULL);
990
991   //www.bob.gnunet A IN 5.6.7.8
992   GNUNET_NAMESTORE_record_create (namestore_handle,
993                                zone_key,
994                                "bob",
995                                &rdb,
996                                NULL,
997                                NULL);
998   GNUNET_NAMESTORE_record_put(namestore_handle,
999                               bob,
1000                               "www",
1001                               GNUNET_TIME_absolute_get_forever (),
1002                               1,
1003                               &rdb_web,
1004                               NULL, //Signature
1005                               NULL, //Cont
1006                               NULL); //cls
1007 }
1008
1009 void
1010 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1011 {
1012   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1013 }
1014
1015 /* prototype */
1016 static void
1017 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1018
1019 /**
1020  * Function used to put all records successively into the DHT.
1021  * FIXME bug here
1022  *
1023  * @param cls the closure (NULL)
1024  * @param key the public key of the authority (ours)
1025  * @param expiration lifetime of the namestore entry
1026  * @param name the name of the records
1027  * @param rd_count the number of records in data
1028  * @param rd the record data
1029  * @param signature the signature for the record data
1030  */
1031 void
1032 put_gns_record(void *cls,
1033                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1034                 struct GNUNET_TIME_Absolute expiration,
1035                 const char *name,
1036                 unsigned int rd_count,
1037                 const struct GNUNET_NAMESTORE_RecordData *rd,
1038                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1039 {
1040   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Putting records into the DHT\n");
1041   struct GNUNET_TIME_Relative timeout;
1042   struct GNSNameRecordBlock *nrb;
1043   struct GNSRecordBlock *rb;
1044   GNUNET_HashCode name_hash;
1045   GNUNET_HashCode xor_hash;
1046   int i;
1047   uint32_t rd_payload_length;
1048
1049   if (NULL == name) //We're done
1050   {
1051     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Zone iteration finished\n");
1052     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1053     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1054                                                    NULL);
1055     return;
1056   }
1057   
1058   rd_payload_length = rd_count * sizeof(struct GNSRecordBlock);
1059   rd_payload_length += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1060   //Calculate payload size
1061   for (i=0; i<rd_count; i++)
1062   {
1063     rd_payload_length += rd[i].data_size;
1064   }
1065   
1066   nrb = GNUNET_malloc(rd_payload_length);
1067   
1068   if (signature != NULL)
1069     memcpy(&nrb->signature, signature,
1070          sizeof(struct GNUNET_CRYPTO_RsaSignature));
1071   //FIXME signature purpose
1072   memcpy(&nrb->public_key, key,
1073          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1074
1075   nrb->rd_count = htonl(rd_count);
1076
1077   memcpy(&nrb[1], name, strlen(name) + 1); //FIXME is this 0 terminated??-sure hope so for we use strlen
1078
1079   rb = (struct GNSRecordBlock *)(&nrb[1] + strlen(name) + 1);
1080
1081   for (i=0; i<rd_count; i++)
1082   {
1083     rb->type = htonl(rd[i].record_type);
1084     rb->expiration = GNUNET_TIME_absolute_hton(rd[i].expiration);
1085     rb->data_length = htonl(rd[i].data_size);
1086     rb->flags = htonl(rd[i].flags);
1087     memcpy(&rb[1], rd[i].data, rd[i].data_size);
1088     rb = &rb[1] + rd[i].data_size;
1089   }
1090
1091   /**
1092    * FIXME magic number 20 move to config file
1093    * DHT_WAIT_TIMEOUT
1094    */
1095   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
1096   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1097   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1098   GNUNET_DHT_put (dht_handle, &xor_hash,
1099                   5, //replication level
1100                   GNUNET_DHT_RO_NONE,
1101                   GNUNET_BLOCK_TYPE_TEST, //FIXME todo block plugin
1102                   rd_payload_length,
1103                   (char*)nrb,
1104                   expiration,
1105                   timeout,
1106                   NULL, //FIXME continuation needed? success check? yes ofc
1107                   NULL); //cls for cont
1108   
1109   num_public_records++;
1110
1111   /**
1112    * Reschedule periodic put
1113    */
1114   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1115                                 &update_zone_dht_next,
1116                                 NULL);
1117
1118 }
1119
1120 /**
1121  * Periodically iterate over our zone and store everything in dht
1122  *
1123  * @param cls NULL
1124  * @param tc task context
1125  */
1126 static void
1127 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1128 {
1129   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Update zone!\n");
1130   if (0 == num_public_records)
1131   {
1132     dht_update_interval = GNUNET_TIME_relative_multiply(
1133                                                       GNUNET_TIME_UNIT_SECONDS,
1134                                                       1);
1135   }
1136   else
1137   {
1138     dht_update_interval = GNUNET_TIME_relative_multiply(
1139                                                       GNUNET_TIME_UNIT_SECONDS,
1140                                                      (3600/num_public_records));
1141   }
1142   num_public_records = 0; //start counting again
1143   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1144                                                           &zone_hash,
1145                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1146                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1147                                                           &put_gns_record,
1148                                                           NULL);
1149 }
1150
1151 /**
1152  * Process GNS requests.
1153  *
1154  * @param cls closure
1155  * @param server the initialized server
1156  * @param c configuration to use
1157  */
1158 static void
1159 run (void *cls, struct GNUNET_SERVER_Handle *server,
1160      const struct GNUNET_CONFIGURATION_Handle *c)
1161 {
1162   
1163   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Init GNS\n");
1164   char* keyfile;
1165   char* trusted_entities;
1166
1167   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
1168                                              "ZONEKEY", &keyfile))
1169   {
1170     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1171                 "No private key for root zone specified%s!\n", keyfile);
1172     GNUNET_SCHEDULER_shutdown(0);
1173     return;
1174   }
1175   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1176   //zone_key = GNUNET_CRYPTO_rsa_key_create ();
1177
1178   GNUNET_CRYPTO_hash(zone_key, GNUNET_CRYPTO_RSA_KEY_LENGTH,
1179                      &zone_hash);
1180   
1181   nc = GNUNET_SERVER_notification_context_create (server, 1);
1182
1183   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1184                                 NULL);
1185
1186   if (GNUNET_YES ==
1187       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1188                                             "HIJACK_DNS"))
1189   {
1190     /**
1191      * Do gnunet dns init here
1192      */
1193     dns_handle = GNUNET_DNS_connect(c,
1194                                     GNUNET_DNS_FLAG_PRE_RESOLUTION,
1195                                     &handle_dns_request, /* rh */
1196                                     NULL); /* Closure */
1197   }
1198
1199   if (NULL == dns_handle)
1200   {
1201     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1202                "Failed to connect to the dnsservice!\n");
1203   }
1204
1205   /**
1206    * handle to our local namestore
1207    */
1208   namestore_handle = GNUNET_NAMESTORE_connect(c);
1209
1210   if (NULL == namestore_handle)
1211   {
1212     //FIXME do error handling;
1213     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1214                "Failed to connect to the namestore!\n");
1215     GNUNET_SCHEDULER_shutdown(0);
1216     return;
1217   }
1218   
1219   char* trusted_start;
1220   char* trusted_name;
1221   char *trusted_key;
1222   int trusted_len;
1223   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (c, "gns",
1224                                                       "TRUSTED",
1225                                                       &trusted_entities))
1226   {
1227     trusted_start = trusted_entities;
1228     trusted_len = strlen(trusted_entities);
1229     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1230                "Found trusted entities in config file, importing\n");
1231     while ((trusted_entities-trusted_start) < trusted_len)
1232     {
1233       trusted_name = trusted_entities;
1234       while (*trusted_entities != ':')
1235         trusted_entities++;
1236       *trusted_entities = '\0';
1237       trusted_entities++;
1238       trusted_key = trusted_entities;
1239       while (*trusted_entities != ',' && (*trusted_entities != '\0'))
1240         trusted_entities++;
1241       *trusted_entities = '\0';
1242       trusted_entities++;
1243
1244       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Adding %s:%s to root zone\n",
1245                  trusted_name,
1246                  trusted_key);
1247     }
1248
1249   }
1250
1251   /**
1252    * handle to the dht
1253    */
1254   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1255
1256   if (NULL == dht_handle)
1257   {
1258     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1259   }
1260
1261   put_some_records(); //FIXME for testing
1262   
1263   /**
1264    * Schedule periodic put
1265    * for our records
1266    * We have roughly an hour for all records;
1267    */
1268   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1269                                                       1);
1270   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1271   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "GNS Init done!\n");
1272
1273 }
1274
1275
1276 /**
1277  * The main function for the GNS service.
1278  *
1279  * @param argc number of arguments from the command line
1280  * @param argv command line arguments
1281  * @return 0 ok, 1 on error
1282  */
1283 int
1284 main (int argc, char *const *argv)
1285 {
1286   int ret;
1287
1288   ret =
1289       (GNUNET_OK ==
1290        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1291                            NULL)) ? 0 : 1;
1292   return ret;
1293 }
1294
1295 /* end of gnunet-service-gns.c */