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