b65e457571244f51b4eca25f8659437fede57ead
[oweals/gnunet.git] / src / gns / gnunet-dns2gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012-2013 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  * @file gnunet-dns2gns.c
22  * @brief DNS server that translates DNS requests to GNS
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_gns_service.h>
29 #include <gnunet_identity_service.h>
30 #include <gnunet_dnsstub_lib.h>
31 #include "gns.h"
32
33 /**
34  * Timeout for DNS requests.
35  */
36 #define TIMEOUT GNUNET_TIME_UNIT_MINUTES
37
38 /**
39  * Default suffix
40  */
41 #define DNS_SUFFIX ".zkey.eu"
42
43 /**
44  * FCFS suffix
45  */
46 #define FCFS_SUFFIX "fcfs.zkey.eu"
47
48 /**
49  * Data kept per request.
50  */
51 struct Request
52 {
53   /**
54    * Socket to use for sending the reply.
55    */
56   struct GNUNET_NETWORK_Handle *lsock;
57
58   /**
59    * Destination address to use.
60    */
61   const void *addr;
62
63   /**
64    * Initially, this is the DNS request, it will then be
65    * converted to the DNS response.
66    */
67   struct GNUNET_DNSPARSER_Packet *packet;
68   
69   /**
70    * Our GNS request handle.
71    */
72   struct GNUNET_GNS_LookupRequest *lookup;
73
74   /**
75    * Our DNS request handle
76    */
77   struct GNUNET_DNSSTUB_RequestSocket *dns_lookup;
78
79   /**
80    * Task run on timeout or shutdown to clean up without
81    * response.
82    */
83   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
84
85   /**
86    * Number of bytes in 'addr'.
87    */ 
88   size_t addr_len;
89
90 };
91
92
93 /**
94  * Handle to GNS resolver.
95  */
96 struct GNUNET_GNS_Handle *gns;
97
98 /**
99  * Stub resolver
100  */
101 struct GNUNET_DNSSTUB_Context *dns_stub;
102
103 /**
104  * Listen socket for IPv4.
105  */
106 static struct GNUNET_NETWORK_Handle *listen_socket4;
107
108 /**
109  * Listen socket for IPv6.
110  */
111 static struct GNUNET_NETWORK_Handle *listen_socket6;
112
113 /**
114  * Task for IPv4 socket.
115  */
116 static GNUNET_SCHEDULER_TaskIdentifier t4;
117
118 /**
119  * Task for IPv6 socket.
120  */
121 static GNUNET_SCHEDULER_TaskIdentifier t6;
122
123 /**
124  * DNS suffix, suffix of this gateway in DNS; defaults to '.zkey.eu'
125  */
126 static char *dns_suffix;
127
128 /**
129  * FCFS suffix, suffix of FCFS-authority in DNS; defaults to 'fcfs.zkey.eu'.
130  */
131 static char *fcfs_suffix;
132
133 /**
134  * IP of DNS server
135  */
136 static char *dns_ip;
137
138 /**
139  * UDP Port we listen on for inbound DNS requests.
140  */
141 static unsigned int listen_port = 53;
142
143 /**
144  * Which GNS zone do we translate incoming DNS requests to?
145  */
146 static struct GNUNET_CRYPTO_EccPublicKey my_zone;
147
148 /**
149  * '-z' option with the main zone to use.
150  */
151 static char *gns_zone_str;
152
153 /**
154  * Configuration to use.
155  */
156 static const struct GNUNET_CONFIGURATION_Handle *cfg;
157
158 /**
159  * Connection to identity service.
160  */
161 static struct GNUNET_IDENTITY_Handle *identity;
162
163 /**
164  * Request for our ego.
165  */
166 static struct GNUNET_IDENTITY_Operation *id_op;
167
168
169
170 /**
171  * Task run on shutdown.  Cleans up everything.
172  *
173  * @param cls unused
174  * @param tc scheduler context
175  */
176 static void
177 do_shutdown (void *cls,
178              const struct GNUNET_SCHEDULER_TaskContext *tc)
179 {
180   if (GNUNET_SCHEDULER_NO_TASK != t4)
181     GNUNET_SCHEDULER_cancel (t4);
182   if (GNUNET_SCHEDULER_NO_TASK != t6)
183     GNUNET_SCHEDULER_cancel (t6);
184   if (NULL != listen_socket4)
185   {
186     GNUNET_NETWORK_socket_close (listen_socket4);
187     listen_socket4 = NULL;
188   }
189   if (NULL != listen_socket6)
190   {
191     GNUNET_NETWORK_socket_close (listen_socket6);
192     listen_socket6 = NULL;
193   }
194   if (NULL != id_op)
195   {
196     GNUNET_IDENTITY_cancel (id_op);
197     id_op = NULL;
198   }
199   if (NULL != identity)
200   {
201     GNUNET_IDENTITY_disconnect (identity);
202     identity = NULL;
203   }
204   GNUNET_GNS_disconnect (gns);
205   gns = NULL;
206   GNUNET_DNSSTUB_stop (dns_stub);
207   dns_stub = NULL;
208 }
209
210
211 /**
212  * Send the response for the given request and clean up.
213  *
214  * @param request context for the request.
215  */
216 static void
217 send_response (struct Request *request)
218 {
219   char *buf;
220   size_t size;
221   
222   if (GNUNET_SYSERR ==
223       GNUNET_DNSPARSER_pack (request->packet,
224                              UINT16_MAX /* is this not too much? */,
225                              &buf,
226                              &size))
227     {
228       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
229                   _("Failed to pack DNS response into UDP packet!\n"));
230     }
231   else
232     {
233       if (size !=
234           GNUNET_NETWORK_socket_sendto (request->lsock,
235                                         buf, size,
236                                         request->addr,
237                                         request->addr_len))
238         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
239       GNUNET_free (buf);
240     }
241   GNUNET_SCHEDULER_cancel (request->timeout_task);
242   GNUNET_DNSPARSER_free_packet (request->packet);
243   GNUNET_free (request);
244 }
245
246
247 /**
248  * Task run on timeout.  Cleans up request.
249  *
250  * @param cls 'struct Request' of the request to clean up
251  * @param tc scheduler context
252  */
253 static void
254 do_timeout (void *cls,
255             const struct GNUNET_SCHEDULER_TaskContext *tc)
256 {
257   struct Request *request = cls;
258
259   if (NULL != request->packet)
260     GNUNET_DNSPARSER_free_packet (request->packet);
261   if (NULL != request->lookup)
262     GNUNET_GNS_lookup_cancel (request->lookup);
263   if (NULL != request->dns_lookup)
264     GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
265   GNUNET_free (request);
266 }
267
268
269 /**
270  * Iterator called on obtained result for a DNS lookup
271  *
272  * @param cls closure
273  * @param rs the request socket
274  * @param dns the DNS udp payload
275  * @param r size of the DNS payload
276  */
277 static void
278 dns_result_processor (void *cls,
279                       struct GNUNET_DNSSTUB_RequestSocket *rs,
280                       const struct GNUNET_TUN_DnsHeader *dns,
281                       size_t r)
282 {
283   struct Request *request = cls;
284
285   request->packet = GNUNET_DNSPARSER_parse ((char*)dns, r);
286   send_response (request);
287 }
288
289
290 /**
291  * Iterator called on obtained result for a GNS lookup.
292  *
293  * @param cls closure
294  * @param rd_count number of records in @a rd
295  * @param rd the records in reply
296  */
297 static void
298 result_processor (void *cls,
299                   uint32_t rd_count,
300                   const struct GNUNET_NAMESTORE_RecordData *rd)
301 {
302   struct Request *request = cls;
303   struct GNUNET_DNSPARSER_Packet *packet;
304   uint32_t i;
305   struct GNUNET_DNSPARSER_Record rec;
306
307   request->lookup = NULL;
308   packet = request->packet;
309   packet->flags.query_or_response = 1;
310   packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
311   packet->flags.checking_disabled = 0;
312   packet->flags.authenticated_data = 1;
313   packet->flags.zero = 0;
314   packet->flags.recursion_available = 1;
315   packet->flags.message_truncated = 0;
316   packet->flags.authoritative_answer = 0;
317   //packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
318   for (i=0;i<rd_count;i++)
319     {
320       // FIXME: do we need to hanlde #GNUNET_NAMESTORE_RF_SHADOW_RECORD
321       // here? Or should we do this in libgnunetgns?
322       rec.expiration_time.abs_value_us = rd[i].expiration_time;
323       switch (rd[i].record_type)
324         {
325         case GNUNET_DNSPARSER_TYPE_A:
326           GNUNET_assert (sizeof (struct in_addr) == rd[i].data_size);
327           rec.name = GNUNET_strdup (packet->queries[0].name);
328           rec.class = GNUNET_TUN_DNS_CLASS_INTERNET;
329           rec.type = GNUNET_DNSPARSER_TYPE_A;
330           rec.data.raw.data = GNUNET_new (struct in_addr);
331           memcpy (rec.data.raw.data,
332                   rd[i].data,
333                   rd[i].data_size);
334           rec.data.raw.data_len = sizeof (struct in_addr);
335           GNUNET_array_append (packet->answers,
336                                packet->num_answers,
337                                rec);
338           break;
339         case GNUNET_DNSPARSER_TYPE_AAAA:
340           GNUNET_assert (sizeof (struct in6_addr) == rd[i].data_size);
341           rec.name = GNUNET_strdup (packet->queries[0].name);
342           rec.data.raw.data = GNUNET_malloc (sizeof (struct in6_addr));
343           rec.class = GNUNET_TUN_DNS_CLASS_INTERNET;
344           rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
345           memcpy (rec.data.raw.data,
346                   rd[i].data,
347                   rd[i].data_size);
348           rec.data.raw.data_len = sizeof (struct in6_addr);
349           GNUNET_array_append (packet->answers,
350                                packet->num_answers,
351                                rec);
352           break;
353         case GNUNET_DNSPARSER_TYPE_CNAME:
354           rec.name = GNUNET_strdup (packet->queries[0].name);
355           rec.data.hostname = strdup (rd[i].data);
356           rec.class = GNUNET_TUN_DNS_CLASS_INTERNET;
357           rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
358           memcpy (rec.data.hostname,
359                   rd[i].data,
360                   rd[i].data_size);
361           GNUNET_array_append (packet->answers,
362                                packet->num_answers,
363                                rec);
364           break;
365         default:
366           /* skip */
367           break;
368         }
369     }
370   send_response (request);
371 }
372
373
374 /**
375  * Handle DNS request.
376  *
377  * @param lsock socket to use for sending the reply
378  * @param addr address to use for sending the reply
379  * @param addr_len number of bytes in @a addr
380  * @param udp_msg DNS request payload
381  * @param udp_msg_size number of bytes in @a udp_msg 
382  */
383 static void
384 handle_request (struct GNUNET_NETWORK_Handle *lsock,
385                 const void *addr,
386                 size_t addr_len,
387                 const char *udp_msg,
388                 size_t udp_msg_size)
389 {
390   struct Request *request;
391   struct GNUNET_DNSPARSER_Packet *packet;
392   char *name;
393   size_t name_len;
394   int type;
395   int use_gns;
396
397   packet = GNUNET_DNSPARSER_parse (udp_msg, udp_msg_size);
398   if (NULL == packet)
399     {
400       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
401                   _("Cannot parse DNS request from %s\n"),
402                   GNUNET_a2s (addr, addr_len));
403       return;
404     }
405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406               "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
407               packet->queries[0].name,
408               (unsigned int) packet->flags.query_or_response,
409               (int) packet->num_answers,
410               (int) packet->num_authority_records,
411               (int) packet->num_additional_records);
412   if ( (0 != packet->flags.query_or_response) || 
413        (0 != packet->num_answers) ||
414        (0 != packet->num_authority_records))
415     {
416       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
417                   _("Received malformed DNS request from %s\n"),
418                   GNUNET_a2s (addr, addr_len));
419       GNUNET_DNSPARSER_free_packet (packet);
420       return;
421     }
422   if ( (1 != packet->num_queries) )
423     {
424       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
425                   _("Received unsupported DNS request from %s\n"),
426                   GNUNET_a2s (addr, addr_len));
427       GNUNET_DNSPARSER_free_packet (packet);
428       return;
429     }
430   request = GNUNET_malloc (sizeof (struct Request) + addr_len);
431   request->lsock = lsock;
432   request->packet = packet;
433   request->addr = &request[1];
434   request->addr_len = addr_len;
435   memcpy (&request[1], addr, addr_len);
436   request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
437                                                         &do_timeout,
438                                                         request);
439   name = GNUNET_strdup (packet->queries[0].name);
440   name_len = strlen (name);
441   use_gns = GNUNET_NO;
442
443   
444   if ( (name_len > strlen (fcfs_suffix)) &&
445        (0 == strcasecmp (fcfs_suffix,
446                          &name[name_len - strlen (fcfs_suffix)])) )
447   {
448     /* replace ".fcfs.zkey.eu" with ".gnu" */
449     strcpy (&name[name_len - strlen (fcfs_suffix)],
450             ".gnu");
451     use_gns = GNUNET_YES;
452   } else if ( (name_len > strlen (dns_suffix)) &&
453        (0 == strcasecmp (dns_suffix,
454                          &name[name_len - strlen (dns_suffix)])) )
455   {
456     /* replace ".zkey.eu" with ".zkey" */
457     strcpy (&name[name_len - strlen (dns_suffix)],
458             ".zkey");
459     use_gns = GNUNET_YES;
460   } else if ( (name_len > strlen (".gnu")) &&
461        (0 == strcasecmp (".gnu",
462                          &name[name_len - strlen (".gnu")])) )
463   {
464     /* name is in GNS */
465     use_gns = GNUNET_YES;
466   }
467   if (GNUNET_YES == use_gns)
468   {
469     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470                 "Calling GNS on `%s'\n",
471                 name);
472     type = packet->queries[0].type;
473     request->lookup = GNUNET_GNS_lookup (gns,
474                                          name,
475                                          &my_zone,
476                                          type,
477                                          GNUNET_NO,
478                                          NULL /* no shorten */,
479                                          &result_processor,
480                                          request);
481   }
482   else
483   {
484     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485                 "Using DNS resolver IP `%s' to resolve `%s'\n", 
486                 dns_ip,
487                 name);
488     GNUNET_DNSPARSER_free_packet (request->packet);
489     request->packet = NULL;
490     request->dns_lookup = GNUNET_DNSSTUB_resolve2 (dns_stub,
491                                                    udp_msg,
492                                                    udp_msg_size,
493                                                    &dns_result_processor,
494                                                    request);
495   }
496   GNUNET_free (name);
497 }
498
499
500 /**
501  * Task to read IPv4 DNS packets.
502  *
503  * @param cls the 'listen_socket4'
504  * @param tc scheduler context
505  */ 
506 static void
507 read_dns4 (void *cls,
508            const struct GNUNET_SCHEDULER_TaskContext *tc)
509 {
510   struct sockaddr_in v4;
511   socklen_t addrlen;
512   ssize_t size;
513
514   GNUNET_assert (listen_socket4 == cls);
515   t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
516                                       listen_socket4,
517                                       &read_dns4,
518                                       listen_socket4);
519   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
520     return; /* shutdown? */
521   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
522   if (0 > size)
523     {
524       GNUNET_break (0);
525       return; /* read error!? */
526     }
527   {
528     char buf[size];
529     
530     addrlen = sizeof (v4);
531     GNUNET_break (size == 
532                   GNUNET_NETWORK_socket_recvfrom (listen_socket4,
533                                                   buf,
534                                                   size,
535                                                   (struct sockaddr *) &v4,
536                                                   &addrlen));
537     handle_request (listen_socket4, &v4, addrlen,
538                     buf, size);
539   }
540 }
541
542
543 /**
544  * Task to read IPv6 DNS packets.
545  *
546  * @param cls the 'listen_socket6'
547  * @param tc scheduler context
548  */ 
549 static void
550 read_dns6 (void *cls,
551            const struct GNUNET_SCHEDULER_TaskContext *tc)
552 {
553   struct sockaddr_in6 v6;
554   socklen_t addrlen;
555   ssize_t size;
556
557   GNUNET_assert (listen_socket6 == cls);
558   t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
559                                       listen_socket6,
560                                       &read_dns6,
561                                       listen_socket6);
562   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
563     return; /* shutdown? */
564   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
565   if (0 > size)
566     {
567       GNUNET_break (0);
568       return; /* read error!? */
569     }
570   {
571     char buf[size];
572     
573     addrlen = sizeof (v6);
574     GNUNET_break (size == 
575                   GNUNET_NETWORK_socket_recvfrom (listen_socket6,
576                                                   buf,
577                                                   size,
578                                                   (struct sockaddr *) &v6,
579                                                   &addrlen));
580     handle_request (listen_socket6, &v6, addrlen,
581                     buf, size);
582   }
583 }
584
585
586 /**
587  * Start DNS daemon.
588  */
589 static void
590 run_dnsd ()
591 {
592   if (NULL == dns_suffix)
593     dns_suffix = DNS_SUFFIX;
594   if (NULL == fcfs_suffix)
595     fcfs_suffix = FCFS_SUFFIX;
596   if (NULL == (gns = GNUNET_GNS_connect (cfg)))
597     return;
598   if (NULL == (dns_stub = GNUNET_DNSSTUB_start (dns_ip)))
599   {
600     GNUNET_GNS_disconnect (gns);
601     gns = NULL;
602     return;
603   }
604   listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
605                                                  SOCK_DGRAM, 
606                                                  IPPROTO_UDP);
607   if (NULL != listen_socket4)
608     {
609       struct sockaddr_in v4;
610
611       memset (&v4, 0, sizeof (v4));
612       v4.sin_family = AF_INET;
613 #if HAVE_SOCKADDR_IN_SIN_LEN
614       v4.sin_len = sizeof (v4);
615 #endif
616       v4.sin_port = htons (listen_port);
617       if (GNUNET_OK !=
618           GNUNET_NETWORK_socket_bind (listen_socket4,
619                                       (struct sockaddr *) &v4,
620                                       sizeof (v4),
621                                       0))
622         {
623           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
624           GNUNET_NETWORK_socket_close (listen_socket4);
625           listen_socket4 = NULL;
626         }
627     }
628   listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
629                                                 SOCK_DGRAM, 
630                                                 IPPROTO_UDP);
631   if (NULL != listen_socket6)
632     {
633       struct sockaddr_in6 v6;
634
635       memset (&v6, 0, sizeof (v6));
636       v6.sin6_family = AF_INET6;
637 #if HAVE_SOCKADDR_IN_SIN_LEN
638       v6.sin6_len = sizeof (v6);
639 #endif
640       v6.sin6_port = htons (listen_port);
641       if (GNUNET_OK !=
642           GNUNET_NETWORK_socket_bind (listen_socket6,
643                                       (struct sockaddr *) &v6,
644                                       sizeof (v6),
645                                       0))
646         {
647           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
648           GNUNET_NETWORK_socket_close (listen_socket6);
649           listen_socket6 = NULL;
650         }
651     }
652   if ( (NULL == listen_socket4) &&
653        (NULL == listen_socket6) )
654     {
655       GNUNET_GNS_disconnect (gns);
656       gns = NULL;
657       GNUNET_DNSSTUB_stop (dns_stub);
658       dns_stub = NULL;
659       return;
660     }
661   if (NULL != listen_socket4)
662     t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
663                                         listen_socket4,
664                                         &read_dns4,
665                                         listen_socket4);
666   if (NULL != listen_socket6)
667     t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
668                                         listen_socket6,
669                                         &read_dns6,
670                                         listen_socket6);
671
672 }
673
674
675 /** 
676  * Method called to inform about the egos of this peer.
677  *
678  * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
679  * this function is only called ONCE, and 'NULL' being passed in
680  * @a ego does indicate an error (i.e. name is taken or no default
681  * value is known).  If @a ego is non-NULL and if '*ctx'
682  * is set in those callbacks, the value WILL be passed to a subsequent
683  * call to the identity callback of #GNUNET_IDENTITY_connect (if 
684  * that one was not NULL).
685  *
686  * @param cls closure, NULL
687  * @param ego ego handle
688  * @param ctx context for application to store data for this ego
689  *                 (during the lifetime of this process, initially NULL)
690  * @param name name assigned by the user for this ego,
691  *                   NULL if the user just deleted the ego and it
692  *                   must thus no longer be used
693  */
694 static void
695 identity_cb (void *cls,
696              struct GNUNET_IDENTITY_Ego *ego,
697              void **ctx,
698              const char *name)
699 {
700   id_op = NULL;
701   if (NULL == ego)
702   {
703     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
704                 _("No ego configured for `dns2gns` subsystem\n"));
705     return;
706   }
707   GNUNET_IDENTITY_ego_get_public_key (ego,
708                                       &my_zone);
709   run_dnsd ();
710 }
711
712
713 /**
714  * Main function that will be run.
715  *
716  * @param cls closure
717  * @param args remaining command-line arguments
718  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
719  * @param c configuration
720  */
721 static void
722 run (void *cls, char *const *args, const char *cfgfile,
723      const struct GNUNET_CONFIGURATION_Handle *c)
724 {
725   cfg = c;
726
727   if (NULL == dns_ip)
728   {
729     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
730                 _("No DNS server specified!\n"));
731     return;
732   }
733   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
734                                 &do_shutdown, NULL);
735   if (NULL == gns_zone_str)
736     {
737       identity = GNUNET_IDENTITY_connect (cfg,
738                                           NULL, NULL);
739       id_op = GNUNET_IDENTITY_get (identity,
740                                    "dns2gns",
741                                    &identity_cb,
742                                    NULL);
743       return;
744     }
745   if ( (NULL == gns_zone_str) ||
746        (GNUNET_OK !=
747         GNUNET_CRYPTO_ecc_public_key_from_string (gns_zone_str,
748                                                   strlen (gns_zone_str),
749                                                   &my_zone)) )
750   {
751     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
752                 _("No valid GNS zone specified!\n"));
753     GNUNET_SCHEDULER_shutdown ();
754     return;
755   }
756   run_dnsd ();
757 }
758
759
760 /**
761  * The main function for the dns2gns daemon.
762  *
763  * @param argc number of arguments from the command line
764  * @param argv command line arguments
765  * @return 0 ok, 1 on error
766  */
767 int
768 main (int argc, 
769       char *const *argv)
770 {
771   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
772     {'d', "dns", "IP",
773       gettext_noop ("IP of recursive DNS resolver to use (required)"), 1,
774       &GNUNET_GETOPT_set_string, &dns_ip},
775     {'f', "fcfs", "NAME",
776       gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"), 1,
777       &GNUNET_GETOPT_set_string, &fcfs_suffix},
778     {'s', "suffix", "SUFFIX",
779       gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"), 1,
780       &GNUNET_GETOPT_set_string, &dns_suffix},
781     {'p', "port", "UDPPORT",
782       gettext_noop ("UDP port to listen on for inbound DNS requests; default: 53"), 1,
783       &GNUNET_GETOPT_set_uint, &listen_port},
784     {'z', "zone", "PUBLICKEY",
785       gettext_noop ("Public key of the GNS zone to use (overrides default)"), 1,
786       &GNUNET_GETOPT_set_string, &gns_zone_str},
787     GNUNET_GETOPT_OPTION_END
788   };
789   int ret;
790
791   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
792                                                  &argc, &argv))
793     return 2;
794   GNUNET_log_setup ("gnunet-dns2gns", "WARNING", NULL);
795   ret =
796       (GNUNET_OK ==
797        GNUNET_PROGRAM_run (argc, argv, "gnunet-dns2gns",
798                            _("GNUnet DNS-to-GNS proxy (a DNS server)"), 
799                            options,
800                            &run, NULL)) ? 0 : 1;
801   GNUNET_free ((void*) argv);
802   return ret;
803 }
804
805 /* end of gnunet-dns2gns.c */