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