small API change: do no longer pass rarely needed GNUNET_SCHEDULER_TaskContext to...
[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 = 2853;
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     GNUNET_SCHEDULER_cancel (t4);
179   if (NULL != t6)
180     GNUNET_SCHEDULER_cancel (t6);
181   if (NULL != listen_socket4)
182   {
183     GNUNET_NETWORK_socket_close (listen_socket4);
184     listen_socket4 = NULL;
185   }
186   if (NULL != listen_socket6)
187   {
188     GNUNET_NETWORK_socket_close (listen_socket6);
189     listen_socket6 = NULL;
190   }
191   if (NULL != id_op)
192   {
193     GNUNET_IDENTITY_cancel (id_op);
194     id_op = NULL;
195   }
196   if (NULL != identity)
197   {
198     GNUNET_IDENTITY_disconnect (identity);
199     identity = NULL;
200   }
201   if (NULL != gns)
202   {
203     GNUNET_GNS_disconnect (gns);
204     gns = NULL;
205   }
206   if (NULL != dns_stub)
207   {
208     GNUNET_DNSSTUB_stop (dns_stub);
209     dns_stub = NULL;
210   }
211 }
212
213
214 /**
215  * Send the response for the given request and clean up.
216  *
217  * @param request context for the request.
218  */
219 static void
220 send_response (struct Request *request)
221 {
222   char *buf;
223   size_t size;
224
225   if (GNUNET_SYSERR ==
226       GNUNET_DNSPARSER_pack (request->packet,
227                              UINT16_MAX /* is this not too much? */,
228                              &buf,
229                              &size))
230     {
231       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
232                   _("Failed to pack DNS response into UDP packet!\n"));
233     }
234   else
235     {
236       if (size !=
237           GNUNET_NETWORK_socket_sendto (request->lsock,
238                                         buf, size,
239                                         request->addr,
240                                         request->addr_len))
241         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
242       GNUNET_free (buf);
243     }
244   GNUNET_SCHEDULER_cancel (request->timeout_task);
245   GNUNET_DNSPARSER_free_packet (request->packet);
246   GNUNET_free (request);
247 }
248
249
250 /**
251  * Task run on timeout.  Cleans up request.
252  *
253  * @param cls `struct Request *` of the request to clean up
254  */
255 static void
256 do_timeout (void *cls)
257 {
258   struct Request *request = cls;
259
260   if (NULL != request->packet)
261     GNUNET_DNSPARSER_free_packet (request->packet);
262   if (NULL != request->lookup)
263     GNUNET_GNS_lookup_cancel (request->lookup);
264   if (NULL != request->dns_lookup)
265     GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
266   GNUNET_free (request);
267 }
268
269
270 /**
271  * Iterator called on obtained result for a DNS lookup
272  *
273  * @param cls closure
274  * @param rs the request socket
275  * @param dns the DNS udp payload
276  * @param r size of the DNS payload
277  */
278 static void
279 dns_result_processor (void *cls,
280                       struct GNUNET_DNSSTUB_RequestSocket *rs,
281                       const struct GNUNET_TUN_DnsHeader *dns,
282                       size_t r)
283 {
284   struct Request *request = cls;
285
286   request->packet = GNUNET_DNSPARSER_parse ((char*)dns, r);
287   send_response (request);
288 }
289
290
291 /**
292  * Iterator called on obtained result for a GNS lookup.
293  *
294  * @param cls closure
295  * @param rd_count number of records in @a rd
296  * @param rd the records in reply
297  */
298 static void
299 result_processor (void *cls,
300                   uint32_t rd_count,
301                   const struct GNUNET_GNSRECORD_Data *rd)
302 {
303   struct Request *request = cls;
304   struct GNUNET_DNSPARSER_Packet *packet;
305   uint32_t i;
306   struct GNUNET_DNSPARSER_Record rec;
307
308   request->lookup = NULL;
309   packet = request->packet;
310   packet->flags.query_or_response = 1;
311   packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
312   packet->flags.checking_disabled = 0;
313   packet->flags.authenticated_data = 1;
314   packet->flags.zero = 0;
315   packet->flags.recursion_available = 1;
316   packet->flags.message_truncated = 0;
317   packet->flags.authoritative_answer = 0;
318   //packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
319   for (i=0;i<rd_count;i++)
320     {
321       // FIXME: do we need to hanlde #GNUNET_GNSRECORD_RF_SHADOW_RECORD
322       // here? Or should we do this in libgnunetgns?
323       rec.expiration_time.abs_value_us = rd[i].expiration_time;
324       switch (rd[i].record_type)
325         {
326         case GNUNET_DNSPARSER_TYPE_A:
327           GNUNET_assert (sizeof (struct in_addr) == rd[i].data_size);
328           rec.name = GNUNET_strdup (packet->queries[0].name);
329           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
330           rec.type = GNUNET_DNSPARSER_TYPE_A;
331           rec.data.raw.data = GNUNET_new (struct in_addr);
332           memcpy (rec.data.raw.data,
333                   rd[i].data,
334                   rd[i].data_size);
335           rec.data.raw.data_len = sizeof (struct in_addr);
336           GNUNET_array_append (packet->answers,
337                                packet->num_answers,
338                                rec);
339           break;
340         case GNUNET_DNSPARSER_TYPE_AAAA:
341           GNUNET_assert (sizeof (struct in6_addr) == rd[i].data_size);
342           rec.name = GNUNET_strdup (packet->queries[0].name);
343           rec.data.raw.data = GNUNET_new (struct in6_addr);
344           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
345           rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
346           memcpy (rec.data.raw.data,
347                   rd[i].data,
348                   rd[i].data_size);
349           rec.data.raw.data_len = sizeof (struct in6_addr);
350           GNUNET_array_append (packet->answers,
351                                packet->num_answers,
352                                rec);
353           break;
354         case GNUNET_DNSPARSER_TYPE_CNAME:
355           rec.name = GNUNET_strdup (packet->queries[0].name);
356           rec.data.hostname = GNUNET_strdup (rd[i].data);
357           rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
358           rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
359           memcpy (rec.data.hostname,
360                   rd[i].data,
361                   rd[i].data_size);
362           GNUNET_array_append (packet->answers,
363                                packet->num_answers,
364                                rec);
365           break;
366         default:
367           /* skip */
368           break;
369         }
370     }
371   send_response (request);
372 }
373
374
375 /**
376  * Handle DNS request.
377  *
378  * @param lsock socket to use for sending the reply
379  * @param addr address to use for sending the reply
380  * @param addr_len number of bytes in @a addr
381  * @param udp_msg DNS request payload
382  * @param udp_msg_size number of bytes in @a udp_msg
383  */
384 static void
385 handle_request (struct GNUNET_NETWORK_Handle *lsock,
386                 const void *addr,
387                 size_t addr_len,
388                 const char *udp_msg,
389                 size_t udp_msg_size)
390 {
391   struct Request *request;
392   struct GNUNET_DNSPARSER_Packet *packet;
393   char *name;
394   size_t name_len;
395   int type;
396   int use_gns;
397
398   packet = GNUNET_DNSPARSER_parse (udp_msg, udp_msg_size);
399   if (NULL == packet)
400     {
401       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
402                   _("Cannot parse DNS request from %s\n"),
403                   GNUNET_a2s (addr, addr_len));
404       return;
405     }
406   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
407               "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
408               packet->queries[0].name,
409               (unsigned int) packet->flags.query_or_response,
410               (int) packet->num_answers,
411               (int) packet->num_authority_records,
412               (int) packet->num_additional_records);
413   if ( (0 != packet->flags.query_or_response) ||
414        (0 != packet->num_answers) ||
415        (0 != packet->num_authority_records))
416     {
417       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
418                   _("Received malformed DNS request from %s\n"),
419                   GNUNET_a2s (addr, addr_len));
420       GNUNET_DNSPARSER_free_packet (packet);
421       return;
422     }
423   if ( (1 != packet->num_queries) )
424     {
425       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
426                   _("Received unsupported DNS request from %s\n"),
427                   GNUNET_a2s (addr, addr_len));
428       GNUNET_DNSPARSER_free_packet (packet);
429       return;
430     }
431   request = GNUNET_malloc (sizeof (struct Request) + addr_len);
432   request->lsock = lsock;
433   request->packet = packet;
434   request->addr = &request[1];
435   request->addr_len = addr_len;
436   memcpy (&request[1], addr, addr_len);
437   request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
438                                                         &do_timeout,
439                                                         request);
440   name = GNUNET_strdup (packet->queries[0].name);
441   name_len = strlen (name);
442   use_gns = GNUNET_NO;
443
444
445   if ( (name_len > strlen (fcfs_suffix)) &&
446        (0 == strcasecmp (fcfs_suffix,
447                          &name[name_len - strlen (fcfs_suffix)])) )
448   {
449     /* replace ".fcfs.zkey.eu" with ".gnu" */
450     strcpy (&name[name_len - strlen (fcfs_suffix)],
451             ".gnu");
452     use_gns = GNUNET_YES;
453   }
454   else if ( (name_len > strlen (dns_suffix)) &&
455             (0 == strcasecmp (dns_suffix,
456                               &name[name_len - strlen (dns_suffix)])) )
457   {
458     /* replace ".zkey.eu" with ".zkey" */
459     strcpy (&name[name_len - strlen (dns_suffix)],
460             ".zkey");
461     use_gns = GNUNET_YES;
462   } else if ( (name_len > strlen (".gnu")) &&
463        (0 == strcasecmp (".gnu",
464                          &name[name_len - strlen (".gnu")])) )
465   {
466     /* name is in GNS */
467     use_gns = GNUNET_YES;
468   }
469   if (GNUNET_YES == use_gns)
470   {
471     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472                 "Calling GNS on `%s'\n",
473                 name);
474     type = packet->queries[0].type;
475     request->lookup = GNUNET_GNS_lookup (gns,
476                                          name,
477                                          &my_zone,
478                                          type,
479                                          GNUNET_NO,
480                                          NULL /* no shorten */,
481                                          &result_processor,
482                                          request);
483   }
484   else
485   {
486     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487                 "Using DNS resolver IP `%s' to resolve `%s'\n",
488                 dns_ip,
489                 name);
490     GNUNET_DNSPARSER_free_packet (request->packet);
491     request->packet = NULL;
492     request->dns_lookup = GNUNET_DNSSTUB_resolve2 (dns_stub,
493                                                    udp_msg,
494                                                    udp_msg_size,
495                                                    &dns_result_processor,
496                                                    request);
497   }
498   GNUNET_free (name);
499 }
500
501
502 /**
503  * Task to read IPv4 DNS packets.
504  *
505  * @param cls the 'listen_socket4'
506  */
507 static void
508 read_dns4 (void *cls)
509 {
510   struct sockaddr_in v4;
511   socklen_t addrlen;
512   ssize_t size;
513   const struct GNUNET_SCHEDULER_TaskContext *tc;
514
515   GNUNET_assert (listen_socket4 == cls);
516   t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
517                                       listen_socket4,
518                                       &read_dns4,
519                                       listen_socket4);
520   tc = GNUNET_SCHEDULER_get_task_context ();
521   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
522     return; /* shutdown? */
523   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
524   if (0 > size)
525     {
526       GNUNET_break (0);
527       return; /* read error!? */
528     }
529   {
530     char buf[size];
531
532     addrlen = sizeof (v4);
533     GNUNET_break (size ==
534                   GNUNET_NETWORK_socket_recvfrom (listen_socket4,
535                                                   buf,
536                                                   size,
537                                                   (struct sockaddr *) &v4,
538                                                   &addrlen));
539     handle_request (listen_socket4, &v4, addrlen,
540                     buf, size);
541   }
542 }
543
544
545 /**
546  * Task to read IPv6 DNS packets.
547  *
548  * @param cls the 'listen_socket6'
549  */
550 static void
551 read_dns6 (void *cls)
552 {
553   struct sockaddr_in6 v6;
554   socklen_t addrlen;
555   ssize_t size;
556   const struct GNUNET_SCHEDULER_TaskContext *tc;
557
558   GNUNET_assert (listen_socket6 == cls);
559   t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
560                                       listen_socket6,
561                                       &read_dns6,
562                                       listen_socket6);
563   tc = GNUNET_SCHEDULER_get_task_context ();
564   if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
565     return; /* shutdown? */
566   size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
567   if (0 > size)
568     {
569       GNUNET_break (0);
570       return; /* read error!? */
571     }
572   {
573     char buf[size];
574
575     addrlen = sizeof (v6);
576     GNUNET_break (size ==
577                   GNUNET_NETWORK_socket_recvfrom (listen_socket6,
578                                                   buf,
579                                                   size,
580                                                   (struct sockaddr *) &v6,
581                                                   &addrlen));
582     handle_request (listen_socket6, &v6, addrlen,
583                     buf, size);
584   }
585 }
586
587
588 /**
589  * Start DNS daemon.
590  */
591 static void
592 run_dnsd ()
593 {
594   if (NULL == dns_suffix)
595     dns_suffix = DNS_SUFFIX;
596   if (NULL == fcfs_suffix)
597     fcfs_suffix = FCFS_SUFFIX;
598   if (NULL == (gns = GNUNET_GNS_connect (cfg)))
599     return;
600   if (NULL == (dns_stub = GNUNET_DNSSTUB_start (dns_ip)))
601   {
602     GNUNET_GNS_disconnect (gns);
603     gns = NULL;
604     return;
605   }
606   listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
607                                                  SOCK_DGRAM,
608                                                  IPPROTO_UDP);
609   if (NULL != listen_socket4)
610     {
611       struct sockaddr_in v4;
612
613       memset (&v4, 0, sizeof (v4));
614       v4.sin_family = AF_INET;
615 #if HAVE_SOCKADDR_IN_SIN_LEN
616       v4.sin_len = sizeof (v4);
617 #endif
618       v4.sin_port = htons (listen_port);
619       if (GNUNET_OK !=
620           GNUNET_NETWORK_socket_bind (listen_socket4,
621                                       (struct sockaddr *) &v4,
622                                       sizeof (v4)))
623         {
624           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
625           GNUNET_NETWORK_socket_close (listen_socket4);
626           listen_socket4 = NULL;
627         }
628     }
629   listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
630                                                 SOCK_DGRAM,
631                                                 IPPROTO_UDP);
632   if (NULL != listen_socket6)
633     {
634       struct sockaddr_in6 v6;
635
636       memset (&v6, 0, sizeof (v6));
637       v6.sin6_family = AF_INET6;
638 #if HAVE_SOCKADDR_IN_SIN_LEN
639       v6.sin6_len = sizeof (v6);
640 #endif
641       v6.sin6_port = htons (listen_port);
642       if (GNUNET_OK !=
643           GNUNET_NETWORK_socket_bind (listen_socket6,
644                                       (struct sockaddr *) &v6,
645                                       sizeof (v6)))
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_ecdsa_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: 2853"), 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 */