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