handle error properly, do not just log but continue gracefully -- v6 also
[oweals/gnunet.git] / src / gns / gnunet-dns2gns.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012-2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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   struct GNUNET_SCHEDULER_Task * 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 struct GNUNET_SCHEDULER_Task * t4;
117
118 /**
119  * Task for IPv6 socket.
120  */
121 static struct GNUNET_SCHEDULER_Task * 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_EcdsaPublicKey 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  * Task run on shutdown.  Cleans up everything.
171  *
172  * @param cls unused
173  */
174 static void
175 do_shutdown (void *cls)
176 {
177   if (NULL != t4)
178   {
179     GNUNET_SCHEDULER_cancel (t4);
180     t4 = NULL;
181   }
182   if (NULL != t6)
183   {
184     GNUNET_SCHEDULER_cancel (t6);
185     t6 = NULL;
186   }
187   if (NULL != listen_socket4)
188   {
189     GNUNET_NETWORK_socket_close (listen_socket4);
190     listen_socket4 = NULL;
191   }
192   if (NULL != listen_socket6)
193   {
194     GNUNET_NETWORK_socket_close (listen_socket6);
195     listen_socket6 = NULL;
196   }
197   if (NULL != id_op)
198   {
199     GNUNET_IDENTITY_cancel (id_op);
200     id_op = NULL;
201   }
202   if (NULL != identity)
203   {
204     GNUNET_IDENTITY_disconnect (identity);
205     identity = NULL;
206   }
207   if (NULL != gns)
208   {
209     GNUNET_GNS_disconnect (gns);
210     gns = NULL;
211   }
212   if (NULL != dns_stub)
213   {
214     GNUNET_DNSSTUB_stop (dns_stub);
215     dns_stub = NULL;
216   }
217 }
218
219
220 /**
221  * Send the response for the given request and clean up.
222  *
223  * @param request context for the request.
224  */
225 static void
226 send_response (struct Request *request)
227 {
228   char *buf;
229   size_t size;
230
231   if (GNUNET_SYSERR ==
232       GNUNET_DNSPARSER_pack (request->packet,
233                              UINT16_MAX /* is this not too much? */,
234                              &buf,
235                              &size))
236     {
237       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
238                   _("Failed to pack DNS response into UDP packet!\n"));
239     }
240   else
241     {
242       if (size !=
243           GNUNET_NETWORK_socket_sendto (request->lsock,
244                                         buf, size,
245                                         request->addr,
246                                         request->addr_len))
247         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
248       GNUNET_free (buf);
249     }
250   GNUNET_SCHEDULER_cancel (request->timeout_task);
251   GNUNET_DNSPARSER_free_packet (request->packet);
252   GNUNET_free (request);
253 }
254
255
256 /**
257  * Task run on timeout.  Cleans up request.
258  *
259  * @param cls `struct Request *` of the request to clean up
260  */
261 static void
262 do_timeout (void *cls)
263 {
264   struct Request *request = cls;
265
266   if (NULL != request->packet)
267     GNUNET_DNSPARSER_free_packet (request->packet);
268   if (NULL != request->lookup)
269     GNUNET_GNS_lookup_cancel (request->lookup);
270   if (NULL != request->dns_lookup)
271     GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
272   GNUNET_free (request);
273 }
274
275
276 /**
277  * Iterator called on obtained result for a DNS lookup
278  *
279  * @param cls closure
280  * @param rs the request socket
281  * @param dns the DNS udp payload
282  * @param r size of the DNS payload
283  */
284 static void
285 dns_result_processor (void *cls,
286                       struct GNUNET_DNSSTUB_RequestSocket *rs,
287                       const struct GNUNET_TUN_DnsHeader *dns,
288                       size_t r)
289 {
290   struct Request *request = cls;
291
292   request->packet = GNUNET_DNSPARSER_parse ((char*)dns, r);
293   send_response (request);
294 }
295
296
297 /**
298  * Iterator called on obtained result for a GNS lookup.
299  *
300  * @param cls closure
301  * @param rd_count number of records in @a rd
302  * @param rd the records in reply
303  */
304 static void
305 result_processor (void *cls,
306                   uint32_t rd_count,
307                   const struct GNUNET_GNSRECORD_Data *rd)
308 {
309   struct Request *request = cls;
310   struct GNUNET_DNSPARSER_Packet *packet;
311   uint32_t i;
312   struct GNUNET_DNSPARSER_Record rec;
313
314   request->lookup = NULL;
315   packet = request->packet;
316   packet->flags.query_or_response = 1;
317   packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
318   packet->flags.checking_disabled = 0;
319   packet->flags.authenticated_data = 1;
320   packet->flags.zero = 0;
321   packet->flags.recursion_available = 1;
322   packet->flags.message_truncated = 0;
323   packet->flags.authoritative_answer = 0;
324   //packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
325   for (i=0;i<rd_count;i++)
326     {
327       // FIXME: do we need to hanlde #GNUNET_GNSRECORD_RF_SHADOW_RECORD
328       // here? Or should we do this in libgnunetgns?
329       rec.expiration_time.abs_value_us = rd[i].expiration_time;
330       switch (rd[i].record_type)
331         {
332         case GNUNET_DNSPARSER_TYPE_A:
333           GNUNET_assert (sizeof (struct in_addr) == rd[i].data_size);
334           rec.name = GNUNET_strdup (packet->queries[0].name);
335           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
336           rec.type = GNUNET_DNSPARSER_TYPE_A;
337           rec.data.raw.data = GNUNET_new (struct in_addr);
338           GNUNET_memcpy (rec.data.raw.data,
339                   rd[i].data,
340                   rd[i].data_size);
341           rec.data.raw.data_len = sizeof (struct in_addr);
342           GNUNET_array_append (packet->answers,
343                                packet->num_answers,
344                                rec);
345           break;
346         case GNUNET_DNSPARSER_TYPE_AAAA:
347           GNUNET_assert (sizeof (struct in6_addr) == rd[i].data_size);
348           rec.name = GNUNET_strdup (packet->queries[0].name);
349           rec.data.raw.data = GNUNET_new (struct in6_addr);
350           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
351           rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
352           GNUNET_memcpy (rec.data.raw.data,
353                   rd[i].data,
354                   rd[i].data_size);
355           rec.data.raw.data_len = sizeof (struct in6_addr);
356           GNUNET_array_append (packet->answers,
357                                packet->num_answers,
358                                rec);
359           break;
360         case GNUNET_DNSPARSER_TYPE_CNAME:
361           rec.name = GNUNET_strdup (packet->queries[0].name);
362           rec.data.hostname = GNUNET_strdup (rd[i].data);
363           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
364           rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
365           GNUNET_memcpy (rec.data.hostname,
366                   rd[i].data,
367                   rd[i].data_size);
368           GNUNET_array_append (packet->answers,
369                                packet->num_answers,
370                                rec);
371           break;
372         default:
373           /* skip */
374           break;
375         }
376     }
377   send_response (request);
378 }
379
380
381 /**
382  * Handle DNS request.
383  *
384  * @param lsock socket to use for sending the reply
385  * @param addr address to use for sending the reply
386  * @param addr_len number of bytes in @a addr
387  * @param udp_msg DNS request payload
388  * @param udp_msg_size number of bytes in @a udp_msg
389  */
390 static void
391 handle_request (struct GNUNET_NETWORK_Handle *lsock,
392                 const void *addr,
393                 size_t addr_len,
394                 const char *udp_msg,
395                 size_t udp_msg_size)
396 {
397   struct Request *request;
398   struct GNUNET_DNSPARSER_Packet *packet;
399   char *name;
400   size_t name_len;
401   int type;
402   int use_gns;
403
404   packet = GNUNET_DNSPARSER_parse (udp_msg, udp_msg_size);
405   if (NULL == packet)
406     {
407       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
408                   _("Cannot parse DNS request from %s\n"),
409                   GNUNET_a2s (addr, addr_len));
410       return;
411     }
412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413               "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
414               packet->queries[0].name,
415               (unsigned int) packet->flags.query_or_response,
416               (int) packet->num_answers,
417               (int) packet->num_authority_records,
418               (int) packet->num_additional_records);
419   if ( (0 != packet->flags.query_or_response) ||
420        (0 != packet->num_answers) ||
421        (0 != packet->num_authority_records))
422     {
423       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
424                   _("Received malformed DNS request from %s\n"),
425                   GNUNET_a2s (addr, addr_len));
426       GNUNET_DNSPARSER_free_packet (packet);
427       return;
428     }
429   if ( (1 != packet->num_queries) )
430     {
431       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
432                   _("Received unsupported DNS request from %s\n"),
433                   GNUNET_a2s (addr, addr_len));
434       GNUNET_DNSPARSER_free_packet (packet);
435       return;
436     }
437   request = GNUNET_malloc (sizeof (struct Request) + addr_len);
438   request->lsock = lsock;
439   request->packet = packet;
440   request->addr = &request[1];
441   request->addr_len = addr_len;
442   GNUNET_memcpy (&request[1], addr, addr_len);
443   request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
444                                                         &do_timeout,
445                                                         request);
446   name = GNUNET_strdup (packet->queries[0].name);
447   name_len = strlen (name);
448   use_gns = GNUNET_NO;
449
450
451   if ( (name_len > strlen (fcfs_suffix)) &&
452        (0 == strcasecmp (fcfs_suffix,
453                          &name[name_len - strlen (fcfs_suffix)])) )
454   {
455     /* replace ".fcfs.zkey.eu" with ".gnu" */
456     strcpy (&name[name_len - strlen (fcfs_suffix)],
457             ".gnu");
458     use_gns = GNUNET_YES;
459   }
460   else if ( (name_len > strlen (dns_suffix)) &&
461             (0 == strcasecmp (dns_suffix,
462                               &name[name_len - strlen (dns_suffix)])) )
463   {
464     /* replace ".zkey.eu" with ".zkey" */
465     strcpy (&name[name_len - strlen (dns_suffix)],
466             ".zkey");
467     use_gns = GNUNET_YES;
468   } else if ( (name_len > strlen (".gnu")) &&
469        (0 == strcasecmp (".gnu",
470                          &name[name_len - strlen (".gnu")])) )
471   {
472     /* name is in GNS */
473     use_gns = GNUNET_YES;
474   }
475   if (GNUNET_YES == use_gns)
476   {
477     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478                 "Calling GNS on `%s'\n",
479                 name);
480     type = packet->queries[0].type;
481     request->lookup = GNUNET_GNS_lookup (gns,
482                                          name,
483                                          &my_zone,
484                                          type,
485                                          GNUNET_NO,
486                                          &result_processor,
487                                          request);
488   }
489   else
490   {
491     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
492                 "Using DNS resolver IP `%s' to resolve `%s'\n",
493                 dns_ip,
494                 name);
495     GNUNET_DNSPARSER_free_packet (request->packet);
496     request->packet = NULL;
497     request->dns_lookup = GNUNET_DNSSTUB_resolve2 (dns_stub,
498                                                    udp_msg,
499                                                    udp_msg_size,
500                                                    &dns_result_processor,
501                                                    request);
502   }
503   GNUNET_free (name);
504 }
505
506
507 /**
508  * Task to read IPv4 DNS packets.
509  *
510  * @param cls the 'listen_socket4'
511  */
512 static void
513 read_dns4 (void *cls)
514 {
515   struct sockaddr_in v4;
516   socklen_t addrlen;
517   ssize_t size;
518   const struct GNUNET_SCHEDULER_TaskContext *tc;
519
520   GNUNET_assert (listen_socket4 == cls);
521   t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
522                                       listen_socket4,
523                                       &read_dns4,
524                                       listen_socket4);
525   tc = GNUNET_SCHEDULER_get_task_context ();
526   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
527     return; /* shutdown? */
528   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
529   if (0 > size)
530     {
531       GNUNET_break (0);
532       return; /* read error!? */
533     }
534   {
535     char buf[size + 1];
536     ssize_t sret;
537
538     addrlen = sizeof (v4);
539     sret = GNUNET_NETWORK_socket_recvfrom (listen_socket4,
540                                            buf,
541                                            size + 1,
542                                            (struct sockaddr *) &v4,
543                                            &addrlen);
544     if (0 > sret)
545     {
546       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
547                            "recvfrom");
548       return;
549     }
550     GNUNET_break (size == (size_t) sret);
551     handle_request (listen_socket4,
552                     &v4,
553                     addrlen,
554                     buf,
555                     size);
556   }
557 }
558
559
560 /**
561  * Task to read IPv6 DNS packets.
562  *
563  * @param cls the 'listen_socket6'
564  */
565 static void
566 read_dns6 (void *cls)
567 {
568   struct sockaddr_in6 v6;
569   socklen_t addrlen;
570   ssize_t size;
571   const struct GNUNET_SCHEDULER_TaskContext *tc;
572
573   GNUNET_assert (listen_socket6 == cls);
574   t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
575                                       listen_socket6,
576                                       &read_dns6,
577                                       listen_socket6);
578   tc = GNUNET_SCHEDULER_get_task_context ();
579   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
580     return; /* shutdown? */
581   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
582   if (0 > size)
583     {
584       GNUNET_break (0);
585       return; /* read error!? */
586     }
587   {
588     char buf[size];
589     ssize_t sret;
590
591     addrlen = sizeof (v6);
592     sret = GNUNET_NETWORK_socket_recvfrom (listen_socket6,
593                                            buf,
594                                            size,
595                                            (struct sockaddr *) &v6,
596                                            &addrlen);
597     if (0 > sret)
598     {
599       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
600                            "recvfrom");
601       return;
602     }
603     GNUNET_break (size == (size_t) sret);
604     handle_request (listen_socket6,
605                     &v6,
606                     addrlen,
607                     buf,
608                     size);
609   }
610 }
611
612
613 /**
614  * Start DNS daemon.
615  */
616 static void
617 run_dnsd ()
618 {
619   if (NULL == dns_suffix)
620     dns_suffix = DNS_SUFFIX;
621   if (NULL == fcfs_suffix)
622     fcfs_suffix = FCFS_SUFFIX;
623   if (NULL == (gns = GNUNET_GNS_connect (cfg)))
624     return;
625   if (NULL == (dns_stub = GNUNET_DNSSTUB_start (dns_ip)))
626   {
627     GNUNET_GNS_disconnect (gns);
628     gns = NULL;
629     return;
630   }
631   listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
632                                                  SOCK_DGRAM,
633                                                  IPPROTO_UDP);
634   if (NULL != listen_socket4)
635   {
636     struct sockaddr_in v4;
637
638     memset (&v4, 0, sizeof (v4));
639     v4.sin_family = AF_INET;
640 #if HAVE_SOCKADDR_IN_SIN_LEN
641     v4.sin_len = sizeof (v4);
642 #endif
643     v4.sin_port = htons (listen_port);
644     if (GNUNET_OK !=
645         GNUNET_NETWORK_socket_bind (listen_socket4,
646                                     (struct sockaddr *) &v4,
647                                     sizeof (v4)))
648     {
649       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
650       GNUNET_NETWORK_socket_close (listen_socket4);
651       listen_socket4 = NULL;
652     }
653   }
654   listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
655                                                 SOCK_DGRAM,
656                                                 IPPROTO_UDP);
657   if (NULL != listen_socket6)
658   {
659     struct sockaddr_in6 v6;
660
661     memset (&v6, 0, sizeof (v6));
662     v6.sin6_family = AF_INET6;
663 #if HAVE_SOCKADDR_IN_SIN_LEN
664     v6.sin6_len = sizeof (v6);
665 #endif
666     v6.sin6_port = htons (listen_port);
667     if (GNUNET_OK !=
668         GNUNET_NETWORK_socket_bind (listen_socket6,
669                                     (struct sockaddr *) &v6,
670                                     sizeof (v6)))
671     {
672       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
673       GNUNET_NETWORK_socket_close (listen_socket6);
674       listen_socket6 = NULL;
675     }
676   }
677   if ( (NULL == listen_socket4) &&
678        (NULL == listen_socket6) )
679   {
680     GNUNET_GNS_disconnect (gns);
681     gns = NULL;
682     GNUNET_DNSSTUB_stop (dns_stub);
683     dns_stub = NULL;
684     return;
685   }
686   if (NULL != listen_socket4)
687     t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
688                                         listen_socket4,
689                                         &read_dns4,
690                                         listen_socket4);
691   if (NULL != listen_socket6)
692     t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
693                                         listen_socket6,
694                                         &read_dns6,
695                                         listen_socket6);
696 }
697
698
699 /**
700  * Method called to inform about the egos of this peer.
701  *
702  * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
703  * this function is only called ONCE, and 'NULL' being passed in
704  * @a ego does indicate an error (i.e. name is taken or no default
705  * value is known).  If @a ego is non-NULL and if '*ctx'
706  * is set in those callbacks, the value WILL be passed to a subsequent
707  * call to the identity callback of #GNUNET_IDENTITY_connect (if
708  * that one was not NULL).
709  *
710  * @param cls closure, NULL
711  * @param ego ego handle
712  * @param ctx context for application to store data for this ego
713  *                 (during the lifetime of this process, initially NULL)
714  * @param name name assigned by the user for this ego,
715  *                   NULL if the user just deleted the ego and it
716  *                   must thus no longer be used
717  */
718 static void
719 identity_cb (void *cls,
720              struct GNUNET_IDENTITY_Ego *ego,
721              void **ctx,
722              const char *name)
723 {
724   id_op = NULL;
725   if (NULL == ego)
726   {
727     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
728                 _("No ego configured for `dns2gns` subsystem\n"));
729     return;
730   }
731   GNUNET_IDENTITY_ego_get_public_key (ego,
732                                       &my_zone);
733   run_dnsd ();
734 }
735
736
737 /**
738  * Main function that will be run.
739  *
740  * @param cls closure
741  * @param args remaining command-line arguments
742  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
743  * @param c configuration
744  */
745 static void
746 run (void *cls,
747      char *const *args,
748      const char *cfgfile,
749      const struct GNUNET_CONFIGURATION_Handle *c)
750 {
751   cfg = c;
752
753   if (NULL == dns_ip)
754   {
755     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
756                 _("No DNS server specified!\n"));
757     return;
758   }
759   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
760   if (NULL == gns_zone_str)
761     {
762       identity = GNUNET_IDENTITY_connect (cfg,
763                                           NULL, NULL);
764       id_op = GNUNET_IDENTITY_get (identity,
765                                    "dns2gns",
766                                    &identity_cb,
767                                    NULL);
768       return;
769     }
770   if ( (NULL == gns_zone_str) ||
771        (GNUNET_OK !=
772         GNUNET_CRYPTO_ecdsa_public_key_from_string (gns_zone_str,
773                                                     strlen (gns_zone_str),
774                                                     &my_zone)) )
775   {
776     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
777                 _("No valid GNS zone specified!\n"));
778     GNUNET_SCHEDULER_shutdown ();
779     return;
780   }
781   run_dnsd ();
782 }
783
784
785 /**
786  * The main function for the dns2gns daemon.
787  *
788  * @param argc number of arguments from the command line
789  * @param argv command line arguments
790  * @return 0 ok, 1 on error
791  */
792 int
793 main (int argc,
794       char *const *argv)
795 {
796   struct GNUNET_GETOPT_CommandLineOption options[] = {
797
798     GNUNET_GETOPT_option_string ('d',
799                                  "dns",
800                                  "IP",
801                                  gettext_noop ("IP of recursive DNS resolver to use (required)"),
802                                  &dns_ip),
803
804     GNUNET_GETOPT_option_string ('f',
805                                  "fcfs",
806                                  "NAME",
807                                  gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"),
808                                  &fcfs_suffix),
809
810     GNUNET_GETOPT_option_string ('s',
811                                  "suffix",
812                                  "SUFFIX",
813                                  gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"),
814                                  &dns_suffix),
815
816     GNUNET_GETOPT_option_uint ('p',
817                                    "port",
818                                    "UDPPORT",
819                                    gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"),
820                                    &listen_port),
821
822     GNUNET_GETOPT_option_string ('z',
823                                  "zone",
824                                  "PUBLICKEY",
825                                  gettext_noop ("Public key of the GNS zone to use (overrides default)"),
826                                  &gns_zone_str), 
827
828     GNUNET_GETOPT_OPTION_END
829   };
830   int ret;
831
832   if (GNUNET_OK !=
833       GNUNET_STRINGS_get_utf8_args (argc, argv,
834                                     &argc, &argv))
835     return 2;
836   GNUNET_log_setup ("gnunet-dns2gns",
837                     "WARNING",
838                     NULL);
839   ret =
840       (GNUNET_OK ==
841        GNUNET_PROGRAM_run (argc, argv,
842                            "gnunet-dns2gns",
843                            _("GNUnet DNS-to-GNS proxy (a DNS server)"),
844                            options,
845                            &run, NULL)) ? 0 : 1;
846   GNUNET_free ((void*) argv);
847   return ret;
848 }
849
850 /* end of gnunet-dns2gns.c */