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